diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/N9H30.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/N9H30.h new file mode 100644 index 0000000000000000000000000000000000000000..2bdc5ebddd03dd3c087664a248366cac8738399d --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/N9H30.h @@ -0,0 +1,2097 @@ +/**************************************************************************//** + * @file N9H30.h + * @version V1.00 + * @brief N9H30 peripheral access layer header file. + * This file contains all the peripheral register's definitions + * and memory mapping for NuMicro N9H30 MCU. + * + * SPDX-License-Identifier: Apache-2.0 + * @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +/** + \mainpage NuMicro N9H30 Family Driver Reference Guide + * + * Introduction + * + * This user manual describes the usage of N9H30 family device driver + * + * Disclaimer + * + * The Software is furnished "AS IS", without warranty as to performance or results, and + * the entire risk as to performance or results is assumed by YOU. Nuvoton disclaims all + * warranties, express, implied or otherwise, with regard to the Software, its use, or + * operation, including without limitation any and all warranties of merchantability, fitness + * for a particular purpose, and non-infringement of intellectual property rights. + * + * Important Notice + * + * Nuvoton Products are neither intended nor warranted for usage in systems or equipment, + * any malfunction or failure of which may cause loss of human life, bodily injury or severe + * property damage. Such applications are deemed, "Insecure Usage". + * + * Insecure usage includes, but is not limited to: equipment for surgical implementation, + * atomic energy control instruments, airplane or spaceship instruments, the control or + * operation of dynamic, brake or safety systems designed for vehicular use, traffic signal + * instruments, all types of safety devices, and other applications intended to support or + * sustain life. + * + * All Insecure Usage shall be made at customer's risk, and in the event that third parties + * lay claims to Nuvoton as a result of customer's Insecure Usage, customer shall indemnify + * the damages and liabilities thus incurred by Nuvoton. + * + * Please note that all data and specifications are subject to change without notice. All the + * trademarks of products and companies mentioned in this document belong to their respective + * owners. + * + * Copyright Notice + * + * Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. + */ + +#ifndef __N9H30_H__ + #define __N9H30_H__ + + #include + + /** @addtogroup N9H30_PERIPHERAL_MEM_MAP N9H30 Peripheral Memory Base + Memory Mapped Structure for N9H30 Peripheral + @{ + */ + + /*!< AHB peripherals */ + #define SYS_BA 0xB0000000 /*!< System Global Control */ + #define CLK_BA 0xB0000200 /*!< Clock Control */ + #define EBI_BA 0xB0001000 /*!< EBI Control */ + #define SDIC_BA 0xB0001800 /*!< SDRAM (SDR/DDR/DDR2) Control */ + #define EMC0_BA 0xB0002000 /*!< Ethernet MAC 0 Control */ + #define EMC1_BA 0xB0003000 /*!< Ethernet MAC 1 Control */ + #define GDMA_BA 0xB0004000 /*!< GDMA control */ + #define USBH_BA 0xB0005000 /*!< USB Host EHCI Control */ + #define USBD_BA 0xB0006000 /*!< USB Device Control */ + #define USBO_BA 0xB0007000 /*!< OHCI USB Host Control */ + #define LCM_BA 0xB0008000 /*!< Display, LCM Interface */ + #define ACTL_BA 0xB0009000 /*!< Audio Control */ + #define JPEG_BA 0xB000A000 /*!< JPEG Engine Control */ + #define GE_BA 0xB000B000 /*!< 2-D Graphic Engine */ + #define SDH_BA 0xB000C000 /*!< SD/SDIO Host Controller */ + #define FMI_BA 0xB000D000 /*!< Flash Memory Card Interface */ + #define CAP_BA 0xB000E000 /*!< Sensor (Capture) Interface Control */ + #define CRPT_BA 0xB000F000 /*!< Crypto Engine Control */ + + /*!< APB peripherals */ + #define UART0_BA 0xB8000000 /*!< UART0 Control */ + #define UART1_BA 0xB8000100 /*!< UART1 Control (High-Speed UART) */ + #define UART2_BA 0xB8000200 /*!< UART2 Control (High-Speed UART) */ + #define UART3_BA 0xB8000300 /*!< UART3 Control */ + #define UART4_BA 0xB8000400 /*!< UART4 Control (High-Speed UART) */ + #define UART5_BA 0xB8000500 /*!< UART5 Control */ + #define UART6_BA 0xB8000600 /*!< UART6 Control (High-Speed UART) */ + #define UART7_BA 0xB8000700 /*!< UART7 Control */ + #define UART8_BA 0xB8000800 /*!< UART8 Control (High-Speed UART) */ + #define UART9_BA 0xB8000900 /*!< UART9 Control */ + #define UARTA_BA 0xB8000A00 /*!< UARTA Control (High-Speed UART) */ + #define TMR0_BA 0xB8001000 /*!< Timer 0 */ + #define TMR1_BA 0xB8001010 /*!< Timer 1 */ + #define TMR2_BA 0xB8001020 /*!< Timer 2 */ + #define TMR3_BA 0xB8001030 /*!< Timer 3 */ + #define TMR4_BA 0xB8001040 /*!< Timer 4 */ + #define ETMR0_BA 0xB8001400 /*!< Enhanced Timer 0 */ + #define ETMR1_BA 0xB8001500 /*!< Enhanced Timer 1 */ + #define ETMR2_BA 0xB8001600 /*!< Enhanced Timer 2 */ + #define ETMR3_BA 0xB8001700 /*!< Enhanced Timer 3 */ + #define WDT_BA 0xB8001800 /*!< Watch Dog Timer */ + #define WWDT_BA 0xB8001900 /*!< Window Watch Dog Timer */ + #define AIC_BA 0xB8002000 /*!< Interrupt Controller */ + #define GPIO_BA 0xB8003000 /*!< GPIO Control */ + #define RTC_BA 0xB8004000 /*!< Real Time Clock Control */ + #define SC0_BA 0xB8005000 /*!< Smart Card 0 Control */ + #define SC1_BA 0xB8005400 /*!< Smart Card 1 Control */ + #define I2C0_BA 0xB8006000 /*!< I2C 0 Control */ + #define I2C1_BA 0xB8006100 /*!< I2C 1 Control */ + #define SPI0_BA 0xB8006200 /*!< Serial Peripheral Interface 0 */ + #define SPI1_BA 0xB8006300 /*!< Serial Peripheral Interface 1 */ + #define PWM_BA 0xB8007000 /*!< Pulse Width Modulation (PWM) Control */ + #define ADC_BA 0xB800A000 /*!< ADC Control */ + #define CAN0_BA 0xB800B000 /*!< CAN 0 Control */ + #define CAN1_BA 0xB800B400 /*!< CAN 1 Control */ + #define MTP_BA 0xB800C000 /*!< MTP Control */ + + /*@}*/ /* end of group N9H30_PERIPHERAL_MEM_MAP */ + + /******************************************************************************/ + /* Device Specific Peripheral registers structures */ + /******************************************************************************/ + /** @addtogroup N9H30_Peripherals N9H30 Control Register + N9H30 Device Specific Peripheral registers structures + @{ + */ + + /*---------------------- System Manger Controller -------------------------*/ + /** + @addtogroup SYS System Manger Controller(SYS) + Memory Mapped Structure for SYS Controller + @{ */ + + #define REG_SYS_PDID (SYS_BA+0x000) /*!< Product Identifier Register */ + #define REG_SYS_PWRON (SYS_BA+0x004) /*!< Power-On Setting Register */ + #define REG_SYS_ARBCON (SYS_BA+0x008) /*!< Arbitration Control Register */ + #define REG_SYS_LVRDCR (SYS_BA+0x020) /*!< Low Voltage Reset & Detect Control Register */ + #define REG_SYS_MISCFCR (SYS_BA+0x030) /*!< Miscellaneous Function Control Register */ + #define REG_SYS_MISCIER (SYS_BA+0x040) /*!< Miscellaneous Interrupt Enable Register */ + #define REG_SYS_MISCISR (SYS_BA+0x044) /*!< Miscellaneous Interrupt Status Register */ + #define REG_SYS_WKUPSER (SYS_BA+0x058) /*!< System Wakeup Source Enable Register */ + #define REG_SYS_WKUPSSR (SYS_BA+0x05C) /*!< System Wakeup Source Status Register */ + #define REG_SYS_AHBIPRST (SYS_BA+0x060) /*!< AHB IP Reset Control Register */ + #define REG_SYS_APBIPRST0 (SYS_BA+0x064) /*!< APB IP Reset Control Register 0 */ + #define REG_SYS_APBIPRST1 (SYS_BA+0x068) /*!< APB IP Reset Control Register 1 */ + #define REG_SYS_RSTSTS (SYS_BA+0x06C) /*!< Reset Source Active Status Register */ + #define REG_SYS_GPA_MFPL (SYS_BA+0x070) /*!< GPIOA Low Byte Multiple Function Control Register */ + #define REG_SYS_GPA_MFPH (SYS_BA+0x074) /*!< GPIOA High Byte Multiple Function Control Register */ + #define REG_SYS_GPB_MFPL (SYS_BA+0x078) /*!< GPIOB Low Byte Multiple Function Control Register */ + #define REG_SYS_GPB_MFPH (SYS_BA+0x07C) /*!< GPIOB High Byte Multiple Function Control Register */ + #define REG_SYS_GPC_MFPL (SYS_BA+0x080) /*!< GPIOC Low Byte Multiple Function Control Register */ + #define REG_SYS_GPC_MFPH (SYS_BA+0x084) /*!< GPIOC High Byte Multiple Function Control Register */ + #define REG_SYS_GPD_MFPL (SYS_BA+0x088) /*!< GPIOD Low Byte Multiple Function Control Register */ + #define REG_SYS_GPD_MFPH (SYS_BA+0x08C) /*!< GPIOD High Byte Multiple Function Control Register */ + #define REG_SYS_GPE_MFPL (SYS_BA+0x090) /*!< GPIOE Low Byte Multiple Function Control Register */ + #define REG_SYS_GPE_MFPH (SYS_BA+0x094) /*!< GPIOE High Byte Multiple Function Control Register */ + #define REG_SYS_GPF_MFPL (SYS_BA+0x098) /*!< GPIOF Low Byte Multiple Function Control Register */ + #define REG_SYS_GPF_MFPH (SYS_BA+0x09C) /*!< GPIOF High Byte Multiple Function Control Register */ + #define REG_SYS_GPG_MFPL (SYS_BA+0x0A0) /*!< GPIOG Low Byte Multiple Function Control Register */ + #define REG_SYS_GPG_MFPH (SYS_BA+0x0A4) /*!< GPIOG High Byte Multiple Function Control Register */ + #define REG_SYS_GPH_MFPL (SYS_BA+0x0A8) /*!< GPIOH Low Byte Multiple Function Control Register */ + #define REG_SYS_GPH_MFPH (SYS_BA+0x0AC) /*!< GPIOH High Byte Multiple Function Control Register */ + #define REG_SYS_GPI_MFPL (SYS_BA+0x0B0) /*!< GPIOI Low Byte Multiple Function Control Register */ + #define REG_SYS_GPI_MFPH (SYS_BA+0x0B4) /*!< GPIOI High Byte Multiple Function Control Register */ + #define REG_SYS_GPJ_MFPL (SYS_BA+0x0B8) /*!< GPIOJ Low Byte Multiple Function Control Register */ + #define REG_SYS_DDR_DSCTL (SYS_BA+0x0F0) /*!< DDR I/O Driving Strength Control Register */ + #define REG_SYS_PORDISCR (SYS_BA+0x100) /*!< Power-On-Reset Disable Control Register */ + #define REG_SYS_ICEDBGCR (SYS_BA+0x104) /*!< ICE Debug Interface Control Register */ + #define REG_SYS_ERRADDCR (SYS_BA+0x108) /*!< Error Response Address Control Regsiter */ + #define REG_SYS_REGWPCTL (SYS_BA+0x1FC) /*!< Register Write-Protection Control Register */ + + /**@}*/ /* end of SYS register group */ + + /*---------------------- System Clock Controller -------------------------*/ + /** + @addtogroup CLK System Clock Controller(CLK) + Memory Mapped Structure for CLK Controller + @{ */ + + #define REG_CLK_PMCON (CLK_BA+0x00) /*!< Power Management Control Register */ + #define REG_CLK_HCLKEN (CLK_BA+0x10) /*!< AHB IP Clock Enable Control Register */ + #define REG_CLK_PCLKEN0 (CLK_BA+0x18) /*!< APB IP Clock Enable Control Register 0 */ + #define REG_CLK_PCLKEN1 (CLK_BA+0x1C) /*!< APB IP Clock Enable Control Register 1 */ + #define REG_CLK_DIVCTL0 (CLK_BA+0x20) /*!< Clock Divider Control Register 0 */ + #define REG_CLK_DIVCTL1 (CLK_BA+0x24) /*!< Clock Divider Control Register 1 */ + #define REG_CLK_DIVCTL2 (CLK_BA+0x28) /*!< Clock Divider Control Register 2 */ + #define REG_CLK_DIVCTL3 (CLK_BA+0x2C) /*!< Clock Divider Control Register 3 */ + #define REG_CLK_DIVCTL4 (CLK_BA+0x30) /*!< Clock Divider Control Register 4 */ + #define REG_CLK_DIVCTL5 (CLK_BA+0x34) /*!< Clock Divider Control Register 5 */ + #define REG_CLK_DIVCTL6 (CLK_BA+0x38) /*!< Clock Divider Control Register 6 */ + #define REG_CLK_DIVCTL7 (CLK_BA+0x3C) /*!< Clock Divider Control Register 7 */ + #define REG_CLK_DIVCTL8 (CLK_BA+0x40) /*!< Clock Divider Control Register 8 */ + #define REG_CLK_DIVCTL9 (CLK_BA+0x44) /*!< Clock Divider Control Register 9 */ + #define REG_CLK_APLLCON (CLK_BA+0x60) /*!< APLL Control Register */ + #define REG_CLK_UPLLCON (CLK_BA+0x64) /*!< UPLL Control Register */ + #define REG_CLK_PLLSTBCNTR (CLK_BA+0x80) /*!< PLL Stable Counter and Test Clock Control Register */ + + /**@}*/ /* end of CLK register group */ + + + /*---------------------- External Bus Interface Controller -------------------------*/ + /** + @addtogroup EBI External Bus Interface Controller(EBI) + Memory Mapped Structure for EBI Controller + @{ */ + + #define REG_EBI_CTL (EBI_BA+0x000) /*!< EBI control register */ + #define REG_EBI_BNKCTL0 (EBI_BA+0x018) /*!< External I/O 0 control register */ + #define REG_EBI_BNKCTL1 (EBI_BA+0x01C) /*!< External I/O 1 control register */ + #define REG_EBI_BNKCTL2 (EBI_BA+0x020) /*!< External I/O 2 control register */ + #define REG_EBI_BNKCTL3 (EBI_BA+0x024) /*!< External I/O 3 control register */ + #define REG_EBI_BNKCTL4 (EBI_BA+0x028) /*!< External I/O 4 control register */ + + /**@}*/ /* end of EBI register group */ + + + /*---------------------- Ethernet MAC Controller -------------------------*/ + /** + @addtogroup EMAC Ethernet MAC Controller(EMAC) + Memory Mapped Structure for EMAC Controller + @{ */ + + #define REG_EMAC0_CAMCMR (EMC0_BA+0x000) /*!< CAM Command Register */ + #define REG_EMAC0_CAMEN (EMC0_BA+0x004) /*!< CAM Enable Register */ + #define REG_EMAC0_CAM0M (EMC0_BA+0x008) /*!< CAM0 Most Significant Word Register */ + #define REG_EMAC0_CAM0L (EMC0_BA+0x00c) /*!< CAM0 Least Significant Word Register */ + #define REG_EMAC0_CAMxM_Reg(x)(REG_EMAC0_CAM0M+(x)*0x8) /*!< CAMx Most Significant Word Register */ + #define REG_EMAC0_CAMxL_Reg(x)(REG_EMAC0_CAM0L+(x)*0x8) /*!< CAMx Least Significant Word Register */ + #define REG_EMAC0_TXDLSA (EMC0_BA+0x088) /*!< Transmit Descriptor Link List Start Address Register */ + #define REG_EMAC0_RXDLSA (EMC0_BA+0x08C) /*!< Receive Descriptor Link List Start Address Register */ + #define REG_EMAC0_MCMDR (EMC0_BA+0x090) /*!< MAC Command Register */ + #define REG_EMAC0_MIID (EMC0_BA+0x094) /*!< MII Management Data Register */ + #define REG_EMAC0_MIIDA (EMC0_BA+0x098) /*!< MII Management Control and Address Register */ + #define REG_EMAC0_FFTCR (EMC0_BA+0x09C) /*!< FIFO Threshold Control Register */ + #define REG_EMAC0_TSDR (EMC0_BA+0x0a0) /*!< Transmit Start Demand Register */ + #define REG_EMAC0_RSDR (EMC0_BA+0x0a4) /*!< Receive Start Demand Register */ + #define REG_EMAC0_DMARFC (EMC0_BA+0x0a8) /*!< Maximum Receive Frame Control Register */ + #define REG_EMAC0_MIEN (EMC0_BA+0x0ac) /*!< MAC Interrupt Enable Register */ + #define REG_EMAC0_MISTA (EMC0_BA+0x0b0) /*!< MAC Interrupt Status Register */ + #define REG_EMAC0_MGSTA (EMC0_BA+0x0b4) /*!< MAC General Status Register */ + #define REG_EMAC0_MPCNT (EMC0_BA+0x0b8) /*!< Missed Packet Count Register */ + #define REG_EMAC0_MRPC (EMC0_BA+0x0bc) /*!< MAC Receive Pause Count Register */ + #define REG_EMAC0_DMARFS (EMC0_BA+0x0c8) /*!< DMA Receive Frame Status Register */ + #define REG_EMAC0_CTXDSA (EMC0_BA+0x0cc) /*!< Current Transmit Descriptor Start Address Register */ + #define REG_EMAC0_CTXBSA (EMC0_BA+0x0d0) /*!< Current Transmit Buffer Start Address Register */ + #define REG_EMAC0_CRXDSA (EMC0_BA+0x0d4) /*!< Current Receive Descriptor Start Address Register */ + #define REG_EMAC0_CRXBSA (EMC0_BA+0x0d8) /*!< Current Receive Buffer Start Address Register */ + #define REG_EMAC0_TSCTL (EMC0_BA+0x100) /*!< Time Stamp Control Register */ + #define REG_EMAC0_TSSEC (EMC0_BA+0x110) /*!< Time Stamp Counter Second Register */ + #define REG_EMAC0_TSSUBSEC (EMC0_BA+0x114) /*!< Time Stamp Counter Sub Second Register */ + #define REG_EMAC0_TSINC (EMC0_BA+0x118) /*!< Time Stamp Increment Register */ + #define REG_EMAC0_TSADDEN (EMC0_BA+0x11c) /*!< Time Stamp Addend Register */ + #define REG_EMAC0_TSUPDSEC (EMC0_BA+0x120) /*!< Time Stamp Update Second Register */ + #define REG_EMAC0_TSUPDSUBSEC (EMC0_BA+0x124) /*!< Time Stamp Update Sub Second Register */ + #define REG_EMAC0_TSALMSEC (EMC0_BA+0x128) /*!< Time Stamp Alarm Second Register */ + #define REG_EMAC0_TSALMSUBSEC (EMC0_BA+0x12c) /*!< Time Stamp Alarm Sub Second Register */ + + #define REG_EMAC1_CAMCMR (EMC1_BA+0x000) /*!< CAM Command Register */ + #define REG_EMAC1_CAMEN (EMC1_BA+0x004) /*!< CAM Enable Register */ + #define REG_EMAC1_CAM0M (EMC1_BA+0x008) /*!< CAM0 Most Significant Word Register */ + #define REG_EMAC1_CAM0L (EMC1_BA+0x00c) /*!< CAM0 Least Significant Word Register */ + #define REG_EMAC1_CAMxM_Reg(x)(REG_EMAC1_CAM0M+(x)*0x8) /*!< CAMx Most Significant Word Register */ + #define REG_EMAC1_CAMxL_Reg(x)(REG_EMAC1_CAM0L+(x)*0x8) /*!< CAMx Least Significant Word Register */ + #define REG_EMAC1_TXDLSA (EMC1_BA+0x088) /*!< Transmit Descriptor Link List Start Address Register */ + #define REG_EMAC1_RXDLSA (EMC1_BA+0x08C) /*!< Receive Descriptor Link List Start Address Register */ + #define REG_EMAC1_MCMDR (EMC1_BA+0x090) /*!< MAC Command Register */ + #define REG_EMAC1_MIID (EMC1_BA+0x094) /*!< MII Management Data Register */ + #define REG_EMAC1_MIIDA (EMC1_BA+0x098) /*!< MII Management Control and Address Register */ + #define REG_EMAC1_FFTCR (EMC1_BA+0x09C) /*!< FIFO Threshold Control Register */ + #define REG_EMAC1_TSDR (EMC1_BA+0x0a0) /*!< Transmit Start Demand Register */ + #define REG_EMAC1_RSDR (EMC1_BA+0x0a4) /*!< Receive Start Demand Register */ + #define REG_EMAC1_DMARFC (EMC1_BA+0x0a8) /*!< Maximum Receive Frame Control Register */ + #define REG_EMAC1_MIEN (EMC1_BA+0x0ac) /*!< MAC Interrupt Enable Register */ + #define REG_EMAC1_MISTA (EMC1_BA+0x0b0) /*!< MAC Interrupt Status Register */ + #define REG_EMAC1_MGSTA (EMC1_BA+0x0b4) /*!< MAC General Status Register */ + #define REG_EMAC1_MPCNT (EMC1_BA+0x0b8) /*!< Missed Packet Count Register */ + #define REG_EMAC1_MRPC (EMC1_BA+0x0bc) /*!< MAC Receive Pause Count Register */ + #define REG_EMAC1_DMARFS (EMC1_BA+0x0c8) /*!< DMA Receive Frame Status Register */ + #define REG_EMAC1_CTXDSA (EMC1_BA+0x0cc) /*!< Current Transmit Descriptor Start Address Register */ + #define REG_EMAC1_CTXBSA (EMC1_BA+0x0d0) /*!< Current Transmit Buffer Start Address Register */ + #define REG_EMAC1_CRXDSA (EMC1_BA+0x0d4) /*!< Current Receive Descriptor Start Address Register */ + #define REG_EMAC1_CRXBSA (EMC1_BA+0x0d8) /*!< Current Receive Buffer Start Address Register */ + #define REG_EMAC1_TSCTL (EMC1_BA+0x100) /*!< Time Stamp Control Register */ + #define REG_EMAC1_TSSEC (EMC1_BA+0x110) /*!< Time Stamp Counter Second Register */ + #define REG_EMAC1_TSSUBSEC (EMC1_BA+0x114) /*!< Time Stamp Counter Sub Second Register */ + #define REG_EMAC1_TSINC (EMC1_BA+0x118) /*!< Time Stamp Increment Register */ + #define REG_EMAC1_TSADDEN (EMC1_BA+0x11c) /*!< Time Stamp Addend Register */ + #define REG_EMAC1_TSUPDSEC (EMC1_BA+0x120) /*!< Time Stamp Update Second Register */ + #define REG_EMAC1_TSUPDSUBSEC (EMC1_BA+0x124) /*!< Time Stamp Update Sub Second Register */ + #define REG_EMAC1_TSALMSEC (EMC1_BA+0x128) /*!< Time Stamp Alarm Second Register */ + #define REG_EMAC1_TSALMSUBSEC (EMC1_BA+0x12c) /*!< Time Stamp Alarm Sub Second Register */ + + /**@}*/ /* end of EMAC register group */ + + /*---------------------- General Direct Memory Access Controller -------------------------*/ + /** + @addtogroup GDMA General Direct Memory Access Controller(GDMA) + Memory Mapped Structure for GDMA Controller + @{ */ + + #define REG_GDMA_CTL0 (GDMA_BA+0x000) /*!< Channel 0 Control Register */ + #define REG_GDMA_SRCB0 (GDMA_BA+0x004) /*!< Channel 0 Source Base Address Register */ + #define REG_GDMA_DSTB0 (GDMA_BA+0x008) /*!< Channel 0 Destination Base Address Register */ + #define REG_GDMA_TCNT0 (GDMA_BA+0x00C) /*!< Channel 0 Transfer Count Register */ + #define REG_GDMA_CSRC0 (GDMA_BA+0x010) /*!< Channel 0 Current Source Address Register */ + #define REG_GDMA_CDST0 (GDMA_BA+0x014) /*!< Channel 0 Current Destination Address Register */ + #define REG_GDMA_CTCNT0 (GDMA_BA+0x018) /*!< Channel 0 Current Transfer Count Register */ + #define REG_GDMA_DADR0 (GDMA_BA+0x01C) /*!< Channel 0 Descriptor Address Register */ + #define REG_GDMA_CTL1 (GDMA_BA+0x020) /*!< Channel 1 Control Register */ + #define REG_GDMA_SRCB1 (GDMA_BA+0x024) /*!< Channel 1 Source Base Address Register */ + #define REG_GDMA_DSTB1 (GDMA_BA+0x028) /*!< Channel 1 Destination Base Address Register */ + #define REG_GDMA_TCNT1 (GDMA_BA+0x02C) /*!< Channel 1 Transfer Count Register */ + #define REG_GDMA_CSRC1 (GDMA_BA+0x030) /*!< Channel 1 Current Source Address Register */ + #define REG_GDMA_CDST1 (GDMA_BA+0x034) /*!< Channel 1 Current Destination Address Register */ + #define REG_GDMA_CTCNT1 (GDMA_BA+0x038) /*!< Channel 1 Current Transfer Count Register */ + #define REG_GDMA_DADR1 (GDMA_BA+0x03C) /*!< Channel 1 Descriptor Address Register */ + #define REG_GDMA_INTBUF0 (GDMA_BA+0x080) /*!< GDMA Internal Buffer Word 0 */ + #define REG_GDMA_INTBUF1 (GDMA_BA+0x084) /*!< GDMA Internal Buffer Word 1 */ + #define REG_GDMA_INTBUF2 (GDMA_BA+0x088) /*!< GDMA Internal Buffer Word 2 */ + #define REG_GDMA_INTBUF3 (GDMA_BA+0x08C) /*!< GDMA Internal Buffer Word 3 */ + #define REG_GDMA_INTBUF4 (GDMA_BA+0x090) /*!< GDMA Internal Buffer Word 4 */ + #define REG_GDMA_INTBUF5 (GDMA_BA+0x094) /*!< GDMA Internal Buffer Word 5 */ + #define REG_GDMA_INTBUF6 (GDMA_BA+0x098) /*!< GDMA Internal Buffer Word 6 */ + #define REG_GDMA_INTBUF7 (GDMA_BA+0x09C) /*!< GDMA Internal Buffer Word 7 */ + #define REG_GDMA_INTCS (GDMA_BA+0x0A0) /*!< Interrupt Control and Status Register */ + + /**@}*/ /* end of GDMA register group */ + + + + /*---------------------- USB Device Controller -------------------------*/ + /** + @addtogroup USBD USB Device Controller(USBD) + Memory Mapped Structure for USBD Controller + @{ */ + #define REG_USBD_GINTSTS (USBD_BA+0x00) /*!< Interrupt Status Low Register */ + #define REG_USBD_GINTEN (USBD_BA+0x08) /*!< Interrupt Enable Low Register */ + #define REG_USBD_BUSINTSTS (USBD_BA+0x10) /*!< USB Bus Interrupt Status Register */ + #define REG_USBD_BUSINTEN (USBD_BA+0x14) /*!< USB Bus Interrupt Enable Register */ + #define REG_USBD_OPER (USBD_BA+0x18) /*!< USB Operational Register */ + #define REG_USBD_FRAMECNT (USBD_BA+0x1C) /*!< USB Frame Count Register */ + #define REG_USBD_FADDR (USBD_BA+0x20) /*!< USB Function Address Register */ + #define REG_USBD_TEST (USBD_BA+0x24) /*!< USB Test Mode Register */ + #define REG_USBD_CEPDAT (USBD_BA+0x28) /*!< Control-ep data buffer register */ + #define REG_USBD_CEPCTL (USBD_BA+0x2C) /*!< Control-ep control and status register */ + #define REG_USBD_CEPINTEN (USBD_BA+0x30) /*!< Control-ep interrupt enable register */ + #define REG_USBD_CEPINTSTS (USBD_BA+0x34) /*!< Control-ep interrupt status register */ + #define REG_USBD_CEPTXCNT (USBD_BA+0x38) /*!< In-transfer data count register */ + #define REG_USBD_CEPRXCNT (USBD_BA+0x3C) /*!< Out-transfer data count register */ + #define REG_USBD_CEPDATCNT (USBD_BA+0x40) /*!< Control-ep data count register */ + #define REG_USBD_SETUP1_0 (USBD_BA+0x44) /*!< Setup byte1 & byte0 register */ + #define REG_USBD_SETUP3_2 (USBD_BA+0x48) /*!< Setup byte3 & byte2 register */ + #define REG_USBD_SETUP5_4 (USBD_BA+0x4C) /*!< Setup byte5 & byte4 register */ + #define REG_USBD_SETUP7_6 (USBD_BA+0x50) /*!< Setup byte7 & byte6 register */ + #define REG_USBD_CEPBUFSTART (USBD_BA+0x54) /*!< Control-ep ram start address register */ + #define REG_USBD_CEPBUFEND (USBD_BA+0x58) /*!< Control-ep ram end address register */ + #define REG_USBD_DMACTL (USBD_BA+0x5C) /*!< Dma control and status register */ + #define REG_USBD_DMACNT (USBD_BA+0x60) /*!< Dma count register */ + + #define REG_USBD_EPADAT (USBD_BA+0x64) /*!< Endpoint A data buffer register */ + #define REG_USBD_EPAINTSTS (USBD_BA+0x68) /*!< Endpoint A interrupt status register */ + #define REG_USBD_EPAINTEN (USBD_BA+0x6C) /*!< Endpoint A interrupt enable register */ + #define REG_USBD_EPADATCNT (USBD_BA+0x70) /*!< Data count available in endpoint A buffer */ + #define REG_USBD_EPARSPCTL (USBD_BA+0x74) /*!< Endpoint A response register set/clear */ + #define REG_USBD_EPAMPS (USBD_BA+0x78) /*!< Endpoint A max packet size register */ + #define REG_USBD_EPATXCNT (USBD_BA+0x7C) /*!< Endpoint A transfer count register */ + #define REG_USBD_EPACFG (USBD_BA+0x80) /*!< Endpoint A configuration register */ + #define REG_USBD_EPABUFSTART (USBD_BA+0x84) /*!< Endpoint A ram start address register */ + #define REG_USBD_EPABUFEND (USBD_BA+0x88) /*!< Endpoint A ram end address register */ + + #define REG_USBD_EPBDAT (USBD_BA+0x8C) /*!< Endpoint B data buffer register */ + #define REG_USBD_EPBINTSTS (USBD_BA+0x90) /*!< Endpoint B interrupt status register */ + #define REG_USBD_EPBINTEN (USBD_BA+0x94) /*!< Endpoint B interrupt enable register */ + #define REG_USBD_EPBDATCNT (USBD_BA+0x98) /*!< Data count available in endpoint B buffer */ + #define REG_USBD_EPBRSPCTL (USBD_BA+0x9C) /*!< Endpoint B response register set/clear */ + #define REG_USBD_EPBMPS (USBD_BA+0xA0) /*!< Endpoint B max packet size register */ + #define REG_USBD_EPBTXCNT (USBD_BA+0xA4) /*!< Endpoint B transfer count register */ + #define REG_USBD_EPBCFG (USBD_BA+0xA8) /*!< Endpoint B configuration register */ + #define REG_USBD_EPBBUFSTART (USBD_BA+0xAC) /*!< Endpoint B ram start address register */ + #define REG_USBD_EPBBUFEND (USBD_BA+0xB0) /*!< Endpoint B ram end address register */ + + #define REG_USBD_EPCDAT (USBD_BA+0xB4) /*!< Endpoint C data buffer register */ + #define REG_USBD_EPCINTSTS (USBD_BA+0xB8) /*!< Endpoint C interrupt status register */ + #define REG_USBD_EPCINTEN (USBD_BA+0xBC) /*!< Endpoint C interrupt enable register */ + #define REG_USBD_EPCDATCNT (USBD_BA+0xC0) /*!< Data count available in endpoint C buffer */ + #define REG_USBD_EPCRSPCTL (USBD_BA+0xC4) /*!< Endpoint C response register set/clear */ + #define REG_USBD_EPCMPS (USBD_BA+0xC8) /*!< Endpoint C max packet size register */ + #define REG_USBD_EPCTXCNT (USBD_BA+0xCC) /*!< Endpoint C transfer count register */ + #define REG_USBD_EPCCFG (USBD_BA+0xD0) /*!< Endpoint C configuration register */ + #define REG_USBD_EPCBUFSTART (USBD_BA+0xD4) /*!< Endpoint C ram start address register */ + #define REG_USBD_EPCBUFEND (USBD_BA+0xD8) /*!< Endpoint C ram end address register */ + + #define REG_USBD_EPDDAT (USBD_BA+0xDC) /*!< Endpoint D data buffer register */ + #define REG_USBD_EPDINTSTS (USBD_BA+0xE0) /*!< Endpoint D interrupt status register */ + #define REG_USBD_EPDINTEN (USBD_BA+0xE4) /*!< Endpoint D interrupt enable register */ + #define REG_USBD_EPDDATCNT (USBD_BA+0xE8) /*!< Data count available in endpoint D buffer */ + #define REG_USBD_EPDRSPCTL (USBD_BA+0xEC) /*!< Endpoint D response register set/clear */ + #define REG_USBD_EPDMPS (USBD_BA+0xF0) /*!< Endpoint D max packet size register */ + #define REG_USBD_EPDTXCNT (USBD_BA+0xF4) /*!< Endpoint D transfer count register */ + #define REG_USBD_EPDCFG (USBD_BA+0xF8) /*!< Endpoint D configuration register */ + #define REG_USBD_EPDBUFSTART (USBD_BA+0xFC) /*!< Endpoint D ram start address register */ + #define REG_USBD_EPDBUFEND (USBD_BA+0x100) /*!< Endpoint D ram end address register */ + + #define REG_USBD_EPEDAT (USBD_BA+0x104) /*!< Endpoint E data buffer register */ + #define REG_USBD_EPEINTSTS (USBD_BA+0x108) /*!< Endpoint E interrupt status register */ + #define REG_USBD_EPEINTEN (USBD_BA+0x10C) /*!< Endpoint E interrupt enable register */ + #define REG_USBD_EPEDATCNT (USBD_BA+0x110) /*!< Data count available in endpoint E buffer */ + #define REG_USBD_EPERSPCTL (USBD_BA+0x114) /*!< Endpoint E response register set/clear */ + #define REG_USBD_EPEMPS (USBD_BA+0x118) /*!< Endpoint E max packet size register */ + #define REG_USBD_EPETXCNT (USBD_BA+0x11C) /*!< Endpoint E transfer count register */ + #define REG_USBD_EPECFG (USBD_BA+0x120) /*!< Endpoint E configuration register */ + #define REG_USBD_EPEBUFSTART (USBD_BA+0x124) /*!< Endpoint E ram start address register */ + #define REG_USBD_EPEBUFEND (USBD_BA+0x128) /*!< Endpoint E ram end address register */ + + #define REG_USBD_EPFDAT (USBD_BA+0x12C) /*!< Endpoint F data buffer register */ + #define REG_USBD_EPFINTSTS (USBD_BA+0x130) /*!< Endpoint F interrupt status register */ + #define REG_USBD_EPFINTEN (USBD_BA+0x134) /*!< Endpoint F interrupt enable register */ + #define REG_USBD_EPFDATCNT (USBD_BA+0x138) /*!< Data count available in endpoint F buffer */ + #define REG_USBD_EPFRSPCTL (USBD_BA+0x13C) /*!< Endpoint F response register set/clear */ + #define REG_USBD_EPFMPS (USBD_BA+0x140) /*!< Endpoint F max packet size register */ + #define REG_USBD_EPFTXCNT (USBD_BA+0x144) /*!< Endpoint F transfer count register */ + #define REG_USBD_EPFCFG (USBD_BA+0x148) /*!< Endpoint F configuration register */ + #define REG_USBD_EPFBUFSTART (USBD_BA+0x14C) /*!< Endpoint F ram start address register */ + #define REG_USBD_EPFBUFEND (USBD_BA+0x150) /*!< Endpoint F ram end address register */ + + #define REG_USBD_EPGDAT (USBD_BA+0x154) /*!< Endpoint G data buffer register */ + #define REG_USBD_EPGINTSTS (USBD_BA+0x158) /*!< Endpoint G interrupt status register */ + #define REG_USBD_EPGINTEN (USBD_BA+0x15C) /*!< Endpoint G interrupt enable register */ + #define REG_USBD_EPGDATCNT (USBD_BA+0x160) /*!< Data count available in endpoint G buffer */ + #define REG_USBD_EPGRSPCTL (USBD_BA+0x164) /*!< Endpoint G response register set/clear */ + #define REG_USBD_EPGMPS (USBD_BA+0x168) /*!< Endpoint G max packet size register */ + #define REG_USBD_EPGTXCNT (USBD_BA+0x16C) /*!< Endpoint G transfer count register */ + #define REG_USBD_EPGCFG (USBD_BA+0x170) /*!< Endpoint G configuration register */ + #define REG_USBD_EPGBUFSTART (USBD_BA+0x174) /*!< Endpoint G ram start address register */ + #define REG_USBD_EPGBUFEND (USBD_BA+0x178) /*!< Endpoint G ram end address register */ + + #define REG_USBD_EPHDAT (USBD_BA+0x17C) /*!< Endpoint H data buffer register */ + #define REG_USBD_EPHINTSTS (USBD_BA+0x180) /*!< Endpoint H interrupt status register */ + #define REG_USBD_EPHINTEN (USBD_BA+0x184) /*!< Endpoint H interrupt enable register */ + #define REG_USBD_EPHDATCNT (USBD_BA+0x188) /*!< Data count available in endpoint H buffer */ + #define REG_USBD_EPHRSPCTL (USBD_BA+0x18C) /*!< Endpoint H response register set/clear */ + #define REG_USBD_EPHMPS (USBD_BA+0x190) /*!< Endpoint H max packet size register */ + #define REG_USBD_EPHTXCNT (USBD_BA+0x194) /*!< Endpoint H transfer count register */ + #define REG_USBD_EPHCFG (USBD_BA+0x198) /*!< Endpoint H configuration register */ + #define REG_USBD_EPHBUFSTART (USBD_BA+0x19C) /*!< Endpoint H ram start address register */ + #define REG_USBD_EPHBUFEND (USBD_BA+0x1A0) /*!< Endpoint H ram end address register */ + + #define REG_USBD_EPIDAT (USBD_BA+0x1A4) /*!< Endpoint I data buffer register */ + #define REG_USBD_EPIINTSTS (USBD_BA+0x1A8) /*!< Endpoint I interrupt status register */ + #define REG_USBD_EPIINTEN (USBD_BA+0x1AC) /*!< Endpoint I interrupt enable register */ + #define REG_USBD_EPIDATCNT (USBD_BA+0x1B0) /*!< Data count available in endpoint I buffer */ + #define REG_USBD_EPIRSPCTL (USBD_BA+0x1B4) /*!< Endpoint I response register set/clear */ + #define REG_USBD_EPIMPS (USBD_BA+0x1B8) /*!< Endpoint I max packet size register */ + #define REG_USBD_EPITXCNT (USBD_BA+0x1BC) /*!< Endpoint I transfer count register */ + #define REG_USBD_EPICFG (USBD_BA+0x1C0) /*!< Endpoint I configuration register */ + #define REG_USBD_EPIBUFSTART (USBD_BA+0x1C4) /*!< Endpoint I ram start address register */ + #define REG_USBD_EPIBUFEND (USBD_BA+0x1C8) /*!< Endpoint I ram end address register */ + + #define REG_USBD_EPJDAT (USBD_BA+0x1CC) /*!< Endpoint J data buffer register */ + #define REG_USBD_EPJINTSTS (USBD_BA+0x1D0) /*!< Endpoint J interrupt status register */ + #define REG_USBD_EPJINTEN (USBD_BA+0x1D4) /*!< Endpoint J interrupt enable register */ + #define REG_USBD_EPJDATCNT (USBD_BA+0x1D8) /*!< Data count available in endpoint J buffer */ + #define REG_USBD_EPJRSPCTL (USBD_BA+0x1DC) /*!< Endpoint J response register set/clear */ + #define REG_USBD_EPJMPS (USBD_BA+0x1E0) /*!< Endpoint J max packet size register */ + #define REG_USBD_EPJTXCNT (USBD_BA+0x1E4) /*!< Endpoint J transfer count register */ + #define REG_USBD_EPJCFG (USBD_BA+0x1E8) /*!< Endpoint J configuration register */ + #define REG_USBD_EPJBUFSTART (USBD_BA+0x1EC) /*!< Endpoint J ram start address register */ + #define REG_USBD_EPJBUFEND (USBD_BA+0x1F0) /*!< Endpoint J ram end address register */ + + #define REG_USBD_EPKDAT (USBD_BA+0x1F4) /*!< Endpoint K data buffer register */ + #define REG_USBD_EPKINTSTS (USBD_BA+0x1F8) /*!< Endpoint K interrupt status register */ + #define REG_USBD_EPKINTEN (USBD_BA+0x1FC) /*!< Endpoint K interrupt enable register */ + #define REG_USBD_EPKDATCNT (USBD_BA+0x200) /*!< Data count available in endpoint K buffer */ + #define REG_USBD_EPKRSPCTL (USBD_BA+0x204) /*!< Endpoint K response register set/clear */ + #define REG_USBD_EPKMPS (USBD_BA+0x208) /*!< Endpoint K max packet size register */ + #define REG_USBD_EPKTXCNT (USBD_BA+0x20C) /*!< Endpoint K transfer count register */ + #define REG_USBD_EPKCFG (USBD_BA+0x210) /*!< Endpoint K configuration register */ + #define REG_USBD_EPKBUFSTART (USBD_BA+0x214) /*!< Endpoint K ram start address register */ + #define REG_USBD_EPKBUFEND (USBD_BA+0x218) /*!< Endpoint K ram end address register */ + + #define REG_USBD_EPLDAT (USBD_BA+0x21C) /*!< Endpoint L data buffer register */ + #define REG_USBD_EPLINTSTS (USBD_BA+0x220) /*!< Endpoint L interrupt status register */ + #define REG_USBD_EPLINTEN (USBD_BA+0x224) /*!< Endpoint L interrupt enable register */ + #define REG_USBD_EPLDATCNT (USBD_BA+0x228) /*!< Data count available in endpoint L buffer */ + #define REG_USBD_EPLRSPCTL (USBD_BA+0x22C) /*!< Endpoint L response register set/clear */ + #define REG_USBD_EPLMPS (USBD_BA+0x230) /*!< Endpoint L max packet size register */ + #define REG_USBD_EPLTXCNT (USBD_BA+0x234) /*!< Endpoint L transfer count register */ + #define REG_USBD_EPLCFG (USBD_BA+0x238) /*!< Endpoint L configuration register */ + #define REG_USBD_EPLBUFSTART (USBD_BA+0x23C) /*!< Endpoint L ram start address register */ + #define REG_USBD_EPLBUFEND (USBD_BA+0x240) /*!< Endpoint L ram end address register */ + #define REG_USBD_DMAADDR (USBD_BA+0x700) /*!< AHB_DMA address register */ + #define REG_USBD_PHYCTL (USBD_BA+0x704) /*!< USB PHY control register */ + + /**@}*/ /* end of USBD register group */ + + + /*---------------------- LCD Display Interface Controller -------------------------*/ + /** + @addtogroup LCM LCD Display Interface Controller(LCM) + Memory Mapped Structure for LCM Controller + @{ */ + + #define REG_LCM_DCCS (LCM_BA+0x00) /*!< Display Controller Control/Status Register */ + #define REG_LCM_DEV_CTRL (LCM_BA+0x04) /*!< Display Output Device Control Register */ + #define REG_LCM_MPU_CMD (LCM_BA+0x08) /*!< MPU-Interface LCD Write Command */ + #define REG_LCM_INT_CS (LCM_BA+0x0c) /*!< Interrupt Control/Status Register */ + #define REG_LCM_CRTC_SIZE (LCM_BA+0x10) /*!< CRTC Display Size Control Register */ + #define REG_LCM_CRTC_DEND (LCM_BA+0x14) /*!< CRTC Display Enable End */ + #define REG_LCM_CRTC_HR (LCM_BA+0x18) /*!< CRTC Internal Horizontal Retrace Control Register */ + #define REG_LCM_CRTC_HSYNC (LCM_BA+0x1C) /*!< CRTC Horizontal Sync Control Register */ + #define REG_LCM_CRTC_VR (LCM_BA+0x20) /*!< CRTC Internal Vertical Retrace Control Register */ + #define REG_LCM_VA_BADDR0 (LCM_BA+0x24) /*!< Video Stream Frame Buffer-0 Starting Address */ + #define REG_LCM_VA_BADDR1 (LCM_BA+0x28) /*!< Video Stream Frame Buffer-1 Starting Address */ + #define REG_LCM_VA_FBCTRL (LCM_BA+0x2C) /*!< Video Stream Frame Buffer Control Register */ + #define REG_LCM_VA_SCALE (LCM_BA+0x30) /*!< Video Stream Scaling Control Register */ + #define REG_LCM_VA_WIN (LCM_BA+0x38) /*!< Image Stream Active Window Coordinates */ + #define REG_LCM_VA_STUFF (LCM_BA+0x3C) /*!< Image Stream Stuff Pixel */ + #define REG_LCM_OSD_WINS (LCM_BA+0x40) /*!< OSD Window Starting Coordinates */ + #define REG_LCM_OSD_WINE (LCM_BA+0x44) /*!< OSD Window Ending Coordinates */ + #define REG_LCM_OSD_BADDR (LCM_BA+0x48) /*!< OSD Stream Frame Buffer Starting Address */ + #define REG_LCM_OSD_FBCTRL (LCM_BA+0x4c) /*!< OSD Stream Frame Buffer Control Register */ + #define REG_LCM_OSD_OVERLAY (LCM_BA+0x50) /*!< OSD Overlay Control Register */ + #define REG_LCM_OSD_CKEY (LCM_BA+0x54) /*!< OSD Overlay Color-Key Pattern Register */ + #define REG_LCM_OSD_CMASK (LCM_BA+0x58) /*!< OSD Overlay Color-Key Mask Register */ + #define REG_LCM_OSD_SKIP1 (LCM_BA+0x5C) /*!< OSD Window Skip1 Register */ + #define REG_LCM_OSD_SKIP2 (LCM_BA+0x60) /*!< OSD Window Skip2 Register */ + #define REG_LCM_OSD_SCALE (LCM_BA+0x64) /*!< OSD horizontal up scaling control register */ + #define REG_LCM_MPU_VSYNC (LCM_BA+0x68) /*!< MPU Vsync control register */ + #define REG_LCM_HC_CTRL (LCM_BA+0x6C) /*!< Hardware cursor control Register */ + #define REG_LCM_HC_POS (LCM_BA+0x70) /*!< Hardware cursot tip point potison on va picture */ + #define REG_LCM_HC_WBCTRL (LCM_BA+0x74) /*!< Hardware Cursor Window Buffer Control Register */ + #define REG_LCM_HC_BADDR (LCM_BA+0x78) /*!< Hardware cursor memory base address register */ + #define REG_LCM_HC_COLOR0 (LCM_BA+0x7C) /*!< Hardware cursor color ram register mapped to bpp = 0 */ + #define REG_LCM_HC_COLOR1 (LCM_BA+0x80) /*!< Hardware cursor color ram register mapped to bpp = 1 */ + #define REG_LCM_HC_COLOR2 (LCM_BA+0x84) /*!< Hardware cursor color ram register mapped to bpp = 2 */ + #define REG_LCM_HC_COLOR3 (LCM_BA+0x88) /*!< Hardware cursor color ram register mapped to bpp = 3 */ + + /**@}*/ /* end of LCM register group */ + + + /*---------------------- I2S Interface Controller -------------------------*/ + /** + @addtogroup I2S I2S Interface Controller(I2S) + Memory Mapped Structure for I2S Controller + @{ */ + + #define REG_ACTL_CON (ACTL_BA+0x00) /*!< Audio controller control register */ + #define REG_ACTL_RESET (ACTL_BA+0x04) /*!< Sub block reset control register */ + #define REG_ACTL_RDESB (ACTL_BA+0x08) /*!< DMA destination base address register for record */ + #define REG_ACTL_RDES_LENGTH (ACTL_BA+0x0C) /*!< DMA destination length register for record */ + #define REG_ACTL_RDESC (ACTL_BA+0x10) /*!< DMA destination current address for record */ + #define REG_ACTL_PDESB (ACTL_BA+0x14) /*!< DMA destination current address for play */ + #define REG_ACTL_PDES_LENGTH (ACTL_BA+0x18) /*!< DMA destination length register for play */ + #define REG_ACTL_PDESC (ACTL_BA+0x1C) /*!< DMA destination current address register for play */ + #define REG_ACTL_RSR (ACTL_BA+0x20) /*!< Record status register */ + #define REG_ACTL_PSR (ACTL_BA+0x24) /*!< Play status register */ + #define REG_ACTL_I2SCON (ACTL_BA+0x28) /*!< I2S control register */ + #define REG_ACTL_COUNTER (ACTL_BA+0x2C) /*!< DMA count down values */ + #define REG_ACTL_PCMCON (ACTL_BA+0x30) /*!< PCM interface control register */ + #define REG_ACTL_PCMS1ST (ACTL_BA+0x34) /*!< PCM interface slot1 start register */ + #define REG_ACTL_PCMS2ST (ACTL_BA+0x38) /*!< PCM interface slot2 start register */ + #define REG_ACTL_RDESB2 (ACTL_BA+0x40) /*!< DMA destination base address register for record right channel */ + #define REG_ACTL_PDESB2 (ACTL_BA+0x44) /*!< DMA destination base address register for play right channel */ + + /**@}*/ /* end of I2S register group */ + + /*---------------------- 2D Graphic Engine -------------------------*/ + /** + @addtogroup GE2D 2D Graphic Engine(GE2D) + Memory Mapped Structure for GE2D Controller + @{ */ + + #define REG_GE2D_TRG (GE_BA+0x00) /*!< Graphic Engine Trigger Control Register */ + #define REG_GE2D_XYSORG (GE_BA+0x04) /*!< Graphic Engine XY Mode Source Origin Starting Register */ + #define REG_GE2D_TCNTVHSF (GE_BA+0x08) /*!< Graphic Engine Tile Width/Height or V/H Scale Factor N/M */ + #define REG_GE2D_XYRRP (GE_BA+0x0C) /*!< Graphic Engine Rotate Reference Point XY Address */ + #define REG_GE2D_INTSTS (GE_BA+0x10) /*!< Graphic Engine Interrupt Status Register */ + #define REG_GE2D_PATSA (GE_BA+0x14) /*!< Graphic Engine Pattern Location Starting Address Register */ + #define REG_GE2D_BETSC (GE_BA+0x18) /*!< GE Bresenham Error Term Stepping Constant Register */ + #define REG_GE2D_BIEPC (GE_BA+0x1C) /*!< GE Bresenham Initial Error, Pixel Count Major M Register */ + #define REG_GE2D_CTL (GE_BA+0x20) /*!< Graphic Engine Control Register */ + #define REG_GE2D_BGCOLR (GE_BA+0x24) /*!< Graphic Engine Background Color Register */ + #define REG_GE2D_FGCOLR (GE_BA+0x28) /*!< Graphic Engine Foreground Color Register */ + #define REG_GE2D_TRNSCOLR (GE_BA+0x2C) /*!< Graphic Engine Transparency Color Register */ + #define REG_GE2D_TCMSK (GE_BA+0x30) /*!< Graphic Engine Transparency Color Mask Register */ + #define REG_GE2D_XYDORG (GE_BA+0x34) /*!< Graphic Engine XY Mode Display Origin Starting Register */ + #define REG_GE2D_SDPITCH (GE_BA+0x38) /*!< Graphic Engine Source/Destination Pitch Register */ + #define REG_GE2D_SRCSPA (GE_BA+0x3C) /*!< Graphic Engine Source Start XY/Linear Address Register */ + #define REG_GE2D_DSTSPA (GE_BA+0x40) /*!< Graphic Engine Destination Start XY/Linear Register */ + #define REG_GE2D_RTGLSZ (GE_BA+0x44) /*!< Graphic Engine Dimension XY/Linear Register */ + #define REG_GE2D_CLPBTL (GE_BA+0x48) /*!< Graphic Engine Clipping Boundary Top/Left Register */ + #define REG_GE2D_CLPBBR (GE_BA+0x4C) /*!< Graphic Engine Clipping Boundary Bottom/Right Register */ + #define REG_GE2D_PTNA (GE_BA+0x50) /*!< Graphic Engine Pattern A Register */ + #define REG_GE2D_PTNB (GE_BA+0x54) /*!< Graphic Engine Pattern B Register */ + #define REG_GE2D_WRPLNMSK (GE_BA+0x58) /*!< Graphic Engine Write Plane Mask Register */ + #define REG_GE2D_MISCTL (GE_BA+0x5C) /*!< Graphic Engine Miscellaneous Control Register */ + #define REG_GE2D_GEHBDW0 (GE_BA+0x60) /*!< Graphic Engine HostBLT data Port 0 Register */ + #define REG_GE2D_GEHBDW1 (GE_BA+0x64) /*!< Graphic Engine HostBLT data Port 1 Register */ + #define REG_GE2D_GEHBDW2 (GE_BA+0x68) /*!< Graphic Engine HostBLT data Port 2 Register */ + #define REG_GE2D_GEHBDW3 (GE_BA+0x6C) /*!< Graphic Engine HostBLT data Port 3 Register */ + #define REG_GE2D_GEHBDW4 (GE_BA+0x70) /*!< Graphic Engine HostBLT data Port 4 Register */ + #define REG_GE2D_GEHBDW5 (GE_BA+0x74) /*!< Graphic Engine HostBLT data Port 5 Register */ + #define REG_GE2D_GEHBDW6 (GE_BA+0x78) /*!< Graphic Engine HostBLT data Port 6 Register */ + #define REG_GE2D_GEHBDW7 (GE_BA+0x7C) /*!< Graphic Engine HostBLT data Port 7 Register */ + + /**@}*/ /* end of GE2D register group */ + + /*---------------------- Flash Memory Interface -------------------------*/ + /** + @addtogroup FMI Flash Memory Interface(FMI) + Memory Mapped Structure for FMI Controller + @{ */ + + /* DMAC Control Registers*/ + #define REG_FMI_BUFFER (FMI_BA+0x000) /*!< FMI Embedded Buffer Word */ + #define REG_FMI_DMACTL (FMI_BA+0x400) /*!< FMI DMA Control Register */ + #define REG_FMI_DMASA (FMI_BA+0x408) /*!< FMI DMA Transfer Starting Address Register */ + #define REG_FMI_DMABCNT (FMI_BA+0x40C) /*!< FMI DMA Transfer Byte Count Register */ + #define REG_FMI_DMAINTEN (FMI_BA+0x410) /*!< FMI DMA Interrupt Enable Register */ + #define REG_FMI_DMAINTSTS (FMI_BA+0x414) /*!< FMI DMA Interrupt Status Register */ + + #define REG_FMI_CTL (FMI_BA+0x800) /*!< Global Control and Status Register */ + #define REG_FMI_INTEN (FMI_BA+0x804) /*!< Global Interrupt Control Register */ + #define REG_FMI_INTSTS (FMI_BA+0x808) /*!< Global Interrupt Status Register */ + + /* eMMC Registers */ + #define REG_FMI_EMMCCTL (FMI_BA+0x820) /*!< eMMC control and status register */ + #define REG_FMI_EMMCCMD (FMI_BA+0x824) /*!< eMMC command argument register */ + #define REG_FMI_EMMCINTEN (FMI_BA+0x828) /*!< eMMC interrupt enable register */ + #define REG_FMI_EMMCINTSTS (FMI_BA+0x82C) /*!< eMMC interrupt status register */ + #define REG_FMI_EMMCRESP0 (FMI_BA+0x830) /*!< eMMC receive response token register 0 */ + #define REG_FMI_EMMCRESP1 (FMI_BA+0x834) /*!< eMMC receive response token register 1 */ + #define REG_FMI_EMMCBLEN (FMI_BA+0x838) /*!< eMMC block length register */ + #define REG_FMI_EMMCTOUT (FMI_BA+0x83C) /*!< eMMC block length register */ + + /* NAND-type Flash Registers */ + #define REG_NANDCTL (FMI_BA+0x8A0) /*!< NAND Flash Control and Status Register */ + #define REG_NANDTMCTL (FMI_BA+0x8A4) /*!< NAND Flash Timing Control Register */ + #define REG_NANDINTEN (FMI_BA+0x8A8) /*!< NAND Flash Interrupt Control Register */ + #define REG_NANDINTSTS (FMI_BA+0x8AC) /*!< NAND Flash Interrupt Status Register */ + #define REG_NANDCMD (FMI_BA+0x8B0) /*!< NAND Flash Command Port Register */ + #define REG_NANDADDR (FMI_BA+0x8B4) /*!< NAND Flash Address Port Register */ + #define REG_NANDDATA (FMI_BA+0x8B8) /*!< NAND Flash Data Port Register */ + #define REG_NANDRACTL (FMI_BA+0x8BC) /*!< NAND Flash Redundant Area Control Register */ + #define REG_NANDECTL (FMI_BA+0x8C0) /*!< NAND Flash Extend Control Regsiter */ + #define REG_NANDECCES0 (FMI_BA+0x8D0) /*!< NAND Flash ECC Error Status 0 */ + #define REG_NANDECCES1 (FMI_BA+0x8D4) /*!< NAND Flash ECC Error Status 1 */ + #define REG_NANDECCES2 (FMI_BA+0x8D8) /*!< NAND Flash ECC Error Status 2 */ + #define REG_NANDECCES3 (FMI_BA+0x8DC) /*!< NAND Flash ECC Error Status 3 */ + #define REG_NANDPROTA0 (FMI_BA+0x8E0) /*!< NAND Flash Protect Region End Address 0 */ + #define REG_NANDPROTA1 (FMI_BA+0x8E4) /*!< NAND Flash Protect Region End Address 1 */ + + /* NAND-type Flash BCH Error Address Registers */ + #define REG_NANDECCEA0 (FMI_BA+0x900) /*!< NAND Flash ECC Error Byte Address 0 */ + #define REG_NANDECCEA1 (FMI_BA+0x904) /*!< NAND Flash ECC Error Byte Address 1 */ + #define REG_NANDECCEA2 (FMI_BA+0x908) /*!< NAND Flash ECC Error Byte Address 2 */ + #define REG_NANDECCEA3 (FMI_BA+0x90C) /*!< NAND Flash ECC Error Byte Address 3 */ + #define REG_NANDECCEA4 (FMI_BA+0x910) /*!< NAND Flash ECC Error Byte Address 4 */ + #define REG_NANDECCEA5 (FMI_BA+0x914) /*!< NAND Flash ECC Error Byte Address 5 */ + #define REG_NANDECCEA6 (FMI_BA+0x918) /*!< NAND Flash ECC Error Byte Address 6 */ + #define REG_NANDECCEA7 (FMI_BA+0x91C) /*!< NAND Flash ECC Error Byte Address 7 */ + #define REG_NANDECCEA8 (FMI_BA+0x920) /*!< NAND Flash ECC Error Byte Address 8 */ + #define REG_NANDECCEA9 (FMI_BA+0x924) /*!< NAND Flash ECC Error Byte Address 9 */ + #define REG_NANDECCEA10 (FMI_BA+0x928) /*!< NAND Flash ECC Error Byte Address 10 */ + #define REG_NANDECCEA11 (FMI_BA+0x92C) /*!< NAND Flash ECC Error Byte Address 11 */ + + /* NAND-type Flash BCH Error Data Registers */ + #define REG_NANDECCED0 (FMI_BA+0x960) /*!< NAND Flash ECC Error Data Register 0 */ + #define REG_NANDECCED1 (FMI_BA+0x964) /*!< NAND Flash ECC Error Data Register 1 */ + #define REG_NANDECCED2 (FMI_BA+0x968) /*!< NAND Flash ECC Error Data Register 2 */ + #define REG_NANDECCED3 (FMI_BA+0x96C) /*!< NAND Flash ECC Error Data Register 3 */ + #define REG_NANDECCED4 (FMI_BA+0x970) /*!< NAND Flash ECC Error Data Register 4 */ + #define REG_NANDECCED5 (FMI_BA+0x974) /*!< NAND Flash ECC Error Data Register 5 */ + + /* NAND-type Flash Redundant Area Registers */ + #define REG_NANDRA0 (FMI_BA+0xA00) /*!< NAND Flash Redundant Area Register */ + #define REG_NANDRA1 (FMI_BA+0xA04) /*!< NAND Flash Redundant Area Register */ + + /**@}*/ /* end of FMI register group */ + + + /*---------------------- SD/SDIO Host Controller -------------------------*/ + /** + @addtogroup SDH SD/SDIO Host Controller(SDH) + Memory Mapped Structure for SDH Controller + @{ */ + + /* DMAC Control Registers*/ + #define REG_SDH_FB0 (SDH_BA+0x000) /*!< SD Host Embedded Buffer Word */ + #define REG_SDH_DMACTL (SDH_BA+0x400) /*!< SD Host DMA Control and Status Register */ + #define REG_SDH_DMASA (SDH_BA+0x408) /*!< SD Host DMA Transfer Starting Address Register */ + #define REG_SDH_DMABCNT (SDH_BA+0x40C) /*!< SD Host DMA Transfer Byte Count Register */ + #define REG_SDH_DMAINTEN (SDH_BA+0x410) /*!< SD Host DMA Interrupt Enable Register */ + #define REG_SDH_DMAINTSTS (SDH_BA+0x414) /*!< SD Host DMA Interrupt Status Register */ + + #define REG_SDH_GCTL (SDH_BA+0x800) /*!< SD Host Global Control and Status Register */ + #define REG_SDH_GINTEN (SDH_BA+0x804) /*!< SD Host Global Interrupt Control Register */ + #define REG_SDH_GINTSTS (SDH_BA+0x808) /*!< SD Host Global Interrupt Status Register */ + + /* Secure Digit Registers */ + #define REG_SDH_CTL (SDH_BA+0x820) /*!< SD Host control and status register */ + #define REG_SDH_CMD (SDH_BA+0x824) /*!< SD Host command argument register */ + #define REG_SDH_INTEN (SDH_BA+0x828) /*!< SD Host interrupt enable register */ + #define REG_SDH_INTSTS (SDH_BA+0x82C) /*!< SD Host interrupt status register */ + #define REG_SDH_RESP0 (SDH_BA+0x830) /*!< SD Host receive response token register 0 */ + #define REG_SDH_RESP1 (SDH_BA+0x834) /*!< SD Host receive response token register 1 */ + #define REG_SDH_BLEN (SDH_BA+0x838) /*!< SD Host block length register */ + #define REG_SDH_TMOUT (SDH_BA+0x83C) /*!< SD Host Response/Data-in Time-out register */ + #define REG_SDH_ECTL (SDH_BA+0x840) /*!< SD Host Extend Control Register */ + + /**@}*/ /* end of SDH register group */ + + + /*---------------------- Cryptographic Accelerator -------------------------*/ + /** + @addtogroup CRYPTO Cryptographic Accelerator(CRYPTO) + Memory Mapped Structure for Cryptographic Accelerator registers + @{ */ + + /* Crypto Control Registers */ + #define CRPT_INTEN (CRPT_BA+0x000) /*!< Crypto Interrupt Enable Control Register */ + #define CRPT_INTSTS (CRPT_BA+0x004) /*!< Crypto Interrupt Flag */ + + /* PRNG Registers */ + #define CRPT_PRNG_CTL (CRPT_BA+0x008) /*!< PRNG Control Register */ + #define CRPT_PRNG_SEED (CRPT_BA+0x00C) /*!< Seed for PRNG */ + #define CRPT_PRNG_KEY0 (CRPT_BA+0x010) /*!< PRNG Generated Key 0 */ + #define CRPT_PRNG_KEY1 (CRPT_BA+0x014) /*!< PRNG Generated Key 1 */ + #define CRPT_PRNG_KEY2 (CRPT_BA+0x018) /*!< PRNG Generated Key 2 */ + #define CRPT_PRNG_KEY3 (CRPT_BA+0x01C) /*!< PRNG Generated Key 3 */ + #define CRPT_PRNG_KEY4 (CRPT_BA+0x020) /*!< PRNG Generated Key 4 */ + #define CRPT_PRNG_KEY5 (CRPT_BA+0x024) /*!< PRNG Generated Key 5 */ + #define CRPT_PRNG_KEY6 (CRPT_BA+0x028) /*!< PRNG Generated Key 6 */ + #define CRPT_PRNG_KEY7 (CRPT_BA+0x02C) /*!< PRNG Generated Key 7 */ + + /* AES/TDES feedback Registers */ + #define CRPT_AES_FDBCK0 (CRPT_BA+0x050) /*!< AES Engine Output Feedback Data after Cryptographic Operation */ + #define CRPT_AES_FDBCK1 (CRPT_BA+0x054) /*!< AES Engine Output Feedback Data after Cryptographic Operation */ + #define CRPT_AES_FDBCK2 (CRPT_BA+0x058) /*!< AES Engine Output Feedback Data after Cryptographic Operation */ + #define CRPT_AES_FDBCK3 (CRPT_BA+0x05C) /*!< AES Engine Output Feedback Data after Cryptographic Operation */ + #define CRPT_TDES_FDBCKH (CRPT_BA+0x060) /*!< TDES/DES Engine Output Feedback High Word Data after Cryptographic Operation */ + #define CRPT_TDES_FDBCKL (CRPT_BA+0x064) /*!< TDES/DES Engine Output Feedback Low Word Data after Cryptographic Operation */ + + /* AES Control Registers */ + #define CRPT_AES_CTL (CRPT_BA+0x100) /*!< AES Control Register */ + #define CRPT_AES_STS (CRPT_BA+0x104) /*!< AES Engine Flag */ + #define CRPT_AES_DATIN (CRPT_BA+0x108) /*!< AES Engine Data Input Port Register */ + #define CRPT_AES_DATOUT (CRPT_BA+0x10C) /*!< AES Engine Data Output Port Register */ + #define CRPT_AES0_KEY0 (CRPT_BA+0x110) /*!< AES Key Word 0 Register for Channel 0 */ + #define CRPT_AES0_KEY1 (CRPT_BA+0x114) /*!< AES Key Word 1 Register for Channel 0 */ + #define CRPT_AES0_KEY2 (CRPT_BA+0x118) /*!< AES Key Word 2 Register for Channel 0 */ + #define CRPT_AES0_KEY3 (CRPT_BA+0x11C) /*!< AES Key Word 3 Register for Channel 0 */ + #define CRPT_AES0_KEY4 (CRPT_BA+0x120) /*!< AES Key Word 4 Register for Channel 0 */ + #define CRPT_AES0_KEY5 (CRPT_BA+0x124) /*!< AES Key Word 5 Register for Channel 0 */ + #define CRPT_AES0_KEY6 (CRPT_BA+0x128) /*!< AES Key Word 6 Register for Channel 0 */ + #define CRPT_AES0_KEY7 (CRPT_BA+0x12C) /*!< AES Key Word 7 Register for Channel 0 */ + #define CRPT_AES0_IV0 (CRPT_BA+0x130) /*!< AES Initial Vector Word 0 Register for Channel 0 */ + #define CRPT_AES0_IV1 (CRPT_BA+0x134) /*!< AES Initial Vector Word 1 Register for Channel 0 */ + #define CRPT_AES0_IV2 (CRPT_BA+0x138) /*!< AES Initial Vector Word 2 Register for Channel 0 */ + #define CRPT_AES0_IV3 (CRPT_BA+0x13C) /*!< AES Initial Vector Word 3 Register for Channel 0 */ + #define CRPT_AES0_SADDR (CRPT_BA+0x140) /*!< AES DMA Source Address Register for Channel 0 */ + #define CRPT_AES0_DADDR (CRPT_BA+0x144) /*!< AES DMA Destination Address Register for Channel 0 */ + #define CRPT_AES0_CNT (CRPT_BA+0x148) /*!< AES Byte Count Register for Channel 0 */ + #define CRPT_AES1_KEY0 (CRPT_BA+0x14C) /*!< AES Key Word 0 Register for Channel 1 */ + #define CRPT_AES1_KEY1 (CRPT_BA+0x150) /*!< AES Key Word 1 Register for Channel 1 */ + #define CRPT_AES1_KEY2 (CRPT_BA+0x154) /*!< AES Key Word 2 Register for Channel 1 */ + #define CRPT_AES1_KEY3 (CRPT_BA+0x158) /*!< AES Key Word 3 Register for Channel 1 */ + #define CRPT_AES1_KEY4 (CRPT_BA+0x15C) /*!< AES Key Word 4 Register for Channel 1 */ + #define CRPT_AES1_KEY5 (CRPT_BA+0x160) /*!< AES Key Word 5 Register for Channel 1 */ + #define CRPT_AES1_KEY6 (CRPT_BA+0x164) /*!< AES Key Word 6 Register for Channel 1 */ + #define CRPT_AES1_KEY7 (CRPT_BA+0x168) /*!< AES Key Word 7 Register for Channel 1 */ + #define CRPT_AES1_IV0 (CRPT_BA+0x16C) /*!< AES Initial Vector Word 0 Register for Channel 1 */ + #define CRPT_AES1_IV1 (CRPT_BA+0x170) /*!< AES Initial Vector Word 1 Register for Channel 1 */ + #define CRPT_AES1_IV2 (CRPT_BA+0x174) /*!< AES Initial Vector Word 2 Register for Channel 1 */ + #define CRPT_AES1_IV3 (CRPT_BA+0x178) /*!< AES Initial Vector Word 3 Register for Channel 1 */ + #define CRPT_AES1_SADDR (CRPT_BA+0x17C) /*!< AES DMA Source Address Register for Channel 1 */ + #define CRPT_AES1_DADDR (CRPT_BA+0x180) /*!< AES DMA Destination Address Register for Channel 1 */ + #define CRPT_AES1_CNT (CRPT_BA+0x184) /*!< AES Byte Count Register for Channel 1 */ + #define CRPT_AES2_KEY0 (CRPT_BA+0x188) /*!< AES Key Word 0 Register for Channel 2 */ + #define CRPT_AES2_KEY1 (CRPT_BA+0x18C) /*!< AES Key Word 1 Register for Channel 2 */ + #define CRPT_AES2_KEY2 (CRPT_BA+0x190) /*!< AES Key Word 2 Register for Channel 2 */ + #define CRPT_AES2_KEY3 (CRPT_BA+0x194) /*!< AES Key Word 3 Register for Channel 2 */ + #define CRPT_AES2_KEY4 (CRPT_BA+0x198) /*!< AES Key Word 4 Register for Channel 2 */ + #define CRPT_AES2_KEY5 (CRPT_BA+0x19C) /*!< AES Key Word 5 Register for Channel 2 */ + #define CRPT_AES2_KEY6 (CRPT_BA+0x1A0) /*!< AES Key Word 6 Register for Channel 2 */ + #define CRPT_AES2_KEY7 (CRPT_BA+0x1A4) /*!< AES Key Word 7 Register for Channel 2 */ + #define CRPT_AES2_IV0 (CRPT_BA+0x1A8) /*!< AES Initial Vector Word 0 Register for Channel 2 */ + #define CRPT_AES2_IV1 (CRPT_BA+0x1AC) /*!< AES Initial Vector Word 1 Register for Channel 2 */ + #define CRPT_AES2_IV2 (CRPT_BA+0x1B0) /*!< AES Initial Vector Word 2 Register for Channel 2 */ + #define CRPT_AES2_IV3 (CRPT_BA+0x1B4) /*!< AES Initial Vector Word 3 Register for Channel 2 */ + #define CRPT_AES2_SADDR (CRPT_BA+0x1B8) /*!< AES DMA Source Address Register for Channel 2 */ + #define CRPT_AES2_DADDR (CRPT_BA+0x1BC) /*!< AES DMA Destination Address Register for Channel 2 */ + #define CRPT_AES2_CNT (CRPT_BA+0x1C0) /*!< AES Byte Count Register for Channel 2 */ + #define CRPT_AES3_KEY0 (CRPT_BA+0x1C4) /*!< AES Key Word 0 Register for Channel 3 */ + #define CRPT_AES3_KEY1 (CRPT_BA+0x1C8) /*!< AES Key Word 1 Register for Channel 3 */ + #define CRPT_AES3_KEY2 (CRPT_BA+0x1CC) /*!< AES Key Word 2 Register for Channel 3 */ + #define CRPT_AES3_KEY3 (CRPT_BA+0x1D0) /*!< AES Key Word 3 Register for Channel 3 */ + #define CRPT_AES3_KEY4 (CRPT_BA+0x1D4) /*!< AES Key Word 4 Register for Channel 3 */ + #define CRPT_AES3_KEY5 (CRPT_BA+0x1D8) /*!< AES Key Word 5 Register for Channel 3 */ + #define CRPT_AES3_KEY6 (CRPT_BA+0x1DC) /*!< AES Key Word 6 Register for Channel 3 */ + #define CRPT_AES3_KEY7 (CRPT_BA+0x1E0) /*!< AES Key Word 7 Register for Channel 3 */ + #define CRPT_AES3_IV0 (CRPT_BA+0x1E4) /*!< AES Initial Vector Word 0 Register for Channel 3 */ + #define CRPT_AES3_IV1 (CRPT_BA+0x1E8) /*!< AES Initial Vector Word 1 Register for Channel 3 */ + #define CRPT_AES3_IV2 (CRPT_BA+0x1EC) /*!< AES Initial Vector Word 2 Register for Channel 3 */ + #define CRPT_AES3_IV3 (CRPT_BA+0x1F0) /*!< AES Initial Vector Word 3 Register for Channel 3 */ + #define CRPT_AES3_SADDR (CRPT_BA+0x1F4) /*!< AES DMA Source Address Register for Channel 3 */ + #define CRPT_AES3_DADDR (CRPT_BA+0x1F8) /*!< AES DMA Destination Address Register for Channel 3 */ + #define CRPT_AES3_CNT (CRPT_BA+0x1FC) /*!< AES Byte Count Register for Channel 3 */ + + /* DES/TDES Control Registers */ + #define CRPT_TDES_CTL (CRPT_BA+0x200) /*!< TDES/DES Control Register */ + #define CRPT_TDES_STS (CRPT_BA+0x204) /*!< TDES/DES Engine Flag */ + #define CRPT_TDES0_KEY1H (CRPT_BA+0x208) /*!< TDES/DES Key 1 High Word Register for Channel 0 */ + #define CRPT_TDES0_KEY1L (CRPT_BA+0x20C) /*!< TDES/DES Key 1 Low Word Register for Channel 0 */ + #define CRPT_TDES0_KEY2H (CRPT_BA+0x210) /*!< TDES/DES Key 2 High Word Register for Channel 0 */ + #define CRPT_TDES0_KEY2L (CRPT_BA+0x214) /*!< TDES/DES Key 2 Low Word Register for Channel 0 */ + #define CRPT_TDES0_KEY3H (CRPT_BA+0x218) /*!< TDES/DES Key 3 High Word Register for Channel 0 */ + #define CRPT_TDES0_KEY3L (CRPT_BA+0x21C) /*!< TDES/DES Key 3 Low Word Register for Channel 0 */ + #define CRPT_TDES0_IVH (CRPT_BA+0x220) /*!< TDES/DES Initial Vector High Word Register for Channel 0 */ + #define CRPT_TDES0_IVL (CRPT_BA+0x224) /*!< TDES/DES Initial Vector Low Word Register for Channel 0 */ + #define CRPT_TDES0_SADDR (CRPT_BA+0x228) /*!< TDES/DES DMA Source Address Register for Channel 0 */ + #define CRPT_TDES0_DADDR (CRPT_BA+0x22C) /*!< TDES/DES DMA Destination Address Register for Channel 0 */ + #define CRPT_TDES0_CNT (CRPT_BA+0x230) /*!< TDES/DES Byte Count Register for Channel 0 */ + #define CRPT_TDES_DATIN (CRPT_BA+0x234) /*!< TDES/DES Engine Input data Word Register */ + #define CRPT_TDES_DATOUT (CRPT_BA+0x238) /*!< TDES/DES Engine Output data Word Register */ + #define CRPT_TDES1_KEY1H (CRPT_BA+0x248) /*!< TDES/DES Key 1 High Word Register for Channel 1 */ + #define CRPT_TDES1_KEY1L (CRPT_BA+0x24C) /*!< TDES/DES Key 1 Low Word Register for Channel 1 */ + #define CRPT_TDES1_KEY2H (CRPT_BA+0x250) /*!< TDES/DES Key 2 High Word Register for Channel 1 */ + #define CRPT_TDES1_KEY2L (CRPT_BA+0x254) /*!< TDES/DES Key 2 Low Word Register for Channel 1 */ + #define CRPT_TDES1_KEY3H (CRPT_BA+0x258) /*!< TDES/DES Key 3 High Word Register for Channel 1 */ + #define CRPT_TDES1_KEY3L (CRPT_BA+0x25C) /*!< TDES/DES Key 3 Low Word Register for Channel 1 */ + #define CRPT_TDES1_IVH (CRPT_BA+0x260) /*!< TDES/DES Initial Vector High Word Register for Channel 1 */ + #define CRPT_TDES1_IVL (CRPT_BA+0x264) /*!< TDES/DES Initial Vector Low Word Register for Channel 1 */ + #define CRPT_TDES1_SADDR (CRPT_BA+0x268) /*!< TDES/DES DMA Source Address Register for Channel 1 */ + #define CRPT_TDES1_DADDR (CRPT_BA+0x26C) /*!< TDES/DES DMA Destination Address Register for Channel 1 */ + #define CRPT_TDES1_CNT (CRPT_BA+0x270) /*!< TDES/DES Byte Count Register for Channel 1 */ + #define CRPT_TDES2_KEY1H (CRPT_BA+0x288) /*!< TDES/DES Key 1 High Word Register for Channel 2 */ + #define CRPT_TDES2_KEY1L (CRPT_BA+0x28C) /*!< TDES/DES Key 1 Low Word Register for Channel 2 */ + #define CRPT_TDES2_KEY2H (CRPT_BA+0x290) /*!< TDES/DES Key 2 High Word Register for Channel 2 */ + #define CRPT_TDES2_KEY2L (CRPT_BA+0x294) /*!< TDES/DES Key 2 Low Word Register for Channel 2 */ + #define CRPT_TDES2_KEY3H (CRPT_BA+0x298) /*!< TDES/DES Key 3 High Word Register for Channel 2 */ + #define CRPT_TDES2_KEY3L (CRPT_BA+0x29C) /*!< TDES/DES Key 3 Low Word Register for Channel 2 */ + #define CRPT_TDES2_IVH (CRPT_BA+0x2A0) /*!< TDES/DES Initial Vector High Word Register for Channel 2 */ + #define CRPT_TDES2_IVL (CRPT_BA+0x2A4) /*!< TDES/DES Initial Vector Low Word Register for Channel 2 */ + #define CRPT_TDES2_SADDR (CRPT_BA+0x2A8) /*!< TDES/DES DMA Source Address Register for Channel 2 */ + #define CRPT_TDES2_DADDR (CRPT_BA+0x2AC) /*!< TDES/DES DMA Destination Address Register for Channel 2 */ + #define CRPT_TDES2_CNT (CRPT_BA+0x2B0) /*!< TDES/DES Byte Count Register for Channel 3 */ + #define CRPT_TDES3_KEY1H (CRPT_BA+0x2C8) /*!< TDES/DES Key 1 High Word Register for Channel 3 */ + #define CRPT_TDES3_KEY1L (CRPT_BA+0x2CC) /*!< TDES/DES Key 1 Low Word Register for Channel 3 */ + #define CRPT_TDES3_KEY2H (CRPT_BA+0x2D0) /*!< TDES/DES Key 2 High Word Register for Channel 3 */ + #define CRPT_TDES3_KEY2L (CRPT_BA+0x2D4) /*!< TDES/DES Key 2 Low Word Register for Channel 3 */ + #define CRPT_TDES3_KEY3H (CRPT_BA+0x2D8) /*!< TDES/DES Key 3 High Word Register for Channel 3 */ + #define CRPT_TDES3_KEY3L (CRPT_BA+0x2DC) /*!< TDES/DES Key 3 Low Word Register for Channel 3 */ + #define CRPT_TDES3_IVH (CRPT_BA+0x2E0) /*!< TDES/DES Initial Vector High Word Register for Channel 3 */ + #define CRPT_TDES3_IVL (CRPT_BA+0x2E4) /*!< TDES/DES Initial Vector Low Word Register for Channel 3 */ + #define CRPT_TDES3_SADDR (CRPT_BA+0x2E8) /*!< TDES/DES DMA Source Address Register for Channel 3 */ + #define CRPT_TDES3_DADDR (CRPT_BA+0x2EC) /*!< TDES/DES DMA Destination Address Register for Channel 3 */ + #define CRPT_TDES3_CNT (CRPT_BA+0x2F0) /*!< TDES/DES Byte Count Register for Channel 3 */ + + /* SHA/HMAC Control Registers */ + #define CRPT_HMAC_CTL (CRPT_BA+0x300) /*!< SHA/HMAC Control Register */ + #define CRPT_HMAC_STS (CRPT_BA+0x304) /*!< SHA/HMAC Status Flag */ + #define CRPT_HMAC_DGST0 (CRPT_BA+0x308) /*!< SHA/HMAC Digest Message 0 */ + #define CRPT_HMAC_DGST1 (CRPT_BA+0x30C) /*!< SHA/HMAC Digest Message 1 */ + #define CRPT_HMAC_DGST2 (CRPT_BA+0x310) /*!< SHA/HMAC Digest Message 2 */ + #define CRPT_HMAC_DGST3 (CRPT_BA+0x314) /*!< SHA/HMAC Digest Message 3 */ + #define CRPT_HMAC_DGST4 (CRPT_BA+0x318) /*!< SHA/HMAC Digest Message 4 */ + #define CRPT_HMAC_DGST5 (CRPT_BA+0x31C) /*!< SHA/HMAC Digest Message 5 */ + #define CRPT_HMAC_DGST6 (CRPT_BA+0x320) /*!< SHA/HMAC Digest Message 6 */ + #define CRPT_HMAC_DGST7 (CRPT_BA+0x324) /*!< SHA/HMAC Digest Message 7 */ + #define CRPT_HMAC_DGST8 (CRPT_BA+0x328) /*!< SHA/HMAC Digest Message 8 */ + #define CRPT_HMAC_DGST9 (CRPT_BA+0x32C) /*!< SHA/HMAC Digest Message 8 */ + #define CRPT_HMAC_DGST10 (CRPT_BA+0x330) /*!< SHA/HMAC Digest Message 10 */ + #define CRPT_HMAC_DGST11 (CRPT_BA+0x334) /*!< SHA/HMAC Digest Message 11 */ + #define CRPT_HMAC_DGST12 (CRPT_BA+0x338) /*!< SHA/HMAC Digest Message 12 */ + #define CRPT_HMAC_DGST13 (CRPT_BA+0x33C) /*!< SHA/HMAC Digest Message 13 */ + #define CRPT_HMAC_DGST14 (CRPT_BA+0x340) /*!< SHA/HMAC Digest Message 14 */ + #define CRPT_HMAC_DGST15 (CRPT_BA+0x344) /*!< SHA/HMAC Digest Message 15 */ + #define CRPT_HMAC_KEYCNT (CRPT_BA+0x348) /*!< SHA/HMAC Key Byte Count */ + #define CRPT_HMAC_SADDR (CRPT_BA+0x34C) /*!< SHA/HMAC Key Byte Count */ + #define CRPT_HMAC_DMACNT (CRPT_BA+0x350) /*!< SHA/HMAC Byte Count Register */ + #define CRPT_HMAC_DATIN (CRPT_BA+0x354) /*!< SHA/HMAC Engine Non-DMA Mode Data Input Port Register */ + + /**@}*/ /* end of Cryptographic Accelerator register group */ + + + + + /*---------------------- Universal Asynchronous Receiver/Transmitter Controller -------------------------*/ + /** + @addtogroup UART Universal Asynchronous Receiver/Transmitter Controller(UART) + Memory Mapped Structure for UART Controller + @{ */ + + #define REG_UART0_RBR (UART0_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART0_THR (UART0_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART0_IER (UART0_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART0_FCR (UART0_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART0_LCR (UART0_BA+0x0C) /*!< Line Control Register */ + #define REG_UART0_MCR (UART0_BA+0x10) /*!< Modem Control Register */ + #define REG_UART0_MSR (UART0_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART0_FSR (UART0_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART0_ISR (UART0_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART0_TOR (UART0_BA+0x20) /*!< Time-out Register */ + #define REG_UART0_BAUD (UART0_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART0_IRCR (UART0_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART0_ALT_CSR (UART0_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART0_FUN_SEL (UART0_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART0_LIN_CTL (UART0_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART0_LIN_SR (UART0_BA+0x38) /*!< LIN Status Register */ + + + + + /* + UART1 Control Registers + */ + #define REG_UART1_RBR (UART1_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART1_THR (UART1_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART1_IER (UART1_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART1_FCR (UART1_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART1_LCR (UART1_BA+0x0C) /*!< Line Control Register */ + #define REG_UART1_MCR (UART1_BA+0x10) /*!< Modem Control Register */ + #define REG_UART1_MSR (UART1_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART1_FSR (UART1_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART1_ISR (UART1_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART1_TOR (UART1_BA+0x20) /*!< Time-out Register */ + #define REG_UART1_BAUD (UART1_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART1_IRCR (UART1_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART1_ALT_CSR (UART1_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART1_FUN_SEL (UART1_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART1_LIN_CTL (UART1_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART1_LIN_SR (UART1_BA+0x38) /*!< LIN Status Register */ + + /* + UART2 Control Registers + */ + #define REG_UART2_RBR (UART2_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART2_THR (UART2_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART2_IER (UART2_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART2_FCR (UART2_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART2_LCR (UART2_BA+0x0C) /*!< Line Control Register */ + #define REG_UART2_MCR (UART2_BA+0x10) /*!< Modem Control Register */ + #define REG_UART2_MSR (UART2_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART2_FSR (UART2_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART2_ISR (UART2_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART2_TOR (UART2_BA+0x20) /*!< Time-out Register */ + #define REG_UART2_BAUD (UART2_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART2_IRCR (UART2_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART2_ALT_CSR (UART2_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART2_FUN_SEL (UART2_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART2_LIN_CTL (UART2_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART2_LIN_SR (UART2_BA+0x38) /*!< LIN Status Register */ + + /* + UART3 Control Registers + */ + #define REG_UART3_RBR (UART3_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART3_THR (UART3_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART3_IER (UART3_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART3_FCR (UART3_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART3_LCR (UART3_BA+0x0C) /*!< Line Control Register */ + #define REG_UART3_MCR (UART3_BA+0x10) /*!< Modem Control Register */ + #define REG_UART3_MSR (UART3_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART3_FSR (UART3_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART3_ISR (UART3_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART3_TOR (UART3_BA+0x20) /*!< Time-out Register */ + #define REG_UART3_BAUD (UART3_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART3_IRCR (UART3_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART3_ALT_CSR (UART3_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART3_FUN_SEL (UART3_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART3_LIN_CTL (UART3_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART3_LIN_SR (UART3_BA+0x38) /*!< LIN Status Register */ + + + /* + UART4 Control Registers + */ + #define REG_UART4_RBR (UART4_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART4_THR (UART4_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART4_IER (UART4_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART4_FCR (UART4_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART4_LCR (UART4_BA+0x0C) /*!< Line Control Register */ + #define REG_UART4_MCR (UART4_BA+0x10) /*!< Modem Control Register */ + #define REG_UART4_MSR (UART4_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART4_FSR (UART4_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART4_ISR (UART4_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART4_TOR (UART4_BA+0x20) /*!< Time-out Register */ + #define REG_UART4_BAUD (UART4_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART4_IRCR (UART4_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART4_ALT_CSR (UART4_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART4_FUN_SEL (UART4_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART4_LIN_CTL (UART4_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART4_LIN_SR (UART4_BA+0x38) /*!< LIN Status Register */ + + /* + UART5 Control Registers + */ + #define REG_UART5_RBR (UART5_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART5_THR (UART5_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART5_IER (UART5_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART5_FCR (UART5_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART5_LCR (UART5_BA+0x0C) /*!< Line Control Register */ + #define REG_UART5_MCR (UART5_BA+0x10) /*!< Modem Control Register */ + #define REG_UART5_MSR (UART5_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART5_FSR (UART5_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART5_ISR (UART5_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART5_TOR (UART5_BA+0x20) /*!< Time-out Register */ + #define REG_UART5_BAUD (UART5_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART5_IRCR (UART5_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART5_ALT_CSR (UART5_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART5_FUN_SEL (UART5_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART5_LIN_CTL (UART5_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART5_LIN_SR (UART5_BA+0x38) /*!< LIN Status Register */ + + /* + UART6 Control Registers + */ + #define REG_UART6_RBR (UART6_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART6_THR (UART6_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART6_IER (UART6_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART6_FCR (UART6_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART6_LCR (UART6_BA+0x0C) /*!< Line Control Register */ + #define REG_UART6_MCR (UART6_BA+0x10) /*!< Modem Control Register */ + #define REG_UART6_MSR (UART6_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART6_FSR (UART6_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART6_ISR (UART6_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART6_TOR (UART6_BA+0x20) /*!< Time-out Register */ + #define REG_UART6_BAUD (UART6_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART6_IRCR (UART6_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART6_ALT_CSR (UART6_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART6_FUN_SEL (UART6_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART6_LIN_CTL (UART6_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART6_LIN_SR (UART6_BA+0x38) /*!< LIN Status Register */ + + /* + UART7 Control Registers + */ + #define REG_UART7_RBR (UART7_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART7_THR (UART7_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART7_IER (UART7_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART7_FCR (UART7_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART7_LCR (UART7_BA+0x0C) /*!< Line Control Register */ + #define REG_UART7_MCR (UART7_BA+0x10) /*!< Modem Control Register */ + #define REG_UART7_MSR (UART7_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART7_FSR (UART7_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART7_ISR (UART7_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART7_TOR (UART7_BA+0x20) /*!< Time-out Register */ + #define REG_UART7_BAUD (UART7_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART7_IRCR (UART7_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART7_ALT_CSR (UART7_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART7_FUN_SEL (UART7_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART7_LIN_CTL (UART7_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART7_LIN_SR (UART7_BA+0x38) /*!< LIN Status Register */ + + /* + UART8 Control Registers + */ + #define REG_UART8_RBR (UART8_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART8_THR (UART8_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART8_IER (UART8_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART8_FCR (UART8_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART8_LCR (UART8_BA+0x0C) /*!< Line Control Register */ + #define REG_UART8_MCR (UART8_BA+0x10) /*!< Modem Control Register */ + #define REG_UART8_MSR (UART8_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART8_FSR (UART8_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART8_ISR (UART8_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART8_TOR (UART8_BA+0x20) /*!< Time-out Register */ + #define REG_UART8_BAUD (UART8_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART8_IRCR (UART8_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART8_ALT_CSR (UART8_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART8_FUN_SEL (UART8_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART8_LIN_CTL (UART8_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART8_LIN_SR (UART8_BA+0x38) /*!< LIN Status Register */ + + /* + UART9 Control Registers + */ + #define REG_UART9_RBR (UART9_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UART9_THR (UART9_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UART9_IER (UART9_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UART9_FCR (UART9_BA+0x08) /*!< FIFO Control Register */ + #define REG_UART9_LCR (UART9_BA+0x0C) /*!< Line Control Register */ + #define REG_UART9_MCR (UART9_BA+0x10) /*!< Modem Control Register */ + #define REG_UART9_MSR (UART9_BA+0x14) /*!< MODEM Status Register */ + #define REG_UART9_FSR (UART9_BA+0x18) /*!< FIFO Status Register */ + #define REG_UART9_ISR (UART9_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UART9_TOR (UART9_BA+0x20) /*!< Time-out Register */ + #define REG_UART9_BAUD (UART9_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UART9_IRCR (UART9_BA+0x28) /*!< IrDA Control Register */ + #define REG_UART9_ALT_CSR (UART9_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UART9_FUN_SEL (UART9_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UART9_LIN_CTL (UART9_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UART9_LIN_SR (UART9_BA+0x38) /*!< LIN Status Register */ + + /* + UARTA Control Registers + */ + #define REG_UARTA_RBR (UARTA_BA+0x00) /*!< Receive Buffer Register */ + #define REG_UARTA_THR (UARTA_BA+0x00) /*!< Transmit Holding Register */ + #define REG_UARTA_IER (UARTA_BA+0x04) /*!< Interrupt Enable Register */ + #define REG_UARTA_FCR (UARTA_BA+0x08) /*!< FIFO Control Register */ + #define REG_UARTA_LCR (UARTA_BA+0x0C) /*!< Line Control Register */ + #define REG_UARTA_MCR (UARTA_BA+0x10) /*!< Modem Control Register */ + #define REG_UARTA_MSR (UARTA_BA+0x14) /*!< MODEM Status Register */ + #define REG_UARTA_FSR (UARTA_BA+0x18) /*!< FIFO Status Register */ + #define REG_UARTA_ISR (UARTA_BA+0x1C) /*!< Interrupt Status Control Register */ + #define REG_UARTA_TOR (UARTA_BA+0x20) /*!< Time-out Register */ + #define REG_UARTA_BAUD (UARTA_BA+0x24) /*!< Baud Rate Divider Register */ + #define REG_UARTA_IRCR (UARTA_BA+0x28) /*!< IrDA Control Register */ + #define REG_UARTA_ALT_CSR (UARTA_BA+0x2C) /*!< Alternate Control Register */ + #define REG_UARTA_FUN_SEL (UARTA_BA+0x30) /*!< UART Function Select REgister */ + #define REG_UARTA_LIN_CTL (UARTA_BA+0x34) /*!< UART LIN Control Register */ + #define REG_UARTA_LIN_SR (UARTA_BA+0x38) /*!< LIN Status Register */ + + + /**@}*/ /* end of UART register group */ + + + /*---------------------- Timer Controller -------------------------*/ + /** + @addtogroup TIMER Timer Controller(TIMER) + Memory Mapped Structure for TIMER Controller + @{ */ + + #define REG_TMR0_CSR (TMR0_BA+0x00) /*!< Timer Control and Status Register 0 */ + #define REG_TMR0_CMPR (TMR0_BA+0x04) /*!< Timer Compare Register 0 */ + #define REG_TMR0_DR (TMR0_BA+0x08) /*!< Timer Data Register 0 */ + + #define REG_TMR1_CSR (TMR1_BA+0x00) /*!< Timer Control and Status Register 1 */ + #define REG_TMR1_CMPR (TMR1_BA+0x04) /*!< Timer Compare Register 1 */ + #define REG_TMR1_TDR (TMR1_BA+0x08) /*!< Timer Data Register 1 */ + + #define REG_TMR2_CSR (TMR2_BA+0x00) /*!< Timer Control and Status Register 2 */ + #define REG_TMR2_CMPR (TMR2_BA+0x04) /*!< Timer Compare Register 2 */ + #define REG_TMR2_DR (TMR2_BA+0x08) /*!< Timer Data Register 2 */ + + #define REG_TMR3_CSR (TMR3_BA+0x00) /*!< Timer Control and Status Register 3 */ + #define REG_TMR3_CMPR (TMR3_BA+0x04) /*!< Timer Compare Register 3 */ + #define REG_TMR3_DR (TMR3_BA+0x08) /*!< Timer Data Register 3 */ + + #define REG_TMR4_CSR (TMR4_BA+0x00) /*!< Timer Control and Status Register 4 */ + #define REG_TMR4_CMPR (TMR4_BA+0x04) /*!< Timer Compare Register 4 */ + #define REG_TMR4_DR (TMR4_BA+0x08) /*!< Timer Data Register 4 */ + + #define REG_TMR_ISR (TMR0_BA+0x60) /*!< Timer Interrupt Status Register */ + + /**@}*/ /* end of TIMER register group */ + + /*---------------------- Enhance Timer Controller -------------------------*/ + /** + @addtogroup ETIMER Enhance Timer Controller(ETIMER) + Memory Mapped Structure for TIMER Controller + @{ */ + + #define REG_ETMR0_CTL (ETMR0_BA+0x00) /*!< Enhance Timer 0 Control Register */ + #define REG_ETMR0_PRECNT (ETMR0_BA+0x04) /*!< Enhance Timer 0 Pre-Scale Counter Register */ + #define REG_ETMR0_CMPR (ETMR0_BA+0x08) /*!< Enhance Timer 0 Compare Register */ + #define REG_ETMR0_IER (ETMR0_BA+0x0C) /*!< Enhance Timer 0 Interrupt Enable Register */ + #define REG_ETMR0_ISR (ETMR0_BA+0x10) /*!< Enhance Timer 0 Interrupt Status Register */ + #define REG_ETMR0_DR (ETMR0_BA+0x14) /*!< Enhance Timer 0 Data Register */ + #define REG_ETMR0_TCAP (ETMR0_BA+0x18) /*!< Enhance Timer 0 Capture Data Register */ + + #define REG_ETMR1_CTL (ETMR1_BA+0x00) /*!< Enhance Timer 1 Control Register */ + #define REG_ETMR1_PRECNT (ETMR1_BA+0x04) /*!< Enhance Timer 1 Pre-Scale Counter Register */ + #define REG_ETMR1_CMPR (ETMR1_BA+0x08) /*!< Enhance Timer 1 Compare Register */ + #define REG_ETMR1_IER (ETMR1_BA+0x0C) /*!< Enhance Timer 1 Interrupt Enable Register */ + #define REG_ETMR1_ISR (ETMR1_BA+0x10) /*!< Enhance Timer 1 Interrupt Status Register */ + #define REG_ETMR1_DR (ETMR1_BA+0x14) /*!< Enhance Timer 1 Data Register */ + #define REG_ETMR1_TCAP (ETMR1_BA+0x18) /*!< Enhance Timer 1 Capture Data Register */ + + #define REG_ETMR2_CTL (ETMR2_BA+0x00) /*!< Enhance Timer 2 Control Register */ + #define REG_ETMR2_PRECNT (ETMR2_BA+0x04) /*!< Enhance Timer 2 Pre-Scale Counter Register */ + #define REG_ETMR2_CMPR (ETMR2_BA+0x08) /*!< Enhance Timer 2 Compare Register */ + #define REG_ETMR2_IER (ETMR2_BA+0x0C) /*!< Enhance Timer 2 Interrupt Enable Register */ + #define REG_ETMR2_ISR (ETMR2_BA+0x10) /*!< Enhance Timer 2 Interrupt Status Register */ + #define REG_ETMR2_DR (ETMR2_BA+0x14) /*!< Enhance Timer 2 Data Register */ + #define REG_ETMR2_TCAP (ETMR2_BA+0x18) /*!< Enhance Timer 2 Capture Data Register */ + + #define REG_ETMR3_CTL (ETMR3_BA+0x00) /*!< Enhance Timer 3 Control Register */ + #define REG_ETMR3_PRECNT (ETMR3_BA+0x04) /*!< Enhance Timer 3 Pre-Scale Counter Register */ + #define REG_ETMR3_CMPR (ETMR3_BA+0x08) /*!< Enhance Timer 3 Compare Register */ + #define REG_ETMR3_IER (ETMR3_BA+0x0C) /*!< Enhance Timer 3 Interrupt Enable Register */ + #define REG_ETMR3_ISR (ETMR3_BA+0x10) /*!< Enhance Timer 3 Interrupt Status Register */ + #define REG_ETMR3_DR (ETMR3_BA+0x14) /*!< Enhance Timer 3 Data Register */ + #define REG_ETMR3_TCAP (ETMR3_BA+0x18) /*!< Enhance Timer 3 Capture Data Register */ + /**@}*/ /* end of ETIMER register group */ + + /*---------------------- WDT Controller -------------------------*/ + /** + @addtogroup WDT Watch Dog Timer Controller(WDT) + Memory Mapped Structure for WDT Controller + @{ */ + + #define REG_WDT_CTL (WDT_BA+0x00) /*!< WDT Control Register */ + #define REG_WDT_ALTCTL (WDT_BA+0x04) /*!< WDT Alternative Control Register */ + + /**@}*/ /* end of WDT register group */ + + /*---------------------- WWDT Controller -------------------------*/ + /** + @addtogroup WWDT Window Watch Dog Timer Controller(WWDT) + Memory Mapped Structure for WWDT Controller + @{ */ + + #define REG_WWDT_RLDCNT (WWDT_BA+0x00) /*!< WWDT Reload Counter Register */ + #define REG_WWDT_CTL (WWDT_BA+0x04) /*!< WWDT Control Register */ + #define REG_WWDT_STATUS (WWDT_BA+0x08) /*!< WWDT Status Register */ + #define REG_WWDT_CNT (WWDT_BA+0x0C) /*!< WWDT Counter Value Register */ + + /**@}*/ /* end of WWDT register group */ + + /*---------------------- SC Host Interface -------------------------*/ + /** + @addtogroup SC Smart Card Host Interface (SC) + Memory Mapped Structure for Smart Card Host Interface + @{ */ + + #define REG_SC0_DAT (SC0_BA+0x00) /*!< SC0 Receiving/Transmit Holding Buffer Register */ + #define REG_SC0_CTL (SC0_BA+0x04) /*!< SC0 Control Register */ + #define REG_SC0_ALTCTL (SC0_BA+0x08) /*!< SC0 Alternate Control Register */ + #define REG_SC0_EGT (SC0_BA+0x0C) /*!< SC0 Extend Guard Time Register */ + #define REG_SC0_RXTOUT (SC0_BA+0x10) /*!< SC0 Receive Buffer Time-out Register */ + #define REG_SC0_ETUCTL (SC0_BA+0x14) /*!< SC0 ETU Control Register */ + #define REG_SC0_INTEN (SC0_BA+0x18) /*!< SC0 Interrupt Enable Control Register */ + #define REG_SC0_INTSTS (SC0_BA+0x1C) /*!< SC0 Interrupt Status Register */ + #define REG_SC0_STATUS (SC0_BA+0x20) /*!< SC0 Status Register */ + #define REG_SC0_PINCTL (SC0_BA+0x24) /*!< SC0 Pin Control State Register */ + #define REG_SC0_TMRCTL0 (SC0_BA+0x28) /*!< SC0 Internal Timer Control Register 0 */ + #define REG_SC0_TMRCTL1 (SC0_BA+0x2C) /*!< SC0 Internal Timer Control Register 1 */ + #define REG_SC0_TMRCTL2 (SC0_BA+0x30) /*!< SC0 Internal Timer Control Register 2 */ + #define REG_SC0_UARTCTL (SC0_BA+0x34) /*!< SC0 UART Mode Control Register */ + #define REG_SC0_TMRDAT0 (SC0_BA+0x38) /*!< SC0 Timer Current Data Register 0 */ + #define REG_SC0_TMRDAT1 (SC0_BA+0x3C) /*!< SC0 Timer Current Data Register 1 */ + + #define REG_SC1_DAT (SC1_BA+0x00) /*!< SC1 Receiving/Transmit Holding Buffer Register */ + #define REG_SC1_CTL (SC1_BA+0x04) /*!< SC1 Control Register */ + #define REG_SC1_ALTCTL (SC1_BA+0x08) /*!< SC1 Alternate Control Register */ + #define REG_SC1_EGT (SC1_BA+0x0C) /*!< SC1 Extend Guard Time Register */ + #define REG_SC1_RXTOUT (SC1_BA+0x10) /*!< SC1 Receive Buffer Time-out Register */ + #define REG_SC1_ETUCTL (SC1_BA+0x14) /*!< SC1 ETU Control Register */ + #define REG_SC1_INTEN (SC1_BA+0x18) /*!< SC1 Interrupt Enable Control Register */ + #define REG_SC1_INTSTS (SC1_BA+0x1C) /*!< SC1 Interrupt Status Register */ + #define REG_SC1_STATUS (SC1_BA+0x20) /*!< SC1 Status Register */ + #define REG_SC1_PINCTL (SC1_BA+0x24) /*!< SC1 Pin Control State Register */ + #define REG_SC1_TMRCTL0 (SC1_BA+0x28) /*!< SC1 Internal Timer Control Register 0 */ + #define REG_SC1_TMRCTL1 (SC1_BA+0x2C) /*!< SC1 Internal Timer Control Register 1 */ + #define REG_SC1_TMRCTL2 (SC1_BA+0x30) /*!< SC1 Internal Timer Control Register 2 */ + #define REG_SC1_UARTCTL (SC1_BA+0x34) /*!< SC1 UART Mode Control Register */ + #define REG_SC1_TMRDAT0 (SC1_BA+0x38) /*!< SC1 Timer Current Data Register 0 */ + #define REG_SC1_TMRDAT1 (SC1_BA+0x3C) /*!< SC1 Timer Current Data Register 1 */ + + /**@}*/ /* end of SC register group */ + + + /*---------------------- Advance Interrupt Controller -------------------------*/ + /** + @addtogroup AIC Advance Interrupt Controller(AIC) + Memory Mapped Structure for AIC Controller + @{ */ + + #define REG_AIC_SCR1 (AIC_BA+0x00) /*!< Source control register 1 */ + #define REG_AIC_SCR2 (AIC_BA+0x04) /*!< Source control register 2 */ + #define REG_AIC_SCR3 (AIC_BA+0x08) /*!< Source control register 3 */ + #define REG_AIC_SCR4 (AIC_BA+0x0C) /*!< Source control register 4 */ + #define REG_AIC_SCR5 (AIC_BA+0x10) /*!< Source control register 5 */ + #define REG_AIC_SCR6 (AIC_BA+0x14) /*!< Source control register 6 */ + #define REG_AIC_SCR7 (AIC_BA+0x18) /*!< Source control register 7 */ + #define REG_AIC_SCR8 (AIC_BA+0x1C) /*!< Source control register 8 */ + #define REG_AIC_SCR9 (AIC_BA+0x20) /*!< Source control register 9 */ + #define REG_AIC_SCR10 (AIC_BA+0x24) /*!< Source control register 10 */ + #define REG_AIC_SCR11 (AIC_BA+0x28) /*!< Source control register 11 */ + #define REG_AIC_SCR12 (AIC_BA+0x2C) /*!< Source control register 12 */ + #define REG_AIC_SCR13 (AIC_BA+0x30) /*!< Source control register 13 */ + #define REG_AIC_SCR14 (AIC_BA+0x34) /*!< Source control register 14 */ + #define REG_AIC_SCR15 (AIC_BA+0x38) /*!< Source control register 15 */ + #define REG_AIC_SCR16 (AIC_BA+0x3C) /*!< Source control register 16 */ + #define REG_AIC_IRSR (AIC_BA+0x100) /*!< Interrupt raw status register */ + #define REG_AIC_IRSRH (AIC_BA+0x104) /*!< Interrupt raw status register (Hign) */ + #define REG_AIC_IASR (AIC_BA+0x108) /*!< Interrupt active status register */ + #define REG_AIC_IASRH (AIC_BA+0x10C) /*!< Interrupt active status register (Hign) */ + #define REG_AIC_ISR (AIC_BA+0x110) /*!< Interrupt status register */ + #define REG_AIC_ISRH (AIC_BA+0x114) /*!< Interrupt status register (High) */ + #define REG_AIC_IPER (AIC_BA+0x118) /*!< Interrupt priority encoding register */ + #define REG_AIC_ISNR (AIC_BA+0x120) /*!< Interrupt source number register */ + #define REG_AIC_OISR (AIC_BA+0x124) /*!< Output interrupt status register */ + #define REG_AIC_IMR (AIC_BA+0x128) /*!< Interrupt mask register */ + #define REG_AIC_IMRH (AIC_BA+0x12C) /*!< Interrupt mask register (High) */ + #define REG_AIC_MECR (AIC_BA+0x130) /*!< Mask enable command register */ + #define REG_AIC_MECRH (AIC_BA+0x134) /*!< Mask enable command register (High) */ + #define REG_AIC_MDCR (AIC_BA+0x138) /*!< Mask disable command register */ + #define REG_AIC_MDCRH (AIC_BA+0x13C) /*!< Mask disable command register (High) */ + #define REG_AIC_SSCR (AIC_BA+0x140) /*!< Source Set Command Register */ + #define REG_AIC_SSCRH (AIC_BA+0x144) /*!< Source Set Command Register (High) */ + #define REG_AIC_SCCR (AIC_BA+0x148) /*!< Source Clear Command Register */ + #define REG_AIC_SCCRH (AIC_BA+0x14C) /*!< Source Clear Command Register (High) */ + #define REG_AIC_EOSCR (AIC_BA+0x150) /*!< End of service command register */ + + /**@}*/ /* end of AIC register group */ + + + /*---------------------- General Purpose Input/Output Controller -------------------------*/ + /** + @addtogroup GPIO General Purpose Input/Output Controller(GPIO) + Memory Mapped Structure for GPIO Controller + @{ */ + + #define REG_GPIOA_DIR (GPIO_BA+0x000) /*!< GPIO portA direction control register */ + #define REG_GPIOA_DATAOUT (GPIO_BA+0x004) /*!< GPIO portA data output register */ + #define REG_GPIOA_DATAIN (GPIO_BA+0x008) /*!< GPIO portA data input register */ + #define REG_GPIOA_IMD (GPIO_BA+0x00C) /*!< GPIO Port A Interrupt Mode Register */ + #define REG_GPIOA_IREN (GPIO_BA+0x010) /*!< GPIO Port A Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOA_IFEN (GPIO_BA+0x014) /*!< GPIO Port A Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOA_ISR (GPIO_BA+0x018) /*!< GPIO Port A Interrupt Status Register */ + #define REG_GPIOA_DBEN (GPIO_BA+0x01C) /*!< GPIO Port A De-bounce Enable Register */ + #define REG_GPIOA_PUEN (GPIO_BA+0x020) /*!< GPIO Port A Pull-Up Enable Register */ + #define REG_GPIOA_PDEN (GPIO_BA+0x024) /*!< GPIO Port A Pull-Down Enable Register */ + #define REG_GPIOA_ICEN (GPIO_BA+0x028) /*!< GPIO Port A CMOS Input Enable Register */ + #define REG_GPIOA_ISEN (GPIO_BA+0x02C) /*!< GPIO Port A Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOB_DIR (GPIO_BA+0x040) /*!< GPIO port B direction control register */ + #define REG_GPIOB_DATAOUT (GPIO_BA+0x044) /*!< GPIO port B data output register */ + #define REG_GPIOB_DATAIN (GPIO_BA+0x048) /*!< GPIO port B data input register */ + #define REG_GPIOB_IMD (GPIO_BA+0x04C) /*!< GPIO Port B Interrupt Mode Register */ + #define REG_GPIOB_IREN (GPIO_BA+0x050) /*!< GPIO Port B Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOB_IFEN (GPIO_BA+0x054) /*!< GPIO Port B Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOB_ISR (GPIO_BA+0x058) /*!< GPIO Port B Interrupt Status Register */ + #define REG_GPIOB_DBEN (GPIO_BA+0x05C) /*!< GPIO Port B De-bounce Enable Register */ + #define REG_GPIOB_PUEN (GPIO_BA+0x060) /*!< GPIO Port B Pull-Up Enable Register */ + #define REG_GPIOB_PDEN (GPIO_BA+0x064) /*!< GPIO Port B Pull-Down Enable Register */ + #define REG_GPIOB_ICEN (GPIO_BA+0x068) /*!< GPIO Port B CMOS Input Enable Register */ + #define REG_GPIOB_ISEN (GPIO_BA+0x06C) /*!< GPIO Port B Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOC_DIR (GPIO_BA+0x080) /*!< GPIO port C direction control register */ + #define REG_GPIOC_DATAOUT (GPIO_BA+0x084) /*!< GPIO port C data output register */ + #define REG_GPIOC_DATAIN (GPIO_BA+0x088) /*!< GPIO port C data input register */ + #define REG_GPIOC_IMD (GPIO_BA+0x08C) /*!< GPIO Port C Interrupt Mode Register */ + #define REG_GPIOC_IREN (GPIO_BA+0x090) /*!< GPIO Port C Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOC_IFEN (GPIO_BA+0x094) /*!< GPIO Port C Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOC_ISR (GPIO_BA+0x098) /*!< GPIO Port C Interrupt Status Register */ + #define REG_GPIOC_DBEN (GPIO_BA+0x09C) /*!< GPIO Port C De-bounce Enable Register */ + #define REG_GPIOC_PUEN (GPIO_BA+0x0A0) /*!< GPIO Port C Pull-Up Enable Register */ + #define REG_GPIOC_PDEN (GPIO_BA+0x0A4) /*!< GPIO Port C Pull-Down Enable Register */ + #define REG_GPIOC_ICEN (GPIO_BA+0x0A8) /*!< GPIO Port C CMOS Input Enable Register */ + #define REG_GPIOC_ISEN (GPIO_BA+0x0AC) /*!< GPIO Port C Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOD_DIR (GPIO_BA+0x0C0) /*!< GPIO port D direction control register */ + #define REG_GPIOD_DATAOUT (GPIO_BA+0x0C4) /*!< GPIO port D data output register */ + #define REG_GPIOD_DATAIN (GPIO_BA+0x0C8) /*!< GPIO port D data input register */ + #define REG_GPIOD_IMD (GPIO_BA+0x0CC) /*!< GPIO Port D Interrupt Mode Register */ + #define REG_GPIOD_IREN (GPIO_BA+0x0D0) /*!< GPIO Port D Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOD_IFEN (GPIO_BA+0x0D4) /*!< GPIO Port D Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOD_ISR (GPIO_BA+0x0D8) /*!< GPIO Port D Interrupt Status Register */ + #define REG_GPIOD_DBEN (GPIO_BA+0x0DC) /*!< GPIO Port D De-bounce Enable Register */ + #define REG_GPIOD_PUEN (GPIO_BA+0x0E0) /*!< GPIO Port D Pull-Up Enable Register */ + #define REG_GPIOD_PDEN (GPIO_BA+0x0E4) /*!< GPIO Port D Pull-Down Enable Register */ + #define REG_GPIOD_ICEN (GPIO_BA+0x0E8) /*!< GPIO Port D CMOS Input Enable Register */ + #define REG_GPIOD_ISEN (GPIO_BA+0x0EC) /*!< GPIO Port D Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOE_DIR (GPIO_BA+0x100) /*!< GPIO port E direction control register */ + #define REG_GPIOE_DATAOUT (GPIO_BA+0x104) /*!< GPIO port E data output register */ + #define REG_GPIOE_DATAIN (GPIO_BA+0x108) /*!< GPIO port E data input register */ + #define REG_GPIOE_IMD (GPIO_BA+0x10C) /*!< GPIO Port E Interrupt Mode Register */ + #define REG_GPIOE_IREN (GPIO_BA+0x110) /*!< GPIO Port E Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOE_IFEN (GPIO_BA+0x114) /*!< GPIO Port E Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOE_ISR (GPIO_BA+0x118) /*!< GPIO Port E Interrupt Status Register */ + #define REG_GPIOE_DBEN (GPIO_BA+0x11C) /*!< GPIO Port E De-bounce Enable Register */ + #define REG_GPIOE_PUEN (GPIO_BA+0x120) /*!< GPIO Port E Pull-Up Enable Register */ + #define REG_GPIOE_PDEN (GPIO_BA+0x124) /*!< GPIO Port E Pull-Down Enable Register */ + #define REG_GPIOE_ICEN (GPIO_BA+0x128) /*!< GPIO Port E CMOS Input Enable Register */ + #define REG_GPIOE_ISEN (GPIO_BA+0x12C) /*!< GPIO Port E Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOF_DIR (GPIO_BA+0x140) /*!< GPIO port F direction control register */ + #define REG_GPIOF_DATAOUT (GPIO_BA+0x144) /*!< GPIO port F data output register */ + #define REG_GPIOF_DATAIN (GPIO_BA+0x148) /*!< GPIO port F data input register */ + #define REG_GPIOF_IMD (GPIO_BA+0x14C) /*!< GPIO Port F Interrupt Mode Register */ + #define REG_GPIOF_IREN (GPIO_BA+0x150) /*!< GPIO Port F Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOF_IFEN (GPIO_BA+0x154) /*!< GPIO Port F Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOF_ISR (GPIO_BA+0x158) /*!< GPIO Port F Interrupt Status Register */ + #define REG_GPIOF_DBEN (GPIO_BA+0x15C) /*!< GPIO Port F De-bounce Enable Register */ + #define REG_GPIOF_PUEN (GPIO_BA+0x160) /*!< GPIO Port F Pull-Up Enable Register */ + #define REG_GPIOF_PDEN (GPIO_BA+0x164) /*!< GPIO Port F Pull-Down Enable Register */ + #define REG_GPIOF_ICEN (GPIO_BA+0x168) /*!< GPIO Port F CMOS Input Enable Register */ + #define REG_GPIOF_ISEN (GPIO_BA+0x16C) /*!< GPIO Port F Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOG_DIR (GPIO_BA+0x180) /*!< GPIO port G direction control register */ + #define REG_GPIOG_DATAOUT (GPIO_BA+0x184) /*!< GPIO port G data output register */ + #define REG_GPIOG_DATAIN (GPIO_BA+0x188) /*!< GPIO port G data input register */ + #define REG_GPIOG_IMD (GPIO_BA+0x18C) /*!< GPIO Port G Interrupt Mode Register */ + #define REG_GPIOG_IREN (GPIO_BA+0x190) /*!< GPIO Port G Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOG_IFEN (GPIO_BA+0x194) /*!< GPIO Port G Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOG_ISR (GPIO_BA+0x198) /*!< GPIO Port G Interrupt Status Register */ + #define REG_GPIOG_DBEN (GPIO_BA+0x19C) /*!< GPIO Port G De-bounce Enable Register */ + #define REG_GPIOG_PUEN (GPIO_BA+0x1A0) /*!< GPIO Port G Pull-Up Enable Register */ + #define REG_GPIOG_PDEN (GPIO_BA+0x1A4) /*!< GPIO Port G Pull-Down Enable Register */ + #define REG_GPIOG_ICEN (GPIO_BA+0x1A8) /*!< GPIO Port G CMOS Input Enable Register */ + #define REG_GPIOG_ISEN (GPIO_BA+0x1AC) /*!< GPIO Port G Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOH_DIR (GPIO_BA+0x1C0) /*!< GPIO port H direction control register */ + #define REG_GPIOH_DATAOUT (GPIO_BA+0x1C4) /*!< GPIO port H data output register */ + #define REG_GPIOH_DATAIN (GPIO_BA+0x1C8) /*!< GPIO port H data input register */ + #define REG_GPIOH_IMD (GPIO_BA+0x1CC) /*!< GPIO Port H Interrupt Mode Register */ + #define REG_GPIOH_IREN (GPIO_BA+0x1D0) /*!< GPIO Port H Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOH_IFEN (GPIO_BA+0x1D4) /*!< GPIO Port H Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOH_ISR (GPIO_BA+0x1D8) /*!< GPIO Port H Interrupt Status Register */ + #define REG_GPIOH_DBEN (GPIO_BA+0x1DC) /*!< GPIO Port H De-bounce Enable Register */ + #define REG_GPIOH_PUEN (GPIO_BA+0x1E0) /*!< GPIO Port H Pull-Up Enable Register */ + #define REG_GPIOH_PDEN (GPIO_BA+0x1E4) /*!< GPIO Port H Pull-Down Enable Register */ + #define REG_GPIOH_ICEN (GPIO_BA+0x1E8) /*!< GPIO Port H CMOS Input Enable Register */ + #define REG_GPIOH_ISEN (GPIO_BA+0x1EC) /*!< GPIO Port H Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOI_DIR (GPIO_BA+0x200) /*!< GPIO port I direction control register */ + #define REG_GPIOI_DATAOUT (GPIO_BA+0x204) /*!< GPIO port I data output register */ + #define REG_GPIOI_DATAIN (GPIO_BA+0x208) /*!< GPIO port I data input register */ + #define REG_GPIOI_IMD (GPIO_BA+0x20C) /*!< GPIO Port I Interrupt Mode Register */ + #define REG_GPIOI_IREN (GPIO_BA+0x210) /*!< GPIO Port I Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOI_IFEN (GPIO_BA+0x214) /*!< GPIO Port I Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOI_ISR (GPIO_BA+0x218) /*!< GPIO Port I Interrupt Status Register */ + #define REG_GPIOI_DBEN (GPIO_BA+0x21C) /*!< GPIO Port I De-bounce Enable Register */ + #define REG_GPIOI_PUEN (GPIO_BA+0x220) /*!< GPIO Port I Pull-Up Enable Register */ + #define REG_GPIOI_PDEN (GPIO_BA+0x224) /*!< GPIO Port I Pull-Down Enable Register */ + #define REG_GPIOI_ICEN (GPIO_BA+0x228) /*!< GPIO Port I CMOS Input Enable Register */ + #define REG_GPIOI_ISEN (GPIO_BA+0x22C) /*!< GPIO Port I Schmitt-Trigger Input Enable Register */ + + #define REG_GPIOJ_DIR (GPIO_BA+0x240) /*!< GPIO port J direction control register */ + #define REG_GPIOJ_DATAOUT (GPIO_BA+0x244) /*!< GPIO port J data output register */ + #define REG_GPIOJ_DATAIN (GPIO_BA+0x248) /*!< GPIO port J data input register */ + #define REG_GPIOJ_IMD (GPIO_BA+0x24C) /*!< GPIO Port J Interrupt Mode Register */ + #define REG_GPIOJ_IREN (GPIO_BA+0x250) /*!< GPIO Port J Interrupt Rising-Edge or Level-High Enable Register */ + #define REG_GPIOJ_IFEN (GPIO_BA+0x254) /*!< GPIO Port J Interrupt Falling-Edge or Level-Low Enable Register */ + #define REG_GPIOJ_ISR (GPIO_BA+0x258) /*!< GPIO Port J Interrupt Status Register */ + #define REG_GPIOJ_DBEN (GPIO_BA+0x25C) /*!< GPIO Port J De-bounce Enable Register */ + #define REG_GPIOJ_PUEN (GPIO_BA+0x260) /*!< GPIO Port J Pull-Up Enable Register */ + #define REG_GPIOJ_PDEN (GPIO_BA+0x264) /*!< GPIO Port J Pull-Down Enable Register */ + #define REG_GPIOJ_ICEN (GPIO_BA+0x268) /*!< GPIO Port J CMOS Input Enable Register */ + #define REG_GPIOJ_ISEN (GPIO_BA+0x26C) /*!< GPIO Port J Schmitt-Trigger Input Enable Register */ + + #define REG_GPIO_DBNCECON (GPIO_BA+0x3F0) /*!< GPIO Debounce Control Register */ + #define REG_GPIO_ISR (GPIO_BA+0x3FC) /*!< GPIO Port Interrupt Status Register */ + + /**@}*/ /* end of GPIO register group */ + + + /*---------------------- Real Time Clock Controller -------------------------*/ + /** + @addtogroup RTC Real Time Clock Controller(RTC) + Memory Mapped Structure for RTC Controller + @{ */ + + #define REG_RTC_INIT (RTC_BA+0x00) /*!< RTC Initiation Register */ + #define REG_RTC_RWEN (RTC_BA+0x04) /*!< RTC Access Enable Register */ + #define REG_RTC_FREQADJ (RTC_BA+0x08) /*!< RTC Frequency Compensation Register */ + #define REG_RTC_TIME (RTC_BA+0x0C) /*!< Time Loading Register */ + #define REG_RTC_CAL (RTC_BA+0x10) /*!< Calendar Loading Register */ + #define REG_RTC_TIMEFMT (RTC_BA+0x14) /*!< Time Format Selection Register */ + #define REG_RTC_WEEKDAY (RTC_BA+0x18) /*!< Day of the Week Register */ + #define REG_RTC_TALM (RTC_BA+0x1C) /*!< Time Alarm Register */ + #define REG_RTC_CALM (RTC_BA+0x20) /*!< Calendar Alarm Register */ + #define REG_RTC_LEAPYEAR (RTC_BA+0x24) /*!< Leap year Indicator Register */ + #define REG_RTC_INTEN (RTC_BA+0x28) /*!< RTC Interrupt Enable Register */ + #define REG_RTC_INTSTS (RTC_BA+0x2C) /*!< RTC Interrupt Indicator Register */ + #define REG_RTC_TICK (RTC_BA+0x30) /*!< RTC Time Tick Register */ + #define REG_RTC_PWRCTL (RTC_BA+0x34) /*!< Power Control Register */ + #define REG_RTC_PWRCNT (RTC_BA+0x38) /*!< Power Control Counter Register */ + #define REG_RTC_SPR0 (RTC_BA+0x40) /*!< Spare REgistger 0 */ + #define REG_RTC_SPR1 (RTC_BA+0x44) /*!< Spare REgistger 1 */ + #define REG_RTC_SPR2 (RTC_BA+0x48) /*!< Spare REgistger 2 */ + #define REG_RTC_SPR3 (RTC_BA+0x4C) /*!< Spare REgistger 3 */ + #define REG_RTC_SPR4 (RTC_BA+0x50) /*!< Spare REgistger 4 */ + #define REG_RTC_SPR5 (RTC_BA+0x54) /*!< Spare REgistger 5 */ + #define REG_RTC_SPR6 (RTC_BA+0x58) /*!< Spare REgistger 6 */ + #define REG_RTC_SPR7 (RTC_BA+0x5C) /*!< Spare REgistger 7 */ + #define REG_RTC_SPR8 (RTC_BA+0x60) /*!< Spare REgistger 8 */ + #define REG_RTC_SPR9 (RTC_BA+0x64) /*!< Spare REgistger 9 */ + #define REG_RTC_SPR10 (RTC_BA+0x68) /*!< Spare REgistger 10 */ + #define REG_RTC_SPR11 (RTC_BA+0x6C) /*!< Spare REgistger 11 */ + #define REG_RTC_SPR12 (RTC_BA+0x70) /*!< Spare REgistger 12 */ + #define REG_RTC_SPR13 (RTC_BA+0x74) /*!< Spare REgistger 13 */ + #define REG_RTC_SPR14 (RTC_BA+0x78) /*!< Spare REgistger 14 */ + #define REG_RTC_SPR15 (RTC_BA+0x7C) /*!< Spare REgistger 15 */ + + /**@}*/ /* end of RTC register group */ + + /*---------------------- Inter-IC Bus Controller -------------------------*/ + /** + @addtogroup I2C Inter-IC Bus Controller(I2C) + Memory Mapped Structure for I2C Controller + @{ */ + + #define REG_I2C0_CSR (I2C0_BA+0x00) /*!< Control and Status Register */ + #define REG_I2C0_DIVIDER (I2C0_BA+0x04) /*!< Clock Prescale Register */ + #define REG_I2C0_CMDR (I2C0_BA+0x08) /*!< Command Register */ + #define REG_I2C0_SWR (I2C0_BA+0x0C) /*!< Software Mode Control Register */ + #define REG_I2C0_RXR (I2C0_BA+0x10) /*!< Data Receive Register */ + #define REG_I2C0_TXR (I2C0_BA+0x14) /*!< Data Transmit Register */ + + #define REG_I2C1_CSR (I2C1_BA+0x00) /*!< Control and Status Register */ + #define REG_I2C1_DIVIDER (I2C1_BA+0x04) /*!< Clock Prescale Register */ + #define REG_I2C1_CMDR (I2C1_BA+0x08) /*!< Command Register */ + #define REG_I2C1_SWR (I2C1_BA+0x0C) /*!< Software Mode Control Register */ + #define REG_I2C1_RXR (I2C1_BA+0x10) /*!< Data Receive Register */ + #define REG_I2C1_TXR (I2C1_BA+0x14) /*!< Data Transmit Register */ + + /**@}*/ /* end of I2C register group */ + + + /*---------------------- Serial Peripheral Interface Controller -------------------------*/ + /** + @addtogroup SPI Serial Peripheral Interface Controller(SPI) + Memory Mapped Structure for SPI Controller + @{ */ + + #define REG_SPI0_CNTRL (SPI0_BA+0x00) /*!< Control and Status Register */ + #define REG_SPI0_DIVIDER (SPI0_BA+0x04) /*!< Clock Divider Register */ + #define REG_SPI0_SSR (SPI0_BA+0x08) /*!< Slave Select Register */ + #define REG_SPI0_RX0 (SPI0_BA+0x10) /*!< Data Receive Register 0 */ + #define REG_SPI0_RX1 (SPI0_BA+0x14) /*!< Data Receive Register 1 */ + #define REG_SPI0_RX2 (SPI0_BA+0x18) /*!< Data Receive Register 2 */ + #define REG_SPI0_RX3 (SPI0_BA+0x1C) /*!< Data Receive Register 3 */ + #define REG_SPI0_TX0 (SPI0_BA+0x10) /*!< Data Transmit Register 0 */ + #define REG_SPI0_TX1 (SPI0_BA+0x14) /*!< Data Transmit Register 1 */ + #define REG_SPI0_TX2 (SPI0_BA+0x18) /*!< Data Transmit Register 2 */ + #define REG_SPI0_TX3 (SPI0_BA+0x1C) /*!< Data Transmit Register 3 */ + + #define REG_SPI1_CNTRL (SPI1_BA+0x00) /*!< Control and Status Register */ + #define REG_SPI1_DIVIDER (SPI1_BA+0x04) /*!< Clock Divider Register */ + #define REG_SPI1_SSR (SPI1_BA+0x08) /*!< Slave Select Register */ + #define REG_SPI1_RX0 (SPI1_BA+0x10) /*!< Data Receive Register 0 */ + #define REG_SPI1_RX1 (SPI1_BA+0x14) /*!< Data Receive Register 1 */ + #define REG_SPI1_RX2 (SPI1_BA+0x18) /*!< Data Receive Register 2 */ + #define REG_SPI1_RX3 (SPI1_BA+0x1C) /*!< Data Receive Register 3 */ + #define REG_SPI1_TX0 (SPI1_BA+0x10) /*!< Data Transmit Register 0 */ + #define REG_SPI1_TX1 (SPI1_BA+0x14) /*!< Data Transmit Register 1 */ + #define REG_SPI1_TX2 (SPI1_BA+0x18) /*!< Data Transmit Register 2 */ + #define REG_SPI1_TX3 (SPI1_BA+0x1C) /*!< Data Transmit Register 3 */ + + /**@}*/ /* end of SPI register group */ + + + /*---------------------- Pulse Width Modulation Controller -------------------------*/ + /** + @addtogroup PWM Pulse Width Modulation Controller(PWM) + Memory Mapped Structure for PWM Controller + @{ */ + + #define REG_PWM_PPR (PWM_BA+0x00) /*!< PWM Pre-scale Register 0 */ + #define REG_PWM_CSR (PWM_BA+0x04) /*!< PWM Clock Select Register */ + #define REG_PWM_PCR (PWM_BA+0x08) /*!< PWM Control Register */ + #define REG_PWM_CNR0 (PWM_BA+0x0C) /*!< PWM Counter Register 0 */ + #define REG_PWM_CMR0 (PWM_BA+0x10) /*!< PWM Comparator Register 0 */ + #define REG_PWM_PDR0 (PWM_BA+0x14) /*!< PWM Data Register 0 */ + #define REG_PWM_CNR1 (PWM_BA+0x18) /*!< PWM Counter Register 1 */ + #define REG_PWM_CMR1 (PWM_BA+0x1C) /*!< PWM Comparator Register 1 */ + #define REG_PWM_PDR1 (PWM_BA+0x20) /*!< PWM Data Register 1 */ + #define REG_PWM_CNR2 (PWM_BA+0x24) /*!< PWM Counter Register 2 */ + #define REG_PWM_CMR2 (PWM_BA+0x28) /*!< PWM Comparator Register 2 */ + #define REG_PWM_PDR2 (PWM_BA+0x2C) /*!< PWM Data Register 2 */ + #define REG_PWM_CNR3 (PWM_BA+0x30) /*!< PWM Counter Register 3 */ + #define REG_PWM_CMR3 (PWM_BA+0x34) /*!< PWM Comparator Register 3 */ + #define REG_PWM_PDR3 (PWM_BA+0x38) /*!< PWM Data Register 3 */ + #define REG_PWM_PIER (PWM_BA+0x3C) /*!< PWM Timer Interrupt Enable Register */ + #define REG_PWM_PIIR (PWM_BA+0x40) /*!< PWM Timer Interrupt Identification Register */ + + /**@}*/ /* end of PWM register group */ + + + /*---------------------- Analog to Digital Converter -------------------------*/ + /** + @addtogroup ADC Analog to Digital Converter(ADC) + Memory Mapped Structure for ADC Controller + @{ */ + + #define REG_ADC_CTL (ADC_BA+0x000) /*!< ADC Contrl */ + #define REG_ADC_CONF (ADC_BA+0x004) /*!< ADC Configure */ + #define REG_ADC_IER (ADC_BA+0x008) /*!< ADC Interrupt Enable Register */ + #define REG_ADC_ISR (ADC_BA+0x00C) /*!< ADC Interrupt Status Register */ + #define REG_ADC_WKISR (ADC_BA+0x010) /*!< ADC Wake Up Interrupt Status Register */ + #define REG_ADC_XYDATA (ADC_BA+0x020) /*!< ADC Touch XY Pressure Data */ + #define REG_ADC_ZDATA (ADC_BA+0x024) /*!< ADC Touch Z Pressure Data */ + #define REG_ADC_DATA (ADC_BA+0x028) /*!< ADC Normal Conversion Data */ + #define REG_ADC_VBADATA (ADC_BA+0x02C) /*!< ADC Battery Detection Data */ + #define REG_ADC_KPDATA (ADC_BA+0x030) /*!< ADC Key Pad Data */ + #define REG_ADC_SELFDATA (ADC_BA+0x034) /*!< ADC Self-Test Data */ + #define REG_ADC_XYSORT0 (ADC_BA+0x1F4) /*!< ADC Touch XY Position Mean Value Sort 0 */ + #define REG_ADC_XYSORT1 (ADC_BA+0x1F8) /*!< ADC Touch XY Position Mean Value Sort 1 */ + #define REG_ADC_XYSORT2 (ADC_BA+0x1FC) /*!< ADC Touch XY Position Mean Value Sort 2 */ + #define REG_ADC_XYSORT3 (ADC_BA+0x200) /*!< ADC Touch XY Position Mean Value Sort 3 */ + #define REG_ADC_ZSORT0 (ADC_BA+0x204) /*!< ADC Touch Z Pressure Mean Value Sort 0 */ + #define REG_ADC_ZSORT1 (ADC_BA+0x208) /*!< ADC Touch Z Pressure Mean Value Sort 1 */ + #define REG_ADC_ZSORT2 (ADC_BA+0x20C) /*!< ADC Touch Z Pressure Mean Value Sort 2 */ + #define REG_ADC_ZSORT3 (ADC_BA+0x210) /*!< ADC Touch Z Pressure Mean Value Sort 3 */ + #define REG_ADC_MTMULCK (ADC_BA+0x220) /*!< ADC Manual Test Mode Unlock */ + #define REG_ADC_MTCONF (ADC_BA+0x224) /*!< ADC Manual Test Mode Configure */ + #define REG_ADC_MTCON (ADC_BA+0x228) /*!< ADC Manual Test Mode Control */ + #define REG_ADC_ADCAII (ADC_BA+0x22C) /*!< ADC Analog Interface Information */ + #define REG_ADC_ADCAIIRLT (ADC_BA+0x230) /*!< ADC Analog Interface Information Result */ + + /**@}*/ /* end of ADC register group */ + + /*------------------ Capture Sensor Interface Controller ---------------------*/ + /** + @addtogroup CAP Capture Sensor Interface Controller(CAP) + Memory Mapped Structure for CAP Controller + @{ */ + + #define REG_CAP_CTL (CAP_BA+0x000) /*!< Image Capture Interface Control Register */ + #define REG_CAP_PAR (CAP_BA+0x004) /*!< Image Capture Interface Parameter Register */ + #define REG_CAP_INT (CAP_BA+0x008) /*!< Image Capture Interface Interrupt Registe */ + #define REG_CAP_POSTERIZE (CAP_BA+0x00C) /*!< YUV Component Posterizing Factor Register */ + #define REG_CAP_MD (CAP_BA+0x010) /*!< Motion Detection Register */ + #define REG_CAP_MDADDR (CAP_BA+0x014) /*!< Motion Detection Output Address Register */ + #define REG_CAP_MDYADDR (CAP_BA+0x018) /*!< Motion Detection Temp YOutput Address Register */ + #define REG_CAP_SEPIA (CAP_BA+0x01C) /*!< Sepia Effect Control Register */ + #define REG_CAP_CWSP (CAP_BA+0x020) /*!< Cropping Window Starting Address Register */ + #define REG_CAP_CWS (CAP_BA+0x024) /*!< Cropping Window Size Register */ + #define REG_CAP_PKTSL (CAP_BA+0x028) /*!< Packet Scaling Vertical/Horizontal Factor Register (LSB) */ + #define REG_CAP_PLNSL (CAP_BA+0x02C) /*!< Planar Scaling Vertical/Horizontal Factor Register (LSB) */ + #define REG_CAP_FRCTL (CAP_BA+0x030) /*!< Scaling Frame Rate Factor Register */ + #define REG_CAP_STRIDE (CAP_BA+0x034) /*!< Frame Output Pixel Stride Register */ + #define REG_CAP_FIFOTH (CAP_BA+0x03C) /*!< FIFO threshold Register */ + #define REG_CAP_CMPADDR (CAP_BA+0x040) /*!< Compare Packet Memory Base Address Register */ + #define REG_CAP_PKTSM (CAP_BA+0x048) /*!< Packet Scaling Vertical/Horizontal Factor Register (MSB) */ + #define REG_CAP_PLNSM (CAP_BA+0x04C) /*!< Planar Scaling Vertical/Horizontal Factor Register (MSB) */ + #define REG_CAP_CURADDRP (CAP_BA+0x050) /*!< Current Packet System Memory Address Register */ + #define REG_CAP_CURADDRY (CAP_BA+0x054) /*!< Current Planar Y System Memory Address Register */ + #define REG_CAP_CURADDRU (CAP_BA+0x058) /*!< Current Planar U System Memory Address Register */ + #define REG_CAP_CURADDRV (CAP_BA+0x05C) /*!< Current Planar V System Memory Address Register */ + #define REG_CAP_PKTBA0 (CAP_BA+0x060) /*!< System Memory Packet Base Address Register */ + #define REG_CAP_PKTBA1 (CAP_BA+0x064) /*!< System Memory Packet Base Address Register */ + #define REG_CAP_YBA (CAP_BA+0x080) /*!< System Memory Planar Y Base Address Register */ + #define REG_CAP_UBA (CAP_BA+0x084) /*!< System Memory Planar U Base Address Register */ + #define REG_CAP_VBA (CAP_BA+0x088) /*!< System Memory Planar V Base Address Register */ + + /**@}*/ /* end of CAP register group */ + + /*------------------ SDRAM Interface Controller ---------------------*/ + /** + @addtogroup SDIC SDRAM Interface Controller(SDIC) + Memory Mapped Structure for SDIC Controller + @{ */ + + #define REG_SDIC_OPMCTL (SDIC_BA+0x000) /*!< SDRAM Controller Operation Mode Control Register */ + #define REG_SDIC_CMD (SDIC_BA+0x004) /*!< SDRAM Command Register */ + #define REG_SDIC_REFCTL (SDIC_BA+0x008) /*!< SDRAM Controller Refresh Control Register */ + #define REG_SDIC_SIZE0 (SDIC_BA+0x010) /*!< SDRAM 0 Size Register */ + #define REG_SDIC_SIZE1 (SDIC_BA+0x014) /*!< SDRAM 1 Size Register */ + #define REG_SDIC_MR (SDIC_BA+0x018) /*!< SDRAM Mode Register */ + #define REG_SDIC_EMR (SDIC_BA+0x01C) /*!< SDRAM Extended Mode Register */ + #define REG_SDIC_EMR2 (SDIC_BA+0x020) /*!< SDRAM Extended Mode Register 2 */ + #define REG_SDIC_EMR3 (SDIC_BA+0x024) /*!< SDRAM Extended Mode Register 3 */ + #define REG_SDIC_TIME (SDIC_BA+0x028) /*!< SDRAM Timing Control Register */ + #define REG_SDIC_DQSODS (SDIC_BA+0x030) /*!< DQS Output Delay Selection Register */ + #define REG_SDIC_CKDQSDS (SDIC_BA+0x034) /*!< Clock and DQS Delay Selection Register */ + #define REG_SDIC_DAENSEL (SDIC_BA+0x038) /*!< Data Latch Enable Selection Register */ + + /**@}*/ /* end of SDIC register group */ + + /*---------------------- Controller Area Network -------------------------*/ + /** + @addtogroup CAN Controller Area Network(CAN) + Memory Mapped Structure for CAN Controller + @{ */ + + #define REG_CAN0_CON (CAN0_BA+0x00) /*!< Control Register */ + #define REG_CAN0_STATUS (CAN0_BA+0x04) /*!< Status Register */ + #define REG_CAN0_ERR (CAN0_BA+0x08) /*!< Error Counter Register */ + #define REG_CAN0_BTIME (CAN0_BA+0x0C) /*!< Bit Time Register */ + #define REG_CAN0_IIDR (CAN0_BA+0x10) /*!< Interrupt Identifier Register */ + #define REG_CAN0_TEST (CAN0_BA+0x14) /*!< Test Register */ + #define REG_CAN0_BRPE (CAN0_BA+0x18) /*!< BRP Extension Register */ + #define REG_CAN0_IF1_CREQ (CAN0_BA+0x20) /*!< IF1 Command Request Register */ + #define REG_CAN0_IF2_CREQ (CAN0_BA+0x80) /*!< IF2 Command Request Register */ + #define REG_CAN0_IF1_CMASK (CAN0_BA+0x24) /*!< IF1 Command Mask Register */ + #define REG_CAN0_IF2_CMASK (CAN0_BA+0x84) /*!< IF2 Command Mask Register */ + #define REG_CAN0_IF1_MASK1 (CAN0_BA+0x28) /*!< IF1 Msak 1 Register */ + #define REG_CNA0_IF2_MASK1 (CAN0_BA+0x88) /*!< IF2 Mask 1 Register */ + #define REG_CAN0_IF1_MASK2 (CAN0_BA+0x2C) /*!< IF1 Mask 2 Register */ + #define REG_CAN0_IF2_MASK2 (CAN0_BA+0x8C) /*!< IF2 Mask 2 REgister */ + #define REG_CAN0_IF1_ARB1 (CAN0_BA+0x30) /*!< IF1 Arbitration 1 Register */ + #define REG_CAN0_IF2_ARB1 (CAN0_BA+0x90) /*!< IF2 Arbitration 1 Register */ + #define REG_CAN0_IF1_ARB2 (CAN0_BA+0x34) /*!< IF1 Arbitration 2 Register */ + #define REG_CAN0_IF2_ARB2 (CAN0_BA+0x94) /*!< IF2 Arbitration 2 Register */ + #define REG_CAN0_IF1_MCON (CAN0_BA+0x38) /*!< IF1 Message Control Register */ + #define REG_CAN0_IF2_MCON (CAN0_BA+0x98) /*!< IF2 Message Control Register */ + #define REG_CAN0_IF1_DAT_A1 (CAN0_BA+0x3C) /*!< IF1 Data A1 Register */ + #define REG_CAN0_IF1_DAT_A2 (CAN0_BA+0x40) /*!< IF1 Data A2 Register */ + #define REG_CAN0_IF1_DAT_B1 (CAN0_BA+0x44) /*!< IF1 Data B1 Register */ + #define REG_CAN0_IF1_DAT_B2 (CAN0_BA+0x48) /*!< IF1 Data B2 Register */ + #define REG_CAN0_IF2_DAT_A1 (CAN0_BA+0x9C) /*!< IF2 Data A1 Register */ + #define REG_CAN0_IF2_DAT_A2 (CAN0_BA+0xA0) /*!< IF2 Data A2 Register */ + #define REG_CAN0_IF2_DAT_B1 (CAN0_BA+0xA4) /*!< IF2 Data B1 Register */ + #define REG_CAN0_IF2_DAT_B2 (CAN0_BA+0xA8) /*!< IF2 Data B2 Register */ + #define REG_CAN0_TXREQ1 (CAN0_BA+0x100) /*!< Transmission Request Register 1 */ + #define REG_CAN0_TXREQ2 (CAN0_BA+0x104) /*!< Transmission Request Register 2 */ + #define REG_CAN0_NDAT1 (CAN0_BA+0x120) /*!< New Data Register 1 */ + #define REG_CAN0_NDAT2 (CAN0_BA+0x124) /*!< New Data Register 2 */ + #define REG_CAN0_IPND1 (CAN0_BA+0x140) /*!< Interrupt Pending Register 1 */ + #define REG_CAN0_IPND2 (CAN0_BA+0x142) /*!< Interrupt Pending Register 2 */ + #define REG_CAN0_MVLD1 (CAN0_BA+0x160) /*!< Message Valid Register 1 */ + #define REG_CAN0_MVLD2 (CAN0_BA+0x164) /*!< Message Valid Register 2 */ + #define REG_CAN0_WU_EN (CAN0_BA+0x168) /*!< Wake-up Function Enable */ + #define REG_CAN0_WU_STATUS (CAN0_BA+0x16C) /*!< Wake-up Function Status */ + + #define REG_CAN1_CON (CAN1_BA+0x00) /*!< Control Register */ + #define REG_CAN1_STATUS (CAN1_BA+0x04) /*!< Status Register */ + #define REG_CAN1_ERR (CAN1_BA+0x08) /*!< Error Counter Register */ + #define REG_CAN1_BTIME (CAN1_BA+0x0C) /*!< Bit Time Register */ + #define REG_CAN1_IIDR (CAN1_BA+0x10) /*!< Interrupt Identifier Register */ + #define REG_CAN1_TEST (CAN1_BA+0x14) /*!< Test Register */ + #define REG_CAN1_BRPE (CAN1_BA+0x18) /*!< BRP Extension Register */ + #define REG_CAN1_IF1_CREQ (CAN1_BA+0x20) /*!< IF1 Command Request Register */ + #define REG_CAN1_IF2_CREQ (CAN1_BA+0x80) /*!< IF2 Command Request Register */ + #define REG_CAN1_IF1_CMASK (CAN1_BA+0x24) /*!< IF1 Command Mask Register */ + #define REG_CAN1_IF2_CMASK (CAN1_BA+0x84) /*!< IF2 Command Mask Register */ + #define REG_CAN1_IF1_MASK1 (CAN1_BA+0x28) /*!< IF1 Msak 1 Register */ + #define REG_CNA1_IF2_MASK1 (CAN1_BA+0x88) /*!< IF2 Mask 1 Register */ + #define REG_CAN1_IF1_MASK2 (CAN1_BA+0x2C) /*!< IF1 Mask 2 Register */ + #define REG_CAN1_IF2_MASK2 (CAN1_BA+0x8C) /*!< IF2 Mask 2 REgister */ + #define REG_CAN1_IF1_ARB1 (CAN1_BA+0x30) /*!< IF1 Arbitration 1 Register */ + #define REG_CAN1_IF2_ARB1 (CAN1_BA+0x90) /*!< IF2 Arbitration 1 Register */ + #define REG_CAN1_IF1_ARB2 (CAN1_BA+0x34) /*!< IF1 Arbitration 2 Register */ + #define REG_CAN1_IF2_ARB2 (CAN1_BA+0x94) /*!< IF2 Arbitration 2 Register */ + #define REG_CAN1_IF1_MCON (CAN1_BA+0x38) /*!< IF1 Message Control Register */ + #define REG_CAN1_IF2_MCON (CAN1_BA+0x98) /*!< IF2 Message Control Register */ + #define REG_CAN1_IF1_DAT_A1 (CAN1_BA+0x3C) /*!< IF1 Data A1 Register */ + #define REG_CAN1_IF1_DAT_A2 (CAN1_BA+0x40) /*!< IF1 Data A2 Register */ + #define REG_CAN1_IF1_DAT_B1 (CAN1_BA+0x44) /*!< IF1 Data B1 Register */ + #define REG_CAN1_IF1_DAT_B2 (CAN1_BA+0x48) /*!< IF1 Data B2 Register */ + #define REG_CAN1_IF2_DAT_A1 (CAN1_BA+0x9C) /*!< IF2 Data A1 Register */ + #define REG_CAN1_IF2_DAT_A2 (CAN1_BA+0xA0) /*!< IF2 Data A2 Register */ + #define REG_CAN1_IF2_DAT_B1 (CAN1_BA+0xA4) /*!< IF2 Data B1 Register */ + #define REG_CAN1_IF2_DAT_B2 (CAN1_BA+0xA8) /*!< IF2 Data B2 Register */ + #define REG_CAN1_TXREQ1 (CAN1_BA+0x100) /*!< Transmission Request Register 1 */ + #define REG_CAN1_TXREQ2 (CAN1_BA+0x104) /*!< Transmission Request Register 2 */ + #define REG_CAN1_NDAT1 (CAN1_BA+0x120) /*!< New Data Register 1 */ + #define REG_CAN1_NDAT2 (CAN1_BA+0x124) /*!< New Data Register 2 */ + #define REG_CAN1_IPND1 (CAN1_BA+0x140) /*!< Interrupt Pending Register 1 */ + #define REG_CAN1_IPND2 (CAN1_BA+0x142) /*!< Interrupt Pending Register 2 */ + #define REG_CAN1_MVLD1 (CAN1_BA+0x160) /*!< Message Valid Register 1 */ + #define REG_CAN1_MVLD2 (CAN1_BA+0x164) /*!< Message Valid Register 2 */ + #define REG_CAN1_WU_EN (CAN1_BA+0x168) /*!< Wake-up Function Enable */ + #define REG_CAN1_WU_STATUS (CAN1_BA+0x16C) /*!< Wake-up Function Status */ + + /**@}*/ /* end of CAN register group */ + + + /*------------------- Multi-Time Programmable Controller --------------------*/ + /** + @addtogroup MTP Multi-Time Programmable Controller (MTP) + Memory Mapped Structure for MTP Controller + @{ */ + + #define MTP_KEYEN (MTP_BA+0x000) /*!< MTP Key Enable Register */ + #define MTP_USERDATA (MTP_BA+0x00C) /*!< MTP User Defined Data Register */ + #define MTP_KEY0 (MTP_BA+0x010) /*!< MTP KEY 0 Register */ + #define MTP_KEY1 (MTP_BA+0x014) /*!< MTP KEY 1 Register */ + #define MTP_KEY2 (MTP_BA+0x018) /*!< MTP KEY 2 Register */ + #define MTP_KEY3 (MTP_BA+0x01C) /*!< MTP KEY 3 Register */ + #define MTP_KEY4 (MTP_BA+0x020) /*!< MTP KEY 4 Register */ + #define MTP_KEY5 (MTP_BA+0x024) /*!< MTP KEY 5 Register */ + #define MTP_KEY6 (MTP_BA+0x028) /*!< MTP KEY 6 Register */ + #define MTP_KEY7 (MTP_BA+0x02C) /*!< MTP KEY 7 Register */ + #define MTP_PCYCLE (MTP_BA+0x030) /*!< MTP Program Cycle Program Count Register */ + #define MTP_CTL (MTP_BA+0x034) /*!< MTP Control Register */ + #define MTP_PSTART (MTP_BA+0x038) /*!< MTP Program Start Registe */ + #define MTP_STATUS (MTP_BA+0x040) /*!< MTP Status Registe */ + #define MTP_REGLCTL (MTP_BA+0x050) /*!< MTP Register Write-Protection Control Register*/ + + /**@}*/ /* end of MTP register group */ + + + /*------------------- JPEG Controller --------------------*/ + /** + @addtogroup JPEG JPEG Controller (JPEG) + Memory Mapped Structure for JPEG Controller + @{ */ + #define JMCR (JPEG_BA+0x00) /*!< JPEG Mode Control Register */ + #define JHEADER (JPEG_BA+0x04) /*!< JPEG Encode Header Control Register */ + #define JITCR (JPEG_BA+0x08) /*!< JPEG Image Type Control Register */ + #define JPRIQC (JPEG_BA+0x10) /*!< JPEG Primary Q-Table Control Register */ + #define JTHBQC (JPEG_BA+0x14) /*!< JPEG Thumbnail Q-Table Control Register */ + #define JPRIWH (JPEG_BA+0x18) /*!< JPEG Encode Primary Width/Height Register */ + #define JTHBWH (JPEG_BA+0x1C) /*!< JPEG Encode Thumbnail Width/Height Register */ + #define JPRST (JPEG_BA+0x20) /*!< JPEG Encode Primary Restart Interval Register */ + #define JTRST (JPEG_BA+0x24) /*!< JPEG Encode Thumbnail Restart Interval */ + #define JDECWH (JPEG_BA+0x28) /*!< JPEG Decode Image Width/Height Register */ + #define JINTCR (JPEG_BA+0x2C) /*!< JPEG Interrupt Control and Status Register */ + #define JDOWFBS (JPEG_BA+0x3c) /*!< JPEG Decoding Output Wait Frame Buffer Size */ + #define JPEG_BSBAD (JPEG_BA+0x40) /*!< JPEG Test Control Register */ + #define JWINDEC0 (JPEG_BA+0x44) /*!< JPEG Window Decode Mode Control Register 0 */ + #define JWINDEC1 (JPEG_BA+0x48) /*!< JPEG Window Decode Mode Control Register 1 */ + #define JWINDEC2 (JPEG_BA+0x4C) /*!< JPEG Window Decode Mode Control Register 2 */ + #define JMACR (JPEG_BA+0x50) /*!< JPEG Memory Address Mode Control Register */ + #define JPSCALU (JPEG_BA+0x54) /*!< JPEG Primary Scaling-Up Control Register */ + #define JPSCALD (JPEG_BA+0x58) /*!< JPEG Primary Scaling-Down Control Register */ + #define JTSCALD (JPEG_BA+0x5C) /*!< JPEG Thumbnail Scaling-Down Control Register */ + #define JDBCR (JPEG_BA+0x60) /*!< JPEG Dual-Buffer Control Register */ + #define JRESERVE (JPEG_BA+0x70) /*!< JPEG Encode Primary Bit-stream Reserved Size Register */ + #define JOFFSET (JPEG_BA+0x74) /*!< JPEG Offset Between Primary & Thumbnail Register */ + #define JFSTRIDE (JPEG_BA+0x78) /*!< JPEG Encode Bit-stream Frame Stride Register */ + #define JYADDR0 (JPEG_BA+0x7C) /*!< JPEG Y Component Frame Buffer-0 Starting Address Register */ + #define JUADDR0 (JPEG_BA+0x80) /*!< JPEG U Component Frame Buffer-0 Starting Address Register */ + #define JVADDR0 (JPEG_BA+0x84) /*!< JPEG V Component Frame Buffer-0 Starting Address Register */ + #define JYADDR1 (JPEG_BA+0x88) /*!< JPEG Y Component Frame Buffer-1 Starting Address Register */ + #define JUADDR1 (JPEG_BA+0x8C) /*!< JPEG U Component Frame Buffer-1 Starting Address Register */ + #define JVADDR1 (JPEG_BA+0x90) /*!< JPEG V Component Frame Buffer-1 Starting Address Register */ + #define JYSTRIDE (JPEG_BA+0x94) /*!< JPEG Y Component Frame Buffer Stride Register */ + #define JUSTRIDE (JPEG_BA+0x98) /*!< JPEG U Component Frame Buffer Stride Register */ + #define JVSTRIDE (JPEG_BA+0x9C) /*!< JPEG V Component Frame Buffer Stride Register */ + #define JIOADDR0 (JPEG_BA+0xA0) /*!< JPEG Bit-stream Frame Buffer-0 Starting Address Register */ + #define JIOADDR1 (JPEG_BA+0xA4) /*!< JPEG Bit-stream Frame Buffer-1 Starting Address Register */ + #define JPRI_SIZE (JPEG_BA+0xA8) /*!< JPEG Encode Primary Image Bit-stream Size Register */ + #define JTHB_SIZE (JPEG_BA+0xAC) /*!< JPEG Encode Thumbnail Image Bit-stream Size Register */ + #define JUPRAT (JPEG_BA+0xB0) /*!< JPEG Encode Up-Scale Ratio Register */ + #define JBSFIFO (JPEG_BA+0xB4) /*!< JPEG Bit-stream FIFO Control Register */ + #define JSRCH (JPEG_BA+0xB8) /*!< JPEG Encode Source Image Height */ + #define JQTAB0 (JPEG_BA+0x100) /*!< JPEG Quantization-Table 0 Register */ + #define JQTAB1 (JPEG_BA+0x140) /*!< JPEG Quantization-Table 1 Register */ + #define JQTAB2 (JPEG_BA+0x180) /*!< JPEG Quantization-Table 2 Register */ + + /**@}*/ /* end of JPEG register group */ + + + + /*@}*/ /* end of group N9H30_Peripherals */ + + + /** @addtogroup N9H30_IO_ROUTINE N9H30 I/O Routines + The Declaration of N9H30 I/O Routines + @{ + */ + + typedef volatile unsigned char vu8; ///< Define 8-bit unsigned volatile data type + typedef volatile unsigned short vu16; ///< Define 16-bit unsigned volatile data type + typedef volatile unsigned long vu32; ///< Define 32-bit unsigned volatile data type + + /** + * @brief Get a 8-bit unsigned value from specified address + * @param[in] addr Address to get 8-bit data from + * @return 8-bit unsigned value stored in specified address + */ + #define M8(addr) (*((vu8 *) (addr))) + + /** + * @brief Get a 16-bit unsigned value from specified address + * @param[in] addr Address to get 16-bit data from + * @return 16-bit unsigned value stored in specified address + * @note The input address must be 16-bit aligned + */ + #define M16(addr) (*((vu16 *) (addr))) + + /** + * @brief Get a 32-bit unsigned value from specified address + * @param[in] addr Address to get 32-bit data from + * @return 32-bit unsigned value stored in specified address + * @note The input address must be 32-bit aligned + */ + #define M32(addr) (*((vu32 *) (addr))) + + /** + * @brief Set a 32-bit unsigned value to specified I/O port + * @param[in] port Port address to set 32-bit data + * @param[in] value Value to write to I/O port + * @return None + * @note The output port must be 32-bit aligned + */ + #define outpw(port,value) *((volatile unsigned int *)(port)) = value + + /** + * @brief Get a 32-bit unsigned value from specified I/O port + * @param[in] port Port address to get 32-bit data from + * @return 32-bit unsigned value stored in specified I/O port + * @note The input port must be 32-bit aligned + */ + #define inpw(port) (*((volatile unsigned int *)(port))) + + /** + * @brief Set a 16-bit unsigned value to specified I/O port + * @param[in] port Port address to set 16-bit data + * @param[in] value Value to write to I/O port + * @return None + * @note The output port must be 16-bit aligned + */ + #define outps(port,value) *((volatile unsigned short *)(port)) = value + + /** + * @brief Get a 16-bit unsigned value from specified I/O port + * @param[in] port Port address to get 16-bit data from + * @return 16-bit unsigned value stored in specified I/O port + * @note The input port must be 16-bit aligned + */ + #define inps(port) (*((volatile unsigned short *)(port))) + + /** + * @brief Set a 8-bit unsigned value to specified I/O port + * @param[in] port Port address to set 8-bit data + * @param[in] value Value to write to I/O port + * @return None + */ + #define outpb(port,value) *((volatile unsigned char *)(port)) = value + + /** + * @brief Get a 8-bit unsigned value from specified I/O port + * @param[in] port Port address to get 8-bit data from + * @return 8-bit unsigned value stored in specified I/O port + */ + #define inpb(port) (*((volatile unsigned char *)(port))) + + /** + * @brief Set a 32-bit unsigned value to specified I/O port + * @param[in] port Port address to set 32-bit data + * @param[in] value Value to write to I/O port + * @return None + * @note The output port must be 32-bit aligned + */ + #define outp32(port,value) *((volatile unsigned int *)(port)) = value + + /** + * @brief Get a 32-bit unsigned value from specified I/O port + * @param[in] port Port address to get 32-bit data from + * @return 32-bit unsigned value stored in specified I/O port + * @note The input port must be 32-bit aligned + */ + #define inp32(port) (*((volatile unsigned int *)(port))) + + /** + * @brief Set a 16-bit unsigned value to specified I/O port + * @param[in] port Port address to set 16-bit data + * @param[in] value Value to write to I/O port + * @return None + * @note The output port must be 16-bit aligned + */ + #define outp16(port,value) *((volatile unsigned short *)(port)) = value + + /** + * @brief Get a 16-bit unsigned value from specified I/O port + * @param[in] port Port address to get 16-bit data from + * @return 16-bit unsigned value stored in specified I/O port + * @note The input port must be 16-bit aligned + */ + #define inp16(port) (*((volatile unsigned short *)(port))) + + /** + * @brief Set a 8-bit unsigned value to specified I/O port + * @param[in] port Port address to set 8-bit data + * @param[in] value Value to write to I/O port + * @return None + */ + #define outp8(port,value) *((volatile unsigned char *)(port)) = value + + /** + * @brief Get a 8-bit unsigned value from specified I/O port + * @param[in] port Port address to get 8-bit data from + * @return 8-bit unsigned value stored in specified I/O port + */ + #define inp8(port) (*((volatile unsigned char *)(port))) + + + /*@}*/ /* end of group N9H30_IO_ROUTINE */ + + /******************************************************************************/ + /* Legacy Constants */ + /******************************************************************************/ + /** @addtogroup N9H30_legacy_Constants N9H30 Legacy Constants + N9H30 Legacy Constants + @{ + */ + typedef void *PVOID; ///< Define void pointer data type + typedef void VOID; ///< Define void data type + typedef char BOOL; ///< Define bool data type + typedef char *PBOOL; ///< Define bool pointer data type + + typedef char INT8; ///< Define 8-bit singed data type + typedef char CHAR; ///< Define char data type + typedef char *PINT8; ///< Define 8-bit singed pointer data type + typedef char *PCHAR; ///< Define char pointer data type + typedef unsigned char UINT8; ///< Define 8-bit unsigned data type + typedef unsigned char UCHAR; ///< Define char unsigned data type + typedef unsigned char *PUINT8; ///< Define 8-bit unsigned pointer data type + typedef unsigned char *PUCHAR; ///< Define char unsigned pointer data type + typedef char *PSTR; ///< Define string pointer data type + typedef const char *PCSTR; ///< Define constant string pointer data type + + typedef short SHORT; ///< Define short signed data type + typedef short *PSHORT; ///< Define short signed pointer data type + typedef unsigned short USHORT; ///< Define short unsigned data type + typedef unsigned short *PUSHORT; ///< Define short unsigned pointer data type + + typedef short INT16; ///< Define 16-bit signed data type + typedef short *PINT16; ///< Define 16-bit signed pointer data type + typedef unsigned short UINT16; ///< Define 16-bit unsigned data type + typedef unsigned short *PUINT16; ///< Define 16-bit unsigned pointer data type + + typedef int INT; ///< Define integer signed data type + typedef int *PINT; ///< Define integer signed pointer data type + typedef unsigned int UINT; ///< Define integer unsigned data type + typedef unsigned int *PUINT; ///< Define integer unsigned pointer data type + + typedef int INT32; ///< Define 32-bit signed data type + typedef int *PINT32; ///< Define 32-bit signed pointer data type + typedef unsigned int UINT32; ///< Define 32-bit unsigned data type + typedef unsigned int *PUINT32; ///< Define 32-bit unsigned pointer data type + + #if defined ( __GNUC__ ) && !(__CC_ARM) + typedef long long INT64; + typedef unsigned long long UINT64; + #else + typedef __int64 INT64; ///< Define 64-bit signed data type + typedef unsigned __int64 UINT64; ///< Define 64-bit unsigned data type + #endif + + typedef float FLOAT; ///< Define float data type + typedef float *PFLOAT; ///< Define float pointer data type + + typedef double DOUBLE; ///< Define double data type + typedef double *PDOUBLE; ///< Define double pointer data type + + typedef int SIZE_T; ///< Define size of data type + + typedef unsigned char REG8; ///< Define 8-bit register data type + typedef unsigned short REG16; ///< Define 16-bit register data type + typedef unsigned int REG32; ///< Define 32-bit register data type + + + #ifndef NULL + #define NULL (0) ///< NULL pointer + #endif + + #define TRUE (1) ///< Boolean true, define to use in API parameters or return value + #define FALSE (0) ///< Boolean false, define to use in API parameters or return value + + #define ENABLE (1) ///< Enable, define to use in API parameters + #define DISABLE (0) ///< Disable, define to use in API parameters + + + #define Successful 0 ///< Function return value success + #define Fail 1 ///< Function return value failed + + /* Define one bit mask */ + #define BIT0 (0x00000001) ///< Bit 0 mask of an 32 bit integer + #define BIT1 (0x00000002) ///< Bit 1 mask of an 32 bit integer + #define BIT2 (0x00000004) ///< Bit 2 mask of an 32 bit integer + #define BIT3 (0x00000008) ///< Bit 3 mask of an 32 bit integer + #define BIT4 (0x00000010) ///< Bit 4 mask of an 32 bit integer + #define BIT5 (0x00000020) ///< Bit 5 mask of an 32 bit integer + #define BIT6 (0x00000040) ///< Bit 6 mask of an 32 bit integer + #define BIT7 (0x00000080) ///< Bit 7 mask of an 32 bit integer + #define BIT8 (0x00000100) ///< Bit 8 mask of an 32 bit integer + #define BIT9 (0x00000200) ///< Bit 9 mask of an 32 bit integer + #define BIT10 (0x00000400) ///< Bit 10 mask of an 32 bit integer + #define BIT11 (0x00000800) ///< Bit 11 mask of an 32 bit integer + #define BIT12 (0x00001000) ///< Bit 12 mask of an 32 bit integer + #define BIT13 (0x00002000) ///< Bit 13 mask of an 32 bit integer + #define BIT14 (0x00004000) ///< Bit 14 mask of an 32 bit integer + #define BIT15 (0x00008000) ///< Bit 15 mask of an 32 bit integer + #define BIT16 (0x00010000) ///< Bit 16 mask of an 32 bit integer + #define BIT17 (0x00020000) ///< Bit 17 mask of an 32 bit integer + #define BIT18 (0x00040000) ///< Bit 18 mask of an 32 bit integer + #define BIT19 (0x00080000) ///< Bit 19 mask of an 32 bit integer + #define BIT20 (0x00100000) ///< Bit 20 mask of an 32 bit integer + #define BIT21 (0x00200000) ///< Bit 21 mask of an 32 bit integer + #define BIT22 (0x00400000) ///< Bit 22 mask of an 32 bit integer + #define BIT23 (0x00800000) ///< Bit 23 mask of an 32 bit integer + #define BIT24 (0x01000000) ///< Bit 24 mask of an 32 bit integer + #define BIT25 (0x02000000) ///< Bit 25 mask of an 32 bit integer + #define BIT26 (0x04000000) ///< Bit 26 mask of an 32 bit integer + #define BIT27 (0x08000000) ///< Bit 27 mask of an 32 bit integer + #define BIT28 (0x10000000) ///< Bit 28 mask of an 32 bit integer + #define BIT29 (0x20000000) ///< Bit 29 mask of an 32 bit integer + #define BIT30 (0x40000000) ///< Bit 30 mask of an 32 bit integer + #define BIT31 (0x80000000) ///< Bit 31 mask of an 32 bit integer + + /* Byte Mask Definitions */ + #define BYTE0_Msk (0x000000FF) ///< Mask to get bit0~bit7 from a 32 bit integer + #define BYTE1_Msk (0x0000FF00) ///< Mask to get bit8~bit15 from a 32 bit integer + #define BYTE2_Msk (0x00FF0000) ///< Mask to get bit16~bit23 from a 32 bit integer + #define BYTE3_Msk (0xFF000000) ///< Mask to get bit24~bit31 from a 32 bit integer + + #define GET_BYTE0(u32Param) ((u32Param & BYTE0_Msk) ) /*!< Extract Byte 0 (Bit 0~ 7) from parameter u32Param */ + #define GET_BYTE1(u32Param) ((u32Param & BYTE1_Msk) >> 8) /*!< Extract Byte 1 (Bit 8~15) from parameter u32Param */ + #define GET_BYTE2(u32Param) ((u32Param & BYTE2_Msk) >> 16) /*!< Extract Byte 2 (Bit 16~23) from parameter u32Param */ + #define GET_BYTE3(u32Param) ((u32Param & BYTE3_Msk) >> 24) /*!< Extract Byte 3 (Bit 24~31) from parameter u32Param */ + + #ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ + #else + #define __I volatile const /*!< Defines 'read only' permissions */ + #endif + #define __O volatile /*!< Defines 'write only' permissions */ + #define __IO volatile /*!< Defines 'read / write' permissions */ + + extern void __nop(void); + +#endif /* __N9H30_H__ */ + +/*@}*/ /* end of group N9H30_legacy_Constants */ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/NuMicro.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/NuMicro.h new file mode 100644 index 0000000000000000000000000000000000000000..6e949c843dbb50a9979a60a114115be8051d67c2 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/NuMicro.h @@ -0,0 +1,51 @@ +/**************************************************************************//** + * @file NuMicro.h + * @version V1.00 + * @brief NuMicro peripheral access layer header file. + * + * SPDX-License-Identifier: Apache-2.0 + * @copyright (C) 2017-2020 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __NUMICRO_H__ +#define __NUMICRO_H__ + +#include "N9H30.h" +#include "nu_adc.h" +#include "nu_uart.h" +#include "nu_spi.h" +#include "nu_i2c.h" +#include "nu_etimer.h" +#include "nu_emac.h" +#include "nu_sdh.h" +#include "nu_gpio.h" +#include "nu_rtc.h" +#include "nu_wdt.h" +//#include "nu_ebi.h" +#include "nu_scuart.h" +#include "nu_pwm.h" +//#include "nu_crypto.h" +#include "nu_can.h" +#include "nu_i2s.h" +#include "nu_usbd.h" +#include "nu_lcd.h" +#include "nu_jpegcodec.h" +#include "nu_2d.h" +#include "nu_crypto.h" + +#include "nu_sys.h" + +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static __inline +#endif + +#ifndef __CLZ + #if defined(__CC_ARM) + #define __CLZ __clz + #else + #define __CLZ __builtin_clz + #endif +#endif + +#endif /* __NUMICRO_H__ */ + + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/emac_reg.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/emac_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..f9ad5efceb57f7397e1e7d671ebb59932eb74c51 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/emac_reg.h @@ -0,0 +1,2063 @@ +/**************************************************************************//** + * @file emac_reg.h + * @version V1.00 + * @brief EMAC register definition header file + * + * SPDX-License-Identifier: Apache-2.0 + * @copyright (C) 2017-2020 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __EMAC_REG_H__ +#define __EMAC_REG_H__ + +#if defined ( __CC_ARM ) + #pragma anon_unions +#endif + +/** + @addtogroup REGISTER Control Register + @{ +*/ + +/** + @addtogroup EMAC Ethernet MAC Controller(EMAC) + Memory Mapped Structure for EMAC Controller +@{ */ + +typedef struct +{ + + /** + * @var EMAC_T::CAMCTL + * Offset: 0x00 CAM Comparison Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |AUP |Accept Unicast Packet + * | | |The AUP controls the unicast packet reception + * | | |If AUP is enabled, EMAC receives all incoming packet its destination MAC address is a unicast address. + * | | |0 = EMAC receives packet depends on the CAM comparison result. + * | | |1 = EMAC receives all unicast packets. + * |[1] |AMP |Accept Multicast Packet + * | | |The AMP controls the multicast packet reception + * | | |If AMP is enabled, EMAC receives all incoming packet its destination MAC address is a multicast address. + * | | |0 = EMAC receives packet depends on the CAM comparison result. + * | | |1 = EMAC receives all multicast packets. + * |[2] |ABP |Accept Broadcast Packet + * | | |The ABP controls the broadcast packet reception + * | | |If ABP is enabled, EMAC receives all incoming packet its destination MAC address is a broadcast address. + * | | |0 = EMAC receives packet depends on the CAM comparison result. + * | | |1 = EMAC receives all broadcast packets. + * |[3] |COMPEN |Complement CAM Comparison Enable Bit + * | | |The COMPEN controls the complement of the CAM comparison result + * | | |If the CMPEN and COMPEN are both enabled, the incoming packet with specific destination MAC address + * | | |configured in CAM entry will be dropped + * | | |And the incoming packet with destination MAC address does not configured in any CAM entry will be received. + * | | |0 = Complement CAM comparison result Disabled. + * | | |1 = Complement CAM comparison result Enabled. + * |[4] |CMPEN |CAM Compare Enable Bit + * | | |The CMPEN controls the enable of CAM comparison function for destination MAC address recognition + * | | |If software wants to receive a packet with specific destination MAC address, configures the MAC address + * | | |into CAM 12~0, then enables that CAM entry and set CMPEN to 1. + * | | |0 = CAM comparison function for destination MAC address recognition Disabled. + * | | |1 = CAM comparison function for destination MAC address recognition Enabled. + * @var EMAC_T::CAMEN + * Offset: 0x04 CAM Enable Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |CAMxEN |CAM Entry X Enable Bit + * | | |The CAMxEN controls the validation of CAM entry x. + * | | |The CAM entry 13, 14 and 15 are for PAUSE control frame transmission + * | | |If software wants to transmit a PAUSE control frame out to network, the enable bits of these three CAM + * | | |entries all must be enabled first. + * | | |0 = CAM entry x Disabled. + * | | |1 = CAM entry x Enabled. + * @var EMAC_T::CAM0M + * Offset: 0x08 CAM0 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM0L + * Offset: 0x0C CAM0 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM1M + * Offset: 0x10 CAM1 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM1L + * Offset: 0x14 CAM1 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM2M + * Offset: 0x18 CAM2 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM2L + * Offset: 0x1C CAM2 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM3M + * Offset: 0x20 CAM3 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM3L + * Offset: 0x24 CAM3 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM4M + * Offset: 0x28 CAM4 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM4L + * Offset: 0x2C CAM4 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM5M + * Offset: 0x30 CAM5 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM5L + * Offset: 0x34 CAM5 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM6M + * Offset: 0x38 CAM6 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM6L + * Offset: 0x3C CAM6 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM7M + * Offset: 0x40 CAM7 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM7L + * Offset: 0x44 CAM7 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM8M + * Offset: 0x48 CAM8 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM8L + * Offset: 0x4C CAM8 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM9M + * Offset: 0x50 CAM9 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM9L + * Offset: 0x54 CAM9 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM10M + * Offset: 0x58 CAM10 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM10L + * Offset: 0x5C CAM10 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM11M + * Offset: 0x60 CAM11 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM11L + * Offset: 0x64 CAM11 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM12M + * Offset: 0x68 CAM12 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM12L + * Offset: 0x6C CAM12 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM13M + * Offset: 0x70 CAM13 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM13L + * Offset: 0x74 CAM13 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM14M + * Offset: 0x78 CAM14 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |MACADDR2 |MAC Address Byte 2 + * |[15:8] |MACADDR3 |MAC Address Byte 3 + * |[23:16] |MACADDR4 |MAC Address Byte 4 + * |[31:24] |MACADDR5 |MAC Address Byte 5 + * | | |The CAMxM keeps the bit 47~16 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM14L + * Offset: 0x7C CAM14 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:16] |MACADDR0 |MAC Address Byte 0 + * |[31:24] |MACADDR1 |MAC Address Byte 1 + * | | |The CAMxL keeps the bit 15~0 of MAC address + * | | |The x can be the 0~14 + * | | |The register pair {EMAC_CAMxM, EMAC_CAMxL} represents a CAM entry and keeps a MAC address. + * | | |For example, if the MAC address 00-50-BA-33-BA-44 kept in CAM entry 1, the register EMAC_CAM1M is + * | | |0x0050_BA33 and EMAC_CAM1L is 0xBA44_0000. + * @var EMAC_T::CAM15MSB + * Offset: 0x80 CAM15 Most Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |OPCODE |OP Code Field of PAUSE Control Frame + * | | |In the PAUSE control frame, an op code field defined and is 0x0001. + * |[31:16] |LENGTH |LENGTH Field of PAUSE Control Frame + * | | |In the PAUSE control frame, a LENGTH field defined and is 0x8808. + * @var EMAC_T::CAM15LSB + * Offset: 0x84 CAM15 Least Significant Word Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:24] |OPERAND |Pause Parameter + * | | |In the PAUSE control frame, an OPERAND field defined and controls how much time the destination + * | | |Ethernet MAC Controller paused + * | | |The unit of the OPERAND is a slot time, the 512-bit time. + * @var EMAC_T::TXDSA + * Offset: 0x88 Transmit Descriptor Link List Start Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |TXDSA |Transmit Descriptor Link-list Start Address + * | | |The TXDSA keeps the start address of transmit descriptor link-list + * | | |If the software enables the bit TXON (EMAC_CTL[8]), the content of TXDSA will be loaded into the + * | | |current transmit descriptor start address register (EMAC_CTXDSA) + * | | |The TXDSA does not be updated by EMAC + * | | |During the operation, EMAC will ignore the bits [1:0] of TXDSA + * | | |This means that TX descriptors must locate at word boundary memory address. + * @var EMAC_T::RXDSA + * Offset: 0x8C Receive Descriptor Link List Start Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |RXDSA |Receive Descriptor Link-list Start Address + * | | |The RXDSA keeps the start address of receive descriptor link-list + * | | |If the S/W enables the bit RXON (EMAC_CTL[0]), the content of RXDSA will be loaded into the current + * | | |receive descriptor start address register (EMAC_CRXDSA) + * | | |The RXDSA does not be updated by EMAC + * | | |During the operation, EMAC will ignore the bits [1:0] of RXDSA + * | | |This means that RX descriptors must locate at word boundary memory address. + * @var EMAC_T::CTL + * Offset: 0x90 MAC Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |RXON |Frame Reception ON + * | | |The RXON controls the normal packet reception of EMAC + * | | |If the RXON is set to high, the EMAC starts the packet reception process, including the RX + * | | |descriptor fetching, packet reception and RX descriptor modification. + * | | |It is necessary to finish EMAC initial sequence before enable RXON + * | | |Otherwise, the EMAC operation is undefined. + * | | |If the RXON is disabled during EMAC is receiving an incoming packet, the EMAC stops the packet + * | | |reception process after the current packet reception finished. + * | | |0 = Packet reception process stopped. + * | | |1 = Packet reception process started. + * |[1] |ALP |Accept Long Packet + * | | |The ALP controls the long packet, which packet length is greater than 1518 bytes, reception + * | | |If the ALP is set to high, the EMAC will accept the long packet. + * | | |Otherwise, the long packet will be dropped. + * | | |0 = Ethernet MAC controller dropped the long packet. + * | | |1 = Ethernet MAC controller received the long packet. + * |[2] |ARP |Accept Runt Packet + * | | |The ARP controls the runt packet, which length is less than 64 bytes, reception + * | | |If the ARP is set to high, the EMAC will accept the runt packet. + * | | |Otherwise, the runt packet will be dropped. + * | | |0 = Ethernet MAC controller dropped the runt packet. + * | | |1 = Ethernet MAC controller received the runt packet. + * |[3] |ACP |Accept Control Packet + * | | |The ACP controls the control frame reception + * | | |If the ACP is set to high, the EMAC will accept the control frame + * | | |Otherwise, the control frame will be dropped + * | | |It is recommended that S/W only enable ACP while EMAC is operating on full duplex mode. + * | | |0 = Ethernet MAC controller dropped the control frame. + * | | |1 = Ethernet MAC controller received the control frame. + * |[4] |AEP |Accept CRC Error Packet + * | | |The AEP controls the EMAC accepts or drops the CRC error packet + * | | |If the AEP is set to high, the incoming packet with CRC error will be received by EMAC as a good packet. + * | | |0 = Ethernet MAC controller dropped the CRC error packet. + * | | |1 = Ethernet MAC controller received the CRC error packet. + * |[5] |STRIPCRC |Strip CRC Checksum + * | | |The STRIPCRC controls if the length of incoming packet is calculated with 4 bytes CRC checksum + * | | |If the STRIPCRC is set to high, 4 bytes CRC checksum is excluded from length calculation of incoming packet. + * | | |0 = The 4 bytes CRC checksum is included in packet length calculation. + * | | |1 = The 4 bytes CRC checksum is excluded in packet length calculation. + * |[6] |WOLEN |Wake on LAN Enable Bit + * | | |The WOLEN high enables the functionality that Ethernet MAC controller checked if the incoming packet + * | | |is Magic Packet and wakeup system from Power-down mode. + * | | |If incoming packet was a Magic Packet and the system was in Power-down, the Ethernet MAC controller + * | | |would generate a wakeup event to wake system up from Power-down mode. + * | | |0 = Wake-up by Magic Packet function Disabled. + * | | |1 = Wake-up by Magic Packet function Enabled. + * |[8] |TXON |Frame Transmission ON + * | | |The TXON controls the normal packet transmission of EMAC + * | | |If the TXON is set to high, the EMAC starts the packet transmission process, including the TX + * | | |descriptor fetching, packet transmission and TX descriptor modification. + * | | |It is must to finish EMAC initial sequence before enable TXON + * | | |Otherwise, the EMAC operation is undefined. + * | | |If the TXON is disabled during EMAC is transmitting a packet out, the EMAC stops the packet + * | | |transmission process after the current packet transmission finished. + * | | |0 = Packet transmission process stopped. + * | | |1 = Packet transmission process started. + * |[9] |NODEF |No Deferral + * | | |The NODEF controls the enable of deferral exceed counter + * | | |If NODEF is set to high, the deferral exceed counter is disabled + * | | |The NODEF is only useful while EMAC is operating on half duplex mode. + * | | |0 = The deferral exceed counter Enabled. + * | | |1 = The deferral exceed counter Disabled. + * |[16] |SDPZ |Send PAUSE Frame + * | | |The SDPZ controls the PAUSE control frame transmission. + * | | |If S/W wants to send a PAUSE control frame out, the CAM entry 13, 14 and 15 must be configured + * | | |first and the corresponding CAM enable bit of CAMEN register also must be set. + * | | |Then, set SDPZ to 1 enables the PAUSE control frame transmission. + * | | |The SDPZ is a self-clear bit + * | | |This means after the PAUSE control frame transmission has completed, the SDPZ will be cleared automatically. + * | | |It is recommended that only enabling SNDPAUSE while EMAC is operating in Full Duplex mode. + * | | |0 = PAUSE control frame transmission completed. + * | | |1 = PAUSE control frame transmission Enabled. + * |[17] |SQECHKEN |SQE Checking Enable Bit + * | | |The SQECHKEN controls the enable of SQE checking + * | | |The SQE checking is only available while EMAC is operating on 10M bps and half duplex mode + * | | |In other words, the SQECHKEN cannot affect EMAC operation, if the EMAC is operating on 100Mbps + * | | |or full duplex mode. + * | | |0 = SQE checking Disabled while EMAC is operating in 10Mbps and Half Duplex mode. + * | | |1 = SQE checking Enabled while EMAC is operating in 10Mbps and Half Duplex mode. + * |[18] |FUDUP |Full Duplex Mode Selection + * | | |The FUDUP controls that if EMAC is operating on full or half duplex mode. + * | | |0 = EMAC operates in half duplex mode. + * | | |1 = EMAC operates in full duplex mode. + * |[19] |RMIIRXCTL |RMII RX Control + * | | |The RMIIRXCTL control the receive data sample in RMII mode + * | | |It's necessary to set this bit high when RMIIEN (EMAC_CTL[ [22]) is high. + * | | |0 = RMII RX control disabled. + * | | |1 = RMII RX control enabled. + * |[20] |OPMODE |Operation Mode Selection + * | | |The OPMODE defines that if the EMAC is operating on 10M or 100M bps mode + * | | |The RST (EMAC_CTL[24]) would not affect OPMODE value. + * | | |0 = EMAC operates in 10Mbps mode. + * | | |1 = EMAC operates in 100Mbps mode. + * |[22] |RMIIEN |RMII Mode Enable Bit + * | | |This bit controls if Ethernet MAC controller connected with off-chip Ethernet PHY by MII + * | | |interface or RMII interface + * | | |The RST (EMAC_CTL[24]) would not affect RMIIEN value. + * | | |0 = Ethernet MAC controller RMII mode Disabled. + * | | |1 = Ethernet MAC controller RMII mode Enabled. + * | | |NOTE: This field must keep 1. + * |[24] |RST |Software Reset + * | | |The RST implements a reset function to make the EMAC return default state + * | | |The RST is a self-clear bit + * | | |This means after the software reset finished, the RST will be cleared automatically + * | | |Enable RST can also reset all control and status registers, exclusive of the control bits + * | | |RMIIEN (EMAC_CTL[22]), and OPMODE (EMAC_CTL[20]). + * | | |The EMAC re-initial is necessary after the software reset completed. + * | | |0 = Software reset completed. + * | | |1 = Software reset Enabled. + * @var EMAC_T::MIIMDAT + * Offset: 0x94 MII Management Data Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |DATA |MII Management Data + * | | |The DATA is the 16 bits data that will be written into the registers of external PHY for MII + * | | |Management write command or the data from the registers of external PHY for MII Management read command. + * @var EMAC_T::MIIMCTL + * Offset: 0x98 MII Management Control and Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[4:0] |PHYREG |PHY Register Address + * | | |The PHYREG keeps the address to indicate which register of external PHY is the target of the + * | | |MII management command. + * |[12:8] |PHYADDR |PHY Address + * | | |The PHYADDR keeps the address to differentiate which external PHY is the target of the MII management command. + * |[16] |WRITE |Write Command + * | | |The Write defines the MII management command is a read or write. + * | | |0 = MII management command is a read command. + * | | |1 = MII management command is a write command. + * |[17] |BUSY |Busy Bit + * | | |The BUSY controls the enable of the MII management frame generation + * | | |If S/W wants to access registers of external PHY, it set BUSY to high and EMAC generates + * | | |the MII management frame to external PHY through MII Management I/F + * | | |The BUSY is a self-clear bit + * | | |This means the BUSY will be cleared automatically after the MII management command finished. + * | | |0 = MII management command generation finished. + * | | |1 = MII management command generation Enabled. + * |[18] |PREAMSP |Preamble Suppress + * | | |The PREAMSP controls the preamble field generation of MII management frame + * | | |If the PREAMSP is set to high, the preamble field generation of MII management frame is skipped. + * | | |0 = Preamble field generation of MII management frame not skipped. + * | | |1 = Preamble field generation of MII management frame skipped. + * |[19] |MDCON |MDC Clock ON + * | | |The MDC controls the MDC clock generation. If the MDCON is set to high, the MDC clock is turned on. + * | | |0 = MDC clock off. + * | | |1 = MDC clock on. + * @var EMAC_T::FIFOCTL + * Offset: 0x9C FIFO Threshold Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[1:0] |RXFIFOTH |RXFIFO Low Threshold + * | | |The RXFIFOTH controls when RXDMA requests internal arbiter for data transfer between RXFIFO + * | | |and system memory + * | | |The RXFIFOTH defines not only the high threshold of RXFIFO, but also the low threshold + * | | |The low threshold is the half of high threshold always + * | | |During the packet reception, if the RXFIFO reaches the high threshold, the RXDMA starts to + * | | |transfer frame data from RXFIFO to system memory + * | | |If the frame data in RXFIFO is less than low threshold, RXDMA stops to transfer the frame + * | | |data to system memory. + * | | |00 = Depend on the burst length setting + * | | |If the burst length is 8 words, high threshold is 8 words, too. + * | | |01 = RXFIFO high threshold is 64B and low threshold is 32B. + * | | |10 = RXFIFO high threshold is 128B and low threshold is 64B. + * | | |11 = RXFIFO high threshold is 192B and low threshold is 96B. + * |[9:8] |TXFIFOTH |TXFIFO Low Threshold + * | | |The TXFIFOTH controls when TXDMA requests internal arbiter for data transfer between system + * | | |memory and TXFIFO + * | | |The TXFIFOTH defines not only the low threshold of TXFIFO, but also the high threshold + * | | |The high threshold is the twice of low threshold always + * | | |During the packet transmission, if the TXFIFO reaches the high threshold, the TXDMA stops + * | | |generate request to transfer frame data from system memory to TXFIFO + * | | |If the frame data in TXFIFO is less than low threshold, TXDMA starts to transfer frame data + * | | |from system memory to TXFIFO. + * | | |The TXFIFOTH also defines when the TXMAC starts to transmit frame out to network + * | | |The TXMAC starts to transmit the frame out while the TXFIFO first time reaches the high threshold + * | | |during the transmission of the frame + * | | |If the frame data length is less than TXFIFO high threshold, the TXMAC starts to transmit the frame + * | | |out after the frame data are all inside the TXFIFO. + * | | |00 = Undefined. + * | | |01 = TXFIFO low threshold is 64B and high threshold is 128B. + * | | |10 = TXFIFO low threshold is 80B and high threshold is 160B. + * | | |11 = TXFIFO low threshold is 96B and high threshold is 192B. + * |[21:20] |BURSTLEN |DMA Burst Length + * | | |This defines the burst length of AHB bus cycle while EMAC accesses system memory. + * | | |00 = 4 words. + * | | |01 = 8 words. + * | | |10 = 16 words. + * | | |11 = 16 words. + * @var EMAC_T::TXST + * Offset: 0xA0 Transmit Start Demand Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |TXST |Transmit Start Demand + * | | |If the TX descriptor is not available for use of TXDMA after the TXON (EMAC_CTL[8]) is enabled, + * | | |the FSM (Finite State Machine) of TXDMA enters the Halt state and the frame transmission is halted + * | | |After the S/W has prepared the new TX descriptor for frame transmission, it must issue a write + * | | |command to EMAC_TXST register to make TXDMA to leave Halt state and continue the frame transmission. + * | | |The EMAC_TXST is a write only register and read from this register is undefined. + * | | |The write to EMAC_TXST register takes effect only when TXDMA stayed at Halt state. + * @var EMAC_T::RXST + * Offset: 0xA4 Receive Start Demand Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |RXST |Receive Start Demand + * | | |If the RX descriptor is not available for use of RXDMA after the RXON (EMAC_CTL[0]) is enabled, + * | | |the FSM (Finite State Machine) of RXDMA enters the Halt state and the frame reception is halted + * | | |After the S/W has prepared the new RX descriptor for frame reception, it must issue a write + * | | |command to EMAC_RXST register to make RXDMA to leave Halt state and continue the frame reception. + * | | |The EMAC_RXST is a write only register and read from this register is undefined. + * | | |The write to EMAC_RXST register take effect only when RXDMA stayed at Halt state. + * @var EMAC_T::MRFL + * Offset: 0xA8 Maximum Receive Frame Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |MRFL |Maximum Receive Frame Length + * | | |The MRFL defines the maximum frame length for received frame + * | | |If the frame length of received frame is greater than MRFL, and bit MFLEIEN (EMAC_INTEN[8]) + * | | |is also enabled, the bit MFLEIF (EMAC_INTSTS[8]) is set and the RX interrupt is triggered. + * | | |It is recommended that only use MRFL to qualify the length of received frame while S/W wants to + * | | |receive a frame which length is greater than 1518 bytes. + * @var EMAC_T::INTEN + * Offset: 0xAC MAC Interrupt Enable Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |RXIEN |Receive Interrupt Enable Bit + * | | |The RXIEN controls the RX interrupt generation. + * | | |If RXIEN is enabled and RXIF (EMAC_INTSTS[0]) is high, EMAC generates the RX interrupt to CPU + * | | |If RXIEN is disabled, no RX interrupt is generated to CPU even any status bit EMAC_INTSTS[15:1] + * | | |is set and the corresponding bit of EMAC_INTEN is enabled + * | | |In other words, if S/W wants to receive RX interrupt from EMAC, this bit must be enabled + * | | |And, if S/W doesn't want to receive any RX interrupt from EMAC, disables this bit. + * | | |0 = RXIF (EMAC_INTSTS[0]) is masked and RX interrupt generation Disabled. + * | | |1 = RXIF (EMAC_INTSTS[0]) is not masked and RX interrupt generation Enabled. + * |[1] |CRCEIEN |CRC Error Interrupt Enable Bit + * | | |The CRCEIEN controls the CRCEIF (EMAC_INTSTS[1]) interrupt generation + * | | |If CRCEIF (EMAC_INTSTS[1]) is set, and both CRCEIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If CRCEIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |CRCEIF (EMAC_INTSTS[1]) is set. + * | | |0 = CRCEIF (EMAC_INTSTS[1]) trigger RX interrupt Disabled. + * | | |1 = CRCEIF (EMAC_INTSTS[1]) trigger RX interrupt Enabled. + * |[2] |RXOVIEN |Receive FIFO Overflow Interrupt Enable Bit + * | | |The RXOVIEN controls the RXOVIF (EMAC_INTSTS[2]) interrupt generation + * | | |If RXOVIF (EMAC_INTSTS[2]) is set, and both RXOVIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If RXOVIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |RXOVIF (EMAC_INTSTS[2]) is set. + * | | |0 = RXOVIF (EMAC_INTSTS[2]) trigger RX interrupt Disabled. + * | | |1 = RXOVIF (EMAC_INTSTS[2]) trigger RX interrupt Enabled. + * |[3] |LPIEN |Long Packet Interrupt Enable Bit + * | | |The LPIEN controls the LPIF (EMAC_INTSTS[3]) interrupt generation + * | | |If LPIF (EMAC_INTSTS[3]) is set, and both LPIEN and RXIEN (EMAC_INTEN[0]) are enabled, the EMAC + * | | |generates the RX interrupt to CPU + * | | |If LPIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the LPIF + * | | |(EMAC_INTSTS[3]) is set. + * | | |0 = LPIF (EMAC_INTSTS[3]) trigger RX interrupt Disabled. + * | | |1 = LPIF (EMAC_INTSTS[3]) trigger RX interrupt Enabled. + * |[4] |RXGDIEN |Receive Good Interrupt Enable Bit + * | | |The RXGDIEN controls the RXGDIF (EMAC_INTSTS[4]) interrupt generation + * | | |If RXGDIF (EMAC_INTSTS[4]) is set, and both RXGDIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If RXGDIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |RXGDIF (EMAC_INTSTS[4]) is set. + * | | |0 = RXGDIF (EMAC_INTSTS[4]) trigger RX interrupt Disabled. + * | | |1 = RXGDIF (EMAC_INTSTS[4]) trigger RX interrupt Enabled. + * |[5] |ALIEIEN |Alignment Error Interrupt Enable Bit + * | | |The ALIEIEN controls the ALIEIF (EMAC_INTSTS[5]) interrupt generation + * | | |If ALIEIF (EMAC_INTSTS[5]) is set, and both ALIEIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If ALIEIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |ALIEIF (EMAC_INTSTS[5]) is set. + * | | |0 = ALIEIF (EMAC_INTSTS[5]) trigger RX interrupt Disabled. + * | | |1 = ALIEIF (EMAC_INTSTS[5]) trigger RX interrupt Enabled. + * |[6] |RPIEN |Runt Packet Interrupt Enable Bit + * | | |The RPIEN controls the RPIF (EMAC_INTSTS[6]) interrupt generation + * | | |If RPIF (EMAC_INTSTS[6]) is set, and both RPIEN and RXIEN (EMAC_INTEN[0]) are enabled, the EMAC + * | | |generates the RX interrupt to CPU + * | | |If RPIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |RPIF (EMAC_INTSTS[6]) is set. + * | | |0 = RPIF (EMAC_INTSTS[6]) trigger RX interrupt Disabled. + * | | |1 = RPIF (EMAC_INTSTS[6]) trigger RX interrupt Enabled. + * |[7] |MPCOVIEN |Miss Packet Counter Overrun Interrupt Enable Bit + * | | |The MPCOVIEN controls the MPCOVIF (EMAC_INTSTS[7]) interrupt generation + * | | |If MPCOVIF (EMAC_INTSTS[7]) is set, and both MPCOVIEN and RXIEN (EMAC_INTEN[0]) are enabled, + * | | |the EMAC generates the RX interrupt to CPU + * | | |If MPCOVIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |MPCOVIF (EMAC_INTSTS[7]) is set. + * | | |0 = MPCOVIF (EMAC_INTSTS[7]) trigger RX interrupt Disabled. + * | | |1 = MPCOVIF (EMAC_INTSTS[7]) trigger RX interrupt Enabled. + * |[8] |MFLEIEN |Maximum Frame Length Exceed Interrupt Enable Bit + * | | |The MFLEIEN controls the MFLEIF (EMAC_INTSTS[8]) interrupt generation + * | | |If MFLEIF (EMAC_INTSTS[8]) is set, and both MFLEIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If MFLEIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |MFLEIF (EMAC_INTSTS[8]) is set. + * | | |0 = MFLEIF (EMAC_INTSTS[8]) trigger RX interrupt Disabled. + * | | |1 = MFLEIF (EMAC_INTSTS[8]) trigger RX interrupt Enabled. + * |[9] |DENIEN |DMA Early Notification Interrupt Enable Bit + * | | |The DENIEN controls the DENIF (EMAC_INTSTS[9]) interrupt generation + * | | |If DENIF (EMAC_INTSTS[9]) is set, and both DENIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If DENIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |DENIF (EMAC_INTSTS[9]) is set. + * | | |0 = TDENIF (EMAC_INTSTS[9]) trigger RX interrupt Disabled. + * | | |1 = TDENIF (EMAC_INTSTS[9]) trigger RX interrupt Enabled. + * |[10] |RDUIEN |Receive Descriptor Unavailable Interrupt Enable Bit + * | | |The RDUIEN controls the RDUIF (EMAC_INTSTS[10]) interrupt generation + * | | |If RDUIF (EMAC_INTSTS[10]) is set, and both RDUIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If RDUIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |RDUIF (EMAC_MIOSTA[10]) register is set. + * | | |0 = RDUIF (EMAC_INTSTS[10]) trigger RX interrupt Disabled. + * | | |1 = RDUIF (EMAC_INTSTS[10]) trigger RX interrupt Enabled. + * |[11] |RXBEIEN |Receive Bus Error Interrupt Enable Bit + * | | |The RXBEIEN controls the RXBEIF (EMAC_INTSTS[11]) interrupt generation + * | | |If RXBEIF (EMAC_INTSTS[11]) is set, and both RXBEIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If RXBEIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |RXBEIF (EMAC_INTSTS[11]) is set. + * | | |0 = RXBEIF (EMAC_INTSTS[11]) trigger RX interrupt Disabled. + * | | |1 = RXBEIF (EMAC_INTSTS[11]) trigger RX interrupt Enabled. + * |[14] |CFRIEN |Control Frame Receive Interrupt Enable Bit + * | | |The CFRIEN controls the CFRIF (EMAC_INTSTS[14]) interrupt generation + * | | |If CFRIF (EMAC_INTSTS[14]) is set, and both CFRIEN and RXIEN (EMAC_INTEN[0]) are enabled, the + * | | |EMAC generates the RX interrupt to CPU + * | | |If CFRIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |CFRIF (EMAC_INTSTS[14]) register is set. + * | | |0 = CFRIF (EMAC_INTSTS[14]) trigger RX interrupt Disabled. + * | | |1 = CFRIF (EMAC_INTSTS[14]) trigger RX interrupt Enabled. + * |[15] |WOLIEN |Wake on LAN Interrupt Enable Bit + * | | |The WOLIEN controls the WOLIF (EMAC_INTSTS[15]) interrupt generation + * | | |If WOLIF (EMAC_INTSTS[15]) is set, and both WOLIEN and RXIEN (EMAC_INTEN[0]) are enabled, + * | | |the EMAC generates the RX interrupt to CPU + * | | |If WOLIEN or RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated to CPU even the + * | | |WOLIF (EMAC_INTSTS[15]) is set. + * | | |0 = WOLIF (EMAC_INTSTS[15]) trigger RX interrupt Disabled. + * | | |1 = WOLIF (EMAC_INTSTS[15]) trigger RX interrupt Enabled. + * |[16] |TXIEN |Transmit Interrupt Enable Bit + * | | |The TXIEN controls the TX interrupt generation. + * | | |If TXIEN is enabled and TXIF (EMAC_INTSTS[16]) is high, EMAC generates the TX interrupt to CPU + * | | |If TXIEN is disabled, no TX interrupt is generated to CPU even any status bit of + * | | |EMAC_INTSTS[24:17] set and the corresponding bit of EMAC_INTEN is enabled + * | | |In other words, if S/W wants to receive TX interrupt from EMAC, this bit must be enabled + * | | |And, if S/W doesn't want to receive any TX interrupt from EMAC, disables this bit. + * | | |0 = TXIF (EMAC_INTSTS[16]) is masked and TX interrupt generation Disabled. + * | | |1 = TXIF (EMAC_INTSTS[16]) is not masked and TX interrupt generation Enabled. + * |[17] |TXUDIEN |Transmit FIFO Underflow Interrupt Enable Bit + * | | |The TXUDIEN controls the TXUDIF (EMAC_INTSTS[17]) interrupt generation + * | | |If TXUDIF (EMAC_INTSTS[17]) is set, and both TXUDIEN and TXIEN (EMAC_INTEN[16]) are enabled, + * | | |the EMAC generates the TX interrupt to CPU + * | | |If TXUDIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even + * | | |the TXUDIF (EMAC_INTSTS[17]) is set. + * | | |0 = TXUDIF (EMAC_INTSTS[17]) TX interrupt Disabled. + * | | |1 = TXUDIF (EMAC_INTSTS[17]) TX interrupt Enabled. + * |[18] |TXCPIEN |Transmit Completion Interrupt Enable Bit + * | | |The TXCPIEN controls the TXCPIF (EMAC_INTSTS[18]) interrupt generation + * | | |If TXCPIF (EMAC_INTSTS[18]) is set, and both TXCPIEN and TXIEN (EMAC_INTEN[16]) are enabled, + * | | |the EMAC generates the TX interrupt to CPU + * | | |If TXCPIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |TXCPIF (EMAC_INTSTS[18]) is set. + * | | |0 = TXCPIF (EMAC_INTSTS[18]) trigger TX interrupt Disabled. + * | | |1 = TXCPIF (EMAC_INTSTS[18]) trigger TX interrupt Enabled. + * |[19] |EXDEFIEN |Defer Exceed Interrupt Enable Bit + * | | |The EXDEFIEN controls the EXDEFIF (EMAC_INTSTS[19]) interrupt generation + * | | |If EXDEFIF (EMAC_INTSTS[19]) is set, and both EXDEFIEN and TXIEN (EMAC_INTEN[16]) are enabled, + * | | |the EMAC generates the TX interrupt to CPU + * | | |If EXDEFIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |EXDEFIF (EMAC_INTSTS[19]) is set. + * | | |0 = EXDEFIF (EMAC_INTSTS[19]) trigger TX interrupt Disabled. + * | | |1 = EXDEFIF (EMAC_INTSTS[19]) trigger TX interrupt Enabled. + * |[20] |NCSIEN |No Carrier Sense Interrupt Enable Bit + * | | |The NCSIEN controls the NCSIF (EMAC_INTSTS[20]) interrupt generation + * | | |If NCSIF (EMAC_INTSTS[20]) is set, and both NCSIEN and TXIEN (EMAC_INTEN[16]) are enabled, the + * | | |EMAC generates the TX interrupt to CPU + * | | |If NCSIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |NCSIF (EMAC_INTSTS[20]) is set. + * | | |0 = NCSIF (EMAC_INTSTS[20]) trigger TX interrupt Disabled. + * | | |1 = NCSIF (EMAC_INTSTS[20]) trigger TX interrupt Enabled. + * |[21] |TXABTIEN |Transmit Abort Interrupt Enable Bit + * | | |The TXABTIEN controls the TXABTIF (EMAC_INTSTS[21]) interrupt generation + * | | |If TXABTIF (EMAC_INTSTS[21]) is set, and both TXABTIEN and TXIEN (EMAC_INTEN[16]) are enabled, + * | | |the EMAC generates the TX interrupt to CPU + * | | |If TXABTIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |TXABTIF (EMAC_INTSTS[21]) is set. + * | | |0 = TXABTIF (EMAC_INTSTS[21]) trigger TX interrupt Disabled. + * | | |1 = TXABTIF (EMAC_INTSTS[21]) trigger TX interrupt Enabled. + * |[22] |LCIEN |Late Collision Interrupt Enable Bit + * | | |The LCIEN controls the LCIF (EMAC_INTSTS[22]) interrupt generation + * | | |If LCIF (EMAC_INTSTS[22]) is set, and both LCIEN and TXIEN (EMAC_INTEN[16]) are enabled, the + * | | |EMAC generates the TX interrupt to CPU + * | | |If LCIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |LCIF (EMAC_INTSTS[22]) is set. + * | | |0 = LCIF (EMAC_INTSTS[22]) trigger TX interrupt Disabled. + * | | |1 = LCIF (EMAC_INTSTS[22]) trigger TX interrupt Enabled. + * |[23] |TDUIEN |Transmit Descriptor Unavailable Interrupt Enable Bit + * | | |The TDUIEN controls the TDUIF (EMAC_INTSTS[23]) interrupt generation + * | | |If TDUIF (EMAC_INTSTS[23]) is set, and both TDUIEN and TXIEN (EMAC_INTEN[16]) are enabled, the + * | | |EMAC generates the TX interrupt to CPU + * | | |If TDUIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |TDUIF (EMAC_INTSTS[23]) is set. + * | | |0 = TDUIF (EMAC_INTSTS[23]) trigger TX interrupt Disabled. + * | | |1 = TDUIF (EMAC_INTSTS[23]) trigger TX interrupt Enabled. + * |[24] |TXBEIEN |Transmit Bus Error Interrupt Enable Bit + * | | |The TXBEIEN controls the TXBEIF (EMAC_INTSTS[24]) interrupt generation + * | | |If TXBEIF (EMAC_INTSTS[24]) is set, and both TXBEIEN and TXIEN (EMAC_INTEN[16]) are enabled, the + * | | |EMAC generates the TX interrupt to CPU + * | | |If TXBEIEN or TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated to CPU even the + * | | |TXBEIF (EMAC_INTSTS[24]) is set. + * | | |0 = TXBEIF (EMAC_INTSTS[24]) trigger TX interrupt Disabled. + * | | |1 = TXBEIF (EMAC_INTSTS[24]) trigger TX interrupt Enabled. + * |[28] |TSALMIEN |Time Stamp Alarm Interrupt Enable Bit + * | | |The TSALMIEN controls the TSALMIF (EMAC_INTSTS[28]) interrupt generation + * | | |If TSALMIF (EMAC_INTSTS[28]) is set, and both TSALMIEN and TXIEN (EMAC_INTEN[16]) enabled, the + * | | |EMAC generates the TX interrupt to CPU + * | | |If TSALMIEN or TXIEN (EMAC_INTEN[16]) disabled, no TX interrupt generated to CPU even the + * | | |TXTSALMIF (EMAC_INTEN[28]) is set. + * | | |0 = TXTSALMIF (EMAC_INTSTS[28]) trigger TX interrupt Disabled. + * | | |1 = TXTSALMIF (EMAC_INTSTS[28]) trigger TX interrupt Enabled. + * @var EMAC_T::INTSTS + * Offset: 0xB0 MAC Interrupt Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |RXIF |Receive Interrupt + * | | |The RXIF indicates the RX interrupt status. + * | | |If RXIF high and its corresponding enable bit, RXIEN (EMAC_INTEN[0]), is also high indicates + * | | |the EMAC generates RX interrupt to CPU + * | | |If RXIF is high but RXIEN (EMAC_INTEN[0]) is disabled, no RX interrupt is generated. + * | | |The RXIF is logic OR result of bit logic AND result of EMAC_INTSTS[15:1] and EMAC_INTEN[15:1] + * | | |In other words, if any bit of EMAC_INTSTS[15:1] is high and its corresponding enable bit in + * | | |EMAC_INTEN[15:1] is also enabled, the RXIF will be high. + * | | |Because the RXIF is a logic OR result, clears EMAC_INTSTS[15:1] makes RXIF be cleared, too. + * | | |0 = No status bit in EMAC_INTSTS[15:1] is set or no enable bit in EMAC_INTEN[15:1] is enabled. + * | | |1 = At least one status in EMAC_INTSTS[15:1] is set and its corresponding enable bit in + * | | |EMAC_INTEN[15:1] is enabled, too. + * |[1] |CRCEIF |CRC Error Interrupt + * | | |The CRCEIF high indicates the incoming packet incurred the CRC error and the packet is dropped + * | | |If the AEP (EMAC_CTL[4]) is set, the CRC error packet will be regarded as a good packet and + * | | |CRCEIF will not be set. + * | | |If the CRCEIF is high and CRCEIEN (EMAC_INTEN[1]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the CRCEIF status. + * | | |0 = The frame does not incur CRC error. + * | | |1 = The frame incurred CRC error. + * |[2] |RXOVIF |Receive FIFO Overflow Interrupt + * | | |The RXOVIF high indicates the RXFIFO overflow occurred during packet reception + * | | |While the RXFIFO overflow occurred, the EMAC drops the current receiving packer + * | | |If the RXFIFO overflow occurred often, it is recommended that modify RXFIFO threshold control, + * | | |the RXFIFOTH of FFTCR register, to higher level. + * | | |If the RXOVIF is high and RXOVIEN (EMAC_INTEN[2]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the RXOVIF status. + * | | |0 = No RXFIFO overflow occurred during packet reception. + * | | |1 = RXFIFO overflow occurred during packet reception. + * |[3] |LPIF |Long Packet Interrupt Flag + * | | |The LPIF high indicates the length of the incoming packet is greater than 1518 bytes and the + * | | |incoming packet is dropped + * | | |If the ALP (EMAC_CTL[1]) is set, the long packet will be regarded as a good packet and LPIF will not be set. + * | | |If the LPIF is high and LPIEN (EMAC_INTEN[3]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the LPIF status. + * | | |0 = The incoming frame is not a long frame or S/W wants to receive a long frame. + * | | |1 = The incoming frame is a long frame and dropped. + * |[4] |RXGDIF |Receive Good Interrupt + * | | |The RXGDIF high indicates the frame reception has completed. + * | | |If the RXGDIF is high and RXGDIEN (EAMC_MIEN[4]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the RXGDIF status. + * | | |0 = The frame reception has not complete yet. + * | | |1 = The frame reception has completed. + * |[5] |ALIEIF |Alignment Error Interrupt + * | | |The ALIEIF high indicates the length of the incoming frame is not a multiple of byte + * | | |If the ALIEIF is high and ALIEIEN (EMAC_INTEN[5]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the ALIEIF status. + * | | |0 = The frame length is a multiple of byte. + * | | |1 = The frame length is not a multiple of byte. + * |[6] |RPIF |Runt Packet Interrupt + * | | |The RPIF high indicates the length of the incoming packet is less than 64 bytes and the packet is dropped + * | | |If the ARP (EMAC_CTL[2]) is set, the short packet is regarded as a good packet and RPIF will not be set. + * | | |If the RPIF is high and RPIEN (EMAC_INTEN[6]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the RPIF status. + * | | |0 = The incoming frame is not a short frame or S/W wants to receive a short frame. + * | | |1 = The incoming frame is a short frame and dropped. + * |[7] |MPCOVIF |Missed Packet Counter Overrun Interrupt Flag + * | | |The MPCOVIF high indicates the MPCNT, Missed Packet Count, has overflow + * | | |If the MPCOVIF is high and MPCOVIEN (EMAC_INTEN[7]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the MPCOVIF status. + * | | |0 = The MPCNT has not rolled over yet. + * | | |1 = The MPCNT has rolled over yet. + * |[8] |MFLEIF |Maximum Frame Length Exceed Interrupt Flag + * | | |The MFLEIF high indicates the length of the incoming packet has exceeded the length limitation + * | | |configured in DMARFC register and the incoming packet is dropped + * | | |If the MFLEIF is high and MFLEIEN (EMAC_INTEN[8]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the MFLEIF status. + * | | |0 = The length of the incoming packet does not exceed the length limitation configured in DMARFC. + * | | |1 = The length of the incoming packet has exceeded the length limitation configured in DMARFC. + * |[9] |DENIF |DMA Early Notification Interrupt + * | | |The DENIF high indicates the EMAC has received the LENGTH field of the incoming packet. + * | | |If the DENIF is high and DENIENI (EMAC_INTEN[9]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the DENIF status. + * | | |0 = The LENGTH field of incoming packet has not received yet. + * | | |1 = The LENGTH field of incoming packet has received. + * |[10] |RDUIF |Receive Descriptor Unavailable Interrupt + * | | |The RDUIF high indicates that there is no available RX descriptor for packet reception and + * | | |RXDMA will stay at Halt state + * | | |Once, the RXDMA enters the Halt state, S/W must issues a write command to RSDR register to + * | | |make RXDMA leave Halt state while new RX descriptor is available. + * | | |If the RDUIF is high and RDUIEN (EMAC_INTEN[10]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the RDUIF status. + * | | |0 = RX descriptor is available. + * | | |1 = RX descriptor is unavailable. + * |[11] |RXBEIF |Receive Bus Error Interrupt + * | | |The RXBEIF high indicates the memory controller replies ERROR response while EMAC access + * | | |system memory through RXDMA during packet reception process + * | | |Reset EMAC is recommended while RXBEIF status is high. + * | | |If the RXBEIF is high and RXBEIEN (EMAC_INTEN[11]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the RXBEIF status. + * | | |0 = No ERROR response is received. + * | | |1 = ERROR response is received. + * |[14] |CFRIF |Control Frame Receive Interrupt + * | | |The CFRIF high indicates EMAC receives a flow control frame + * | | |The CFRIF only available while EMAC is operating on full duplex mode. + * | | |If the CFRIF is high and CFRIEN (EMAC_INTEN[14]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the CFRIF status. + * | | |0 = The EMAC does not receive the flow control frame. + * | | |1 = The EMAC receives a flow control frame. + * |[15] |WOLIF |Wake on LAN Interrupt Flag + * | | |The WOLIF high indicates EMAC receives a Magic Packet + * | | |The CFRIF only available while system is in power down mode and WOLEN is set high. + * | | |If the WOLIF is high and WOLIEN (EMAC_INTEN[15]) is enabled, the RXIF will be high + * | | |Write 1 to this bit clears the WOLIF status. + * | | |0 = The EMAC does not receive the Magic Packet. + * | | |1 = The EMAC receives a Magic Packet. + * |[16] |TXIF |Transmit Interrupt + * | | |The TXIF indicates the TX interrupt status. + * | | |If TXIF high and its corresponding enable bit, TXIEN (EMAC_INTEN[16]), is also high indicates + * | | |the EMAC generates TX interrupt to CPU + * | | |If TXIF is high but TXIEN (EMAC_INTEN[16]) is disabled, no TX interrupt is generated. + * | | |The TXIF is logic OR result of bit logic AND result of EMAC_INTSTS[28:17] and EMAC_INTEN[28:17] + * | | |In other words, if any bit of EMAC_INTSTS[28:17] is high and its corresponding enable bit + * | | |in EMAC_INTEN[28:17] is also enabled, the TXIF will be high + * | | |Because the TXIF is a logic OR result, clears EMAC_INTSTS[28:17] makes TXIF be cleared, too. + * | | |0 = No status bit in EMAC_INTSTS[28:17] is set or no enable bit in EMAC_INTEN[28:17] is enabled. + * | | |1 = At least one status in EMAC_INTSTS[28:17] is set and its corresponding enable bit + * | | |in EMAC_INTEN[28:17] is enabled, too. + * |[17] |TXUDIF |Transmit FIFO Underflow Interrupt + * | | |The TXUDIF high indicates the TXFIFO underflow occurred during packet transmission + * | | |While the TXFIFO underflow occurred, the EMAC will retransmit the packet automatically + * | | |without S/W intervention + * | | |If the TXFIFO underflow occurred often, it is recommended that modify TXFIFO threshold control, + * | | |the TXFIFOTH of FFTCR register, to higher level. + * | | |If the TXUDIF is high and TXUDIEN (EMAC_INTEN[17]) is enabled, the TXIF will be high + * | | |Write 1 to this bit clears the TXUDIF status. + * | | |0 = No TXFIFO underflow occurred during packet transmission. + * | | |1 = TXFIFO underflow occurred during packet transmission. + * |[18] |TXCPIF |Transmit Completion Interrupt + * | | |The TXCPIF indicates the packet transmission has completed correctly. + * | | |If the TXCPIF is high and TXCPIEN (EMAC_INTEN[18]) is enabled, the TXIF will be high + * | | |Write 1 to this bit clears the TXCPIF status. + * | | |0 = The packet transmission not completed. + * | | |1 = The packet transmission has completed. + * |[19] |EXDEFIF |Defer Exceed Interrupt + * | | |The EXDEFIF high indicates the frame waiting for transmission has deferred over 0.32768ms + * | | |on 100Mbps mode, or 3.2768ms on 10Mbps mode. + * | | |The deferral exceed check will only be done while bit NODEF of MCMDR is disabled, and EMAC + * | | |is operating on half-duplex mode. + * | | |If the EXDEFIF is high and EXDEFIEN (EMAC_INTEN[19]) is enabled, the TXIF will be high + * | | |Write 1 to this bit clears the EXDEFIF status. + * | | |0 = Frame waiting for transmission has not deferred over 0.32768ms (100Mbps) or 3.2768ms (10Mbps). + * | | |1 = Frame waiting for transmission has deferred over 0.32768ms (100Mbps) or 3.2768ms (10Mbps). + * |[20] |NCSIF |No Carrier Sense Interrupt + * | | |The NCSIF high indicates the MII I/F signal CRS does not active at the start of or during + * | | |the packet transmission + * | | |The NCSIF is only available while EMAC is operating on half-duplex mode + * | | |If the NCSIF is high and NCSIEN (EMAC_INTEN[20]) is enabled, the TXIF will be high. + * | | |Write 1 to this bit clears the NCSIF status. + * | | |0 = CRS signal actives correctly. + * | | |1 = CRS signal does not active at the start of or during the packet transmission. + * |[21] |TXABTIF |Transmit Abort Interrupt + * | | |The TXABTIF high indicates the packet incurred 16 consecutive collisions during transmission, + * | | |and then the transmission process for this packet is aborted + * | | |The transmission abort is only available while EMAC is operating on half-duplex mode. + * | | |If the TXABTIF is high and TXABTIEN (EMAC_INTEN[21]) is enabled, the TXIF will be high + * | | |Write 1 to this bit clears the TXABTIF status. + * | | |0 = Packet does not incur 16 consecutive collisions during transmission. + * | | |1 = Packet incurred 16 consecutive collisions during transmission. + * |[22] |LCIF |Late Collision Interrupt + * | | |The LCIF high indicates the collision occurred in the outside of 64 bytes collision window + * | | |This means after the 64 bytes of a frame has been transmitted out to the network, the collision + * | | |still occurred. + * | | |The late collision check will only be done while EMAC is operating on half-duplex mode + * | | |If the LCIF is high and LCIEN (EMAC_INTEN[22]) is enabled, the TXIF will be high. + * | | |Write 1 to this bit clears the LCIF status. + * | | |0 = No collision occurred in the outside of 64 bytes collision window. + * | | |1 = Collision occurred in the outside of 64 bytes collision window. + * |[23] |TDUIF |Transmit Descriptor Unavailable Interrupt + * | | |The TDUIF high indicates that there is no available TX descriptor for packet transmission and + * | | |TXDMA will stay at Halt state. + * | | |Once, the TXDMA enters the Halt state, S/W must issues a write command to TSDR register to make + * | | |TXDMA leave Halt state while new TX descriptor is available. + * | | |If the TDUIF is high and TDUIEN (EMAC_INTEN[23]) is enabled, the TXIF will be high. + * | | |Write 1 to this bit clears the TDUIF status. + * | | |0 = TX descriptor is available. + * | | |1 = TX descriptor is unavailable. + * |[24] |TXBEIF |Transmit Bus Error Interrupt + * | | |The TXBEIF high indicates the memory controller replies ERROR response while EMAC access system + * | | |memory through TXDMA during packet transmission process + * | | |Reset EMAC is recommended while TXBEIF status is high. + * | | |If the TXBEIF is high and TXBEIEN (EMAC_INTEN[24]) is enabled, the TXIF will be high. + * | | |Write 1 to this bit clears the TXBEIF status. + * | | |0 = No ERROR response is received. + * | | |1 = ERROR response is received. + * |[28] |TSALMIF |Time Stamp Alarm Interrupt + * | | |The TSALMIF high indicates the EMAC_TSSEC register value equals to EMAC_ALMSEC register and + * | | |EMAC_TSSUBSEC register value equals to register EMAC_ALMSUBLSR. + * | | |If TSALMIF is high and TSALMIEN (EMAC_INTEN[28]) enabled, the TXIF will be high. + * | | |Write 1 to this bit clears the TSALMIF status. + * | | |0 = EMAC_TSSEC did not equal EMAC_ALMSEC or EMAC_TSSUBSEC did not equal EMAC_ALMSUBSEC. + * | | |1 = EMAC_TSSEC equals EMAC_ALMSEC and EMAC_TSSUBSEC equals EMAC_ALMSUBSEC. + * @var EMAC_T::GENSTS + * Offset: 0xB4 MAC General Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |CFR |Control Frame Received + * | | |The CFRIF high indicates EMAC receives a flow control frame + * | | |The CFRIF only available while EMAC is operating on full duplex mode. + * | | |0 = The EMAC does not receive the flow control frame. + * | | |1 = The EMAC receives a flow control frame. + * |[1] |RXHALT |Receive Halted + * | | |The RXHALT high indicates the next normal packet reception process will be halted because + * | | |the bit RXON of MCMDR is disabled be S/W. + * | | |0 = Next normal packet reception process will go on. + * | | |1 = Next normal packet reception process will be halted. + * |[2] |RXFFULL |RXFIFO Full + * | | |The RXFFULL indicates the RXFIFO is full due to four 64-byte packets are kept in RXFIFO + * | | |and the following incoming packet will be dropped. + * | | |0 = The RXFIFO is not full. + * | | |1 = The RXFIFO is full and the following incoming packet will be dropped. + * |[7:4] |COLCNT |Collision Count + * | | |The COLCNT indicates that how many collisions occurred consecutively during a packet transmission + * | | |If the packet incurred 16 consecutive collisions during transmission, the COLCNT will be + * | | |0 and bit TXABTIF will be set to 1. + * |[8] |DEF |Deferred Transmission + * | | |The DEF high indicates the packet transmission has deferred once + * | | |The DEF is only available while EMAC is operating on half-duplex mode. + * | | |0 = Packet transmission does not defer. + * | | |1 = Packet transmission has deferred once. + * |[9] |TXPAUSED |Transmission Paused + * | | |The TXPAUSED high indicates the next normal packet transmission process will be paused temporally + * | | |because EMAC received a PAUSE control frame. + * | | |0 = Next normal packet transmission process will go on. + * | | |1 = Next normal packet transmission process will be paused. + * |[10] |SQE |Signal Quality Error + * | | |The SQE high indicates the SQE error found at end of packet transmission on 10Mbps half-duplex mode + * | | |The SQE error check will only be done while both bit SQECHKEN (EMAC_CTL[17]) is enabled and EMAC + * | | |is operating on 10Mbps half-duplex mode. + * | | |0 = No SQE error found at end of packet transmission. + * | | |1 = SQE error found at end of packet transmission. + * |[11] |TXHALT |Transmission Halted + * | | |The TXHALT high indicates the next normal packet transmission process will be halted because + * | | |the bit TXON (EMAC_CTL[8]) is disabled be S/W. + * | | |0 = Next normal packet transmission process will go on. + * | | |1 = Next normal packet transmission process will be halted. + * |[12] |RPSTS |Remote Pause Status + * | | |The RPSTS indicates that remote pause counter down counting actives. + * | | |After Ethernet MAC controller sent PAUSE frame out successfully, it starts the remote pause + * | | |counter down counting + * | | |When this bit high, it's predictable that remote Ethernet MAC controller wouldn't start the packet + * | | |transmission until the down counting done. + * | | |0 = Remote pause counter down counting done. + * | | |1 = Remote pause counter down counting actives. + * @var EMAC_T::MPCNT + * Offset: 0xB8 Missed Packet Count Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |MPCNT |Miss Packet Count + * | | |The MPCNT indicates the number of packets that were dropped due to various types of receive errors + * | | |The following type of receiving error makes missed packet counter increase: + * | | |1. Incoming packet is incurred RXFIFO overflow. + * | | |2. Incoming packet is dropped due to RXON is disabled. + * | | |3. Incoming packet is incurred CRC error. + * @var EMAC_T::RPCNT + * Offset: 0xBC MAC Receive Pause Count Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |RPCNT |MAC Receive Pause Count + * | | |The RPCNT keeps the OPERAND field of the PAUSE control frame + * | | |It indicates how many slot time (512 bit time) the TX of EMAC will be paused. + * @var EMAC_T::FRSTS + * Offset: 0xC8 DMA Receive Frame Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |RXFLT |Receive Frame LENGTH + * | | |The RXFLT keeps the LENGTH field of each incoming Ethernet packet + * | | |If the bit DENIEN (EMAC_INTEN[9]) is enabled and the LENGTH field of incoming packet has + * | | |received, the bit DENIF (EMAC_INTSTS[9]) will be set and trigger interrupt. + * | | |And, the content of LENGTH field will be stored in RXFLT. + * @var EMAC_T::CTXDSA + * Offset: 0xCC Current Transmit Descriptor Start Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |CTXDSA |Current Transmit Descriptor Start Address + * | | |The CTXDSA keeps the start address of TX descriptor that is used by TXDMA currently + * | | |The CTXDSA is read only and write to this register has no effect. + * @var EMAC_T::CTXBSA + * Offset: 0xD0 Current Transmit Buffer Start Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |CTXBSA |Current Transmit Buffer Start Address + * | | |The CTXDSA keeps the start address of TX frame buffer that is used by TXDMA currently + * | | |The CTXBSA is read only and write to this register has no effect. + * @var EMAC_T::CRXDSA + * Offset: 0xD4 Current Receive Descriptor Start Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |CRXDSA |Current Receive Descriptor Start Address + * | | |The CRXDSA keeps the start address of RX descriptor that is used by RXDMA currently + * | | |The CRXDSA is read only and write to this register has no effect. + * @var EMAC_T::CRXBSA + * Offset: 0xD8 Current Receive Buffer Start Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |CRXBSA |Current Receive Buffer Start Address + * | | |The CRXBSA keeps the start address of RX frame buffer that is used by RXDMA currently + * | | |The CRXBSA is read only and write to this register has no effect. + * @var EMAC_T::TSCTL + * Offset: 0x100 Time Stamp Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |TSEN |Time Stamp Function Enable Bit + * | | |This bit controls if the IEEE 1588 PTP time stamp function is enabled or not. + * | | |Set this bit high to enable IEEE 1588 PTP time stamp function while set this bit low + * | | |to disable IEEE 1588 PTP time stamp function. + * | | |0 = I EEE 1588 PTP time stamp function Disabled. + * | | |1 = IEEE 1588 PTP time stamp function Enabled. + * |[1] |TSIEN |Time Stamp Counter Initialization Enable Bit + * | | |Set this bit high enables Ethernet MAC controller to load value of register EMAC_UPDSEC + * | | |and EMAC_UPDSUBSEC to PTP time stamp counter. + * | | |After the load operation finished, Ethernet MAC controller clear this bit to low automatically. + * | | |0 = Time stamp counter initialization done. + * | | |1 = Time stamp counter initialization Enabled. + * |[2] |TSMODE |Time Stamp Fine Update Enable Bit + * | | |This bit chooses the time stamp counter update mode. + * | | |0 = Time stamp counter is in coarse update mode. + * | | |1 = Time stamp counter is in fine update mode. + * |[3] |TSUPDATE |Time Stamp Counter Time Update Enable Bit + * | | |Set this bit high enables Ethernet MAC controller to add value of register EMAC_UPDSEC and + * | | |EMAC_UPDSUBSEC to PTP time stamp counter. + * | | |After the add operation finished, Ethernet MAC controller clear this bit to low automatically. + * | | |0 = No action. + * | | |1 = EMAC_UPDSEC updated to EMAC_TSSEC and EMAC_UPDSUBSEC updated to EMAC_TSSUBSEC. + * |[5] |TSALMEN |Time Stamp Alarm Enable Bit + * | | |Set this bit high enable Ethernet MAC controller to set TSALMIF (EMAC_INTSTS[28]) high when + * | | |EMAC_TSSEC equals to EMAC_ALMSEC and EMAC_TSSUBSEC equals to EMAC_ALMSUBSEC. + * | | |0 = Alarm disabled when EMAC_TSSEC equals to EMAC_ALMSEC and EMAC_TSSUBSEC equals to EMAC_ALMSUBSEC. + * | | |1 = Alarm enabled when EMAC_TSSEC equals to EMAC_ALMSEC and EMAC_TSSUBSEC equals to EMAC_ALMSUBSEC. + * @var EMAC_T::TSSEC + * Offset: 0x110 Time Stamp Counter Second Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |SEC |Time Stamp Counter Second + * | | |This register reflects the bit [63:32] value of 64-bit reference timing counter + * | | |This 32-bit value is used as the second part of time stamp when TSEN (EMAC_TSCTL[0]) is high. + * @var EMAC_T::TSSUBSEC + * Offset: 0x114 Time Stamp Counter Sub Second Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |SUBSEC |Time Stamp Counter Sub-second + * | | |This register reflects the bit [31:0] value of 64-bit reference timing counter + * | | |This 32-bit value is used as the sub-second part of time stamp when TSEN (EMAC_TSCTL[0]) is high. + * @var EMAC_T::TSINC + * Offset: 0x118 Time Stamp Increment Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |CNTINC |Time Stamp Counter Increment + * | | |Time stamp counter increment value. + * | | |If TSEN (EMAC_TSCTL[0]) is high, EMAC adds EMAC_TSSUBSEC with this 8-bit value every + * | | |time when it wants to increase the EMAC_TSSUBSEC value. + * @var EMAC_T::TSADDEND + * Offset: 0x11C Time Stamp Addend Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |ADDEND |Time Stamp Counter Addend + * | | |This register keeps a 32-bit value for accumulator to enable increment of EMAC_TSSUBSEC. + * | | |If TSEN (EMAC_TSCTL[0]) and TSMODE (EMAC_TSCTL[2]) are both high, EMAC increases accumulator + * | | |with this 32-bit value in each HCLK + * | | |Once the accumulator is overflow, it generates a enable to increase EMAC_TSSUBSEC with an 8-bit + * | | |value kept in register EMAC_TSINC. + * @var EMAC_T::UPDSEC + * Offset: 0x120 Time Stamp Update Second Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |SEC |Time Stamp Counter Second Update + * | | |When TSIEN (EMAC_TSCTL[1]) is high + * | | |EMAC loads this 32-bit value to EMAC_TSSEC directly + * | | |When TSUPDATE (EMAC_TSCTL[3]) is high, EMAC increases EMAC_TSSEC with this 32-bit value. + * @var EMAC_T::UPDSUBSEC + * Offset: 0x124 Time Stamp Update Sub Second Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |SUBSEC |Time Stamp Counter Sub-second Update + * | | |When TSIEN (EMAC_TSCTL[1]) is high + * | | |EMAC loads this 32-bit value to EMAC_TSSUBSEC directly + * | | |When TSUPDATE (EMAC_TSCTL[3]) is high, EMAC increases EMAC_TSSUBSEC with this 32-bit value. + * @var EMAC_T::ALMSEC + * Offset: 0x128 Time Stamp Alarm Second Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |SEC |Time Stamp Counter Second Alarm + * | | |Time stamp counter second part alarm value. + * | | |This value is only useful when ALMEN (EMAC_TSCTL[5]) high + * | | |If ALMEN (EMAC_TSCTL[5]) is high, EMAC_TSSEC equals to EMAC_ALMSEC and EMAC_TSSUBSEC equals to + * | | |EMAC_ALMSUBSEC, Ethernet MAC controller set TSALMIF (EMAC_INTSTS[28]) high. + * @var EMAC_T::ALMSUBSEC + * Offset: 0x12C Time Stamp Alarm Sub Second Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |SUBSEC |Time Stamp Counter Sub-second Alarm + * | | |Time stamp counter sub-second part alarm value. + * | | |This value is only useful when ALMEN (EMAC_TSCTL[5]) high + * | | |If ALMEN (EMAC_TSCTL[5]) is high, EMAC_TSSEC equals to EMAC_ALMSEC and EMAC_TSSUBSEC equals to + * | | |EMAC_ALMSUBSEC, Ethernet MAC controller set TSALMIF (EMAC_INTSTS[28]) high. + */ + __IO uint32_t CAMCTL; /*!< [0x0000] CAM Comparison Control Register */ + __IO uint32_t CAMEN; /*!< [0x0004] CAM Enable Register */ + __IO uint32_t CAM0M; /*!< [0x0008] CAM0 Most Significant Word Register */ + __IO uint32_t CAM0L; /*!< [0x000c] CAM0 Least Significant Word Register */ + __IO uint32_t CAM1M; /*!< [0x0010] CAM1 Most Significant Word Register */ + __IO uint32_t CAM1L; /*!< [0x0014] CAM1 Least Significant Word Register */ + __IO uint32_t CAM2M; /*!< [0x0018] CAM2 Most Significant Word Register */ + __IO uint32_t CAM2L; /*!< [0x001c] CAM2 Least Significant Word Register */ + __IO uint32_t CAM3M; /*!< [0x0020] CAM3 Most Significant Word Register */ + __IO uint32_t CAM3L; /*!< [0x0024] CAM3 Least Significant Word Register */ + __IO uint32_t CAM4M; /*!< [0x0028] CAM4 Most Significant Word Register */ + __IO uint32_t CAM4L; /*!< [0x002c] CAM4 Least Significant Word Register */ + __IO uint32_t CAM5M; /*!< [0x0030] CAM5 Most Significant Word Register */ + __IO uint32_t CAM5L; /*!< [0x0034] CAM5 Least Significant Word Register */ + __IO uint32_t CAM6M; /*!< [0x0038] CAM6 Most Significant Word Register */ + __IO uint32_t CAM6L; /*!< [0x003c] CAM6 Least Significant Word Register */ + __IO uint32_t CAM7M; /*!< [0x0040] CAM7 Most Significant Word Register */ + __IO uint32_t CAM7L; /*!< [0x0044] CAM7 Least Significant Word Register */ + __IO uint32_t CAM8M; /*!< [0x0048] CAM8 Most Significant Word Register */ + __IO uint32_t CAM8L; /*!< [0x004c] CAM8 Least Significant Word Register */ + __IO uint32_t CAM9M; /*!< [0x0050] CAM9 Most Significant Word Register */ + __IO uint32_t CAM9L; /*!< [0x0054] CAM9 Least Significant Word Register */ + __IO uint32_t CAM10M; /*!< [0x0058] CAM10 Most Significant Word Register */ + __IO uint32_t CAM10L; /*!< [0x005c] CAM10 Least Significant Word Register */ + __IO uint32_t CAM11M; /*!< [0x0060] CAM11 Most Significant Word Register */ + __IO uint32_t CAM11L; /*!< [0x0064] CAM11 Least Significant Word Register */ + __IO uint32_t CAM12M; /*!< [0x0068] CAM12 Most Significant Word Register */ + __IO uint32_t CAM12L; /*!< [0x006c] CAM12 Least Significant Word Register */ + __IO uint32_t CAM13M; /*!< [0x0070] CAM13 Most Significant Word Register */ + __IO uint32_t CAM13L; /*!< [0x0074] CAM13 Least Significant Word Register */ + __IO uint32_t CAM14M; /*!< [0x0078] CAM14 Most Significant Word Register */ + __IO uint32_t CAM14L; /*!< [0x007c] CAM14 Least Significant Word Register */ + __IO uint32_t CAM15MSB; /*!< [0x0080] CAM15 Most Significant Word Register */ + __IO uint32_t CAM15LSB; /*!< [0x0084] CAM15 Least Significant Word Register */ + __IO uint32_t TXDSA; /*!< [0x0088] Transmit Descriptor Link List Start Address Register */ + __IO uint32_t RXDSA; /*!< [0x008c] Receive Descriptor Link List Start Address Register */ + __IO uint32_t CTL; /*!< [0x0090] MAC Control Register */ + __IO uint32_t MIIMDAT; /*!< [0x0094] MII Management Data Register */ + __IO uint32_t MIIMCTL; /*!< [0x0098] MII Management Control and Address Register */ + __IO uint32_t FIFOCTL; /*!< [0x009c] FIFO Threshold Control Register */ + __O uint32_t TXST; /*!< [0x00a0] Transmit Start Demand Register */ + __O uint32_t RXST; /*!< [0x00a4] Receive Start Demand Register */ + __IO uint32_t MRFL; /*!< [0x00a8] Maximum Receive Frame Control Register */ + __IO uint32_t INTEN; /*!< [0x00ac] MAC Interrupt Enable Register */ + __IO uint32_t INTSTS; /*!< [0x00b0] MAC Interrupt Status Register */ + __IO uint32_t GENSTS; /*!< [0x00b4] MAC General Status Register */ + __IO uint32_t MPCNT; /*!< [0x00b8] Missed Packet Count Register */ + __I uint32_t RPCNT; /*!< [0x00bc] MAC Receive Pause Count Register */ + /** @cond HIDDEN_SYMBOLS */ + __I uint32_t RESERVE0[2]; + /** @endcond */ + __IO uint32_t FRSTS; /*!< [0x00c8] DMA Receive Frame Status Register */ + __I uint32_t CTXDSA; /*!< [0x00cc] Current Transmit Descriptor Start Address Register */ + __I uint32_t CTXBSA; /*!< [0x00d0] Current Transmit Buffer Start Address Register */ + __I uint32_t CRXDSA; /*!< [0x00d4] Current Receive Descriptor Start Address Register */ + __I uint32_t CRXBSA; /*!< [0x00d8] Current Receive Buffer Start Address Register */ + /** @cond HIDDEN_SYMBOLS */ + __I uint32_t RESERVE1[9]; + /** @endcond */ + __IO uint32_t TSCTL; /*!< [0x0100] Time Stamp Control Register */ + /** @cond HIDDEN_SYMBOLS */ + __I uint32_t RESERVE2[3]; + /** @endcond */ + __I uint32_t TSSEC; /*!< [0x0110] Time Stamp Counter Second Register */ + __I uint32_t TSSUBSEC; /*!< [0x0114] Time Stamp Counter Sub Second Register */ + __IO uint32_t TSINC; /*!< [0x0118] Time Stamp Increment Register */ + __IO uint32_t TSADDEND; /*!< [0x011c] Time Stamp Addend Register */ + __IO uint32_t UPDSEC; /*!< [0x0120] Time Stamp Update Second Register */ + __IO uint32_t UPDSUBSEC; /*!< [0x0124] Time Stamp Update Sub Second Register */ + __IO uint32_t ALMSEC; /*!< [0x0128] Time Stamp Alarm Second Register */ + __IO uint32_t ALMSUBSEC; /*!< [0x012c] Time Stamp Alarm Sub Second Register */ + +} EMAC_T; + +/** + @addtogroup EMAC_CONST EMAC Bit Field Definition + Constant Definitions for EMAC Controller +@{ */ + +#define EMAC_CAMCTL_AUP_Pos (0) /*!< EMAC_T::CAMCTL: AUP Position */ +#define EMAC_CAMCTL_AUP_Msk (0x1ul << EMAC_CAMCTL_AUP_Pos) /*!< EMAC_T::CAMCTL: AUP Mask */ + +#define EMAC_CAMCTL_AMP_Pos (1) /*!< EMAC_T::CAMCTL: AMP Position */ +#define EMAC_CAMCTL_AMP_Msk (0x1ul << EMAC_CAMCTL_AMP_Pos) /*!< EMAC_T::CAMCTL: AMP Mask */ + +#define EMAC_CAMCTL_ABP_Pos (2) /*!< EMAC_T::CAMCTL: ABP Position */ +#define EMAC_CAMCTL_ABP_Msk (0x1ul << EMAC_CAMCTL_ABP_Pos) /*!< EMAC_T::CAMCTL: ABP Mask */ + +#define EMAC_CAMCTL_COMPEN_Pos (3) /*!< EMAC_T::CAMCTL: COMPEN Position */ +#define EMAC_CAMCTL_COMPEN_Msk (0x1ul << EMAC_CAMCTL_COMPEN_Pos) /*!< EMAC_T::CAMCTL: COMPEN Mask */ + +#define EMAC_CAMCTL_CMPEN_Pos (4) /*!< EMAC_T::CAMCTL: CMPEN Position */ +#define EMAC_CAMCTL_CMPEN_Msk (0x1ul << EMAC_CAMCTL_CMPEN_Pos) /*!< EMAC_T::CAMCTL: CMPEN Mask */ + +#define EMAC_CAMEN_CAMxEN_Pos (0) /*!< EMAC_T::CAMEN: CAMxEN Position */ +#define EMAC_CAMEN_CAMxEN_Msk (0x1ul << EMAC_CAMEN_CAMxEN_Pos) /*!< EMAC_T::CAMEN: CAMxEN Mask */ + +#define EMAC_CAM0M_MACADDR2_Pos (0) /*!< EMAC_T::CAM0M: MACADDR2 Position */ +#define EMAC_CAM0M_MACADDR2_Msk (0xfful << EMAC_CAM0M_MACADDR2_Pos) /*!< EMAC_T::CAM0M: MACADDR2 Mask */ + +#define EMAC_CAM0M_MACADDR3_Pos (8) /*!< EMAC_T::CAM0M: MACADDR3 Position */ +#define EMAC_CAM0M_MACADDR3_Msk (0xfful << EMAC_CAM0M_MACADDR3_Pos) /*!< EMAC_T::CAM0M: MACADDR3 Mask */ + +#define EMAC_CAM0M_MACADDR4_Pos (16) /*!< EMAC_T::CAM0M: MACADDR4 Position */ +#define EMAC_CAM0M_MACADDR4_Msk (0xfful << EMAC_CAM0M_MACADDR4_Pos) /*!< EMAC_T::CAM0M: MACADDR4 Mask */ + +#define EMAC_CAM0M_MACADDR5_Pos (24) /*!< EMAC_T::CAM0M: MACADDR5 Position */ +#define EMAC_CAM0M_MACADDR5_Msk (0xfful << EMAC_CAM0M_MACADDR5_Pos) /*!< EMAC_T::CAM0M: MACADDR5 Mask */ + +#define EMAC_CAM0L_MACADDR0_Pos (16) /*!< EMAC_T::CAM0L: MACADDR0 Position */ +#define EMAC_CAM0L_MACADDR0_Msk (0xfful << EMAC_CAM0L_MACADDR0_Pos) /*!< EMAC_T::CAM0L: MACADDR0 Mask */ + +#define EMAC_CAM0L_MACADDR1_Pos (24) /*!< EMAC_T::CAM0L: MACADDR1 Position */ +#define EMAC_CAM0L_MACADDR1_Msk (0xfful << EMAC_CAM0L_MACADDR1_Pos) /*!< EMAC_T::CAM0L: MACADDR1 Mask */ + +#define EMAC_CAM1M_MACADDR2_Pos (0) /*!< EMAC_T::CAM1M: MACADDR2 Position */ +#define EMAC_CAM1M_MACADDR2_Msk (0xfful << EMAC_CAM1M_MACADDR2_Pos) /*!< EMAC_T::CAM1M: MACADDR2 Mask */ + +#define EMAC_CAM1M_MACADDR3_Pos (8) /*!< EMAC_T::CAM1M: MACADDR3 Position */ +#define EMAC_CAM1M_MACADDR3_Msk (0xfful << EMAC_CAM1M_MACADDR3_Pos) /*!< EMAC_T::CAM1M: MACADDR3 Mask */ + +#define EMAC_CAM1M_MACADDR4_Pos (16) /*!< EMAC_T::CAM1M: MACADDR4 Position */ +#define EMAC_CAM1M_MACADDR4_Msk (0xfful << EMAC_CAM1M_MACADDR4_Pos) /*!< EMAC_T::CAM1M: MACADDR4 Mask */ + +#define EMAC_CAM1M_MACADDR5_Pos (24) /*!< EMAC_T::CAM1M: MACADDR5 Position */ +#define EMAC_CAM1M_MACADDR5_Msk (0xfful << EMAC_CAM1M_MACADDR5_Pos) /*!< EMAC_T::CAM1M: MACADDR5 Mask */ + +#define EMAC_CAM1L_MACADDR0_Pos (16) /*!< EMAC_T::CAM1L: MACADDR0 Position */ +#define EMAC_CAM1L_MACADDR0_Msk (0xfful << EMAC_CAM1L_MACADDR0_Pos) /*!< EMAC_T::CAM1L: MACADDR0 Mask */ + +#define EMAC_CAM1L_MACADDR1_Pos (24) /*!< EMAC_T::CAM1L: MACADDR1 Position */ +#define EMAC_CAM1L_MACADDR1_Msk (0xfful << EMAC_CAM1L_MACADDR1_Pos) /*!< EMAC_T::CAM1L: MACADDR1 Mask */ + +#define EMAC_CAM2M_MACADDR2_Pos (0) /*!< EMAC_T::CAM2M: MACADDR2 Position */ +#define EMAC_CAM2M_MACADDR2_Msk (0xfful << EMAC_CAM2M_MACADDR2_Pos) /*!< EMAC_T::CAM2M: MACADDR2 Mask */ + +#define EMAC_CAM2M_MACADDR3_Pos (8) /*!< EMAC_T::CAM2M: MACADDR3 Position */ +#define EMAC_CAM2M_MACADDR3_Msk (0xfful << EMAC_CAM2M_MACADDR3_Pos) /*!< EMAC_T::CAM2M: MACADDR3 Mask */ + +#define EMAC_CAM2M_MACADDR4_Pos (16) /*!< EMAC_T::CAM2M: MACADDR4 Position */ +#define EMAC_CAM2M_MACADDR4_Msk (0xfful << EMAC_CAM2M_MACADDR4_Pos) /*!< EMAC_T::CAM2M: MACADDR4 Mask */ + +#define EMAC_CAM2M_MACADDR5_Pos (24) /*!< EMAC_T::CAM2M: MACADDR5 Position */ +#define EMAC_CAM2M_MACADDR5_Msk (0xfful << EMAC_CAM2M_MACADDR5_Pos) /*!< EMAC_T::CAM2M: MACADDR5 Mask */ + +#define EMAC_CAM2L_MACADDR0_Pos (16) /*!< EMAC_T::CAM2L: MACADDR0 Position */ +#define EMAC_CAM2L_MACADDR0_Msk (0xfful << EMAC_CAM2L_MACADDR0_Pos) /*!< EMAC_T::CAM2L: MACADDR0 Mask */ + +#define EMAC_CAM2L_MACADDR1_Pos (24) /*!< EMAC_T::CAM2L: MACADDR1 Position */ +#define EMAC_CAM2L_MACADDR1_Msk (0xfful << EMAC_CAM2L_MACADDR1_Pos) /*!< EMAC_T::CAM2L: MACADDR1 Mask */ + +#define EMAC_CAM3M_MACADDR2_Pos (0) /*!< EMAC_T::CAM3M: MACADDR2 Position */ +#define EMAC_CAM3M_MACADDR2_Msk (0xfful << EMAC_CAM3M_MACADDR2_Pos) /*!< EMAC_T::CAM3M: MACADDR2 Mask */ + +#define EMAC_CAM3M_MACADDR3_Pos (8) /*!< EMAC_T::CAM3M: MACADDR3 Position */ +#define EMAC_CAM3M_MACADDR3_Msk (0xfful << EMAC_CAM3M_MACADDR3_Pos) /*!< EMAC_T::CAM3M: MACADDR3 Mask */ + +#define EMAC_CAM3M_MACADDR4_Pos (16) /*!< EMAC_T::CAM3M: MACADDR4 Position */ +#define EMAC_CAM3M_MACADDR4_Msk (0xfful << EMAC_CAM3M_MACADDR4_Pos) /*!< EMAC_T::CAM3M: MACADDR4 Mask */ + +#define EMAC_CAM3M_MACADDR5_Pos (24) /*!< EMAC_T::CAM3M: MACADDR5 Position */ +#define EMAC_CAM3M_MACADDR5_Msk (0xfful << EMAC_CAM3M_MACADDR5_Pos) /*!< EMAC_T::CAM3M: MACADDR5 Mask */ + +#define EMAC_CAM3L_MACADDR0_Pos (16) /*!< EMAC_T::CAM3L: MACADDR0 Position */ +#define EMAC_CAM3L_MACADDR0_Msk (0xfful << EMAC_CAM3L_MACADDR0_Pos) /*!< EMAC_T::CAM3L: MACADDR0 Mask */ + +#define EMAC_CAM3L_MACADDR1_Pos (24) /*!< EMAC_T::CAM3L: MACADDR1 Position */ +#define EMAC_CAM3L_MACADDR1_Msk (0xfful << EMAC_CAM3L_MACADDR1_Pos) /*!< EMAC_T::CAM3L: MACADDR1 Mask */ + +#define EMAC_CAM4M_MACADDR2_Pos (0) /*!< EMAC_T::CAM4M: MACADDR2 Position */ +#define EMAC_CAM4M_MACADDR2_Msk (0xfful << EMAC_CAM4M_MACADDR2_Pos) /*!< EMAC_T::CAM4M: MACADDR2 Mask */ + +#define EMAC_CAM4M_MACADDR3_Pos (8) /*!< EMAC_T::CAM4M: MACADDR3 Position */ +#define EMAC_CAM4M_MACADDR3_Msk (0xfful << EMAC_CAM4M_MACADDR3_Pos) /*!< EMAC_T::CAM4M: MACADDR3 Mask */ + +#define EMAC_CAM4M_MACADDR4_Pos (16) /*!< EMAC_T::CAM4M: MACADDR4 Position */ +#define EMAC_CAM4M_MACADDR4_Msk (0xfful << EMAC_CAM4M_MACADDR4_Pos) /*!< EMAC_T::CAM4M: MACADDR4 Mask */ + +#define EMAC_CAM4M_MACADDR5_Pos (24) /*!< EMAC_T::CAM4M: MACADDR5 Position */ +#define EMAC_CAM4M_MACADDR5_Msk (0xfful << EMAC_CAM4M_MACADDR5_Pos) /*!< EMAC_T::CAM4M: MACADDR5 Mask */ + +#define EMAC_CAM4L_MACADDR0_Pos (16) /*!< EMAC_T::CAM4L: MACADDR0 Position */ +#define EMAC_CAM4L_MACADDR0_Msk (0xfful << EMAC_CAM4L_MACADDR0_Pos) /*!< EMAC_T::CAM4L: MACADDR0 Mask */ + +#define EMAC_CAM4L_MACADDR1_Pos (24) /*!< EMAC_T::CAM4L: MACADDR1 Position */ +#define EMAC_CAM4L_MACADDR1_Msk (0xfful << EMAC_CAM4L_MACADDR1_Pos) /*!< EMAC_T::CAM4L: MACADDR1 Mask */ + +#define EMAC_CAM5M_MACADDR2_Pos (0) /*!< EMAC_T::CAM5M: MACADDR2 Position */ +#define EMAC_CAM5M_MACADDR2_Msk (0xfful << EMAC_CAM5M_MACADDR2_Pos) /*!< EMAC_T::CAM5M: MACADDR2 Mask */ + +#define EMAC_CAM5M_MACADDR3_Pos (8) /*!< EMAC_T::CAM5M: MACADDR3 Position */ +#define EMAC_CAM5M_MACADDR3_Msk (0xfful << EMAC_CAM5M_MACADDR3_Pos) /*!< EMAC_T::CAM5M: MACADDR3 Mask */ + +#define EMAC_CAM5M_MACADDR4_Pos (16) /*!< EMAC_T::CAM5M: MACADDR4 Position */ +#define EMAC_CAM5M_MACADDR4_Msk (0xfful << EMAC_CAM5M_MACADDR4_Pos) /*!< EMAC_T::CAM5M: MACADDR4 Mask */ + +#define EMAC_CAM5M_MACADDR5_Pos (24) /*!< EMAC_T::CAM5M: MACADDR5 Position */ +#define EMAC_CAM5M_MACADDR5_Msk (0xfful << EMAC_CAM5M_MACADDR5_Pos) /*!< EMAC_T::CAM5M: MACADDR5 Mask */ + +#define EMAC_CAM5L_MACADDR0_Pos (16) /*!< EMAC_T::CAM5L: MACADDR0 Position */ +#define EMAC_CAM5L_MACADDR0_Msk (0xfful << EMAC_CAM5L_MACADDR0_Pos) /*!< EMAC_T::CAM5L: MACADDR0 Mask */ + +#define EMAC_CAM5L_MACADDR1_Pos (24) /*!< EMAC_T::CAM5L: MACADDR1 Position */ +#define EMAC_CAM5L_MACADDR1_Msk (0xfful << EMAC_CAM5L_MACADDR1_Pos) /*!< EMAC_T::CAM5L: MACADDR1 Mask */ + +#define EMAC_CAM6M_MACADDR2_Pos (0) /*!< EMAC_T::CAM6M: MACADDR2 Position */ +#define EMAC_CAM6M_MACADDR2_Msk (0xfful << EMAC_CAM6M_MACADDR2_Pos) /*!< EMAC_T::CAM6M: MACADDR2 Mask */ + +#define EMAC_CAM6M_MACADDR3_Pos (8) /*!< EMAC_T::CAM6M: MACADDR3 Position */ +#define EMAC_CAM6M_MACADDR3_Msk (0xfful << EMAC_CAM6M_MACADDR3_Pos) /*!< EMAC_T::CAM6M: MACADDR3 Mask */ + +#define EMAC_CAM6M_MACADDR4_Pos (16) /*!< EMAC_T::CAM6M: MACADDR4 Position */ +#define EMAC_CAM6M_MACADDR4_Msk (0xfful << EMAC_CAM6M_MACADDR4_Pos) /*!< EMAC_T::CAM6M: MACADDR4 Mask */ + +#define EMAC_CAM6M_MACADDR5_Pos (24) /*!< EMAC_T::CAM6M: MACADDR5 Position */ +#define EMAC_CAM6M_MACADDR5_Msk (0xfful << EMAC_CAM6M_MACADDR5_Pos) /*!< EMAC_T::CAM6M: MACADDR5 Mask */ + +#define EMAC_CAM6L_MACADDR0_Pos (16) /*!< EMAC_T::CAM6L: MACADDR0 Position */ +#define EMAC_CAM6L_MACADDR0_Msk (0xfful << EMAC_CAM6L_MACADDR0_Pos) /*!< EMAC_T::CAM6L: MACADDR0 Mask */ + +#define EMAC_CAM6L_MACADDR1_Pos (24) /*!< EMAC_T::CAM6L: MACADDR1 Position */ +#define EMAC_CAM6L_MACADDR1_Msk (0xfful << EMAC_CAM6L_MACADDR1_Pos) /*!< EMAC_T::CAM6L: MACADDR1 Mask */ + +#define EMAC_CAM7M_MACADDR2_Pos (0) /*!< EMAC_T::CAM7M: MACADDR2 Position */ +#define EMAC_CAM7M_MACADDR2_Msk (0xfful << EMAC_CAM7M_MACADDR2_Pos) /*!< EMAC_T::CAM7M: MACADDR2 Mask */ + +#define EMAC_CAM7M_MACADDR3_Pos (8) /*!< EMAC_T::CAM7M: MACADDR3 Position */ +#define EMAC_CAM7M_MACADDR3_Msk (0xfful << EMAC_CAM7M_MACADDR3_Pos) /*!< EMAC_T::CAM7M: MACADDR3 Mask */ + +#define EMAC_CAM7M_MACADDR4_Pos (16) /*!< EMAC_T::CAM7M: MACADDR4 Position */ +#define EMAC_CAM7M_MACADDR4_Msk (0xfful << EMAC_CAM7M_MACADDR4_Pos) /*!< EMAC_T::CAM7M: MACADDR4 Mask */ + +#define EMAC_CAM7M_MACADDR5_Pos (24) /*!< EMAC_T::CAM7M: MACADDR5 Position */ +#define EMAC_CAM7M_MACADDR5_Msk (0xfful << EMAC_CAM7M_MACADDR5_Pos) /*!< EMAC_T::CAM7M: MACADDR5 Mask */ + +#define EMAC_CAM7L_MACADDR0_Pos (16) /*!< EMAC_T::CAM7L: MACADDR0 Position */ +#define EMAC_CAM7L_MACADDR0_Msk (0xfful << EMAC_CAM7L_MACADDR0_Pos) /*!< EMAC_T::CAM7L: MACADDR0 Mask */ + +#define EMAC_CAM7L_MACADDR1_Pos (24) /*!< EMAC_T::CAM7L: MACADDR1 Position */ +#define EMAC_CAM7L_MACADDR1_Msk (0xfful << EMAC_CAM7L_MACADDR1_Pos) /*!< EMAC_T::CAM7L: MACADDR1 Mask */ + +#define EMAC_CAM8M_MACADDR2_Pos (0) /*!< EMAC_T::CAM8M: MACADDR2 Position */ +#define EMAC_CAM8M_MACADDR2_Msk (0xfful << EMAC_CAM8M_MACADDR2_Pos) /*!< EMAC_T::CAM8M: MACADDR2 Mask */ + +#define EMAC_CAM8M_MACADDR3_Pos (8) /*!< EMAC_T::CAM8M: MACADDR3 Position */ +#define EMAC_CAM8M_MACADDR3_Msk (0xfful << EMAC_CAM8M_MACADDR3_Pos) /*!< EMAC_T::CAM8M: MACADDR3 Mask */ + +#define EMAC_CAM8M_MACADDR4_Pos (16) /*!< EMAC_T::CAM8M: MACADDR4 Position */ +#define EMAC_CAM8M_MACADDR4_Msk (0xfful << EMAC_CAM8M_MACADDR4_Pos) /*!< EMAC_T::CAM8M: MACADDR4 Mask */ + +#define EMAC_CAM8M_MACADDR5_Pos (24) /*!< EMAC_T::CAM8M: MACADDR5 Position */ +#define EMAC_CAM8M_MACADDR5_Msk (0xfful << EMAC_CAM8M_MACADDR5_Pos) /*!< EMAC_T::CAM8M: MACADDR5 Mask */ + +#define EMAC_CAM8L_MACADDR0_Pos (16) /*!< EMAC_T::CAM8L: MACADDR0 Position */ +#define EMAC_CAM8L_MACADDR0_Msk (0xfful << EMAC_CAM8L_MACADDR0_Pos) /*!< EMAC_T::CAM8L: MACADDR0 Mask */ + +#define EMAC_CAM8L_MACADDR1_Pos (24) /*!< EMAC_T::CAM8L: MACADDR1 Position */ +#define EMAC_CAM8L_MACADDR1_Msk (0xfful << EMAC_CAM8L_MACADDR1_Pos) /*!< EMAC_T::CAM8L: MACADDR1 Mask */ + +#define EMAC_CAM9M_MACADDR2_Pos (0) /*!< EMAC_T::CAM9M: MACADDR2 Position */ +#define EMAC_CAM9M_MACADDR2_Msk (0xfful << EMAC_CAM9M_MACADDR2_Pos) /*!< EMAC_T::CAM9M: MACADDR2 Mask */ + +#define EMAC_CAM9M_MACADDR3_Pos (8) /*!< EMAC_T::CAM9M: MACADDR3 Position */ +#define EMAC_CAM9M_MACADDR3_Msk (0xfful << EMAC_CAM9M_MACADDR3_Pos) /*!< EMAC_T::CAM9M: MACADDR3 Mask */ + +#define EMAC_CAM9M_MACADDR4_Pos (16) /*!< EMAC_T::CAM9M: MACADDR4 Position */ +#define EMAC_CAM9M_MACADDR4_Msk (0xfful << EMAC_CAM9M_MACADDR4_Pos) /*!< EMAC_T::CAM9M: MACADDR4 Mask */ + +#define EMAC_CAM9M_MACADDR5_Pos (24) /*!< EMAC_T::CAM9M: MACADDR5 Position */ +#define EMAC_CAM9M_MACADDR5_Msk (0xfful << EMAC_CAM9M_MACADDR5_Pos) /*!< EMAC_T::CAM9M: MACADDR5 Mask */ + +#define EMAC_CAM9L_MACADDR0_Pos (16) /*!< EMAC_T::CAM9L: MACADDR0 Position */ +#define EMAC_CAM9L_MACADDR0_Msk (0xfful << EMAC_CAM9L_MACADDR0_Pos) /*!< EMAC_T::CAM9L: MACADDR0 Mask */ + +#define EMAC_CAM9L_MACADDR1_Pos (24) /*!< EMAC_T::CAM9L: MACADDR1 Position */ +#define EMAC_CAM9L_MACADDR1_Msk (0xfful << EMAC_CAM9L_MACADDR1_Pos) /*!< EMAC_T::CAM9L: MACADDR1 Mask */ + +#define EMAC_CAM10M_MACADDR2_Pos (0) /*!< EMAC_T::CAM10M: MACADDR2 Position */ +#define EMAC_CAM10M_MACADDR2_Msk (0xfful << EMAC_CAM10M_MACADDR2_Pos) /*!< EMAC_T::CAM10M: MACADDR2 Mask */ + +#define EMAC_CAM10M_MACADDR3_Pos (8) /*!< EMAC_T::CAM10M: MACADDR3 Position */ +#define EMAC_CAM10M_MACADDR3_Msk (0xfful << EMAC_CAM10M_MACADDR3_Pos) /*!< EMAC_T::CAM10M: MACADDR3 Mask */ + +#define EMAC_CAM10M_MACADDR4_Pos (16) /*!< EMAC_T::CAM10M: MACADDR4 Position */ +#define EMAC_CAM10M_MACADDR4_Msk (0xfful << EMAC_CAM10M_MACADDR4_Pos) /*!< EMAC_T::CAM10M: MACADDR4 Mask */ + +#define EMAC_CAM10M_MACADDR5_Pos (24) /*!< EMAC_T::CAM10M: MACADDR5 Position */ +#define EMAC_CAM10M_MACADDR5_Msk (0xfful << EMAC_CAM10M_MACADDR5_Pos) /*!< EMAC_T::CAM10M: MACADDR5 Mask */ + +#define EMAC_CAM10L_MACADDR0_Pos (16) /*!< EMAC_T::CAM10L: MACADDR0 Position */ +#define EMAC_CAM10L_MACADDR0_Msk (0xfful << EMAC_CAM10L_MACADDR0_Pos) /*!< EMAC_T::CAM10L: MACADDR0 Mask */ + +#define EMAC_CAM10L_MACADDR1_Pos (24) /*!< EMAC_T::CAM10L: MACADDR1 Position */ +#define EMAC_CAM10L_MACADDR1_Msk (0xfful << EMAC_CAM10L_MACADDR1_Pos) /*!< EMAC_T::CAM10L: MACADDR1 Mask */ + +#define EMAC_CAM11M_MACADDR2_Pos (0) /*!< EMAC_T::CAM11M: MACADDR2 Position */ +#define EMAC_CAM11M_MACADDR2_Msk (0xfful << EMAC_CAM11M_MACADDR2_Pos) /*!< EMAC_T::CAM11M: MACADDR2 Mask */ + +#define EMAC_CAM11M_MACADDR3_Pos (8) /*!< EMAC_T::CAM11M: MACADDR3 Position */ +#define EMAC_CAM11M_MACADDR3_Msk (0xfful << EMAC_CAM11M_MACADDR3_Pos) /*!< EMAC_T::CAM11M: MACADDR3 Mask */ + +#define EMAC_CAM11M_MACADDR4_Pos (16) /*!< EMAC_T::CAM11M: MACADDR4 Position */ +#define EMAC_CAM11M_MACADDR4_Msk (0xfful << EMAC_CAM11M_MACADDR4_Pos) /*!< EMAC_T::CAM11M: MACADDR4 Mask */ + +#define EMAC_CAM11M_MACADDR5_Pos (24) /*!< EMAC_T::CAM11M: MACADDR5 Position */ +#define EMAC_CAM11M_MACADDR5_Msk (0xfful << EMAC_CAM11M_MACADDR5_Pos) /*!< EMAC_T::CAM11M: MACADDR5 Mask */ + +#define EMAC_CAM11L_MACADDR0_Pos (16) /*!< EMAC_T::CAM11L: MACADDR0 Position */ +#define EMAC_CAM11L_MACADDR0_Msk (0xfful << EMAC_CAM11L_MACADDR0_Pos) /*!< EMAC_T::CAM11L: MACADDR0 Mask */ + +#define EMAC_CAM11L_MACADDR1_Pos (24) /*!< EMAC_T::CAM11L: MACADDR1 Position */ +#define EMAC_CAM11L_MACADDR1_Msk (0xfful << EMAC_CAM11L_MACADDR1_Pos) /*!< EMAC_T::CAM11L: MACADDR1 Mask */ + +#define EMAC_CAM12M_MACADDR2_Pos (0) /*!< EMAC_T::CAM12M: MACADDR2 Position */ +#define EMAC_CAM12M_MACADDR2_Msk (0xfful << EMAC_CAM12M_MACADDR2_Pos) /*!< EMAC_T::CAM12M: MACADDR2 Mask */ + +#define EMAC_CAM12M_MACADDR3_Pos (8) /*!< EMAC_T::CAM12M: MACADDR3 Position */ +#define EMAC_CAM12M_MACADDR3_Msk (0xfful << EMAC_CAM12M_MACADDR3_Pos) /*!< EMAC_T::CAM12M: MACADDR3 Mask */ + +#define EMAC_CAM12M_MACADDR4_Pos (16) /*!< EMAC_T::CAM12M: MACADDR4 Position */ +#define EMAC_CAM12M_MACADDR4_Msk (0xfful << EMAC_CAM12M_MACADDR4_Pos) /*!< EMAC_T::CAM12M: MACADDR4 Mask */ + +#define EMAC_CAM12M_MACADDR5_Pos (24) /*!< EMAC_T::CAM12M: MACADDR5 Position */ +#define EMAC_CAM12M_MACADDR5_Msk (0xfful << EMAC_CAM12M_MACADDR5_Pos) /*!< EMAC_T::CAM12M: MACADDR5 Mask */ + +#define EMAC_CAM12L_MACADDR0_Pos (16) /*!< EMAC_T::CAM12L: MACADDR0 Position */ +#define EMAC_CAM12L_MACADDR0_Msk (0xfful << EMAC_CAM12L_MACADDR0_Pos) /*!< EMAC_T::CAM12L: MACADDR0 Mask */ + +#define EMAC_CAM12L_MACADDR1_Pos (24) /*!< EMAC_T::CAM12L: MACADDR1 Position */ +#define EMAC_CAM12L_MACADDR1_Msk (0xfful << EMAC_CAM12L_MACADDR1_Pos) /*!< EMAC_T::CAM12L: MACADDR1 Mask */ + +#define EMAC_CAM13M_MACADDR2_Pos (0) /*!< EMAC_T::CAM13M: MACADDR2 Position */ +#define EMAC_CAM13M_MACADDR2_Msk (0xfful << EMAC_CAM13M_MACADDR2_Pos) /*!< EMAC_T::CAM13M: MACADDR2 Mask */ + +#define EMAC_CAM13M_MACADDR3_Pos (8) /*!< EMAC_T::CAM13M: MACADDR3 Position */ +#define EMAC_CAM13M_MACADDR3_Msk (0xfful << EMAC_CAM13M_MACADDR3_Pos) /*!< EMAC_T::CAM13M: MACADDR3 Mask */ + +#define EMAC_CAM13M_MACADDR4_Pos (16) /*!< EMAC_T::CAM13M: MACADDR4 Position */ +#define EMAC_CAM13M_MACADDR4_Msk (0xfful << EMAC_CAM13M_MACADDR4_Pos) /*!< EMAC_T::CAM13M: MACADDR4 Mask */ + +#define EMAC_CAM13M_MACADDR5_Pos (24) /*!< EMAC_T::CAM13M: MACADDR5 Position */ +#define EMAC_CAM13M_MACADDR5_Msk (0xfful << EMAC_CAM13M_MACADDR5_Pos) /*!< EMAC_T::CAM13M: MACADDR5 Mask */ + +#define EMAC_CAM13L_MACADDR0_Pos (16) /*!< EMAC_T::CAM13L: MACADDR0 Position */ +#define EMAC_CAM13L_MACADDR0_Msk (0xfful << EMAC_CAM13L_MACADDR0_Pos) /*!< EMAC_T::CAM13L: MACADDR0 Mask */ + +#define EMAC_CAM13L_MACADDR1_Pos (24) /*!< EMAC_T::CAM13L: MACADDR1 Position */ +#define EMAC_CAM13L_MACADDR1_Msk (0xfful << EMAC_CAM13L_MACADDR1_Pos) /*!< EMAC_T::CAM13L: MACADDR1 Mask */ + +#define EMAC_CAM14M_MACADDR2_Pos (0) /*!< EMAC_T::CAM14M: MACADDR2 Position */ +#define EMAC_CAM14M_MACADDR2_Msk (0xfful << EMAC_CAM14M_MACADDR2_Pos) /*!< EMAC_T::CAM14M: MACADDR2 Mask */ + +#define EMAC_CAM14M_MACADDR3_Pos (8) /*!< EMAC_T::CAM14M: MACADDR3 Position */ +#define EMAC_CAM14M_MACADDR3_Msk (0xfful << EMAC_CAM14M_MACADDR3_Pos) /*!< EMAC_T::CAM14M: MACADDR3 Mask */ + +#define EMAC_CAM14M_MACADDR4_Pos (16) /*!< EMAC_T::CAM14M: MACADDR4 Position */ +#define EMAC_CAM14M_MACADDR4_Msk (0xfful << EMAC_CAM14M_MACADDR4_Pos) /*!< EMAC_T::CAM14M: MACADDR4 Mask */ + +#define EMAC_CAM14M_MACADDR5_Pos (24) /*!< EMAC_T::CAM14M: MACADDR5 Position */ +#define EMAC_CAM14M_MACADDR5_Msk (0xfful << EMAC_CAM14M_MACADDR5_Pos) /*!< EMAC_T::CAM14M: MACADDR5 Mask */ + +#define EMAC_CAM14L_MACADDR0_Pos (16) /*!< EMAC_T::CAM14L: MACADDR0 Position */ +#define EMAC_CAM14L_MACADDR0_Msk (0xfful << EMAC_CAM14L_MACADDR0_Pos) /*!< EMAC_T::CAM14L: MACADDR0 Mask */ + +#define EMAC_CAM14L_MACADDR1_Pos (24) /*!< EMAC_T::CAM14L: MACADDR1 Position */ +#define EMAC_CAM14L_MACADDR1_Msk (0xfful << EMAC_CAM14L_MACADDR1_Pos) /*!< EMAC_T::CAM14L: MACADDR1 Mask */ + +#define EMAC_CAM15MSB_OPCODE_Pos (0) /*!< EMAC_T::CAM15MSB: OPCODE Position */ +#define EMAC_CAM15MSB_OPCODE_Msk (0xfffful << EMAC_CAM15MSB_OPCODE_Pos) /*!< EMAC_T::CAM15MSB: OPCODE Mask */ + +#define EMAC_CAM15MSB_LENGTH_Pos (16) /*!< EMAC_T::CAM15MSB: LENGTH Position */ +#define EMAC_CAM15MSB_LENGTH_Msk (0xfffful << EMAC_CAM15MSB_LENGTH_Pos) /*!< EMAC_T::CAM15MSB: LENGTH Mask */ + +#define EMAC_CAM15LSB_OPERAND_Pos (24) /*!< EMAC_T::CAM15LSB: OPERAND Position */ +#define EMAC_CAM15LSB_OPERAND_Msk (0xfful << EMAC_CAM15LSB_OPERAND_Pos) /*!< EMAC_T::CAM15LSB: OPERAND Mask */ + +#define EMAC_TXDSA_TXDSA_Pos (0) /*!< EMAC_T::TXDSA: TXDSA Position */ +#define EMAC_TXDSA_TXDSA_Msk (0xfffffffful << EMAC_TXDSA_TXDSA_Pos) /*!< EMAC_T::TXDSA: TXDSA Mask */ + +#define EMAC_RXDSA_RXDSA_Pos (0) /*!< EMAC_T::RXDSA: RXDSA Position */ +#define EMAC_RXDSA_RXDSA_Msk (0xfffffffful << EMAC_RXDSA_RXDSA_Pos) /*!< EMAC_T::RXDSA: RXDSA Mask */ + +#define EMAC_CTL_RXON_Pos (0) /*!< EMAC_T::CTL: RXON Position */ +#define EMAC_CTL_RXON_Msk (0x1ul << EMAC_CTL_RXON_Pos) /*!< EMAC_T::CTL: RXON Mask */ + +#define EMAC_CTL_ALP_Pos (1) /*!< EMAC_T::CTL: ALP Position */ +#define EMAC_CTL_ALP_Msk (0x1ul << EMAC_CTL_ALP_Pos) /*!< EMAC_T::CTL: ALP Mask */ + +#define EMAC_CTL_ARP_Pos (2) /*!< EMAC_T::CTL: ARP Position */ +#define EMAC_CTL_ARP_Msk (0x1ul << EMAC_CTL_ARP_Pos) /*!< EMAC_T::CTL: ARP Mask */ + +#define EMAC_CTL_ACP_Pos (3) /*!< EMAC_T::CTL: ACP Position */ +#define EMAC_CTL_ACP_Msk (0x1ul << EMAC_CTL_ACP_Pos) /*!< EMAC_T::CTL: ACP Mask */ + +#define EMAC_CTL_AEP_Pos (4) /*!< EMAC_T::CTL: AEP Position */ +#define EMAC_CTL_AEP_Msk (0x1ul << EMAC_CTL_AEP_Pos) /*!< EMAC_T::CTL: AEP Mask */ + +#define EMAC_CTL_STRIPCRC_Pos (5) /*!< EMAC_T::CTL: STRIPCRC Position */ +#define EMAC_CTL_STRIPCRC_Msk (0x1ul << EMAC_CTL_STRIPCRC_Pos) /*!< EMAC_T::CTL: STRIPCRC Mask */ + +#define EMAC_CTL_WOLEN_Pos (6) /*!< EMAC_T::CTL: WOLEN Position */ +#define EMAC_CTL_WOLEN_Msk (0x1ul << EMAC_CTL_WOLEN_Pos) /*!< EMAC_T::CTL: WOLEN Mask */ + +#define EMAC_CTL_TXON_Pos (8) /*!< EMAC_T::CTL: TXON Position */ +#define EMAC_CTL_TXON_Msk (0x1ul << EMAC_CTL_TXON_Pos) /*!< EMAC_T::CTL: TXON Mask */ + +#define EMAC_CTL_NODEF_Pos (9) /*!< EMAC_T::CTL: NODEF Position */ +#define EMAC_CTL_NODEF_Msk (0x1ul << EMAC_CTL_NODEF_Pos) /*!< EMAC_T::CTL: NODEF Mask */ + +#define EMAC_CTL_SDPZ_Pos (16) /*!< EMAC_T::CTL: SDPZ Position */ +#define EMAC_CTL_SDPZ_Msk (0x1ul << EMAC_CTL_SDPZ_Pos) /*!< EMAC_T::CTL: SDPZ Mask */ + +#define EMAC_CTL_SQECHKEN_Pos (17) /*!< EMAC_T::CTL: SQECHKEN Position */ +#define EMAC_CTL_SQECHKEN_Msk (0x1ul << EMAC_CTL_SQECHKEN_Pos) /*!< EMAC_T::CTL: SQECHKEN Mask */ + +#define EMAC_CTL_FUDUP_Pos (18) /*!< EMAC_T::CTL: FUDUP Position */ +#define EMAC_CTL_FUDUP_Msk (0x1ul << EMAC_CTL_FUDUP_Pos) /*!< EMAC_T::CTL: FUDUP Mask */ + +#define EMAC_CTL_RMIIRXCTL_Pos (19) /*!< EMAC_T::CTL: RMIIRXCTL Position */ +#define EMAC_CTL_RMIIRXCTL_Msk (0x1ul << EMAC_CTL_RMIIRXCTL_Pos) /*!< EMAC_T::CTL: RMIIRXCTL Mask */ + +#define EMAC_CTL_OPMODE_Pos (20) /*!< EMAC_T::CTL: OPMODE Position */ +#define EMAC_CTL_OPMODE_Msk (0x1ul << EMAC_CTL_OPMODE_Pos) /*!< EMAC_T::CTL: OPMODE Mask */ + +#define EMAC_CTL_RMIIEN_Pos (22) /*!< EMAC_T::CTL: RMIIEN Position */ +#define EMAC_CTL_RMIIEN_Msk (0x1ul << EMAC_CTL_RMIIEN_Pos) /*!< EMAC_T::CTL: RMIIEN Mask */ + +#define EMAC_CTL_RST_Pos (24) /*!< EMAC_T::CTL: RST Position */ +#define EMAC_CTL_RST_Msk (0x1ul << EMAC_CTL_RST_Pos) /*!< EMAC_T::CTL: RST Mask */ + +#define EMAC_MIIMDAT_DATA_Pos (0) /*!< EMAC_T::MIIMDAT: DATA Position */ +#define EMAC_MIIMDAT_DATA_Msk (0xfffful << EMAC_MIIMDAT_DATA_Pos) /*!< EMAC_T::MIIMDAT: DATA Mask */ + +#define EMAC_MIIMCTL_PHYREG_Pos (0) /*!< EMAC_T::MIIMCTL: PHYREG Position */ +#define EMAC_MIIMCTL_PHYREG_Msk (0x1ful << EMAC_MIIMCTL_PHYREG_Pos) /*!< EMAC_T::MIIMCTL: PHYREG Mask */ + +#define EMAC_MIIMCTL_PHYADDR_Pos (8) /*!< EMAC_T::MIIMCTL: PHYADDR Position */ +#define EMAC_MIIMCTL_PHYADDR_Msk (0x1ful << EMAC_MIIMCTL_PHYADDR_Pos) /*!< EMAC_T::MIIMCTL: PHYADDR Mask */ + +#define EMAC_MIIMCTL_WRITE_Pos (16) /*!< EMAC_T::MIIMCTL: WRITE Position */ +#define EMAC_MIIMCTL_WRITE_Msk (0x1ul << EMAC_MIIMCTL_WRITE_Pos) /*!< EMAC_T::MIIMCTL: WRITE Mask */ + +#define EMAC_MIIMCTL_BUSY_Pos (17) /*!< EMAC_T::MIIMCTL: BUSY Position */ +#define EMAC_MIIMCTL_BUSY_Msk (0x1ul << EMAC_MIIMCTL_BUSY_Pos) /*!< EMAC_T::MIIMCTL: BUSY Mask */ + +#define EMAC_MIIMCTL_PREAMSP_Pos (18) /*!< EMAC_T::MIIMCTL: PREAMSP Position */ +#define EMAC_MIIMCTL_PREAMSP_Msk (0x1ul << EMAC_MIIMCTL_PREAMSP_Pos) /*!< EMAC_T::MIIMCTL: PREAMSP Mask */ + +#define EMAC_MIIMCTL_MDCON_Pos (19) /*!< EMAC_T::MIIMCTL: MDCON Position */ +#define EMAC_MIIMCTL_MDCON_Msk (0x1ul << EMAC_MIIMCTL_MDCON_Pos) /*!< EMAC_T::MIIMCTL: MDCON Mask */ + +#define EMAC_FIFOCTL_RXFIFOTH_Pos (0) /*!< EMAC_T::FIFOCTL: RXFIFOTH Position */ +#define EMAC_FIFOCTL_RXFIFOTH_Msk (0x3ul << EMAC_FIFOCTL_RXFIFOTH_Pos) /*!< EMAC_T::FIFOCTL: RXFIFOTH Mask */ + +#define EMAC_FIFOCTL_TXFIFOTH_Pos (8) /*!< EMAC_T::FIFOCTL: TXFIFOTH Position */ +#define EMAC_FIFOCTL_TXFIFOTH_Msk (0x3ul << EMAC_FIFOCTL_TXFIFOTH_Pos) /*!< EMAC_T::FIFOCTL: TXFIFOTH Mask */ + +#define EMAC_FIFOCTL_BURSTLEN_Pos (20) /*!< EMAC_T::FIFOCTL: BURSTLEN Position */ +#define EMAC_FIFOCTL_BURSTLEN_Msk (0x3ul << EMAC_FIFOCTL_BURSTLEN_Pos) /*!< EMAC_T::FIFOCTL: BURSTLEN Mask */ + +#define EMAC_TXST_TXST_Pos (0) /*!< EMAC_T::TXST: TXST Position */ +#define EMAC_TXST_TXST_Msk (0xfffffffful << EMAC_TXST_TXST_Pos) /*!< EMAC_T::TXST: TXST Mask */ + +#define EMAC_RXST_RXST_Pos (0) /*!< EMAC_T::RXST: RXST Position */ +#define EMAC_RXST_RXST_Msk (0xfffffffful << EMAC_RXST_RXST_Pos) /*!< EMAC_T::RXST: RXST Mask */ + +#define EMAC_MRFL_MRFL_Pos (0) /*!< EMAC_T::MRFL: MRFL Position */ +#define EMAC_MRFL_MRFL_Msk (0xfffful << EMAC_MRFL_MRFL_Pos) /*!< EMAC_T::MRFL: MRFL Mask */ + +#define EMAC_INTEN_RXIEN_Pos (0) /*!< EMAC_T::INTEN: RXIEN Position */ +#define EMAC_INTEN_RXIEN_Msk (0x1ul << EMAC_INTEN_RXIEN_Pos) /*!< EMAC_T::INTEN: RXIEN Mask */ + +#define EMAC_INTEN_CRCEIEN_Pos (1) /*!< EMAC_T::INTEN: CRCEIEN Position */ +#define EMAC_INTEN_CRCEIEN_Msk (0x1ul << EMAC_INTEN_CRCEIEN_Pos) /*!< EMAC_T::INTEN: CRCEIEN Mask */ + +#define EMAC_INTEN_RXOVIEN_Pos (2) /*!< EMAC_T::INTEN: RXOVIEN Position */ +#define EMAC_INTEN_RXOVIEN_Msk (0x1ul << EMAC_INTEN_RXOVIEN_Pos) /*!< EMAC_T::INTEN: RXOVIEN Mask */ + +#define EMAC_INTEN_LPIEN_Pos (3) /*!< EMAC_T::INTEN: LPIEN Position */ +#define EMAC_INTEN_LPIEN_Msk (0x1ul << EMAC_INTEN_LPIEN_Pos) /*!< EMAC_T::INTEN: LPIEN Mask */ + +#define EMAC_INTEN_RXGDIEN_Pos (4) /*!< EMAC_T::INTEN: RXGDIEN Position */ +#define EMAC_INTEN_RXGDIEN_Msk (0x1ul << EMAC_INTEN_RXGDIEN_Pos) /*!< EMAC_T::INTEN: RXGDIEN Mask */ + +#define EMAC_INTEN_ALIEIEN_Pos (5) /*!< EMAC_T::INTEN: ALIEIEN Position */ +#define EMAC_INTEN_ALIEIEN_Msk (0x1ul << EMAC_INTEN_ALIEIEN_Pos) /*!< EMAC_T::INTEN: ALIEIEN Mask */ + +#define EMAC_INTEN_RPIEN_Pos (6) /*!< EMAC_T::INTEN: RPIEN Position */ +#define EMAC_INTEN_RPIEN_Msk (0x1ul << EMAC_INTEN_RPIEN_Pos) /*!< EMAC_T::INTEN: RPIEN Mask */ + +#define EMAC_INTEN_MPCOVIEN_Pos (7) /*!< EMAC_T::INTEN: MPCOVIEN Position */ +#define EMAC_INTEN_MPCOVIEN_Msk (0x1ul << EMAC_INTEN_MPCOVIEN_Pos) /*!< EMAC_T::INTEN: MPCOVIEN Mask */ + +#define EMAC_INTEN_MFLEIEN_Pos (8) /*!< EMAC_T::INTEN: MFLEIEN Position */ +#define EMAC_INTEN_MFLEIEN_Msk (0x1ul << EMAC_INTEN_MFLEIEN_Pos) /*!< EMAC_T::INTEN: MFLEIEN Mask */ + +#define EMAC_INTEN_DENIEN_Pos (9) /*!< EMAC_T::INTEN: DENIEN Position */ +#define EMAC_INTEN_DENIEN_Msk (0x1ul << EMAC_INTEN_DENIEN_Pos) /*!< EMAC_T::INTEN: DENIEN Mask */ + +#define EMAC_INTEN_RDUIEN_Pos (10) /*!< EMAC_T::INTEN: RDUIEN Position */ +#define EMAC_INTEN_RDUIEN_Msk (0x1ul << EMAC_INTEN_RDUIEN_Pos) /*!< EMAC_T::INTEN: RDUIEN Mask */ + +#define EMAC_INTEN_RXBEIEN_Pos (11) /*!< EMAC_T::INTEN: RXBEIEN Position */ +#define EMAC_INTEN_RXBEIEN_Msk (0x1ul << EMAC_INTEN_RXBEIEN_Pos) /*!< EMAC_T::INTEN: RXBEIEN Mask */ + +#define EMAC_INTEN_CFRIEN_Pos (14) /*!< EMAC_T::INTEN: CFRIEN Position */ +#define EMAC_INTEN_CFRIEN_Msk (0x1ul << EMAC_INTEN_CFRIEN_Pos) /*!< EMAC_T::INTEN: CFRIEN Mask */ + +#define EMAC_INTEN_WOLIEN_Pos (15) /*!< EMAC_T::INTEN: WOLIEN Position */ +#define EMAC_INTEN_WOLIEN_Msk (0x1ul << EMAC_INTEN_WOLIEN_Pos) /*!< EMAC_T::INTEN: WOLIEN Mask */ + +#define EMAC_INTEN_TXIEN_Pos (16) /*!< EMAC_T::INTEN: TXIEN Position */ +#define EMAC_INTEN_TXIEN_Msk (0x1ul << EMAC_INTEN_TXIEN_Pos) /*!< EMAC_T::INTEN: TXIEN Mask */ + +#define EMAC_INTEN_TXUDIEN_Pos (17) /*!< EMAC_T::INTEN: TXUDIEN Position */ +#define EMAC_INTEN_TXUDIEN_Msk (0x1ul << EMAC_INTEN_TXUDIEN_Pos) /*!< EMAC_T::INTEN: TXUDIEN Mask */ + +#define EMAC_INTEN_TXCPIEN_Pos (18) /*!< EMAC_T::INTEN: TXCPIEN Position */ +#define EMAC_INTEN_TXCPIEN_Msk (0x1ul << EMAC_INTEN_TXCPIEN_Pos) /*!< EMAC_T::INTEN: TXCPIEN Mask */ + +#define EMAC_INTEN_EXDEFIEN_Pos (19) /*!< EMAC_T::INTEN: EXDEFIEN Position */ +#define EMAC_INTEN_EXDEFIEN_Msk (0x1ul << EMAC_INTEN_EXDEFIEN_Pos) /*!< EMAC_T::INTEN: EXDEFIEN Mask */ + +#define EMAC_INTEN_NCSIEN_Pos (20) /*!< EMAC_T::INTEN: NCSIEN Position */ +#define EMAC_INTEN_NCSIEN_Msk (0x1ul << EMAC_INTEN_NCSIEN_Pos) /*!< EMAC_T::INTEN: NCSIEN Mask */ + +#define EMAC_INTEN_TXABTIEN_Pos (21) /*!< EMAC_T::INTEN: TXABTIEN Position */ +#define EMAC_INTEN_TXABTIEN_Msk (0x1ul << EMAC_INTEN_TXABTIEN_Pos) /*!< EMAC_T::INTEN: TXABTIEN Mask */ + +#define EMAC_INTEN_LCIEN_Pos (22) /*!< EMAC_T::INTEN: LCIEN Position */ +#define EMAC_INTEN_LCIEN_Msk (0x1ul << EMAC_INTEN_LCIEN_Pos) /*!< EMAC_T::INTEN: LCIEN Mask */ + +#define EMAC_INTEN_TDUIEN_Pos (23) /*!< EMAC_T::INTEN: TDUIEN Position */ +#define EMAC_INTEN_TDUIEN_Msk (0x1ul << EMAC_INTEN_TDUIEN_Pos) /*!< EMAC_T::INTEN: TDUIEN Mask */ + +#define EMAC_INTEN_TXBEIEN_Pos (24) /*!< EMAC_T::INTEN: TXBEIEN Position */ +#define EMAC_INTEN_TXBEIEN_Msk (0x1ul << EMAC_INTEN_TXBEIEN_Pos) /*!< EMAC_T::INTEN: TXBEIEN Mask */ + +#define EMAC_INTEN_TSALMIEN_Pos (28) /*!< EMAC_T::INTEN: TSALMIEN Position */ +#define EMAC_INTEN_TSALMIEN_Msk (0x1ul << EMAC_INTEN_TSALMIEN_Pos) /*!< EMAC_T::INTEN: TSALMIEN Mask */ + +#define EMAC_INTSTS_RXIF_Pos (0) /*!< EMAC_T::INTSTS: RXIF Position */ +#define EMAC_INTSTS_RXIF_Msk (0x1ul << EMAC_INTSTS_RXIF_Pos) /*!< EMAC_T::INTSTS: RXIF Mask */ + +#define EMAC_INTSTS_CRCEIF_Pos (1) /*!< EMAC_T::INTSTS: CRCEIF Position */ +#define EMAC_INTSTS_CRCEIF_Msk (0x1ul << EMAC_INTSTS_CRCEIF_Pos) /*!< EMAC_T::INTSTS: CRCEIF Mask */ + +#define EMAC_INTSTS_RXOVIF_Pos (2) /*!< EMAC_T::INTSTS: RXOVIF Position */ +#define EMAC_INTSTS_RXOVIF_Msk (0x1ul << EMAC_INTSTS_RXOVIF_Pos) /*!< EMAC_T::INTSTS: RXOVIF Mask */ + +#define EMAC_INTSTS_LPIF_Pos (3) /*!< EMAC_T::INTSTS: LPIF Position */ +#define EMAC_INTSTS_LPIF_Msk (0x1ul << EMAC_INTSTS_LPIF_Pos) /*!< EMAC_T::INTSTS: LPIF Mask */ + +#define EMAC_INTSTS_RXGDIF_Pos (4) /*!< EMAC_T::INTSTS: RXGDIF Position */ +#define EMAC_INTSTS_RXGDIF_Msk (0x1ul << EMAC_INTSTS_RXGDIF_Pos) /*!< EMAC_T::INTSTS: RXGDIF Mask */ + +#define EMAC_INTSTS_ALIEIF_Pos (5) /*!< EMAC_T::INTSTS: ALIEIF Position */ +#define EMAC_INTSTS_ALIEIF_Msk (0x1ul << EMAC_INTSTS_ALIEIF_Pos) /*!< EMAC_T::INTSTS: ALIEIF Mask */ + +#define EMAC_INTSTS_RPIF_Pos (6) /*!< EMAC_T::INTSTS: RPIF Position */ +#define EMAC_INTSTS_RPIF_Msk (0x1ul << EMAC_INTSTS_RPIF_Pos) /*!< EMAC_T::INTSTS: RPIF Mask */ + +#define EMAC_INTSTS_MPCOVIF_Pos (7) /*!< EMAC_T::INTSTS: MPCOVIF Position */ +#define EMAC_INTSTS_MPCOVIF_Msk (0x1ul << EMAC_INTSTS_MPCOVIF_Pos) /*!< EMAC_T::INTSTS: MPCOVIF Mask */ + +#define EMAC_INTSTS_MFLEIF_Pos (8) /*!< EMAC_T::INTSTS: MFLEIF Position */ +#define EMAC_INTSTS_MFLEIF_Msk (0x1ul << EMAC_INTSTS_MFLEIF_Pos) /*!< EMAC_T::INTSTS: MFLEIF Mask */ + +#define EMAC_INTSTS_DENIF_Pos (9) /*!< EMAC_T::INTSTS: DENIF Position */ +#define EMAC_INTSTS_DENIF_Msk (0x1ul << EMAC_INTSTS_DENIF_Pos) /*!< EMAC_T::INTSTS: DENIF Mask */ + +#define EMAC_INTSTS_RDUIF_Pos (10) /*!< EMAC_T::INTSTS: RDUIF Position */ +#define EMAC_INTSTS_RDUIF_Msk (0x1ul << EMAC_INTSTS_RDUIF_Pos) /*!< EMAC_T::INTSTS: RDUIF Mask */ + +#define EMAC_INTSTS_RXBEIF_Pos (11) /*!< EMAC_T::INTSTS: RXBEIF Position */ +#define EMAC_INTSTS_RXBEIF_Msk (0x1ul << EMAC_INTSTS_RXBEIF_Pos) /*!< EMAC_T::INTSTS: RXBEIF Mask */ + +#define EMAC_INTSTS_CFRIF_Pos (14) /*!< EMAC_T::INTSTS: CFRIF Position */ +#define EMAC_INTSTS_CFRIF_Msk (0x1ul << EMAC_INTSTS_CFRIF_Pos) /*!< EMAC_T::INTSTS: CFRIF Mask */ + +#define EMAC_INTSTS_WOLIF_Pos (15) /*!< EMAC_T::INTSTS: WOLIF Position */ +#define EMAC_INTSTS_WOLIF_Msk (0x1ul << EMAC_INTSTS_WOLIF_Pos) /*!< EMAC_T::INTSTS: WOLIF Mask */ + +#define EMAC_INTSTS_TXIF_Pos (16) /*!< EMAC_T::INTSTS: TXIF Position */ +#define EMAC_INTSTS_TXIF_Msk (0x1ul << EMAC_INTSTS_TXIF_Pos) /*!< EMAC_T::INTSTS: TXIF Mask */ + +#define EMAC_INTSTS_TXUDIF_Pos (17) /*!< EMAC_T::INTSTS: TXUDIF Position */ +#define EMAC_INTSTS_TXUDIF_Msk (0x1ul << EMAC_INTSTS_TXUDIF_Pos) /*!< EMAC_T::INTSTS: TXUDIF Mask */ + +#define EMAC_INTSTS_TXCPIF_Pos (18) /*!< EMAC_T::INTSTS: TXCPIF Position */ +#define EMAC_INTSTS_TXCPIF_Msk (0x1ul << EMAC_INTSTS_TXCPIF_Pos) /*!< EMAC_T::INTSTS: TXCPIF Mask */ + +#define EMAC_INTSTS_EXDEFIF_Pos (19) /*!< EMAC_T::INTSTS: EXDEFIF Position */ +#define EMAC_INTSTS_EXDEFIF_Msk (0x1ul << EMAC_INTSTS_EXDEFIF_Pos) /*!< EMAC_T::INTSTS: EXDEFIF Mask */ + +#define EMAC_INTSTS_NCSIF_Pos (20) /*!< EMAC_T::INTSTS: NCSIF Position */ +#define EMAC_INTSTS_NCSIF_Msk (0x1ul << EMAC_INTSTS_NCSIF_Pos) /*!< EMAC_T::INTSTS: NCSIF Mask */ + +#define EMAC_INTSTS_TXABTIF_Pos (21) /*!< EMAC_T::INTSTS: TXABTIF Position */ +#define EMAC_INTSTS_TXABTIF_Msk (0x1ul << EMAC_INTSTS_TXABTIF_Pos) /*!< EMAC_T::INTSTS: TXABTIF Mask */ + +#define EMAC_INTSTS_LCIF_Pos (22) /*!< EMAC_T::INTSTS: LCIF Position */ +#define EMAC_INTSTS_LCIF_Msk (0x1ul << EMAC_INTSTS_LCIF_Pos) /*!< EMAC_T::INTSTS: LCIF Mask */ + +#define EMAC_INTSTS_TDUIF_Pos (23) /*!< EMAC_T::INTSTS: TDUIF Position */ +#define EMAC_INTSTS_TDUIF_Msk (0x1ul << EMAC_INTSTS_TDUIF_Pos) /*!< EMAC_T::INTSTS: TDUIF Mask */ + +#define EMAC_INTSTS_TXBEIF_Pos (24) /*!< EMAC_T::INTSTS: TXBEIF Position */ +#define EMAC_INTSTS_TXBEIF_Msk (0x1ul << EMAC_INTSTS_TXBEIF_Pos) /*!< EMAC_T::INTSTS: TXBEIF Mask */ + +#define EMAC_INTSTS_TSALMIF_Pos (28) /*!< EMAC_T::INTSTS: TSALMIF Position */ +#define EMAC_INTSTS_TSALMIF_Msk (0x1ul << EMAC_INTSTS_TSALMIF_Pos) /*!< EMAC_T::INTSTS: TSALMIF Mask */ + +#define EMAC_GENSTS_CFR_Pos (0) /*!< EMAC_T::GENSTS: CFR Position */ +#define EMAC_GENSTS_CFR_Msk (0x1ul << EMAC_GENSTS_CFR_Pos) /*!< EMAC_T::GENSTS: CFR Mask */ + +#define EMAC_GENSTS_RXHALT_Pos (1) /*!< EMAC_T::GENSTS: RXHALT Position */ +#define EMAC_GENSTS_RXHALT_Msk (0x1ul << EMAC_GENSTS_RXHALT_Pos) /*!< EMAC_T::GENSTS: RXHALT Mask */ + +#define EMAC_GENSTS_RXFFULL_Pos (2) /*!< EMAC_T::GENSTS: RXFFULL Position */ +#define EMAC_GENSTS_RXFFULL_Msk (0x1ul << EMAC_GENSTS_RXFFULL_Pos) /*!< EMAC_T::GENSTS: RXFFULL Mask */ + +#define EMAC_GENSTS_COLCNT_Pos (4) /*!< EMAC_T::GENSTS: COLCNT Position */ +#define EMAC_GENSTS_COLCNT_Msk (0xful << EMAC_GENSTS_COLCNT_Pos) /*!< EMAC_T::GENSTS: COLCNT Mask */ + +#define EMAC_GENSTS_DEF_Pos (8) /*!< EMAC_T::GENSTS: DEF Position */ +#define EMAC_GENSTS_DEF_Msk (0x1ul << EMAC_GENSTS_DEF_Pos) /*!< EMAC_T::GENSTS: DEF Mask */ + +#define EMAC_GENSTS_TXPAUSED_Pos (9) /*!< EMAC_T::GENSTS: TXPAUSED Position */ +#define EMAC_GENSTS_TXPAUSED_Msk (0x1ul << EMAC_GENSTS_TXPAUSED_Pos) /*!< EMAC_T::GENSTS: TXPAUSED Mask */ + +#define EMAC_GENSTS_SQE_Pos (10) /*!< EMAC_T::GENSTS: SQE Position */ +#define EMAC_GENSTS_SQE_Msk (0x1ul << EMAC_GENSTS_SQE_Pos) /*!< EMAC_T::GENSTS: SQE Mask */ + +#define EMAC_GENSTS_TXHALT_Pos (11) /*!< EMAC_T::GENSTS: TXHALT Position */ +#define EMAC_GENSTS_TXHALT_Msk (0x1ul << EMAC_GENSTS_TXHALT_Pos) /*!< EMAC_T::GENSTS: TXHALT Mask */ + +#define EMAC_GENSTS_RPSTS_Pos (12) /*!< EMAC_T::GENSTS: RPSTS Position */ +#define EMAC_GENSTS_RPSTS_Msk (0x1ul << EMAC_GENSTS_RPSTS_Pos) /*!< EMAC_T::GENSTS: RPSTS Mask */ + +#define EMAC_MPCNT_MPCNT_Pos (0) /*!< EMAC_T::MPCNT: MPCNT Position */ +#define EMAC_MPCNT_MPCNT_Msk (0xfffful << EMAC_MPCNT_MPCNT_Pos) /*!< EMAC_T::MPCNT: MPCNT Mask */ + +#define EMAC_RPCNT_RPCNT_Pos (0) /*!< EMAC_T::RPCNT: RPCNT Position */ +#define EMAC_RPCNT_RPCNT_Msk (0xfffful << EMAC_RPCNT_RPCNT_Pos) /*!< EMAC_T::RPCNT: RPCNT Mask */ + +#define EMAC_FRSTS_RXFLT_Pos (0) /*!< EMAC_T::FRSTS: RXFLT Position */ +#define EMAC_FRSTS_RXFLT_Msk (0xfffful << EMAC_FRSTS_RXFLT_Pos) /*!< EMAC_T::FRSTS: RXFLT Mask */ + +#define EMAC_CTXDSA_CTXDSA_Pos (0) /*!< EMAC_T::CTXDSA: CTXDSA Position */ +#define EMAC_CTXDSA_CTXDSA_Msk (0xfffffffful << EMAC_CTXDSA_CTXDSA_Pos) /*!< EMAC_T::CTXDSA: CTXDSA Mask */ + +#define EMAC_CTXBSA_CTXBSA_Pos (0) /*!< EMAC_T::CTXBSA: CTXBSA Position */ +#define EMAC_CTXBSA_CTXBSA_Msk (0xfffffffful << EMAC_CTXBSA_CTXBSA_Pos) /*!< EMAC_T::CTXBSA: CTXBSA Mask */ + +#define EMAC_CRXDSA_CRXDSA_Pos (0) /*!< EMAC_T::CRXDSA: CRXDSA Position */ +#define EMAC_CRXDSA_CRXDSA_Msk (0xfffffffful << EMAC_CRXDSA_CRXDSA_Pos) /*!< EMAC_T::CRXDSA: CRXDSA Mask */ + +#define EMAC_CRXBSA_CRXBSA_Pos (0) /*!< EMAC_T::CRXBSA: CRXBSA Position */ +#define EMAC_CRXBSA_CRXBSA_Msk (0xfffffffful << EMAC_CRXBSA_CRXBSA_Pos) /*!< EMAC_T::CRXBSA: CRXBSA Mask */ + +#define EMAC_TSCTL_TSEN_Pos (0) /*!< EMAC_T::TSCTL: TSEN Position */ +#define EMAC_TSCTL_TSEN_Msk (0x1ul << EMAC_TSCTL_TSEN_Pos) /*!< EMAC_T::TSCTL: TSEN Mask */ + +#define EMAC_TSCTL_TSIEN_Pos (1) /*!< EMAC_T::TSCTL: TSIEN Position */ +#define EMAC_TSCTL_TSIEN_Msk (0x1ul << EMAC_TSCTL_TSIEN_Pos) /*!< EMAC_T::TSCTL: TSIEN Mask */ + +#define EMAC_TSCTL_TSMODE_Pos (2) /*!< EMAC_T::TSCTL: TSMODE Position */ +#define EMAC_TSCTL_TSMODE_Msk (0x1ul << EMAC_TSCTL_TSMODE_Pos) /*!< EMAC_T::TSCTL: TSMODE Mask */ + +#define EMAC_TSCTL_TSUPDATE_Pos (3) /*!< EMAC_T::TSCTL: TSUPDATE Position */ +#define EMAC_TSCTL_TSUPDATE_Msk (0x1ul << EMAC_TSCTL_TSUPDATE_Pos) /*!< EMAC_T::TSCTL: TSUPDATE Mask */ + +#define EMAC_TSCTL_TSALMEN_Pos (5) /*!< EMAC_T::TSCTL: TSALMEN Position */ +#define EMAC_TSCTL_TSALMEN_Msk (0x1ul << EMAC_TSCTL_TSALMEN_Pos) /*!< EMAC_T::TSCTL: TSALMEN Mask */ + +#define EMAC_TSSEC_SEC_Pos (0) /*!< EMAC_T::TSSEC: SEC Position */ +#define EMAC_TSSEC_SEC_Msk (0xfffffffful << EMAC_TSSEC_SEC_Pos) /*!< EMAC_T::TSSEC: SEC Mask */ + +#define EMAC_TSSUBSEC_SUBSEC_Pos (0) /*!< EMAC_T::TSSUBSEC: SUBSEC Position */ +#define EMAC_TSSUBSEC_SUBSEC_Msk (0xfffffffful << EMAC_TSSUBSEC_SUBSEC_Pos) /*!< EMAC_T::TSSUBSEC: SUBSEC Mask */ + +#define EMAC_TSINC_CNTINC_Pos (0) /*!< EMAC_T::TSINC: CNTINC Position */ +#define EMAC_TSINC_CNTINC_Msk (0xfful << EMAC_TSINC_CNTINC_Pos) /*!< EMAC_T::TSINC: CNTINC Mask */ + +#define EMAC_TSADDEND_ADDEND_Pos (0) /*!< EMAC_T::TSADDEND: ADDEND Position */ +#define EMAC_TSADDEND_ADDEND_Msk (0xfffffffful << EMAC_TSADDEND_ADDEND_Pos) /*!< EMAC_T::TSADDEND: ADDEND Mask */ + +#define EMAC_UPDSEC_SEC_Pos (0) /*!< EMAC_T::UPDSEC: SEC Position */ +#define EMAC_UPDSEC_SEC_Msk (0xfffffffful << EMAC_UPDSEC_SEC_Pos) /*!< EMAC_T::UPDSEC: SEC Mask */ + +#define EMAC_UPDSUBSEC_SUBSEC_Pos (0) /*!< EMAC_T::UPDSUBSEC: SUBSEC Position */ +#define EMAC_UPDSUBSEC_SUBSEC_Msk (0xfffffffful << EMAC_UPDSUBSEC_SUBSEC_Pos) /*!< EMAC_T::UPDSUBSEC: SUBSEC Mask */ + +#define EMAC_ALMSEC_SEC_Pos (0) /*!< EMAC_T::ALMSEC: SEC Position */ +#define EMAC_ALMSEC_SEC_Msk (0xfffffffful << EMAC_ALMSEC_SEC_Pos) /*!< EMAC_T::ALMSEC: SEC Mask */ + +#define EMAC_ALMSUBSEC_SUBSEC_Pos (0) /*!< EMAC_T::ALMSUBSEC: SUBSEC Position */ +#define EMAC_ALMSUBSEC_SUBSEC_Msk (0xfffffffful << EMAC_ALMSUBSEC_SUBSEC_Pos) /*!< EMAC_T::ALMSUBSEC: SUBSEC Mask */ + +/**@}*/ /* EMAC_CONST */ +/**@}*/ /* end of EMAC register group */ +/**@}*/ /* end of REGISTER group */ + +#if defined ( __CC_ARM ) + #pragma no_anon_unions +#endif + +#endif /* __EMAC_REG_H__ */ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_2d.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_2d.h new file mode 100644 index 0000000000000000000000000000000000000000..36275b15eaf7d4004324607a1c68aaefd76ad951 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_2d.h @@ -0,0 +1,190 @@ +/**************************************************************************//** +* @file 2d.h +* @brief N9H30 2DGE driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_2D_H__ +#define __NU_2D_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_GE2D_Driver GE2D Driver + @{ +*/ + +/** @addtogroup N9H30_GE2D_EXPORTED_CONSTANTS GE2D Exported Constants + @{ +*/ + +/// @cond HIDDEN_SYMBOLS +typedef struct +{ + UINT32 PatternA; + UINT32 PatternB; +} MONOPATTERN; + +#define COLOR_KEY 0xFF000000 +/// @endcond HIDDEN_SYMBOLS + +/////////////////////////////////////////////////////////////////////////////// +// Definition of ROP2 +/////////////////////////////////////////////////////////////////////////////// +#define BLACKNESS 0x00 /*!< rop code: 0 */ +#define DSTINVERT 0x55 /*!< rop code: Dn */ +#define MERGECOPY 0xC0 /*!< rop code: PSa */ +#define MERGEPAINT 0xBB /*!< rop code: DSno */ +#define NOTSRCCOPY 0x33 /*!< rop code: Sn */ +#define NOTSRCERASE 0x11 /*!< rop code: DSon */ +#define PATCOPY 0xF0 /*!< rop code: P */ +#define PATINVERT 0x5A /*!< rop code: DPx */ +#define PATPAINT 0xFB /*!< rop code: DPSnoo */ +#define SRCAND 0x88 /*!< rop code: DSa */ +#define SRCCOPY 0xCC /*!< rop code: S */ +#define SRCERASE 0x44 /*!< rop code: SDna */ +#define SRCINVERT 0x66 /*!< rop code: DSx */ +#define SRCPAINT 0xEE /*!< rop code: DSo */ +#define WHITENESS 0xFF /*!< rop code: 1 */ + +/////////////////////////////////////////////////////////////////////////////// +// Definition of Pen Styles +/////////////////////////////////////////////////////////////////////////////// +#define PS_SOLID 0xffff /*!< pan style: solid */ //1111111111111111 (1111111111111111) +#define PS_DASH 0xcccc /*!< pan style: dash */ //1100110011001100 (1111000011110000) +#define PS_DOT 0xaaaa /*!< pan style: dot */ //1010101010101010 (1100110011001100) +#define PS_DASHDOT 0xe4e4 /*!< pan style: dash and dot */ //1110010011100100 (1111110000110000) +#define PS_DASHDOTDOT 0xeaea /*!< pan style: dash and two dots */ //1110101011101010 (1111110011001100) +#define PS_NULL 0x0000 /*!< pan style: null */ //0000000000000000 (0000000000000000) + +/////////////////////////////////////////////////////////////////////////////// +// Definition of Brush Styles +// +// HS_HORIZONTAL: 00000000 HS_BDIAGONAL: 00000001 +// 00000000 00000010 +// 00000000 00000100 +// 00000000 00001000 +// 11111111 00010000 +// 00000000 00100000 +// 00000000 01000000 +// 00000000 10000000 +// +// HS_VERTICAL: 00001000 HS_CROSS: 00001000 +// 00001000 00001000 +// 00001000 00001000 +// 00001000 00001000 +// 00001000 11111111 +// 00001000 00001000 +// 00001000 00001000 +// 00001000 00001000 +// +// HS_FDIAGONAL: 10000000 HS_DIAGCROSS: 10000001 +// 01000000 01000010 +// 00100000 00100100 +// 00010000 00011000 +// 00001000 00011000 +// 00000100 00100100 +// 00000010 01000010 +// 00000001 10000001 +/////////////////////////////////////////////////////////////////////////////// +#define HS_HORIZONTAL 0 /*!< brush style: horizontal */ +#define HS_VERTICAL 1 /*!< brush style: vertical */ +#define HS_FDIAGONAL 2 /*!< brush style: fdiagonal */ +#define HS_BDIAGONAL 3 /*!< brush style: bdiagonal */ +#define HS_CROSS 4 /*!< brush style: cross */ +#define HS_DIAGCROSS 5 /*!< brush style: diagcross */ + +#define MODE_OPAQUE 0 /*!< opaque mode */ +#define MODE_TRANSPARENT 1 /*!< transparent mode */ +#define MODE_SRC_TRANSPARENT MODE_TRANSPARENT /*!< source transparent mode */ +#define MODE_DEST_TRANSPARENT 2 /*!< destination transparent mode */ + +#define MODE_INSIDE_CLIP 0 /*!< clip inside */ +#define MODE_OUTSIDE_CLIP 1 /*!< clip outside */ + +#define TYPE_MONO 0 /*!< mono */ +#define TYPE_COLOR 1 /*!< color */ + +#define GE_BPP_8 0x00000000 /*!< 8bpp display */ +#define GE_BPP_16 0x00000010 /*!< 16bpp display */ +#define GE_BPP_32 0x00000020 /*!< 32bpp display */ + +#define RGB332 1 /*!< 8bpp display */ +#define RGB565 2 /*!< 16bpp display */ +#define RGB888 3 /*!< 24bpp display */ + +#define F8x8 0 /*!< 8x8 font support */ +#define F8x16 1 /*!< 8x16 font support */ + +/*@}*/ /* end of group N9H30_GE2D_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_GE2D_EXPORTED_FUNCTIONS GE2D Exported Functions + @{ +*/ + +void ge2dClearScreen(int color); +void ge2dSetWriteMask(int mask); +void ge2dSetSourceOriginStarting(void *ptr); +void ge2dSetDestinationOriginStarting(void *ptr); +void ge2dInit(int bpp, int width, int height, void *destination); +void ge2dReset(void); +void ge2dResetFIFO(void); +void ge2dBitblt_SetDrawMode(int opt, int ckey, int mask); +int ge2dBitblt_SetAlphaMode(int opt, int ks, int kd); +void ge2dBitblt_ScreenToScreen(int srcx, int srcy, int destx, int desty, int width, int height); +void ge2dBitblt_ScreenToScreenRop(int srcx, int srcy, int destx, int desty, int width, int height, int rop); +void ge2dBitblt_SourceToDestination(int srcx, int srcy, int destx, int desty, int width, int height, int srcpitch, int destpitch); +void ge2dClip_SetClip(int x1, int y1, int x2, int y2); +void ge2dClip_SetClipMode(int opt); +void ge2dDrawFrame(int x1, int y1, int x2, int y2, int color, int opt); +void ge2dLine_DrawSolidLine(int x1, int y1, int x2, int y2, int color); +void ge2dLine_DrawSolidLine_RGB565(int x1, int y1, int x2, int y2, int color); +void ge2dLine_DrawStyledLine(int x1, int y1, int x2, int y2, int style, int fgcolor, int bkcolor, int draw_mode); +void ge2dLine_DrawStyledLine_RGB565(int x1, int y1, int x2, int y2, int style, int fgcolor, int bkcolor, int draw_mode); +void ge2dFill_Solid(int dx, int dy, int width, int height, int color); +void ge2dFill_Solid_RGB565(int dx, int dy, int width, int height, int color); +void ge2dFill_SolidBackground(int dx, int dy, int width, int height, int color); +void ge2dFill_ColorPattern(int dx, int dy, int width, int height); +void ge2dFill_MonoPattern(int dx, int dy, int width, int height, int opt); +void ge2dFill_ColorPatternROP(int sx, int sy, int width, int height, int rop); +void ge2dFill_MonoPatternROP(int sx, int sy, int width, int height, int rop, int opt); +void ge2dFill_TileBlt(int srcx, int srcy, int destx, int desty, int width, int height, int x_count, int y_count); +void ge2dHostBlt_Write(int x, int y, int width, int height, void *buf); +void ge2dHostBlt_Read(int x, int y, int width, int height, void *buf); +void ge2dHostBlt_Sprite(int x, int y, int width, int height, void *buf); +void ge2dRotation(int srcx, int srcy, int destx, int desty, int width, int height, int ctl); +void ge2dSpriteBlt_Screen(int destx, int desty, int sprite_width, int sprite_height, void *buf); +void ge2dSpriteBltx_Screen(int x, int y, int sprite_sx, int sprite_sy, int width, int height, int sprite_width, int sprite_height, void *buf); +void ge2dSpriteBlt_ScreenRop(int x, int y, int sprite_width, int sprite_height, void *buf, int rop); +void ge2dSpriteBltx_ScreenRop(int x, int y, int sprite_sx, int sprite_sy, int width, int height, int sprite_width, int sprite_height, void *buf, int rop); +void ge2dColorExpansionBlt(int x, int y, int width, int height, int fore_color, int back_color, int opt, void *buf); +void ge2dHostColorExpansionBlt(int x, int y, int width, int height, int fore_color, int back_color, int opt, void *buf); +void ge2dInitMonoPattern(int opt, int fore_color, int back_color); +void ge2dInitMonoInputPattern(UINT32 PatternA, UINT32 PatternB, int fore_color, int back_color); +void ge2dInitColorPattern(int patformat, void *patdata); +void ge2dFont_PutChar(int x, int y, char asc_code, int fore_color, int back_color, int draw_mode, int font_id); +void ge2dFont_PutString(int x, int y, char *str, int fore_color, int back_color, int draw_mode, int font_id); + +/*@}*/ /* end of group N9H30_GE2D_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_GE2D_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + + +#ifdef __cplusplus +} +#endif + +#endif //__NU_2D_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_adc.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_adc.h new file mode 100644 index 0000000000000000000000000000000000000000..6747946db503675328e1cc052758baa169c4f37e --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_adc.h @@ -0,0 +1,198 @@ +/**************************************************************************//** +* @file adc.h +* @brief N9H30 ADC driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_ADC_H__ +#define __NU_ADC_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_ADC_Driver ADC Driver + @{ +*/ + +/** @addtogroup N9H30_ADC_EXPORTED_CONSTANTS ADC Exported Constants + @{ +*/ + +#define ADC_ERR_ARGS 1 /*!< The arguments is wrong */ +#define ADC_ERR_CMD 2 /*!< The command is wrong */ + +/// @cond HIDDEN_SYMBOLS +typedef int32_t(*ADC_CALLBACK)(uint32_t status, uint32_t userData); +/// @endcond HIDDEN_SYMBOLS +/*---------------------------------------------------------------------------------------------------------*/ +/* ADC_CTL constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define ADC_CTL_ADEN 0x00000001 /*!< ADC Power Control */ +#define ADC_CTL_VBGEN 0x00000002 /*!< ADC Internal Bandgap Power Control */ +#define ADC_CTL_PWKPEN 0x00000004 /*!< ADC Keypad Power Enable Control */ +#define ADC_CTL_MST 0x00000100 /*!< Menu Start Conversion */ +#define ADC_CTL_PEDEEN 0x00000200 /*!< Pen Down Event Enable */ +#define ADC_CTL_WKPEN 0x00000400 /*!< Keypad Press Wake Up Enable */ +#define ADC_CTL_WKTEN 0x00000800 /*!< Touch Wake Up Enable */ +#define ADC_CTL_WMSWCH 0x00010000 /*!< Wire Mode Switch For 5-Wire/4-Wire Configuration */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* ADC_CONF constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define ADC_CONF_TEN 0x00000001 /*!< Touch Enable */ +#define ADC_CONF_ZEN 0x00000002 /*!< Press Enable */ +#define ADC_CONF_NACEN 0x00000004 /*!< Normal AD Conversion Enable */ +#define ADC_CONF_VBATEN 0x00000100 /*!< Voltage Battery Enable */ +#define ADC_CONF_KPCEN 0x00000200 /*!< Keypad Press Conversion Enable */ +#define ADC_CONF_SELFTEN 0x00000400 /*!< Selft Test Enable */ +#define ADC_CONF_DISTMAVEN (1<<20) /*!< Display T Mean Average Enable */ +#define ADC_CONF_DISZMAVEN (1<<21) /*!< Display Z Mean Average Enable */ +#define ADC_CONF_HSPEED (1<<22) /*!< High Speed Enable */ + +#define ADC_CONF_CHSEL_Pos 3 /*!< Channel Selection Position */ +#define ADC_CONF_CHSEL_Msk (7<<3) /*!< Channel Selection Mask */ +#define ADC_CONF_CHSEL_VBT (0<<3) /*!< ADC input channel select VBT */ +#define ADC_CONF_CHSEL_VHS (1<<3) /*!< ADC input channel select VHS */ +#define ADC_CONF_CHSEL_A2 (2<<3) /*!< ADC input channel select A2 */ +#define ADC_CONF_CHSEL_A3 (3<<3) /*!< ADC input channel select A3 */ +#define ADC_CONF_CHSEL_YM (4<<3) /*!< ADC input channel select YM */ +#define ADC_CONF_CHSEL_YP (5<<3) /*!< ADC input channel select YP */ +#define ADC_CONF_CHSEL_XM (6<<3) /*!< ADC input channel select XM */ +#define ADC_CONF_CHSEL_XP (7<<3) /*!< ADC input channel select XP */ + +#define ADC_CONF_REFSEL_Pos 6 /*!< Reference Selection Position */ +#define ADC_CONF_REFSEL_Msk (3<<6) /*!< Reference Selection Mask */ +#define ADC_CONF_REFSEL_VREF (0<<6) /*!< ADC reference select VREF input or 2.5v buffer output */ +#define ADC_CONF_REFSEL_YMYP (1<<6) /*!< ADC reference select YM vs YP */ +#define ADC_CONF_REFSEL_XMXP (2<<6) /*!< ADC reference select XM vs XP */ +#define ADC_CONF_REFSEL_AVDD33 (3<<6) /*!< ADC reference select AGND33 vs AVDD33 */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* ADC_IER constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define ADC_IER_MIEN 0x00000001 /*!< Menu Interrupt Enable */ +#define ADC_IER_KPEIEN 0x00000002 /*!< Keypad Press Event Interrupt Enable */ +#define ADC_IER_PEDEIEN 0x00000004 /*!< Pen Down Even Interrupt Enable */ +#define ADC_IER_WKTIEN 0x00000008 /*!< Wake Up Touch Interrupt Enable */ +#define ADC_IER_WKPIEN 0x00000010 /*!< Wake Up Keypad Press Interrupt Enable */ +#define ADC_IER_KPUEIEN 0x00000020 /*!< Keypad Press Up Event Interrupt Enable */ +#define ADC_IER_PEUEIEN 0x00000040 /*!< Pen Up Event Interrupt Enable */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* ADC_ISR constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define ADC_ISR_MF 0x00000001 /*!< Menu Complete Flag */ +#define ADC_ISR_KPEF 0x00000002 /*!< Keypad Press Event Flag */ +#define ADC_ISR_PEDEF 0x00000004 /*!< Pen Down Event Flag */ +#define ADC_ISR_KPUEF 0x00000008 /*!< Keypad Press Up Event Flag */ +#define ADC_ISR_PEUEF 0x00000010 /*!< Pen Up Event Flag */ +#define ADC_ISR_TF 0x00000100 /*!< Touch Conversion Finish */ +#define ADC_ISR_ZF 0x00000200 /*!< Press Conversion Finish */ +#define ADC_ISR_NACF 0x00000400 /*!< Normal AD Conversion Finish */ +#define ADC_ISR_VBF 0x00000800 /*!< Voltage Battery Conversion Finish */ +#define ADC_ISR_KPCF 0x00001000 /*!< Keypad Press Conversion Finish */ +#define ADC_ISR_SELFTF 0x00002000 /*!< Self-Test Conversion Finish */ +#define ADC_ISR_INTKP 0x00010000 /*!< Interrupt Signal For Keypad Detection */ +#define ADC_ISR_INTTC 0x00020000 /*!< Interrupt Signal For Touch Screen Touching Detection */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* ADC_WKISR constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define ADC_WKISR_WKPEF 0x00000001 /*!< Wake Up Pen Down Event Flag */ +#define ADC_WKISR_WPEDEF 0x00000002 /*!< Wake Up Keypad Press Event Flage */ + +/** \brief Structure type of ADC_CHAN + */ +typedef enum +{ + AIN0 = ADC_CONF_CHSEL_VBT, /*!< ADC input channel select \ref ADC_CONF_CHSEL_VBT */ + AIN1 = ADC_CONF_CHSEL_VHS, /*!< ADC input channel select \ref ADC_CONF_CHSEL_VHS */ + AIN2 = ADC_CONF_CHSEL_A2, /*!< ADC input channel select \ref ADC_CONF_CHSEL_A2 */ + AIN3 = ADC_CONF_CHSEL_A3, /*!< ADC input channel select \ref ADC_CONF_CHSEL_A3 */ + AIN4 = ADC_CONF_CHSEL_YM, /*!< ADC input channel select \ref ADC_CONF_CHSEL_YM */ + AIN5 = ADC_CONF_CHSEL_XP, /*!< ADC input channel select \ref ADC_CONF_CHSEL_XP */ + AIN6 = ADC_CONF_CHSEL_XM, /*!< ADC input channel select \ref ADC_CONF_CHSEL_XM */ + AIN7 = ADC_CONF_CHSEL_XP /*!< ADC input channel select \ref ADC_CONF_CHSEL_XP */ +} ADC_CHAN; + +/** \brief Structure type of ADC_CMD + */ +typedef enum +{ + START_MST, /*!STATUS) + +/** + * @brief Get specified interrupt pending status. + * + * @param[in] can The base address of can module. + * + * @return The source of the interrupt. + * + * @details If several interrupts are pending, the CAN Interrupt Register will point to the pending interrupt + * with the highest priority, disregarding their chronological order. + * \hideinitializer + */ +#define CAN_GET_INT_PENDING_STATUS(can) ((can)->IIDR) + +/** + * @brief Disable wake-up function. + * + * @param[in] can The base address of can module. + * + * @return None + * + * @details The macro is used to disable wake-up function. + * \hideinitializer + */ +#define CAN_DISABLE_WAKEUP(can) ((can)->WU_EN = 0ul) + +/** + * @brief Enable wake-up function. + * + * @param[in] can The base address of can module. + * + * @return None + * + * @details User can wake-up system when there is a falling edge in the CAN_Rx pin. + * \hideinitializer + */ +#define CAN_ENABLE_WAKEUP(can) ((can)->WU_EN = CAN_WU_EN_WAKUP_EN_Msk) + +/** + * @brief Get specified Message Object new data into bit value. + * + * @param[in] can The base address of can module. + * @param[in] u32MsgNum Specified Message Object number, valid value are from 0 to 31. + * + * @return Specified Message Object new data into bit value. + * + * @details The NewDat bit (CAN_IFn_MCON[15]) of a specific Message Object can be set/reset by the software through the IFn Message Interface Registers + * or by the Message Handler after reception of a Data Frame or after a successful transmission. + * \hideinitializer + */ +#define CAN_GET_NEW_DATA_IN_BIT(can, u32MsgNum) ((u32MsgNum) < 16 ? (can)->NDAT1 & (1 << (u32MsgNum)) : (can)->NDAT2 & (1 << ((u32MsgNum)-16))) + + +/*---------------------------------------------------------------------------------------------------------*/ +/* Define CAN functions prototype */ +/*---------------------------------------------------------------------------------------------------------*/ +uint32_t CAN_SetBaudRate(CAN_T *tCAN, uint32_t u32BaudRate); +uint32_t CAN_Open(CAN_T *tCAN, uint32_t u32BaudRate, uint32_t u32Mode); +void CAN_Close(CAN_T *tCAN); +void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum); +void CAN_EnableInt(CAN_T *tCAN, uint32_t u32Mask); +void CAN_DisableInt(CAN_T *tCAN, uint32_t u32Mask); +int32_t CAN_Transmit(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T *pCanMsg); +int32_t CAN_Receive(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T *pCanMsg); +int32_t CAN_SetMultiRxMsg(CAN_T *tCAN, uint32_t u32MsgNum, uint32_t u32MsgCount, uint32_t u32IDType, uint32_t u32ID); +int32_t CAN_SetRxMsg(CAN_T *tCAN, uint32_t u32MsgNum, uint32_t u32IDType, uint32_t u32ID); +int32_t CAN_SetRxMsgAndMsk(CAN_T *tCAN, uint32_t u32MsgNum, uint32_t u32IDType, uint32_t u32ID, uint32_t u32IDMask); +int32_t CAN_SetTxMsg(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T *pCanMsg); +int32_t CAN_TriggerTxMsg(CAN_T *tCAN, uint32_t u32MsgNum); +int32_t CAN_BasicSendMsg(CAN_T *tCAN, STR_CANMSG_T *pCanMsg); +int32_t CAN_BasicReceiveMsg(CAN_T *tCAN, STR_CANMSG_T *pCanMsg); +void CAN_EnterInitMode(CAN_T *tCAN, uint8_t u8Mask); +void CAN_EnterTestMode(CAN_T *tCAN, uint8_t u8TestMask); +void CAN_LeaveTestMode(CAN_T *tCAN); +uint32_t CAN_GetCANBitRate(CAN_T *tCAN); +uint32_t CAN_IsNewDataReceived(CAN_T *tCAN, uint8_t u8MsgObj); +void CAN_LeaveInitMode(CAN_T *tCAN); +int32_t CAN_SetRxMsgObjAndMsk(CAN_T *tCAN, uint8_t u8MsgObj, uint8_t u8idType, uint32_t u32id, uint32_t u32idmask, uint8_t u8singleOrFifoLast); +int32_t CAN_SetRxMsgObj(CAN_T *tCAN, uint8_t u8MsgObj, uint8_t u8idType, uint32_t u32id, uint8_t u8singleOrFifoLast); +void CAN_WaitMsg(CAN_T *tCAN); +int32_t CAN_ReadMsgObj(CAN_T *tCAN, uint8_t u8MsgObj, uint8_t u8Release, STR_CANMSG_T *pCanMsg); + +/*@}*/ /* end of group CAN_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group CAN_Driver */ + +/*@}*/ /* end of group Standard_Driver */ + + + +#endif /*__NU_CAN_H__ */ + +/*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_cap.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_cap.h new file mode 100644 index 0000000000000000000000000000000000000000..dc06ea7f608f71fe75745581172182f02f8805ce --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_cap.h @@ -0,0 +1,316 @@ +/**************************************************************************//** +* @file cap.h +* @version V1.00 +* $Revision: 2 $ +* $Date: 15/06/12 8:48a $ +* @brief N9H30 CAP driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_CAP_H__ +#define __NU_CAP_H__ + +// #include header file +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_CAP_Driver CAP Driver + @{ +*/ + +/** @addtogroup N9H30_CAP_EXPORTED_CONSTANTS CAP Exported Constants + @{ +*/ + +/* Define data type (struct, union? */ +// #define Constant +#include "N9H30.h" +#include "nu_sys.h" + +/*---------------------------------------------------------------------------------------------------------*/ +/* CAP_CTL constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define CAPEN BIT0 /*!< Interrupt enable for VPE operations */ +#define ADDRSW BIT3 /*!< Packet Buffer Address Switch */ +#define PLNEN BIT5 /*!< Planar Output Enable */ +#define PKTEN BIT6 /*!< Packet Output Enable */ +#define SHUTTER BIT16 /*!< Image Capture Interface Automatically Disable The Capture Inteface After A Frame Had Been Captured */ +#define UPDATE BIT20 /*!< Update Register At New Frame */ +#define VPRST BIT24 /*!< Capture Interface Reset */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* CAP_PAR constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define INFMT BIT0 /*!< Sensor Input Data Format */ +#define SENTYPE BIT1 /*!< Sensor Input Type */ +#define INDATORD (BIT2|BIT3) /*!< Sensor Input Data Order */ +#define OUTFMT (BIT4|BIT5) /*!< Image Data Format Output To System Memory */ +#define RANGE BIT6 /*!< Scale Input YUV CCIR601 Color Range To Full Range */ +#define PLNFMT BIT7 /*!< Planar Output YUV Format */ +#define PCLKP BIT8 /*!< Sensor Pixel Clock Polarity */ +#define HSP BIT9 /*!< Sensor Hsync Polarity */ +#define VSP BIT10 /*!< Sensor Vsync Polarity */ +#define COLORCTL (BIT11|BIT12) /*!< Special COLORCTL Processing */ +#define FBB BIT18 /*!< Field By Blank */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* CAP_INT constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define MDIEN BIT20 /*!< Motion Detection Output Finish Interrupt Enable */ +#define ADDRMIEN BIT19 /*!< Address Match Interrupt Enable */ +#define MEIEN BIT17 /*!< System Memory Error Interrupt Enable */ +#define VIEN BIT16 /*!< Video Frame End Interrupt Enable */ +#define MDINTF BIT4 /*!< Motion Detection Output Finish Interrupt */ +#define ADDRMINTF BIT3 /*!< Memory Address Match Interrupt */ +#define MEINTF BIT1 /*!< Bus Master Transfer Error Interrupt */ +#define VINTF BIT0 /*!< Video Frame End Interrupt */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* CAP_MD constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define MDEN BIT0 /*!< Motion Detection Enable */ +#define MDBS BIT8 /*!< Motion Detection Block Size */ +#define MDSM BIT9 /*!< Motion Detection Save Mode */ +#define MDDF (BIT10|BIT11) /*!< Motion Detection Detect Frequency */ +#define MDTHR (BIT16|BIT17|BIT18|BIT19|BIT20) /*!< Motion Detection Differential Threshold */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* CAP_CWSP constant definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define CWSADDRH (0xFFF<<0) /*!INTEN |= CRPT_INTEN_PRNGIEN_Msk) + +/** + * @brief This macro disables PRNG interrupt. + * @return None + * \hideinitializer + */ +#define PRNG_DISABLE_INT() (CRPT->INTEN &= ~CRPT_INTEN_PRNGIEN_Msk) + +/** + * @brief This macro gets PRNG interrupt flag. + * @return PRNG interrupt flag. + * \hideinitializer + */ +#define PRNG_GET_INT_FLAG() (CRPT->INTSTS & CRPT_INTSTS_PRNGIF_Msk) + +/** + * @brief This macro clears PRNG interrupt flag. + * @return None + * \hideinitializer + */ +#define PRNG_CLR_INT_FLAG() (CRPT->INTSTS = CRPT_INTSTS_PRNGIF_Msk) + +/** + * @brief This macro enables AES interrupt. + * @return None + * \hideinitializer + */ +#define AES_ENABLE_INT() (CRPT->INTEN |= (CRPT_INTEN_AESIEN_Msk|CRPT_INTEN_AESERRIEN_Msk)) + +/** + * @brief This macro disables AES interrupt. + * @return None + * \hideinitializer + */ +#define AES_DISABLE_INT() (CRPT->INTEN &= ~(CRPT_INTEN_AESIEN_Msk|CRPT_INTEN_AESERRIEN_Msk)) + +/** + * @brief This macro gets AES interrupt flag. + * @return AES interrupt flag. + * \hideinitializer + */ +#define AES_GET_INT_FLAG() (CRPT->INTSTS & (CRPT_INTSTS_AESIF_Msk|CRPT_INTSTS_AESERRIF_Msk)) + +/** + * @brief This macro clears AES interrupt flag. + * @return None + * \hideinitializer + */ +#define AES_CLR_INT_FLAG() (CRPT->INTSTS = (CRPT_INTSTS_AESIF_Msk|CRPT_INTSTS_AESERRIF_Msk)) + +/** + * @brief This macro enables AES key protection. + * @return None + * \hideinitializer + */ +#define AES_ENABLE_KEY_PROTECT() (CRPT->AES_CTL |= CRPT_AES_CTL_KEYPRT_Msk) + +/** + * @brief This macro disables AES key protection. + * @return None + * \hideinitializer + */ +#define AES_DISABLE_KEY_PROTECT() (CRPT->AES_CTL = (CRPT->AES_CTL & ~CRPT_AES_CTL_KEYPRT_Msk) | (0x16<INTEN |= (CRPT_INTEN_TDESIEN_Msk|CRPT_INTEN_TDESERRIEN_Msk)) + +/** + * @brief This macro disables TDES interrupt. + * @return None + * \hideinitializer + */ +#define TDES_DISABLE_INT() (CRPT->INTEN &= ~(CRPT_INTEN_TDESIEN_Msk|CRPT_INTEN_TDESERRIEN_Msk)) + +/** + * @brief This macro gets TDES interrupt flag. + * @return TDES interrupt flag. + * \hideinitializer + */ +#define TDES_GET_INT_FLAG() (CRPT->INTSTS & (CRPT_INTSTS_TDESIF_Msk|CRPT_INTSTS_TDESERRIF_Msk)) + +/** + * @brief This macro clears TDES interrupt flag. + * @return None + * \hideinitializer + */ +#define TDES_CLR_INT_FLAG() (CRPT->INTSTS = (CRPT_INTSTS_TDESIF_Msk|CRPT_INTSTS_TDESERRIF_Msk)) + +/** + * @brief This macro enables TDES key protection. + * @return None + * \hideinitializer + */ +#define TDES_ENABLE_KEY_PROTECT() (CRPT->TDES_CTL |= CRPT_TDES_CTL_KEYPRT_Msk) + +/** + * @brief This macro disables TDES key protection. + * @return None + * \hideinitializer + */ +#define TDES_DISABLE_KEY_PROTECT() (CRPT->TDES_CTL = (CRPT->TDES_CTL & ~CRPT_TDES_CTL_KEYPRT_Msk) | (0x16<INTEN |= (CRPT_INTEN_SHAIEN_Msk|CRPT_INTEN_SHAERRIEN_Msk)) + +/** + * @brief This macro disables SHA interrupt. + * @return None + * \hideinitializer + */ +#define SHA_DISABLE_INT() (CRPT->INTEN &= ~(CRPT_INTEN_SHAIEN_Msk|CRPT_INTEN_SHAERRIEN_Msk)) + +/** + * @brief This macro gets SHA interrupt flag. + * @return SHA interrupt flag. + * \hideinitializer + */ +#define SHA_GET_INT_FLAG() (CRPT->INTSTS & (CRPT_INTSTS_SHAIF_Msk|CRPT_INTSTS_SHAERRIF_Msk)) + +/** + * @brief This macro clears SHA interrupt flag. + * @return None + * \hideinitializer + */ +#define SHA_CLR_INT_FLAG() (CRPT->INTSTS = (CRPT_INTSTS_SHAIF_Msk|CRPT_INTSTS_SHAERRIF_Msk)) + + + +/*---------------------------------------------------------------------------------------------------------*/ +/* Functions */ +/*---------------------------------------------------------------------------------------------------------*/ + +void PRNG_Open(uint32_t u32KeySize, uint32_t u32SeedReload, uint32_t u32Seed); +void PRNG_Start(void); +void PRNG_Read(uint32_t u32RandKey[]); +void AES_Open(uint32_t u32Channel, uint32_t u32EncDec, uint32_t u32OpMode, uint32_t u32KeySize, uint32_t u32SwapType); +void AES_Start(int32_t u32Channel, uint32_t u32DMAMode); +void AES_SetKey(uint32_t u32Channel, uint32_t au32Keys[], uint32_t u32KeySize); +void AES_SetInitVect(uint32_t u32Channel, uint32_t au32IV[]); +void AES_SetDMATransfer(uint32_t u32Channel, uint32_t u32SrcAddr, uint32_t u32DstAddr, uint32_t u32TransCnt); +void TDES_Open(uint32_t u32Channel, uint32_t u32EncDec, int32_t Is3DES, int32_t Is3Key, uint32_t u32OpMode, uint32_t u32SwapType); +void TDES_Start(int32_t u32Channel, uint32_t u32DMAMode); +void TDES_SetKey(uint32_t u32Channel, uint32_t au32Keys[3][2]); +void TDES_SetInitVect(uint32_t u32Channel, uint32_t u32IVH, uint32_t u32IVL); +void TDES_SetDMATransfer(uint32_t u32Channel, uint32_t u32SrcAddr, uint32_t u32DstAddr, uint32_t u32TransCnt); +void SHA_Open(uint32_t u32OpMode, uint32_t u32SwapType, int hmac_key_len); +void SHA_Start(uint32_t u32DMAMode); +void SHA_SetDMATransfer(uint32_t u32SrcAddr, uint32_t u32TransCnt); +void SHA_Read(uint32_t u32Digest[]); + + +/*@}*/ /* end of group N9H30_CRYPTO_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_CRYPTO_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif // __NU_CRYPTO_H__ + +/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_emac.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_emac.h new file mode 100644 index 0000000000000000000000000000000000000000..f6a5ce86e9c9d1eefecffeb58d9f65f8b957ecf5 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_emac.h @@ -0,0 +1,396 @@ +/**************************************************************************//** + * @file nu_emac.h + * @version V1.00 + * @brief EMAC driver header file + * + * SPDX-License-Identifier: Apache-2.0 + * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#ifndef __NU_EMAC_H__ +#define __NU_EMAC_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "emac_reg.h" + +/** @addtogroup Standard_Driver Standard Driver + @{ +*/ + +/** @addtogroup EMAC_Driver EMAC Driver + @{ +*/ + +/** @addtogroup EMAC_EXPORTED_CONSTANTS EMAC Exported Constants + @{ +*/ + +#define EMAC_PHY_ADDR 1UL /*!< PHY address, this address is board dependent \hideinitializer */ +#define EMAC_RX_DESC_SIZE 64UL /*!< Number of Rx Descriptors, should be 2 at least \hideinitializer */ +#define EMAC_TX_DESC_SIZE 32UL /*!< Number of Tx Descriptors, should be 2 at least \hideinitializer */ +#define EMAC_CAMENTRY_NB 16UL /*!< Number of CAM \hideinitializer */ +#define EMAC_MAX_PKT_SIZE 1536UL /*!< Number of HDR + EXTRA + VLAN_TAG + PAYLOAD + CRC \hideinitializer */ + +#define EMAC_LINK_DOWN 0UL /*!< Ethernet link is down \hideinitializer */ +#define EMAC_LINK_100F 1UL /*!< Ethernet link is 100Mbps full duplex \hideinitializer */ +#define EMAC_LINK_100H 2UL /*!< Ethernet link is 100Mbps half duplex \hideinitializer */ +#define EMAC_LINK_10F 3UL /*!< Ethernet link is 10Mbps full duplex \hideinitializer */ +#define EMAC_LINK_10H 4UL /*!< Ethernet link is 10Mbps half duplex \hideinitializer */ + +/*@}*/ /* end of group EMAC_EXPORTED_CONSTANTS */ + + +/** Tx/Rx buffer descriptor structure */ +typedef struct +{ + uint32_t u32Status1; /*!< Status word 1 */ + uint32_t u32Data; /*!< Pointer to data buffer */ + uint32_t u32Status2; /*!< Status word 2 */ + uint32_t u32Next; /*!< Pointer to next descriptor */ + uint32_t u32Backup1; /*!< For backup descriptor fields over written by time stamp */ + uint32_t u32Backup2; /*!< For backup descriptor fields over written by time stamp */ +} EMAC_DESCRIPTOR_T; + +/** Tx/Rx buffer structure */ +typedef struct +{ + uint8_t au8Buf[EMAC_MAX_PKT_SIZE]; +} EMAC_FRAME_T; + +typedef struct +{ + EMAC_T *psEmac; + + uint32_t u32TxDescSize; + uint32_t u32RxDescSize; + + EMAC_DESCRIPTOR_T *psRXDescs; + EMAC_FRAME_T *psRXFrames; + EMAC_DESCRIPTOR_T *psTXDescs; + EMAC_FRAME_T *psTXFrames; + + EMAC_DESCRIPTOR_T *psCurrentTxDesc; + EMAC_DESCRIPTOR_T *psNextTxDesc; + EMAC_DESCRIPTOR_T *psCurrentRxDesc; + +} EMAC_MEMMGR_T; + +/** @addtogroup EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions + @{ +*/ + + +/** + * @brief Enable EMAC Tx function + * @param None + * @return None + * \hideinitializer + */ +#define EMAC_ENABLE_TX(EMAC) (EMAC->CTL |= EMAC_CTL_TXON_Msk) + + +/** + * @brief Enable EMAC Rx function + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_ENABLE_RX(EMAC) do{EMAC->CTL |= EMAC_CTL_RXON_Msk; EMAC->RXST = 0;}while(0) + +/** + * @brief Disable EMAC Tx function + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_DISABLE_TX(EMAC) (EMAC->CTL &= ~EMAC_CTL_TXON_Msk) + + +/** + * @brief Disable EMAC Rx function + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_DISABLE_RX(EMAC) (EMAC->CTL &= ~EMAC_CTL_RXON_Msk) + +/** + * @brief Enable EMAC Magic Packet Wakeup function + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_ENABLE_MAGIC_PKT_WAKEUP(EMAC) (EMAC->CTL |= EMAC_CTL_WOLEN_Msk) + +/** + * @brief Disable EMAC Magic Packet Wakeup function + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_DISABLE_MAGIC_PKT_WAKEUP(EMAC) (EMAC->CTL &= ~EMAC_CTL_WOLEN_Msk) + +/** + * @brief Enable EMAC to receive broadcast packets + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_ENABLE_RECV_BCASTPKT(EMAC) (EMAC->CAMCTL |= EMAC_CAMCTL_ABP_Msk) + +/** + * @brief Disable EMAC to receive broadcast packets + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_DISABLE_RECV_BCASTPKT(EMAC) (EMAC->CAMCTL &= ~EMAC_CAMCTL_ABP_Msk) + +/** + * @brief Enable EMAC to receive multicast packets + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_ENABLE_RECV_MCASTPKT(EMAC) (EMAC->CAMCTL |= EMAC_CAMCTL_AMP_Msk) + +/** + * @brief Disable EMAC Magic Packet Wakeup function + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_DISABLE_RECV_MCASTPKT(EMAC) (EMAC->CAMCTL &= ~EMAC_CAMCTL_AMP_Msk) + +/** + * @brief Check if EMAC time stamp alarm interrupt occurred or not + * @param The pointer of the specified EMAC module + * @return If time stamp alarm interrupt occurred or not + * @retval 0 Alarm interrupt does not occur + * @retval 1 Alarm interrupt occurred + * \hideinitializer + */ +#define EMAC_GET_ALARM_FLAG(EMAC) (EMAC->INTSTS & EMAC_INTSTS_TSALMIF_Msk ? 1 : 0) + +/** + * @brief Clear EMAC time stamp alarm interrupt flag + * @param The pointer of the specified EMAC module + * @return None + * \hideinitializer + */ +#define EMAC_CLR_ALARM_FLAG(EMAC) (EMAC->INTSTS = EMAC_INTSTS_TSALMIF_Msk) + +/** + * @brief Trigger EMAC Rx function + * @param The pointer of the specified EMAC module + * @return None + */ +#define EMAC_TRIGGER_RX(EMAC) do{EMAC->RXST = 0UL;}while(0) + +/** + * @brief Trigger EMAC Tx function + * @param The pointer of the specified EMAC module + * @return None + */ +#define EMAC_TRIGGER_TX(EMAC) do{EMAC->TXST = 0UL;}while(0) + +/** + * @brief Enable specified EMAC interrupt + * + * @param[in] EMAC The pointer of the specified EMAC module + * @param[in] u32eIntSel Interrupt type select + * - \ref EMAC_INTEN_RXIEN_Msk : Receive + * - \ref EMAC_INTEN_CRCEIEN_Msk : CRC Error + * - \ref EMAC_INTEN_RXOVIEN_Msk : Receive FIFO Overflow + * - \ref EMAC_INTEN_LPIEN_Msk : Long Packet + * - \ref EMAC_INTEN_RXGDIEN_Msk : Receive Good + * - \ref EMAC_INTEN_ALIEIEN_Msk : Alignment Error + * - \ref EMAC_INTEN_RPIEN_Msk : Runt Packet + * - \ref EMAC_INTEN_MPCOVIEN_Msk : Miss Packet Counter Overrun + * - \ref EMAC_INTEN_MFLEIEN_Msk : Maximum Frame Length Exceed + * - \ref EMAC_INTEN_DENIEN_Msk : DMA Early Notification + * - \ref EMAC_INTEN_RDUIEN_Msk : Receive Descriptor Unavailable + * - \ref EMAC_INTEN_RXBEIEN_Msk : Receive Bus Error + * - \ref EMAC_INTEN_CFRIEN_Msk : Control Frame Receive + * - \ref EMAC_INTEN_WOLIEN_Msk : Wake on LAN Interrupt + * - \ref EMAC_INTEN_TXIEN_Msk : Transmit + * - \ref EMAC_INTEN_TXUDIEN_Msk : Transmit FIFO Underflow + * - \ref EMAC_INTEN_TXCPIEN_Msk : Transmit Completion + * - \ref EMAC_INTEN_EXDEFIEN_Msk : Defer Exceed + * - \ref EMAC_INTEN_NCSIEN_Msk : No Carrier Sense + * - \ref EMAC_INTEN_TXABTIEN_Msk : Transmit Abort + * - \ref EMAC_INTEN_LCIEN_Msk : Late Collision + * - \ref EMAC_INTEN_TDUIEN_Msk : Transmit Descriptor Unavailable + * - \ref EMAC_INTEN_TXBEIEN_Msk : Transmit Bus Error + * - \ref EMAC_INTEN_TSALMIEN_Msk : Time Stamp Alarm + * + * @return None + * + * @details This macro enable specified EMAC interrupt. + * \hideinitializer + */ +#define EMAC_ENABLE_INT(EMAC, u32eIntSel) ((EMAC)->INTEN |= (u32eIntSel)) + +/** + * @brief Disable specified EMAC interrupt + * + * @param[in] emac The pointer of the specified EMAC module + * @param[in] u32eIntSel Interrupt type select + * - \ref EMAC_INTEN_RXIEN_Msk : Receive + * - \ref EMAC_INTEN_CRCEIEN_Msk : CRC Error + * - \ref EMAC_INTEN_RXOVIEN_Msk : Receive FIFO Overflow + * - \ref EMAC_INTEN_LPIEN_Msk : Long Packet + * - \ref EMAC_INTEN_RXGDIEN_Msk : Receive Good + * - \ref EMAC_INTEN_ALIEIEN_Msk : Alignment Error + * - \ref EMAC_INTEN_RPIEN_Msk : Runt Packet + * - \ref EMAC_INTEN_MPCOVIEN_Msk : Miss Packet Counter Overrun + * - \ref EMAC_INTEN_MFLEIEN_Msk : Maximum Frame Length Exceed + * - \ref EMAC_INTEN_DENIEN_Msk : DMA Early Notification + * - \ref EMAC_INTEN_RDUIEN_Msk : Receive Descriptor Unavailable + * - \ref EMAC_INTEN_RXBEIEN_Msk : Receive Bus Error + * - \ref EMAC_INTEN_CFRIEN_Msk : Control Frame Receive + * - \ref EMAC_INTEN_WOLIEN_Msk : Wake on LAN Interrupt + * - \ref EMAC_INTEN_TXIEN_Msk : Transmit + * - \ref EMAC_INTEN_TXUDIEN_Msk : Transmit FIFO Underflow + * - \ref EMAC_INTEN_TXCPIEN_Msk : Transmit Completion + * - \ref EMAC_INTEN_EXDEFIEN_Msk : Defer Exceed + * - \ref EMAC_INTEN_NCSIEN_Msk : No Carrier Sense + * - \ref EMAC_INTEN_TXABTIEN_Msk : Transmit Abort + * - \ref EMAC_INTEN_LCIEN_Msk : Late Collision + * - \ref EMAC_INTEN_TDUIEN_Msk : Transmit Descriptor Unavailable + * - \ref EMAC_INTEN_TXBEIEN_Msk : Transmit Bus Error + * - \ref EMAC_INTEN_TSALMIEN_Msk : Time Stamp Alarm + * + * @return None + * + * @details This macro disable specified EMAC interrupt. + * \hideinitializer + */ +#define EMAC_DISABLE_INT(EMAC, u32eIntSel) ((EMAC)->INTEN &= ~ (u32eIntSel)) + +/** + * @brief Get specified interrupt flag/status + * + * @param[in] emac The pointer of the specified EMAC module + * @param[in] u32eIntTypeFlag Interrupt Type Flag, should be + * - \ref EMAC_INTSTS_RXIF_Msk : Receive + * - \ref EMAC_INTSTS_CRCEIF_Msk : CRC Error + * - \ref EMAC_INTSTS_RXOVIF_Msk : Receive FIFO Overflow + * - \ref EMAC_INTSTS_LPIF_Msk : Long Packet + * - \ref EMAC_INTSTS_RXGDIF_Msk : Receive Good + * - \ref EMAC_INTSTS_ALIEIF_Msk : Alignment Error + * - \ref EMAC_INTSTS_RPIF_Msk : Runt Packet + * - \ref EMAC_INTSTS_MPCOVIF_Msk : Missed Packet Counter + * - \ref EMAC_INTSTS_MFLEIF_Msk : Maximum Frame Length Exceed + * - \ref EMAC_INTSTS_DENIF_Msk : DMA Early Notification + * - \ref EMAC_INTSTS_RDUIF_Msk : Receive Descriptor Unavailable + * - \ref EMAC_INTSTS_RXBEIF_Msk : Receive Bus Error + * - \ref EMAC_INTSTS_CFRIF_Msk : Control Frame Receive + * - \ref EMAC_INTSTS_WOLIF_Msk : Wake on LAN + * - \ref EMAC_INTSTS_TXIF_Msk : Transmit + * - \ref EMAC_INTSTS_TXUDIF_Msk : Transmit FIFO Underflow + * - \ref EMAC_INTSTS_TXCPIF_Msk : Transmit Completion + * - \ref EMAC_INTSTS_EXDEFIF_Msk : Defer Exceed + * - \ref EMAC_INTSTS_NCSIF_Msk : No Carrier Sense + * - \ref EMAC_INTSTS_TXABTIF_Msk : Transmit Abort + * - \ref EMAC_INTSTS_LCIF_Msk : Late Collision + * - \ref EMAC_INTSTS_TDUIF_Msk : Transmit Descriptor Unavailable + * - \ref EMAC_INTSTS_TXBEIF_Msk : Transmit Bus Error + * - \ref EMAC_INTSTS_TSALMIF_Msk : Time Stamp Alarm + * + * @return None + * + * @details This macro get specified interrupt flag or interrupt indicator status. + * \hideinitializer + */ +#define EMAC_GET_INT_FLAG(EMAC, u32eIntTypeFlag) (((EMAC)->INTSTS & (u32eIntTypeFlag))?1:0) + +/** + * @brief Clear specified interrupt flag/status + * + * @param[in] emac The pointer of the specified EMAC module + * @param[in] u32eIntTypeFlag Interrupt Type Flag, should be + * - \ref EMAC_INTSTS_RXIF_Msk : Receive + * - \ref EMAC_INTSTS_CRCEIF_Msk : CRC Error + * - \ref EMAC_INTSTS_RXOVIF_Msk : Receive FIFO Overflow + * - \ref EMAC_INTSTS_LPIF_Msk : Long Packet + * - \ref EMAC_INTSTS_RXGDIF_Msk : Receive Good + * - \ref EMAC_INTSTS_ALIEIF_Msk : Alignment Error + * - \ref EMAC_INTSTS_RPIF_Msk : Runt Packet + * - \ref EMAC_INTSTS_MPCOVIF_Msk : Missed Packet Counter + * - \ref EMAC_INTSTS_MFLEIF_Msk : Maximum Frame Length Exceed + * - \ref EMAC_INTSTS_DENIF_Msk : DMA Early Notification + * - \ref EMAC_INTSTS_RDUIF_Msk : Receive Descriptor Unavailable + * - \ref EMAC_INTSTS_RXBEIF_Msk : Receive Bus Error + * - \ref EMAC_INTSTS_CFRIF_Msk : Control Frame Receive + * - \ref EMAC_INTSTS_WOLIF_Msk : Wake on LAN + * - \ref EMAC_INTSTS_TXIF_Msk : Transmit + * - \ref EMAC_INTSTS_TXUDIF_Msk : Transmit FIFO Underflow + * - \ref EMAC_INTSTS_TXCPIF_Msk : Transmit Completion + * - \ref EMAC_INTSTS_EXDEFIF_Msk : Defer Exceed + * - \ref EMAC_INTSTS_NCSIF_Msk : No Carrier Sense + * - \ref EMAC_INTSTS_TXABTIF_Msk : Transmit Abort + * - \ref EMAC_INTSTS_LCIF_Msk : Late Collision + * - \ref EMAC_INTSTS_TDUIF_Msk : Transmit Descriptor Unavailable + * - \ref EMAC_INTSTS_TXBEIF_Msk : Transmit Bus Error + * - \ref EMAC_INTSTS_TSALMIF_Msk : Time Stamp Alarm + * + * @retval 0 The specified interrupt is not happened. + * 1 The specified interrupt is happened. + * + * @details This macro clear specified interrupt flag or interrupt indicator status. + * \hideinitializer + */ +#define EMAC_CLEAR_INT_FLAG(EMAC, u32eIntTypeFlag) ((EMAC)->INTSTS |= (u32eIntTypeFlag)) +#define EMAC_CLEAR_ALL_INT_FLAG(EMAC) ((EMAC)->INTSTS |= (EMAC)->INTSTS) + + +void EMAC_Open(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8MacAddr); +void EMAC_Close(EMAC_T *EMAC); +void EMAC_SetMacAddr(EMAC_T *EMAC, uint8_t *pu8MacAddr); +void EMAC_EnableCamEntry(EMAC_T *EMAC, uint32_t u32Entry, uint8_t pu8MacAddr[]); +void EMAC_DisableCamEntry(EMAC_T *EMAC, uint32_t u32Entry); + +uint32_t EMAC_RecvPkt(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t *pu32Size); +uint32_t EMAC_RecvPktTS(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t *pu32Size, uint32_t *pu32Sec, uint32_t *pu32Nsec); +void EMAC_RecvPktDone(EMAC_MEMMGR_T *psMemMgr); + +uint32_t EMAC_SendPkt(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t u32Size); +uint32_t EMAC_SendPktDone(EMAC_MEMMGR_T *psMemMgr); +uint32_t EMAC_SendPktDoneTS(EMAC_MEMMGR_T *psMemMgr, uint32_t *pu32Sec, uint32_t *pu32Nsec); + +void EMAC_EnableTS(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec); +void EMAC_DisableTS(EMAC_T *EMAC); +void EMAC_GetTime(EMAC_T *EMAC, uint32_t *pu32Sec, uint32_t *pu32Nsec); +void EMAC_SetTime(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec); +void EMAC_UpdateTime(EMAC_T *EMAC, uint32_t u32Neg, uint32_t u32Sec, uint32_t u32Nsec); +void EMAC_EnableAlarm(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec); +void EMAC_DisableAlarm(EMAC_T *EMAC); + +uint32_t EMAC_CheckLinkStatus(EMAC_T *EMAC); + +void EMAC_Reset(EMAC_T *EMAC); +void EMAC_PhyInit(EMAC_T *EMAC); +int32_t EMAC_FillCamEntry(EMAC_T *EMAC, uint8_t pu8MacAddr[]); +uint8_t *EMAC_ClaimFreeTXBuf(EMAC_MEMMGR_T *psMemMgr); +uint32_t EMAC_GetAvailRXBufSize(EMAC_MEMMGR_T *psMemMgr, uint8_t **ppuDataBuf); +uint32_t EMAC_SendPktWoCopy(EMAC_MEMMGR_T *psMemMgr, uint32_t u32Size); +void EMAC_RecvPktDoneWoRxTrigger(EMAC_MEMMGR_T *psMemMgr); + +/*@}*/ /* end of group EMAC_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group EMAC_Driver */ + +/*@}*/ /* end of group Standard_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif /* __NU_EMAC_H__ */ + +/*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_etimer.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_etimer.h new file mode 100644 index 0000000000000000000000000000000000000000..4176a1719b61a1bca0fffa12e5b1da55ab5362fe --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_etimer.h @@ -0,0 +1,717 @@ +/**************************************************************************//** + * @file etimer.h + * @brief N9H30 series ETIMER driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __NU_ETIMER_H__ +#define __NU_ETIMER_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "N9H30.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_ETIMER_Driver ETIMER Driver + @{ +*/ + +/** @addtogroup N9H30_ETIMER_EXPORTED_CONSTANTS ETIMER Exported Constants + @{ +*/ + +#define ETIMER_ONESHOT_MODE (0UL) /*!< Timer working in one shot mode */ +#define ETIMER_PERIODIC_MODE (1UL << 4) /*!< Timer working in periodic mode */ +#define ETIMER_TOGGLE_MODE (2UL << 4) /*!< Timer working in toggle mode */ +#define ETIMER_CONTINUOUS_MODE (3UL << 4) /*!< Timer working in continuous mode */ + +#define ETIMER_CAPTURE_FREE_COUNTING_MODE (0UL) /*!< Free counting mode */ +#define ETIMER_CAPTURE_TRIGGER_COUNTING_MODE (1UL << 20) /*!< Trigger counting mode */ +#define ETIMER_CAPTURE_COUNTER_RESET_MODE (1UL << 17) /*!< Counter reset mode */ + +#define ETIMER_CAPTURE_FALLING_EDGE (0UL) /*!< Falling edge trigger timer capture */ +#define ETIMER_CAPTURE_RISING_EDGE (1UL << 18) /*!< Rising edge trigger timer capture */ +#define ETIMER_CAPTURE_FALLING_THEN_RISING_EDGE (2UL << 18) /*!< Falling edge then rising edge trigger timer capture */ +#define ETIMER_CAPTURE_RISING_THEN_FALLING_EDGE (3UL << 18) /*!< Rising edge then falling edge trigger timer capture */ + +#define ETIMER_TIMEOUT_TRIGGER (0UL) /*!< Timer timeout trigger other modules */ +#define ETIMER_CAPTURE_TRIGGER (1UL << 11) /*!< Timer capture trigger other modules */ + +#define ETIMER_COUNTER_RISING_EDGE (1UL << 13) /*!< Counter increase on rising edge */ +#define ETIMER_COUNTER_FALLING_EDGE (0UL) /*!< Counter increase on falling edge */ + +/*@}*/ /* end of group ETIMER_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_ETIMER_EXPORTED_FUNCTIONS ETIMER Exported Functions + @{ +*/ + +/** + * @brief This macro is used to set new Timer compared value + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @param[in] u32Value Timer compare value. Valid values are between 2 to 0xFFFFFF + * @return None + * \hideinitializer + */ +#define ETIMER_SET_CMP_VALUE(timer, u32Value) \ + do{\ + if((timer) == 0) {\ + outpw(REG_ETMR0_CMPR, u32Value);\ + } else if((timer) == 1) {\ + outpw(REG_ETMR1_CMPR, u32Value);\ + } else if((timer) == 2) {\ + outpw(REG_ETMR2_CMPR, u32Value);\ + } else {\ + outpw(REG_ETMR3_CMPR, u32Value);\ + }\ + }while(0) + +/** + * @brief This macro is used to set new Timer prescale value + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @param[in] u32Value Timer prescale value. Valid values are between 0 to 0xFF + * @return None + * @note Clock input is divided by (prescale + 1) before it is fed into timer + * \hideinitializer + */ +#define ETIMER_SET_PRESCALE_VALUE(timer, u32Value) \ + do{\ + if((timer) == 0) {\ + outpw(REG_ETMR0_PRECNT, u32Value);\ + } else if((timer) == 1) {\ + outpw(REG_ETMR1_PRECNT, u32Value);\ + } else if((timer) == 2) {\ + outpw(REG_ETMR2_PRECNT, u32Value);\ + } else {\ + outpw(REG_ETMR3_PRECNT, u32Value);\ + }\ + }while(0) + +/** +* @brief Select Timer operating mode +* +* @param[in] timer The pointer of the specified Timer module. It could be TIMER0, TIMER1, TIMER2, TIMER3. +* @param[in] u32OpMode Operation mode. Possible options are +* - \ref ETIMER_ONESHOT_MODE +* - \ref ETIMER_PERIODIC_MODE +* - \ref ETIMER_TOGGLE_MODE +* - \ref ETIMER_CONTINUOUS_MODE +* +* @return None +* \hideinitializer +*/ +#define ETIMER_SET_OPMODE(timer, u32OpMode) \ + do{\ + if((timer) == 0) {\ + outpw(REG_ETMR0_CTL, (inpw(REG_ETMR0_CTL)&~0x30) | u32OpMode);\ + } else if((timer) == 1) {\ + outpw(REG_ETMR1_CTL, (inpw(REG_ETMR1_CTL)&~0x30) | u32OpMode);\ + } else if((timer) == 2) {\ + outpw(REG_ETMR2_CTL, (inpw(REG_ETMR2_CTL)&~0x30) | u32OpMode);\ + } else {\ + outpw(REG_ETMR3_CTL, (inpw(REG_ETMR3_CTL)&~0x30) | u32OpMode);\ + }\ + }while(0) + +/* + * @brief This macro is used to check if specify Timer is inactive or active + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return timer is activate or inactivate + * @retval 0 Timer 24-bit up counter is inactive + * @retval 1 Timer 24-bit up counter is active + * \hideinitializer + */ +static __inline int ETIMER_Is_Active(UINT timer) +{ + int reg; + + if (timer == 0) + { + reg = inpw(REG_ETMR0_CTL); + } + else if (timer == 1) + { + reg = inpw(REG_ETMR1_CTL); + } + else if (timer == 2) + { + reg = inpw(REG_ETMR2_CTL); + } + else + { + reg = inpw(REG_ETMR3_CTL); + } + return reg & 0x80 ? 1 : 0; +} + +/** + * @brief This function is used to start Timer counting + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_Start(UINT timer) +{ + + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) | 1); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) | 1); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) | 1); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) | 1); + } +} + +/** + * @brief This function is used to stop Timer counting + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_Stop(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) & ~1); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) & ~1); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) & ~1); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) & ~1); + } +} + +/** + * @brief This function is used to enable the Timer wake-up function + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + * @note To wake the system from power down mode, timer clock source must be ether LXT or LIRC + */ +static __inline void ETIMER_EnableWakeup(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) | 4); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) | 4); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) | 4); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) | 4); + } +} + +/** + * @brief This function is used to disable the Timer wake-up function + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_DisableWakeup(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) & ~4); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) & ~4); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) & ~4); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) & ~4); + } +} + + +/** + * @brief This function is used to enable the capture pin detection de-bounce function. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_EnableCaptureDebounce(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) | 0x400000); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) | 0x400000); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) | 0x400000); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) | 0x400000); + } +} + +/** + * @brief This function is used to disable the capture pin detection de-bounce function. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_DisableCaptureDebounce(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) & ~0x400000); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) & ~0x400000); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) & ~0x400000); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) & ~0x400000); + } +} + + +/** + * @brief This function is used to enable the Timer time-out interrupt function. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_EnableInt(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_IER, inpw(REG_ETMR0_IER) | 1); + } + else if (timer == 1) + { + outpw(REG_ETMR1_IER, inpw(REG_ETMR1_IER) | 1); + } + else if (timer == 2) + { + outpw(REG_ETMR2_IER, inpw(REG_ETMR2_IER) | 1); + } + else + { + outpw(REG_ETMR3_IER, inpw(REG_ETMR3_IER) | 1); + } +} + +/** + * @brief This function is used to disable the Timer time-out interrupt function. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_DisableInt(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_IER, inpw(REG_ETMR0_IER) & ~1); + } + else if (timer == 1) + { + outpw(REG_ETMR1_IER, inpw(REG_ETMR1_IER) & ~1); + } + else if (timer == 2) + { + outpw(REG_ETMR2_IER, inpw(REG_ETMR2_IER) & ~1); + } + else + { + outpw(REG_ETMR3_IER, inpw(REG_ETMR3_IER) & ~1); + } +} + +/** + * @brief This function is used to enable the Timer capture trigger interrupt function. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_EnableCaptureInt(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_IER, inpw(REG_ETMR0_IER) | 2); + } + else if (timer == 1) + { + outpw(REG_ETMR1_IER, inpw(REG_ETMR1_IER) | 2); + } + else if (timer == 2) + { + outpw(REG_ETMR2_IER, inpw(REG_ETMR2_IER) | 2); + } + else + { + outpw(REG_ETMR3_IER, inpw(REG_ETMR3_IER) | 2); + } +} + +/** + * @brief This function is used to disable the Timer capture trigger interrupt function. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_DisableCaptureInt(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_IER, inpw(REG_ETMR0_IER) & ~2); + } + else if (timer == 1) + { + outpw(REG_ETMR1_IER, inpw(REG_ETMR1_IER) & ~2); + } + else if (timer == 2) + { + outpw(REG_ETMR2_IER, inpw(REG_ETMR2_IER) & ~2); + } + else + { + outpw(REG_ETMR3_IER, inpw(REG_ETMR3_IER) & ~2); + } +} + +/** + * @brief This function indicates Timer time-out interrupt occurred or not. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return Timer time-out interrupt occurred or not + * @retval 0 Timer time-out interrupt did not occur + * @retval 1 Timer time-out interrupt occurred + */ +static __inline UINT ETIMER_GetIntFlag(UINT timer) +{ + int reg; + + if (timer == 0) + { + reg = inpw(REG_ETMR0_ISR); + } + else if (timer == 1) + { + reg = inpw(REG_ETMR1_ISR); + } + else if (timer == 2) + { + reg = inpw(REG_ETMR2_ISR); + } + else + { + reg = inpw(REG_ETMR3_ISR); + } + return reg & 1; +} + +/** + * @brief This function clears the Timer time-out interrupt flag. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_ClearIntFlag(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_ISR, 1); + } + else if (timer == 1) + { + outpw(REG_ETMR1_ISR, 1); + } + else if (timer == 2) + { + outpw(REG_ETMR2_ISR, 1); + } + else + { + outpw(REG_ETMR3_ISR, 1); + } +} + +/** + * @brief This function indicates Timer capture interrupt occurred or not. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return Timer capture interrupt occurred or not + * @retval 0 Timer capture interrupt did not occur + * @retval 1 Timer capture interrupt occurred + */ +static __inline UINT ETIMER_GetCaptureIntFlag(UINT timer) +{ + int reg; + + if (timer == 0) + { + reg = inpw(REG_ETMR0_ISR); + } + else if (timer == 1) + { + reg = inpw(REG_ETMR1_ISR); + } + else if (timer == 2) + { + reg = inpw(REG_ETMR2_ISR); + } + else + { + reg = inpw(REG_ETMR3_ISR); + } + return (reg & 2) >> 1; +} + +/** + * @brief This function clears the Timer capture interrupt flag. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_ClearCaptureIntFlag(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_ISR, 2); + } + else if (timer == 1) + { + outpw(REG_ETMR1_ISR, 2); + } + else if (timer == 2) + { + outpw(REG_ETMR2_ISR, 2); + } + else + { + outpw(REG_ETMR3_ISR, 2); + } +} + +/** +* @brief This function gets the Timer capture falling edge flag. +* @param[in] timer ETIMER number. Range from 0 ~ 5 +* @return None +*/ +static __inline UINT8 ETIMER_GetCaptureFallingEdgeFlag(UINT timer) +{ + UINT ret; + + if (timer == 0) + { + ret = inpw(REG_ETMR0_ISR); + } + else if (timer == 1) + { + ret = inpw(REG_ETMR1_ISR); + } + else if (timer == 2) + { + ret = inpw(REG_ETMR2_ISR); + } + else + { + ret = inpw(REG_ETMR3_ISR); + } + return (ret & (1 << 6)) >> 6; +} + +/* + * @brief This function indicates Timer has waked up system or not. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return Timer has waked up system or not + * @retval 0 Timer did not wake up system + * @retval 1 Timer wake up system + */ +static __inline UINT ETIMER_GetWakeupFlag(UINT timer) +{ + int reg; + + if (timer == 0) + { + reg = inpw(REG_ETMR0_ISR); + } + else if (timer == 1) + { + reg = inpw(REG_ETMR1_ISR); + } + else if (timer == 2) + { + reg = inpw(REG_ETMR2_ISR); + } + else + { + reg = inpw(REG_ETMR3_ISR); + } + return (reg & 0x10) >> 4; +} + +/** + * @brief This function clears the Timer wakeup interrupt flag. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +static __inline void ETIMER_ClearWakeupFlag(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_ISR, 0x10); + } + else if (timer == 1) + { + outpw(REG_ETMR1_ISR, 0x10); + } + else if (timer == 2) + { + outpw(REG_ETMR2_ISR, 0x10); + } + else + { + outpw(REG_ETMR3_ISR, 0x10); + } +} + +/** + * @brief This function gets the Timer compare value. + * @param[in] timer ETIMER number. Range from 0 ~ 5 + * @return Timer compare data value + */ +static __inline UINT ETIMER_GetCompareData(UINT timer) +{ + + if (timer == 0) + { + return inpw(REG_ETMR0_CMPR); + } + else if (timer == 1) + { + return inpw(REG_ETMR1_CMPR); + } + else if (timer == 2) + { + return inpw(REG_ETMR2_CMPR); + } + else + { + return inpw(REG_ETMR3_CMPR); + } +} + +/** + * @brief This function gets the Timer capture data. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return Timer capture data value + */ +static __inline UINT ETIMER_GetCaptureData(UINT timer) +{ + + if (timer == 0) + { + return inpw(REG_ETMR0_TCAP); + } + else if (timer == 1) + { + return inpw(REG_ETMR1_TCAP); + } + else if (timer == 2) + { + return inpw(REG_ETMR2_TCAP); + } + else + { + return inpw(REG_ETMR3_TCAP); + } +} + +/** + * @brief This function reports the current timer counter value. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return Timer counter value + */ +static __inline UINT ETIMER_GetCounter(UINT timer) +{ + if (timer == 0) + { + return inpw(REG_ETMR0_DR); + } + else if (timer == 1) + { + return inpw(REG_ETMR1_DR); + } + else if (timer == 2) + { + return inpw(REG_ETMR2_DR); + } + else + { + return inpw(REG_ETMR3_DR); + } +} + +static __inline UINT ETIMER_ClearCounter(UINT timer) +{ + if (timer == 0) + { + return outpw(REG_ETMR0_DR, 0); + } + else if (timer == 1) + { + return outpw(REG_ETMR1_DR, 0); + } + else if (timer == 2) + { + return outpw(REG_ETMR2_DR, 0); + } + else + { + return outpw(REG_ETMR3_DR, 0); + } +} +UINT ETIMER_Open(UINT timer, UINT u32Mode, UINT u32Freq); +void ETIMER_Close(UINT timer); +void ETIMER_Delay(UINT timer, UINT u32Usec); +void ETIMER_EnableCapture(UINT timer, UINT u32CapMode, UINT u32Edge); +void ETIMER_DisableCapture(UINT timer); +UINT ETIMER_GetModuleClock(UINT timer); + +/*@}*/ /* end of group N9H30_ETIMER_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_ETIMER_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_ETIMER_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_fmi.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_fmi.h new file mode 100644 index 0000000000000000000000000000000000000000..a0b85078fcb6c5b620b78210f692fc357998bdea --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_fmi.h @@ -0,0 +1,315 @@ +/**************************************************************************//** + * @file fmi.h + * @brief N9H30 FMI eMMC driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include + +#ifndef __NU_FMI_H__ +#define __NU_FMI_H__ + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_FMI_Driver FMI Driver + @{ +*/ + + +/** @addtogroup N9H30_FMI_EXPORTED_CONSTANTS FMI Exported Constants + @{ +*/ + +/** + @addtogroup FMI_CONST FMI Bit Field Definition + Constant Definitions for FMI Controller +@{ */ + +#define FMI_DMACTL_DMAEN_Pos (0) /*!< FMI DMACTL: DMAEN Position */ +#define FMI_DMACTL_DMAEN_Msk (0x1ul << FMI_DMACTL_DMAEN_Pos) /*!< FMI DMACTL: DMAEN Mask */ + +#define FMI_DMACTL_DMARST_Pos (1) /*!< FMI DMACTL: DMARST Position */ +#define FMI_DMACTL_DMARST_Msk (0x1ul << FMI_DMACTL_DMARST_Pos) /*!< FMI DMACTL: DMARST Mask */ + +#define FMI_DMACTL_SGEN_Pos (3) /*!< FMI DMACTL: SGEN Position */ +#define FMI_DMACTL_SGEN_Msk (0x1ul << FMI_DMACTL_SGEN_Pos) /*!< FMI DMACTL: SGEN Mask */ + +#define FMI_DMACTL_DMABUSY_Pos (9) /*!< FMI DMACTL: DMABUSY Position */ +#define FMI_DMACTL_DMABUSY_Msk (0x1ul << FMI_DMACTL_DMABUSY_Pos) /*!< FMI DMACTL: DMABUSY Mask */ + +#define FMI_DMASA_ORDER_Pos (0) /*!< FMI DMASA: ORDER Position */ +#define FMI_DMASA_ORDER_Msk (0x1ul << FMI_DMASA_ORDER_Pos) /*!< FMI DMASA: ORDER Mask */ + +#define FMI_DMASA_DMASA_Pos (1) /*!< FMI DMASA: DMASA Position */ +#define FMI_DMASA_DMASA_Msk (0x7ffffffful << FMI_DMASA_DMASA_Pos) /*!< FMI DMASA: DMASA Mask */ + +#define FMI_DMABCNT_BCNT_Pos (0) /*!< FMI DMABCNT: BCNT Position */ +#define FMI_DMABCNT_BCNT_Msk (0x3fffffful << FMI_DMABCNT_BCNT_Pos) /*!< FMI DMABCNT: BCNT Mask */ + +#define FMI_DMAINTEN_ABORTIEN_Pos (0) /*!< FMI DMAINTEN: ABORTIEN Position */ +#define FMI_DMAINTEN_ABORTIEN_Msk (0x1ul << FMI_DMAINTEN_ABORTIEN_Pos) /*!< FMI DMAINTEN: ABORTIEN Mask */ + +#define FMI_DMAINTEN_WEOTIEN_Pos (1) /*!< FMI DMAINTEN: WEOTIEN Position */ +#define FMI_DMAINTEN_WEOTIEN_Msk (0x1ul << FMI_DMAINTEN_WEOTIEN_Pos) /*!< FMI DMAINTEN: WEOTIEN Mask */ + +#define FMI_DMAINTSTS_ABORTIF_Pos (0) /*!< FMI DMAINTSTS: ABORTIF Position */ +#define FMI_DMAINTSTS_ABORTIF_Msk (0x1ul << FMI_DMAINTSTS_ABORTIF_Pos) /*!< FMI DMAINTSTS: ABORTIF Mask */ + +#define FMI_DMAINTSTS_WEOTIF_Pos (1) /*!< FMI DMAINTSTS: WEOTIF Position */ +#define FMI_DMAINTSTS_WEOTIF_Msk (0x1ul << FMI_DMAINTSTS_WEOTIF_Pos) /*!< FMI DMAINTSTS: WEOTIF Mask */ + +#define FMI_CTL_CTLRST_Pos (0) /*!< FMI CTL: CTLRST Position */ +#define FMI_CTL_CTLRST_Msk (0x1ul << FMI_CTL_CTLRST_Pos) /*!< FMI CTL: CTLRST Mask */ + +#define FMI_CTL_EMMCEN_Pos (1) /*!< FMI CTL: EMMCEN Position */ +#define FMI_CTL_EMMCEN_Msk (0x1ul << FMI_CTL_EMMCEN_Pos) /*!< FMI CTL: EMMCEN Mask */ + +#define FMI_CTL_NANDEN_Pos (1) /*!< FMI CTL: NANDEN Position */ +#define FMI_CTL_NANDEN_Msk (0x1ul << FMI_CTL_NANDEN_Pos) /*!< FMI CTL: NANDEN Mask */ + +#define FMI_INTEN_DTAIEN_Pos (0) /*!< FMI INTEN: DTAIEN Position */ +#define FMI_INTEN_DTAIEN_Msk (0x1ul << FMI_INTEN_DTAIEN_Pos) /*!< FMI INTEN: DTAIEN Mask */ + +#define FMI_INTSTS_DTAIF_Pos (0) /*!< FMI INTSTS: DTAIF Position */ +#define FMI_INTSTS_DTAIF_Msk (0x1ul << FMI_INTSTS_DTAIF_Pos) /*!< FMI INTSTS: DTAIF Mask */ + +#define FMI_EMMCCTL_COEN_Pos (0) /*!< FMI EMMCCTL: COEN Position */ +#define FMI_EMMCCTL_COEN_Msk (0x1ul << FMI_EMMCCTL_COEN_Pos) /*!< FMI EMMCCTL: COEN Mask */ + +#define FMI_EMMCCTL_RIEN_Pos (1) /*!< FMI EMMCCTL: RIEN Position */ +#define FMI_EMMCCTL_RIEN_Msk (0x1ul << FMI_EMMCCTL_RIEN_Pos) /*!< FMI EMMCCTL: RIEN Mask */ + +#define FMI_EMMCCTL_DIEN_Pos (2) /*!< FMI EMMCCTL: DIEN Position */ +#define FMI_EMMCCTL_DIEN_Msk (0x1ul << FMI_EMMCCTL_DIEN_Pos) /*!< FMI EMMCCTL: DIEN Mask */ + +#define FMI_EMMCCTL_DOEN_Pos (3) /*!< FMI EMMCCTL: DOEN Position */ +#define FMI_EMMCCTL_DOEN_Msk (0x1ul << FMI_EMMCCTL_DOEN_Pos) /*!< FMI EMMCCTL: DOEN Mask */ + +#define FMI_EMMCCTL_R2EN_Pos (4) /*!< FMI EMMCCTL: R2EN Position */ +#define FMI_EMMCCTL_R2EN_Msk (0x1ul << FMI_EMMCCTL_R2EN_Pos) /*!< FMI EMMCCTL: R2EN Mask */ + +#define FMI_EMMCCTL_CLK74OEN_Pos (5) /*!< FMI EMMCCTL: CLK74OEN Position */ +#define FMI_EMMCCTL_CLK74OEN_Msk (0x1ul << FMI_EMMCCTL_CLK74OEN_Pos) /*!< FMI EMMCCTL: CLK74OEN Mask */ + +#define FMI_EMMCCTL_CLK8OEN_Pos (6) /*!< FMI EMMCCTL: CLK8OEN Position */ +#define FMI_EMMCCTL_CLK8OEN_Msk (0x1ul << FMI_EMMCCTL_CLK8OEN_Pos) /*!< FMI EMMCCTL: CLK8OEN Mask */ + +#define FMI_EMMCCTL_CLKKEEP0_Pos (7) /*!< FMI EMMCCTL: CLKKEEP0 Position */ +#define FMI_EMMCCTL_CLKKEEP0_Msk (0x1ul << FMI_EMMCCTL_CLKKEEP0_Pos) /*!< FMI EMMCCTL: CLKKEEP0 Mask */ + +#define FMI_EMMCCTL_CMDCODE_Pos (8) /*!< FMI EMMCCTL: CMDCODE Position */ +#define FMI_EMMCCTL_CMDCODE_Msk (0x3ful << FMI_EMMCCTL_CMDCODE_Pos) /*!< FMI EMMCCTL: CMDCODE Mask */ + +#define FMI_EMMCCTL_CTLRST_Pos (14) /*!< FMI EMMCCTL: CTLRST Position */ +#define FMI_EMMCCTL_CTLRST_Msk (0x1ul << FMI_EMMCCTL_CTLRST_Pos) /*!< FMI EMMCCTL: CTLRST Mask */ + +#define FMI_EMMCCTL_DBW_Pos (15) /*!< FMI EMMCCTL: DBW Position */ +#define FMI_EMMCCTL_DBW_Msk (0x1ul << FMI_EMMCCTL_DBW_Pos) /*!< FMI EMMCCTL: DBW Mask */ + +#define FMI_EMMCCTL_BLKCNT_Pos (16) /*!< FMI EMMCCTL: BLKCNT Position */ +#define FMI_EMMCCTL_BLKCNT_Msk (0xfful << FMI_EMMCCTL_BLKCNT_Pos) /*!< FMI EMMCCTL: BLKCNT Mask */ + +#define FMI_EMMCCTL_SDNWR_Pos (24) /*!< FMI EMMCCTL: SDNWR Position */ +#define FMI_EMMCCTL_SDNWR_Msk (0xful << FMI_EMMCCTL_SDNWR_Pos) /*!< FMI EMMCCTL: SDNWR Mask */ + +#define FMI_EMMCCMD_ARGUMENT_Pos (0) /*!< FMI EMMCCMD: ARGUMENT Position */ +#define FMI_EMMCCMD_ARGUMENT_Msk (0xfffffffful << FMI_EMMCCMD_ARGUMENT_Pos) /*!< FMI EMMCCMD: ARGUMENT Mask */ + +#define FMI_EMMCINTEN_BLKDIEN_Pos (0) /*!< FMI EMMCINTEN: BLKDIEN Position */ +#define FMI_EMMCINTEN_BLKDIEN_Msk (0x1ul << FMI_EMMCINTEN_BLKDIEN_Pos) /*!< FMI EMMCINTEN: BLKDIEN Mask */ + +#define FMI_EMMCINTEN_CRCIEN_Pos (1) /*!< FMI EMMCINTEN: CRCIEN Position */ +#define FMI_EMMCINTEN_CRCIEN_Msk (0x1ul << FMI_EMMCINTEN_CRCIEN_Pos) /*!< FMI EMMCINTEN: CRCIEN Mask */ + +#define FMI_EMMCINTEN_RTOIEN_Pos (12) /*!< FMI EMMCINTEN: RTOIEN Position */ +#define FMI_EMMCINTEN_RTOIEN_Msk (0x1ul << FMI_EMMCINTEN_RTOIEN_Pos) /*!< FMI EMMCINTEN: RTOIEN Mask */ + +#define FMI_EMMCINTEN_DITOIEN_Pos (13) /*!< FMI EMMCINTEN: DITOIEN Position */ +#define FMI_EMMCINTEN_DITOIEN_Msk (0x1ul << FMI_EMMCINTEN_DITOIEN_Pos) /*!< FMI EMMCINTEN: DITOIEN Mask */ + +#define FMI_EMMCINTSTS_BLKDIF_Pos (0) /*!< FMI EMMCINTSTS: BLKDIF Position */ +#define FMI_EMMCINTSTS_BLKDIF_Msk (0x1ul << FMI_EMMCINTSTS_BLKDIF_Pos) /*!< FMI EMMCINTSTS: BLKDIF Mask */ + +#define FMI_EMMCINTSTS_CRCIF_Pos (1) /*!< FMI EMMCINTSTS: CRCIF Position */ +#define FMI_EMMCINTSTS_CRCIF_Msk (0x1ul << FMI_EMMCINTSTS_CRCIF_Pos) /*!< FMI EMMCINTSTS: CRCIF Mask */ + +#define FMI_EMMCINTSTS_CRC7_Pos (2) /*!< FMI EMMCINTSTS: CRC7 Position */ +#define FMI_EMMCINTSTS_CRC7_Msk (0x1ul << FMI_EMMCINTSTS_CRC7_Pos) /*!< FMI EMMCINTSTS: CRC7 Mask */ + +#define FMI_EMMCINTSTS_CRC16_Pos (3) /*!< FMI EMMCINTSTS: CRC16 Position */ +#define FMI_EMMCINTSTS_CRC16_Msk (0x1ul << FMI_EMMCINTSTS_CRC16_Pos) /*!< FMI EMMCINTSTS: CRC16 Mask */ + +#define FMI_EMMCINTSTS_CRCSTS_Pos (4) /*!< FMI EMMCINTSTS: CRCSTS Position */ +#define FMI_EMMCINTSTS_CRCSTS_Msk (0x7ul << FMI_EMMCINTSTS_CRCSTS_Pos) /*!< FMI EMMCINTSTS: CRCSTS Mask */ + +#define FMI_EMMCINTSTS_DAT0STS_Pos (7) /*!< FMI EMMCINTSTS: DAT0STS Position */ +#define FMI_EMMCINTSTS_DAT0STS_Msk (0x1ul << FMI_EMMCINTSTS_DAT0STS_Pos) /*!< FMI EMMCINTSTS: DAT0STS Mask */ + +#define FMI_EMMCINTSTS_RTOIF_Pos (12) /*!< FMI EMMCINTSTS: RTOIF Position */ +#define FMI_EMMCINTSTS_RTOIF_Msk (0x1ul << FMI_EMMCINTSTS_RTOIF_Pos) /*!< FMI EMMCINTSTS: RTOIF Mask */ + +#define FMI_EMMCINTSTS_DINTOIF_Pos (13) /*!< FMI EMMCINTSTS: DINTOIF Position */ +#define FMI_EMMCINTSTS_DINTOIF_Msk (0x1ul << FMI_EMMCINTSTS_DINTOIF_Pos) /*!< FMI EMMCINTSTS: DINTOIF Mask */ + +#define FMI_EMMCRESP0_RESPTK0_Pos (0) /*!< FMI EMMCRESP0: RESPTK0 Position */ +#define FMI_EMMCRESP0_RESPTK0_Msk (0xfffffffful << FMI_EMMCRESP0_RESPTK0_Pos) /*!< FMI EMMCRESP0: RESPTK0 Mask */ + +#define FMI_EMMCRESP1_RESPTK1_Pos (0) /*!< FMI EMMCRESP1: RESPTK1 Position */ +#define FMI_EMMCRESP1_RESPTK1_Msk (0xfful << FMI_EMMCRESP1_RESPTK1_Pos) /*!< FMI EMMCRESP1: RESPTK1 Mask */ + +#define FMI_EMMCBLEN_BLKLEN_Pos (0) /*!< FMI EMMCBLEN: BLKLEN Position */ +#define FMI_EMMCBLEN_BLKLEN_Msk (0x7fful << FMI_EMMCBLEN_BLKLEN_Pos) /*!< FMI EMMCBLEN: BLKLEN Mask */ + +#define FMI_EMMCTOUT_TOUT_Pos (0) /*!< FMI EMMCTOUT: TOUT Position */ +#define FMI_EMMCTOUT_TOUT_Msk (0xfffffful << FMI_EMMCTOUT_TOUT_Pos) /*!< FMI EMMCTOUT: TOUT Mask */ + +/**@}*/ /* FMI_CONST */ + +//--- define type of SD card or MMC +#define EMMC_TYPE_UNKNOWN 0 /*!< Card Type - Unknoen \hideinitializer */ +#define EMMC_TYPE_SD_HIGH 1 /*!< Card Type - SDH \hideinitializer */ +#define EMMC_TYPE_SD_LOW 2 /*!< Card Type - SD \hideinitializer */ +#define EMMC_TYPE_MMC 3 /*!< Card Type - MMC \hideinitializer */ +#define EMMC_TYPE_EMMC 4 /*!< Card Type - eMMC \hideinitializer */ + +#define EMMC_ERR_ID 0xFFFF0180 /*!< FMI Error ID \hideinitializer */ +#define EMMC_TIMEOUT (EMMC_ERR_ID|0x01) /*!< FMI Error - Timeout \hideinitializer */ +#define EMMC_NO_MEMORY (EMMC_ERR_ID|0x02) /*!< FMI Error - No Memory \hideinitializer */ +/* EMMC error */ +#define EMMC_NO_CARD (EMMC_ERR_ID|0x10) /*!< FMI Error - No card \hideinitializer */ +#define EMMC_ERR_DEVICE (EMMC_ERR_ID|0x11) /*!< FMI Error - device err \hideinitializer */ +#define EMMC_INIT_TIMEOUT (EMMC_ERR_ID|0x12) /*!< FMI Error - init timeout \hideinitializer */ +#define EMMC_SELECT_ERROR (EMMC_ERR_ID|0x13) /*!< FMI Error - select err \hideinitializer */ +#define EMMC_WRITE_PROTECT (EMMC_ERR_ID|0x14) /*!< FMI Error - write protect \hideinitializer */ +#define EMMC_INIT_ERROR (EMMC_ERR_ID|0x15) /*!< FMI Error - init err \hideinitializer */ +#define EMMC_CRC7_ERROR (EMMC_ERR_ID|0x16) /*!< FMI Error - crc7 err \hideinitializer */ +#define EMMC_CRC16_ERROR (EMMC_ERR_ID|0x17) /*!< FMI Error - crc16 err \hideinitializer */ +#define EMMC_CRC_ERROR (EMMC_ERR_ID|0x18) /*!< FMI Error - crc err \hideinitializer */ +#define EMMC_CMD8_ERROR (EMMC_ERR_ID|0x19) /*!< FMI Error - CMD8 err \hideinitializer */ + +#define SD_FREQ 25000 /*!< Unit: kHz. Output 25MHz to SD \hideinitializer */ +#define SDHC_FREQ 50000 /*!< Unit: kHz. Output 50MHz to SDH \hideinitializer */ +#define MMC_FREQ 20000 /*!< Unit: kHz. Output 20MHz to MMC \hideinitializer */ +#define EMMC_FREQ 26000 /*!< Unit: kHz. Output 26MHz to eMMC \hideinitializer */ + +/*@}*/ /* end of group N9H30_FMI_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_FMI_EXPORTED_TYPEDEF FMI Exported Type Defines + @{ +*/ +/** \brief Structure type of Card information. + */ +typedef struct eMMC_info_t +{ + unsigned int CardType; /*!< SDHC, SD, or MMC */ + unsigned int RCA; /*!< relative card address */ + unsigned char IsCardInsert; /*!< card insert state */ + unsigned int totalSectorN; /*!< total sector number */ + unsigned int diskSize; /*!< disk size in Kbytes */ + int sectorSize; /*!< sector size in bytes */ +} EMMC_INFO_T; + +/*@}*/ /* end of group N9H30_FMI_EXPORTED_TYPEDEF */ + +/// @cond HIDDEN_SYMBOLS +extern EMMC_INFO_T eMMC; +extern unsigned char volatile _fmi_eMMCDataReady; + +/// @endcond HIDDEN_SYMBOLS + +/** @addtogroup N9H30_FMI_EXPORTED_FUNCTIONS FMI Exported Functions + @{ +*/ + + +/** + * @brief Enable specified interrupt. + * + * @param[in] u32IntMask Interrupt type mask: + * \ref FMI_EMMCINTEN_BLKDIEN_Msk / \ref FMI_EMMCINTEN_CRCIEN_Msk / + * \ref FMI_EMMCINTEN_RTOIEN_Msk / \ref FMI_EMMCINTEN_DITOIEN_Msk / + * + * @return None. + * \hideinitializer + */ +#define FMI_EMMC_ENABLE_INT(u32IntMask) (outpw(REG_FMI_EMMCINTEN, inpw(REG_FMI_EMMCINTEN)|(u32IntMask))) + +/** + * @brief Disable specified interrupt. + * + * @param[in] u32IntMask Interrupt type mask: + * \ref FMI_EMMCINTEN_BLKDIEN_Msk / \ref FMI_EMMCINTEN_CRCIEN_Msk / + * \ref FMI_EMMCINTEN_RTOIEN_Msk / \ref FMI_EMMCINTEN_DITOIEN_Msk / + * + * @return None. + * \hideinitializer + */ +#define FMI_EMMC_DISABLE_INT(u32IntMask) (outpw(REG_FMI_EMMCINTEN, inpw(REG_FMI_EMMCINTEN) & ~(u32IntMask))) + +/** + * @brief Get specified interrupt flag/status. + * + * @param[in] u32IntMask Interrupt type mask: + * \ref FMI_EMMCINTSTS_BLKDIF_Msk / \ref FMI_EMMCINTSTS_CRCIF_Msk / \ref FMI_EMMCINTSTS_CRC7_Msk / + * \ref FMI_EMMCINTSTS_CRC16_Msk / \ref FMI_EMMCINTSTS_CRCSTS_Msk / \ref FMI_EMMCINTSTS_DAT0STS_Msk / + * \ref FMI_EMMCINTSTS_RTOIF_Msk / \ref FMI_EMMCINTSTS_DINTOIF_Msk / + * + * @return 0 = The specified interrupt is not happened. + * 1 = The specified interrupt is happened. + * \hideinitializer + */ +#define FMI_EMMC_GET_INT_FLAG(u32IntMask) ((inpw(REG_FMI_EMMCINTSTS)&(u32IntMask))?1:0) + + +/** + * @brief Clear specified interrupt flag/status. + * + * @param[in] u32IntMask Interrupt type mask: + * \ref FMI_EMMCINTSTS_BLKDIF_Msk / \ref FMI_EMMCINTSTS_CRCIF_Msk / + * \ref FMI_EMMCINTSTS_RTOIF_Msk / \ref FMI_EMMCINTSTS_DINTOIF_Msk + * + * @return None. + * \hideinitializer + */ +#define FMI_EMMC_CLR_INT_FLAG(u32IntMask) (outpw(REG_FMI_EMMCINTSTS, u32IntMask)) + + +/** + * @brief Check eMMC Card inserted or removed. + * + * @return 1: Card inserted. + * 0: Card removed. + * \hideinitializer + */ +#define FMI_EMMC_IS_CARD_PRESENT() (eMMC.IsCardInsert) + +/** + * @brief Get eMMC Card capacity. + * + * @return eMMC Card capacity. (unit: KByte) + * \hideinitializer + */ +#define FMI_EMMC_GET_CARD_CAPACITY() (eMMC.diskSize) + + +void eMMC_Open(void); +void eMMC_Probe(void); +unsigned int eMMC_Read(unsigned char *pu8BufAddr, unsigned int u32StartSec, unsigned int u32SecCount); +unsigned int eMMC_Write(unsigned char *pu8BufAddr, unsigned int u32StartSec, unsigned int u32SecCount); +void FMI_SetReferenceClock(unsigned int u32Clock); +void eMMC_Open_Disk(void); +void eMMC_Close_Disk(void); + + +/*@}*/ /* end of group N9H30_FMI_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_FMI_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#endif //end of __NU_FMI_H__ +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_gpio.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..f644ab122973474146b539f54f8f43ce02c16dbf --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_gpio.h @@ -0,0 +1,162 @@ +/**************************************************************************//** +* @file gpio.h +* @version V1.00 +* @brief N9H30 GPIO driver header file +* +* SPDX-License-Identifier: Apache-2.0 +* @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_GPIO_H__ +#define __NU_GPIO_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_GPIO_Driver GPIO Driver + @{ +*/ + +/** @addtogroup N9H30_GPIO_EXPORTED_CONSTANTS GPIO Exported Constants + @{ +*/ + +/*---------------------------------------------------------------------------------------------------------*/ +/* MODE Constant Definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +/// @cond HIDDEN_SYMBOLS +#ifndef GPIO_ERR_PORT_BUSY +#define GPIO_ERR_PORT_BUSY -1 +#define GPIO_ERR_UNSUPPORTED -2 +#define GPIO_ERR_BIT_BUSY -3 +#define SUCCESSFUL 0 +#endif +/// @endcond HIDDEN_SYMBOLS + +#define MAX_PORT 10 /*!< GPIO Port Number */ + +#define GPIOA_MASK 0x0000FFFF /*!< GPIO Port A Mask */ +#define GPIOB_MASK 0x0000FFFF /*!< GPIO Port B Mask */ +#define GPIOC_MASK 0x00007FFF /*!< GPIO Port C Mask */ +#define GPIOD_MASK 0x0000FFFF /*!< GPIO Port D Mask */ +#define GPIOE_MASK 0x0000FFFF /*!< GPIO Port E Mask */ +#define GPIOF_MASK 0x0000FFFF /*!< GPIO Port F Mask */ +#define GPIOG_MASK 0x0000FFFF /*!< GPIO Port G Mask */ +#define GPIOH_MASK 0x0000FFFF /*!< GPIO Port H Mask */ +#define GPIOI_MASK 0x0000FFFF /*!< GPIO Port I Mask */ +#define GPIOJ_MASK 0x0000003F /*!< GPIO Port J Mask */ + +/// @cond HIDDEN_SYMBOLS +typedef INT32(*GPIO_CALLBACK)(UINT32 status, UINT32 userData); +typedef INT32(*EINT_CALLBACK)(UINT32 status, UINT32 userData); +/// @endcond HIDDEN_SYMBOLS + +/** \brief Structure type of GPIO_PORT + */ +typedef enum +{ + GPIOA = 0x000, /*!< Port A offset of GPIO base address */ + GPIOB = 0x040, /*!< Port B offset of GPIO base address */ + GPIOC = 0x080, /*!< Port C offset of GPIO base address */ + GPIOD = 0x0C0, /*!< Port D offset of GPIO base address */ + GPIOE = 0x100, /*!< Port E offset of GPIO base address */ + GPIOF = 0x140, /*!< Port F offset of GPIO base address */ + GPIOG = 0x180, /*!< Port G offset of GPIO base address */ + GPIOH = 0x1C0, /*!< Port H offset of GPIO base address */ + GPIOI = 0x200, /*!< Port I offset of GPIO base address */ + GPIOJ = 0x240, /*!< Port J offset of GPIO base address */ +} GPIO_PORT; + +/** \brief Structure type of GPIO_DIR + */ +typedef enum +{ + DIR_INPUT, /*!< GPIO Output mode */ + DIR_OUTPUT /*!< GPIO Input mode */ +} GPIO_DIR; + +/** \brief Structure type of GPIO_PULL + */ +typedef enum +{ + NO_PULL_UP, /*!< GPIO Pull-Up Disable */ + PULL_UP, /*!< GPIO Pull-Up Enable */ + PULL_DOWN /*!< GPIO Pull-Down Enable */ +} GPIO_PULL; + +/** \brief Structure type of GPIO_DRV + */ +typedef enum +{ + DRV_LOW, /*!< GPIO Set to Low */ + DRV_HIGH /*!< GPIO Set to High */ +} GPIO_DRV; + +/** \brief Structure type of GPIO_NIRQ + */ +typedef enum +{ + NIRQ0 = 0, /*!< External interrupt 0 */ + NIRQ1, /*!< External interrupt 1 */ + NIRQ2, /*!< External interrupt 2 */ + NIRQ3, /*!< External interrupt 3 */ + NIRQ4, /*!< External interrupt 4 */ + NIRQ5, /*!< External interrupt 5 */ + NIRQ6, /*!< External interrupt 6 */ + NIRQ7, /*!< External interrupt 7 */ +} GPIO_NIRQ; + +/** \brief Structure type of GPIO_TRIGGER_TYPE + */ +typedef enum +{ + LOW, /*!< Trigger type set low */ + HIGH, /*!< Trigger type set high */ + FALLING, /*!< Trigger type set falling edge */ + RISING, /*!< Trigger type set rising edge */ + BOTH_EDGE /*!< Trigger type set falling edge and rising edge */ +} GPIO_TRIGGER_TYPE; + +/// @cond HIDDEN_SYMBOLS +/// @endcond HIDDEN_SYMBOLS + +/*@}*/ /* end of group N9H30_GPIO_EXPORTED_CONSTANTS */ + + +/** @addtogroup N9H30_GPIO_EXPORTED_FUNCTIONS GPIO Exported Functions + @{ +*/ + +/* General GPIO bit function */ +INT32 GPIO_OpenBit(GPIO_PORT port, UINT32 bit, GPIO_DIR direction, GPIO_PULL pull); +INT32 GPIO_CloseBit(GPIO_PORT port, UINT32 bit); +INT32 GPIO_SetBit(GPIO_PORT port, UINT32 bit); +INT32 GPIO_ClrBit(GPIO_PORT port, UINT32 bit); +INT32 GPIO_ReadBit(GPIO_PORT port, UINT32 bit); +INT32 GPIO_SetBitDir(GPIO_PORT port, UINT32 bit, GPIO_DIR direction); +INT32 GPIO_EnableTriggerType(GPIO_PORT port, UINT32 bit, GPIO_TRIGGER_TYPE triggerType); +INT32 GPIO_DisableTriggerType(GPIO_PORT port, UINT32 bit); + +/* External GPIO interrupt function */ +INT32 GPIO_EnableDebounce(INT32 debounceClkSel); +INT32 GPIO_DisableDebounce(void); + +/*@}*/ /* end of group N9H30_GPIO_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_GPIO_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_GPIO_H__ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_i2c.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..ece04bfa83d29e7b07ac6330b289b9f2b18bbd97 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_i2c.h @@ -0,0 +1,105 @@ +/**************************************************************************//** +* @file i2c.h +* @brief N9H30 I2C driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_I2C_H__ +#define __NU_I2C_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_I2C_Driver I2C Driver + @{ +*/ + +/** @addtogroup N9H30_I2C_EXPORTED_CONSTANTS I2C Exported Constants + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +/*-----------------------------------------*/ +/* marco, type and constant definitions */ +/*-----------------------------------------*/ +#define I2C_MAX_BUF_LEN 450 + +/*-----------------------------------------*/ +/* global interface variables declarations */ +/*-----------------------------------------*/ +/* + bit map in CMDR +*/ +#define I2C_CMD_START 0x10 +#define I2C_CMD_STOP 0x08 +#define I2C_CMD_READ 0x04 +#define I2C_CMD_WRITE 0x02 +#define I2C_CMD_NACK 0x01 + +/* + for transfer use +*/ +#define I2C_WRITE 0x00 +#define I2C_READ 0x01 + +#define I2C_STATE_NOP 0x00 +#define I2C_STATE_READ 0x01 +#define I2C_STATE_WRITE 0x02 +#define I2C_STATE_PROBE 0x03 + +/* + i2c register offset +*/ +#define I2C_CSR (0x00) /*!< Control and Status Register */ +#define I2C_DIVIDER (0x04) /*!< Clock Prescale Register */ +#define I2C_CMDR (0x08) /*!< Command Register */ +#define I2C_SWR (0x0C) /*!< Software Mode Control Register */ +#define I2C_RxR (0x10) /*!< Data Receive Register */ +#define I2C_TxR (0x14) /*!< Data Transmit Register */ + +/// @endcond HIDDEN_SYMBOLS + +/* + ioctl commands +*/ +#define I2C_IOC_SET_DEV_ADDRESS 0 /*!< Set device slave address */ +#define I2C_IOC_SET_SUB_ADDRESS 1 /*!< Set sub address */ +#define I2C_IOC_SET_SPEED 2 /*!< Set I2C interface speed */ + +/* + error code +*/ +#define I2C_ERR_ID 0xFFFF1100 /*!< I2C library ID */ +#define I2C_ERR_NOERROR (0x00) /*!< No error */ +#define I2C_ERR_LOSTARBITRATION (0x01 | I2C_ERR_ID) /*!< Arbitration lost error */ +#define I2C_ERR_BUSBUSY (0x02 | I2C_ERR_ID) /*!< Bus busy error */ +#define I2C_ERR_NACK (0x03 | I2C_ERR_ID) /*!< data transfer error */ +#define I2C_ERR_SLAVENACK (0x04 | I2C_ERR_ID) /*!< slave not respond after address */ +#define I2C_ERR_NODEV (0x05 | I2C_ERR_ID) /*!< Wrong device */ +#define I2C_ERR_BUSY (0x06 | I2C_ERR_ID) /*!< Device busy */ +#define I2C_ERR_IO (0x07 | I2C_ERR_ID) /*!< Interface not open */ +#define I2C_ERR_NOTTY (0x08 | I2C_ERR_ID) /*!< Command not support */ + +/*@}*/ /* end of group N9H30_I2C_EXPORTED_CONSTANTS */ + +/*@}*/ /* end of group N9H30_I2C_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_I2C_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_i2s.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_i2s.h new file mode 100644 index 0000000000000000000000000000000000000000..e7ee11de217e7a61e978b1f5b6817861d1670663 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_i2s.h @@ -0,0 +1,130 @@ +/**************************************************************************//** +* @file i2s.h +* @brief N9H30 I2S driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_I2S_H__ +#define __NU_I2S_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_I2S_Driver I2S Driver + @{ +*/ + +/** @addtogroup N9H30_I2S_EXPORTED_CONSTANTS I2S Exported Constants + @{ +*/ + +#define I2S_ERR_BUSY -1 /*!< Interface is busy */ +#define I2S_ERR_IO -2 /*!< IO contril error */ + +#define I2S_DISABLE 0 /*!< Enable I2S */ +#define I2S_ENABLE 1 /*!< Disable I2S */ + +#define I2S_PLAY 0 /*!< Play I2S audio */ +#define I2S_REC 1 /*!< Reocrd I2S audio */ + +#define PCM_PLAY 0 /*!< Play PCM audio */ +#define PCM_REC 1 /*!< Record PCM audio */ + +#define I2S_SET_PLAY 0 /*!< Start or stop to play */ +#define I2S_START_PLAY 0 /*!< Start to play */ +#define I2S_STOP_PLAY 1 /*!< Stop to play */ + +#define I2S_SET_RECORD 1 /*!< Start or stop to record */ +#define I2S_START_REC 0 /*!< Start to record */ +#define I2S_STOP_REC 1 /*!< Stop to record */ + +#define I2S_SELECT_BLOCK 2 /*!< Select block function */ +#define I2S_BLOCK_I2S 0 /*!< Select I2S function */ +#define I2S_BLOCK_PCM 1 /*!< Select PCM function */ + +#define I2S_SELECT_BIT 3 /*!< Select data bit width */ +#define I2S_BIT_WIDTH_8 0 /*!< 8-bit */ +#define I2S_BIT_WIDTH_16 1 /*!< 16-bit */ +#define I2S_BIT_WIDTH_24 2 /*!< 24-bit */ + +#define I2S_SET_PLAY_DMA_INT_SEL 4 /*!< Select play DMA interrupt request */ +#define I2S_SET_REC_DMA_INT_SEL 5 /*!< Select record DMA interrupt request */ +#define I2S_DMA_INT_END 0 /*!< End of buffer */ +#define I2S_DMA_INT_HALF 1 /*!< Half of buffer */ +#define I2S_DMA_INT_QUARTER 2 /*!< Quarter of buffer */ +#define I2S_DMA_INT_EIGHTH 3 /*!< Eighth of buffer */ + +#define I2S_SET_ZEROCROSS 6 /*!< Enable or disable zero cross function */ +#define I2S_SET_DMACOUNTER 7 /*!< Enable or disable DMA counter function */ + +#define I2S_SET_CHANNEL 8 /*!< Set channel number */ +#define I2S_CHANNEL_P_I2S_ONE 2 /*!< I2S one channel */ +#define I2S_CHANNEL_P_I2S_TWO 3 /*!< I2S two channels */ +#define I2S_CHANNEL_P_PCM_TWO 3 /*!< PCM two slots */ +#define I2S_CHANNEL_P_PCM_TWO_SLOT1 0 /*!< PCM two slots with all slot1 data */ +#define I2S_CHANNEL_P_PCM_TWO_SLOT0 1 /*!< PCM two slots with all slot0 data */ +#define I2S_CHANNEL_P_PCM_ONE_SLOT0 2 /*!< PCM one slot with all slot0 data */ + +#define I2S_CHANNEL_R_I2S_LEFT_PCM_SLOT0 1 /*!< I2S left channel or PCM slot0 */ +#define I2S_CHANNEL_R_I2S_RIGHT_PCM_SLOT1 2 /*!< I2S right channel or PCM slot1 */ +#define I2S_CHANNEL_R_I2S_TWO 3 /*!< I2S two channels */ + +#define I2S_SET_MODE 9 /*!< Select master or slave mode */ +#define I2S_MODE_MASTER 0 /*!< master mode */ +#define I2S_MODE_SLAVE 1 /*!< slave mode */ + +#define I2S_SET_SPLITDATA 10 /*!< Enable or disable split data function */ +#define I2S_SET_DMA_ADDRESS 11 /*!< Set DMA address */ +#define I2S_SET_DMA_LENGTH 12 /*!< Set DMA length */ +#define I2S_GET_DMA_CUR_ADDRESS 13 /*!< Get current DMA address */ + +#define I2S_SET_I2S_FORMAT 14 /*!< Select I2S format */ +#define I2S_FORMAT_I2S 0 /*!< I2S format */ +#define I2S_FORMAT_MSB 1 /*!< MSB foramt */ + +#define I2S_SET_I2S_CALLBACKFUN 15 /*!< Install play or record call-back function */ + +#define I2S_SET_PCMSLOT 16 /*!< Set PCM interface start position of slot */ +#define PCM_SLOT1_IN 0 /*!< Slot-1 in position */ +#define PCM_SLOT1_OUT 1 /*!< Slot-1 out position */ +#define PCM_SLOT2_IN 2 /*!< Slot-2 in position */ +#define PCM_SLOT2_OUT 3 /*!< Slot-2 out position */ + +#define I2S_SET_PCM_FS_PERIOD 17 /*!< Set PCM FS pulse period */ + +/*@}*/ /* end of group N9H30_I2S_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_I2S_EXPORTED_FUNCTIONS I2S Exported Functions + @{ +*/ + +int32_t i2sOpen(void); +void i2sClose(void); +void i2sInit(void); +int32_t i2sIoctl(uint32_t cmd, uint32_t arg0, uint32_t arg1); +void i2sSetSampleRate(uint32_t u32SourceClockRate, uint32_t u32SampleRate, uint32_t u32DataBit, uint32_t u32Channel); +void i2sSetMCLKFrequency(uint32_t u32SourceClockRate, uint32_t u32SampleRate); +void i2sSetPCMBCLKFrequency(uint32_t u32SourceClockRate, uint32_t u32Rate); + +/*@}*/ /* end of group N9H30_I2S_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_I2S_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_I2S_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_jpeg.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_jpeg.h new file mode 100644 index 0000000000000000000000000000000000000000..4dcb153d4139a895a0df86fcc10d9b35f7184f94 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_jpeg.h @@ -0,0 +1,398 @@ +/**************************************************************************//** +* @file jpeg.h +* @brief N9H30 JPEG driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_JPEG_H__ +#define __NU_JPEG_H__ + +#include "nu_jpegcodec.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_JPEG_Driver JPEG Driver + @{ +*/ + +/** @addtogroup N9H30_JPEG_EXPORTED_CONSTANTS JPEG Exported Constants + @{ +*/ + + +/// @cond HIDDEN_SYMBOLS +// Define bits mask +#define NVTBIT(start,end) ((0xFFFFFFFFUL >> (31 - start)) & (0xFFFFFFFFUL >>end << end)) +/// @endcond HIDDEN_SYMBOLS + + +//JMCR +#define RESUMEI BIT9 /*!< Resume JPEG Operation for Input On-the-Fly Mode */ +#define RESUMEO BIT8 /*!< Resume JPEG Operation for Output On-the-Fly Mode */ +#define ENC_DEC BIT7 /*!< JPEG Encode/Decode Mode */ +#define WIN_DEC BIT6 /*!< JPEG Window Decode Mode */ +#define PRI BIT5 /*!< Encode Primary Image */ +#define THB BIT4 /*!< Encode Thumbnail Image */ +#define EY422 BIT3 /*!< Encode Image Format */ +#define QT_BUSY BIT2 /*!< Quantization-Table Busy Status (Read-Only) */ +#define ENG_RST BIT1 /*!< Soft Reset JPEG Engine (Except JPEG Control Registers) */ +#define JPG_EN BIT0 /*!< JPEG Engine Operation Control */ + +//JHEADER +#define P_JFIF BIT7 /*!< Primary JPEG Bit-stream Include JFIF Header */ +#define P_HTAB BIT6 /*!< Primary JPEG Bit-stream Include Huffman-Table */ +#define P_QTAB BIT5 /*!< Primary JPEG Bit-stream Include Quantization-Table */ +#define P_DRI BIT4 /*!< Primary JPEG Bit-stream Include Restart Interval */ +#define T_JFIF BIT3 /*!< Thumbnail JPEG Bit-stream Include JFIF Header */ +#define T_HTAB BIT2 /*!< Thumbnail JPEG Bit-stream Include Huffman-Table */ +#define T_QTAB BIT1 /*!< Thumbnail JPEG Bit-stream Include Quantization-Table */ +#define T_DRI BIT0 /*!< Thumbnail JPEG Bit-stream Include Restart Interval */ + +//JITCR +#define Dec_Scatter_Gather BIT18 +#define DEC_OTF BIT17 /*!< Decoder on the fly with VPE */ +#define ARGB8888 BIT16 /*!< ARGB8888 */ +#define PLANAR_ON BIT15 /*!< Packet On */ +#define ORDER BIT14 /*!< Decode Packet Data Order */ +#define RGB_555_565 BIT13 /*!< RGB555 & RGB565 */ +#define ROTATE NVTBIT(12,11) /*!< Encode Image Rotate */ +#define DYUV_MODE NVTBIT(10,8) /*!< Decoded Image YUV Color Format (Read-Only) */ +#define EXIF BIT7 /*!< Encode Quantization-Table & Huffman-Table Header Format Selection */ +#define EY_ONLY BIT6 /*!< Encode Gray-level (Y-component Only) Image */ +#define DHEND BIT5 /*!< Header Decode Complete Stop Enable */ +#define DTHB BIT4 /*!< Decode Thumbnail Image Only */ +#define E3QTAB BIT3 /*!< Numbers of Quantization-Table are Used For Encode */ +#define D3QTAB BIT2 /*!< Numbers of Quantization-Table are Used For Decode (Read-Only) */ +#define ERR_DIS BIT1 /*!< Decode Error Engine Abort */ +#define PDHTAB BIT0 /*!< Programmable Huffman-Table Function For Decode */ + +//JPRIQC +#define P_QADJUST NVTBIT(7,4) /*!< Primary Quantization-Table Adjustment */ +#define P_QVS NVTBIT(3,0) /*!< Primary Quantization-Table Scaling Control */ + +//JTHBQC +#define T_QADJUST NVTBIT(7,4) /*!< Thumbnail Quantization-Table Adjustment */ +#define T_QVS NVTBIT(3,0) /*!< Thumbnail Quantization-Table Scaling Control */ + +//JPRIWH +#define P_HEIGHT NVTBIT(27,16) /*!< Primary Encode Image Height */ +#define P_WIDTH NVTBIT(11,0) /*!< Primary Encode Image Width */ + +//JTHBWH +#define T_HEIGHT NVTBIT(27,16) /*!< Thumbnail Encode Image Height */ +#define T_WIDTH NVTBIT(11,0) /*!< Thumbnail Encode Image Width */ + +//JPRST +#define P_RST NVTBIT(7,0) /*!< Primary Encode Restart Interval Value */ + +//JTRST +#define T_RST NVTBIT(7,0) /*!< Thumbnail Encode Restart Interval Value */ + +//JDECWH +#define DEC_HEIGHT NVTBIT(31,16) /*!< 13-bit Bit Stream Buffer threshold */ +#define DEC_WIDTH NVTBIT(15,0) /*!< 13-bit Header Offset Address */ + +//JINTCR +#define JPG_DOW_INTE BIT28 /*!< Decoding Output Wait Interrupt Enable */ +#define JPG_DOW_INTS BIT24 /*!< Status of Decoding Output Wait */ +#define JPG_WAITI BIT23 /*!< JPEG Input Wait Status (Read-Only) */ +#define JPG_WAITO BIT22 /*!< JPEG Output Wait Status (Read-Only) */ +#define BAbort BIT16 /*!< JPEG Memory Access Error Status (Read-Only) */ +#define CER_INTE BIT15 /*!< Un-complete Capture On-The-Fly Frame Occur Interrupt Enable */ +#define DHE_INTE BIT14 /*!< JPEG Header Decode End Wait Interrupt Enable */ +#define IPW_INTE BIT13 /*!< Input Wait Interrupt Enable */ +#define OPW_INTE BIT12 /*!< Output Wait Interrupt Enable */ +#define ENC_INTE BIT11 /*!< Encode Complete Interrupt Enable */ +#define DEC_INTE BIT10 /*!< Decode Complete Interrupt Enable */ +#define DER_INTE BIT9 /*!< Decode Error Interrupt Enable */ +#define EER_INTE BIT8 /*!< Encode (On-The-Fly) Error Interrupt Enable */ +#define CER_INTS BIT7 /*!< Un-complete Capture On-The-Fly Frame Occur Interrupt Status */ +#define DHE_INTS BIT6 /*!< JPEG Header Decode End Wait Interrupt Status */ +#define IPW_INTS BIT5 /*!< Input Wait Interrupt Status */ +#define OPW_INTS BIT4 /*!< Output Wait Interrupt Status */ +#define ENC_INTS BIT3 /*!< Encode Complete Interrupt Status */ +#define DEC_INTS BIT2 /*!< Decode Complete Interrupt Status */ +#define DER_INTS BIT1 /*!< Decode Error Interrupt Status */ +#define EER_INTS BIT0 /*!< Encode (On-The-Fly) Error Interrupt Status */ + +//JPEG_BSBAD +#define BIST_ST NVTBIT(23,16) /*!< Internal SRAM BIST Status (Read-Only) */ +#define TEST_DOUT NVTBIT(15,8) /*!< Test Data Output (Read-Only) */ +#define TEST_ON BIT7 /*!< Test Enable */ +#define BIST_ON BIT6 /*!< Internal SRAM BIST Mode Enable */ +#define BIST_FINI BIT5 /*!< Internal SRAM BIST Mode Finish (Read-Only) */ +#define BSBAD_BIST_FAIL BIT4 /*!< Internal SRAM BIST Mode Fail (Read-Only) */ +#define TEST_SEL NVTBIT(3,0) /*!< Test Data Selection */ + +//JWINDEC0 +#define MCU_S_Y NVTBIT(24,16) /*!< MCU Start Position Y For Window Decode Mode */ +#define MCU_S_X NVTBIT(8,0) /*!< MCU Start Position X For Window Decode Mode */ + +//JWINDEC1 +#define MCU_E_Y NVTBIT(24,16) /*!< MCU End Position Y For Window Decode Mode */ +#define MCU_E_X NVTBIT(8,0) /*!< MCU End Position X For Window Decode Mode */ + +//JWINDEC2 +#define WD_WIDTH NVTBIT(11,0)) /*!< Image Width (Y-Stride) For Window Decode Mode */ + +//JMACR +#define FLY_SEL NVTBIT(29,24) /*!< Hardware Memory On-the-Fly Access Image Buffer-Size Selection for Encode */ +#define FLY_TYPE NVTBIT(23,22) /*!< Dual/Single buffer on-the fly */ +#define BSF_SEL NVTBIT(17,8) /*!< Memory On-the-Fly Access Bitstream Buffer-Size Selection */ +#define FLY_ON BIT7 /*!< Hardware Memory On-the-Fly Access Mode */ +#define IP_SF_ON BIT3 /*!< Software Memory On-the-Fly Access Mode for Data Input */ +#define OP_SF_ON BIT2 /*!< Software Memory On-the-Fly Access Mode for Data Output */ +#define ENC_MODE NVTBIT(1,0) /*!< JPEG Memory Address Mode Control */ + +//JPSCALU +#define JPSCALU_8X BIT6 /*!< Primary Image Up-Scaling For Encode */ +#define A_JUMP BIT2 /*!< Reserve Buffer Size In JPEG Bit-stream For Software Application */ + +//JPSCALD +#define PSX_ON BIT15 /*!< Primary Image Horizontal Down-Scaling For Encode/Decode */ +#define PS_LPF_ON BIT14 /*!< Primary Image Down-Scaling Low Pass Filter For Decode */ +#define PSCALX_F NVTBIT(12,8) /*!< Primary Image Horizontal Down-Scaling Factor */ +#define PSCALY_F NVTBIT(5,0) /*!< Primary Image Vertical Down-Scaling Factor */ + +//JTSCALD +#define TSX_ON BIT15 /*!< Thumbnail Image Horizontal Down-Scaling For Encode/Decode */ +#define TSCALX_F NVTBIT(14,8) /*!< Thumbnail Image Horizontal Down-Scaling Factor */ +#define TSCALY_F NVTBIT(7,0) /*!< Thumbnail Image Vertical Down-Scaling Factor */ + +//JDBCR +#define DBF_EN BIT7 /*!< Dual Buffering Control */ +#define IP_BUF BIT4 /*!< Input Dual Buffer Control */ + +//JRESERVE +#define RES_SIZE NVTBIT(15,0) /*!< Primary Encode Bit-stream Reserved Size */ + +//JOFFSET +#define OFFSET_SIZE NVTBIT(23,0) /*!< Primary/Thumbnail Starting Address Offset Size */ + +//JFSTRIDE +#define F_STRIDE NVTBIT(23,0) /*!< JPEG Encode Bit-stream Frame Stride */ + +//JYADDR0 +#define Y_IADDR0 NVTBIT(31,0) /*!< JPEG Y Component Frame Buffer-0 Starting Address */ + +//JUADDR0 +#define U_IADDR0 NVTBIT(31,0) /*!< JPEG U Component Frame Buffer-0 Starting Address */ + +//JVADDR0 +#define V_IADDR0 NVTBIT(31,0) /*!< JPEG V Component Frame Buffer-0 Starting Address */ + +//JYADDR1 +#define Y_IADDR1 NVTBIT(31,0) /*!< JPEG Y Component Frame Buffer-1 Starting Address */ + +//JUADDR1 +#define U_IADDR1 NVTBIT(31,0) /*!< JPEG U Component Frame Buffer-1 Starting Address */ + +//JVADDR1 +#define V_IADDR1 NVTBIT(31,0) /*!< JPEG V Component Frame Buffer-1 Starting Address */ + +//JYSTRIDE +#define Y_STRIDE NVTBIT(11,0) /*!< JPEG Y Component Frame Buffer Stride */ + +//JUSTRIDE +#define U_STRIDE NVTBIT(11,0) /*!< JPEG U Component Frame Buffer Stride */ + +//JVSTRIDE +#define V_STRIDE NVTBIT(11,0) /*!< JPEG V Component Frame Buffer Stride */ + +//JIOADDR0 +#define IO_IADDR0 NVTBIT(31,0) /*!< JPEG Bit-stream Frame Buffer-0 Starting Address */ + +//JIOADDR1 +#define IO_IADDR1 NVTBIT(31,0) /*!< JPEG Bit-stream Frame Buffer-1 Starting Address */ + +//JPRI_SIZE +#define PRI_SIZE NVTBIT(23,0) /*!< JPEG Primary Image Encode Bit-stream Size */ + +//JTHB_SIZE +#define THB_SIZE NVTBIT(15,0) /*!< JPEG Thumbnail Image Encode Bit-stream Size */ + +//JUPRAT +#define S_HEIGHT NVTBIT(29,16) /*!< JPEG Image Height Up-Scale Ratio */ +#define S_WIDTH NVTBIT(13,0) /*!< JPEG Image Width Up-Scale Ratio */ + +//JBSFIFO +#define BSFIFO_HT NVTBIT(6,4) /*!< Bit-stream FIFO High-Threshold Control */ +#define BSFIFO_LT NVTBIT(2,0) /*!< Bit-stream FIFO Low-Threshold Control */ + +//JSRCH +#define JSRCH_JSRCH NVTBIT(11,0) /*!< JPEG Encode Source Image Height */ + +/*@}*/ /* end of group N9H30_JPEG_EXPORTED_CONSTANTS */ + +/// @cond HIDDEN_SYMBOLS + +//Define for Interrupt Status +#define JPEG_EER_INTS EER_INTS +#define JPEG_DER_INTS DER_INTS +#define JPEG_DEC_INTS DEC_INTS +#define JPEG_ENC_INTS ENC_INTS +#define JPEG_DHE_INTS DHE_INTS +#define JPEG_IPW_INTS IPW_INTS + +//Define for Scaling +#define JPEG_ENC_UPSCALE_MODE 0 +#define JPEG_DEC_PACKET_DOWNSCALE_MODE 1 +#define JPEG_DEC_PLANAR_DOWNSCALE_MODE 2 +#define JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE 3 +#define JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE 4 + +//Define for Interrupt Enable +#define JPEG_EER_INTE ERR_INTE +#define JPEG_DER_INTE DER_INTE +#define JPEG_DEC_INTE DEC_INTE +#define JPEG_ENC_INTE ENC_INTE +#define JPEG_DHE_INTE DHE_INTE +#define JPEG_IPW_INTE IPW_INTE + +//Register +#define REG_JMCR JMCR /*!< JPEG Mode Control Register */ +#define REG_JHEADER JHEADER /*!< JPEG Encode Header Control Register */ +#define REG_JITCR JITCR /*!< JPEG Image Type Control Register */ +#define REG_JPRIQC JPRIQC /*!< JPEG Primary Q-Table Control Register */ +#define REG_JTHBQC JTHBQC /*!< JPEG Thumbnail Q-Table Control Register */ +#define REG_JPRIWH JPRIWH /*!< JPEG Encode Primary Width/Height Register */ +#define REG_JTHBWH JTHBWH /*!< JPEG Encode Thumbnail Width/Height Register */ +#define REG_JPRST JPRST /*!< JPEG Encode Primary Restart Interval Register */ +#define REG_JTRST JTRST /*!< JPEG Encode Thumbnail Restart Interval */ +#define REG_JDECWH JDECWH /*!< JPEG Decode Image Width/Height Register */ +#define REG_JINTCR JINTCR /*!< JPEG Interrupt Control and Status Register */ +#define REG_JTEST JTEST /*!< JPEG Test Control Register */ +#define REG_JWINDEC0 JWINDEC0 /*!< JPEG Window Decode Mode Control Register 0 */ +#define REG_JWINDEC1 JWINDEC1 /*!< JPEG Window Decode Mode Control Register 1 */ +#define REG_JWINDEC2 JWINDEC2 /*!< JPEG Window Decode Mode Control Register 2 */ +#define REG_JMACR JMACR /*!< JPEG Memory Address Mode Control Register */ +#define REG_JPSCALU JPSCALU /*!< JPEG Primary Scaling-Up Control Register */ +#define REG_JPSCALD JPSCALD /*!< JPEG Primary Scaling-Down Control Register */ +#define REG_JTSCALD JTSCALD /*!< JPEG Thumbnail Scaling-Down Control Register */ +#define REG_JDBCR JDBCR /*!< JPEG Dual-Buffer Control Register */ +#define REG_JRESERVE JRESERVE /*!< JPEG Encode Primary Bit-stream Reserved Size Register */ +#define REG_JOFFSET JOFFSET /*!< JPEG Offset Between Primary & Thumbnail Register */ +#define REG_JFSTRIDE JFSTRIDE /*!< JPEG Encode Bit-stream Frame Stride Register */ +#define REG_JYADDR0 JYADDR0 /*!< JPEG Y Component Frame Buffer-0 Starting Address Register */ +#define REG_JUADDR0 JUADDR0 /*!< JPEG U Component Frame Buffer-0 Starting Address Register */ +#define REG_JVADDR0 JVADDR0 /*!< JPEG V Component Frame Buffer-0 Starting Address Register */ +#define REG_JYADDR1 JYADDR1 /*!< JPEG Y Component Frame Buffer-1 Starting Address Register */ +#define REG_JUADDR1 JUADDR1 /*!< JPEG U Component Frame Buffer-1 Starting Address Register */ +#define REG_JVADDR1 JVADDR1 /*!< JPEG V Component Frame Buffer-1 Starting Address Register */ +#define REG_JYSTRIDE JYSTRIDE /*!< JPEG Y Component Frame Buffer Stride Register */ +#define REG_JUSTRIDE JUSTRIDE /*!< JPEG U Component Frame Buffer Stride Register */ +#define REG_JVSTRIDE JVSTRIDE /*!< JPEG V Component Frame Buffer Stride Register */ +#define REG_JIOADDR0 JIOADDR0 /*!< JPEG Bit-stream Frame Buffer-0 Starting Address Register */ +#define REG_JIOADDR1 JIOADDR1 /*!< JPEG Bit-stream Frame Buffer-1 Starting Address Register */ +#define REG_JPRI_SIZE JPRI_SIZE /*!< JPEG Encode Primary Image Bit-stream Size Register */ +#define REG_JTHB_SIZE JTHB_SIZE /*!< JPEG Encode Thumbnail Image Bit-stream Size Register */ +#define REG_JUPRAT JUPRAT /*!< JPEG Encode Up-Scale Ratio Register */ +#define REG_JBSFIFO JBSFIFO /*!< JPEG Bit-stream FIFO Control Register */ +#define REG_JSRCH JSRCH /*!< JPEG Encode Source Image Height */ +#define REG_JQTAB0 JQTAB0 /*!< JPEG Quantization-Table 0 Register */ +#define REG_JQTAB1 JQTAB1 /*!< JPEG Quantization-Table 1 Register */ +#define REG_JQTAB2 JQTAB2 /*!< JPEG Quantization-Table 2 Register */ + +//Export functions +#define JPEG_SET_YADDR(u32Address) outp32(REG_JYADDR0, u32Address) +#define JPEG_SET_UADDR(u32Address) outp32(REG_JUADDR0, u32Address) +#define JPEG_SET_VADDR(u32Address) outp32(REG_JVADDR0, u32Address) +#define JPEG_GET_YADDR() inp32(REG_JYADDR0) +#define JPEG_GET_UADDR() inp32(REG_JUADDR0) +#define JPEG_GET_VADDR() inp32(REG_JVADDR0) +#define JPEG_SET_YSTRIDE(u32Stride) outp32(REG_JYSTRIDE, u32Stride) +#define JPEG_SET_USTRIDE(u32Stride) outp32(REG_JUSTRIDE, u32Stride) +#define JPEG_SET_VSTRIDE(u32Stride) outp32(REG_JVSTRIDE, u32Stride) +#define JPEG_GET_YSTRIDE() inp32(REG_JYSTRIDE) +#define JPEG_GET_USTRIDE() inp32(REG_JUSTRIDE) +#define JPEG_GET_VSTRIDE() inp32(REG_JVSTRIDE) +#define JPEG_SET_BITSTREAM_ADDR(u32Address) outp32(REG_JIOADDR0,u32Address) +#define JPEG_GET_BITSTREAM_ADDR() inp32(REG_JIOADDR0) +#define JPEG_SET_ENC_DEC(u8Mode) outp32(REG_JMCR, (inp32(REG_JMCR) & ~ENC_DEC) | (u8Mode << 7)); + +//Encode +#define JPEG_GET_ENC_PRIMARY_BITSTREAM_SIZE() inp32(REG_JPRI_SIZE) +#define JPEG_GET_ENC_THUMBNAIL_BITSTREAM_SIZE() inp32(REG_JTHB_SIZE) +#define JPEG_SET_SOURCE_IMAGE_HEIGHT(u16Size) outp32(REG_JSRCH,u16Size) +#define JPEG_GET_SOURCE_IMAGE_HEIGHT() inp32(REG_JSRCH) +#define JPEG_ENC_ENABLE_UPSCALING() outp32(REG_JPSCALU,inp32(REG_JPSCALU) | JPSCALU_8X) +#define JPEG_ENC_DISABLE_UPSCALING() outp32(REG_JPSCALU,inp32(REG_JPSCALU) & ~JPSCALU_8X) +#define JPEG_ENC_ISENABLE_UPSCALING() ((inp32(REG_JPSCALU) & JPSCALU_8X) >> 6) +#define JPEG_ENC_SET_HEADER_CONTROL(u8Control) outp32(REG_JHEADER, u8Control) +#define JPEG_ENC_GET_HEADER_CONTROL() inp32(REG_JHEADER) +#define JPEG_ENC_SET_RDI_VALUE(u8Value) outp32(REG_JPRST,u8Value) +#define JPEG_ENC_GET_RDI_VALUE() inp32(REG_JPRST) + +//Decode +#define JPEG_DEC_ENABLE_DOWNSCALING() outp32(REG_JPSCALD, PSX_ON) +#define JPEG_DEC_ISENABLE_DOWNSCALING() ((inp32(REG_JPSCALD) & PSX_ON) >> 15) +#define JPEG_DEC_DISABLE_DOWNSCALING() outp32(REG_JPSCALD,~PSX_ON) +#define JPEG_DEC_GET_DECODED_IMAGE_FORMAT() (inp32(REG_JITCR) & DYUV_MODE) +#define JPEG_DEC_ENABLE_LOW_PASS_FILTER() outp32(REG_JPSCALD,inp32(REG_JPSCALD) | PS_LPF_ON) +#define JPEG_DEC_DISABLE_LOW_PASS_FILTER() outp32(REG_JPSCALD,inp32(REG_JPSCALD) & ~PS_LPF_ON) +#define JPEG_DEC_ISENABLE_LOW_PASS_FILTER() ((inp32(REG_JPSCALD) & PS_LPF_ON) >> 14) +#define JPEG_DEC_SET_INPUT_WAIT(u16Size) outp32(REG_JMACR, 0x00400008 | ((u16Size & 0x3FF)<< 8) ); +#define JPEG_DEC_RESUME_INPUT_WAIT() outp32(REG_JMCR,inp32(REG_JMCR) | RESUMEI); +#define JPEG_DEC_DISABLE_WINDOWDECODE() outp32(REG_JMCR, inp32(REG_JMCR) & ~(WIN_DEC)); + +//Interrupt +#define JPEG_INT_ENABLE(u32Intflag) outp32(REG_JINTCR, u32Intflag) +#define JPEG_INT_DISABLE(u32Intflag) outp32(REG_JINTCR, inp32 (REG_JINTCR) & ~(u32Intflag)) +#define JPEG_GET_INT_STATUS() (inp32(REG_JINTCR) & 0x010000FF) +#define JPEG_CLEAR_INT(u32Intflag) outp32(REG_JINTCR, (inp32 (REG_JINTCR) & ~0xFF) | u32Intflag) + +static INT jpegSetEncodeMode(UINT8 u8SourceFormat, UINT16 u16JpegFormat); +static INT jpegSetDecodeMode(UINT32 u8OutputFormat); +static BOOL jpegPollInt(UINT32 u32Intflag); +static VOID jpegEncodeTrigger(void); +static VOID jpegDecodeTrigger(void); +static VOID jpegGetDecodedDimension( + PUINT16 pu16Height, //Decode/Encode Height + PUINT16 pu16Width //Decode/Encode Width +); +static VOID jpegSetDimension( + UINT16 u16Height, //Decode/Encode Height + UINT16 u16Width //Decode/Encode Width +); +static VOID jpegGetDimension( + PUINT16 pu16Height, //Decoded Height from bit stream + PUINT16 pu16Width //Decoded Width from bit stream +); +static INT jpegSetWindowDecode( + UINT16 u16StartMCUX, //Start X MCU + UINT16 u16StartMCUY, //Horizontal Scaling Factor + UINT16 u16EndMCUX, //Vertical Scaling Factor + UINT16 u16EndMCUY, //Horizontal Scaling Factor + UINT32 u32Stride //Decode Output Stride +); +static INT jpegCalScalingFactor( + UINT8 u8Mode, //Up / Down Scaling + UINT16 u16Height, //Original Height + UINT16 u16Width, //Original Width + UINT16 u16ScalingHeight, //Scaled Height + UINT16 u16ScalingWidth, //Scaled Width + PUINT16 pu16RatioH, //Horizontal Ratio + PUINT16 pu16RatioW //Vertical Ratio +); +static INT jpegSetScalingFactor( + UINT8 u8Mode, //Up / Down Scaling + UINT16 u16FactorH, //Vertical Scaling Factor + UINT16 u16FactorW //Horizontal Scaling Factor +); +static VOID jpegGetScalingFactor( + UINT8 u8Mode, //Up / Down Scaling + PUINT16 pu16FactorH, //Vertical Scaling Factor + PUINT16 pu16FactorW //Horizontal Scaling Factor +); +/// @endcond HIDDEN_SYMBOLS + +/*@}*/ /* end of group N9H30_JPEG_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_jpegcodec.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_jpegcodec.h new file mode 100644 index 0000000000000000000000000000000000000000..c18e6ba9ba7fe4e3f09c671e98e35a266d1d2b36 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_jpegcodec.h @@ -0,0 +1,227 @@ +/**************************************************************************//** +* @file jpegcodec.h +* @brief N9H30 JPEG driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_JPEGCODEC_H__ +#define __NU_JPEGCODEC_H__ + +//Include header file +#include "N9H30.h" +#include "nu_sys.h" + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_JPEG_Driver JPEG Driver + @{ +*/ + + +/** @addtogroup N9H30_JPEG_EXPORTED_CONSTANTS JPEG Exported Constants + @{ +*/ + +#define E_FAIL 0 /*!< JPEG function Error */ +#define E_SUCCESS 1 /*!< JPEG function Success */ +#define E_JPEG_INVALID_PARAM 2 /*!< Input invalid paramater */ +#define E_JPEG_TIMEOUT 3 /*!< JPEG function Time-out */ + + +#define JPEG_ENC_PRIMARY 0 /*!< JPEG encode Primary */ +#define JPEG_ENC_THUMBNAIL 1 /*!< JPEG encode Thumbanil */ + +//Define for Encode input Format +#define JPEG_ENC_SOURCE_PLANAR 0 /*!< JPEG encode input formate is Planar */ +#define JPEG_ENC_SOURCE_PACKET 1 /*!< JPEG encode input formate is Packet */ + +//Define for Decode Output Format + +//(PLANAR_ON | PDHTAB | DHEND) +#define JPEG_DEC_PRIMARY_PLANAR_YUV 0x8021 /*!< JPEG decode output Primary Planar YUV */ +//(PDHTAB | DHEND) +#define JPEG_DEC_PRIMARY_PACKET_YUV422 0x0021 /*!< JPEG decode output Primary Packet YUV422 */ + +//(PDHTAB | DHEND | ORDER) +#define JPEG_DEC_PRIMARY_PACKET_RGB555 0x04021 /*!< JPEG decode output Primary Packet RGB555 */ +//(PDHTAB | DHEND | RGB555_565 | ORDER ) +#define JPEG_DEC_PRIMARY_PACKET_RGB565 0x06021 /*!< JPEG decode output Primary Packet RGB565 */ + +//(PDHTAB | DHEND | ORDER) +#define JPEG_DEC_PRIMARY_PACKET_RGB555R1 0x404021 /*!< JPEG decode output Primary Packet RGB555R1 */ +//(PDHTAB | DHEND | RGB555_565 | ORDER ) +#define JPEG_DEC_PRIMARY_PACKET_RGB565R1 0x406021 /*!< JPEG decode output Primary Packet RGB565R1 */ + +#define JPEG_DEC_PRIMARY_PACKET_RGB565R2 0x806021 /*!< JPEG decode output Primary Packet RGB565R2 */ +//(PDHTAB | DHEND | ORDER) +#define JPEG_DEC_PRIMARY_PACKET_RGB555R2 0x804021 /*!< JPEG decode output Primary Packet RGB555R2 */ + +//(PDHTAB | DHEND | RGB555_565 | ORDER ) +#define JPEG_DEC_PRIMARY_PACKET_RGB888 0x14021 /*!< JPEG decode Primary Packet RGB888 */ +//(PLANAR_ON | DTHB | PDHTAB) +#define JPEG_DEC_THUMBNAIL_PLANAR_YUV 0x8031 /*!< JPEG decode Thumbnail Planar YUV */ +//(DTHB | PDHTAB | DHEND) +#define JPEG_DEC_THUMBNAIL_PACKET_YUV422 0x0031 /*!< JPEG decode Thumbnail Packet YUV422 */ +//(DTHB | PDHTAB | DHEND | ORDER) +#define JPEG_DEC_THUMBNAIL_PACKET_RGB555 0x4031 /*!< JPEG decode Thumbnail Packet RGB555 */ + +//Define for Encode Image Format +#define JPEG_ENC_PRIMARY_YUV420 0xA0 /*!< JPEG encode Primary YUV420 */ +#define JPEG_ENC_PRIMARY_YUV422 0xA8 /*!< JPEG encode Primary YUV422 */ +#define JPEG_ENC_PRIMARY_GRAY 0xA1 /*!< JPEG encode Primary Gray */ +#define JPEG_ENC_THUMBNAIL_YUV420 0x90 /*!< JPEG encode Thumbnail YUV420 */ +#define JPEG_ENC_THUMBNAIL_YUV422 0x98 /*!< JPEG encode Thumbnail YUV422 */ +#define JPEG_ENC_THUMBNAIL_GRAY 0x91 /*!< JPEG encode Thumbnail Gray */ + +//Define for Decode Image Format +#define JPEG_DEC_YUV420 0x000 /*!< JPEG decode image formatr is YUV420 */ +#define JPEG_DEC_YUV422 0x100 /*!< JPEG decode image formatr is YUV422 */ +#define JPEG_DEC_YUV444 0x200 /*!< JPEG decode image formatr is YUV444 */ +#define JPEG_DEC_YUV411 0x300 /*!< JPEG decode image formatr is YUV411 */ +#define JPEG_DEC_GRAY 0x400 /*!< JPEG decode image formatr is Gray */ +#define JPEG_DEC_YUV422T 0x500 /*!< JPEG decode image formatr is YUV422T */ + +//Define for Encode Image Header +/*P_DRI*/ +#define JPEG_ENC_PRIMARY_DRI 0x10 /*!< JPEG encode image header Primary DRI */ +/*P_QTAB*/ +#define JPEG_ENC_PRIMARY_QTAB 0x20 /*!< JPEG encode image header Primary Q Table */ +/*P_HTAB*/ +#define JPEG_ENC_PRIMARY_HTAB 0x40 /*!< JPEG encode image header Primary H Table */ +/*P_JFIF*/ +#define JPEG_ENC_PRIMARY_JFIF 0x80 /*!< JPEG encode image header Primary JFIF */ +/*T_DRI*/ +#define JPEG_ENC_THUMBNAIL_DRI 0x1 /*!< JPEG encode image header Thumbnail DRI */ +/*T_QTAB*/ +#define JPEG_ENC_THUMBNAIL_QTAB 0x2 /*!< JPEG encode image header Thumbnail Q Table */ +/*T_HTAB*/ +#define JPEG_ENC_THUMBNAIL_HTAB 0x4 /*!< JPEG encode image header Thumbnail H Table */ +/*T_JFIF*/ +#define JPEG_ENC_THUMBNAIL_JFIF 0x8 /*!< JPEG encode image header Thumbnail JFIF */ + + +#define JPEG_IOCTL_SET_YADDR 0 /*!< Set Y Component Frame Buffer-0 Starting Address Register */ +#define JPEG_IOCTL_SET_YSTRIDE 1 /*!< Set Y Component Frame Buffer Stride Register */ +#define JPEG_IOCTL_SET_USTRIDE 2 /*!< Set U Component Frame Buffer Stride Register */ +#define JPEG_IOCTL_SET_VSTRIDE 3 /*!< Set V Component Frame Buffer Stride Register */ +#define JPEG_IOCTL_SET_BITSTREAM_ADDR 4 /*!< Set Bit-stream Frame Buffer-0 Starting Address Register */ +#define JPEG_IOCTL_SET_SOURCE_IMAGE_HEIGHT 5 /*!< Set JPEG Bit-stream FIFO Control Register */ +#define JPEG_IOCTL_ENC_SET_HEADER_CONTROL 6 /*!< Set JPEG Encode Header Control Register */ +#define JPEG_IOCTL_SET_DEFAULT_QTAB 7 /*!< Set Default Q Table */ +#define JPEG_IOCTL_SET_DECODE_MODE 8 /*!< Set Decode Mode */ +#define JPEG_IOCTL_SET_ENCODE_MODE 9 /*!< Set Encode Mode */ +#define JPEG_IOCTL_SET_DIMENSION 10 /*!< Set Encode Primary Width/Height */ +#define JPEG_IOCTL_ENCODE_TRIGGER 11 /*!< Encode Trigger */ +#define JPEG_IOCTL_DECODE_TRIGGER 12 /*!< Decode Trigger */ +#define JPEG_IOCTL_WINDOW_DECODE 13 /*!< Window Decode Setting */ +#define JPEG_IOCTL_SET_DECODE_STRIDE 14 /*!< Set Decode Stride */ +#define JPEG_IOCTL_SET_DECODE_DOWNSCALE 15 /*!< Set Decode Downscale */ +#define JPEG_IOCTL_SET_ENCODE_UPSCALE 16 /*!< Set Encode Upscale */ +#define JPEG_IOCTL_SET_HEADERDECODE_CALBACKFUN 17 /*!< Set Header decode call back function */ +#define JPEG_IOCTL_SET_DECINPUTWAIT_CALBACKFUN 18 /*!< Set Decode Input Wait call back function */ +#define JPEG_IOCTL_ADJUST_QTAB 19 /*!< Set Primary or Thumbnail Q Table */ +#define JPEG_IOCTL_ENC_RESERVED_FOR_SOFTWARE 20 /*!< Set Encode Reserved Size */ +#define JPEG_IOCTL_SET_UADDR 21 /*!< Set U Component Frame Buffer-0 Starting Address Register */ +#define JPEG_IOCTL_SET_VADDR 22 /*!< Set V Component Frame Buffer-0 Starting Address Register */ +#define JPEG_IOCTL_SET_ENCODE_PRIMARY_RESTART_INTERVAL 23 /*!< Set Encode Primary restart interval */ +#define JPEG_IOCTL_SET_ENCODE_THUMBNAIL_RESTART_INTERVAL 24 /*!< Set Encode Thumbnail restart interval */ +#define JPEG_IOCTL_GET_ENCODE_PRIMARY_RESTART_INTERVAL 25 /*!< Get Encode Primary restart interval */ +#define JPEG_IOCTL_GET_ENCODE_THUMBNAIL_RESTART_INTERVAL 26 /*!< Get Encode Thumbnail restart interval */ +#define JPEG_IOCTL_SET_THUMBNAIL_DIMENSION 27 /*!< Set Encode Thumbnail Width/Height */ +#define JPEG_IOCTL_SET_ENCODE_SW_OFFSET 28 /*!< Set Offset Between Primary & Thumbnail Register */ +#define JPEG_IOCTL_GET_THUMBNAIL_DIMENSION 29 /*!< Get Thumbnail Width/Height */ +#define JPEG_IOCTL_GET_ENCODE_SW_OFFSET 30 /*!< Get Offset Between Primary & Thumbnail Register */ +#define JPEG_IOCTL_SET_ENCODE_PRIMARY_DOWNSCALE 31 /*!< Set Enciode Primary Downscale */ +#define JPEG_IOCTL_SET_ENCODE_THUMBNAIL_DOWNSCALE 32 /*!< Set Encode Thumbnail Downscale */ +#define JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_RIGHT 33 /*!< Set Encode Primary rotate right */ +#define JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT 34 /*!< Set Encode Primary rotate left */ +#define JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_NORMAL 35 /*!< Set Encode Primary rotate normal */ +#define JPEG_IOCTL_SET_DECOUTPUTWAIT_CALBACKFUN 36 /*!< Set Decode Output wait call back function */ +#define JPEG_IOCTL_SET_DECOUTPUTWAIT 37 /*!< Set Decode Output wait */ +#define JPEG_IOCTL_GET_DECOUTPUTWAIT_ADDR 38 /*!< Get Decode Output wait address */ +#define JPEG_IOCTL_GET_DECOUTPUTWAIT_SIZE 39 /*!< Get Decode Output wait size */ +#define JPEG_IOCTL_SET_DECODE_COMPLETE_CALBACKFUN 40 /*!< Set Decode complete call back function */ +#define JPEG_IOCTL_SET_ENCODE_COMPLETE_CALBACKFUN 41 /*!< Set Encode complete call back function */ +#define JPEG_IOCTL_SET_DECODE_ERROR_CALBACKFUN 42 /*!< Set Decode Error call back function */ + +typedef BOOL (*PFN_JPEG_HEADERDECODE_CALLBACK)(void); /*!< JPEG Header decode call back function */ +typedef BOOL (*PFN_JPEG_CALLBACK)(void); /*!< JPEG call back function */ +typedef BOOL (*PFN_JPEG_DECWAIT_CALLBACK)(UINT32 u32Address, UINT32 u32Size); /*!< JPEG decode wait call back function */ + +/** \brief Structure type of JPEG encode/decode information + */ +typedef struct +{ + /*decode information*/ + UINT32 yuvformat; /*!< JPEG YUV Format for decode*/ + UINT32 width; /*!< Image Width */ + UINT32 height; /*!< Image High */ + UINT32 jpeg_width; /*!< JPEG decode width*/ + UINT32 jpeg_height; /*!< JPEG decode high*/ + UINT32 stride; /*!< Stride for decode*/ + /*encode information*/ + UINT32 bufferend; /*!< Encode buffer */ + UINT32 image_size[2]; /*!< Image size after encoded*/ +} JPEG_INFO_T; + +/** \brief Structure type of JPEG Window Decode information + */ +typedef struct +{ + UINT16 u16StartMCUX; /*!< Start X MCU */ + UINT16 u16StartMCUY; /*!< Horizontal Scaling Factor */ + UINT16 u16EndMCUX; /*!< Vertical Scaling Factor */ + UINT16 u16EndMCUY; /*!< Horizontal Scaling Factor */ + UINT32 u32Stride; /*!< Decode Output Stride */ +} JPEG_WINDOW_DECODE_T; + +struct nu_jpeg_ioctl +{ + UINT32 arg0; + UINT32 arg1; +}; +typedef struct nu_jpeg_ioctl *nu_jpeg_ioctl_t; + +struct nu_jpeg_qtab +{ + PUINT8 puQTable0; + PUINT8 puQTable1; + PUINT8 puQTable2; + UINT8 u8num; +}; +typedef struct nu_jpeg_qtab *nu_jpeg_qtab_t; + +/*@}*/ /* end of group N9H30_JPEG_EXPORTED_CONSTANTS */ + + +/** @addtogroup N9H30_JPEG_EXPORTED_FUNCTIONS JPEG Exported Functions + @{ +*/ +#define JPEG_IOCTL_SET_QTAB 64 /*!< Set User-defined Q Table */ +#define JPEG_IOCTL_INITIAL_CODEC 65 /*!< Reset Initial internal variables */ +#define JPEG_IOCTL_GET_INFO 66 /*!< Set Decode Error call back function */ +#define JPEG_IOCTL_IS_READY 67 /*!< Check JPEG codec is ready or not */ +#define JPEG_IOCTL_WAITDONE 68 /*!< Wait JPEG action done. */ + +INT jpegSetQTAB(PUINT8 puQTable0, PUINT8 puQTable1, PUINT8 puQTable2, UINT8 u8num); +INT jpegOpen(void); +VOID jpegClose(void); +VOID jpegInit(void); +VOID jpegGetInfo(JPEG_INFO_T *info); +BOOL jpegIsReady(void); +INT jpegWait(void); +VOID jpegIoctl(UINT32 cmd, UINT32 arg0, UINT32 arg1); + +/*@}*/ /* end of group N9H30_JPEG_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_JPEG_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_lcd.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_lcd.h new file mode 100644 index 0000000000000000000000000000000000000000..910d708845a71d9677b1f711cee0d590345ae66b --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_lcd.h @@ -0,0 +1,247 @@ +/**************************************************************************//** +* @file lcd.h +* @version V1.00 +* @brief N9H30 LCD driver header file +* +* SPDX-License-Identifier: Apache-2.0 +* @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#ifndef __NU_LCD_H__ +#define __NU_LCD_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_LCD_Driver LCD Driver + @{ +*/ + +/** @addtogroup N9H30_LCD_EXPORTED_CONSTANTS LCD Exported Constants + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +/* bit definition of REG_LCM_DCCS register */ +#define VPOSTB_HC_EN ((UINT32)1<<31) +#define VPOSTB_DISP_ON (1<<25) +#define VPOSTB_ITUEN (1<<15) +#define VPOSTB_OSD_SRC_YUV422 (0<<12) +#define VPOSTB_OSD_SRC_YCBCR422 (1<<12) +#define VPOSTB_OSD_SRC_RGB888 (2<<12) +#define VPOSTB_OSD_SRC_RGB666 (3<<12) +#define VPOSTB_OSD_SRC_RGB565 (4<<12) +#define VPOSTB_OSD_SRC_RGB444_LOW (5<<12) +#define VPOSTB_OSD_SRC_RGB444_HIGH (7<<12) +#define VPOSTB_VA_SRC_YUV422 (0<<8 ) +#define VPOSTB_VA_SRC_YCBCR422 (1<<8 ) +#define VPOSTB_VA_SRC_RGB888 (2<<8 ) +#define VPOSTB_VA_SRC_RGB666 (3<<8 ) +#define VPOSTB_VA_SRC_RGB565 (4<<8 ) +#define VPOSTB_VA_SRC_RGB444_LOW (5<<8 ) +#define VPOSTB_VA_SRC_RGB444_HIGH (7<<8 ) +#define VPOSTB_SINGLE (1<<7 ) +#define VPOSTB_FIELD_INTR (1<<6 ) +#define VPOSTB_CMD_ON (1<<5 ) +#define VPOSTB_DISP_INT_EN (1<<4 ) +#define VPOSTB_DISP_OUT_EN (1<<3 ) +#define VPOSTB_OSD_EN (1<<2 ) +#define VPOSTB_VA_EN (1<<1 ) +#define VPOSTB_ENG_RST (1) + + +/* bit definition of REG_LCM_DEV_CTRL register */ +#define VPOSTB_CMDHIGH (0) +#define VPOSTB_CMDLOW ((UINT32)1<<31) +#define VPOSTB_CM16t18LOW (0) +#define VPOSTB_CM16t18HIGH ((UINT32)1<<30) +#define VPOSTB_CMD8 (0) +#define VPOSTB_CMD16 ((UINT32)1<<29) +#define VPOSTB_IM256K_9or18 (0) +#define VPOSTB_IM256K_8or16 ((UINT32)1<<28) +#define VPOSTB_MPU80 (0) +#define VPOSTB_MPU68 (1<<27) +#define VPOSTB_DATA8or9 (0) +#define VPOSTB_DATA16or18 (1<<26) +#define VPOSTB_COLORTYPE_4K (0) +#define VPOSTB_COLORTYPE_64K (1<<24) +#define VPOSTB_COLORTYPE_256K (2<<24) +#define VPOSTB_COLORTYPE_16M (3<<24) +#define VPOSTB_LACE (1<<23) +#define VPOSTB_VR_LACE (1<<22) +#define VPOSTB_V_POL (1<<21) +#define VPOSTB_H_POL (1<<20) +#define VPOSTB_FAL_D (1<<19) +#define VPOSTB_YUV2CCIR (1<<16) +#define VPOSTB_DEVICE_SYNC_YUV422 (0) +#define VPOSTB_DEVICE_SYNC_UNIPAC (4<<5) +#define VPOSTB_DEVICE_SYNC_EPSON (5<<5) +#define VPOSTB_DEVICE_SYNC_HIGHCOLOR (6<<5) +#define VPOSTB_DEVICE_MPU (7<<5) +#define VPOSTB_SWAP_YUYV (1<<1) + +/* bit definition of REG_LCM_INT_CS register */ +#define VPOSTB_DISP_F_INT ((UINT32)1<<31) +#define VPOSTB_DISP_F_STATUS (1<<30) +#define VPOSTB_UNDERRUN_INT (1<<29) +#define VPOSTB_BUS_ERROR_INT (1<<28) +#define VPOSTB_FLY_ERR (1<<27) +#define VPOSTB_UNDERRUN_EN (1<<1) +#define VPOSTB_DISP_F_EN (1) + +/* bit definition of REG_LCM_VA_FBCTRL register */ +#define VPOSTB_DB_EN ((UINT32)1<<31) +#define VPOSTB_FLY_EN (1<<12) + +/* bit definition of REG_LCM_OSD_OVERLAY register */ +#define VPOSTB_BLI_ON (1<<9) +#define VPOSTB_CKEY_ON (1<<8) + +#define DISPLAY_VIDEO (0) +#define DISPLAY_OSD (1) +#define DISPLAY_SYNTHESIZED (2) + +/// @endcond HIDDEN_SYMBOLS + +#define VA_SRC_YUV422 (0<<8 ) /*!< YUV422 format */ +#define VA_SRC_YCBCR422 (1<<8 ) /*!< YCBCR422 format */ +#define VA_SRC_RGB888 (2<<8 ) /*!< RGB888 format */ +#define VA_SRC_RGB666 (3<<8 ) /*!< RGB666 format */ +#define VA_SRC_RGB565 (4<<8 ) /*!< RGB565 format */ +#define VA_SRC_RGB444_LOW (5<<8 ) /*!< RGB444 low nibble format */ +#define VA_SRC_RGB444_HIGH (7<<8 ) /*!< RGB444 high nibble format */ + +#define OSD_SRC_YUV422 (0<<12) /*!< YUV422 format */ +#define OSD_SRC_YCBCR422 (1<<12) /*!< YCBCR422 format */ +#define OSD_SRC_RGB888 (2<<12) /*!< RGB888 format */ +#define OSD_SRC_RGB666 (3<<12) /*!< RGB666 format */ +#define OSD_SRC_RGB565 (4<<12) /*!< RGB565 format */ +#define OSD_SRC_RGB444_LOW (5<<12) /*!< RGB444 low nibble format */ +#define OSD_SRC_RGB444_HIGH (7<<12) /*!< RGB444 high nibble format */ +#define OSD_SRC_RGB332 (6<<12) /*!< RGB332 format */ + +#define VPOST_DISPLAY_SINGLE 1 /*!< Single display mode */ +#define VPOST_DISPLAY_CONTINUOUS 0 /*!< Continuous display mode */ + +#define VPOSTB_OSD_VUP_1X (0<<16) /*!< OSD vertical scale up 1x */ +#define VPOSTB_OSD_VUP_2X (1<<16) /*!< OSD vertical scale up 2x */ +#define VPOSTB_OSD_VUP_4X (2<<16) /*!< OSD vertical scale up 4x */ + +#define DISPLAY_VIDEO (0) /*!< Display video data */ +#define DISPLAY_OSD (1) /*!< Display OSD data */ +#define DISPLAY_SYNTHESIZED (2) /*!< Display synthesized data */ + +#define VA_SCALE_INTERPOLATION (0) /*!< Scale mode is interpolation */ +#define VA_SCALE_DUPLICATION (1<<15) /*!< Scale mode is duplication */ + +typedef enum va_hcmode_e +{ + HC_MODE0, /*!< 32X32X2bpp 4 color */ + HC_MODE1, /*!< 32X32X2bpp 3 color and 1 transparent */ + HC_MODE2, /*!< 64X64X2bpp 4 color */ + HC_MODE3, /*!< 64X64X2bpp 3 color and 1 transparent */ + HC_MODE4, /*!< 128X128X1bpp 2 color */ + HC_MODE5 /*!< 128X128X1bpp 1 color and 1 transparent */ +} VA_HCMODE_E; + +typedef struct +{ + uint32_t ucVASrcFormat; /*!< User input Display source format */ + uint32_t nScreenWidth; /*!< Driver output,LCD width */ + uint32_t nScreenHeight; /*!< Driver output,LCD height */ + uint32_t nFrameBufferSize; /*!< Driver output,Frame buffer size(malloc by driver) */ + uint8_t ucROT90; /*!< Rotate 90 degree or not */ +} LCDFORMATEX; + +typedef struct +{ + uint32_t ucOSDSrcFormat; /*!< User input, OSD source format */ + uint32_t nXstart; /*!< User input, OSD X axis position */ + uint32_t nYstart; /*!< User input, OSD Y axis position */ + uint32_t nOSDWidth; /*!< User input, OSD width */ + uint32_t nOSDHeight; /*!< User input, OSD height */ + uint32_t nImageWidth; /*!< User input, The width of OSD source image width */ + uint32_t *pFrameBuffer; /*!< User input, The address of OSD source image */ +} OSDFORMATEX; + +#define DIS_PANEL_E50A2V1 0 +#define DIS_PANEL_ILI9341_MPU80 1 +#define DIS_LSA40AT9001 2 +#define DIS_PANEL_FW070TFT 3 +typedef struct +{ + uint32_t u32DevWidth; /*!< Panel width */ + uint32_t u32DevHeight; /*!< Panel height */ + uint32_t u32CmdLow; /*!< MPU command line low indicator */ + uint32_t u32Cmd16t18; /*!< MPU command width */ + uint32_t u32CmdBusWidth; /*!< MPU bus width */ + uint32_t u32DataBusWidth; /*!< Display bus width */ + uint32_t u32MPU_Mode; /*!< MPU mode */ + uint32_t u32DisplayColors; /*!< Display colors */ + uint32_t u32DevType; /*!< Type of display panel */ + uint32_t u32Reg_CRTCSIZE; /*!< CRTCSIZE register value */ + uint32_t u32Reg_CRTCDEND; /*!< CRTCDEND register value */ + uint32_t u32Reg_CRTCHR; /*!< CRTCHR register value */ + uint32_t u32Reg_CRTCHSYNC; /*!< CRTCHSYNC register value */ + uint32_t u32Reg_CRTCVR; /*!< CRTCVR register value */ +} VPOST_T; + +#define LCM_ERR_ID 0xFFFF0400 /*!< LCM library ID */ + +/* error code */ +#define ERR_NULL_BUF (LCM_ERR_ID | 0x04) /*!< error memory location */ +#define ERR_NO_DEVICE (LCM_ERR_ID | 0x05) /*!< error no device */ +#define ERR_BAD_PARAMETER (LCM_ERR_ID | 0x06) /*!< error for bad parameter */ +#define ERR_POWER_STATE (LCM_ERR_ID | 0x07) /*!< error power state control */ +/*@}*/ /* end of group N9H30_LCD_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_LCD_EXPORTED_FUNCTIONS LCD Exported Functions + @{ +*/ + +void vpostLCMInit(uint32_t u32DisplayPanelID); +uint8_t *vpostGetFrameBuffer(void); +uint8_t *vpostGetMultiFrameBuffer(uint32_t u32Cnt); +void vpostLCMDeinit(void); +void vpostSetDisplayMode(uint8_t u8DisplayMode); +void vpostSetVASrc(uint32_t u32VASrcType); +void vpostVAStartTrigger(void); +void vpostVAStopTrigger(void); +void vpostVAScalingCtrl(uint8_t u8HIntegral, uint16_t u16HDecimal, uint8_t u8VIntegral, uint16_t u16VDecimal, uint32_t u32Mode); + +void vpostOSDSetColKey(uint8_t u8CKeyColorR, uint8_t u8CKeyColorG, uint8_t u8CKeyColorB); +void vpostOSDSetColMask(uint8_t u8MaskColorR, uint8_t u8MaskColorG, uint8_t u8MaskColorB); +void vpostOSDSetBlinking(uint8_t u8OSDBlinkVcnt); +void vpostOSDDisableBlinking(void); +void vpostSetOSDSrc(uint32_t u32OSDSrcType); +uint8_t *vpostGetOSDBuffer(void); +void vpostOSDEnable(void); +void vpostOSDDisable(void); +void vpostOSDScalingCtrl(uint8_t u8HIntegral, uint16_t u16HDecimal, uint8_t u8VScall); +void vpostOSDSetWindow(uint32_t u32XStart, uint32_t u32YStart, uint32_t u32Width, uint32_t u32Height); +void vpostHCInit(uint32_t *u32CursorBMPBuff, VA_HCMODE_E ucMode); +void vpostHCPosCtrl(uint32_t u32CursorX, uint32_t u32CursorY); +void vpostOSDSetOverlay(uint8_t u8OSDDisplayMatch, uint8_t u8OSDDisplayUnMatch, uint8_t u8OSDSynW); +void vpostMPUWriteAddr(uint16_t uscmd); +void vpostMPUWriteData(uint16_t usdata); +uint32_t vpostMPUReadData(void); +VPOST_T *vpostLCMGetInstance(uint32_t u32DisplayPanelID); + +/*@}*/ /* end of group N9H30_LCD_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_LCD_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_LCD_H__ + + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_pwm.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_pwm.h new file mode 100644 index 0000000000000000000000000000000000000000..4282d5099ca67d3bc7758422bcbf85ee780b868c --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_pwm.h @@ -0,0 +1,238 @@ +/**************************************************************************//** + * @file pwm.h + * @brief N9H30 series PWM driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __NU_PWM_H__ +#define __NU_PWM_H__ +#include "N9H30.h" +#include "nu_sys.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_PWM_Driver PWM Driver + @{ +*/ + +/** @addtogroup N9H30_PWM_EXPORTED_CONSTANTS PWM Exported Constants + @{ +*/ + +#define PWM_OFFSET 0xc ///< each channel has 3 control registers which occupies 12 bytes + +// Timer channel identity information +#define PWM_TIMER_NUM 4 ///< Total PWM channel count +#define PWM_TIMER_MIN 0 ///< Min PWM channel number +#define PWM_TIMER_MAX 3 ///< Max PWM channel number +#define PWM_TIMER0 0 ///< PWM channel 0 +#define PWM_TIMER1 1 ///< PWM channel 1 +#define PWM_TIMER2 2 ///< PWM channel 2 +#define PWM_TIMER3 3 ///< PWM channel 3 + +//ioctl command +#define START_PWMTIMER 0 ///< Start PWM ioctl command +#define STOP_PWMTIMER 1 ///< Stop PWM ioctl command +#define SET_CSR 2 ///< Set CSR ioctl command +#define SET_CP 3 ///< Set CP ioctl command +#define SET_DZI 4 ///< Set dead zone ioctl command +#define SET_INVERTER 5 ///< Set inverter ioctl command +#define SET_MODE 6 ///< Set OP mode ioctl command +#define ENABLE_DZ_GENERATOR 7 ///< Enable dead zone ioctl command +#define DISABLE_DZ_GENERATOR 8 ///< Disable dead zone ioctl command +#define ENABLE_PWMGPIOOUTPUT 9 ///< Enable PWM output ioctl command + +#define PWM_STOP_METHOD1 1 ///< PWM stop method 1 +#define PWM_STOP_METHOD2 2 ///< PWM stop method 2 +//#define PWM_STOP_METHOD3 3 not recommended + +//Timer default value +#define DEFAULT_CSR CSRD16 ///< Default CSR value +#define DEFAULT_CP 255 ///< Default CP value +#define DEFAULT_DZI 50 ///< Default DZI value +#define DEFAULT_CNR 19531 ///< Default CNR value +#define DEFAULT_CMR (19531/4) ///< Default CMR value +#define DEFAULT_MODE PWM_TOGGLE ///< Default OP mode + +// for PWM_PPR +#define DZI_MIN 0 ///< Min DZI value +#define DZI_MAX 255 ///< Max DZI value +#define CP_MIN 0 ///< Min CP value +#define CP_MAX 255 ///< Max CP value + +// for PWM_CSR +#define CSR_MIN 0 ///< Min CSR value +#define CSR_MAX 4 ///< Mac SCR value +#define CSRD2 0x0 ///< Div by 2 +#define CSRD4 0x1 ///< Div by 4 +#define CSRD8 0x2 ///< Div by 8 +#define CSRD16 0x3 ///< Div by 16 +#define CSRD1 0x4 ///< Div by 1 + +// for PWM_PCR +#define PWMDZG_ENABLE 1 ///< Enable PWM dead zone +#define PWMDZG_DISABLE 0 ///< Disable PWM dead zone +#define PWM_ENABLE 1 ///< Enable PWM channel +#define PWM_DISABLE 0 ///< Disable PWM channel +#define PWM_TOGGLE 1 ///< PWM toggle mode +#define PWM_ONESHOT 0 ///< PWM one-shot mode +#define PWM_INVON 1 ///< Enable PWM inverter +#define PWM_INVOFF 0 ///< Disable PWM inverter + +// for PWM_CNR +#define CNR_MIN 0 ///< Min CNR value +#define CNR_MAX 65535 ///< Mac CNR value + +// for PWM_CMR +#define CMR_MIN 0 ///< Min CMR value +#define CMR_MAX 65535 ///< Max CMR value + +// for pin control +#define PWM0_GPA12 0 ///< PWM0 output on GPA12 +#define PWM0_GPB2 1 ///< PWM0 output on GPB2 +#define PWM1_GPA13 4 ///< PWM1 output on GPA13 +#define PWM1_GPB3 5 ///< PWM1 output on GPB3 +#define PWM2_GPA14 7 ///< PWM2 output on GPA14 +#define PWM2_GPH2 9 ///< PWM2 output on GPH2 +#define PWM3_GPA15 10 ///< PWM3 output on GPA15 +#define PWM3_GPH3 12 ///< PWM3 output on GPH3 + +#define PWM_ERR_ID 0xFFFF1300 ///< PWM library ID + +//PWM Error code +#define pwmInvalidTimerChannel (PWM_ERR_ID|1) ///< Invalid channel number +#define pwmInvalidStructLength (PWM_ERR_ID|2) ///< Invalid structure length +#define pwmInvalidIoctlCommand (PWM_ERR_ID|3) ///< Invalid ioctl command +#define pwmInvalidStopMethod (PWM_ERR_ID|4) ///< Invalid stop mode +#define pwmInvalidCPValue (PWM_ERR_ID|5) ///< Invalid CP value +#define pwmInvalidDZIValue (PWM_ERR_ID|6) ///< Invalid DZI value +#define pwmInvalidCSRValue (PWM_ERR_ID|7) ///< Invalid CSR value +#define pwmInvalidDZGStatus (PWM_ERR_ID|8) ///< Invalid DZ status +#define pwmInvalidTimerStatus (PWM_ERR_ID|9) ///< Invalid timer status +#define pwmInvalidInverterValue (PWM_ERR_ID|10) ///< Invalid inverter value +#define pwmInvalidModeStatus (PWM_ERR_ID|11) ///< Invalid OP mode +#define pwmInvalidCNRValue (PWM_ERR_ID|12) ///< Invalid CNR value +#define pwmInvalidCMRValue (PWM_ERR_ID|13) ///< Invalid CMR value +#define pwmTimerNotOpen (PWM_ERR_ID|14) ///< PWM channel not stop +#define pwmTimerBusy (PWM_ERR_ID|15) ///< PWM channel is busy +#define pwmInvalidPin (PWM_ERR_ID|16) ///< Invalid PWM output pin + +/*@}*/ /* end of group N9H30_PWM_EXPORTED_CONSTANTS */ + +/// @cond HIDDEN_SYMBOLS +/** @addtogroup N9H30_PWM_EXPORTED_STRUCTS PWM Exported Structs + @{ +*/ + +typedef union +{ + UINT value; + struct + { + UINT cp0: 8, cp1: 8, dzi0: 8, dzi1: 8; + } field; +} typePPR; + +typedef union +{ + UINT value; + struct + { + UINT csr0: 3, _reserved3: 1, + csr1: 3, _reserved7: 1, + csr2: 3, _reserved11: 1, + csr3: 3, _reserved15: 1, + _reserved16_31: 16; + } field; +} typeCSR; + +typedef union +{ + UINT value; + struct + { + UINT ch0_en: 1, _reserved1: 1, ch0_inverter: 1, ch0_mode: 1, + grpup0_dzen: 1, grpup1_dzen: 1, + _reserved6_7: 2, + ch1_en: 1, _reserved9: 1, ch1_inverter: 1, ch1_mode: 1, + ch2_en: 1, _reserved13: 1, ch2_inverter: 1, ch2_mode: 1, + ch3_en: 1, _reserved17: 1, ch3_inverter: 1, ch3_mode: 1, + _reserved20_31: 12; + } field; +} typePCR; + +typedef union +{ + UINT value; + struct + { + UINT cnr: 16, _reserved16_31: 16; + } field; +} typeCNR; + +typedef union +{ + UINT value; + struct + { + UINT cmr: 16, _reserved16_31: 16; + } field; +} typeCMR; + +// for write operation +typedef union +{ + UINT value; + struct + { + UINT cnr: 16, cmr: 16; + } field; +} typePWMVALUE; + +// for read operation +typedef struct +{ + UINT volatile PDR; + BOOL volatile InterruptFlag; + BOOL _reversed0; + BOOL _reversed1; + BOOL _reversed2; +} typePWMSTATUS; + +/*@}*/ /* end of group N9H30_PWM_EXPORTED_STRUCTS */ +/// @endcond /* HIDDEN_SYMBOLS */ + +/** @addtogroup N9H30_PWM_EXPORTED_FUNCTIONS PWM Exported Functions + @{ +*/ + +// function definition +INT pwmInit(void); +INT pwmExit(void); +INT pwmOpen(const INT nTimerIdentity); +INT pwmClose(const INT nTimerIdentity); +INT pwmRead(const INT nTimerIdentity, PUCHAR pucStatusValue, const UINT uLength); +INT pwmWrite(const INT nTimerIdentity, PUCHAR pucCNRCMRValue, const UINT uLength); +INT pwmIoctl(const INT nTimerIdentity, const UINT uCommand, const UINT uIndication, UINT uValue); + +/*@}*/ /* end of group N9H30_PWM_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_PWM_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_PWM_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_rtc.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_rtc.h new file mode 100644 index 0000000000000000000000000000000000000000..6deb571d156128a8f3cce194e613a913c368040d --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_rtc.h @@ -0,0 +1,508 @@ +/**************************************************************************//** +* @file RTC.h +* @brief N9H30 RTC driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_RTC_H__ +#define __NU_RTC_H__ + + +/*---------------------------------------------------------------------------------------------------------*/ +/* Includes of system headers */ +/*---------------------------------------------------------------------------------------------------------*/ +#include "N9H30.h" +#include "nu_sys.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_RTC_Driver RTC Driver + @{ +*/ + +/** @addtogroup N9H30_RTC_EXPORTED_CONSTANTS RTC Exported Constants + @{ +*/ + +/*---------------------------------------------------------------------------------------------------------*/ +/* Define Error Code */ +/*---------------------------------------------------------------------------------------------------------*/ +#define E_RTC_SUCCESS 0 /*!< success */ +#define E_RTC_ERR_CALENDAR_VALUE 1 /*!< Wrong Calendar Value */ +#define E_RTC_ERR_TIMESACLE_VALUE 2 /*!< Wrong Time Scale Value */ +#define E_RTC_ERR_TIME_VALUE 3 /*!< Wrong Time Value */ +#define E_RTC_ERR_DWR_VALUE 4 /*!< Wrong Day Value */ +#define E_RTC_ERR_FCR_VALUE 5 /*!< Wrong Compenation value */ +#define E_RTC_ERR_EIO 6 /*!< Initial RTC Failed */ +#define E_RTC_ERR_ENOTTY 7 /*!< Command not support, or parameter incorrect */ +#define E_RTC_ERR_ENODEV 8 /*!< Interface number incorrect */ + +#define RTC_FCR_REFERENCE 32761 /*!< RTC Reference for frequency compensation */ + +#define RTC_INIT_KEY 0xa5eb1357 /*!< RTC Access Key \hideinitializer */ +#define RTC_WRITE_KEY 0xa965 /*!< RTC Access Key \hideinitializer */ + +#define RTC_WAIT_COUNT 0xFFFFFFFF /*!< Initial Time Out Value \hideinitializer */ + +#define RTC_YEAR2000 2000 /*!< RTC Reference \hideinitializer */ + +#define RTC_LEAP_YEAR 1 /*!< RTC leap year \hideinitializer */ + +#define RTC_CLOCK_12 0 /*!< RTC 12 Hour */ +#define RTC_CLOCK_24 1 /*!< RTC 24 Hour */ + +#define RTC_AM 1 /*!< RTC AM \hideinitializer */ +#define RTC_PM 2 /*!< RTC PM \hideinitializer */ + +#define RTC_INIT_ACTIVE_Pos (0) /*!< RTC INIT: ACTIVE Position */ +#define RTC_INIT_ACTIVE_Msk (0x1ul << RTC_INIT_ACTIVE_Pos) /*!< RTC INIT: ACTIVE Mask */ + +#define RTC_INIT_INIT_Pos (0) /*!< RTC INIT: INIT Position */ +#define RTC_INIT_INIT_Msk (0xfffffffful << RTC_INIT_INIT_Pos) /*!< RTC INIT: INIT Mask */ + +#define RTC_RWEN_RWENPASSWD_Pos (0) /*!< RTC RWEN: RWEN Position */ +#define RTC_RWEN_RWENPASSWD_Msk (0xfffful << RTC_RWEN_RWEN_Pos) /*!< RTC RWEN: RWEN Mask */ + +#define RTC_RWEN_RWENF_Pos (16) /*!< RTC RWEN: RWENF Position */ +#define RTC_RWEN_RWENF_Msk (0x1ul << RTC_RWEN_RWENF_Pos) /*!< RTC RWEN: RWENF Mask */ + +#define RTC_FREQADJ_FRACTION_Pos (0) /*!< RTC FREQADJ: FRACTION Position */ +#define RTC_FREQADJ_FRACTION_Msk (0x3ful << RTC_FREQADJ_FRACTION_Pos) /*!< RTC FREQADJ: FRACTION Mask */ + +#define RTC_FREQADJ_INTEGER_Pos (8) /*!< RTC FREQADJ: INTEGER Position */ +#define RTC_FREQADJ_INTEGER_Msk (0xful << RTC_FREQADJ_INTEGER_Pos) /*!< RTC FREQADJ: INTEGER Mask */ + +#define RTC_TIME_SEC_Pos (0) /*!< RTC TIME: SEC Position */ +#define RTC_TIME_SEC_Msk (0xful << RTC_TIME_SEC_Pos) /*!< RTC TIME: SEC Mask */ + +#define RTC_TIME_TENSEC_Pos (4) /*!< RTC TIME: TENSEC Position */ +#define RTC_TIME_TENSEC_Msk (0x7ul << RTC_TIME_TENSEC_Pos) /*!< RTC TIME: TENSEC Mask */ + +#define RTC_TIME_MIN_Pos (8) /*!< RTC TIME: MIN Position */ +#define RTC_TIME_MIN_Msk (0xful << RTC_TIME_MIN_Pos) /*!< RTC TIME: MIN Mask */ + +#define RTC_TIME_TENMIN_Pos (12) /*!< RTC TIME: TENMIN Position */ +#define RTC_TIME_TENMIN_Msk (0x7ul << RTC_TIME_TENMIN_Pos) /*!< RTC TIME: TENMIN Mask */ + +#define RTC_TIME_HR_Pos (16) /*!< RTC TIME: HR Position */ +#define RTC_TIME_HR_Msk (0xful << RTC_TIME_HR_Pos) /*!< RTC TIME: HR Mask */ + +#define RTC_TIME_TENHR_Pos (20) /*!< RTC TIME: TENHR Position */ +#define RTC_TIME_TENHR_Msk (0x3ul << RTC_TIME_TENHR_Pos) /*!< RTC TIME: TENHR Mask */ + +#define RTC_CAL_DAY_Pos (0) /*!< RTC CAL: DAY Position */ +#define RTC_CAL_DAY_Msk (0xful << RTC_CAL_DAY_Pos) /*!< RTC CAL: DAY Mask */ + +#define RTC_CAL_TENDAY_Pos (4) /*!< RTC CAL: TENDAY Position */ +#define RTC_CAL_TENDAY_Msk (0x3ul << RTC_CAL_TENDAY_Pos) /*!< RTC CAL: TENDAY Mask */ + +#define RTC_CAL_MON_Pos (8) /*!< RTC CAL: MON Position */ +#define RTC_CAL_MON_Msk (0xful << RTC_CAL_MON_Pos) /*!< RTC CAL: MON Mask */ + +#define RTC_CAL_TENMON_Pos (12) /*!< RTC CAL: TENMON Position */ +#define RTC_CAL_TENMON_Msk (0x1ul << RTC_CAL_TENMON_Pos) /*!< RTC CAL: TENMON Mask */ + +#define RTC_CAL_YEAR_Pos (16) /*!< RTC CAL: YEAR Position */ +#define RTC_CAL_YEAR_Msk (0xful << RTC_CAL_YEAR_Pos) /*!< RTC CAL: YEAR Mask */ + +#define RTC_CAL_TENYEAR_Pos (20) /*!< RTC CAL: TENYEAR Position */ +#define RTC_CAL_TENYEAR_Msk (0xful << RTC_CAL_TENYEAR_Pos) /*!< RTC CAL: TENYEAR Mask */ + +#define RTC_TIMEFMT_24HEN_Pos (0) /*!< RTC CLKFMT: 24HEN Position */ +#define RTC_TIMEFMT_24HEN_Msk (0x1ul << RTC_CLKFMT_24HEN_Pos) /*!< RTC CLKFMT: 24HEN Mask */ + +#define RTC_WEEKDAY_WEEKDAY_Pos (0) /*!< RTC WEEKDAY: WEEKDAY Position */ +#define RTC_WEEKDAY_WEEKDAY_Msk (0x7ul << RTC_WEEKDAY_WEEKDAY_Pos) /*!< RTC WEEKDAY: WEEKDAY Mask */ + +#define RTC_TALM_SEC_Pos (0) /*!< RTC TALM: SEC Position */ +#define RTC_TALM_SEC_Msk (0xful << RTC_TALM_SEC_Pos) /*!< RTC TALM: SEC Mask */ + +#define RTC_TALM_TENSEC_Pos (4) /*!< RTC TALM: TENSEC Position */ +#define RTC_TALM_TENSEC_Msk (0x7ul << RTC_TALM_TENSEC_Pos) /*!< RTC TALM: TENSEC Mask */ + +#define RTC_TALM_MIN_Pos (8) /*!< RTC TALM: MIN Position */ +#define RTC_TALM_MIN_Msk (0xful << RTC_TALM_MIN_Pos) /*!< RTC TALM: MIN Mask */ + +#define RTC_TALM_TENMIN_Pos (12) /*!< RTC TALM: TENMIN Position */ +#define RTC_TALM_TENMIN_Msk (0x7ul << RTC_TALM_TENMIN_Pos) /*!< RTC TALM: TENMIN Mask */ + +#define RTC_TALM_HR_Pos (16) /*!< RTC TALM: HR Position */ +#define RTC_TALM_HR_Msk (0xful << RTC_TALM_HR_Pos) /*!< RTC TALM: HR Mask */ + +#define RTC_TALM_TENHR_Pos (20) /*!< RTC TALM: TENHR Position */ +#define RTC_TALM_TENHR_Msk (0x3ul << RTC_TALM_TENHR_Pos) /*!< RTC TALM: TENHR Mask */ + +#define RTC_CALM_DAY_Pos (0) /*!< RTC CALM: DAY Position */ +#define RTC_CALM_DAY_Msk (0xful << RTC_CALM_DAY_Pos) /*!< RTC CALM: DAY Mask */ + +#define RTC_CALM_TENDAY_Pos (4) /*!< RTC CALM: TENDAY Position */ +#define RTC_CALM_TENDAY_Msk (0x3ul << RTC_CALM_TENDAY_Pos) /*!< RTC CALM: TENDAY Mask */ + +#define RTC_CALM_MON_Pos (8) /*!< RTC CALM: MON Position */ +#define RTC_CALM_MON_Msk (0xful << RTC_CALM_MON_Pos) /*!< RTC CALM: MON Mask */ + +#define RTC_CALM_TENMON_Pos (12) /*!< RTC CALM: TENMON Position */ +#define RTC_CALM_TENMON_Msk (0x1ul << RTC_CALM_TENMON_Pos) /*!< RTC CALM: TENMON Mask */ + +#define RTC_CALM_YEAR_Pos (16) /*!< RTC CALM: YEAR Position */ +#define RTC_CALM_YEAR_Msk (0xful << RTC_CALM_YEAR_Pos) /*!< RTC CALM: YEAR Mask */ + +#define RTC_CALM_TENYEAR_Pos (20) /*!< RTC CALM: TENYEAR Position */ +#define RTC_CALM_TENYEAR_Msk (0xful << RTC_CALM_TENYEAR_Pos) /*!< RTC CALM: TENYEAR Mask */ + +#define RTC_CALM_WEEKDAY_Pos (24) /*!< RTC CALM: WEEKDAY Position */ +#define RTC_CALM_WEEKDAY_Msk (0x7ul << RTC_CALM_WEEKDAY_Pos) /*!< RTC CALM: WEEKDAY Mask */ + +#define RTC_CALM_DAYALM_MSK_Pos (28) /*!< RTC CALM: DAYALM_MSK Position */ +#define RTC_CALM_DAYALM_MSK_Msk (0x1ul << RTC_CALM_DAYALM_MSK_Pos) /*!< RTC CALM: DAYALM_MSK Mask */ + +#define RTC_CALM_MONALM_MSK_Pos (29) /*!< RTC CALM: MONALM_MSK Position */ +#define RTC_CALM_MONALM_MSK_Msk (0x1ul << RTC_CALM_MONALM_MSK_Pos) /*!< RTC CALM: MONALM_MSK Mask */ + +#define RTC_CALM_YRALM_MSK_Pos (30) /*!< RTC CALM: YRALM_MSK Position */ +#define RTC_CALM_YRALM_MSK_Msk (0x1ul << RTC_CALM_YRALM_MSK_Pos) /*!< RTC CALM: YRALM_MSK Mask */ + +#define RTC_CALM_WKDALM_MSK_Pos (31) /*!< RTC CALM: WKDALM_MSK Position */ +#define RTC_CALM_WKDALM_MSK_Msk (0x1ul << RTC_CALM_WKDALM_MSK_Pos) /*!< RTC CALM: WKDALM_MSK Mask */ + + +#define RTC_LEAPYEAR_LEAPYEAR_Pos (0) /*!< RTC LEAPYEAR: LEAPYEAR Position */ +#define RTC_LEAPYEAR_LEAPYEAR_Msk (0x1ul << RTC_LEAPYEAR_LEAPYEAR_Pos) /*!< RTC LEAPYEAR: LEAPYEAR Mask */ + +#define RTC_INTEN_ALMIEN_Pos (0) /*!< RTC INTEN: ALMIEN Position */ +#define RTC_INTEN_ALMIEN_Msk (0x1ul << RTC_INTEN_ALMIEN_Pos) /*!< RTC INTEN: ALMIEN Mask */ + +#define RTC_INTEN_TICKIEN_Pos (1) /*!< RTC INTEN: TICKIEN Position */ +#define RTC_INTEN_TICKIEN_Msk (0x1ul << RTC_INTEN_TICKIEN_Pos) /*!< RTC INTEN: TICKIEN Mask */ + +#define RTC_INTEN_WAKEUPIEN_Pos (2) /*!< RTC INTEN: WAKEUPIEN Position */ +#define RTC_INTEN_WAKEUPIEN_Msk (0x1ul << RTC_INTEN_WAKEUPIEN_Pos) /*!< RTC INTEN: WAKEUPIEN Mask */ + +#define RTC_INTEN_PWRSWIEN_Pos (3) /*!< RTC INTEN: PWRSWIEN Position */ +#define RTC_INTEN_PWRSWIEN_Msk (0x1ul << RTC_INTEN_PWRSWIEN_Pos) /*!< RTC INTEN: PWRSWIEN Mask */ + +#define RTC_INTEN_RELALMIEN_Pos (4) /*!< RTC INTEN: RELALMIEN Position */ +#define RTC_INTEN_RELALMIEN_Msk (0x1ul << RTC_INTEN_RELALMIEN_Pos) /*!< RTC INTEN: RELALMIEN Mask */ + +#define RTC_INTEN_KEYPRESIEN_Pos (5) /*!< RTC INTEN: KEYPRESIEN Position */ +#define RTC_INTEN_KEYPRESIEN_Msk (0x1ul << RTC_INTEN_KEYPRESIEN_Pos) /*!< RTC INTEN: KEYPRESIEN Mask */ + + +#define RTC_INTSTS_ALMINT_Pos (0) /*!< RTC INTSTS: ALMINT Position */ +#define RTC_INTSTS_ALMINT_Msk (0x1ul << RTC_INTSTS_ALMINT_Pos) /*!< RTC INTSTS: ALMINT Mask */ + +#define RTC_INTSTS_TICKINT_Pos (1) /*!< RTC INTSTS: TICKINT Position */ +#define RTC_INTSTS_TICKINT_Msk (0x1ul << RTC_INTSTS_TICKINT_Pos) /*!< RTC INTSTS: TICKINT Mask */ + +#define RTC_INTSTS_WAKEUPINT_Pos (2) /*!< RTC INTSTS: WAKEUPINT Position */ +#define RTC_INTSTS_WAKEUPINT_Msk (0x1ul << RTC_INTSTS_WAKEUPINT_Pos) /*!< RTC INTSTS: WAKEUPINT Mask */ + +#define RTC_INTSTS_PWRSWINT_Pos (3) /*!< RTC INTSTS: PWRSWINT Position */ +#define RTC_INTSTS_PWRSWINT_Msk (0x1ul << RTC_INTSTS_PWRSWINT_Pos) /*!< RTC INTSTS: PWRSWINT Mask */ + +#define RTC_INTSTS_RELALMINT_Pos (4) /*!< RTC INTSTS: RELALMINT Position */ +#define RTC_INTSTS_RELALMINT_Msk (0x1ul << RTC_INTSTS_RELALMINT_Pos) /*!< RTC INTSTS: RELALMINT Mask */ + +#define RTC_INTSTS_KEYPRESINT_Pos (5) /*!< RTC INTSTS: KEYPRESINT Position */ +#define RTC_INTSTS_KEYPRESINT_Msk (0x1ul << RTC_INTSTS_KEYPRESINT_Pos) /*!< RTC INTSTS: KEYPRESINT Mask */ + +#define RTC_INTSTS_REGWRBUSY_Pos (31) /*!< RTC INTSTS: REGWRBUSY Position */ +#define RTC_INTSTS_REGWRBUSY_Msk (0x1ul << RTC_INTSTS_REGWRBUSY_Pos) /*!< RTC INTSTS: REGWRBUSY Mask */ + + +#define RTC_TICK_TTR_Pos (0) /*!< RTC TICK: TTR Position */ +#define RTC_TICK_TTR_Msk (0x7ul << RTC_TICK_TTR_Pos) /*!< RTC TICK: TTR Mask */ + +#define RTC_PWRCTL_PWR_ON_Pos (0) /*!< RTC PWRCTL: PWR_ON Position */ +#define RTC_PWRCTL_PWR_ON_Msk (0x1ul << RTC_PWRCTL_PWR_ON_Pos) /*!< RTC PWRCTL: PWR_ON Mask */ + +#define RTC_PWRCTL_SW_PCLR_Pos (1) /*!< RTC PWRCTL: SW_PCLR Position */ +#define RTC_PWRCTL_SW_PCLR_Msk (0x1ul << RTC_PWRCTL_SW_PCLR_Pos) /*!< RTC PWRCTL: SW_PCLR Mask */ + +#define RTC_PWRCTL_HW_PCLR_EN_Pos (2) /*!< RTC PWRCTL: HW_PCLR_EN Position */ +#define RTC_PWRCTL_HW_PCLR_EN_Msk (0x1ul << RTC_PWRCTL_HW_PCLR_EN_Pos) /*!< RTC PWRCTL: HW_PCLR_EN Mask */ + +#define RTC_PWRCTL_ALARM_EN_Pos (3) /*!< RTC PWRCTL: ALARM_EN Position */ +#define RTC_PWRCTL_ALARM_EN_Msk (0x1ul << RTC_PWRCTL_ALARM_EN_Pos) /*!< RTC PWRCTL: ALARM_EN Mask */ + +#define RTC_PWRCTL_REL_ALARM_EN_Pos (4) /*!< RTC PWRCTL: REL_ALARM_EN Position */ +#define RTC_PWRCTL_REL_ALARM_EN_Msk (0x1ul << RTC_PWRCTL_REL_ALARM_EN_Pos) /*!< RTC PWRCTL: REL_ALARM_EN Mask */ + +#define RTC_PWRCTL_EDGE_TRIG_Pos (5) /*!< RTC PWRCTL: EDGE_TRIG Position */ +#define RTC_PWRCTL_EDGE_TRIG_Msk (0x1ul << RTC_PWRCTL_EDGE_TRIG_Pos) /*!< RTC PWRCTL: EDGE_TRIG Mask */ + +#define RTC_PWRCTL_TIMEUNITL_Pos (6) /*!< RTC PWRCTL: TIMEUNITL Position */ +#define RTC_PWRCTL_TIMEUNITL_Msk (0x1ul << RTC_PWRCTL_TIMEUNITLPos) /*!< RTC PWRCTL: TIMEUNITL Mask */ + +#define RTC_PWRCTL_PWR_KEY_Pos (7) /*!< RTC PWRCTL: PWR_KEY Position */ +#define RTC_PWRCTL_PWR_KEY_Msk (0x1ul << RTC_PWRCTL_PWR_KEY_Pos) /*!< RTC PWRCTL: PWR_KEY Mask */ + +#define RTC_PWRCTL_PWRON_TIME_Pos (8) /*!< RTC PWRCTL: PWRON_TIME Position */ +#define RTC_PWRCTL_PWRON_TIME_Msk (0xful << RTC_PWRCTL_PWRON_TIME_Pos) /*!< RTC PWRCTL: PWRON_TIME Mask */ + +#define RTC_PWRCTL_PWROFF_TIME_Pos (12) /*!< RTC PWRCTL: PWROFF_TIME Position */ +#define RTC_PWRCTL_PWROFF_TIME_Msk (0xful << RTC_PWRCTL_PWROFF_TIME_Pos) /*!< RTC PWRCTL: PWROFF_TIME Mask */ + +#define RTC_PWRCTL_RELALM_TIME_Pos (16) /*!< RTC PWRCTL: RELALM_TIME Position */ +#define RTC_PWRCTL_RELALM_TIME_Msk (0xffful << RTC_PWRCTL_RELALM_TIME_Pos) /*!< RTC PWRCTL: RELALM_TIME Mask */ + +#define RTC_PWRCTL_ALARM_MODE_Pos (28) /*!< RTC PWRCTL: ALARM_MODE Position */ +#define RTC_PWRCTL_ALARM_MODE_Msk (0x1ul << RTC_PWRCTL_ALARM_MODE_Pos) /*!< RTC PWRCTL: ALARM_MODE Mask */ + + +#define RTC_SPRCTL_SNPDEN_Pos (0) /*!< RTC SPRCTL: SNPDEN Position */ +#define RTC_SPRCTL_SNPDEN_Msk (0x1ul << RTC_SPRCTL_SNPDEN_Pos) /*!< RTC SPRCTL: SNPDEN Mask */ + +#define RTC_SPRCTL_SNPTYPE0_Pos (1) /*!< RTC SPRCTL: SNPTYPE0 Position */ +#define RTC_SPRCTL_SNPTYPE0_Msk (0x1ul << RTC_SPRCTL_SNPTYPE0_Pos) /*!< RTC SPRCTL: SNPTYPE0 Mask */ + +#define RTC_SPRCTL_SPRRWEN_Pos (2) /*!< RTC SPRCTL: SPRRWEN Position */ +#define RTC_SPRCTL_SPRRWEN_Msk (0x1ul << RTC_SPRCTL_SPRRWEN_Pos) /*!< RTC SPRCTL: SPRRWEN Mask */ + +#define RTC_SPRCTL_SNPTYPE1_Pos (3) /*!< RTC SPRCTL: SNPTYPE1 Position */ +#define RTC_SPRCTL_SNPTYPE1_Msk (0x1ul << RTC_SPRCTL_SNPTYPE1_Pos) /*!< RTC SPRCTL: SNPTYPE1 Mask */ + +#define RTC_SPRCTL_SPRCSTS_Pos (5) /*!< RTC SPRCTL: SPRCSTS Position */ +#define RTC_SPRCTL_SPRCSTS_Msk (0x1ul << RTC_SPRCTL_SPRCSTS_Pos) /*!< RTC SPRCTL: SPRCSTS Mask */ + +#define RTC_SPRCTL_SPRRWRDY_Pos (7) /*!< RTC SPRCTL: SPRRWRDY Position */ +#define RTC_SPRCTL_SPRRWRDY_Msk (0x1ul << RTC_SPRCTL_SPRRWRDY_Pos) /*!< RTC SPRCTL: SPRRWRDY Mask */ + +#define RTC_SPR0_SPARE_Pos (0) /*!< RTC SPR0: SPARE Position */ +#define RTC_SPR0_SPARE_Msk (0xfffffffful << RTC_SPR0_SPARE_Pos) /*!< RTC SPR0: SPARE Mask */ + +#define RTC_SPR1_SPARE_Pos (0) /*!< RTC SPR1: SPARE Position */ +#define RTC_SPR1_SPARE_Msk (0xfffffffful << RTC_SPR1_SPARE_Pos) /*!< RTC SPR1: SPARE Mask */ + +#define RTC_SPR2_SPARE_Pos (0) /*!< RTC SPR2: SPARE Position */ +#define RTC_SPR2_SPARE_Msk (0xfffffffful << RTC_SPR2_SPARE_Pos) /*!< RTC SPR2: SPARE Mask */ + +#define RTC_SPR3_SPARE_Pos (0) /*!< RTC SPR3: SPARE Position */ +#define RTC_SPR3_SPARE_Msk (0xfffffffful << RTC_SPR3_SPARE_Pos) /*!< RTC SPR3: SPARE Mask */ + +#define RTC_SPR4_SPARE_Pos (0) /*!< RTC SPR4: SPARE Position */ +#define RTC_SPR4_SPARE_Msk (0xfffffffful << RTC_SPR4_SPARE_Pos) /*!< RTC SPR4: SPARE Mask */ + +#define RTC_SPR5_SPARE_Pos (0) /*!< RTC SPR5: SPARE Position */ +#define RTC_SPR5_SPARE_Msk (0xfffffffful << RTC_SPR5_SPARE_Pos) /*!< RTC SPR5: SPARE Mask */ + +#define RTC_SPR6_SPARE_Pos (0) /*!< RTC SPR6: SPARE Position */ +#define RTC_SPR6_SPARE_Msk (0xfffffffful << RTC_SPR6_SPARE_Pos) /*!< RTC SPR6: SPARE Mask */ + +#define RTC_SPR7_SPARE_Pos (0) /*!< RTC SPR7: SPARE Position */ +#define RTC_SPR7_SPARE_Msk (0xfffffffful << RTC_SPR7_SPARE_Pos) /*!< RTC SPR7: SPARE Mask */ + +#define RTC_SPR8_SPARE_Pos (0) /*!< RTC SPR8: SPARE Position */ +#define RTC_SPR8_SPARE_Msk (0xfffffffful << RTC_SPR8_SPARE_Pos) /*!< RTC SPR8: SPARE Mask */ + +#define RTC_SPR9_SPARE_Pos (0) /*!< RTC SPR9: SPARE Position */ +#define RTC_SPR9_SPARE_Msk (0xfffffffful << RTC_SPR9_SPARE_Pos) /*!< RTC SPR9: SPARE Mask */ + +#define RTC_SPR10_SPARE_Pos (0) /*!< RTC SPR10: SPARE Position */ +#define RTC_SPR10_SPARE_Msk (0xfffffffful << RTC_SPR10_SPARE_Pos) /*!< RTC SPR10: SPARE Mask */ + +#define RTC_SPR11_SPARE_Pos (0) /*!< RTC SPR11: SPARE Position */ +#define RTC_SPR11_SPARE_Msk (0xfffffffful << RTC_SPR11_SPARE_Pos) /*!< RTC SPR11: SPARE Mask */ + +#define RTC_SPR12_SPARE_Pos (0) /*!< RTC SPR12: SPARE Position */ +#define RTC_SPR12_SPARE_Msk (0xfffffffful << RTC_SPR12_SPARE_Pos) /*!< RTC SPR12: SPARE Mask */ + +#define RTC_SPR13_SPARE_Pos (0) /*!< RTC SPR13: SPARE Position */ +#define RTC_SPR13_SPARE_Msk (0xfffffffful << RTC_SPR13_SPARE_Pos) /*!< RTC SPR13: SPARE Mask */ + +#define RTC_SPR14_SPARE_Pos (0) /*!< RTC SPR14: SPARE Position */ +#define RTC_SPR14_SPARE_Msk (0xfffffffful << RTC_SPR14_SPARE_Pos) /*!< RTC SPR14: SPARE Mask */ + +#define RTC_SPR15_SPARE_Pos (0) /*!< RTC SPR15: SPARE Position */ +#define RTC_SPR15_SPARE_Msk (0xfffffffful << RTC_SPR15_SPARE_Pos) /*!< RTC SPR15: SPARE Mask */ + +#define RTC_SPR16_SPARE_Pos (0) /*!< RTC SPR16: SPARE Position */ +#define RTC_SPR16_SPARE_Msk (0xfffffffful << RTC_SPR16_SPARE_Pos) /*!< RTC SPR16: SPARE Mask */ + +#define RTC_SPR17_SPARE_Pos (0) /*!< RTC SPR17: SPARE Position */ +#define RTC_SPR17_SPARE_Msk (0xfffffffful << RTC_SPR17_SPARE_Pos) /*!< RTC SPR17: SPARE Mask */ + +#define RTC_SPR18_SPARE_Pos (0) /*!< RTC SPR18: SPARE Position */ +#define RTC_SPR18_SPARE_Msk (0xfffffffful << RTC_SPR18_SPARE_Pos) /*!< RTC SPR18: SPARE Mask */ + +#define RTC_SPR19_SPARE_Pos (0) /*!< RTC SPR19: SPARE Position */ +#define RTC_SPR19_SPARE_Msk (0xfffffffful << RTC_SPR19_SPARE_Pos) /*!< RTC SPR19: SPARE Mask */ + +/** + * @brief RTC define interrupt source + */ +typedef enum +{ + RTC_ALARM_INT = 0x01, /*!< Alarm interrupt */ + RTC_TICK_INT = 0x02, /*!< Tick interrupt */ + RTC_WAKEUP_INT = 0x04, /*!< Wake-up interrupt */ + RTC_PSWI_INT = 0x08, /*!< Power switch interrupt */ + RTC_RELATIVE_ALARM_INT = 0x10, /*!< Releative Alarm interrupt */ + RTC_KEY_PRESS_INT = 0x20, /*!< Power Key press interrupt */ + RTC_ALL_INT = 0x3F /*!< All interrupt */ +} RTC_INT_SOURCE; + +/** + * @brief Define Ioctl commands + */ +typedef enum +{ + RTC_IOC_IDENTIFY_LEAP_YEAR = 0, /*!< Identify leap year */ + RTC_IOC_SET_TICK_MODE = 1, /*!< Set tick mode */ + RTC_IOC_GET_TICK = 2, /*!< Get tick count */ + RTC_IOC_RESTORE_TICK = 3, /*!< Reset tick count */ + RTC_IOC_ENABLE_INT = 4, /*!< Enable RTC interrupt */ + RTC_IOC_DISABLE_INT = 5, /*!< Disable RTC interrupt */ + RTC_IOC_SET_CURRENT_TIME = 6, /*!< Set current time */ + RTC_IOC_SET_ALAMRM_TIME = 7, /*!< set alarm time */ + RTC_IOC_SET_FREQUENCY = 8, /*!< Set frequency compensation value */ + RTC_IOC_SET_POWER_ON = 9, /*!< Set Power on */ + RTC_IOC_SET_POWER_OFF = 10, /*!< Set Power off*/ + RTC_IOC_SET_POWER_OFF_PERIOD = 11, /*!< Set Power off period */ + RTC_IOC_ENABLE_HW_POWEROFF = 12, /*!< Enable H/W Power off */ + RTC_IOC_DISABLE_HW_POWEROFF = 13, /*!< Disable H/W Power off */ + RTC_IOC_GET_POWERKEY_STATUS = 14, /*!< Get Power key status */ + RTC_IOC_SET_PSWI_CALLBACK = 15, /*!< Set Power switch isr call back function */ + //RTC_IOC_GET_SW_STATUS = 16, + //RTC_IOC_SET_SW_STATUS = 17, + RTC_IOC_SET_RELEATIVE_ALARM = 18, /*!< Set releative alarm */ + //RTC_IOC_SET_POWER_KEY_DELAY = 19, + //RTC_IOC_SET_CLOCK_SOURCE = 20, + //RTC_IOC_GET_CLOCK_SOURCE = 21 +} E_RTC_CMD; + +/** + * @brief RTC define Tick mode + */ +typedef enum +{ + RTC_TICK_1_SEC = 0, /*!< Time tick is 1 second */ + RTC_TICK_1_2_SEC = 1, /*!< Time tick is 1/2 second */ + RTC_TICK_1_4_SEC = 2, /*!< Time tick is 1/4 second */ + RTC_TICK_1_8_SEC = 3, /*!< Time tick is 1/8 second */ + RTC_TICK_1_16_SEC = 4, /*!< Time tick is 1/16 second */ + RTC_TICK_1_32_SEC = 5, /*!< Time tick is 1/32 second */ + RTC_TICK_1_64_SEC = 6, /*!< Time tick is 1/64 second */ + RTC_TICK_1_128_SEC = 7 /*!< Time tick is 1/128 second */ +} RTC_TICK; + +typedef void (PFN_RTC_CALLBACK)(void); /*!< Call back function \hideinitializer */ + +/** + * @brief RTC current/alarm time select + */ +typedef enum +{ + RTC_CURRENT_TIME = 0, /*!< Select current time */ + RTC_ALARM_TIME = 1 /*!< Select alarm time */ +} E_RTC_TIME_SELECT; + +/** + * @brief RTC define Day of week parameter + */ +typedef enum +{ + RTC_SUNDAY = 0, /*!< Sunday */ + RTC_MONDAY = 1, /*!< Monday */ + RTC_TUESDAY = 2, /*!< Tuesday */ + RTC_WEDNESDAY = 3, /*!< Wednesday */ + RTC_THURSDAY = 4, /*!< Thursday */ + RTC_FRIDAY = 5, /*!< Friday */ + RTC_SATURDAY = 6 /*!< Saturday */ +} E_RTC_DWR_PARAMETER; + + +/** + * @brief RTC define Time Data Struct + */ +typedef struct +{ + UINT8 u8cClockDisplay; /*!< 12-Hour, 24-Hour */ + UINT8 u8cAmPm; /*!< Time Scale select 12-hr/24-hr */ + UINT32 u32cSecond; /*!< Second value */ + UINT32 u32cMinute; /*!< Minute value */ + UINT32 u32cHour; /*!< Hour value */ + UINT32 u32cDayOfWeek; /*!< Day of week value */ + UINT32 u32cDay; /*!< Day value */ + UINT32 u32cMonth; /*!< Month value */ + UINT32 u32Year; /*!< Year value */ + UINT32 u32AlarmMaskSecond; /*!< Alarm mask second */ + UINT32 u32AlarmMaskMinute; /*!< Alarm mask minute */ + UINT32 u32AlarmMaskHour; /*!< Alarm mask hour */ + PFN_RTC_CALLBACK *pfnAlarmCallBack; /*!< Alarm ISR call back function */ +} S_RTC_TIME_DATA_T; + + +/** + * @brief RTC define Tick Struct + */ +typedef struct +{ + UINT8 ucMode; /*!< Tick Mode */ + PFN_RTC_CALLBACK *pfnTickCallBack; /*!< Tick ISR call back function */ +} RTC_TICK_T; + +/*@}*/ /* end of group N9H30_RTC_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_RTC_EXPORTED_FUNCTIONS RTC Exported Functions + @{ +*/ + +UINT32 RTC_Init(void); +UINT32 RTC_Open(S_RTC_TIME_DATA_T *sPt); +UINT32 RTC_Ioctl(INT32 i32Num, E_RTC_CMD eCmd, UINT32 u32Arg0, UINT32 u32Arg1); +UINT32 RTC_Read(E_RTC_TIME_SELECT eTime, S_RTC_TIME_DATA_T *sPt); +UINT32 RTC_Write(E_RTC_TIME_SELECT eTime, S_RTC_TIME_DATA_T *sPt); +UINT32 RTC_DoFrequencyCompensation(INT32 i32FrequencyX100); +UINT32 RTC_WriteEnable(BOOL bEnable); +UINT32 RTC_Close(void); +void RTC_EnableClock(BOOL bEnable); +VOID RTC_Check(void); + +#define RTC_DisableInt(u32IntFlag) RTC_Ioctl(0, RTC_IOC_DISABLE_INT, u32IntFlag, 0) +#define RTC_EnableInt(u32IntFlag) RTC_Ioctl(0, RTC_IOC_ENABLE_INT, u32IntFlag, 0) +#define RTC_GET_TICK_INT_FLAG() (inp32(REG_RTC_INTSTS)&RTC_TICK_INT) +#define RTC_GET_ALARM_INT_FLAG() (inp32(REG_RTC_INTSTS)&RTC_ALARM_INT) + +static __inline void RTC_CLEAR_TICK_INT_FLAG(void) +{ + RTC_WriteEnable(1); + outp32(REG_RTC_INTSTS, RTC_TICK_INT); + RTC_Check(); +} + +static __inline void RTC_CLEAR_ALARM_INT_FLAG(void) +{ + RTC_WriteEnable(1); + outp32(REG_RTC_INTSTS, RTC_ALARM_INT); + RTC_Check(); +} + + +/*@}*/ /* end of group N9H30_RTC_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_RTC_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif /* __NU_RTC_H__ */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + + + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_scuart.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_scuart.h new file mode 100644 index 0000000000000000000000000000000000000000..58746264ee0f95cfd0d8893f4161380ee52950e9 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_scuart.h @@ -0,0 +1,335 @@ +/**************************************************************************//** + * @file scuart.h + * @brief N9H30 series Smartcard UART mode (SCUART) driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __NU_SCUART_H__ +#define __NU_SCUART_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_SCUART_Driver SCUART Driver + @{ +*/ + +/** @addtogroup N9H30_SCUART_EXPORTED_CONSTANTS SCUART Exported Constants + @{ +*/ +#define SCUART_CHAR_LEN_5 (0x3ul << 4) /*!< Set SCUART word length to 5 bits */ +#define SCUART_CHAR_LEN_6 (0x2ul << 4) /*!< Set SCUART word length to 6 bits */ +#define SCUART_CHAR_LEN_7 (0x1ul << 4) /*!< Set SCUART word length to 7 bits */ +#define SCUART_CHAR_LEN_8 (0) /*!< Set SCUART word length to 8 bits */ + +#define SCUART_PARITY_NONE (0x00000040) /*!< Set SCUART transfer with no parity */ +#define SCUART_PARITY_ODD (0x00000080) /*!< Set SCUART transfer with odd parity */ +#define SCUART_PARITY_EVEN (0) /*!< Set SCUART transfer with even parity */ + +#define SCUART_STOP_BIT_1 (0x00008000) /*!< Set SCUART transfer with one stop bit */ +#define SCUART_STOP_BIT_2 (0) /*!< Set SCUART transfer with two stop bits */ + +#define SC_STATUS_RXEMPTY_Msk 0x00000002 +#define SC_STATUS_RXFULL_Msk 0x00000004 +#define SC_STATUS_PEF_Msk 0x00000010 +#define SC_STATUS_FEF_Msk 0x00000020 +#define SC_STATUS_BEF_Msk 0x00000040 +#define SC_STATUS_TXEMPTY_Msk 0x00000200 +#define SC_STATUS_TXFULL_Msk 0x00000400 +#define SC_STATUS_TXACT_Msk 0x80000000 + +#define SC_INTEN_RXTOIEN_Msk 0x00000200 +#define SC_INTEN_TERRIEN_Msk 0x00000004 +#define SC_INTEN_TBEIEN_Msk 0x00000002 +#define SC_INTEN_RDAIEN_Msk 0x00000001 + +#define SC_INTSTS_RBTOIF_Msk 0x00000200 +#define SC_INTSTS_TERRIF_Msk 0x00000004 +#define SC_INTSTS_TBEIF_Msk 0x00000002 +#define SC_INTSTS_RDAIF_Msk 0x00000001 + +#define SC_CTL_SCEN_Msk 0x00000001 +#define SC_CTL_NSB_Msk 0x00008000 + +#define SC_UARTCTL_UARTEN_Msk 0x00000001 + +/*@}*/ /* end of group N9H30_SCUART_EXPORTED_CONSTANTS */ + + +/** @addtogroup N9H30_SCUART_EXPORTED_FUNCTIONS SCUART Exported Functions + @{ +*/ + +/* TX Macros */ +/** + * @brief Write Data to Tx data register. + * @param[in] sc Smartcard module number + * @param[in] u8Data Data byte to transmit. + * @return None + * @details By writing data to DAT register, the SC will send out an 8-bit data. + * \hideinitializer + */ +#define SCUART_WRITE(sc, u8Data) \ +do {\ + if(sc == 0)\ + outpw(REG_SC0_DAT, u8Data);\ + else\ + outpw(REG_SC1_DAT, u8Data);\ +}while(0) + +/** + * @brief Get TX FIFO empty flag status from register. + * @param[in] sc Smartcard module number + * @return Transmit FIFO empty status. + * @retval 0 Transmit FIFO is not empty. + * @retval SC_STATUS_TXEMPTY_Msk Transmit FIFO is empty. + * @details When the last byte of TX buffer has been transferred to Transmitter Shift Register, hardware sets TXEMPTY bit (SC_STATUS[9]) high. + * It will be cleared when writing data into DAT (SC_DAT[7:0]). + * \hideinitializer + */ +#define SCUART_GET_TX_EMPTY(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_TXEMPTY_Msk) : (inpw(REG_SC1_STATUS) & SC_STATUS_TXEMPTY_Msk)) + +/** + * @brief Get TX FIFO full flag status from register. + * @param[in] sc Smartcard module number + * @retval 0 Transmit FIFO is not full. + * @retval SC_STATUS_TXFULL_Msk Transmit FIFO is full. + * @details TXFULL(SC_STATUS[10]) is set when TX pointer is equal to 4, otherwise is cleared by hardware. + * \hideinitializer + */ +#define SCUART_GET_TX_FULL(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_TXFULL_Msk) : (inpw(REG_SC1_STATUS) & SC_STATUS_TXFULL_Msk)) + +/** + * @brief Wait specified smartcard port transmission complete. + * @param[in] sc Smartcard module number + * @return None + * @details TXACT (SC_STATUS[31]) is cleared automatically when TX transfer is finished or the last byte transmission has completed. + * @note This macro blocks until transmit complete. + * \hideinitializer + */ +#define SCUART_WAIT_TX_EMPTY(sc)\ +do {\ + if(sc == 0)\ + while(inpw(REG_SC0_STATUS) & SC_STATUS_TXACT_Msk);\ + else\ + while(inpw(REG_SC1_STATUS) & SC_STATUS_TXACT_Msk);\ +}while(0) + +/** + * @brief Check specified smartcard port transmit FIFO is full or not. + * @param[in] sc Smartcard module number + * @retval 0 Transmit FIFO is not full. + * @retval 1 Transmit FIFO is full. + * @details TXFULL(SC_STATUS[10]) indicates TX buffer full or not. + * This is set when TX pointer is equal to 4, otherwise is cleared by hardware. + * \hideinitializer + */ +#define SCUART_IS_TX_FULL(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_TXFULL_Msk ? 1 : 0) : (inpw(REG_SC1_STATUS) & SC_STATUS_TXFULL_Msk ? 1 : 0)) + +/** + * @brief Check specified smartcard port transmission is over. + * @param[in] sc Smartcard module number + * @retval 0 Transmit is not complete. + * @retval 1 Transmit complete. + * @details TXACT (SC_STATUS[31]) is set by hardware when TX transfer is in active and the STOP bit of the last byte has been transmitted. + * \hideinitializer + */ +#define SCUART_IS_TX_EMPTY(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_TXACT_Msk ? 1 : 0) : (inpw(REG_SC1_STATUS) & SC_STATUS_TXACT_Msk ? 1 : 0)) + +/* RX Macros */ + +/** + * @brief Read Rx data register. + * @param[in] sc Smartcard module number + * @return The oldest data byte in RX FIFO. + * @details By reading DAT register, the SC will return an 8-bit received data. + * \hideinitializer + */ +#define SCUART_READ(sc) (sc == 0 ? inpw(REG_SC0_DAT) : inpw(REG_SC1_DAT)) + +/** + * @brief Get RX FIFO empty flag status from register. + * @param[in] sc Smartcard module number + * @retval 0 Receive FIFO is not empty. + * @retval SC_STATUS_RXEMPTY_Msk Receive FIFO is empty. + * @details When the last byte of Rx buffer has been read by CPU, hardware sets RXEMPTY(SC_STATUS[1]) high. + * It will be cleared when SC receives any new data. + * \hideinitializer + */ +#define SCUART_GET_RX_EMPTY(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_RXEMPTY_Msk) : (inpw(REG_SC1_STATUS) & SC_STATUS_RXEMPTY_Msk)) + + +/** + * @brief Get RX FIFO full flag status from register. + * @param[in] sc Smartcard module number + * @retval 0 Receive FIFO is not full. + * @retval SC_STATUS_RXFULL_Msk Receive FIFO is full. + * @details RXFULLF(SC_STATUS[2]) is set when RX pointer is equal to 4, otherwise it is cleared by hardware. + * \hideinitializer + */ +#define SCUART_GET_RX_FULL(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_RXFULL_Msk) : (inpw(REG_SC1_STATUS) & SC_STATUS_RXFULL_Msk)) + +/** + * @brief Check if receive data number in FIFO reach FIFO trigger level or not. + * @param[in] sc Smartcard module number + * @retval 0 The number of bytes in receive FIFO is less than trigger level. + * @retval 1 The number of bytes in receive FIFO equals or larger than trigger level. + * @details RDAIF(SC_INTSTS[0]) is used for received data reaching trigger level RXTRGLV (SC_CTL[7:6]) interrupt status flag. + * @note If receive trigger level is \b not 1 byte, this macro return 0 does not necessary indicates there is no data in FIFO. + * \hideinitializer + */ +#define SCUART_IS_RX_READY(sc) (sc == 0 ? (inpw(REG_SC0_INTSTS) & SC_INTSTS_RDAIF_Msk ? 1 : 0) : (inpw(REG_SC1_INTSTS) & SC_INTSTS_RDAIF_Msk ? 1 : 0)) + +/** + * @brief Check specified smartcard port receive FIFO is full or not. + * @param[in] sc Smartcard module number + * @retval 0 Receive FIFO is not full. + * @retval 1 Receive FIFO is full. + * @details RXFULLF(SC_STATUS[2]) is set when RX pointer is equal to 4, otherwise it is cleared by hardware. + * \hideinitializer + */ +#define SCUART_IS_RX_FULL(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & SC_STATUS_RXFULL_Msk ? 1 : 0) : (inpw(REG_SC1_STATUS) & SC_STATUS_RXFULL_Msk ? 1 : 0)) + +/* Interrupt Macros */ + +/** + * @brief Enable specified interrupts. + * @param[in] sc Smartcard module number + * @param[in] u32Mask Interrupt masks to enable, a combination of following bits. + * - \ref SC_INTEN_RXTOIEN_Msk + * - \ref SC_INTEN_TERRIEN_Msk + * - \ref SC_INTEN_TBEIEN_Msk + * - \ref SC_INTEN_RDAIEN_Msk + * @return None + * @details The macro is used to enable receiver buffer time-out interrupt, transfer error interrupt, + * transmit buffer empty interrupt or receive data reach trigger level interrupt. + * \hideinitializer + */ +#define SCUART_ENABLE_INT(sc, u32Mask)\ +do {\ + if(sc == 0)\ + outpw(REG_SC0_INTEN, inpw(REG_SC0_INTEN) | (u32Mask));\ + else\ + outpw(REG_SC1_INTEN, inpw(REG_SC1_INTEN) | (u32Mask));\ +}while(0) + +/** + * @brief Disable specified interrupts. + * @param[in] sc Smartcard module number + * @param[in] u32Mask Interrupt masks to disable, a combination of following bits. + * - \ref SC_INTEN_RXTOIEN_Msk + * - \ref SC_INTEN_TERRIEN_Msk + * - \ref SC_INTEN_TBEIEN_Msk + * - \ref SC_INTEN_RDAIEN_Msk + * @return None + * @details The macro is used to disable receiver buffer time-out interrupt, transfer error interrupt, + * transmit buffer empty interrupt or receive data reach trigger level interrupt. + * \hideinitializer + */ +#define SCUART_DISABLE_INT(sc, u32Mask)\ +do {\ + if(sc == 0)\ + outpw(REG_SC0_INTEN, inpw(REG_SC0_INTEN) & ~(u32Mask));\ + else\ + outpw(REG_SC1_INTEN, inpw(REG_SC1_INTEN) & ~(u32Mask));\ +}while(0) + +/** + * @brief Get specified interrupt flag/status. + * @param[in] sc Smartcard module number + * @param[in] u32Type Interrupt flag/status to check, could be one of following value: + * - \ref SC_INTSTS_RBTOIF_Msk + * - \ref SC_INTSTS_TERRIF_Msk + * - \ref SC_INTSTS_TBEIF_Msk + * - \ref SC_INTSTS_RDAIF_Msk + * @return The status of specified interrupt. + * @retval 0 Specified interrupt does not happened. + * @retval 1 Specified interrupt happened. + * @details The macro is used to get receiver buffer time-out interrupt status, transfer error interrupt status, + * transmit buffer empty interrupt status or receive data reach interrupt status. + * \hideinitializer + */ +#define SCUART_GET_INT_FLAG(sc, u32Type) (sc == 0 ? (inpw(REG_SC0_INTSTS) & (u32Type) ? 1 : 0) : (inpw(REG_SC1_INTSTS) & (u32Type) ? 1 : 0)) + +/** + * @brief Clear specified interrupt flag/status. + * @param[in] sc Smartcard module number + * @param[in] u32Type Interrupt flag/status to clear, could be the combination of following values: + * - \ref SC_INTSTS_RBTOIF_Msk + * - \ref SC_INTSTS_TERRIF_Msk + * - \ref SC_INTSTS_TBEIF_Msk + * @return None + * @details The macro is used to clear receiver buffer time-out interrupt flag, transfer error interrupt flag or + * transmit buffer empty interrupt flag. + * \hideinitializer + */ +#define SCUART_CLR_INT_FLAG(sc, u32Type) \ +do {\ + if(sc == 0)\ + outpw(REG_SC0_INTSTS, (u32Type));\ + else\ + outpw(REG_SC1_INTSTS, (u32Type));\ +}while(0) + +/** + * @brief Get receive error flag/status. + * @param[in] sc Smartcard module number + * @return Current receive error status, could one of following errors: + * @retval SC_STATUS_PEF_Msk Parity error. + * @retval SC_STATUS_FEF_Msk Frame error. + * @retval SC_STATUS_BEF_Msk Break error. + * @details The macro is used to get receiver parity error status, receiver frame error status or + * receiver break error status. + * \hideinitializer + */ +#define SCUART_GET_ERR_FLAG(sc) (sc == 0 ? (inpw(REG_SC0_STATUS) & (SC_STATUS_PEF_Msk | SC_STATUS_FEF_Msk | SC_STATUS_BEF_Msk)) : (inpw(REG_SC1_STATUS) & (SC_STATUS_PEF_Msk | SC_STATUS_FEF_Msk | SC_STATUS_BEF_Msk))) + +/** + * @brief Clear specified receive error flag/status. + * @param[in] sc Smartcard module number + * @param[in] u32Mask Receive error flag/status to clear, combination following values: + * - \ref SC_STATUS_PEF_Msk + * - \ref SC_STATUS_FEF_Msk + * - \ref SC_STATUS_BEF_Msk + * @return None + * @details The macro is used to clear receiver parity error flag, receiver frame error flag or + * receiver break error flag. + * \hideinitializer + */ +#define SCUART_CLR_ERR_FLAG(sc, u32Mask)\ +do {\ + if(sc == 0)\ + outpw(REG_SC0_STATUS, (u32Mask));\ + else\ + outpw(REG_SC1_STATUS, (u32Mask));\ +}while(0) + +void SCUART_Close(UINT sc); +UINT SCUART_Open(UINT sc, UINT u32baudrate); +UINT SCUART_Read(UINT sc, char *pu8RxBuf, UINT u32ReadBytes); +UINT SCUART_SetLineConfig(UINT sc, UINT u32Baudrate, UINT u32DataWidth, UINT u32Parity, UINT u32StopBits); +void SCUART_SetTimeoutCnt(UINT sc, UINT u32TOC); +void SCUART_Write(UINT sc, char *pu8TxBuf, UINT u32WriteBytes); + +/*@}*/ /* end of group N9H30_SCUART_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SCUART_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_SCUART_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_sdh.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_sdh.h new file mode 100644 index 0000000000000000000000000000000000000000..2171f2ff71ed3e1e3af0ce83fb8615d6c9127589 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_sdh.h @@ -0,0 +1,757 @@ +/**************************************************************************//** + * @file sdh.h + * @brief N9H30 SDH driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include + +#ifndef __NU_SDH_H__ +#define __NU_SDH_H__ + +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +#define TIMER0 0 + +/** + @addtogroup REGISTER Control Register + @{ +*/ + +/** + @addtogroup SDH SD/SDIO Host Controller(SDH) + Memory Mapped Structure for SDH Controller +@{ */ + +typedef struct +{ + + /** + * @var SDH_T::FB + * Offset: 0x00~0x7C Shared Buffer (FIFO) + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |BUFFER |Shared Buffer + * | | |Buffer for DMA transfer + * @var SDH_T::DMACTL + * Offset: 0x400 DMA Control and Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |DMAEN |DMA Engine Enable Bit + * | | |0 = DMA Disabled. + * | | |1 = DMA Enabled. + * | | |If this bit is cleared, DMA will ignore all requests from SD host and force bus master into IDLE state. + * | | |Note: If target abort is occurred, DMAEN will be cleared. + * |[1] |DMARST |Software Engine Reset + * | | |0 = No effect. + * | | |1 = Reset internal state machine and pointers + * | | |The contents of control register will not be cleared + * | | |This bit will auto be cleared after few clock cycles. + * | | |Note: The software reset DMA related registers. + * |[3] |SGEN |Scatter-gather Function Enable Bit + * | | |0 = Scatter-gather function Disabled (DMA will treat the starting address in DMASAR as starting pointer of a single block memory). + * | | |1 = Scatter-gather function Enabled (DMA will treat the starting address in DMASAR as a starting address of Physical Address Descriptor (PAD) table + * | | |The format of these Pads' will be described later). + * |[9] |DMABUSY |DMA Transfer Is in Progress + * | | |This bit indicates if SD Host is granted and doing DMA transfer or not. + * | | |0 = DMA transfer is not in progress. + * | | |1 = DMA transfer is in progress. + * @var SDH_T::DMASA + * Offset: 0x408 DMA Transfer Starting Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |ORDER |Determined to the PAD Table Fetching Is in Order or Out of Order + * | | |0 = PAD table is fetched in order. + * | | |1 = PAD table is fetched out of order. + * | | |Note: the bit0 is valid in scatter-gather mode when SGEN = 1. + * |[31:1] |DMASA |DMA Transfer Starting Address + * | | |This field pads 0 as least significant bit indicates a 32-bit starting address of system memory (SRAM) for DMA to retrieve or fill in data. + * | | |If DMA is not in normal mode, this field will be interpreted as a starting address of Physical Address Descriptor (PAD) table. + * | | |Note: Starting address of the SRAM must be word aligned, for example, 0x0000_0000, 0x0000_0004. + * @var SDH_T::DMABCNT + * Offset: 0x40C DMA Transfer Byte Count Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[25:0] |BCNT |DMA Transfer Byte Count (Read Only) + * | | |This field indicates the remained byte count of DMA transfer + * | | |The value of this field is valid only when DMA is busy; otherwise, it is 0. + * @var SDH_T::DMAINTEN + * Offset: 0x410 DMA Interrupt Enable Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |ABORTIEN |DMA Read/Write Target Abort Interrupt Enable Bit + * | | |0 = Target abort interrupt generation Disabled during DMA transfer. + * | | |1 = Target abort interrupt generation Enabled during DMA transfer. + * |[1] |WEOTIEN |Wrong EOT Encountered Interrupt Enable Bit + * | | |0 = Interrupt generation Disabled when wrong EOT is encountered. + * | | |1 = Interrupt generation Enabled when wrong EOT is encountered. + * @var SDH_T::DMAINTSTS + * Offset: 0x414 DMA Interrupt Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |ABORTIF |DMA Read/Write Target Abort Interrupt Flag + * | | |0 = No bus ERROR response received. + * | | |1 = Bus ERROR response received. + * | | |Note1: This bit is read only, but can be cleared by writing '1' to it. + * | | |Note2: When DMA's bus master received ERROR response, it means that target abort is happened + * | | |DMA will stop transfer and respond this event and then go to IDLE state + * | | |When target abort occurred or WEOTIF is set, software must reset DMA and SD host, and then transfer those data again. + * |[1] |WEOTIF |Wrong EOT Encountered Interrupt Flag + * | | |When DMA Scatter-Gather function is enabled, and EOT of the descriptor is encountered before DMA transfer finished (that means the total sector count of all PAD is less than the sector count of SD host), this bit will be set. + * | | |0 = No EOT encountered before DMA transfer finished. + * | | |1 = EOT encountered before DMA transfer finished. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * @var SDH_T::GCTL + * Offset: 0x800 Global Control and Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |GCTLRST |Software Engine Reset + * | | |0 = No effect. + * | | |1 = Reset SD host + * | | |The contents of control register will not be cleared + * | | |This bit will auto cleared after reset complete. + * |[1] |SDEN |Secure Digital Functionality Enable Bit + * | | |0 = SD functionality disabled. + * | | |1 = SD functionality enabled. + * @var SDH_T::GINTEN + * Offset: 0x804 Global Interrupt Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |DTAIEN |DMA READ/WRITE Target Abort Interrupt Enable Bit + * | | |0 = DMA READ/WRITE target abort interrupt generation disabled. + * | | |1 = DMA READ/WRITE target abort interrupt generation enabled. + * @var SDH_T::GINTSTS + * Offset: 0x808 Global Interrupt Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |DTAIF |DMA READ/WRITE Target Abort Interrupt Flag (Read Only) + * | | |This bit indicates DMA received an ERROR response from internal AHB bus during DMA read/write operation + * | | |When Target Abort is occurred, please reset all engine. + * | | |0 = No bus ERROR response received. + * | | |1 = Bus ERROR response received. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * @var SDH_T::CTL + * Offset: 0x820 SD Control and Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |COEN |Command Output Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will output a command to SD card. + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[1] |RIEN |Response Input Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will wait to receive a response from SD card. + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[2] |DIEN |Data Input Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will wait to receive block data and the CRC16 value from SD card. + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[3] |DOEN |Data Output Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will transfer block data and the CRC16 value to SD card. + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[4] |R2EN |Response R2 Input Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will wait to receive a response R2 from SD card and store the response data into DMC's flash buffer (exclude CRC7). + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[5] |CLK74OEN |Initial 74 Clock Cycles Output Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will output 74 clock cycles to SD card. + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[6] |CLK8OEN |Generating 8 Clock Cycles Output Enable Bit + * | | |0 = No effect. (Please use DMARST (SDH_CTL [0]) to clear this bit.) + * | | |1 = Enabled, SD host will output 8 clock cycles. + * | | |Note: When operation is finished, this bit will be cleared automatically, so don't write 0 to this bit (the controller will be abnormal). + * |[7] |CLKKEEP |SD Clock Enable Control + * | | |0 = SD host decided when to output clock and when to disable clock output automatically. + * | | |1 = SD clock always keeps free running. + * |[13:8] |CMDCODE |SD Command Code + * | | |This register contains the SD command code (0x00 - 0x3F). + * |[14] |CTLRST |Software Engine Reset + * | | |0 = No effect. + * | | |1 = Reset the internal state machine and counters + * | | |The contents of control register will not be cleared (but RIEN, DIEN, DOEN and R2_EN will be cleared) + * | | |This bit will be auto cleared after few clock cycles. + * |[15] |DBW |SD Data Bus Width (for 1-bit / 4-bit Selection) + * | | |0 = Data bus width is 1-bit. + * | | |1 = Data bus width is 4-bit. + * |[23:16] |BLKCNT |Block Counts to Be Transferred or Received + * | | |This field contains the block counts for data-in and data-out transfer + * | | |For READ_MULTIPLE_BLOCK and WRITE_MULTIPLE_BLOCK command, software can use this function to accelerate data transfer and improve performance + * | | |Don't fill 0x0 to this field. + * | | |Note: For READ_MULTIPLE_BLOCK and WRITE_MULTIPLE_BLOCK command, the actual total length is BLKCNT * (BLKLEN +1). + * |[27:24] |SDNWR |NWR Parameter for Block Write Operation + * | | |This value indicates the NWR parameter for data block write operation in SD clock counts + * | | |The actual clock cycle will be SDNWR+1. + * @var SDH_T::CMDARG + * Offset: 0x824 SD Command Argument Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |ARGUMENT |SD Command Argument + * | | |This register contains a 32-bit value specifies the argument of SD command from host controller to SD card + * | | |Before trigger COEN (SDH_CTL [0]), software should fill argument in this field. + * @var SDH_T::INTEN + * Offset: 0x828 SD Interrupt Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |BLKDIEN |Block Transfer Done Interrupt Enable Bit + * | | |0 = BLKDIF (SDH_INTEN[0]) trigger interrupt Disable. + * | | |1 = BLKDIF (SDH_INTEN[0]) trigger interrupt Enabled. + * |[1] |CRCIEN |CRC7, CRC16 and CRC Status Error Interrupt Enable Bit + * | | |0 = CRCIF (SDH_INTEN[1]) trigger interrupt Disable. + * | | |1 = CRCIF (SDH_INTEN[1]) trigger interrupt Enabled. + * |[8] |CDIEN |SD Card Detection Interrupt Enable Bit + * | | |Enable/Disable interrupts generation of SD controller when card is inserted or removed. + * | | |0 = CDIF (SDH_INTEN[8]) trigger interrupt Disable. + * | | |1 = CDIF (SDH_INTEN[8]) trigger interrupt Enabled. + * |[12] |RTOIEN |Response Time-out Interrupt Enable Bit + * | | |Enable/Disable interrupts generation of SD controller when receiving response or R2 time-out + * | | |Time-out value is specified at TOUT register. + * | | |0 = RTOIF (SDH_INTEN[12]) trigger interrupt Disabled. + * | | |1 = RTOIF (SDH_INTEN[12]) trigger interrupt Enabled. + * |[13] |DITOIEN |Data Input Time-out Interrupt Enable Bit + * | | |Enable/Disable interrupts generation of SD controller when data input time-out + * | | |Time-out value is specified at TOUT register. + * | | |0 = DITOIF (SDH_INTEN[13]) trigger interrupt Disabled. + * | | |1 = DITOIF (SDH_INTEN[13]) trigger interrupt Enabled. + * |[14] |WKIEN |Wake-up Signal Generating Enable Bit + * | | |Enable/Disable wake-up signal generating of SD host when current using SD card issues an interrupt (wake-up) via DAT [1] to host. + * | | |0 = SD Card interrupt to wake-up chip Disabled. + * | | |1 = SD Card interrupt to wake-up chip Enabled. + * |[30] |CDSRC |SD Card Detect Source Selection + * | | |0 = From SD card's DAT3 pin. + * | | |Host need clock to got data on pin DAT3 + * | | |Please make sure CLKKEEP (SDH_CTL[7]) is 1 in order to generate free running clock for DAT3 pin. + * | | |1 = From GPIO pin. + * @var SDH_T::INTSTS + * Offset: 0x82C SD Interrupt Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |BLKDIF |Block Transfer Done Interrupt Flag (Read Only) + * | | |This bit indicates that SD host has finished all data-in or data-out block transfer + * | | |If there is a CRC16 error or incorrect CRC status during multiple block data transfer, the transfer will be broken and this bit will also be set. + * | | |0 = Not finished yet. + * | | |1 = Done. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * |[1] |CRCIF |CRC7, CRC16 and CRC Status Error Interrupt Flag (Read Only) + * | | |This bit indicates that SD host has occurred CRC error during response in, data-in or data-out (CRC status error) transfer + * | | |When CRC error is occurred, software should reset SD engine + * | | |Some response (ex + * | | |R3) doesn't have CRC7 information with it; SD host will still calculate CRC7, get CRC error and set this flag + * | | |In this condition, software should ignore CRC error and clears this bit manually. + * | | |0 = No CRC error is occurred. + * | | |1 = CRC error is occurred. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * |[2] |CRC7 |CRC7 Check Status (Read Only) + * | | |SD host will check CRC7 correctness during each response in + * | | |If that response does not contain CRC7 information (ex + * | | |R3), then software should turn off CRCIEN (SDH_INTEN[1]) and ignore this bit. + * | | |0 = Fault. + * | | |1 = OK. + * |[3] |CRC16 |CRC16 Check Status of Data-in Transfer (Read Only) + * | | |SD host will check CRC16 correctness after data-in transfer. + * | | |0 = Fault. + * | | |1 = OK. + * |[6:4] |CRCSTS |CRC Status Value of Data-out Transfer (Read Only) + * | | |SD host will record CRC status of data-out transfer + * | | |Software could use this value to identify what type of error is during data-out transfer. + * | | |010 = Positive CRC status. + * | | |101 = Negative CRC status. + * | | |111 = SD card programming error occurs. + * |[7] |DAT0STS |DAT0 Pin Status of Current Selected SD Port (Read Only) + * | | |This bit is the DAT0 pin status of current selected SD port. + * |[8] |CDIF |SD Card Detection Interrupt Flag (Read Only) + * | | |This bit indicates that SD card is inserted or removed + * | | |Only when CDIEN (SDH_INTEN[8]) is set to 1, this bit is active. + * | | |0 = No card is inserted or removed. + * | | |1 = There is a card inserted in or removed from SD. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * |[12] |RTOIF |Response Time-out Interrupt Flag (Read Only) + * | | |This bit indicates that SD host counts to time-out value when receiving response or R2 (waiting start bit). + * | | |0 = Not time-out. + * | | |1 = Response time-out. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * |[13] |DITOIF |Data Input Time-out Interrupt Flag (Read Only) + * | | |This bit indicates that SD host counts to time-out value when receiving data (waiting start bit). + * | | |0 = Not time-out. + * | | |1 = Data input time-out. + * | | |Note: This bit is read only, but can be cleared by writing '1' to it. + * |[16] |CDSTS |Card Detect Status of SD (Read Only) + * | | |This bit indicates the card detect pin status of SD, and is used for card detection + * | | |When there is a card inserted in or removed from SD, software should check this bit to confirm if there is really a card insertion or removal. + * | | |If CDSRC (SDH_INTEN[30]) = 0, to select DAT3 for card detection:. + * | | |0 = Card removed. + * | | |1 = Card inserted. + * | | |If CDSRC (SDH_INTEN[30]) = 1, to select GPIO for card detection:. + * | | |0 = Card inserted. + * | | |1 = Card removed. + * |[18] |DAT1STS |DAT1 Pin Status of SD Port (Read Only) + * | | |This bit indicates the DAT1 pin status of SD port. + * @var SDH_T::RESP0 + * Offset: 0x830 SD Receiving Response Token Register 0 + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:0] |RESPTK0 |SD Receiving Response Token 0 + * | | |SD host controller will receive a response token for getting a reply from SD card when RIEN (SDH_CTL[1]) is set + * | | |This field contains response bit 47-16 of the response token. + * @var SDH_T::RESP1 + * Offset: 0x834 SD Receiving Response Token Register 1 + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |RESPTK1 |SD Receiving Response Token 1 + * | | |SD host controller will receive a response token for getting a reply from SD card when RIEN (SDH_CTL[1]) is set + * | | |This register contains the bit 15-8 of the response token. + * @var SDH_T::BLEN + * Offset: 0x838 SD Block Length Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[10:0] |BLKLEN |SD BLOCK LENGTH in Byte Unit + * | | |An 11-bit value specifies the SD transfer byte count of a block + * | | |The actual byte count is equal to BLKLEN+1. + * | | |Note: The default SD block length is 512 bytes + * @var SDH_T::TOUT + * Offset: 0x83C SD Response/Data-in Time-out Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[23:0] |TOUT |SD Response/Data-in Time-out Value + * | | |A 24-bit value specifies the time-out counts of response and data input + * | | |SD host controller will wait start bit of response or data-in until this value reached + * | | |The time period depends on SD engine clock frequency + * | | |Do not write a small number into this field, or you may never get response or data due to time-out. + * | | |Note: Filling 0x0 into this field will disable hardware time-out function. + */ + + __IO uint32_t FB[32]; /*!< Shared Buffer (FIFO) */ + /// @cond HIDDEN_SYMBOLS + __I uint32_t RESERVE0[224]; + /// @endcond //HIDDEN_SYMBOLS + __IO uint32_t DMACTL; /*!< [0x0400] DMA Control and Status Register */ + /// @cond HIDDEN_SYMBOLS + __I uint32_t RESERVE1[1]; + /// @endcond //HIDDEN_SYMBOLS + __IO uint32_t DMASA; /*!< [0x0408] DMA Transfer Starting Address Register */ + __I uint32_t DMABCNT; /*!< [0x040c] DMA Transfer Byte Count Register */ + __IO uint32_t DMAINTEN; /*!< [0x0410] DMA Interrupt Enable Control Register */ + __IO uint32_t DMAINTSTS; /*!< [0x0414] DMA Interrupt Status Register */ + /// @cond HIDDEN_SYMBOLS + __I uint32_t RESERVE2[250]; + /// @endcond //HIDDEN_SYMBOLS + __IO uint32_t GCTL; /*!< [0x0800] Global Control and Status Register */ + __IO uint32_t GINTEN; /*!< [0x0804] Global Interrupt Control Register */ + __I uint32_t GINTSTS; /*!< [0x0808] Global Interrupt Status Register */ + /// @cond HIDDEN_SYMBOLS + __I uint32_t RESERVE3[5]; + /// @endcond //HIDDEN_SYMBOLS + __IO uint32_t CTL; /*!< [0x0820] SD Control and Status Register */ + __IO uint32_t CMDARG; /*!< [0x0824] SD Command Argument Register */ + __IO uint32_t INTEN; /*!< [0x0828] SD Interrupt Control Register */ + __IO uint32_t INTSTS; /*!< [0x082c] SD Interrupt Status Register */ + __I uint32_t RESP0; /*!< [0x0830] SD Receiving Response Token Register 0 */ + __I uint32_t RESP1; /*!< [0x0834] SD Receiving Response Token Register 1 */ + __IO uint32_t BLEN; /*!< [0x0838] SD Block Length Register */ + __IO uint32_t TOUT; /*!< [0x083c] SD Response/Data-in Time-out Register */ + +} SDH_T; + + +/** + @addtogroup SDH_CONST SDH Bit Field Definition + Constant Definitions for SDH Controller +@{ */ + +#define SDH_DMACTL_DMAEN_Pos (0) /*!< SDH_T::DMACTL: DMAEN Position */ +#define SDH_DMACTL_DMAEN_Msk (0x1ul << SDH_DMACTL_DMAEN_Pos) /*!< SDH_T::DMACTL: DMAEN Mask */ + +#define SDH_DMACTL_DMARST_Pos (1) /*!< SDH_T::DMACTL: DMARST Position */ +#define SDH_DMACTL_DMARST_Msk (0x1ul << SDH_DMACTL_DMARST_Pos) /*!< SDH_T::DMACTL: DMARST Mask */ + +#define SDH_DMACTL_SGEN_Pos (3) /*!< SDH_T::DMACTL: SGEN Position */ +#define SDH_DMACTL_SGEN_Msk (0x1ul << SDH_DMACTL_SGEN_Pos) /*!< SDH_T::DMACTL: SGEN Mask */ + +#define SDH_DMACTL_DMABUSY_Pos (9) /*!< SDH_T::DMACTL: DMABUSY Position */ +#define SDH_DMACTL_DMABUSY_Msk (0x1ul << SDH_DMACTL_DMABUSY_Pos) /*!< SDH_T::DMACTL: DMABUSY Mask */ + +#define SDH_DMASA_ORDER_Pos (0) /*!< SDH_T::DMASA: ORDER Position */ +#define SDH_DMASA_ORDER_Msk (0x1ul << SDH_DMASA_ORDER_Pos) /*!< SDH_T::DMASA: ORDER Mask */ + +#define SDH_DMASA_DMASA_Pos (1) /*!< SDH_T::DMASA: DMASA Position */ +#define SDH_DMASA_DMASA_Msk (0x7ffffffful << SDH_DMASA_DMASA_Pos) /*!< SDH_T::DMASA: DMASA Mask */ + +#define SDH_DMABCNT_BCNT_Pos (0) /*!< SDH_T::DMABCNT: BCNT Position */ +#define SDH_DMABCNT_BCNT_Msk (0x3fffffful << SDH_DMABCNT_BCNT_Pos) /*!< SDH_T::DMABCNT: BCNT Mask */ + +#define SDH_DMAINTEN_ABORTIEN_Pos (0) /*!< SDH_T::DMAINTEN: ABORTIEN Position */ +#define SDH_DMAINTEN_ABORTIEN_Msk (0x1ul << SDH_DMAINTEN_ABORTIEN_Pos) /*!< SDH_T::DMAINTEN: ABORTIEN Mask */ + +#define SDH_DMAINTEN_WEOTIEN_Pos (1) /*!< SDH_T::DMAINTEN: WEOTIEN Position */ +#define SDH_DMAINTEN_WEOTIEN_Msk (0x1ul << SDH_DMAINTEN_WEOTIEN_Pos) /*!< SDH_T::DMAINTEN: WEOTIEN Mask */ + +#define SDH_DMAINTSTS_ABORTIF_Pos (0) /*!< SDH_T::DMAINTSTS: ABORTIF Position */ +#define SDH_DMAINTSTS_ABORTIF_Msk (0x1ul << SDH_DMAINTSTS_ABORTIF_Pos) /*!< SDH_T::DMAINTSTS: ABORTIF Mask */ + +#define SDH_DMAINTSTS_WEOTIF_Pos (1) /*!< SDH_T::DMAINTSTS: WEOTIF Position */ +#define SDH_DMAINTSTS_WEOTIF_Msk (0x1ul << SDH_DMAINTSTS_WEOTIF_Pos) /*!< SDH_T::DMAINTSTS: WEOTIF Mask */ + +#define SDH_GCTL_GCTLRST_Pos (0) /*!< SDH_T::GCTL: GCTLRST Position */ +#define SDH_GCTL_GCTLRST_Msk (0x1ul << SDH_GCTL_GCTLRST_Pos) /*!< SDH_T::GCTL: GCTLRST Mask */ + +#define SDH_GCTL_SDEN_Pos (1) /*!< SDH_T::GCTL: SDEN Position */ +#define SDH_GCTL_SDEN_Msk (0x1ul << SDH_GCTL_SDEN_Pos) /*!< SDH_T::GCTL: SDEN Mask */ + +#define SDH_GINTEN_DTAIEN_Pos (0) /*!< SDH_T::GINTEN: DTAIEN Position */ +#define SDH_GINTEN_DTAIEN_Msk (0x1ul << SDH_GINTEN_DTAIEN_Pos) /*!< SDH_T::GINTEN: DTAIEN Mask */ + +#define SDH_GINTSTS_DTAIF_Pos (0) /*!< SDH_T::GINTSTS: DTAIF Position */ +#define SDH_GINTSTS_DTAIF_Msk (0x1ul << SDH_GINTSTS_DTAIF_Pos) /*!< SDH_T::GINTSTS: DTAIF Mask */ + +#define SDH_CTL_COEN_Pos (0) /*!< SDH_T::CTL: COEN Position */ +#define SDH_CTL_COEN_Msk (0x1ul << SDH_CTL_COEN_Pos) /*!< SDH_T::CTL: COEN Mask */ + +#define SDH_CTL_RIEN_Pos (1) /*!< SDH_T::CTL: RIEN Position */ +#define SDH_CTL_RIEN_Msk (0x1ul << SDH_CTL_RIEN_Pos) /*!< SDH_T::CTL: RIEN Mask */ + +#define SDH_CTL_DIEN_Pos (2) /*!< SDH_T::CTL: DIEN Position */ +#define SDH_CTL_DIEN_Msk (0x1ul << SDH_CTL_DIEN_Pos) /*!< SDH_T::CTL: DIEN Mask */ + +#define SDH_CTL_DOEN_Pos (3) /*!< SDH_T::CTL: DOEN Position */ +#define SDH_CTL_DOEN_Msk (0x1ul << SDH_CTL_DOEN_Pos) /*!< SDH_T::CTL: DOEN Mask */ + +#define SDH_CTL_R2EN_Pos (4) /*!< SDH_T::CTL: R2EN Position */ +#define SDH_CTL_R2EN_Msk (0x1ul << SDH_CTL_R2EN_Pos) /*!< SDH_T::CTL: R2EN Mask */ + +#define SDH_CTL_CLK74OEN_Pos (5) /*!< SDH_T::CTL: CLK74OEN Position */ +#define SDH_CTL_CLK74OEN_Msk (0x1ul << SDH_CTL_CLK74OEN_Pos) /*!< SDH_T::CTL: CLK74OEN Mask */ + +#define SDH_CTL_CLK8OEN_Pos (6) /*!< SDH_T::CTL: CLK8OEN Position */ +#define SDH_CTL_CLK8OEN_Msk (0x1ul << SDH_CTL_CLK8OEN_Pos) /*!< SDH_T::CTL: CLK8OEN Mask */ + +#define SDH_CTL_CLKKEEP_Pos (7) /*!< SDH_T::CTL: CLKKEEP Position */ +#define SDH_CTL_CLKKEEP_Msk (0x1ul << SDH_CTL_CLKKEEP_Pos) /*!< SDH_T::CTL: CLKKEEP Mask */ + +#define SDH_CTL_CMDCODE_Pos (8) /*!< SDH_T::CTL: CMDCODE Position */ +#define SDH_CTL_CMDCODE_Msk (0x3ful << SDH_CTL_CMDCODE_Pos) /*!< SDH_T::CTL: CMDCODE Mask */ + +#define SDH_CTL_CTLRST_Pos (14) /*!< SDH_T::CTL: CTLRST Position */ +#define SDH_CTL_CTLRST_Msk (0x1ul << SDH_CTL_CTLRST_Pos) /*!< SDH_T::CTL: CTLRST Mask */ + +#define SDH_CTL_DBW_Pos (15) /*!< SDH_T::CTL: DBW Position */ +#define SDH_CTL_DBW_Msk (0x1ul << SDH_CTL_DBW_Pos) /*!< SDH_T::CTL: DBW Mask */ + +#define SDH_CTL_BLKCNT_Pos (16) /*!< SDH_T::CTL: BLKCNT Position */ +#define SDH_CTL_BLKCNT_Msk (0xfful << SDH_CTL_BLKCNT_Pos) /*!< SDH_T::CTL: BLKCNT Mask */ + +#define SDH_CTL_SDNWR_Pos (24) /*!< SDH_T::CTL: SDNWR Position */ +#define SDH_CTL_SDNWR_Msk (0xful << SDH_CTL_SDNWR_Pos) /*!< SDH_T::CTL: SDNWR Mask */ + +#define SDH_CTL_SDPORT_Pos (29) /*!< SDH CTL: SDPORT Position */ +#define SDH_CTL_SDPORT_Msk (0x3ul << SDH_CTL_SDPORT_Pos) /*!< SDH CTL: SDPORT Mask */ + +#define SDH_CTL_CLKKEEP1_Pos (31) /*!< SDH CTL: CLKKEEP1 Position */ +#define SDH_CTL_CLKKEEP1_Msk (0x1ul << SDH_CTL_CLKKEEP1_Pos) /*!< SDH CTL: CLKKEEP1 Mask */ + +#define SDH_CMDARG_ARGUMENT_Pos (0) /*!< SDH_T::CMDARG: ARGUMENT Position */ +#define SDH_CMDARG_ARGUMENT_Msk (0xfffffffful << SDH_CMDARG_ARGUMENT_Pos) /*!< SDH_T::CMDARG: ARGUMENT Mask */ + +#define SDH_INTEN_BLKDIEN_Pos (0) /*!< SDH_T::INTEN: BLKDIEN Position */ +#define SDH_INTEN_BLKDIEN_Msk (0x1ul << SDH_INTEN_BLKDIEN_Pos) /*!< SDH_T::INTEN: BLKDIEN Mask */ + +#define SDH_INTEN_CRCIEN_Pos (1) /*!< SDH_T::INTEN: CRCIEN Position */ +#define SDH_INTEN_CRCIEN_Msk (0x1ul << SDH_INTEN_CRCIEN_Pos) /*!< SDH_T::INTEN: CRCIEN Mask */ + +#define SDH_INTEN_CDIEN_Pos (8) /*!< SDH_T::INTEN: CDIEN Position */ +#define SDH_INTEN_CDIEN_Msk (0x1ul << SDH_INTEN_CDIEN_Pos) /*!< SDH_T::INTEN: CDIEN Mask */ + +#define SDH_INTEN_CDIEN1_Pos (9) /*!< SDH INTEN: CDIEN1 Position */ +#define SDH_INTEN_CDIEN1_Msk (0x1ul << SDH_INTEN_CDIEN1_Pos) /*!< SDH INTEN: CDIEN1 Mask */ + +#define SDH_INTEN_SDHOST0IEN_Pos (10) /*!< SDH INTSTS: SDHOST0IEN Position */ +#define SDH_INTEN_SDHOST0IEN_Msk (0x1ul << SDH_INTEN_SDHOST0IEN_Pos) /*!< SDH INTSTS: SDHOST0IEN Mask */ + +#define SDH_INTEN_SDHOST1IEN_Pos (11) /*!< SDH INTSTS: SDHOST1IEN Position */ +#define SDH_INTEN_SDHOST1IEN_Msk (0x1ul << SDH_INTEN_SDHOST1IEN_Pos) /*!< SDH INTSTS: SDHOST1IEN Mask */ + +#define SDH_INTEN_RTOIEN_Pos (12) /*!< SDH INTEN: RTOIEN Position */ +#define SDH_INTEN_RTOIEN_Msk (0x1ul << SDH_INTEN_RTOIEN_Pos) /*!< SDH INTEN: RTOIEN Mask */ + +#define SDH_INTEN_DITOIEN_Pos (13) /*!< SDH_T::INTEN: DITOIEN Position */ +#define SDH_INTEN_DITOIEN_Msk (0x1ul << SDH_INTEN_DITOIEN_Pos) /*!< SDH_T::INTEN: DITOIEN Mask */ + +#define SDH_INTEN_WKIEN_Pos (14) /*!< SDH_T::INTEN: WKIEN Position */ +#define SDH_INTEN_WKIEN_Msk (0x1ul << SDH_INTEN_WKIEN_Pos) /*!< SDH_T::INTEN: WKIEN Mask */ + +#define SDH_INTEN_CDSRC_Pos (30) /*!< SDH_T::INTEN: CDSRC Position */ +#define SDH_INTEN_CDSRC_Msk (0x1ul << SDH_INTEN_CDSRC_Pos) /*!< SDH_T::INTEN: CDSRC Mask */ + +#define SDH_INTEN_CDSRC1_Pos (31) /*!< SDH INTEN: CDSRC1 Position */ +#define SDH_INTEN_CDSRC1_Msk (0x1ul << SDH_INTEN_CDSRC1_Pos) /*!< SDH INTEN: CDSRC1 Mask */ + +#define SDH_INTSTS_BLKDIF_Pos (0) /*!< SDH_T::INTSTS: BLKDIF Position */ +#define SDH_INTSTS_BLKDIF_Msk (0x1ul << SDH_INTSTS_BLKDIF_Pos) /*!< SDH_T::INTSTS: BLKDIF Mask */ + +#define SDH_INTSTS_CRCIF_Pos (1) /*!< SDH_T::INTSTS: CRCIF Position */ +#define SDH_INTSTS_CRCIF_Msk (0x1ul << SDH_INTSTS_CRCIF_Pos) /*!< SDH_T::INTSTS: CRCIF Mask */ + +#define SDH_INTSTS_CRC7_Pos (2) /*!< SDH_T::INTSTS: CRC7 Position */ +#define SDH_INTSTS_CRC7_Msk (0x1ul << SDH_INTSTS_CRC7_Pos) /*!< SDH_T::INTSTS: CRC7 Mask */ + +#define SDH_INTSTS_CRC16_Pos (3) /*!< SDH_T::INTSTS: CRC16 Position */ +#define SDH_INTSTS_CRC16_Msk (0x1ul << SDH_INTSTS_CRC16_Pos) /*!< SDH_T::INTSTS: CRC16 Mask */ + +#define SDH_INTSTS_CRCSTS_Pos (4) /*!< SDH_T::INTSTS: CRCSTS Position */ +#define SDH_INTSTS_CRCSTS_Msk (0x7ul << SDH_INTSTS_CRCSTS_Pos) /*!< SDH_T::INTSTS: CRCSTS Mask */ + +#define SDH_INTSTS_DAT0STS_Pos (7) /*!< SDH_T::INTSTS: DAT0STS Position */ +#define SDH_INTSTS_DAT0STS_Msk (0x1ul << SDH_INTSTS_DAT0STS_Pos) /*!< SDH_T::INTSTS: DAT0STS Mask */ + +#define SDH_INTSTS_CDIF_Pos (8) /*!< SDH_T::INTSTS: CDIF Position */ +#define SDH_INTSTS_CDIF_Msk (0x1ul << SDH_INTSTS_CDIF_Pos) /*!< SDH_T::INTSTS: CDIF Mask */ + +#define SDH_INTSTS_CDIF1_Pos (9) /*!< SDH INTSTS: CDIF1 Position */ +#define SDH_INTSTS_CDIF1_Msk (0x1ul << SDH_INTSTS_CDIF1_Pos) /*!< SDH INTSTS: CDIF1 Mask */ + +#define SDH_INTSTS_SDHOST0IF_Pos (10) /*!< SDH INTSTS: SDHOST0IF Position */ +#define SDH_INTSTS_SDHOST0IF_Msk (0x1ul << SDH_INTSTS_SDHOST0IF_Pos) /*!< SDH INTSTS: SDHOST0IF Mask */ + +#define SDH_INTSTS_SDHOST1IF_Pos (11) /*!< SDH INTSTS: SDHOST1IF Position */ +#define SDH_INTSTS_SDHOST1IF_Msk (0x1ul << SDH_INTSTS_SDHOST1IF_Pos) /*!< SDH INTSTS: SDHOST1IF Mask */ + +#define SDH_INTSTS_RTOIF_Pos (12) /*!< SDH_T::INTSTS: RTOIF Position */ +#define SDH_INTSTS_RTOIF_Msk (0x1ul << SDH_INTSTS_RTOIF_Pos) /*!< SDH_T::INTSTS: RTOIF Mask */ + +#define SDH_INTSTS_DITOIF_Pos (13) /*!< SDH_T::INTSTS: DITOIF Position */ +#define SDH_INTSTS_DITOIF_Msk (0x1ul << SDH_INTSTS_DITOIF_Pos) /*!< SDH_T::INTSTS: DITOIF Mask */ + +#define SDH_INTSTS_CDSTS_Pos (16) /*!< SDH_T::INTSTS: CDSTS Position */ +#define SDH_INTSTS_CDSTS_Msk (0x1ul << SDH_INTSTS_CDSTS_Pos) /*!< SDH_T::INTSTS: CDSTS Mask */ + +#define SDH_INTSTS_CDSTS1_Pos (17) /*!< SDH INTSTS: CDSTS1 Position */ +#define SDH_INTSTS_CDSTS1_Msk (0x1ul << SDH_INTSTS_CDSTS1_Pos) /*!< SDH INTSTS: CDSTS1 Mask */ + +#define SDH_INTSTS_DAT1STS_Pos (18) /*!< SDH_T::INTSTS: DAT1STS Position */ +#define SDH_INTSTS_DAT1STS_Msk (0x1ul << SDH_INTSTS_DAT1STS_Pos) /*!< SDH_T::INTSTS: DAT1STS Mask */ + +#define SDH_RESP0_RESPTK0_Pos (0) /*!< SDH_T::RESP0: RESPTK0 Position */ +#define SDH_RESP0_RESPTK0_Msk (0xfffffffful << SDH_RESP0_RESPTK0_Pos) /*!< SDH_T::RESP0: RESPTK0 Mask */ + +#define SDH_RESP1_RESPTK1_Pos (0) /*!< SDH_T::RESP1: RESPTK1 Position */ +#define SDH_RESP1_RESPTK1_Msk (0xfful << SDH_RESP1_RESPTK1_Pos) /*!< SDH_T::RESP1: RESPTK1 Mask */ + +#define SDH_BLEN_BLKLEN_Pos (0) /*!< SDH_T::BLEN: BLKLEN Position */ +#define SDH_BLEN_BLKLEN_Msk (0x7fful << SDH_BLEN_BLKLEN_Pos) /*!< SDH_T::BLEN: BLKLEN Mask */ + +#define SDH_TOUT_TOUT_Pos (0) /*!< SDH_T::TOUT: TOUT Position */ +#define SDH_TOUT_TOUT_Msk (0xfffffful << SDH_TOUT_TOUT_Pos) /*!< SDH_T::TOUT: TOUT Mask */ + +/**@}*/ /* SDH_CONST */ +/**@}*/ /* end of SDH register group */ +/**@}*/ /* end of REGISTER group */ + +#define SDH0 ((SDH_T *) FMI_BA) +#define SDH1 ((SDH_T *) SDH_BA) + +/** @addtogroup Standard_Driver Standard Driver + @{ +*/ + +/** @addtogroup SDH_Driver SDH Driver + @{ +*/ + + +/** @addtogroup SDH_EXPORTED_CONSTANTS SDH Exported Constants + @{ +*/ + +#define SDH_ERR_ID 0xFFFF0100ul /*!< SDH error ID \hideinitializer */ + +#define SDH_TIMEOUT (SDH_ERR_ID|0x01ul) /*!< Timeout \hideinitializer */ +#define SDH_NO_MEMORY (SDH_ERR_ID|0x02ul) /*!< OOM \hideinitializer */ + +/*--- define type of SD card or MMC */ +#define SDH_TYPE_UNKNOWN 0ul /*!< Unknown card type \hideinitializer */ +#define SDH_TYPE_SD_HIGH 1ul /*!< SDHC card \hideinitializer */ +#define SDH_TYPE_SD_LOW 2ul /*!< SD card \hideinitializer */ +#define SDH_TYPE_MMC 3ul /*!< MMC card \hideinitializer */ +#define SDH_TYPE_EMMC 4ul /*!< eMMC card \hideinitializer */ + +/* SD error */ +#define SDH_NO_SD_CARD (SDH_ERR_ID|0x10ul) /*!< Card removed \hideinitializer */ +#define SDH_ERR_DEVICE (SDH_ERR_ID|0x11ul) /*!< Device error \hideinitializer */ +#define SDH_INIT_TIMEOUT (SDH_ERR_ID|0x12ul) /*!< Card init timeout \hideinitializer */ +#define SDH_SELECT_ERROR (SDH_ERR_ID|0x13ul) /*!< Card select error \hideinitializer */ +#define SDH_WRITE_PROTECT (SDH_ERR_ID|0x14ul) /*!< Card write protect \hideinitializer */ +#define SDH_INIT_ERROR (SDH_ERR_ID|0x15ul) /*!< Card init error \hideinitializer */ +#define SDH_CRC7_ERROR (SDH_ERR_ID|0x16ul) /*!< CRC 7 error \hideinitializer */ +#define SDH_CRC16_ERROR (SDH_ERR_ID|0x17ul) /*!< CRC 16 error \hideinitializer */ +#define SDH_CRC_ERROR (SDH_ERR_ID|0x18ul) /*!< CRC error \hideinitializer */ +#define SDH_CMD8_ERROR (SDH_ERR_ID|0x19ul) /*!< Command 8 error \hideinitializer */ + +#define MMC_FREQ 20000ul /*!< output 20MHz to MMC \hideinitializer */ +#define SD_FREQ 25000ul /*!< output 25MHz to SD \hideinitializer */ +#define SDHC_FREQ 50000ul /*!< output 50MHz to SDH \hideinitializer */ + +#define SD_PORT0 (1 << 0) /*!< Card select SD0 \hideinitializer */ +#define SD_PORT1 (1 << 2) /*!< Card select SD1 \hideinitializer */ +#define CardDetect_From_GPIO (1ul << 8) /*!< Card detection pin is GPIO \hideinitializer */ +#define CardDetect_From_DAT3 (1ul << 9) /*!< Card detection pin is DAT3 \hideinitializer */ + +/*@}*/ /* end of group N9H30_SDH_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_SDH_EXPORTED_TYPEDEF SDH Exported Type Defines + @{ +*/ + +/** \brief Structure type of inserted Card information. + */ +typedef struct SDH_info_t +{ + unsigned char IsCardInsert; /*!< Card insert state */ + unsigned char R3Flag; + unsigned char R7Flag; + unsigned char volatile DataReadyFlag; + unsigned int CardType; /*!< SDHC, SD, or MMC */ + unsigned int RCA; /*!< Relative card address */ + unsigned int totalSectorN; /*!< Total sector number */ + unsigned int diskSize; /*!< Disk size in K bytes */ + int sectorSize; /*!< Sector size in bytes */ + unsigned char *dmabuf; +} SDH_INFO_T; /*!< Structure holds SD card info */ + +/*@}*/ /* end of group N9H30_SDH_EXPORTED_TYPEDEF */ + +/// @cond HIDDEN_SYMBOLS +extern SDH_INFO_T SD0, SD1; + +/// @endcond HIDDEN_SYMBOLS + +/** @addtogroup N9H30_SDH_EXPORTED_FUNCTIONS SDH Exported Functions + @{ +*/ + + +/** + * @brief Enable specified interrupt. + * + * @param[in] u32IntMask Interrupt type mask: + * \ref SDH_INTEN_BLKDIEN_Msk / \ref SDH_INTEN_CRCIEN_Msk / \ref SDH_INTEN_CDIEN0_Msk / \ref SDH_INTEN_CDIEN1_Msk / + * \ref SDH_INTEN_CDSRC0_Msk / \ref SDH_INTEN_CDSRC1_Msk / \ref SDH_INTEN_RTOIEN_Msk / \ref SDH_INTEN_DITOIEN_Msk / + * \ref SDH_INTEN_WKIEN_Msk + * + * @return None. + * \hideinitializer + */ +#define SDH_ENABLE_INT(sdh, u32IntMask) ((sdh)->INTEN |= (u32IntMask)) + +/** + * @brief Disable specified interrupt. + * + * @param[in] sdh Select SDH0 or SDH1. + * @param[in] u32IntMask Interrupt type mask: + * \ref SDH_INTEN_BLKDIEN_Msk / \ref SDH_INTEN_CRCIEN_Msk / \ref SDH_INTEN_CDIEN0_Msk / \ref SDH_INTEN_CDIEN1_Msk / + * \ref SDH_INTEN_SDHOST0IEN_Msk / \ref SDH_INTEN_SDHOST1IEN_Msk / \ref SDH_INTEN_RTOIEN_Msk / \ref SDH_INTEN_DITOIEN_Msk / + * \ref SDH_INTEN_WKIEN_Msk / \ref SDH_INTEN_CDSRC0_Msk / \ref SDH_INTEN_CDSRC1_Msk + * + * @return None. + * \hideinitializer + */ +#define SDH_DISABLE_INT(sdh, u32IntMask) ((sdh)->INTEN &= ~(u32IntMask)) + +/** + * @brief Get specified interrupt flag/status. + * + * @param[in] sdh Select SDH0 or SDH1. + * @param[in] u32IntMask Interrupt type mask: + * \ref SDH_INTSTS_BLKDIF_Msk / \ref SDH_INTSTS_CRCIF_Msk / \ref SDH_INTSTS_CRC7_Msk / + * \ref SDH_INTSTS_CRC16_Msk / \ref SDH_INTSTS_CRCSTS_Msk / \ref SDH_INTSTS_DAT0STS_Msk / \ref SDH_INTSTS_CDIF0_Msk / + * \ref SDH_INTSTS_CDIF1_Msk / \ref SDH_INTSTS_SDHOST0IF_Msk / \ref SDH_INTSTS_SDHOST1IF_Msk / \ref SDH_INTSTS_RTOIF_Msk / + * \ref SDH_INTSTS_DINTOIF_Msk / \ref SDH_INTSTS_CDSTS0_Msk / \ref SDH_INTSTS_CDSTS1_Msk / \ref SDH_INTSTS_DAT1STS_Msk + * + * + * @return 0 = The specified interrupt is not happened. + * 1 = The specified interrupt is happened. + * \hideinitializer + */ +#define SDH_GET_INT_FLAG(sdh, u32IntMask) (((sdh)->INTSTS & (u32IntMask))?1:0) + + +/** + * @brief Clear specified interrupt flag/status. + * + * @param[in] sdh Select SDH0 or SDH1. + * @param[in] u32IntMask Interrupt type mask: + * \ref SDH_INTSTS_BLKDIF_Msk / \ref SDH_INTSTS_CRCIF_Msk / \ref SDH_INTSTS_CDIF0_Msk / + * \ref SDH_INTSTS_CDIF1_Msk / \ref SDH_INTSTS_SDHOST0IF_Msk / \ref SDH_INTSTS_SDHOST1IF_Msk / + * \ref SDH_INTSTS_RTOIF_Msk / \ref SDH_INTSTS_DINTOIF_Msk + * + * + * @return None. + * \hideinitializer + */ +#define SDH_CLR_INT_FLAG(sdh, u32IntMask) ((sdh)->INTSTS = (u32IntMask)) + + +/** + * @brief Check SD Card inserted or removed. + * + * @param[in] sdh Select SDH0 or SDH1. + * + * @return 1: Card inserted. + * 0: Card removed. + * \hideinitializer + */ +#define SDH_IS_CARD_PRESENT(sdh) (((sdh) == SDH0)? SD0.IsCardInsert : SD1.IsCardInsert) + +/** + * @brief Get SD Card capacity. + * + * @param[in] sdh Select SDH0 or SDH1. + * + * @return SD Card capacity. (unit: KByte) + * \hideinitializer + */ +#define SDH_GET_CARD_CAPACITY(sdh) (((sdh) == SDH0)? SD0.diskSize : SD1.diskSize) + + +void SDH_Open(SDH_T *sdh, uint32_t u32CardDetSrc); +uint32_t SDH_Probe(SDH_T *sdh); +uint32_t SDH_Read(SDH_T *sdh, uint8_t *pu8BufAddr, uint32_t u32StartSec, uint32_t u32SecCount); +uint32_t SDH_Write(SDH_T *sdh, uint8_t *pu8BufAddr, uint32_t u32StartSec, uint32_t u32SecCount); + +uint32_t SDH_CardDetection(SDH_T *sdh); +void SDH_Open_Disk(SDH_T *sdh, uint32_t u32CardDetSrc); +void SDH_Close_Disk(SDH_T *sdh); + + +/*@}*/ /* end of group N9H30_SDH_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SDH_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#endif //end of __NU_SDH_H__ +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_spi.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_spi.h new file mode 100644 index 0000000000000000000000000000000000000000..a453e1dddcfc8d182f53a90ba283f1f23c808a56 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_spi.h @@ -0,0 +1,121 @@ +/**************************************************************************//** +* @file spi.h +* @brief N9H30 SPI driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#ifndef __NU_SPI_H__ +#define __NU_SPI_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_SPI_Driver SPI Driver + @{ +*/ + +/** @addtogroup N9H30_SPI_EXPORTED_CONSTANTS SPI Exported Constants + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +#define CNTRL 0x00 /*!< Control Register Address */ +#define DIVIDER 0x04 /*!< Divider Register Address */ +#define SSR 0x08 /*!< Slave Select Register Address */ +#define RX0 0x10 /*!< Receive Register 0 Address */ +#define RX1 0x14 /*!< Receive Register 1 Address */ +#define RX2 0x18 /*!< Receive Register 2 Address */ +#define RX3 0x1C /*!< Receive Register 3 Address */ +#define TX0 0x10 /*!< Transfer Register 0 Address */ +#define TX1 0x14 /*!< Transfer Register 1 Address */ +#define TX2 0x18 /*!< Transfer Register 2 Address */ +#define TX3 0x1C /*!< Transfer Register 3 Address */ + +#define SPI_INPUT_CLOCK 75000000 /* Unit: Hz */ +/// @endcond HIDDEN_SYMBOLS + +#define SPI_NUMBER 2 /*!< 2 spi interfaces */ + +#define SPI_NO_ERR 0 /*!< No error */ + +#define SPI_ERR_NODEV -1 /*!< Wrong device id */ +#define SPI_ERR_BUSY -2 /*!< Interface is busy */ +#define SPI_ERR_IO -3 /*!< IO control error for not opened interface */ +#define SPI_ERR_ARG -4 /*!< Wrong argument in IO control */ + +#define SPI_IOC_TRIGGER 0 /*!< Trigger SPI interface */ +#define SPI_IOC_SET_INTERRUPT 1 /*!< Enable/disable interrupt ,arguments could be \ref SPI_DISABLE_INTERRUPT and \ref SPI_ENABLE_INTERRUPT */ +#define SPI_IOC_SET_SPEED 2 /*!< Set SPI clock speed */ +#define SPI_IOC_SET_DUAL_QUAD_MODE 3 /*!< Enable/disable Quad/Dual mode ,arguments could be \ref SPI_DISABLE_DUAL_QUAD, \ref SPI_DUAL_MODE, \ref SPI_QUAD_MODE*/ +#define SPI_IOC_SET_DUAL_QUAD_DIR 4 /*!< Set Quad/Dual mode direction ,arguments could be \ref SPI_DUAL_QUAD_INPUT, \ref SPI_DUAL_QUAD_OUTPUT */ +#define SPI_IOC_SET_LSB_MSB 5 /*!< Set MSB/LSB ,arguments could be \ref SPI_MSB, \ref SPI_LSB */ +#define SPI_IOC_SET_TX_NUM 6 /*!< Set transfer number */ +#define SPI_IOC_SET_TX_BITLEN 7 /*!< Set transfer bit number */ +#define SPI_IOC_SET_MODE 8 /*!< Set SPI mode ,arguments could be \ref SPI_MODE_0, \ref SPI_MODE_1, \ref SPI_MODE_2, \ref SPI_MODE_3 */ +#define SPI_IOC_ENABLE_SS 9 /*!< Enable slave select pin */ +#define SPI_IOC_DISABLE_SS 10 /*!< Disable slave select pin */ +#define SPI_IOC_SET_AUTOSS 11 /*!< Enable/disable auto slave select function ,arguments could be \ref SPI_DISABLE_AUTOSS, \ref SPI_ENABLE_AUTOSS */ +#define SPI_IOC_SET_SS_ACTIVE_LEVEL 12 /*!< Set slave select active level ,arguments could be \ref SPI_SS_ACTIVE_LOW, \ref SPI_SS_ACTIVE_HIGH */ + +#define SPI_DISABLE_INTERRUPT 0 /*!< Disable interrupt */ +#define SPI_ENABLE_INTERRUPT 1 /*!< Enable interrupt */ + +#define SPI_DISABLE_DUAL_QUAD 0 /*!< Disable quad and dual mode */ +#define SPI_DUAL_MODE 1 /*!< Enable dual mode */ +#define SPI_QUAD_MODE 2 /*!< Enable quad mode */ + +#define SPI_DUAL_QUAD_INPUT 0 /*!< Set dual/quad mode io direction to input */ +#define SPI_DUAL_QUAD_OUTPUT 1 /*!< Set dual/quad mode io direction to output */ + +#define SPI_MSB 0 /*!< Enable MSB */ +#define SPI_LSB 1 /*!< Enable LSB */ + +#define SPI_MODE_0 0 /*!< Set to SPI mode 0 */ +#define SPI_MODE_1 1 /*!< Set to SPI mode 1 */ +#define SPI_MODE_2 2 /*!< Set to SPI mode 2 */ +#define SPI_MODE_3 3 /*!< Set to SPI mode 3 */ + +#define SPI_SS_SS0 0 /*!< Select SS0 */ +#define SPI_SS_SS1 1 /*!< Select SS1 */ +#define SPI_SS_BOTH 2 /*!< Select both SS0/SS1 */ + +#define SPI_DISABLE_AUTOSS 0 /*!< Disable auto slave select function */ +#define SPI_ENABLE_AUTOSS 1 /*!< Enable auto slave select function */ + +#define SPI_SS_ACTIVE_LOW 0 /*!< Set active level of slave select to low */ +#define SPI_SS_ACTIVE_HIGH 1 /*!< Set active level of slave select to high */ + +/*@}*/ /* end of group N9H30_SPI_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_SPI_EXPORTED_FUNCTIONS SPI Exported Functions + @{ +*/ + +int32_t spiInit(int32_t fd); +int32_t spiIoctl(int32_t fd, uint32_t cmd, uint32_t arg0, uint32_t arg1); +int spiOpen(int32_t fd); +uint8_t spiGetBusyStatus(int32_t fd); +uint32_t spiRead(int32_t fd, uint8_t buff_id); +void spiWrite(int32_t fd, uint8_t buff_id, uint32_t data); +/*@}*/ /* end of group N9H30_SPI_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SPI_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#ifdef __cplusplus +} +#endif + +#endif //__NU_SPI_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_sys.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_sys.h new file mode 100644 index 0000000000000000000000000000000000000000..8a4cea517bc1274416c82ee42efefbd87a7510cf --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_sys.h @@ -0,0 +1,373 @@ +/**************************************************************************//** +* @file sys.h +* @brief N9H30 SYS driver header file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_SYS_H__ +#define __NU_SYS_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_SYS_Driver SYS Driver + @{ +*/ + +/** @addtogroup N9H30_SYS_EXPORTED_CONSTANTS SYS Exported Constants + @{ +*/ + +/** + * @details Interrupt Number Definition. + */ +typedef enum IRQn +{ + + /****** N9H30 Specific Interrupt Numbers *****************************************/ + + WDT_IRQn = 1, /*!< Watch Dog Timer Interrupt */ + WWDT_IRQn = 2, /*!< Windowed-WDT Interrupt */ + LVD_IRQn = 3, /*!< Low Voltage Detect Interrupt */ + EINT0_IRQn = 4, /*!< External Interrupt 0 */ + EINT1_IRQn = 5, /*!< External Interrupt 1 */ + EINT2_IRQn = 6, /*!< External Interrupt 2 */ + EINT3_IRQn = 7, /*!< External Interrupt 3 */ + EINT4_IRQn = 8, /*!< External Interrupt 4 */ + EINT5_IRQn = 9, /*!< External Interrupt 5 */ + EINT6_IRQn = 10, /*!< External Interrupt 6 */ + EINT7_IRQn = 11, /*!< External Interrupt 7 */ + ACTL_IRQn = 12, /*!< Audio Controller Interrupt */ + LCD_IRQn = 13, /*!< LCD Controller Interrupt */ + CAP_IRQn = 14, /*!< Sensor Interface Controller Interrupt */ + RTC_IRQn = 15, /*!< Real Time Clock Interrupt */ + TMR0_IRQn = 16, /*!< Timer 0 Interrupt */ + TMR1_IRQn = 17, /*!< Timer 1 Interrupt */ + ADC_IRQn = 18, /*!< ADC Interrupt */ + EMC0_RX_IRQn = 19, /*!< EMC 0 RX Interrupt */ + EMC1_RX_IRQn = 20, /*!< EMC 1 RX Interrupt */ + EMC0_TX_IRQn = 21, /*!< EMC 0 TX Interrupt */ + EMC1_TX_IRQn = 22, /*!< EMC 1 TX Interrupt */ + EHCI_IRQn = 23, /*!< USB 2.0 Host Controller Interrupt */ + OHCI_IRQn = 24, /*!< USB 1.1 Host Controller Interrupt */ + GDMA0_IRQn = 25, /*!< GDMA Channel 0 Interrupt */ + GDMA1_IRQn = 26, /*!< GDMA Channel 1 Interrupt */ + SDH_IRQn = 27, /*!< SD/SDIO Host Interrupt */ + FMI_IRQn = 28, /*!< FMI Interrupt */ + USBD_IRQn = 29, /*!< USB Device Interrupt */ + TMR2_IRQn = 30, /*!< Timer 2 Interrupt */ + TMR3_IRQn = 31, /*!< Timer 3 Interrupt */ + TMR4_IRQn = 32, /*!< Timer 4 Interrupt */ + JPEG_IRQn = 33, /*!< JPEG Engine Interrupt */ + GE2D_IRQn = 34, /*!< 2D Graphic Engine Interrupt */ + CRPT_IRQn = 35, /*!< Cryptographic Accelerator Interrupt */ + UART0_IRQn = 36, /*!< UART 0 Interrupt */ + UART1_IRQn = 37, /*!< UART 1 Interrupt */ + UART2_IRQn = 38, /*!< UART 2 Interrupt */ + UART4_IRQn = 39, /*!< UART 4 Interrupt */ + UART6_IRQn = 40, /*!< UART 6 Interrupt */ + UART8_IRQn = 41, /*!< UART 8 Interrupt */ + UART10_IRQn = 42, /*!< UART 10 Interrupt */ + UART3_IRQn = 43, /*!< UART 3 Interrupt */ + UART5_IRQn = 44, /*!< UART 5 Interrupt */ + UART7_IRQn = 45, /*!< UART 7 Interrupt */ + UART9_IRQn = 46, /*!< UART 9 Interrupt */ + ETMR0_IRQn = 47, /*!< Enhanced Timer 0 Interrupt */ + ETMR1_IRQn = 48, /*!< Enhanced Timer 1 Interrupt */ + ETMR2_IRQn = 49, /*!< Enhanced Timer 2 Interrupt */ + ETMR3_IRQn = 50, /*!< Enhanced Timer 3 Interrupt */ + SPI0_IRQn = 51, /*!< SPI 0 Interrupt */ + SPI1_IRQn = 52, /*!< SPI 1 Interrupt */ + I2C0_IRQn = 53, /*!< I2C 0 Interrupt */ + I2C1_IRQn = 54, /*!< I2C 1 Interrupt */ + SC0_IRQn = 55, /*!< Smart Card 0 Interrupt */ + SC1_IRQn = 56, /*!< Smart Card 1 Interrupt */ + GPIO_IRQn = 57, /*!< GPIO Interrupt */ + CAN0_IRQn = 58, /*!< CAN 0 Interrupt */ + CAN1_IRQn = 59, /*!< CAN 1 Interrupt */ + PWM_IRQn = 60, /*!< PWM Interrupt */ + + /* Renaming for RTT porting */ + IRQ_WDT = 1, /*!< Watch Dog Timer Interrupt */ + IRQ_WWDT = 2, /*!< Windowed-WDT Interrupt */ + IRQ_LVD = 3, /*!< Low Voltage Detect Interrupt */ + IRQ_EINT0 = 4, /*!< External Interrupt 0 */ + IRQ_EINT1 = 5, /*!< External Interrupt 1 */ + IRQ_EINT2 = 6, /*!< External Interrupt 2 */ + IRQ_EINT3 = 7, /*!< External Interrupt 3 */ + IRQ_EINT4 = 8, /*!< External Interrupt 4 */ + IRQ_EINT5 = 9, /*!< External Interrupt 5 */ + IRQ_EINT6 = 10, /*!< External Interrupt 6 */ + IRQ_EINT7 = 11, /*!< External Interrupt 7 */ + IRQ_ACTL = 12, /*!< Audio Controller Interrupt */ + IRQ_LCD = 13, /*!< LCD Controller Interrupt */ + IRQ_CAP = 14, /*!< Sensor Interface Controller Interrupt */ + IRQ_RTC = 15, /*!< Real Time Clock Interrupt */ + IRQ_TMR0 = 16, /*!< Timer 0 Interrupt */ + IRQ_TMR1 = 17, /*!< Timer 1 Interrupt */ + IRQ_ADC = 18, /*!< ADC Interrupt */ + IRQ_EMC0_RX = 19, /*!< EMC 0 RX Interrupt */ + IRQ_EMC1_RX = 20, /*!< EMC 1 RX Interrupt */ + IRQ_EMC0_TX = 21, /*!< EMC 0 TX Interrupt */ + IRQ_EMC1_TX = 22, /*!< EMC 1 TX Interrupt */ + IRQ_EHCI = 23, /*!< USB 2.0 Host Controller Interrupt */ + IRQ_OHCI = 24, /*!< USB 1.1 Host Controller Interrupt */ + IRQ_GDMA0 = 25, /*!< GDMA Channel 0 Interrupt */ + IRQ_GDMA1 = 26, /*!< GDMA Channel 1 Interrupt */ + IRQ_SDH = 27, /*!< SD/SDIO Host Interrupt */ + IRQ_FMI = 28, /*!< FMI Interrupt */ + IRQ_USBD = 29, /*!< USB Device Interrupt */ + IRQ_TMR2 = 30, /*!< Timer 2 Interrupt */ + IRQ_TMR3 = 31, /*!< Timer 3 Interrupt */ + IRQ_TMR4 = 32, /*!< Timer 4 Interrupt */ + IRQ_JPEG = 33, /*!< JPEG Engine Interrupt */ + IRQ_GE2D = 34, /*!< 2D Graphic Engine Interrupt */ + IRQ_CRPT = 35, /*!< Cryptographic Accelerator Interrupt */ + IRQ_UART0 = 36, /*!< UART 0 Interrupt */ + IRQ_UART1 = 37, /*!< UART 1 Interrupt */ + IRQ_UART2 = 38, /*!< UART 2 Interrupt */ + IRQ_UART4 = 39, /*!< UART 4 Interrupt */ + IRQ_UART6 = 40, /*!< UART 6 Interrupt */ + IRQ_UART8 = 41, /*!< UART 8 Interrupt */ + IRQ_UART10 = 42, /*!< UART 10 Interrupt */ + IRQ_UART3 = 43, /*!< UART 3 Interrupt */ + IRQ_UART5 = 44, /*!< UART 5 Interrupt */ + IRQ_UART7 = 45, /*!< UART 7 Interrupt */ + IRQ_UART9 = 46, /*!< UART 9 Interrupt */ + IRQ_ETMR0 = 47, /*!< Enhanced Timer 0 Interrupt */ + IRQ_ETMR1 = 48, /*!< Enhanced Timer 1 Interrupt */ + IRQ_ETMR2 = 49, /*!< Enhanced Timer 2 Interrupt */ + IRQ_ETMR3 = 50, /*!< Enhanced Timer 3 Interrupt */ + IRQ_SPI0 = 51, /*!< SPI 0 Interrupt */ + IRQ_SPI1 = 52, /*!< SPI 1 Interrupt */ + IRQ_I2C0 = 53, /*!< I2C 0 Interrupt */ + IRQ_I2C1 = 54, /*!< I2C 1 Interrupt */ + IRQ_SC0 = 55, /*!< Smart Card 0 Interrupt */ + IRQ_SC1 = 56, /*!< Smart Card 1 Interrupt */ + IRQ_GPIO = 57, /*!< GPIO Interrupt */ + IRQ_CAN0 = 58, /*!< CAN 0 Interrupt */ + IRQ_CAN1 = 59, /*!< CAN 1 Interrupt */ + IRQ_PWM = 60, /*!< PWM Interrupt */ +} +IRQn_Type; + +/* Define constants for use timer in service parameters. */ +#define TIMER0 0 /*!< Select Timer0 */ +#define TIMER1 1 /*!< Select Timer1 */ + +#define ONE_SHOT_MODE 0 /*!< Timer Operation Mode - One Shot */ +#define PERIODIC_MODE 1 /*!< Timer Operation Mode - Periodic */ +#define TOGGLE_MODE 2 /*!< Timer Operation Mode - Toggle */ + +/* The parameters for sysSetInterruptPriorityLevel() and + sysInstallISR() use */ +#define FIQ_LEVEL_0 0 /*!< FIQ Level 0 */ +#define IRQ_LEVEL_1 1 /*!< IRQ Level 1 */ +#define IRQ_LEVEL_2 2 /*!< IRQ Level 2 */ +#define IRQ_LEVEL_3 3 /*!< IRQ Level 3 */ +#define IRQ_LEVEL_4 4 /*!< IRQ Level 4 */ +#define IRQ_LEVEL_5 5 /*!< IRQ Level 5 */ +#define IRQ_LEVEL_6 6 /*!< IRQ Level 6 */ +#define IRQ_LEVEL_7 7 /*!< IRQ Level 7 */ + +#define ONE_HALF_SECS 0 /*!< WDT interval - 1.5s */ +#define FIVE_SECS 1 /*!< WDT interval - 5s */ +#define TEN_SECS 2 /*!< WDT interval - 10s */ +#define TWENTY_SECS 3 /*!< WDT interval - 20s */ + +/* Define constants for use AIC in service parameters. */ +#define SYS_SWI 0 /*!< Exception - SWI */ +#define SYS_D_ABORT 1 /*!< Exception - Data abort */ +#define SYS_I_ABORT 2 /*!< Exception - Instruction abort */ +#define SYS_UNDEFINE 3 /*!< Exception - undefine */ + +/* The parameters for sysSetLocalInterrupt() use */ +#define ENABLE_IRQ 0x7F /*!< Enable I-bit of CP15 */ +#define ENABLE_FIQ 0xBF /*!< Enable F-bit of CP15 */ +#define ENABLE_FIQ_IRQ 0x3F /*!< Enable I-bit and F-bit of CP15 */ +#define DISABLE_IRQ 0x80 /*!< Disable I-bit of CP15 */ +#define DISABLE_FIQ 0x40 /*!< Disable F-bit of CP15 */ +#define DISABLE_FIQ_IRQ 0xC0 /*!< Disable I-bit and F-bit of CP15 */ + +/* Define Cache type */ +#define CACHE_WRITE_BACK 0 /*!< Cache Write-back mode */ +#define CACHE_WRITE_THROUGH 1 /*!< Cache Write-through mode */ +#define CACHE_DISABLE -1 /*!< Cache Disable */ + +/** \brief Structure type of clock source + */ +typedef enum CLKn +{ + + SYS_UPLL = 1, /*!< UPLL clock */ + SYS_APLL = 2, /*!< APLL clock */ + SYS_SYSTEM = 3, /*!< System clock */ + SYS_HCLK1 = 4, /*!< HCLK1 clock */ + SYS_HCLK234 = 5, /*!< HCLK234 clock */ + SYS_PCLK = 6, /*!< PCLK clock */ + SYS_CPU = 7, /*!< CPU clock */ + +} CLK_Type; + + + +/// @cond HIDDEN_SYMBOLS +typedef struct datetime_t +{ + UINT32 year; + UINT32 mon; + UINT32 day; + UINT32 hour; + UINT32 min; + UINT32 sec; +} DateTime_T; + +/* The parameters for sysSetInterruptType() use */ +#define LOW_LEVEL_SENSITIVE 0x00 +#define HIGH_LEVEL_SENSITIVE 0x40 +#define NEGATIVE_EDGE_TRIGGER 0x80 +#define POSITIVE_EDGE_TRIGGER 0xC0 + +/* The parameters for sysSetGlobalInterrupt() use */ +#define ENABLE_ALL_INTERRUPTS 0 +#define DISABLE_ALL_INTERRUPTS 1 + +#define MMU_DIRECT_MAPPING 0 +#define MMU_INVERSE_MAPPING 1 + + +/* Define constants for use Cache in service parameters. */ +#define CACHE_4M 2 +#define CACHE_8M 3 +#define CACHE_16M 4 +#define CACHE_32M 5 +#define I_CACHE 6 +#define D_CACHE 7 +#define I_D_CACHE 8 + + +/** + * @brief Disable register write-protection function + * @param None + * @return None + * @details This function disable register write-protection function. + * To unlock the protected register to allow write access. + */ +static __inline void SYS_UnlockReg(void) +{ + do + { + outpw(0xB00001FC, 0x59UL); + outpw(0xB00001FC, 0x16UL); + outpw(0xB00001FC, 0x88UL); + } + while (inpw(0xB00001FC) == 0UL); +} + +/** + * @brief Enable register write-protection function + * @param None + * @return None + * @details This function is used to enable register write-protection function. + * To lock the protected register to forbid write access. + */ +static __inline void SYS_LockReg(void) +{ + outpw(0xB00001FC, 0); +} + + +/// @endcond HIDDEN_SYMBOLS + +/*@}*/ /* end of group N9H30_SYS_EXPORTED_CONSTANTS */ + + +/** @addtogroup N9H30_SYS_EXPORTED_FUNCTIONS SYS Exported Functions + @{ +*/ + +/* Define system library Timer functions */ +UINT32 sysGetTicks(INT32 nTimeNo); +INT32 sysResetTicks(INT32 nTimeNo); +INT32 sysUpdateTickCount(INT32 nTimeNo, UINT32 uCount); +INT32 sysSetTimerReferenceClock(INT32 nTimeNo, UINT32 uClockRate); +INT32 sysStartTimer(INT32 nTimeNo, UINT32 uTicksPerSecond, INT32 nOpMode); +INT32 sysStopTimer(INT32 nTimeNo); +void sysClearWatchDogTimerCount(void); +void sysClearWatchDogTimerInterruptStatus(void); +void sysDisableWatchDogTimer(void); +void sysDisableWatchDogTimerReset(void); +void sysEnableWatchDogTimer(void); +void sysEnableWatchDogTimerReset(void); +PVOID sysInstallWatchDogTimerISR(INT32 nIntTypeLevel, PVOID pvNewISR); +INT32 sysSetWatchDogTimerInterval(INT32 nWdtInterval); +INT32 sysSetTimerEvent(INT32 nTimeNo, UINT32 uTimeTick, PVOID pvFun); +void sysClearTimerEvent(INT32 nTimeNo, UINT32 uTimeEventNo); +void sysSetLocalTime(DateTime_T ltime); /*!< Set local time \hideinitializer */ +void sysGetCurrentTime(DateTime_T *curTime); /*!< Get current time \hideinitializer */ +void sysDelay(UINT32 uTicks); + +/* Define system library UART functions */ +//INT8 sysGetChar(void); +//INT32 sysInitializeUART(void); +//void sysprintf(PINT8 pcStr, ...); +//void sysPutChar(UINT8 ucCh); +//INT sysIsKbHit(void); + +/* Define system library AIC functions */ +INT32 sysDisableInterrupt(IRQn_Type eIntNo); +INT32 sysEnableInterrupt(IRQn_Type eIntNo); +BOOL sysGetIBitState(void); /*!< Get I bit state \hideinitializer */ +UINT32 sysGetInterruptEnableStatus(void); /*!< Get interrupt enable status \hideinitializer */ +UINT32 sysGetInterruptEnableStatusH(void); /*!< Get interrupt enable status \hideinitializer */ +PVOID sysInstallExceptionHandler(INT32 nExceptType, PVOID pvNewHandler); +PVOID sysInstallFiqHandler(PVOID pvNewISR); +PVOID sysInstallIrqHandler(PVOID pvNewISR); +PVOID sysInstallISR(INT32 nIntTypeLevel, IRQn_Type eIntNo, PVOID pvNewISR); +INT32 sysSetGlobalInterrupt(INT32 nIntState); /*!< Enable/Disable all interrupt \hideinitializer */ +INT32 sysSetInterruptPriorityLevel(IRQn_Type eIntNo, UINT32 uIntLevel); +INT32 sysSetInterruptType(IRQn_Type eIntNo, UINT32 uIntSourceType); /*!< Change interrupt type \hideinitializer */ +INT32 sysSetLocalInterrupt(INT32 nIntState); + + +/* Define system library Cache functions */ +void sysDisableCache(void); +INT32 sysEnableCache(UINT32 uCacheOpMode); +void sysFlushCache(INT32 nCacheType); /*!< flush cache \hideinitializer */ +BOOL sysGetCacheState(void); /*!< get cache state \hideinitializer */ +INT32 sysGetSdramSizebyMB(void); /*!< Get DRAM size \hideinitializer */ +void sysInvalidCache(void); /*!< invalid cache \hideinitializer */ +INT32 sysSetCachePages(UINT32 addr, INT32 size, INT32 cache_mode); /*!< set cache page \hideinitializer */ + +int sysSetMMUMappingMethod(int mode); /*!< MMU mapping \hideinitializer */ + +UINT32 sysGetClock(CLK_Type clk); + +typedef void (*sys_pvFunPtr)(); /* function pointer */ +/// @cond HIDDEN_SYMBOLS +extern sys_pvFunPtr sysIrqHandlerTable[]; +extern BOOL volatile _sys_bIsAICInitial; +/// @endcond +#ifdef __cplusplus +} +#endif + +/*@}*/ /* end of group N9H30_SYS_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SYS_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#endif //__NU_SYS_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_timer.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..674cc86eac106e783559ea11828a394caedf046e --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_timer.h @@ -0,0 +1,61 @@ +/**************************************************************************//** + * @file timer.h + * @brief N9H30 series TIMER driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __NU_TIMER_H__ +#define __NU_TIMER_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "N9H30.h" + +#define TIMER_COUNTER_ENABLE (1UL << 30) /*!< Timer counter enable */ +#define TIMER_INTERRUPT_ENABLE (1UL << 29) /*!< Timer interrupt enable */ + +#define TIMER_ONESHOT_MODE (0UL) /*!< Timer working in one shot mode */ +#define TIMER_PERIODIC_MODE (1UL << 27) /*!< Timer working in periodic mode */ +#define TIMER_CONTINUOUS_MODE (3UL << 27) /*!< Timer working in continuous mode */ + +#define TIMER_COUNTER_RESET (1UL << 26) /*!< Timer reset counter */ +#define TIMER_IS_ALIVE (1UL << 25) /*!< Timer is alive */ + +static __inline void TIMER_ClearIntFlag(uint32_t timer) +{ + outpw(REG_TMR_ISR, (1 << timer)); +} + +static __inline uint32_t TIMER_GetIntFlag(uint32_t timer) +{ + return inpw(REG_TMR_ISR) & (1 << timer); +} + +void TIMER_SET_CMP_VALUE(uint32_t timer, uint32_t u32Cmpr); +void TIMER_SET_OPMODE(uint32_t timer, uint32_t u32OpMode); +void TIMER_SET_PRESCALE_VALUE(uint32_t timer, uint32_t u32PreScale); +uint32_t TIMER_GetModuleClock(uint32_t timer); +void TIMER_Start(uint32_t timer); +void TIMER_Stop(uint32_t timer); +void TIMER_ClearCounter(uint32_t timer); +uint32_t TIMER_GetCounter(uint32_t timer); +uint32_t TIMER_GetCompareData(uint32_t timer); +void TIMER_EnableInt(uint32_t timer); +void TIMER_DisableInt(uint32_t timer); +void TIMER_Close(uint32_t timer); +uint32_t TIMER_Open(uint32_t timer, uint32_t u32Mode, uint32_t u32Freq); +__inline void TIMER_ClearIntFlag(uint32_t timer); +__inline uint32_t TIMER_GetIntFlag(uint32_t timer); + +#ifdef __cplusplus +} +#endif + +#endif //__NU_TIMER_H__ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_uart.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_uart.h new file mode 100644 index 0000000000000000000000000000000000000000..4f24a2d10d9bcadb869ebefd7aaad584a6700ded --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_uart.h @@ -0,0 +1,773 @@ +/**************************************************************************//** +* @file uart.h +* @version V1.00 +* @brief N9H30 UART driver header file +* +* SPDX-License-Identifier: Apache-2.0 +* @copyright (C) 2015 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#ifndef __NU_UART_H__ +#define __NU_UART_H__ + +#include "N9H30.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_UART_Driver UART Driver + @{ +*/ + + + +/*-----------------------------------------*/ +/* marco, type and constant definitions */ +/*-----------------------------------------*/ +/// @cond HIDDEN_SYMBOLS +#define UART_NUM 11 + +#define UARTOFFSET 0x100 +/// @endcond HIDDEN_SYMBOLS + +/** @addtogroup N9H30_UART_EXPORTED_CONSTANTS UART Exported Constants + @{ +*/ + +#define UARTWRITESIZE 100 /*!< UART max. write size */ + +#define UARTINTMODE 1 /*!< UART interrupt mode */ +#define UARTPOLLMODE 0 /*!< UART polling mode */ +#define DISABLEALLIER 0 /*!< Disable all interrupt */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UART channel number */ +/*---------------------------------------------------------------------------------------------------------*/ +#define ALLCHANNEL 11 /*!< UART ALL channel */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UA_FCR constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ + +#define UART_FCR_RFITL_1BYTE (0x0 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 1 bit */ +#define UART_FCR_RFITL_4BYTES (0x1 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 4 bits */ +#define UART_FCR_RFITL_8BYTES (0x2 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 8 bits */ +#define UART_FCR_RFITL_14BYTES (0x3 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 14 bits */ +#define UART_FCR_RFITL_30BYTES (0x4 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 30 bits */ +#define UART_FCR_RFITL_46BYTES (0x5 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 46 bits */ +#define UART_FCR_RFITL_62BYTES (0x6 << UART_FCR_RFITL_Pos) /*!< UA_FCR setting to set RX FIFO Trigger Level to 62 bits */ + +#define UART_FCR_RTS_TRI_LEV_1BYTE (0x0 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 1 bit */ +#define UART_FCR_RTS_TRI_LEV_4BYTES (0x1 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 4 bits */ +#define UART_FCR_RTS_TRI_LEV_8BYTES (0x2 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 8 bits */ +#define UART_FCR_RTS_TRI_LEV_14BYTES (0x3 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 14 bits */ +#define UART_FCR_RTS_TRI_LEV_30BYTES (0x4 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 30 bits */ +#define UART_FCR_RTS_TRI_LEV_46BYTES (0x5 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 46 bits */ +#define UART_FCR_RTS_TRI_LEV_62BYTES (0x6 << UART_FCR_RTS_TRI_LEV_Pos) /*!< UA_FCR setting to set RTS Trigger Level to 62 bits */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UA_LCR constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_WORD_LEN_5 (0) /*!< UA_LCR setting to set UART word length to 5 bits */ +#define UART_WORD_LEN_6 (1) /*!< UA_LCR setting to set UART word length to 6 bits */ +#define UART_WORD_LEN_7 (2) /*!< UA_LCR setting to set UART word length to 7 bits */ +#define UART_WORD_LEN_8 (3) /*!< UA_LCR setting to set UART word length to 8 bits */ + +#define UART_PARITY_NONE (0x0 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as no parity */ +#define UART_PARITY_ODD (0x1 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as odd parity */ +#define UART_PARITY_EVEN (0x3 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as even parity */ +#define UART_PARITY_STICK (0x8 << UART_LCR_PBE_Pos) /*!< UA_LCR setting to set UART as stick parity */ + +#define UART_STOP_BIT_1 (0x0 << UART_LCR_NSB_Pos) /*!< UA_LCR setting for one stop bit */ +#define UART_STOP_BIT_1_5 (0x1 << UART_LCR_NSB_Pos) /*!< UA_LCR setting for 1.5 stop bit when 5-bit word length */ +#define UART_STOP_BIT_2 (0x1 << UART_LCR_NSB_Pos) /*!< UA_LCR setting for two stop bit when 6, 7, 8-bit word length */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UART RTS LEVEL TRIGGER constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_RTS_IS_HIGH_LEV_TRG (0x1 << UART_MCR_LEV_RTS_Pos) /*!< Set RTS is High Level Tigger */ +#define UART_RTS_IS_LOW_LEV_TRG (0x0 << UART_MCR_LEV_RTS_Pos) /*!< Set RTS is Low Level Tigger */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UART CTS LEVEL TRIGGER constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_CTS_IS_HIGH_LEV_TRG (0x1 << UART_MSR_LEV_CTS_Pos) /*!< Set CTS is High Level Trigger */ +#define UART_CTS_IS_LOW_LEV_TRG (0x0 << UART_MSR_LEV_CTS_Pos) /*!< Set CTS is Low Level Trigger */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UA_FUNC_SEL constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_FUNC_SEL_UART (0x0 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set UART Function (Default) */ +#define UART_FUNC_SEL_LIN (0x1 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set LIN Funciton */ +#define UART_FUNC_SEL_IrDA (0x2 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set IrDA Function */ +#define UART_FUNC_SEL_RS485 (0x3 << UART_FUN_SEL_FUN_SEL_Pos) /*!< UA_FUNC_SEL setting to set RS485 Function */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UA_LIN_CTL constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_LIN_CTL_LINS_EN (0x1UL << UART_LIN_CTL_LINS_EN_Pos) /*!< UA_LIN_CTL setting to set LIN Slave Mode Enable */ +#define UART_LIN_CTL_LINS_HDET_EN (0x1UL << UART_LIN_CTL_LINS_HDET_EN_Pos) /*!< UA_LIN_CTL setting to set LIN Slave Header Detection Enable */ +#define UART_LIN_CTL_LINS_ARS_EN (0x1UL << UART_LIN_CTL_LINS_ARS_EN_Pos) /*!< UA_LIN_CTL setting to set LIN Slave Automatic Resynchronization Mode Enable */ +#define UART_LIN_CTL_LINS_DUM_EN (0x1UL << UART_LIN_CTL_LINS_DUM_EN_Pos) /*!< UA_LIN_CTL setting to set LIN Slave Divider Update Method Enable */ +#define UART_LIN_CTL_LIN_WAKE_EN (0x1UL << UART_LIN_CTL_LIN_WAKE_EN_Pos) /*!< UA_LIN_CTL setting to set LIN Wake-Up Mode Enable */ +#define UART_LIN_CTL_LIN_SHD (0x1UL << UART_LIN_CTL_LIN_SHD_Pos) /*!< UA_LIN_CTL setting to set LIN TX Send Header Enable */ +#define UART_LIN_CTL_LIN_IDPEN (0x1UL << UART_LIN_CTL_LIN_IDPEN_Pos) /*!< UA_LIN_CTL setting to set LIN ID Parity Enable */ +#define UART_LIN_CTL_LIN_BKDET_ENN (0x1UL << UART_LIN_CTL_LIN_BKDET_EN_Pos) /*!< UA_LIN_CTL setting to set LIN Break Detection Enable */ +#define UART_LIN_CTL_LIN_RX_DIS (0x1UL << UART_LIN_CTL_LIN_RX_DIS_Pos) /*!< UA_LIN_CTL setting to set LIN Receiver Disable */ +#define UART_LIN_CTL_BIT_ERR_EN (0x1UL << UART_LIN_CTL_BIT_ERR_EN_Pos) /*!< UA_LIN_CTL setting to set Bit Error Detect Enable */ +#define UART_LIN_CTL_LIN_BKFL(x) (((x)-1) << UART_LIN_CTL_LIN_BKFL_Pos) /*!< UA_LIN_CTL setting to set LIN Break Field Length, x = 10 ~ 15, default value is 12 */ +#define UART_LIN_CTL_LIN_BS_LEN(x) (((x)-1) << UART_LIN_CTL_LIN_BS_LEN_Pos)/*!< UA_LIN_CTL setting to set LIN Break/Sync Delimiter Length, x = 1 ~ 4 */ +#define UART_LIN_CTL_LIN_HEAD_SEL_BREAK (0x0UL << UART_LIN_CTL_LIN_HEAD_SEL_Pos) /*!< UA_LIN_CTL setting to set LIN Header Select to break field */ +#define UART_LIN_CTL_LIN_HEAD_SEL_BREAK_SYNC (0x1UL << UART_LIN_CTL_LIN_HEAD_SEL_Pos) /*!< UA_LIN_CTL setting to set LIN Header Select to break field and sync field */ +#define UART_LIN_CTL_LIN_HEAD_SEL_BREAK_SYNC_ID (0x2UL << UART_LIN_CTL_LIN_HEAD_SEL_Pos) /*!< UA_LIN_CTL setting to set LIN Header Select to break field, sync field and ID field*/ +#define UART_LIN_CTL_LIN_LIN_PID(x) ((x) << UART_LIN_CTL_LIN_PID_Pos) /*!< UA_LIN_CTL setting to set LIN PID value */ + + +/*---------------------------------------------------------------------------------------------------------*/ +/* BAUD constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_BAUD_MODE0 (0) /*!< Set UART Baudrate Mode is Mode0 */ +#define UART_BAUD_MODE2 (UART_BAUD_DIV_X_EN_Msk | UART_BAUD_DIV_X_ONE_Msk) /*!< Set UART Baudrate Mode is Mode2 */ + +/* UART THR Bit Field Definitions */ +#define UART_THR_THR_Pos 0 /*!< UART THR: THR Position */ +#define UART_THR_THR_Msk (0xFFul << UART_THR_THR_Pos) /*!< UART THR: THR Mask */ + +/* UART RBR Bit Field Definitions */ +#define UART_RBR_RBR_Pos 0 /*!< UART RBR: RBR Posistion */ +#define UART_RBR_RBR_Msk (0xFFul << UART_RBR_RBR_Pos) /*!< UART RBR: RBR Mask */ + +/* UART IER Bit Field Definitions */ +#define UART_IER_DMA_RX_EN_Pos 15 /*!< UART IER: RX DMA Enable Posistion */ +#define UART_IER_DMA_RX_EN_Msk (1ul << UART_IER_DMA_RX_EN_Pos) /*!< UART IER: RX DMA Enable Mask */ + +#define UART_IER_DMA_TX_EN_Pos 14 /*!< UART IER: TX DMA Enable Posistion */ +#define UART_IER_DMA_TX_EN_Msk (1ul << UART_IER_DMA_TX_EN_Pos) /*!< UART IER: TX DMA Enable Mask */ + +#define UART_IER_AUTO_CTS_EN_Pos 13 /*!< UART IER: AUTO_CTS_EN Posistion */ +#define UART_IER_AUTO_CTS_EN_Msk (1ul << UART_IER_AUTO_CTS_EN_Pos) /*!< UART IER: AUTO_CTS_EN Mask */ + +#define UART_IER_AUTO_RTS_EN_Pos 12 /*!< UART IER: AUTO_RTS_EN Posistion */ +#define UART_IER_AUTO_RTS_EN_Msk (1ul << UART_IER_AUTO_RTS_EN_Pos) /*!< UART IER: AUTO_RTS_EN Mask */ + +#define UART_IER_TIME_OUT_EN_Pos 11 /*!< UART IER: TIME_OUT_EN Posistion */ +#define UART_IER_TIME_OUT_EN_Msk (1ul << UART_IER_TIME_OUT_EN_Pos) /*!< UART IER: TIME_OUT_EN Mask */ + +#define UART_IER_LIN_RX_BRK_IEN_Pos 8 /*!< UART IER: LIN_RX_BRK_IEN Posistion */ +#define UART_IER_LIN_RX_BRK_IEN_Msk (1ul << UART_IER_LIN_RX_BRK_IEN_Pos) /*!< UART IER: LIN_RX_BRK_IEN Mask */ + +#define UART_IER_WAKE_EN_Pos 6 /*!< UART IER: WAKE_EN Posistion */ +#define UART_IER_WAKE_EN_Msk (1ul << UART_IER_WAKE_EN_Pos) /*!< UART IER: WAKE_EN Mask */ + +#define UART_IER_BUF_ERR_IEN_Pos 5 /*!< UART IER: BUF_ERR_IEN Posistion */ +#define UART_IER_BUF_ERR_IEN_Msk (1ul << UART_IER_BUF_ERR_IEN_Pos) /*!< UART IER: BUF_ERR_IEN Mask */ + +#define UART_IER_RTO_IEN_Pos 4 /*!< UART IER: RTO_IEN Posistion */ +#define UART_IER_RTO_IEN_Msk (1ul << UART_IER_RTO_IEN_Pos) /*!< UART IER: RTO_IEN Mask */ + +#define UART_IER_MODEM_IEN_Pos 3 /*!< UART IER: MODEM_IEN Posistion */ +#define UART_IER_MODEM_IEN_Msk (1ul << UART_IER_MODEM_IEN_Pos) /*!< UART IER: MODEM_IEN Mask */ + +#define UART_IER_RLS_IEN_Pos 2 /*!< UART IER: RLS_IEN Posistion */ +#define UART_IER_RLS_IEN_Msk (1ul << UART_IER_RLS_IEN_Pos) /*!< UART IER: RLS_IEN Mask */ + +#define UART_IER_THRE_IEN_Pos 1 /*!< UART IER: THRE_IEN Posistion */ +#define UART_IER_THRE_IEN_Msk (1ul << UART_IER_THRE_IEN_Pos) /*!< UART IER: THRE_IEN Mask */ + +#define UART_IER_RDA_IEN_Pos 0 /*!< UART IER: RDA_IEN Position */ +#define UART_IER_RDA_IEN_Msk (1ul << UART_IER_RDA_IEN_Pos) /*!< UART IER: RDA_IEN Mask */ + +/* UART FCR Bit Field Definitions */ +#define UART_FCR_RTS_TRI_LEV_Pos 16 /*!< UART FCR: RTS_TRI_LEV Position */ +#define UART_FCR_RTS_TRI_LEV_Msk (0xFul << UART_FCR_RTS_TRI_LEV_Pos) /*!< UART FCR: RTS_TRI_LEV Mask */ + +#define UART_FCR_RX_DIS_Pos 8 /*!< UART FCR: RX_DIS Position */ +#define UART_FCR_RX_DIS_Msk (1ul << UART_FCR_RX_DIS_Pos) /*!< UART FCR: RX_DIS Mask */ + +#define UART_FCR_RFITL_Pos 4 /*!< UART FCR: RFITL Position */ +#define UART_FCR_RFITL_Msk (0xFul << UART_FCR_RFITL_Pos) /*!< UART FCR: RFITL Mask */ + +#define UART_FCR_TFR_Pos 2 /*!< UART FCR: TFR Position */ +#define UART_FCR_TFR_Msk (1ul << UART_FCR_TFR_Pos) /*!< UART FCR: TFR Mask */ + +#define UART_FCR_RFR_Pos 1 /*!< UART FCR: RFR Position */ +#define UART_FCR_RFR_Msk (1ul << UART_FCR_RFR_Pos) /*!< UART FCR: RFR Mask */ + +/* UART LCR Bit Field Definitions */ +#define UART_LCR_BCB_Pos 6 /*!< UART LCR: BCB Position */ +#define UART_LCR_BCB_Msk (1ul << UART_LCR_BCB_Pos) /*!< UART LCR: BCB Mask */ + +#define UART_LCR_SPE_Pos 5 /*!< UART LCR: SPE Position */ +#define UART_LCR_SPE_Msk (1ul << UART_LCR_SPE_Pos) /*!< UART LCR: SPE Mask */ + +#define UART_LCR_EPE_Pos 4 /*!< UART LCR: EPE Position */ +#define UART_LCR_EPE_Msk (1ul << UART_LCR_EPE_Pos) /*!< UART LCR: EPE Mask */ + +#define UART_LCR_PBE_Pos 3 /*!< UART LCR: PBE Position */ +#define UART_LCR_PBE_Msk (1ul << UART_LCR_PBE_Pos) /*!< UART LCR: PBE Mask */ + +#define UART_LCR_NSB_Pos 2 /*!< UART LCR: NSB Position */ +#define UART_LCR_NSB_Msk (1ul << UART_LCR_NSB_Pos) /*!< UART LCR: NSB Mask */ + +#define UART_LCR_WLS_Pos 0 /*!< UART LCR: WLS Position */ +#define UART_LCR_WLS_Msk (0x3ul << UART_LCR_WLS_Pos) /*!< UART LCR: WLS Mask */ + +/* UART MCR Bit Field Definitions */ +#define UART_MCR_RTS_ST_Pos 13 /*!< UART MCR: RTS_ST Position */ +#define UART_MCR_RTS_ST_Msk (1ul << UART_MCR_RTS_ST_Pos) /*!< UART MCR: RTS_ST Mask */ + +#define UART_MCR_LEV_RTS_Pos 9 /*!< UART MCR: LEV_RTS Position */ +#define UART_MCR_LEV_RTS_Msk (1ul << UART_MCR_LEV_RTS_Pos) /*!< UART MCR: LEV_RTS Mask */ + +#define UART_MCR_RTS_Pos 1 /*!< UART MCR: RTS Position */ +#define UART_MCR_RTS_Msk (1ul << UART_MCR_RTS_Pos) /*!< UART MCR: RTS Mask */ + +/* UART MSR Bit Field Definitions */ +#define UART_MSR_LEV_CTS_Pos 8 /*!< UART MSR: LEV_CTS Position */ +#define UART_MSR_LEV_CTS_Msk (1ul << UART_MSR_LEV_CTS_Pos) /*!< UART MSR: LEV_CTS Mask */ + +#define UART_MSR_CTS_ST_Pos 4 /*!< UART MSR: CTS_ST Position */ +#define UART_MSR_CTS_ST_Msk (1ul << UART_MSR_CTS_ST_Pos) /*!< UART MSR: CTS_ST Mask */ + +#define UART_MSR_DCTSF_Pos 0 /*!< UART MSR: DCTST Position */ +#define UART_MSR_DCTSF_Msk (1ul << UART_MSR_DCTSF_Pos) /*!< UART MSR: DCTST Mask */ + + +/* UART FSR Bit Field Definitions */ +#define UART_FSR_TE_FLAG_Pos 28 /*!< UART FSR: TE_FLAG Position */ +#define UART_FSR_TE_FLAG_Msk (1ul << UART_FSR_TE_FLAG_Pos) /*!< UART FSR: TE_FLAG Mask */ + +#define UART_FSR_TX_OVER_IF_Pos 24 /*!< UART FSR: TX_OVER_IF Position */ +#define UART_FSR_TX_OVER_IF_Msk (1ul << UART_FSR_TX_OVER_IF_Pos) /*!< UART FSR: TX_OVER_IF Mask */ + +#define UART_FSR_TX_FULL_Pos 23 /*!< UART FSR: TX_FULL Position */ +#define UART_FSR_TX_FULL_Msk (1ul << UART_FSR_TX_FULL_Pos) /*!< UART FSR: TX_FULL Mask */ + +#define UART_FSR_TX_EMPTY_Pos 22 /*!< UART FSR: TX_EMPTY Position */ +#define UART_FSR_TX_EMPTY_Msk (1ul << UART_FSR_TX_EMPTY_Pos) /*!< UART FSR: TX_EMPTY Mask */ + +#define UART_FSR_TX_POINTER_Pos 16 /*!< UART FSR: TX_POINTER Position */ +#define UART_FSR_TX_POINTER_Msk (0x3Ful << UART_FSR_TX_POINTER_Pos) /*!< UART FSR: TX_POINTER Mask */ + +#define UART_FSR_RX_FULL_Pos 15 /*!< UART FSR: RX_FULL Position */ +#define UART_FSR_RX_FULL_Msk (1ul << UART_FSR_RX_FULL_Pos) /*!< UART FSR: RX_FULL Mask */ + +#define UART_FSR_RX_EMPTY_Pos 14 /*!< UART FSR: RX_EMPTY Position */ +#define UART_FSR_RX_EMPTY_Msk (1ul << UART_FSR_RX_EMPTY_Pos) /*!< UART FSR: RX_EMPTY Mask */ + +#define UART_FSR_RX_POINTER_Pos 8 /*!< UART FSR: RX_POINTERS Position */ +#define UART_FSR_RX_POINTER_Msk (0x3Ful << UART_FSR_RX_POINTER_Pos) /*!< UART FSR: RX_POINTER Mask */ + +#define UART_FSR_BIF_Pos 6 /*!< UART FSR: BIF Position */ +#define UART_FSR_BIF_Msk (1ul << UART_FSR_BIF_Pos) /*!< UART FSR: BIF Mask */ + +#define UART_FSR_FEF_Pos 5 /*!< UART FSR: FEF Position */ +#define UART_FSR_FEF_Msk (1ul << UART_FSR_FEF_Pos) /*!< UART FSR: FEF Mask */ + +#define UART_FSR_PEF_Pos 4 /*!< UART FSR: PEF Position */ +#define UART_FSR_PEF_Msk (1ul << UART_FSR_PEF_Pos) /*!< UART FSR: PEF Mask */ + +#define UART_FSR_RS485_ADD_DETF_Pos 3 /*!< UART FSR: RS485_ADD_DETF Position */ +#define UART_FSR_RS485_ADD_DETF_Msk (1ul << UART_FSR_RS485_ADD_DETF_Pos) /*!< UART FSR: RS485_ADD_DETF Mask */ + +#define UART_FSR_RX_OVER_IF_Pos 0 /*!< UART FSR: RX_OVER_IF Position */ +#define UART_FSR_RX_OVER_IF_Msk (1ul << UART_FSR_RX_OVER_IF_Pos) /*!< UART FSR: RX_OVER_IF Mask */ + +/* UART ISR Bit Field Definitions */ +#define UART_ISR_LIN_RX_BREAK_INT_Pos 15 /*!< UART ISR: LIN_RX_BREAK_INT Position */ +#define UART_ISR_LIN_RX_BREAK_INT_Msk (1ul << UART_ISR_LIN_RX_BREAK_INT_Pos) /*!< UART ISR: LIN_RX_BREAK_INT Mask */ + +#define UART_ISR_BUF_ERR_INT_Pos 13 /*!< UART ISR: BUF_ERR_INT Position */ +#define UART_ISR_BUF_ERR_INT_Msk (1ul << UART_ISR_BUF_ERR_INT_Pos) /*!< UART ISR: BUF_ERR_INT Mask */ + +#define UART_ISR_TOUT_INT_Pos 12 /*!< UART ISR: TOUT_INT Position */ +#define UART_ISR_TOUT_INT_Msk (1ul << UART_ISR_TOUT_INT_Pos) /*!< UART ISR: TOUT_INT Mask */ + +#define UART_ISR_MODEM_INT_Pos 11 /*!< UART ISR: MODEM_INT Position */ +#define UART_ISR_MODEM_INT_Msk (1ul << UART_ISR_MODEM_INT_Pos) /*!< UART ISR: MODEM_INT Mask */ + +#define UART_ISR_RLS_INT_Pos 10 /*!< UART ISR: RLS_INT Position */ +#define UART_ISR_RLS_INT_Msk (1ul << UART_ISR_RLS_INT_Pos) /*!< UART ISR: RLS_INT Mask */ + +#define UART_ISR_THRE_INT_Pos 9 /*!< UART ISR: THRE_INT Position */ +#define UART_ISR_THRE_INT_Msk (1ul << UART_ISR_THRE_INT_Pos) /*!< UART ISR: THRE_INT Mask */ + +#define UART_ISR_RDA_INT_Pos 8 /*!< UART ISR: RDA_INT Position */ +#define UART_ISR_RDA_INT_Msk (1ul << UART_ISR_RDA_INT_Pos) /*!< UART ISR: RDA_INT Mask */ + +#define UART_ISR_LIN_RX_BREAK_IF_Pos 7 /*!< UART ISR: LIN RX BREAK IF Position */ +#define UART_ISR_LIN_RX_BREAK_IF_Msk (1ul << UART_ISR_LIN_RX_BREAK_IF_Pos) /*!< UART ISR: LIN RX BREAK IF Mask */ + +#define UART_ISR_BUF_ERR_IF_Pos 5 /*!< UART ISR: BUF_ERR_IF Position */ +#define UART_ISR_BUF_ERR_IF_Msk (1ul << UART_ISR_BUF_ERR_IF_Pos) /*!< UART ISR: BUF_ERR_IF Mask */ + +#define UART_ISR_TOUT_IF_Pos 4 /*!< UART ISR: TOUT_IF Position */ +#define UART_ISR_TOUT_IF_Msk (1ul << UART_ISR_TOUT_IF_Pos) /*!< UART ISR: TOUT_IF Mask */ + +#define UART_ISR_MODEM_IF_Pos 3 /*!< UART ISR: MODEM_IF Position */ +#define UART_ISR_MODEM_IF_Msk (1ul << UART_ISR_MODEM_IF_Pos) /*!< UART ISR: MODEM_IF Mask */ + +#define UART_ISR_RLS_IF_Pos 2 /*!< UART ISR: RLS_IF Position */ +#define UART_ISR_RLS_IF_Msk (1ul << UART_ISR_RLS_IF_Pos) /*!< UART ISR: RLS_IF Mask */ + +#define UART_ISR_THRE_IF_Pos 1 /*!< UART ISR: THRE_IF Position */ +#define UART_ISR_THRE_IF_Msk (1ul << UART_ISR_THRE_IF_Pos) /*!< UART ISR: THRE_IF Mask */ + +#define UART_ISR_RDA_IF_Pos 0 /*!< UART ISR: RDA_IF Position */ +#define UART_ISR_RDA_IF_Msk (1ul << UART_ISR_RDA_IF_Pos) /*!< UART ISR: RDA_IF Mask */ + + +/* UART TOR Bit Field Definitions */ +#define UART_TOR_DLY_Pos 8 /*!< UART TOR: DLY Position */ +#define UART_TOR_DLY_Msk (0xFFul << UART_TOR_DLY_Pos) /*!< UART TOR: DLY Mask */ + +#define UART_TOR_TOIC_Pos 0 /*!< UART TOR: TOIC Position */ +#define UART_TOR_TOIC_Msk (0xFFul << UART_TOR_TOIC_Pos) /*!< UART TOR: TOIC Mask */ + +/* UART BAUD Bit Field Definitions */ +#define UART_BAUD_DIV_X_EN_Pos 29 /*!< UART BARD: DIV_X_EN Position */ +#define UART_BAUD_DIV_X_EN_Msk (1ul << UART_BAUD_DIV_X_EN_Pos) /*!< UART BARD: DIV_X_EN Mask */ + +#define UART_BAUD_DIV_X_ONE_Pos 28 /*!< UART BARD: DIV_X_ONE Position */ +#define UART_BAUD_DIV_X_ONE_Msk (1ul << UART_BAUD_DIV_X_ONE_Pos) /*!< UART BARD: DIV_X_ONE Mask */ + +#define UART_BAUD_DIVIDER_X_Pos 24 /*!< UART BARD: DIVIDER_X Position */ +#define UART_BAUD_DIVIDER_X_Msk (0xFul << UART_BAUD_DIVIDER_X_Pos) /*!< UART BARD: DIVIDER_X Mask */ + +#define UART_BAUD_BRD_Pos 0 /*!< UART BARD: BRD Position */ +#define UART_BAUD_BRD_Msk (0xFFFFul << UART_BAUD_BRD_Pos) /*!< UART BARD: BRD Mask */ + +/* UART IRCR Bit Field Definitions */ +#define UART_IRCR_INV_RX_Pos 6 /*!< UART IRCR: INV_RX Position */ +#define UART_IRCR_INV_RX_Msk (1ul << UART_IRCR_INV_RX_Pos) /*!< UART IRCR: INV_RX Mask */ + +#define UART_IRCR_INV_TX_Pos 5 /*!< UART IRCR: INV_TX Position */ +#define UART_IRCR_INV_TX_Msk (1ul << UART_IRCR_INV_TX_Pos) /*!< UART IRCR: INV_TX Mask */ + +#define UART_IRCR_TX_SELECT_Pos 1 /*!< UART IRCR: TX_SELECT Position */ +#define UART_IRCR_TX_SELECT_Msk (1ul << UART_IRCR_TX_SELECT_Pos) /*!< UART IRCR: TX_SELECT Mask */ + +/* UART ALT_CSR Bit Field Definitions */ +#define UART_ALT_CSR_ADDR_MATCH_Pos 24 /*!< UART ALT_CSR: ADDR_MATCH Position */ +#define UART_ALT_CSR_ADDR_MATCH_Msk (0xFFul << UART_ALT_CSR_ADDR_MATCH_Pos) /*!< UART ALT_CSR: ADDR_MATCH Mask */ + +#define UART_ALT_CSR_RS485_ADD_EN_Pos 15 /*!< UART ALT_CSR: RS485_ADD_EN Position */ +#define UART_ALT_CSR_RS485_ADD_EN_Msk (1ul << UART_ALT_CSR_RS485_ADD_EN_Pos) /*!< UART ALT_CSR: RS485_ADD_EN Mask */ + +#define UART_ALT_CSR_RS485_AUD_Pos 10 /*!< UART ALT_CSR: RS485_AUD Position */ +#define UART_ALT_CSR_RS485_AUD_Msk (1ul << UART_ALT_CSR_RS485_AUD_Pos) /*!< UART ALT_CSR: RS485_AUD Mask */ + +#define UART_ALT_CSR_RS485_AAD_Pos 9 /*!< UART ALT_CSR: RS485_AAD Position */ +#define UART_ALT_CSR_RS485_AAD_Msk (1ul << UART_ALT_CSR_RS485_AAD_Pos) /*!< UART ALT_CSR: RS485_AAD Mask */ + +#define UART_ALT_CSR_RS485_NMM_Pos 8 /*!< UART ALT_CSR: RS485_NMM Position */ +#define UART_ALT_CSR_RS485_NMM_Msk (1ul << UART_ALT_CSR_RS485_NMM_Pos) /*!< UART ALT_CSR: RS485_NMM Mask */ + +#define UART_ALT_CSR_LIN_TX_EN_Pos 7 /*!< UART ALT_CSR: LIN TX Break Mode Enable Position */ +#define UART_ALT_CSR_LIN_TX_EN_Msk (1ul << UART_ALT_CSR_LIN_TX_EN_Pos) /*!< UART ALT_CSR: LIN TX Break Mode Enable Mask */ + +#define UART_ALT_CSR_LIN_RX_EN_Pos 6 /*!< UART ALT_CSR: LIN RX Enable Position */ +#define UART_ALT_CSR_LIN_RX_EN_Msk (1ul << UART_ALT_CSR_LIN_RX_EN_Pos) /*!< UART ALT_CSR: LIN RX Enable Mask */ + +#define UART_ALT_CSR_UA_LIN_BKFL_Pos 0 /*!< UART ALT_CSR: UART LIN Break Field Length Position */ +#define UART_ALT_CSR_UA_LIN_BKFL_Msk (0xFul << UART_ALT_CSR_UA_LIN_BKFL_Pos) /*!< UART ALT_CSR: UART LIN Break Field Length Mask */ + +/* UART FUN_SEL Bit Field Definitions */ +#define UART_FUN_SEL_FUN_SEL_Pos 0 /*!< UART FUN_SEL: FUN_SEL Position */ +#define UART_FUN_SEL_FUN_SEL_Msk (0x3ul << UART_FUN_SEL_FUN_SEL_Pos) /*!< UART FUN_SEL: FUN_SEL Mask */ + +/* UART LIN_CTL Bit Field Definitions */ +#define UART_LIN_CTL_LIN_PID_Pos 24 /*!< UART LIN_CTL: LIN_PID Position */ +#define UART_LIN_CTL_LIN_PID_Msk (0xFFul << UART_LIN_CTL_LIN_PID_Pos) /*!< UART LIN_CTL: LIN_PID Mask */ + +#define UART_LIN_CTL_LIN_HEAD_SEL_Pos 22 /*!< UART LIN_CTL: LIN_HEAD_SEL Position */ +#define UART_LIN_CTL_LIN_HEAD_SEL_Msk (0x3ul << UART_LIN_CTL_LIN_HEAD_SEL_Pos) /*!< UART LIN_CTL: LIN_HEAD_SEL Mask */ + +#define UART_LIN_CTL_LIN_BS_LEN_Pos 20 /*!< UART LIN_CTL: LIN_BS_LEN Position */ +#define UART_LIN_CTL_LIN_BS_LEN_Msk (0x3ul << UART_LIN_CTL_LIN_BS_LEN_Pos) /*!< UART LIN_CTL: LIN_BS_LEN Mask */ + +#define UART_LIN_CTL_LIN_BKFL_Pos 16 /*!< UART LIN_CTL: LIN_BKFL Position */ +#define UART_LIN_CTL_LIN_BKFL_Msk (0xFul << UART_LIN_CTL_LIN_BKFL_Pos) /*!< UART LIN_CTL: LIN_BKFL Mask */ + +#define UART_LIN_CTL_BIT_ERR_EN_Pos 12 /*!< UART LIN_CTL: BIT_ERR_EN Position */ +#define UART_LIN_CTL_BIT_ERR_EN_Msk (1ul << UART_LIN_CTL_BIT_ERR_EN_Pos) /*!< UART LIN_CTL: BIT_ERR_EN Mask */ + +#define UART_LIN_CTL_LIN_RX_DIS_Pos 11 /*!< UART LIN_CTL: LIN_RX_DIS Position */ +#define UART_LIN_CTL_LIN_RX_DIS_Msk (1ul << UART_LIN_CTL_LIN_RX_DIS_Pos) /*!< UART LIN_CTL: LIN_RX_DIS Mask */ + +#define UART_LIN_CTL_LIN_BKDET_EN_Pos 10 /*!< UART LIN_CTL: LIN_BKDET_EN Position */ +#define UART_LIN_CTL_LIN_BKDET_EN_Msk (1ul << UART_LIN_CTL_LIN_BKDET_EN_Pos) /*!< UART LIN_CTL: LIN_BKDET_EN Mask */ + +#define UART_LIN_CTL_LIN_IDPEN_Pos 9 /*!< UART LIN_CTL: LIN_IDPEN Position */ +#define UART_LIN_CTL_LIN_IDPEN_Msk (1ul << UART_LIN_CTL_LIN_IDPEN_Pos) /*!< UART LIN_CTL: LIN_IDPEN Mask */ + +#define UART_LIN_CTL_LIN_SHD_Pos 8 /*!< UART LIN_CTL: LIN_SHD Position */ +#define UART_LIN_CTL_LIN_SHD_Msk (1ul << UART_LIN_CTL_LIN_SHD_Pos) /*!< UART LIN_CTL: LIN_SHD Mask */ + +#define UART_LIN_CTL_LIN_WAKE_EN_Pos 4 /*!< UART LIN_CTL: LIN_WAKE_EN Position */ +#define UART_LIN_CTL_LIN_WAKE_EN_Msk (1ul << UART_LIN_CTL_LIN_WAKE_EN_Pos) /*!< UART LIN_CTL: LIN_WAKE_EN Mask */ + +#define UART_LIN_CTL_LINS_DUM_EN_Pos 3 /*!< UART LIN_CTL: LINS_DUM_EN Position */ +#define UART_LIN_CTL_LINS_DUM_EN_Msk (1ul << UART_LIN_CTL_LINS_DUM_EN_Pos) /*!< UART LIN_CTL: LINS_DUM_EN Mask */ + +#define UART_LIN_CTL_LINS_ARS_EN_Pos 2 /*!< UART LIN_CTL: LINS_ARS_EN Position */ +#define UART_LIN_CTL_LINS_ARS_EN_Msk (1ul << UART_LIN_CTL_LINS_ARS_EN_Pos) /*!< UART LIN_CTL: LINS_ARS_EN Mask */ + +#define UART_LIN_CTL_LINS_HDET_EN_Pos 1 /*!< UART LIN_CTL: LINS_HDET_EN Position */ +#define UART_LIN_CTL_LINS_HDET_EN_Msk (1ul << UART_LIN_CTL_LINS_HDET_EN_Pos) /*!< UART LIN_CTL: LINS_HDET_EN Mask */ + +#define UART_LIN_CTL_LINS_EN_Pos 0 /*!< UART LIN_CTL: LINS_EN Position */ +#define UART_LIN_CTL_LINS_EN_Msk (1ul << UART_LIN_CTL_LINS_EN_Pos) /*!< UART LIN_CTL: LINS_EN Mask */ + +/* UART LIN_SR Bit Field Definitions */ +#define UART_LIN_SR_LINS_SYNC_F_Pos 3 /*!< UART LIN_SR: LINS_SYNC_F Position */ +#define UART_LIN_SR_LINS_SYNC_F_Msk (1ul << UART_LIN_SR_LINS_SYNC_F_Pos) /*!< UART LIN_SR: LINS_SYNC_F Mask */ + +#define UART_LIN_SR_LINS_IDPERR_F_Pos 2 /*!< UART LIN_SR: LINS_IDPERR_F Position */ +#define UART_LIN_SR_LINS_IDPERR_F_Msk (1ul << UART_LIN_SR_LINS_IDPERR_F_Pos) /*!< UART LIN_SR: LINS_IDPERR_F Mask */ + +#define UART_LIN_SR_LINS_HERR_F_Pos 1 /*!< UART LIN_SR: LINS_HERR_F Position */ +#define UART_LIN_SR_LINS_HERR_F_Msk (1ul << UART_LIN_SR_LINS_HERR_F_Pos) /*!< UART LIN_SR: LINS_HERR_F Mask */ + +#define UART_LIN_SR_LINS_HDET_F_Pos 0 /*!< UART LIN_SR: LINS_HDET_F Position */ +#define UART_LIN_SR_LINS_HDET_F_Msk (1ul << UART_LIN_SR_LINS_HDET_F_Pos) /*!< UART LIN_SR: LINS_HDET_F Mask */ + +/* UART DEBUG Bit Field Definitions */ +#define UART_DEBUG_ERR_DIVIA_F_Pos 0 /*!< UART DEBUG: ERR_DIVIA_F Position */ +#define UART_DEBUG_ERR_DIVIA_F_Msk (1ul << UART_DEBUG_ERR_DIVIA_F_Pos) /*!< UART DEBUG: ERR_DIVIA_F Mask */ + +#define UART_DEBUG_ERR_HETIME_OUT_F_Pos 1 /*!< UART DEBUG: ERR_HETIME_OUT_F Position */ +#define UART_DEBUG_ERR_HETIME_OUT_F_Msk (1ul << UART_DEBUG_ERR_HETIME_OUT_F_Pos) /*!< UART DEBUG: ERR_HETIME_OUT_F Mask */ + +#define UART_DEBUG_ERR_HEFE_F_Pos 2 /*!< UART DEBUG: ERR_HEFE_F Position */ +#define UART_DEBUG_ERR_HEFE_F_Msk (1ul << UART_DEBUG_ERR_HEFE_F_Pos) /*!< UART DEBUG: ERR_HEFE_F Mask */ + +#define UART_DEBUG_ERR_SYNC_F_Pos 3 /*!< UART DEBUG: ERR_SYNC_F Position */ +#define UART_DEBUG_ERR_SYNC_F_Msk (1ul << UART_DEBUG_ERR_SYNC_F_Pos) /*!< UART DEBUG: ERR_SYNC_F Mask */ + +/* UART SC_CTL Bit Field Definitions */ +#define UART_SC_CTL_RX_ERETRY_Pos 0 /*!< UART SC_CTL: RX_ERETRY Position */ +#define UART_SC_CTL_RX_ERETRY_Msk (7ul << UART_SC_CTL_RX_ERETRY_Pos) /*!< UART SC_CTL: RX_ERETRY Mask */ + +#define UART_SC_CTL_RX_ERETRY_EN_Pos 3 /*!< UART SC_CTL: RX_ERETRY_EN Position */ +#define UART_SC_CTL_RX_ERETRY_EN_Msk (1ul << UART_SC_CTL_RX_ERETRY_EN_Pos) /*!< UART SC_CTL: RX_ERETRY_EN Mask */ + +#define UART_SC_CTL_TX_ERETRY_Pos 4 /*!< UART SC_CTL: TX_ERETRY Position */ +#define UART_SC_CTL_TX_ERETRY_Msk (7ul << UART_SC_CTL_TX_ERETRY_Pos) /*!< UART SC_CTL: TX_ERETRY Mask */ + +#define UART_SC_CTL_TX_ERETRY_EN_Pos 7 /*!< UART SC_CTL: TX_ERETRY_EN Position */ +#define UART_SC_CTL_TX_ERETRY_EN_Msk (1ul << UART_SC_CTL_TX_ERETRY_EN_Pos) /*!< UART SC_CTL: TX_ERETRY_EN Mask */ + +/* UART SC_FSR Bit Field Definitions */ +#define UART_SC_FSR_RX_OVER_ERETRY_Pos 0 /*!< UART SC_FSR: RX_OVER_ERETRY Position */ +#define UART_SC_FSR_RX_OVER_ERETRY_Msk (1ul << UART_SC_FSR_RX_OVER_ERETRY_Pos) /*!< UART SC_FSR: RX_OVER_ERETRY Mask */ + +#define UART_SC_FSR_TX_OVER_ERETRY_Pos 1 /*!< UART SC_FSR: TX_OVER_ERETRY Position */ +#define UART_SC_FSR_TX_OVER_ERETRY_Msk (1ul << UART_SC_FSR_TX_OVER_ERETRY_Pos) /*!< UART SC_FSR: TX_OVER_ERETRY Mask */ + +#define UART_SC_FSR_RX_ERETRY_F_Pos 8 /*!< UART SC_FSR: RX_ERETRY_F Position */ +#define UART_SC_FSR_RX_ERETRY_F_Msk (1ul << UART_SC_FSR_RX_ERETRY_F_Pos) /*!< UART SC_FSR: RX_ERETRY_F Mask */ + +#define UART_SC_FSR_TX_ERETRY_F_Pos 9 /*!< UART SC_FSR: TX_ERETRY_F Position */ +#define UART_SC_FSR_TX_ERETRY_F_Msk (1ul << UART_SC_FSR_TX_ERETRY_F_Pos) /*!< UART SC_FSR: TX_ERETRY_F Mask */ + +/* Enable/Disable IrDA Mode */ +#define ENABLEIrDA 1 /*!< Enable IrDA */ +#define DISABLEIrDA 0 /*!< Disable IrDA */ + +/* define IrDA Direction */ +#define IrDA_TX 0 /*!< Set IrDA Tx direction*/ +#define IrDA_RX 1 /*!< Set IrDA Rx direction*/ + +/* define RTS signal */ +#define UART_RTS_HIGH 1 /*!< Set RTS high*/ +#define UART_RTS_LOW 0 /*!< Set RTS low*/ + +/* define IOCTL command of UART operation mode, interrupt or pooling mode */ +#define UART_IOC_SETTXMODE 1 /*!< Set Tx Mode */ +#define UART_IOC_SETRXMODE 2 /*!< Set Tx Mode */ +#define UART_IOC_GETRECCHARINFO 3 /*!< Get receive character */ +#define UART_IOC_SETUARTPARAMETER 4 /*!< Config UART */ +//#define UART_IOC_PERFORMBLUETOOTH 5 +#define UART_IOC_PERFORMIrDA 6 /*!< Config IrDA */ +#define UART_IOC_GETUARTREGISTERVALUE 7 /*!< Get UART register value*/ +#define UART_IOC_GETERRNO 8 /*!< Get rrror code */ +//#define UART_IOC_SETMODEMLOOPBACK 9 +//#define UART_IOC_GETDSRSTATE 10 +//#define UART_IOC_SETDTRSIGNAL 11 +#define UART_IOC_SETINTERRUPT 12 /*!< Set interrupt */ +#define UART_IOC_SETBREAKCONTROL 13 /*!< Set break */ +#define UART_IOC_GETBIISTATE 14 /*!< Get break status */ +#define UART_IOC_GETCTSSTATE 15 /*!< Get CTS status */ +#define UART_IOC_SETRTSSIGNAL 16 /*!< Set RTS signal */ +#define UART_IOC_SETMODEMINTERRUPT 17 /*!< Set modem interrupt */ +#define UART_IOC_ENABLEHWFLOWCONTROL 18 /*!< Enable H/W flow control */ +#define UART_IOC_DISABLEHWFLOWCONTROL 19 /*!< Disable H/W flow control */ +//#define UART_IOC_ENABLESWFLOWCONTROL 20 /*!< Enable S/W flow control */ +//#define UART_IOC_DISABLESWFLOWCONTROL 21 /*!< Disable S/W flow control */ +//#define UART_IOC_SETUART1FULLMODEM 22 +//#define UART_IOC_SETUART1HIGHSPEED 23 + +#define UART_IOC_FLUSH_TX_BUFFER 24 /*!< Flush Tx buffer */ +#define UART_IOC_FLUSH_RX_BUFFER 25 /*!< Flus Rx buffer */ + +#define UART_IOC_SET_RS485_MODE 26 /*!< Select RS485 Mode */ +#define UART_IOC_SEND_RS485_ADDRESS 27 /*!< Send RS485 Address*/ +#define UART_IOC_SET_RS485_RXOFF 28 /*!< Select RS485 Mode */ +#define UART_IOC_SET_ALTCTL_REG 29 /*!< Set ALT_CTL register */ +#define UART_IOC_GET_ALTCTL_REG 30 /*!< Get ALT_CTL register */ + +#define UART_IOC_SET_LIN_MODE 31 /*!< Select LIN Mode */ + + +/* Enable/Disable Modem interrupt */ +#define UART_ENABLE_MODEM_INT 0 /*!< Enable Modem interrupt */ +#define UART_DISABLE_MODEM_INT 1 /*!< Disable Modem interrupt */ + +/* These error code can get from UART_IOC_GETERRNO */ +#define UART_ERR_PARITY_INVALID -1 /*!< Parity invalid */ +#define UART_ERR_DATA_BITS_INVALID -2 /*!< Data bits invalid */ +#define UART_ERR_STOP_BITS_INVALID -3 /*!< Stop bit invalid */ +#define UART_ERR_TRIGGERLEVEL_INVALID -4 /*!< Trigger level invalid */ +#define UART_ERR_CHANNEL_INVALID -5 /*!< UART channel invalid */ +#define UART_ERR_ALLOC_MEMORY_FAIL -6 /*!< Allocate memory error */ +//#define UART_ERR_CLOCK_SOURCE_INVALID -7 /*!< Clock Source invalid */ +//#define UART_ERR_BAUDRATE_INVALID -8 /*!< Baudrate invalid */ +//#define UART_ERR_CONFIGURE_BT_FAIL -9 +#define UART_ERR_IrDA_COMMAND_INVALID -10 /*!< IrDA mode invalid */ +#define UART_ERR_TX_BUF_NOT_ENOUGH -11 /*!< Tx buffer not enough */ +#define UART_ERR_OPERATE_MODE_INVALID -12 /*!< Operation mode invalid */ +#define UART_ERR_SET_BAUDRATE_FAIL -13 /*!< Set baudrate fail */ + +/* These are the error code actually returns to user application */ +#define UART_ERR_ID 0xFFFF1700 /*!< UART library ID */ +#define UART_ENOTTY (1 | UART_ERR_ID) /*!< Command not support */ +#define UART_ENODEV (2 | UART_ERR_ID) /*!< Interface number out of range */ +#define UART_EIO (3 | UART_ERR_ID) /*!< Read/Write error */ + +/*@}*/ /* end of group N9H30_UART_EXPORTED_CONSTANTS */ + + +/** @addtogroup N9H30_UART_EXPORTED_STRUCTS UART Exported Structs + @{ +*/ + +/// @cond HIDDEN_SYMBOLS +/*----------------------------------------------------*/ +/* Define UART buffer structure */ +/*----------------------------------------------------*/ +typedef struct UART_BUFFER_STRUCT +{ + UINT32 volatile uUartTxHead, uUartTxTail; + UINT32 volatile uUartRxHead, uUartRxTail; + + PUINT8 pucUartTxBuf; + PUINT8 pucUartRxBuf; + PVOID pvUartVector; + BOOL bIsUseUARTTxInt; + BOOL bIsUseUARTRxInt; + BOOL bIsUARTInitial; + + PINT pucUARTFlag; + PINT pucLINFlag; + INT32 volatile nErrno; + +} UART_BUFFER_T; +/// @endcond HIDDEN_SYMBOLS + +/** \brief Structure type of UART data + */ +#if 0 +#define UART0 0 /*!< UART0 channel */ +#define UART1 1 /*!< UART1 channel */ +#define UART2 2 /*!< UART2 channel */ +#define UART3 3 /*!< UART3 channel */ +#define UART4 4 /*!< UART4 channel */ +#define UART5 5 /*!< UART5 channel */ +#define UART6 6 /*!< UART6 channel */ +#define UART7 7 /*!< UART7 channel */ +#define UART8 8 /*!< UART8 channel */ +#define UART9 9 /*!< UART9 channel */ +#define UARTA 10 /*!< UARTA channel */ + +typedef struct UART_STRUCT +{ + UINT32 uFreq; /*!< UART clock frequency */ + UINT32 uBaudRate; /*!< Baudrate */ + UINT8 ucUartNo; /*!< UART Port */ + UINT8 ucDataBits; /*!< Select Data length */ + UINT8 ucStopBits; /*!< Select stop bit length */ + UINT8 ucParity; /*!< Select Parity */ + UINT8 ucRxTriggerLevel; /*!< Select Rx FIFO trigger level */ +} UART_T; +#else + +typedef struct +{ + __IO uint32_t DAT; /*!< [0x0000] UART Receive/Transmit Buffer Register */ + __IO uint32_t INTEN; /*!< [0x0004] UART Interrupt Enable Register */ + __IO uint32_t FIFO; /*!< [0x0008] UART FIFO Control Register */ + __IO uint32_t LINE; /*!< [0x000c] UART Line Control Register */ + __IO uint32_t MODEM; /*!< [0x0010] UART Modem Control Register */ + __IO uint32_t MODEMSTS; /*!< [0x0014] UART Modem Status Register */ + __IO uint32_t FIFOSTS; /*!< [0x0018] UART FIFO Status Register */ + __IO uint32_t INTSTS; /*!< [0x001c] UART Interrupt Status Register */ + __IO uint32_t TOUT; /*!< [0x0020] UART Time-out Register */ + __IO uint32_t BAUD; /*!< [0x0024] UART Baud Rate Divider Register */ + __IO uint32_t IRDA; /*!< [0x0028] UART IrDA Control Register */ + __IO uint32_t ALTCTL; /*!< [0x002c] UART Alternate Control/Status Register */ + __IO uint32_t FUNCSEL; /*!< [0x0030] UART Function Select Register */ + __IO uint32_t LINCTL; /*!< [0x0034] UART LIN Control Register */ + __IO uint32_t LINSTS; /*!< [0x0038] UART LIN Status Register */ +} UART_T; + +#define UART0 ((UART_T *) UART0_BA) /*!< UART0 channel */ +#define UART1 ((UART_T *) UART1_BA) /*!< UART1 channel */ +#define UART2 ((UART_T *) UART2_BA) /*!< UART2 channel */ +#define UART3 ((UART_T *) UART3_BA) /*!< UART3 channel */ +#define UART4 ((UART_T *) UART4_BA) /*!< UART4 channel */ +#define UART5 ((UART_T *) UART5_BA) /*!< UART5 channel */ +#define UART6 ((UART_T *) UART6_BA) /*!< UART6 channel */ +#define UART7 ((UART_T *) UART7_BA) /*!< UART7 channel */ +#define UART8 ((UART_T *) UART8_BA) /*!< UART8 channel */ +#define UART9 ((UART_T *) UART9_BA) /*!< UART9 channel */ +#define UARTA ((UART_T *) UARTA_BA) /*!< UARTA channel */ + +/*---------------------------------------------------------------------------------------------------------*/ +/* UART_FUNCSEL constants definitions */ +/*---------------------------------------------------------------------------------------------------------*/ +#define UART_FIFO_RFITL_Pos (4) /*!< UART_T::FIFO: RFITL Position */ +#define UART_FIFO_RFITL_Msk (0xful << UART_FIFO_RFITL_Pos) /*!< UART_T::FIFO: RFITL Mask */ + +#define UART_FIFO_RTSTRGLV_Pos (16) /*!< UART_T::FIFO: RTSTRGLV Position */ +#define UART_FIFO_RTSTRGLV_Msk (0xful << UART_FIFO_RTSTRGLV_Pos) /*!< UART_T::FIFO: RTSTRGLV Mask */ + +#define UART_FUNCSEL_FUNCSEL_Pos (0) /*!< UART_T::FUNCSEL: FUNCSEL Position */ +#define UART_FUNCSEL_FUNCSEL_Msk (0x3ul << UART_FUNCSEL_FUNCSEL_Pos) /*!< UART_T::FUNCSEL: FUNCSEL Mask */ + +#define UART_FUNCSEL_UART (0x0ul << UART_FUNCSEL_FUNCSEL_Pos) /*!< UART_FUNCSEL setting to set UART Function (Default) \hideinitializer */ +#define UART_FUNCSEL_LIN (0x1ul << UART_FUNCSEL_FUNCSEL_Pos) /*!< UART_FUNCSEL setting to set LIN Function \hideinitializer */ +#define UART_FUNCSEL_IrDA (0x2ul << UART_FUNCSEL_FUNCSEL_Pos) /*!< UART_FUNCSEL setting to set IrDA Function \hideinitializer */ +#define UART_FUNCSEL_RS485 (0x3ul << UART_FUNCSEL_FUNCSEL_Pos) /*!< UART_FUNCSEL setting to set RS485 Function \hideinitializer */ + +#endif + +/** \brief Structure type of UART register + */ +typedef struct UART_REGISTER_STRUCT +{ + UINT32 uUartReg[14][2]; /*!< Store UART register value */ +} UART_REGISTER_T; + +/*@}*/ /* end of group N9H30_UART_EXPORTED_STRUCTS */ + + +/** @addtogroup N9H30_UART_EXPORTED_FUNCTIONS UART Exported Functions + @{ +*/ + +/** + * @brief Calculate UART baudrate mode0 divider + * + * @param[in] u32SrcFreq UART clock frequency + * @param[in] u32BaudRate Baudrate of UART module + * + * @return UART baudrate mode0 divider + * \hideinitializer + * + */ +#define UART_BAUD_MODE0_DIVIDER(u32SrcFreq, u32BaudRate) (((u32SrcFreq + (u32BaudRate*8)) / u32BaudRate >> 4)-2) + +/** + * @brief Calculate UART baudrate mode2 divider + * + * @param[in] u32SrcFreq UART clock frequency + * @param[in] u32BaudRate Baudrate of UART module + * + * @return UART baudrate mode2 divider + * \hideinitializer + */ +#define UART_BAUD_MODE2_DIVIDER(u32SrcFreq, u32BaudRate) (((u32SrcFreq + (u32BaudRate/2)) / u32BaudRate)-2) + + +/** + * @brief Get Rx empty + * + * @param[in] uart The pointer of the specified UART module + * + * @retval 0 Rx FIFO is not empty + * @retval >=1 Rx FIFO is empty + * + * @details This macro get Receiver FIFO empty register value. + * \hideinitializer + */ +#define UART_GET_RX_EMPTY(uart) ((uart)->FIFOSTS & UART_FSR_RX_EMPTY_Msk) + +/** + * @brief Check TX FIFO is full or not + * + * @param[in] uart The pointer of the specified UART module + * + * @retval 1 TX FIFO is full + * @retval 0 TX FIFO is not full + * + * @details This macro check TX FIFO is full or not. + * \hideinitializer + */ +#define UART_IS_TX_FULL(uart) (((uart)->FIFOSTS & UART_FSR_TX_FULL_Msk)>>UART_FSR_TX_FULL_Pos) + +/** + * @brief Write UART data + * + * @param[in] uart The pointer of the specified UART module + * @param[in] u8Data Data byte to transmit. + * + * @return None + * + * @details This macro write Data to Tx data register. + * \hideinitializer + */ +#define UART_WRITE(uart, u8Data) ((uart)->DAT = (u8Data)) + +/** + * @brief Read UART data + * + * @param[in] uart The pointer of the specified UART module + * + * @return The oldest data byte in RX FIFO. + * + * @details This macro read Rx data register. + * \hideinitializer + */ +#define UART_READ(uart) ((uart)->DAT) + +#define UART_ENABLE_INT(uart, u32eIntSel) ((uart)->INTEN |= (u32eIntSel)) +#define UART_DISABLE_INT(uart, u32eIntSel) ((uart)->INTEN &= ~ (u32eIntSel)) + +/*-----------------------------------------*/ +/* interface function declarations */ +/*-----------------------------------------*/ +INT uartOpen(PVOID param); +INT uartInit(void); +INT uartIoctl(INT nNum, UINT32 uCom, UINT32 uArg0, UINT32 uArg1); +INT32 uartRelease(INT nNum); +INT32 uartWrite(INT nNum, PUINT8 pucBuf, UINT32 uLen); +INT32 uartRead(INT nNum, PUINT8 pucBuf, UINT32 uLen); + + +void UART_Open(UART_T *uart, uint32_t u32baudrate); +void UART_Close(UART_T *uart); +void UART_SetLineConfig(UART_T *uart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t u32stop_bits); +/*@}*/ /* end of group N9H30_UART_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_UART_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_usbd.h b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_usbd.h new file mode 100644 index 0000000000000000000000000000000000000000..5f8719b45d843a2e249da087123c1a85d572ef86 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Include/nu_usbd.h @@ -0,0 +1,937 @@ +/**************************************************************************//** + * @file usbd.h + * @brief N9H30 USBD driver header file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ +#ifndef __NU_USBD_H__ +#define __NU_USBD_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_USBD_Driver USBD Driver + @{ +*/ + +/** @addtogroup N9H30_USBD_EXPORTED_CONSTANTS USBD Exported Constants + @{ +*/ +/// @cond HIDDEN_SYMBOLS +#define USBD_MAX_EP 12 + +#define Maximum(a,b) (a)>(b) ? (a) : (b) +#define Minimum(a,b) (a)<(b) ? (a) : (b) + + +#define CEP 0xff /*!< Control Endpoint \hideinitializer */ +#define EPA 0 /*!< Endpoint A \hideinitializer */ +#define EPB 1 /*!< Endpoint B \hideinitializer */ +#define EPC 2 /*!< Endpoint C \hideinitializer */ +#define EPD 3 /*!< Endpoint D \hideinitializer */ +#define EPE 4 /*!< Endpoint E \hideinitializer */ +#define EPF 5 /*!< Endpoint F \hideinitializer */ +#define EPG 6 /*!< Endpoint G \hideinitializer */ +#define EPH 7 /*!< Endpoint H \hideinitializer */ +#define EPI 8 /*!< Endpoint I \hideinitializer */ +#define EPJ 9 /*!< Endpoint J \hideinitializer */ +#define EPK 10 /*!< Endpoint K \hideinitializer */ +#define EPL 11 /*!< Endpoint L \hideinitializer */ + +/* USB Request Type */ +#define REQ_STANDARD 0x00 +#define REQ_CLASS 0x20 +#define REQ_VENDOR 0x40 + +/* USB Standard Request */ +#define GET_STATUS 0x00 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 +#define SET_ADDRESS 0x05 +#define GET_DESCRIPTOR 0x06 +#define SET_DESCRIPTOR 0x07 +#define GET_CONFIGURATION 0x08 +#define SET_CONFIGURATION 0x09 +#define GET_INTERFACE 0x0A +#define SET_INTERFACE 0x0B +#define SYNC_FRAME 0x0C + +/* USB Descriptor Type */ +#define DESC_DEVICE 0x01 +#define DESC_CONFIG 0x02 +#define DESC_STRING 0x03 +#define DESC_INTERFACE 0x04 +#define DESC_ENDPOINT 0x05 +#define DESC_QUALIFIER 0x06 +#define DESC_OTHERSPEED 0x07 +#define DESC_IFPOWER 0x08 +#define DESC_OTG 0x09 + +/* USB HID Descriptor Type */ +#define DESC_HID 0x21 +#define DESC_HID_RPT 0x22 + +/* USB Descriptor Length */ +#define LEN_DEVICE 18 +#define LEN_QUALIFIER 10 +#define LEN_CONFIG 9 +#define LEN_INTERFACE 9 +#define LEN_ENDPOINT 7 +#define LEN_OTG 5 +#define LEN_HID 9 + +/* USB Endpoint Type */ +#define EP_ISO 0x01 +#define EP_BULK 0x02 +#define EP_INT 0x03 + +#define EP_INPUT 0x80 +#define EP_OUTPUT 0x00 + +/* USB Feature Selector */ +#define FEATURE_DEVICE_REMOTE_WAKEUP 0x01 +#define FEATURE_ENDPOINT_HALT 0x00 +/// @endcond HIDDEN_SYMBOLS +/********************* Bit definition of CEPCTL register **********************/ +#define USB_CEPCTL_NAKCLR ((uint32_t)0x00000000) /*!PHYCTL |= (USBD_PHYCTL_PHYEN_Msk|USBD_PHYCTL_DPPUEN_Msk))) /*!PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk)) /*!PHYCTL |= USBD_PHYCTL_PHYEN_Msk)) /*!PHYCTL &= ~USBD_PHYCTL_PHYEN_Msk)) /*!PHYCTL &= ~USBD_PHYCTL_DPPUEN_Msk)) /*!PHYCTL |= USBD_PHYCTL_DPPUEN_Msk)) /*!FADDR = (addr)) /*!FADDR)) /*!GINTEN = (intr)) /*!BUSINTEN = (intr)) /*!BUSINTSTS) /*!BUSINTSTS = flag) /*!CEPINTEN = (intr)) /*!CEPINTSTS = flag) /*!CEPCTL = flag) /*!CEPTXCNT = size) /*!EP[ep].EPMPS = (size)) /*!EP[ep].EPINTEN = (intr)) /*!EP[ep].EPINTSTS) /*!EP[ep].EPINTSTS = (flag)) /*!DMACNT = len) /*!DMAADDR = addr) /*!DMACTL = (USBD->DMACTL & ~USBD_DMACTL_EPNUM_Msk) | USBD_DMACTL_DMARD_Msk | epnum) /*!DMACTL = (USBD->DMACTL & ~(USBD_DMACTL_EPNUM_Msk | USBD_DMACTL_DMARD_Msk)) | epnum) /*!DMACTL |= USBD_DMACTL_DMAEN_Msk) /*!PHYCTL & USBD_PHYCTL_VBUSDET_Msk)) /*!DMACNT = 0; + USBD->DMACTL = 0x80; + USBD->DMACTL = 0x00; +} +/** + * @brief USBD_SetEpBufAddr, Set Endpoint buffer address + * @param[in] u32Ep Endpoint Number + * @param[in] u32Base Buffer Start Address + * @param[in] u32Len Buffer length + * @retval None. + */ +static __inline void USBD_SetEpBufAddr(uint32_t u32Ep, uint32_t u32Base, uint32_t u32Len) +{ + if (u32Ep == CEP) + { + USBD->CEPBUFSTART = u32Base; + USBD->CEPBUFEND = u32Base + u32Len - 1; + } + else + { + USBD->EP[u32Ep].EPBUFSTART = u32Base; + USBD->EP[u32Ep].EPBUFEND = u32Base + u32Len - 1; + } +} + +/** + * @brief USBD_ConfigEp, Config Endpoint + * @param[in] u32Ep USB endpoint + * @param[in] u32EpNum Endpoint number + * @param[in] u32EpType Endpoint type + * @param[in] u32EpDir Endpoint direction + * @retval None. + */ +static __inline void USBD_ConfigEp(uint32_t u32Ep, uint32_t u32EpNum, uint32_t u32EpType, uint32_t u32EpDir) +{ + if (u32EpType == USB_EP_CFG_TYPE_BULK) + USBD->EP[u32Ep].EPRSPCTL = (USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_MODE_AUTO); + else if (u32EpType == USB_EP_CFG_TYPE_INT) + USBD->EP[u32Ep].EPRSPCTL = (USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_MODE_MANUAL); + else if (u32EpType == USB_EP_CFG_TYPE_ISO) + USBD->EP[u32Ep].EPRSPCTL = (USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_MODE_FLY); + + USBD->EP[u32Ep].EPCFG = (u32EpType | u32EpDir | USB_EP_CFG_VALID | (u32EpNum << 4)); +} + +/** + * @brief Set USB endpoint stall state + * @param[in] u32Ep The USB endpoint ID. + * @return None + * @details Set USB endpoint stall state for the specified endpoint ID. Endpoint will respond STALL token automatically. + */ +static __inline void USBD_SetEpStall(uint32_t u32Ep) +{ + if (u32Ep == CEP) + USBD_SET_CEP_STATE(USB_CEPCTL_STALL); + else + { + USBD->EP[u32Ep].EPRSPCTL = USBD->EP[u32Ep].EPRSPCTL & 0xf7 | USB_EP_RSPCTL_HALT; + } +} + +/** + * @brief Set USB endpoint stall state + * + * @param[in] u32EpNum USB endpoint + * @return None + * + * @details Set USB endpoint stall state, endpoint will return STALL token. + */ +static __inline void USBD_SetStall(uint32_t u32EpNum) +{ + int i; + + if (u32EpNum == 0) + USBD_SET_CEP_STATE(USB_CEPCTL_STALL); + else + { + for (i = 0; i < USBD_MAX_EP; i++) + { + if (((USBD->EP[i].EPCFG & 0xf0) >> 4) == u32EpNum) + { + USBD->EP[i].EPRSPCTL = USBD->EP[i].EPRSPCTL & 0xf7 | USB_EP_RSPCTL_HALT; + } + } + } +} + +/** + * @brief Clear USB endpoint stall state + * @param[in] u32Ep The USB endpoint ID. + * @return None + * @details Clear USB endpoint stall state for the specified endpoint ID. Endpoint will respond ACK/NAK token. + */ +static __inline void USBD_ClearEpStall(uint32_t u32Ep) +{ + USBD->EP[u32Ep].EPRSPCTL = USB_EP_RSPCTL_TOGGLE; +} + +/** + * @brief Clear USB endpoint stall state + * + * @param[in] u32EpNum USB endpoint + * @return None + * + * @details Clear USB endpoint stall state, endpoint will return ACK/NAK token. + */ +static __inline void USBD_ClearStall(uint32_t u32EpNum) +{ + int i; + + for (i = 0; i < USBD_MAX_EP; i++) + { + if (((USBD->EP[i].EPCFG & 0xf0) >> 4) == u32EpNum) + { + USBD->EP[i].EPRSPCTL = USB_EP_RSPCTL_TOGGLE; + } + } +} + +/** + * @brief Get USB endpoint stall state + * @param[in] u32Ep The USB endpoint ID. + * @retval 0 USB endpoint is not stalled. + * @retval Others USB endpoint is stalled. + * @details Get USB endpoint stall state of the specified endpoint ID. + */ +static __inline uint32_t USBD_GetEpStall(uint32_t u32Ep) +{ + return (USBD->EP[u32Ep].EPRSPCTL & USB_EP_RSPCTL_HALT); +} + +/** + * @brief Get USB endpoint stall state + * + * @param[in] u32EpNum USB endpoint + * @retval 0: USB endpoint is not stalled. + * @retval non-0: USB endpoint is stalled. + * + * @details Get USB endpoint stall state. + */ +static __inline uint32_t USBD_GetStall(uint32_t u32EpNum) +{ + int i; + + for (i = 0; i < USBD_MAX_EP; i++) + { + if (((USBD->EP[i].EPCFG & 0xf0) >> 4) == u32EpNum) + { + return (USBD->EP[i].EPRSPCTL & USB_EP_RSPCTL_HALT); + } + } + return 0; +} + + +/*-------------------------------------------------------------------------------------------*/ +typedef void (*VENDOR_REQ)(void); /*!CON & (CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk); + tCAN->CON = tCAN->CON & ~(CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk); + + /* Check interface 1 is available or not */ + if ((tCAN->IF[0ul].CREQ & CAN_IF_CREQ_BUSY_Msk) == 0ul) + { + if (gu8LockCanIf[u32CanNo][0ul] == 0ul) + { + gu8LockCanIf[u32CanNo][0ul] = 1u; + u32FreeIfNo = 0ul; + } + else + { + } + } + else + { + } + + /* Or check interface 2 is available or not */ + if (u32FreeIfNo == 2ul) + { + if ((tCAN->IF[1ul].CREQ & CAN_IF_CREQ_BUSY_Msk) == 0ul) + { + if (gu8LockCanIf[u32CanNo][1ul] == 0ul) + { + gu8LockCanIf[u32CanNo][1ul] = 1u; + u32FreeIfNo = 1ul; + } + else + { + } + } + else + { + } + } + else + { + } + + /* Enable CAN interrupt */ + tCAN->CON |= u32IntMask; + + return u32FreeIfNo; +} + +/** + * @brief Check if any interface is available in a time limitation then lock it for usage. + * @param[in] tCAN The pointer to CAN module base address. + * @retval 0 IF0 is free + * @retval 1 IF1 is free + * @retval 2 No IF is free + * @details Search the first free message interface, starting from 0. If no interface is + * it will try again until time out. If a interface is available, set a flag to + * lock the interface. + */ +static uint32_t LockIF_TL(CAN_T *tCAN) +{ + uint32_t u32Count; + uint32_t u32FreeIfNo; + + for (u32Count = 0ul; u32Count < RETRY_COUNTS; u32Count++) + { + if ((u32FreeIfNo = LockIF(tCAN)) != 2ul) + { + break; + } + else + { + } + } + + return u32FreeIfNo; +} + +/** + * @brief Release locked interface. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32Info The interface number, 0 or 1. + * @return none + * @details Release the locked interface. + */ +static void ReleaseIF(CAN_T *tCAN, uint32_t u32IfNo) +{ + uint32_t u32IntMask; + uint32_t u32CanNo; + + if (u32IfNo >= 2ul) + { + } + else + { + if (tCAN == CAN0) + u32CanNo = 0ul; +#if defined(CAN1) + else if (tCAN == CAN1) + u32CanNo = 1ul; +#endif +#if defined(CAN2) + else if (tCAN == CAN2) + u32CanNo = 2ul; +#endif +#if defined(CAN3) + else if (tCAN == CAN3) + u32CanNo = 3ul; +#endif + else + return ; + + + /* Disable CAN interrupt */ + u32IntMask = tCAN->CON & (CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk); + tCAN->CON = tCAN->CON & ~(CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk); + + gu8LockCanIf[u32CanNo][u32IfNo] = 0u; + + /* Enable CAN interrupt */ + tCAN->CON |= u32IntMask; + } +} + +static int can_update_spt(int sampl_pt, int tseg, int *tseg1, int *tseg2) +{ + *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000; + if (*tseg2 < TSEG2_MIN) + { + *tseg2 = TSEG2_MIN; + } + else + { + } + + if (*tseg2 > TSEG2_MAX) + { + *tseg2 = TSEG2_MAX; + } + else + { + } + + *tseg1 = tseg - *tseg2; + if (*tseg1 > TSEG1_MAX) + { + *tseg1 = TSEG1_MAX; + *tseg2 = tseg - *tseg1; + } + else + { + } + + return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); +} + +/** @endcond HIDDEN_SYMBOLS */ + +/** + * @brief Enter initialization mode + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u8Mask Following values can be used. + * \ref CAN_CON_DAR_Msk Disable automatic retransmission. + * \ref CAN_CON_EIE_Msk Enable error interrupt. + * \ref CAN_CON_SIE_Msk Enable status interrupt. + * \ref CAN_CON_IE_Msk CAN interrupt. + * @return None + * @details This function is used to set CAN to enter initialization mode and enable access bit timing + * register. After bit timing configuration ready, user must call CAN_LeaveInitMode() + * to leave initialization mode and lock bit timing register to let new configuration + * take effect. + */ +void CAN_EnterInitMode(CAN_T *tCAN, uint8_t u8Mask) +{ + tCAN->CON = u8Mask | (CAN_CON_INIT_Msk | CAN_CON_CCE_Msk); +} + + +/** + * @brief Leave initialization mode + * @param[in] tCAN The pointer to CAN module base address. + * @return None + * @details This function is used to set CAN to leave initialization mode to let + * bit timing configuration take effect after configuration ready. + */ +void CAN_LeaveInitMode(CAN_T *tCAN) +{ + tCAN->CON &= (~(CAN_CON_INIT_Msk | CAN_CON_CCE_Msk)); + while (tCAN->CON & CAN_CON_INIT_Msk) + { + /* Check INIT bit is released */ + } +} + +/** + * @brief Wait message into message buffer in basic mode. + * @param[in] tCAN The pointer to CAN module base address. + * @return None + * @details This function is used to wait message into message buffer in basic mode. Please notice the + * function is polling NEWDAT bit of MCON register by while loop and it is used in basic mode. + */ +void CAN_WaitMsg(CAN_T *tCAN) +{ + tCAN->STATUS = 0x0ul; /* clr status */ + + while (1) + { + if (tCAN->IF[1].MCON & CAN_IF_MCON_NEWDAT_Msk) /* check new data */ + { + /* New Data IN */ + break; + } + else + { + } + + if (tCAN->STATUS & CAN_STATUS_RXOK_Msk) + { + /* Rx OK */ + } + else + { + } + + if (tCAN->STATUS & CAN_STATUS_LEC_Msk) + { + /* Error */ + } + else + { + } + } +} + +/** + * @brief Get current bit rate + * @param[in] tCAN The pointer to CAN module base address. + * @return Current Bit-Rate (kilo bit per second) + * @details Return current CAN bit rate according to the user bit-timing parameter settings + */ +uint32_t CAN_GetCANBitRate(CAN_T *tCAN) +{ + uint32_t u32Tseg1, u32Tseg2; + uint32_t u32Bpr; + + u32Tseg1 = (tCAN->BTIME & CAN_BTIME_TSEG1_Msk) >> CAN_BTIME_TSEG1_Pos; + u32Tseg2 = (tCAN->BTIME & CAN_BTIME_TSEG2_Msk) >> CAN_BTIME_TSEG2_Pos; + u32Bpr = (tCAN->BTIME & CAN_BTIME_BRP_Msk) | (tCAN->BRPE << 6ul); + + return (CAN_Clock / (u32Bpr + 1ul) / (u32Tseg1 + u32Tseg2 + 3ul)); +} + +/** + * @brief Switch the CAN into test mode. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u8TestMask Specifies the configuration in test modes + * \ref CAN_TEST_BASIC_Msk Enable basic mode of test mode + * \ref CAN_TEST_SILENT_Msk Enable silent mode of test mode + * \ref CAN_TEST_LBACK_Msk Enable Loop Back Mode of test mode + * \ref CAN_TEST_Tx_Msk Control CAN_TX pin bit field + * @return None + * @details Switch the CAN into test mode. There are four test mode (BASIC/SILENT/LOOPBACK/ + * LOOPBACK combined SILENT/CONTROL_TX_PIN)could be selected. After setting test mode,user + * must call CAN_LeaveInitMode() to let the setting take effect. + */ +void CAN_EnterTestMode(CAN_T *tCAN, uint8_t u8TestMask) +{ + tCAN->CON |= CAN_CON_TEST_Msk; + tCAN->TEST = u8TestMask; +} + + +/** + * @brief Leave the test mode + * @param[in] tCAN The pointer to CAN module base address. + * @return None + * @details This function is used to Leave the test mode (switch into normal mode). + */ +void CAN_LeaveTestMode(CAN_T *tCAN) +{ + tCAN->CON |= CAN_CON_TEST_Msk; + tCAN->TEST &= ~(CAN_TEST_LBACK_Msk | CAN_TEST_SILENT_Msk | CAN_TEST_BASIC_Msk); + tCAN->CON &= (~CAN_CON_TEST_Msk); +} + +/** + * @brief Get the waiting status of a received message. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u8MsgObj Specifies the Message object number, from 0 to 31. + * @retval non-zero The corresponding message object has a new data bit is set. + * @retval 0 No message object has new data. + * @details This function is used to get the waiting status of a received message. + */ +uint32_t CAN_IsNewDataReceived(CAN_T *tCAN, uint8_t u8MsgObj) +{ + return (u8MsgObj < 16ul ? tCAN->NDAT1 & (1ul << u8MsgObj) : tCAN->NDAT2 & (1ul << (u8MsgObj - 16ul))); +} + + +/** + * @brief Send CAN message in BASIC mode of test mode + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] pCanMsg Pointer to the message structure containing data to transmit. + * @return TRUE: Transmission OK + * FALSE: Check busy flag of interface 0 is timeout + * @details The function is used to send CAN message in BASIC mode of test mode. Before call the API, + * the user should be call CAN_EnterTestMode(CAN_TEST_BASIC) and let CAN controller enter + * basic mode of test mode. Please notice IF1 Registers used as Tx Buffer in basic mode. + */ +int32_t CAN_BasicSendMsg(CAN_T *tCAN, STR_CANMSG_T *pCanMsg) +{ + uint32_t i = 0ul; + int32_t rev = 1l; + + while (tCAN->IF[0].CREQ & CAN_IF_CREQ_BUSY_Msk) + { + } + + tCAN->STATUS &= (~CAN_STATUS_TXOK_Msk); + + if (pCanMsg->IdType == CAN_STD_ID) + { + /* standard ID*/ + tCAN->IF[0].ARB1 = 0ul; + tCAN->IF[0].ARB2 = (((pCanMsg->Id) & 0x7FFul) << 2ul) ; + } + else + { + /* extended ID*/ + tCAN->IF[0].ARB1 = (pCanMsg->Id) & 0xFFFFul; + tCAN->IF[0].ARB2 = ((pCanMsg->Id) & 0x1FFF0000ul) >> 16ul | CAN_IF_ARB2_XTD_Msk; + + } + + if (pCanMsg->FrameType) + { + tCAN->IF[0].ARB2 |= CAN_IF_ARB2_DIR_Msk; + } + else + { + tCAN->IF[0].ARB2 &= (~CAN_IF_ARB2_DIR_Msk); + } + + tCAN->IF[0].MCON = (tCAN->IF[0].MCON & (~CAN_IF_MCON_DLC_Msk)) | pCanMsg->DLC; + tCAN->IF[0].DAT_A1 = (uint16_t)((uint16_t)((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0]); + tCAN->IF[0].DAT_A2 = (uint16_t)((uint16_t)((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2]); + tCAN->IF[0].DAT_B1 = (uint16_t)((uint16_t)((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4]); + tCAN->IF[0].DAT_B2 = (uint16_t)((uint16_t)((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6]); + + /* request transmission*/ + tCAN->IF[0].CREQ &= (~CAN_IF_CREQ_BUSY_Msk); + if (tCAN->IF[0].CREQ & CAN_IF_CREQ_BUSY_Msk) + { + /* Cannot clear busy for sending ...*/ + rev = 0l; /* return FALSE */ + } + else + { + tCAN->IF[0].CREQ |= CAN_IF_CREQ_BUSY_Msk; /* sending */ + + for (i = 0ul; i < 0xFFFFFul; i++) + { + if ((tCAN->IF[0].CREQ & CAN_IF_CREQ_BUSY_Msk) == 0ul) + { + break; + } + else + { + } + } + + if (i >= 0xFFFFFul) + { + /* Cannot send out... */ + rev = 0l; /* return FALSE */ + } + else + { + } + } + + return rev; +} + +/** + * @brief Get a message information in BASIC mode. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] pCanMsg Pointer to the message structure where received data is copied. + * + * @return FALSE No any message received. + * TRUE Receive a message success. + * + */ +int32_t CAN_BasicReceiveMsg(CAN_T *tCAN, STR_CANMSG_T *pCanMsg) +{ + int32_t rev = 1l; + + if ((tCAN->IF[1].MCON & CAN_IF_MCON_NEWDAT_Msk) == 0ul) + { + /* In basic mode, receive data always save in IF2 */ + rev = 0; /* return FALSE */ + } + else + { + + tCAN->STATUS &= (~CAN_STATUS_RXOK_Msk); + + tCAN->IF[1].CMASK = CAN_IF_CMASK_ARB_Msk + | CAN_IF_CMASK_CONTROL_Msk + | CAN_IF_CMASK_DATAA_Msk + | CAN_IF_CMASK_DATAB_Msk; + + if ((tCAN->IF[1].ARB2 & CAN_IF_ARB2_XTD_Msk) == 0ul) + { + /* standard ID*/ + pCanMsg->IdType = CAN_STD_ID; + pCanMsg->Id = (tCAN->IF[1].ARB2 >> 2) & 0x07FFul; + + } + else + { + /* extended ID*/ + pCanMsg->IdType = CAN_EXT_ID; + pCanMsg->Id = (tCAN->IF[1].ARB2 & 0x1FFFul) << 16; + pCanMsg->Id |= (uint32_t)tCAN->IF[1].ARB1; + } + + pCanMsg->FrameType = (((tCAN->IF[1].ARB2 & CAN_IF_ARB2_DIR_Msk) >> CAN_IF_ARB2_DIR_Pos)) ? 0ul : 1ul; + + pCanMsg->DLC = (uint8_t)(tCAN->IF[1].MCON & CAN_IF_MCON_DLC_Msk); + pCanMsg->Data[0] = (uint8_t)(tCAN->IF[1].DAT_A1 & CAN_IF_DAT_A1_DATA0_Msk); + pCanMsg->Data[1] = (uint8_t)((tCAN->IF[1].DAT_A1 & CAN_IF_DAT_A1_DATA1_Msk) >> CAN_IF_DAT_A1_DATA1_Pos); + pCanMsg->Data[2] = (uint8_t)(tCAN->IF[1].DAT_A2 & CAN_IF_DAT_A2_DATA2_Msk); + pCanMsg->Data[3] = (uint8_t)((tCAN->IF[1].DAT_A2 & CAN_IF_DAT_A2_DATA3_Msk) >> CAN_IF_DAT_A2_DATA3_Pos); + pCanMsg->Data[4] = (uint8_t)(tCAN->IF[1].DAT_B1 & CAN_IF_DAT_B1_DATA4_Msk); + pCanMsg->Data[5] = (uint8_t)((tCAN->IF[1].DAT_B1 & CAN_IF_DAT_B1_DATA5_Msk) >> CAN_IF_DAT_B1_DATA5_Pos); + pCanMsg->Data[6] = (uint8_t)(tCAN->IF[1].DAT_B2 & CAN_IF_DAT_B2_DATA6_Msk); + pCanMsg->Data[7] = (uint8_t)((tCAN->IF[1].DAT_B2 & CAN_IF_DAT_B2_DATA7_Msk) >> CAN_IF_DAT_B2_DATA7_Pos); + } + + return rev; +} + +/** + * @brief Set Rx message object, include ID mask. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u8MsgObj Specifies the Message object number, from 0 to 31. + * @param[in] u8idType Specifies the identifier type of the frames that will be transmitted + * This parameter can be one of the following values: + * \ref CAN_STD_ID (standard ID, 11-bit) + * \ref CAN_EXT_ID (extended ID, 29-bit) + * @param[in] u32id Specifies the identifier used for acceptance filtering. + * @param[in] u32idmask Specifies the identifier mask used for acceptance filtering. + * @param[in] u8singleOrFifoLast Specifies the end-of-buffer indicator. + * This parameter can be one of the following values: + * TRUE: for a single receive object or a FIFO receive object that is the last one of the FIFO. + * FALSE: for a FIFO receive object that is not the last one. + * @retval TRUE SUCCESS + * @retval FALSE No useful interface + * @details The function is used to configure a receive message object. + */ +int32_t CAN_SetRxMsgObjAndMsk(CAN_T *tCAN, uint8_t u8MsgObj, uint8_t u8idType, uint32_t u32id, uint32_t u32idmask, uint8_t u8singleOrFifoLast) +{ + int32_t rev = 1l; + uint32_t u32MsgIfNum; + + /* Get and lock a free interface */ + if ((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul) + { + rev = 0; /* return FALSE */ + } + else + { + /* Command Setting */ + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_WRRD_Msk | CAN_IF_CMASK_MASK_Msk | CAN_IF_CMASK_ARB_Msk | + CAN_IF_CMASK_CONTROL_Msk | CAN_IF_CMASK_DATAA_Msk | CAN_IF_CMASK_DATAB_Msk; + + if (u8idType == CAN_STD_ID) /* According STD/EXT ID format,Configure Mask and Arbitration register */ + { + tCAN->IF[u32MsgIfNum].ARB1 = 0ul; + tCAN->IF[u32MsgIfNum].ARB2 = CAN_IF_ARB2_MSGVAL_Msk | (u32id & 0x7FFul) << 2; + } + else + { + tCAN->IF[u32MsgIfNum].ARB1 = u32id & 0xFFFFul; + tCAN->IF[u32MsgIfNum].ARB2 = CAN_IF_ARB2_MSGVAL_Msk | CAN_IF_ARB2_XTD_Msk | (u32id & 0x1FFF0000ul) >> 16; + } + + tCAN->IF[u32MsgIfNum].MASK1 = (u32idmask & 0xFFFFul); + tCAN->IF[u32MsgIfNum].MASK2 = (u32idmask >> 16) & 0xFFFFul; + + /* tCAN->IF[u32MsgIfNum].MCON |= CAN_IF_MCON_UMASK_Msk | CAN_IF_MCON_RXIE_Msk; */ + tCAN->IF[u32MsgIfNum].MCON = CAN_IF_MCON_UMASK_Msk | CAN_IF_MCON_RXIE_Msk; + if (u8singleOrFifoLast) + { + tCAN->IF[u32MsgIfNum].MCON |= CAN_IF_MCON_EOB_Msk; + } + else + { + tCAN->IF[u32MsgIfNum].MCON &= (~CAN_IF_MCON_EOB_Msk); + } + + tCAN->IF[u32MsgIfNum].DAT_A1 = 0ul; + tCAN->IF[u32MsgIfNum].DAT_A2 = 0ul; + tCAN->IF[u32MsgIfNum].DAT_B1 = 0ul; + tCAN->IF[u32MsgIfNum].DAT_B2 = 0ul; + + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u8MsgObj; + ReleaseIF(tCAN, u32MsgIfNum); + } + + return rev; +} + +/** + * @brief Set Rx message object + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u8MsgObj Specifies the Message object number, from 0 to 31. + * @param[in] u8idType Specifies the identifier type of the frames that will be transmitted + * This parameter can be one of the following values: + * \ref CAN_STD_ID (standard ID, 11-bit) + * \ref CAN_EXT_ID (extended ID, 29-bit) + * @param[in] u32id Specifies the identifier used for acceptance filtering. + * @param[in] u8singleOrFifoLast Specifies the end-of-buffer indicator. + * This parameter can be one of the following values: + * TRUE: for a single receive object or a FIFO receive object that is the last one of the FIFO. + * FALSE: for a FIFO receive object that is not the last one. + * @retval TRUE SUCCESS + * @retval FALSE No useful interface + * @details The function is used to configure a receive message object. + */ +int32_t CAN_SetRxMsgObj(CAN_T *tCAN, uint8_t u8MsgObj, uint8_t u8idType, uint32_t u32id, uint8_t u8singleOrFifoLast) +{ + int32_t rev = 1l; + uint32_t u32MsgIfNum; + + /* Get and lock a free interface */ + if ((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul) + { + rev = 0; /* return FALSE */ + } + else + { + /* Command Setting */ + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_WRRD_Msk | CAN_IF_CMASK_MASK_Msk | CAN_IF_CMASK_ARB_Msk | + CAN_IF_CMASK_CONTROL_Msk | CAN_IF_CMASK_DATAA_Msk | CAN_IF_CMASK_DATAB_Msk; + + if (u8idType == CAN_STD_ID) /* According STD/EXT ID format,Configure Mask and Arbitration register */ + { + tCAN->IF[u32MsgIfNum].ARB1 = 0ul; + tCAN->IF[u32MsgIfNum].ARB2 = CAN_IF_ARB2_MSGVAL_Msk | (u32id & 0x7FFul) << 2; + } + else + { + tCAN->IF[u32MsgIfNum].ARB1 = u32id & 0xFFFFul; + tCAN->IF[u32MsgIfNum].ARB2 = CAN_IF_ARB2_MSGVAL_Msk | CAN_IF_ARB2_XTD_Msk | (u32id & 0x1FFF0000ul) >> 16; + } + + /* tCAN->IF[u8MsgIfNum].MCON |= CAN_IF_MCON_UMASK_Msk | CAN_IF_MCON_RXIE_Msk; */ + tCAN->IF[u32MsgIfNum].MCON = CAN_IF_MCON_UMASK_Msk | CAN_IF_MCON_RXIE_Msk; + if (u8singleOrFifoLast) + { + tCAN->IF[u32MsgIfNum].MCON |= CAN_IF_MCON_EOB_Msk; + } + else + { + tCAN->IF[u32MsgIfNum].MCON &= (~CAN_IF_MCON_EOB_Msk); + } + + tCAN->IF[u32MsgIfNum].DAT_A1 = 0ul; + tCAN->IF[u32MsgIfNum].DAT_A2 = 0ul; + tCAN->IF[u32MsgIfNum].DAT_B1 = 0ul; + tCAN->IF[u32MsgIfNum].DAT_B2 = 0ul; + + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u8MsgObj; + ReleaseIF(tCAN, u32MsgIfNum); + } + + return rev; +} + +/** + * @brief Gets the message + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u8MsgObj Specifies the Message object number, from 0 to 31. + * @param[in] u8Release Specifies the message release indicator. + * This parameter can be one of the following values: + * TRUE: the message object is released when getting the data. + * FALSE:the message object is not released. + * @param[in] pCanMsg Pointer to the message structure where received data is copied. + * @retval TRUE Success + * @retval FALSE No any message received + * @details Gets the message, if received. + */ +int32_t CAN_ReadMsgObj(CAN_T *tCAN, uint8_t u8MsgObj, uint8_t u8Release, STR_CANMSG_T *pCanMsg) +{ + int32_t rev = 1l; + uint32_t u32MsgIfNum; + + if (!CAN_IsNewDataReceived(tCAN, u8MsgObj)) + { + rev = 0; /* return FALSE */ + } + else + { + /* Get and lock a free interface */ + if ((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul) + { + rev = 0; /* return FALSE */ + } + else + { + tCAN->STATUS &= (~CAN_STATUS_RXOK_Msk); + + /* read the message contents*/ + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_MASK_Msk + | CAN_IF_CMASK_ARB_Msk + | CAN_IF_CMASK_CONTROL_Msk + | CAN_IF_CMASK_CLRINTPND_Msk + | (u8Release ? CAN_IF_CMASK_TXRQSTNEWDAT_Msk : 0ul) + | CAN_IF_CMASK_DATAA_Msk + | CAN_IF_CMASK_DATAB_Msk; + + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u8MsgObj; + + while (tCAN->IF[u32MsgIfNum].CREQ & CAN_IF_CREQ_BUSY_Msk) + { + /*Wait*/ + } + + if ((tCAN->IF[u32MsgIfNum].ARB2 & CAN_IF_ARB2_XTD_Msk) == 0ul) + { + /* standard ID*/ + pCanMsg->IdType = CAN_STD_ID; + pCanMsg->Id = (tCAN->IF[u32MsgIfNum].ARB2 & CAN_IF_ARB2_ID_Msk) >> 2ul; + } + else + { + /* extended ID*/ + pCanMsg->IdType = CAN_EXT_ID; + pCanMsg->Id = (((tCAN->IF[u32MsgIfNum].ARB2) & 0x1FFFul) << 16) | tCAN->IF[u32MsgIfNum].ARB1; + } + + pCanMsg->DLC = (uint8_t)(tCAN->IF[u32MsgIfNum].MCON & CAN_IF_MCON_DLC_Msk); + pCanMsg->Data[0] = (uint8_t)(tCAN->IF[u32MsgIfNum].DAT_A1 & CAN_IF_DAT_A1_DATA0_Msk); + pCanMsg->Data[1] = (uint8_t)((tCAN->IF[u32MsgIfNum].DAT_A1 & CAN_IF_DAT_A1_DATA1_Msk) >> CAN_IF_DAT_A1_DATA1_Pos); + pCanMsg->Data[2] = (uint8_t)(tCAN->IF[u32MsgIfNum].DAT_A2 & CAN_IF_DAT_A2_DATA2_Msk); + pCanMsg->Data[3] = (uint8_t)((tCAN->IF[u32MsgIfNum].DAT_A2 & CAN_IF_DAT_A2_DATA3_Msk) >> CAN_IF_DAT_A2_DATA3_Pos); + pCanMsg->Data[4] = (uint8_t)(tCAN->IF[u32MsgIfNum].DAT_B1 & CAN_IF_DAT_B1_DATA4_Msk); + pCanMsg->Data[5] = (uint8_t)((tCAN->IF[u32MsgIfNum].DAT_B1 & CAN_IF_DAT_B1_DATA5_Msk) >> CAN_IF_DAT_B1_DATA5_Pos); + pCanMsg->Data[6] = (uint8_t)(tCAN->IF[u32MsgIfNum].DAT_B2 & CAN_IF_DAT_B2_DATA6_Msk); + pCanMsg->Data[7] = (uint8_t)((tCAN->IF[u32MsgIfNum].DAT_B2 & CAN_IF_DAT_B2_DATA7_Msk) >> CAN_IF_DAT_B2_DATA7_Pos); + + ReleaseIF(tCAN, u32MsgIfNum); + } + } + + return rev; +} + + +/** + * @brief Set bus baud-rate. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32BaudRate The target CAN baud-rate. The range of u32BaudRate is 1~1000KHz. + * + * @return u32CurrentBitRate Real baud-rate value. + * + * @details The function is used to set bus timing parameter according current clock and target baud-rate. + */ +uint32_t CAN_SetBaudRate(CAN_T *tCAN, uint32_t u32BaudRate) +{ + long rate; + long best_error = 1000000000, error = 0; + int best_tseg = 0, best_brp = 0, brp = 0; + int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0; + int spt_error = 1000, spt = 0, sampl_pt; + uint64_t clock_freq = (uint64_t)0, u64PCLK_DIV = (uint64_t)1; + uint32_t sjw = (uint32_t)1; + + CAN_EnterInitMode(tCAN, (uint8_t)0); + + CAN_Clock = sysGetClock(SYS_PCLK) * 1000000; + + clock_freq = CAN_Clock / u64PCLK_DIV; + + if (u32BaudRate >= (uint32_t)1000000) + { + u32BaudRate = (uint32_t)1000000; + } + + /* Use CIA recommended sample points */ + if (u32BaudRate > (uint32_t)800000) + { + sampl_pt = (int)750; + } + else if (u32BaudRate > (uint32_t)500000) + { + sampl_pt = (int)800; + } + else + { + sampl_pt = (int)875; + } + + /* tseg even = round down, odd = round up */ + for (tseg = (TSEG1_MAX + TSEG2_MAX) * 2ul + 1ul; tseg >= (TSEG1_MIN + TSEG2_MIN) * 2ul; tseg--) + { + tsegall = 1ul + tseg / 2ul; + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = clock_freq / (tsegall * u32BaudRate) + tseg % 2; + /* chose brp step which is possible in system */ + brp = (brp / BRP_INC) * BRP_INC; + + if ((brp < BRP_MIN) || (brp > BRP_MAX)) + { + continue; + } + rate = clock_freq / (brp * tsegall); + + error = u32BaudRate - rate; + + /* tseg brp biterror */ + if (error < 0) + { + error = -error; + } + if (error > best_error) + { + continue; + } + best_error = error; + if (error == 0) + { + spt = can_update_spt(sampl_pt, tseg / 2, &tseg1, &tseg2); + error = sampl_pt - spt; + if (error < 0) + { + error = -error; + } + if (error > spt_error) + { + continue; + } + spt_error = error; + } + best_tseg = tseg / 2; + best_brp = brp; + + if (error == 0) + { + break; + } + } + + spt = can_update_spt(sampl_pt, best_tseg, &tseg1, &tseg2); + + /* check for sjw user settings */ + /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ + if (sjw > SJW_MAX) + { + sjw = SJW_MAX; + } + /* bt->sjw must not be higher than tseg2 */ + if (tseg2 < sjw) + { + sjw = tseg2; + } + + /* real bit-rate */ + u32BaudRate = clock_freq / (best_brp * (tseg1 + tseg2 + 1)); + + tCAN->BTIME = ((uint32_t)(tseg2 - 1ul) << CAN_BTIME_TSEG2_Pos) | ((uint32_t)(tseg1 - 1ul) << CAN_BTIME_TSEG1_Pos) | + ((uint32_t)(best_brp - 1ul) & CAN_BTIME_BRP_Msk) | (sjw << CAN_BTIME_SJW_Pos); + tCAN->BRPE = ((uint32_t)(best_brp - 1ul) >> 6) & 0x0Ful; + + /* printf("\n bitrate = %d \n", CAN_GetCANBitRate(tCAN)); */ + + CAN_LeaveInitMode(tCAN); + + return u32BaudRate; +} + +/** + * @brief The function is used to disable all CAN interrupt. + * + * @param[in] tCAN The pointer to CAN module base address. + * + * @return None + * + * @details No Status Change Interrupt and Error Status Interrupt will be generated. + */ +void CAN_Close(CAN_T *tCAN) +{ + CAN_DisableInt(tCAN, (CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk)); +} + +/** + * @brief Set CAN operation mode and target baud-rate. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32BaudRate The target CAN baud-rate. The range of u32BaudRate is 1~1000KHz. + * @param[in] u32Mode The CAN operation mode. Valid values are: + * - \ref CAN_NORMAL_MODE Normal operation. + * - \ref CAN_BASIC_MODE Basic mode. + * @return u32CurrentBitRate Real baud-rate value. + * + * @details Set bus timing parameter according current clock and target baud-rate. + * In Basic mode, IF1 Registers used as Tx Buffer, IF2 Registers used as Rx Buffer. + */ +uint32_t CAN_Open(CAN_T *tCAN, uint32_t u32BaudRate, uint32_t u32Mode) +{ + uint32_t u32CurrentBitRate; + + u32CurrentBitRate = CAN_SetBaudRate(tCAN, u32BaudRate); + + if (u32Mode == CAN_BASIC_MODE) + { + CAN_EnterTestMode(tCAN, (uint8_t)CAN_TEST_BASIC_Msk); + } + else + { + } + + return u32CurrentBitRate; +} + +/** + * @brief The function is used to configure a transmit object. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * @param[in] pCanMsg Pointer to the message structure where received data is copied. + * + * @retval FALSE No useful interface. + * @retval TRUE Config message object success. + * + * @details The two sets of interface registers (IF1 and IF2) control the software access to the Message RAM. + * They buffer the data to be transferred to and from the RAM, avoiding conflicts between software accesses and message reception/transmission. + */ +int32_t CAN_SetTxMsg(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T *pCanMsg) +{ + int32_t rev = 1l; + uint32_t u32MsgIfNum; + + if ((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul) + { + rev = 0; /* return FALSE */ + } + else + { + /* update the contents needed for transmission*/ + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_WRRD_Msk | CAN_IF_CMASK_MASK_Msk | CAN_IF_CMASK_ARB_Msk | + CAN_IF_CMASK_CONTROL_Msk | CAN_IF_CMASK_DATAA_Msk | CAN_IF_CMASK_DATAB_Msk; + + if (pCanMsg->IdType == CAN_STD_ID) + { + /* standard ID*/ + tCAN->IF[u32MsgIfNum].ARB1 = 0ul; + tCAN->IF[u32MsgIfNum].ARB2 = (((pCanMsg->Id) & 0x7FFul) << 2) | CAN_IF_ARB2_DIR_Msk | CAN_IF_ARB2_MSGVAL_Msk; + } + else + { + /* extended ID*/ + tCAN->IF[u32MsgIfNum].ARB1 = (pCanMsg->Id) & 0xFFFFul; + tCAN->IF[u32MsgIfNum].ARB2 = ((pCanMsg->Id) & 0x1FFF0000ul) >> 16 | + CAN_IF_ARB2_DIR_Msk | CAN_IF_ARB2_XTD_Msk | CAN_IF_ARB2_MSGVAL_Msk; + } + + if (pCanMsg->FrameType) + { + tCAN->IF[u32MsgIfNum].ARB2 |= CAN_IF_ARB2_DIR_Msk; + } + else + { + tCAN->IF[u32MsgIfNum].ARB2 &= (~CAN_IF_ARB2_DIR_Msk); + } + + tCAN->IF[u32MsgIfNum].DAT_A1 = (uint16_t)((uint16_t)(((uint16_t)pCanMsg->Data[1] << 8)) | pCanMsg->Data[0]); + tCAN->IF[u32MsgIfNum].DAT_A2 = (uint16_t)((uint16_t)(((uint16_t)pCanMsg->Data[3] << 8)) | pCanMsg->Data[2]); + tCAN->IF[u32MsgIfNum].DAT_B1 = (uint16_t)((uint16_t)(((uint16_t)pCanMsg->Data[5] << 8)) | pCanMsg->Data[4]); + tCAN->IF[u32MsgIfNum].DAT_B2 = (uint16_t)((uint16_t)(((uint16_t)pCanMsg->Data[7] << 8)) | pCanMsg->Data[6]); + + tCAN->IF[u32MsgIfNum].MCON = CAN_IF_MCON_NEWDAT_Msk | pCanMsg->DLC | CAN_IF_MCON_TXIE_Msk | CAN_IF_MCON_EOB_Msk; + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u32MsgNum; + + ReleaseIF(tCAN, u32MsgIfNum); + } + + return rev; +} + +/** + * @brief Set transmit request bit. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * + * @return TRUE: Start transmit message. + * + * @details If a transmission is requested by programming bit TxRqst/NewDat (IFn_CMASK[2]), the TxRqst (IFn_MCON[8]) will be ignored. + */ +int32_t CAN_TriggerTxMsg(CAN_T *tCAN, uint32_t u32MsgNum) +{ + int32_t rev = 1l; + uint32_t u32MsgIfNum; + + if ((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul) + { + rev = 0; /* return FALSE */ + } + else + { + tCAN->STATUS &= (~CAN_STATUS_TXOK_Msk); + + /* read the message contents*/ + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_CLRINTPND_Msk + | CAN_IF_CMASK_TXRQSTNEWDAT_Msk; + + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u32MsgNum; + + while (tCAN->IF[u32MsgIfNum].CREQ & CAN_IF_CREQ_BUSY_Msk) + { + /*Wait*/ + } + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_WRRD_Msk | CAN_IF_CMASK_TXRQSTNEWDAT_Msk; + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u32MsgNum; + + ReleaseIF(tCAN, u32MsgIfNum); + } + + return rev; +} + +/** + * @brief Enable CAN interrupt. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32Mask Interrupt Mask. Valid values are: + * - \ref CAN_CON_IE_Msk Module interrupt enable. + * - \ref CAN_CON_SIE_Msk Status change interrupt enable. + * - \ref CAN_CON_EIE_Msk Error interrupt enable. + * + * @return None + * + * @details The application software has two possibilities to follow the source of a message interrupt. + * First, it can follow the IntId in the Interrupt Register and second it can poll the Interrupt Pending Register. + */ +void CAN_EnableInt(CAN_T *tCAN, uint32_t u32Mask) +{ + tCAN->CON = (tCAN->CON & ~(CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk)) | + (u32Mask & (CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk)); +} + +/** + * @brief Disable CAN interrupt. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32Mask Interrupt Mask. (CAN_CON_IE_Msk / CAN_CON_SIE_Msk / CAN_CON_EIE_Msk). + * + * @return None + * + * @details The interrupt remains active until the Interrupt Register is back to value zero (the cause of the interrupt is reset) or until IE is reset. + */ +void CAN_DisableInt(CAN_T *tCAN, uint32_t u32Mask) +{ + tCAN->CON = tCAN->CON & ~((u32Mask & (CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk))); +} + + +/** + * @brief The function is used to configure a receive message object. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * @param[in] u32IDType Specifies the identifier type of the frames that will be transmitted. Valid values are: + * - \ref CAN_STD_ID The 11-bit identifier. + * - \ref CAN_EXT_ID The 29-bit identifier. + * @param[in] u32ID Specifies the identifier used for acceptance filtering. + * + * @retval FALSE No useful interface. + * @retval TRUE Configure a receive message object success. + * + * @details If the RxIE bit (CAN_IFn_MCON[10]) is set, the IntPnd bit (CAN_IFn_MCON[13]) + * will be set when a received Data Frame is accepted and stored in the Message Object. + */ +int32_t CAN_SetRxMsg(CAN_T *tCAN, uint32_t u32MsgNum, uint32_t u32IDType, uint32_t u32ID) +{ + int32_t rev = (int32_t)TRUE; + uint32_t u32TimeOutCount = 0ul; + + while (CAN_SetRxMsgObj(tCAN, (uint8_t)u32MsgNum, (uint8_t)u32IDType, u32ID, (uint8_t)TRUE) == (int32_t)FALSE) + { + if (++u32TimeOutCount >= RETRY_COUNTS) + { + rev = (int32_t)(FALSE); /* return FALSE */ + break; + } + else + { + } + } + + return rev; +} + +/** + * @brief The function is used to configure a receive message object. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * @param[in] u32IDType Specifies the identifier type of the frames that will be transmitted. Valid values are: + * - \ref CAN_STD_ID The 11-bit identifier. + * - \ref CAN_EXT_ID The 29-bit identifier. + * @param[in] u32ID Specifies the identifier used for acceptance filtering. + * @param[in] u32IDMask Specifies the identifier mask used for acceptance filtering. + * + * @retval FALSE No useful interface. + * @retval TRUE Configure a receive message object success. + * + * @details If the RxIE bit (CAN_IFn_MCON[10]) is set, the IntPnd bit (CAN_IFn_MCON[13]) + * will be set when a received Data Frame is accepted and stored in the Message Object. + */ +int32_t CAN_SetRxMsgAndMsk(CAN_T *tCAN, uint32_t u32MsgNum, uint32_t u32IDType, uint32_t u32ID, uint32_t u32IDMask) +{ + int32_t rev = (int32_t)TRUE; + uint32_t u32TimeOutCount = 0ul; + + while (CAN_SetRxMsgObjAndMsk(tCAN, (uint8_t)u32MsgNum, (uint8_t)u32IDType, u32ID, u32IDMask, (uint8_t)TRUE) == (int32_t)FALSE) + { + if (++u32TimeOutCount >= RETRY_COUNTS) + { + rev = (int32_t)FALSE; + break; + } + else + { + } + } + + return rev; +} + +/** + * @brief The function is used to configure several receive message objects. + * + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum The starting MSG RAM number(0 ~ 31). + * @param[in] u32MsgCount the number of MSG RAM of the FIFO. + * @param[in] u32IDType Specifies the identifier type of the frames that will be transmitted. Valid values are: + * - \ref CAN_STD_ID The 11-bit identifier. + * - \ref CAN_EXT_ID The 29-bit identifier. + * @param[in] u32ID Specifies the identifier used for acceptance filtering. + * + * @retval FALSE No useful interface. + * @retval TRUE Configure receive message objects success. + * + * @details The Interface Registers avoid conflict between the CPU accesses to the Message RAM and CAN message reception + * and transmission by buffering the data to be transferred. + */ +int32_t CAN_SetMultiRxMsg(CAN_T *tCAN, uint32_t u32MsgNum, uint32_t u32MsgCount, uint32_t u32IDType, uint32_t u32ID) +{ + int32_t rev = (int32_t)TRUE; + uint32_t i; + uint32_t u32TimeOutCount; + uint32_t u32EOB_Flag = 0ul; + + for (i = 1ul; i <= u32MsgCount; i++) + { + u32TimeOutCount = 0ul; + + u32MsgNum += (i - 1ul); + + if (i == u32MsgCount) + { + u32EOB_Flag = 1ul; + } + else + { + } + + while (CAN_SetRxMsgObj(tCAN, (uint8_t)u32MsgNum, (uint8_t)u32IDType, u32ID, (uint8_t)u32EOB_Flag) == (int32_t)FALSE) + { + if (++u32TimeOutCount >= RETRY_COUNTS) + { + rev = (int32_t)FALSE; + break; + } + else + { + } + } + } + + return rev; +} + + +/** + * @brief Send CAN message. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * @param[in] pCanMsg Pointer to the message structure where received data is copied. + * + * @retval FALSE 1. When operation in basic mode: Transmit message time out. \n + * 2. When operation in normal mode: No useful interface. \n + * @retval TRUE Transmit Message success. + * + * @details The receive/transmit priority for the Message Objects is attached to the message number. + * Message Object 1 has the highest priority, while Message Object 32 has the lowest priority. + */ +int32_t CAN_Transmit(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T *pCanMsg) +{ + int32_t rev = (int32_t)TRUE; + uint32_t u32Tmp; + + u32Tmp = (tCAN->TEST & CAN_TEST_BASIC_Msk); + + if ((tCAN->CON & CAN_CON_TEST_Msk) && u32Tmp) + { + rev = CAN_BasicSendMsg(tCAN, pCanMsg); + } + else + { + if (CAN_SetTxMsg(tCAN, u32MsgNum, pCanMsg) == FALSE) + { + rev = (int32_t)FALSE; + } + else + { + CAN_TriggerTxMsg(tCAN, u32MsgNum); + } + } + + return rev; +} + + +/** + * @brief Gets the message, if received. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * @param[in] pCanMsg Pointer to the message structure where received data is copied. + * + * @retval FALSE No any message received. + * @retval TRUE Receive Message success. + * + * @details The Interface Registers avoid conflict between the CPU accesses to the Message RAM and CAN message reception + * and transmission by buffering the data to be transferred. + */ +int32_t CAN_Receive(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T *pCanMsg) +{ + int32_t rev = (int32_t)TRUE; + uint32_t u32Tmp; + + u32Tmp = (tCAN->TEST & CAN_TEST_BASIC_Msk); + + if ((tCAN->CON & CAN_CON_TEST_Msk) && u32Tmp) + { + rev = CAN_BasicReceiveMsg(tCAN, pCanMsg); + } + else + { + rev = CAN_ReadMsgObj(tCAN, (uint8_t)u32MsgNum, (uint8_t)TRUE, pCanMsg); + } + + return rev; +} + +/** + * @brief Clear interrupt pending bit. + * @param[in] tCAN The pointer to CAN module base address. + * @param[in] u32MsgNum Specifies the Message object number, from 0 to 31. + * + * @return None + * + * @details An interrupt remains pending until the application software has cleared it. + */ +void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum) +{ + uint32_t u32MsgIfNum; + + if ((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul) + { + u32MsgIfNum = 0ul; + } + else + { + } + + tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_CLRINTPND_Msk | CAN_IF_CMASK_TXRQSTNEWDAT_Msk; + tCAN->IF[u32MsgIfNum].CREQ = 1ul + u32MsgNum; + + ReleaseIF(tCAN, u32MsgIfNum); +} + + +/*@}*/ /* end of group CAN_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group CAN_Driver */ + +/*@}*/ /* end of group Standard_Driver */ + +/*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_cap.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_cap.c new file mode 100644 index 0000000000000000000000000000000000000000..69bea7c7a44686160af48b07b78f9615dd76b4f3 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_cap.c @@ -0,0 +1,1520 @@ +/**************************************************************************//** +* @file cap.c +* @version V1.00 +* @brief N9H30 CAP driver source file +* +* SPDX-License-Identifier: Apache-2.0 +* @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_cap.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_CAP_Driver CAP Driver + @{ +*/ + +/** @addtogroup N9H30_CAP_EXPORTED_FUNCTIONS CAP Exported Functions + @{ +*/ + +/// @cond HIDDEN_SYMBOLS +PFN_CAP_CALLBACK(pfnCAP_IntHandlerTable)[4] = {0}; +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief CAP interrupt Handler + * + * @param None + * + * @return None + * + * @details Driver internal use API to process the interrupt of CAP + * As interrupt occurrence, the register call back function will be executed + */ +static UINT32 u32EscapeFrame = 0; +//static UINT32 g_u32DeviceType = 0; +static void CAP_IntHandler(void) +{ + UINT32 u32CapInt; + UINT32 uBuf = 0; + + if ((inp32(REG_CLK_HCLKEN) & (0x1 << 26)) == (0x1 << 26)) /* CMOS sensor interface controller clock enabled */ + { + u32CapInt = inp32(REG_CAP_INT); + if ((u32CapInt & (VIEN | VINTF)) == (VIEN | VINTF)) + { + if (pfnCAP_IntHandlerTable[0] != 0) + pfnCAP_IntHandlerTable[0](uBuf, uBuf, u32EscapeFrame); + outp32(REG_CAP_INT, (u32CapInt & ~(MDINTF | ADDRMINTF | MEINTF))); /* Clear Frame end interrupt */ + u32EscapeFrame = u32EscapeFrame + 1; + } + else if ((u32CapInt & (ADDRMIEN | ADDRMINTF)) == (ADDRMIEN | ADDRMINTF)) + { + if (pfnCAP_IntHandlerTable[1] != 0) + pfnCAP_IntHandlerTable[1](uBuf, uBuf, u32EscapeFrame); + outp32(REG_CAP_INT, (u32CapInt & ~(MDINTF | VINTF | MEINTF))); /* Clear Address match interrupt */ + } + else if ((u32CapInt & (MEIEN | MEINTF)) == (MEIEN | MEINTF)) + { + if (pfnCAP_IntHandlerTable[2] != 0) + pfnCAP_IntHandlerTable[2](uBuf, uBuf, u32EscapeFrame); + outp32(REG_CAP_INT, (u32CapInt & ~(MDINTF | VINTF | ADDRMINTF))); /* Clear Memory error interrupt */ + } + else if ((u32CapInt & (MDIEN | MDINTF)) == (MDIEN | MDINTF)) + { + if (pfnCAP_IntHandlerTable[3] != 0) + pfnCAP_IntHandlerTable[3](uBuf, uBuf, u32EscapeFrame); + outp32(REG_CAP_INT, (u32CapInt & ~(VINTF | MEINTF | ADDRMINTF))); /* Clear Memory error interrupt */ + } + } +} + +/** + * @brief Set Inital Frame + * + * @return None + * + * @details If enable interrupt, there is internal counter that records how many frames have pass. + * Set the internal counters to zero. The internal counter may be not a constant + */ +void CAP_SetInitFrame(void) +{ + u32EscapeFrame = 0; +} + +/** + * @brief Get Inital Frame + * + * @retval >0 Internal counters + * + * @details If enable interrupt, there is internal counter that records how many frames have pass. + * Get the internal counters. The internal counter may be not a constant + */ +UINT32 CAP_GetSkipFrame(void) +{ + return u32EscapeFrame; +} + +/** + * @brief CAP Initial + * + * @param[in] bIsEnableSnrClock Enable/Disable sensor clock + * 1 : Enable + * 0 : Disable + * @param[in] eSnrSrc Set CAP clock source. Including : + * - \ref eCAP_SNR_APLL + * - \ref eCAP_SNR_UPLL + * @param[in] u32SensorFreqKHz Specify the sensor clock + * + * @return None + * + * @details To Initial sensor source clock and frequency for CAP interface + */ +void CAP_Init(BOOL bIsEnableSnrClock, E_CAP_SNR_SRC eSnrSrc, UINT32 u32SensorFreqKHz/*KHz unit*/) +{ + UINT32 u32PllClock, u32SenDiv;// u32ExtFreq; + UINT32 u32Div0, u32Div1; + UINT32 u32SenSrc; + volatile UINT32 u32Divider; + + /* MFP_GPI_L : I3=SEN_CLK0, I4=SEN_PCLK, I5=SEN_HSYNC, I6=SEN_VSYNC, I7=SEN_FIFLD*/ + outpw(REG_SYS_GPI_MFPL, (inpw(REG_SYS_GPI_MFPL) & (0x00000FFF)) | 0x33333000); + + /* MFP_GPI_H : SEN_PDATA[0~7]*/ + outpw(REG_SYS_GPI_MFPH, (inpw(REG_SYS_GPI_MFPH) & (0xFFFFFFFF)) | 0x33333333); + + u32SensorFreqKHz = u32SensorFreqKHz * 1000; + switch (eSnrSrc) + { + case eCAP_SNR_APLL: + u32PllClock = sysGetClock(SYS_APLL) * 1000000; + u32SenSrc = 0x2 << 19; //APLL for sensor clock + break; + case eCAP_SNR_UPLL: + u32PllClock = sysGetClock(SYS_UPLL) * 1000000; + u32SenSrc = 0x3 << 19; //UPLL for sensor clock + break; + } + + + u32SenDiv = u32PllClock / (u32SensorFreqKHz); + if (u32PllClock % u32SensorFreqKHz != 0) u32SenDiv = u32SenDiv + 1; + for (u32Div1 = 1; u32Div1 <= 16; u32Div1 = u32Div1 + 1) + { + for (u32Div0 = 1; u32Div0 <= 8; u32Div0 = u32Div0 + 1) + if (u32SenDiv == u32Div0 * u32Div1) break; + if (u32Div0 >= 9) continue; + if (u32SenDiv == u32Div0 * u32Div1) break; + } + //sysprintf("Div0 and Div1 = %d, %d ", u32Div0, u32Div1); + u32Div0 = u32Div0 - 1; + u32Div1 = u32Div1 - 1; + + if (bIsEnableSnrClock) + { + outp32(REG_CLK_HCLKEN, inp32(REG_CLK_HCLKEN) | (1 << 27)); /* CMOS Sensor Reference Clock Output Enable */ + outp32(REG_CLK_HCLKEN, inp32(REG_CLK_HCLKEN) | (1 << 26)); /* CMOS Sensor Interface Controller Clock Enable */ + } + else + { + outp32(REG_CLK_HCLKEN, inp32(REG_CLK_HCLKEN) & ~(1 << 27)); /* CMOS Sensor Reference Clock Output Disabled */ + outp32(REG_CLK_HCLKEN, inp32(REG_CLK_HCLKEN) & ~(1 << 26)); /* CMOS Sensor Interface Controller Clock Disabled */ + } + u32Divider = u32SenSrc | ((u32Div0 << 16) | (u32Div1 << 24)) ; + //sysprintf("Sensor Divider = 0x%08x\n", u32Divider); + + outp32(REG_CLK_DIVCTL3, (inp32(REG_CLK_DIVCTL3) & ~((0x3 << 19) | (0x7 << 16) | (0xF << 24))) | u32Divider); + + +} + +/** + * @brief CAP Open + * + * @param[in] u32SensorFreqKHz Specify the sensor clock + * + * @retval 0 Success + * @retval <0 Error code + * + * @details Initialize the CAP engine. Register a call back for driver internal using + */ +INT32 CAP_Open(UINT32 u32SensorFreqKHz) +{ + + UINT32 u32PllClock;// u32ExtFreq; + UINT32 u32SenDiv; + UINT32 u32Div0, u32Div1; + UINT32 u32SenSrc; + volatile UINT32 u32Divider; + + u32SensorFreqKHz = u32SensorFreqKHz * 1000; + + outp32(REG_CLK_PMCON, inpw(REG_CLK_PMCON) | (0x1 << 4)) ; /* Sensor clock keep on high level */ + outp32(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | (0x1 << 26)); /* CMOS sensor interface controller clock enable */ + outp32(REG_SYS_AHBIPRST, inp32(REG_SYS_AHBIPRST) | (1 << 10)); /* Video capture (CMOS sensor interface) reset enable. */ + outp32(REG_SYS_AHBIPRST, inp32(REG_SYS_AHBIPRST) & ~(1 << 10)); /* Video capture (CMOS sensor interface) reset disable */ + + switch ((inpw(REG_CLK_DIVCTL3) >> 19) & 0x3) + { + case eCAP_SNR_APLL: + u32PllClock = sysGetClock(SYS_APLL) * 1000000; + u32SenSrc = 0x2 << 19; //APLL for sensor clock + break; + case eCAP_SNR_UPLL: + u32PllClock = sysGetClock(SYS_UPLL) * 1000000; + u32SenSrc = 0x3 << 19; //APLL for sensor clock + break; + } + + u32SenDiv = u32PllClock / (u32SensorFreqKHz); + if (u32PllClock % u32SensorFreqKHz != 0) + u32SenDiv = u32SenDiv + 1; + for (u32Div1 = 1; u32Div1 <= 16; u32Div1 = u32Div1 + 1) + { + for (u32Div0 = 1; u32Div0 <= 8; u32Div0 = u32Div0 + 1) + { + if (u32SenDiv == u32Div0 * u32Div1) + break; + } + if (u32Div0 >= 9) continue; + if (u32SenDiv == u32Div0 * u32Div1) + break; + } + //sysprintf("Div0 and Div1 = %d, %d ", u32Div0, u32Div1); + u32Div0 = u32Div0 - 1; + u32Div1 = u32Div1 - 1; + u32Divider = u32SenSrc | ((u32Div0 << 16) | (u32Div1 << 24)) ; + //sysprintf("Sensor Divider = 0x%08x\n", u32Divider); + + outp32(REG_CLK_DIVCTL3, (inp32(REG_CLK_DIVCTL3) & ~((0x3 << 19) | (0x7 << 16) | (0xF << 24))) | u32Divider); + + sysInstallISR(IRQ_LEVEL_1, CAP_IRQn, (PVOID)CAP_IntHandler); + sysEnableInterrupt(CAP_IRQn); + + return Successful; +} + + +/** + * @brief videoIn Reset + * + * @return None + * + * @details Capture interface reset. + */ +void CAP_Reset(void) +{ + outp32(REG_CAP_CTL, inp32(REG_CAP_CTL) | (VPRST)); + outp32(REG_CAP_CTL, inp32(REG_CAP_CTL) & (~VPRST)); +} + +/** + * @brief videoIn Close + * + * @return None + * + * @details Disable pin function,engine clock and interrupt + */ +void CAP_Close(void) +{ + // 1. Disable IP's interrupt + sysDisableInterrupt(CAP_IRQn); + // 2. Disable IP’s clock + outp32(REG_CLK_HCLKEN, inp32(REG_CLK_HCLKEN) & ~(0x1 << 25)); + CAP_Reset(); + outp32(REG_CLK_HCLKEN, inp32(REG_CLK_HCLKEN) & ~(0x1 << 26)); + // 3. Disable Capture pin function +} + +/** + * @brief Configure packet frame buffer. + * + * @param[in] bFrameSwitch Software mode buffer select + * 0: Packet buffer 0 + * 1: Packet buffer 1 + * @return None + * + * @details This function set packet frame buffer control + */ +void CAP_SetPacketFrameBufferControl(BOOL bFrameSwitch) +{ + UINT32 u32Ctl; + u32Ctl = inp32(REG_CAP_CTL) & ~(ADDRSW); + outp32(REG_CAP_CTL, u32Ctl | (bFrameSwitch ? ADDRSW : 0)); +} + +/** +* @brief Get packet frame buffer. + * + * @param pbFrameSwitch Software mode buffer select + * 0: Packet buffer 0 + * 1: Packet buffer 1 + * @return None + * + * @details This function get packet frame buffer control + */ +void CAP_GetPacketFrameBufferControl(PBOOL pbFrameSwitch) +{ + UINT32 u32Ctl = inp32(REG_CAP_CTL); + *pbFrameSwitch = (u32Ctl & ADDRSW) >> 3; +} + +/** +* @brief Configure callback function + * + * @param[in] eIntType Set interrupt type. Including : + * - \ref eCAP_MDINTF + * - \ref eCAP_ADDRMINTF + * - \ref eCAP_MEINTF + * - \ref eCAP_VINTF + * @param[in] pfnCallback Set Callback function. + * The callbakc function : + * void (*PFN_CAP_CALLBACK)(UINT8 u8PacketBufID,UINT8 u8PlanarBufID, UINT8 u8FrameRate); + * @param[in] pfnOldCallback Set Old callback function + * The callbakc function : + * void *(*PFN_CAP_CALLBACK)(UINT8 u8PacketBufID,UINT8 u8PlanarBufID, UINT8 u8FrameRate); + * @retval 0 Success + * @retval <0 Error code + * + * @details This function configure callback function and set trigger level + */ +INT32 CAP_InstallCallback(E_CAP_INT_TYPE eIntType, PFN_CAP_CALLBACK pfnCallback, PFN_CAP_CALLBACK *pfnOldCallback) +{ + if (eIntType == eCAP_VINTF) + { + *pfnOldCallback = pfnCAP_IntHandlerTable[0]; + pfnCAP_IntHandlerTable[0] = (PFN_CAP_CALLBACK)(pfnCallback); + } + else if (eIntType == eCAP_ADDRMINTF) + { + *pfnOldCallback = pfnCAP_IntHandlerTable[1]; + pfnCAP_IntHandlerTable[1] = (PFN_CAP_CALLBACK)(pfnCallback); + } + else if (eIntType == eCAP_MEINTF) + { + *pfnOldCallback = pfnCAP_IntHandlerTable[2]; + pfnCAP_IntHandlerTable[2] = (PFN_CAP_CALLBACK)(pfnCallback); + } + else if (eIntType == eCAP_MDINTF) + { + *pfnOldCallback = pfnCAP_IntHandlerTable[3]; + pfnCAP_IntHandlerTable[3] = (PFN_CAP_CALLBACK)(pfnCallback); + } + else + return E_CAP_INVALID_INT; + return Successful; +} + +/** + * @brief Enable videoIn interrupt. + * + * @param[in] eIntType Interrupt type. Incuding: + * - \ref eCAP_MDINTF + * - \ref eCAP_ADDRMINTF + * - \ref eCAP_MEINTF + * - \ref eCAP_VINTF + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to enable videoIn interrupt. + */ +INT32 CAP_EnableInt(E_CAP_INT_TYPE eIntType) +{ + switch (eIntType) + { + case eCAP_MDINTF: + case eCAP_ADDRMINTF: + case eCAP_MEINTF: + case eCAP_VINTF: + outp32(REG_CAP_INT, inp32(REG_CAP_INT) | eIntType); + break; + default: + return E_CAP_INVALID_INT; + } + return Successful; +} + +/** + * @brief Disable videoIn interrupt + * + * @param[in] eIntType Interrupt type. Incuding: + * - \ref eCAP_MDINTF + * - \ref eCAP_ADDRMINTF + * - \ref eCAP_MEINTF + * - \ref eCAP_VINTF + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to disable videoIn interrupt. + */ +INT32 CAP_DisableInt(E_CAP_INT_TYPE eIntType) +{ + switch (eIntType) + { + case eCAP_MDINTF: + case eCAP_ADDRMINTF: + case eCAP_MEINTF: + case eCAP_VINTF: + outp32(REG_CAP_INT, inp32(REG_CAP_INT) & ~eIntType); + break; + default: + return E_CAP_INVALID_INT; + } + return Successful; +} + +/** + * @brief Check videoIn interrupt + * + * @param[in] eIntType Interrupt type. Incuding: + * - \ref eCAP_MDINTF + * - \ref eCAP_ADDRMINTF + * - \ref eCAP_MEINTF + * - \ref eCAP_VINTF + * @retval 1 Enable + * @retval 0 Disable + * + * @details This function is used to check videoIn interrupt. + */ +BOOL CAP_IsIntEnabled(E_CAP_INT_TYPE eIntType) +{ + UINT32 u32IntEnable = inp32(REG_CAP_INT); + switch (eIntType) + { + case eCAP_MDINTF: + u32IntEnable = u32IntEnable & eCAP_MDINTF; + break; + case eCAP_ADDRMINTF: + u32IntEnable = u32IntEnable & eCAP_ADDRMINTF; + break; + case eCAP_MEINTF: + u32IntEnable = u32IntEnable & eCAP_MEINTF; + break; + case eCAP_VINTF: + u32IntEnable = u32IntEnable & eCAP_VINTF; + break; + } + return (u32IntEnable ? TRUE : FALSE); +} + +/** + * @brief Clear videoIn interrupt flag. + * + * @param[in] eIntType Interrupt type. Incuding: + * - \ref eCAP_MDINTF + * - \ref eCAP_ADDRMINTF + * - \ref eCAP_MEINTF + * - \ref eCAP_VINTF + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to clear videoIn interrupt flag. + */ +INT32 CAP_ClearInt(E_CAP_INT_TYPE eIntType) +{ + UINT32 u32IntChannel = eIntType >> 16; + switch (eIntType) + { + case eCAP_MDINTF: + outp32(REG_CAP_INT, (inp32(REG_CAP_INT) & ~((eCAP_ADDRMINTF | eCAP_MEINTF | eCAP_VINTF) >> 16)) | + u32IntChannel); + break; + case eCAP_ADDRMINTF: + outp32(REG_CAP_INT, (inp32(REG_CAP_INT) & ~((eCAP_MDINTF | eCAP_MEINTF | eCAP_VINTF) >> 16)) | + u32IntChannel); + break; + case eCAP_MEINTF: + outp32(REG_CAP_INT, (inp32(REG_CAP_INT) & ~((eCAP_MDINTF | eCAP_ADDRMINTF | eCAP_VINTF) >> 16)) | + u32IntChannel); + break; + case eCAP_VINTF: + outp32(REG_CAP_INT, (inp32(REG_CAP_INT) & ~((eCAP_MDINTF | eCAP_MEINTF | eCAP_ADDRMINTF) >> 16)) | + u32IntChannel); + break; + default: + return E_CAP_INVALID_INT; + } + return Successful; + + +} + +/** + * @brief Polling videoIn interrupt flag. + * + * @param[in] eIntType Interrupt type. Incuding: + * - \ref eCAP_MDINTF + * - \ref eCAP_ADDRMINTF + * - \ref eCAP_MEINTF + * - \ref eCAP_VINTF + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to poll videoIn interrupt flag. + */ +BOOL CAP_PollInt(E_CAP_INT_TYPE eIntType) +{ + UINT32 u32IntStatus = inp32(REG_CAP_INT); + switch (eIntType) + { + case eCAP_MDINTF: + u32IntStatus = u32IntStatus & (eCAP_MDINTF >> 16); + break; + case eCAP_ADDRMINTF: + u32IntStatus = u32IntStatus & (eCAP_ADDRMINTF >> 16); + break; + case eCAP_MEINTF: + u32IntStatus = u32IntStatus & (eCAP_MEINTF >> 16); + break; + case eCAP_VINTF: + u32IntStatus = u32IntStatus & (eCAP_VINTF >> 16); + break; + } + return (u32IntStatus ? TRUE : FALSE); +} + +/** + * @brief Enable engine clock and turn on the pipe. + * + * @param[in] bEngEnable Enable engine clock. + * 1 : Enable engine clock. + * 0 : Disable engine clock. + * @param[in] ePipeEnable Enable pipe type. Incuding: + * - \ref eCAP_BOTH_PIPE_DISABLE + * - \ref eCAP_PLANAR + * - \ref eCAP_PACKET + * - \ref eCAP_BOTH_PIPE_ENABLE + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to enable engine clock and pipe type. + */ +void CAP_SetPipeEnable( + BOOL bEngEnable, + E_CAP_PIPE ePipeEnable +) +{ + outp32(REG_CAP_CTL, (inp32(REG_CAP_CTL) & ~(CAPEN | PKTEN | PLNEN)) + | (((bEngEnable ? CAPEN : 0x0)) + // | ((ePipeEnable & ~(PKTEN | PLNEN))<<5)) ); + | ((ePipeEnable & 0x03) << 5))); +} // DrvVideoIn_SetPipeEnable + +/** + * @brief Get engine clock and pipe type. + * + * @param[out] pbEngEnable Enable engine clock. + * 1 : Enable engine clock. + * 0 : Disable engine clock. + * @param[out] pePipeEnable Pipe type. Incuding: + * - \ref eCAP_BOTH_PIPE_DISABLE + * - \ref eCAP_PLANAR + * - \ref eCAP_PACKET + * - \ref eCAP_BOTH_PIPE_ENABLE + * @return None + * + * @details This function is used to get engin clock and pipe type. + */ +void CAP_GetPipeEnable(PBOOL pbEngEnable, E_CAP_PIPE *pePipeEnable) +{ + UINT32 u32Temp = inp32(REG_CAP_CTL); + + *pbEngEnable = (u32Temp & CAPEN) ? TRUE : FALSE; + *pePipeEnable = (E_CAP_PIPE)((u32Temp & (PKTEN | PLNEN)) >> 5); +} // DrvVideoIn_GetPipeEnable + + +/** + * @brief Set Shadow(Update) Register + * + * @details This function is used to reload frame buffer address after + * setting shoaw(update) register. + */ +void CAP_SetShadowRegister(void) +{ + outp32(REG_CAP_CTL, inp32(REG_CAP_CTL) | UPDATE); +} // DrvVideoIn_SetShadowRegister + + +/** + * @brief Set sensor polarity. + * + * @param[in] bVsync Sensor Vsync Polarity. + * 1 : High Active + * 0 : Low Active + * @param[in] bHsync Sensor Hsync Polarity. + * 1 : High Active + * 0 : Low Active + * @param[in] bPixelClk Sensor Vsync Polarity. + * 1 : Falling Edge + * 0 : Rising Edig + * @return None + * + * @details This function is used to set sensor polarity. + */ +void CAP_SetSensorPolarity(BOOL bVsync, BOOL bHsync, BOOL bPixelClk) +{ + UINT32 u32Polarity, u32RegVal; + u32RegVal = inp32(REG_CAP_PAR); + //sysprintf("Enter Register addr = 0x%x\n", (REG_CAP_PAR)); + //sysprintf("Enter Register value = 0x%x\n", u32RegVal); + u32Polarity = (((bVsync ? VSP : 0x0) | (bHsync ? HSP : 0x0)) | (bPixelClk ? PCLKP : 0x0)); + u32RegVal = (inp32(REG_CAP_PAR) & ~(VSP | HSP | PCLKP)) ; + //sysprintf("REG_VPEPAR = 0x%x", (u32RegVal | u32Polarity)); + outp32((REG_CAP_PAR), (u32RegVal | u32Polarity)); +} + +/** + * @brief Get sensor polarity. + * + * @param[out] pbVsync Sensor Vsync Polarity. + * 1 : High Active + * 0 : Low Active + * @param[out] pbHsync Sensor Hsync Polarity. + * 1 : High Active + * 0 : Low Active + * @param[out] pbPixelClk Sensor Vsync Polarity. + * 1 : Falling Edge + * 0 : Rising Edig + * @return None + * + * @details This function is used to get sensor polarity. + */ +void CAP_GetSensorPolarity(PBOOL pbVsync, PBOOL pbHsync, PBOOL pbPixelClk) +{ + UINT32 u32Temp = inp32(REG_CAP_PAR); + + *pbVsync = (u32Temp & VSP) ? TRUE : FALSE; + *pbHsync = (u32Temp & HSP) ? TRUE : FALSE; + *pbPixelClk = (u32Temp & PCLKP) ? TRUE : FALSE; +} + +/** + * @brief Set data format and order. + * + * @param[in] eInputOrder Data order for input format.Including : + * - \ref eCAP_IN_UYVY = Y0 U0 Y1 V0 + * - \ref eCAP_IN_YUYV = Y0 V0 Y1 U0 + * - \ref eCAP_IN_VYUY = U0 Y0 V0 Y1 + * - \ref eCAP_IN_YVYU = V0 Y0 U0 Y1 + * @param[in] eInputFormat Input data format.Including : + * - \ref eCAP_IN_YUV422 + * - \ref eCAP_IN_RGB565 + * @param[in] eOutputFormat Sensor Vsync Polarity.Including : + * - \ref eCAP_OUT_YUV422 = YCbCr422 + * - \ref eCAP_OUT_ONLY_Y = only output Y + * - \ref eCAP_OUT_RGB555 = rgb555 + * - \ref eCAP_OUT_RGB565 = rgb565 + * @return None + * + * @details This function is used to set data format and order. + */ +void CAP_SetDataFormatAndOrder(E_CAP_ORDER eInputOrder, E_CAP_IN_FORMAT eInputFormat, E_CAP_OUT_FORMAT eOutputFormat) +{ + outp32((REG_CAP_PAR), (inp32(REG_CAP_PAR) & ~(OUTFMT | INDATORD | INFMT)) + | ((((eInputOrder << 2) & INDATORD) + | (eInputFormat & INFMT)) + | ((eOutputFormat << 4) & OUTFMT))); +} // DrvVideoIn_SetDataFormatAndOrder + +/** + * @brief Get data format and order. + * + * @param[out] peInputOrder Data order for input format.Including : + * - \ref eCAP_IN_UYVY + * - \ref eCAP_IN_YUYV + * - \ref eCAP_IN_VYUY + * - \ref eCAP_IN_YVYU + * @param[out] peInputFormat Input data format.Including : + * - \ref eCAP_IN_YUV422 + * - \ref eCAP_IN_RGB565 + * @param[out] peOutputFormat Sensor Vsync Polarity.Including : + * - \ref eCAP_OUT_YUV422 = YCbCr422 + * - \ref eCAP_OUT_ONLY_Y = only output Y + * - \ref eCAP_OUT_RGB555 = rgb555 + * - \ref eCAP_OUT_RGB565 = rgb565 + * @return None + * + * @details This function is used to get data format and order. + */ +void CAP_GetDataFormatAndOrder(E_CAP_ORDER *peInputOrder, E_CAP_IN_FORMAT *peInputFormat, E_CAP_OUT_FORMAT *peOutputFormat) +{ + UINT32 u32Temp = inp32(REG_CAP_PAR); + + *peInputOrder = (E_CAP_ORDER)((u32Temp & INDATORD) >> 2); + *peInputFormat = (E_CAP_IN_FORMAT)(u32Temp & INFMT); + *peOutputFormat = (E_CAP_OUT_FORMAT)((u32Temp & OUTFMT) >> 4); +} + +/** + * @brief Set planar format. + * + * @param[in] ePlanarFmt Data order for input format.Including : + * - \ref eCAP_PLANAR_YUV422 + * - \ref eCAP_PLANAR_YUV420 + * @return None + * + * @details This function is used to set planar format. + */ +void CAP_SetPlanarFormat(E_CAP_PLANAR_FORMAT ePlanarFmt) +{ + switch (ePlanarFmt) + { + case eCAP_PLANAR_YUV422: + outp32((REG_CAP_PAR), (inp32(REG_CAP_PAR) & ~(PLNFMT))); + break; + case eCAP_PLANAR_YUV420: + outp32((REG_CAP_PAR), ((inp32(REG_CAP_PAR) | (PLNFMT)))); + break; + } +} + +/** + * @brief Get planar format. + * + * @retval - \ref eCAP_PLANAR_YUV422 : Planar format is YUV420. + * @retval - \ref eCAP_PLANAR_YUV420 : Planar format is YUV422. + * + * @details This function is used to get planar format. + */ +BOOL CAP_GetPlanarFormat(void) +{ + return ((inp32(REG_CAP_PAR) & PLNFMT) >> 7); +} + +/** + * @brief Set motion detection parameter. + * + * @param[in] bEnable Enable Motion Detection.Including : + * 0 : Disable motion detection. + * 1 : Enable motion detection. + * @param[in] bBlockSize Motion Detection Block Size.Including : + * 0 : Block size is set to 16x16. + * 1 : Block size is set to 8x8. + * @param[in] bSaveMode Motion Detection Save Mode.Including : + * 0 : 1 bit DIFF + 7 Y Differential. + * 1 : 1 bit DIFF only. + * @return None + * + * @details This function is used to set motion detection parameter. + */ +void CAP_SetMotionDet(BOOL bEnable, BOOL bBlockSize, BOOL bSaveMode) +{ + outp32(REG_CAP_MD, (inp32(REG_CAP_MD) & ~(MDSM | MDBS | MDEN)) | + (((bEnable ? MDEN : 0) | (bBlockSize ? MDBS : 0)) | + (bSaveMode ? MDSM : 0))); +} + +/** + * @brief Get motion detection parameter. + * + * @param[out] pbEnable Enable Motion Detection.Including : + * 0 : Disable motion detection. + * 1 : Enable motion detection. + * @param[out] pbBlockSize Motion Detection Block Size.Including : + * 0 : Block size is set to 16x16. + * 1 : Block size is set to 8x8. + * @param[out] pbSaveMode Motion Detection Save Mode.Including : + * 0 : 1 bit DIFF + 7 Y Differential. + * 1 : 1 bit DIFF only. + * @return None + * + * @details This function is used to get motion detection parameter. + */ +void CAP_GetMotionDet(PBOOL pbEnable, PBOOL pbBlockSize, PBOOL pbSaveMode) +{ + UINT32 u32RegData = inp32(REG_CAP_MD); + *pbEnable = (u32RegData & MDEN); + *pbBlockSize = (u32RegData & MDBS) >> 8; + *pbSaveMode = (u32RegData & MDSM) >> 9; +} + +/** + * @brief Set motion detection parameter externtion. + * + * @param[in] u32DetFreq Motion Detection frequency.Including : + * 0 : Each frame + * 1 : Every 2 frame + * 2 : Every 3 frame + * 3 : Every 4 frame + * @param[in] u32Threshold Motion detection threshold.It should be 0~31. + * + * @param[in] u32OutBuffer Motion Detection Output Address Register.(Word Alignment) + * + * @param[in] u32LumBuffer Motion Detection Temp Y Output Address Register.(Word Alignment) + * + * @return None + * + * @details This function is used to set motion detection parameter externtion. + */ +void CAP_SetMotionDetEx(UINT32 u32DetFreq, UINT32 u32Threshold, UINT32 u32OutBuffer, UINT32 u32LumBuffer) +{ + outp32(REG_CAP_MD, (inp32(REG_CAP_MD) & ~MDDF) | ((u32DetFreq << 10) & MDDF)); + outp32(REG_CAP_MD, (inp32(REG_CAP_MD) & ~MDTHR) | ((u32Threshold << 16) & MDTHR)); + outp32(REG_CAP_MDADDR, u32OutBuffer); + outp32(REG_CAP_MDYADDR, u32LumBuffer); +} + +/** + * @brief Get motion detection parameter externtion. + * + * @param[out] pu32DetFreq Motion Detection frequency.Including : + * 0 : Each frame + * 1 : Every 2 frame + * 2 : Every 3 frame + * 3 : Every 4 frame + * @param[out] pu32Threshold Motion detection threshold.It should be 0~31. + * + * @param[out] pu32OutBuffer Motion Detection Output Address Register.(Word Alignment) + * + * @param[out] pu32LumBuffer Motion Detection Temp Y Output Address Register.(Word Alignment) + * + * @return None + * + * @details This function is used to get motion detection parameter externtion. + */ +void CAP_GetMotionDetEx(PUINT32 pu32DetFreq, PUINT32 pu32Threshold, PUINT32 pu32OutBuffer, PUINT32 pu32LumBuffer) +{ + UINT32 u32RegData; + u32RegData = inp32(REG_CAP_MD); + *pu32DetFreq = u32RegData & MDDF; + *pu32Threshold = u32RegData & MDTHR; + *pu32OutBuffer = inp32(REG_CAP_MDADDR); + *pu32LumBuffer = inp32(REG_CAP_MDYADDR); +} + +/** + * @brief Set motion detection frequency. + * + * @param[in] u32DetFreq Motion Detection frequency.Including : + * 0 : Each frame + * 1 : Every 2 frame + * 2 : Every 3 frame + * 3 : Every 4 frame + * @return None + * + * @details This function is used to set motion detection frequency. + */ +void CAP_SetMotionDetFreq(UINT32 u32DetFreq) +{ + outp32(REG_CAP_MD, (inp32(REG_CAP_MD) & ~MDDF) | + ((u32DetFreq << 10) & MDDF)); +} + +/** + * @brief Get motion detection frequency. + * + * @param[out] pu32DetFreq Motion Detection frequency.Including : + * 0 : Each frame + * 1 : Every 2 frame + * 2 : Every 3 frame + * 3 : Every 4 frame + * @return None + * + * @details This function is used to get motion detection frequency. + */ +void CAP_GetMotionDetFreq(PUINT32 pu32DetFreq) +{ + UINT32 u32RegData; + u32RegData = inp32(REG_CAP_MD); + *pu32DetFreq = u32RegData & MDDF; +} + +/** + * @brief Set One shutte or continuous mode. + * + * @param[in] bIsOneSutterMode Enable One shutte.Including : + * 1 : Enable One shutte mode. + * 0 : Disable One shutte mode. + * @return None + * + * @details This function is used to set one shutte or continuous mode. + * Image capture interface automatically disable the capture + * inteface after a frame bad been captured. + */ +void CAP_SetOperationMode(BOOL bIsOneSutterMode) +{ + outp32(REG_CAP_CTL, (inp32(REG_CAP_CTL) & ~SHUTTER) | + ((bIsOneSutterMode << 16) & SHUTTER)); +} // DrvVideoIn_SetOperationMode + +/** + * @brief Get One shutte or continuous mode. + * + * @retval 1 : Disable one shutte mode + * @retval 0 : Enable one shutte mode + * + * @details This function is used to get one shutte or continuous mode. + * Image capture interface automatically disable the capture + * inteface after a frame bad been captured. + */ +BOOL CAP_GetOperationMode(void) +{ + return ((inp32(REG_CAP_CTL) & SHUTTER) ? TRUE : FALSE); +} // DrvVideoIn_GetOperationMode + + +/** + * @brief Get packet/planar processed data count. + * + * @param[in] ePipe Pipe type. Including : + * - \ref eCAP_PACKET + * - \ref eCAP_PLANAR + * + * @return Get current packet/planar processed data count. + * + * @details This function is used to get packet/planar processed data count. + */ +UINT32 CAP_GetProcessedDataCount(E_CAP_PIPE ePipe) +{ + if (ePipe == eCAP_PACKET) + return inp32(REG_CAP_CURADDRP); /* Packet pipe */ + else if (ePipe == eCAP_PLANAR) + return inp32(REG_CAP_CURADDRY); /* Planar pipe */ + else + return 0; +} + + +/** + * @brief Set cropping window vertical/horizontal starting address. + * + * @param[in] u32VerticalStart Cropping window vertical starting address. + * @param[in] u32HorizontalStart Cropping window horizontal starting address. + * + * @return None. + * + * @details This function is used to set cropping window vertical/horizontal starting address. + */ +void CAP_SetCropWinStartAddr(UINT32 u32VerticalStart, UINT32 u32HorizontalStart) +{ + outp32(REG_CAP_CWSP, (inp32(REG_CAP_CWSP) & ~(CWSADDRV | CWSADDRH)) //(Y|X) + | ((u32VerticalStart << 16) + | u32HorizontalStart)); +} + + +/** + * @brief Get cropping window vertical/horizontal starting address. + * + * @param[out] pu32VerticalStart Cropping window vertical starting address. + * @param[out] pu32HorizontalStart Cropping window horizontal starting address. + * + * @return None. + * + * @details This function is used to get cropping window vertical/horizontal starting address. + */ +void CAP_GetCropWinStartAddr(PUINT32 pu32VerticalStart, PUINT32 pu32HorizontalStart) +{ + UINT32 u32Temp = inp32(REG_CAP_CWSP); + + *pu32VerticalStart = (u32Temp & CWSADDRV) >> 16; + *pu32HorizontalStart = u32Temp & CWSADDRH; +} + +/** + * @brief Set cropping window size. + * + * @param[in] u32Width Cropping window width. + * @param[in] u32Height Cropping window heigh. + * + * @return None. + * + * @details This function is used to set cropping window size. + */ +void CAP_SetCropWinSize(UINT32 u32Height, UINT32 u32Width) +{ + outp32(REG_CAP_CWS, (inp32(REG_CAP_CWS) & ~(CWH | CWW)) + | ((u32Height << 16) + | u32Width)); +} + + +/** + * @brief Get cropping window size. + * + * @param[out] pu32Width Cropping window width. + * @param[out] pu32Height Cropping window heigh. + * + * @return None. + * + * @details This function is used to get cropping window size. + */ +void CAP_GetCropWinSize(PUINT32 pu32Height, PUINT32 pu32Width) +{ + UINT32 u32Temp = inp32(REG_CAP_CWS); + + *pu32Height = (u32Temp & CWH) >> 16; + *pu32Width = u32Temp & CWW; +} + +/** + * @brief Set packet/planar scaling vertical factor. + * + * @param[in] ePipe Pipe type.Including. + * - \ref eCAP_PACKET. + * - \ref eCAP_PLANAR. + * @param[in] u16Numerator Scaling Vertical Factor N. + * @param[in] u16Denominator Scaling Vertical Factor M. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to set packet/planar scaling vertical factor. + * The output image width will be equal to the image width * N/M. + * Note: The value of N must be equal to or less than M + */ +INT32 CAP_SetVerticalScaleFactor(E_CAP_PIPE ePipe, UINT16 u16Numerator, UINT16 u16Denominator) +{ + UINT8 u8NumeratorL = u16Numerator & 0xFF, u8NumeratorH = u16Numerator >> 8; + UINT8 u8DenominatorL = u16Denominator & 0xFF, u8DenominatorH = u16Denominator >> 8; + if (ePipe == eCAP_PACKET) + { + outp32(REG_CAP_PKTSL, (inp32(REG_CAP_PKTSL) & ~(PKTSVNL | PKTSVML)) + | ((u8NumeratorL << 24) + | (u8DenominatorL << 16))); + outp32(REG_CAP_PKTSM, (inp32(REG_CAP_PKTSM) & ~(PKTSHMH | PKTSVMH)) + | ((u8NumeratorH << 24) + | (u8DenominatorH << 16))); + } + else if (ePipe == eCAP_PLANAR) + { + outp32(REG_CAP_PLNSL, (inp32(REG_CAP_PLNSL) & ~(PKTSVNL | PKTSVML)) + | ((u8NumeratorL << 24) + | (u8DenominatorL << 16))); + outp32(REG_CAP_PLNSM, (inp32(REG_CAP_PLNSM) & ~(PKTSHMH | PKTSVMH)) + | ((u8NumeratorH << 24) + | (u8DenominatorH << 16))); + } + else + return E_CAP_INVALID_PIPE; + return Successful; +} + +/** + * @brief Get packet/planar scaling vertical factor. + * + * @param[in] ePipe Pipe type.Including. + * - \ref eCAP_PACKET. + * - \ref eCAP_PLANAR. + * @param[out] pu16Numerator Scaling Vertical Factor N. + * @param[out] pu16Denominator Scaling Vertical Factor M. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to get packet/planar scaling vertical factor. + * The output image width will be equal to the image width * N/M. + * Note: The value of N must be equal to or less than M + */ +INT32 DrvCAP_GetVerticalScaleFactor(E_CAP_PIPE ePipe, PUINT16 pu16Numerator, PUINT16 pu16Denominator) +{ + UINT32 u32Temp1, u32Temp2; + if (ePipe == eCAP_PACKET) + { + u32Temp1 = inp32(REG_CAP_PKTSL); + u32Temp2 = inp32(REG_CAP_PKTSM); + } + else if (ePipe == eCAP_PLANAR) + { + u32Temp1 = inp32(REG_CAP_PLNSL); + u32Temp2 = inp32(REG_CAP_PLNSM); + } + else + return E_CAP_INVALID_PIPE; + *pu16Numerator = ((u32Temp1 & PKTSVNL) >> 24) | (((u32Temp2 & PKTSHMH) >> 24) << 8); + *pu16Denominator = (u32Temp1 & PKTSVML) >> 16 | (((u32Temp2 & PKTSVMH) >> 16) << 8); + return Successful; +} + +/** + * @brief Set packet/planar scaling horizontal factor. + * + * @param[in] bPipe Pipe type.Including. + * - \ref eCAP_PACKET. + * - \ref eCAP_PLANAR. + * @param[in] u16Numerator Scaling Horizontal Factor N. + * @param[in] u16Denominator Scaling Horizontal Factor M. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to set packet/planar scaling horizontal factor. + * The output image width will be equal to the image width * N/M. + * Note: The value of N must be equal to or less than M + */ +INT32 CAP_SetHorizontalScaleFactor(E_CAP_PIPE bPipe, UINT16 u16Numerator, UINT16 u16Denominator) +{ + UINT8 u8NumeratorL = u16Numerator & 0xFF, u8NumeratorH = u16Numerator >> 8; + UINT8 u8DenominatorL = u16Denominator & 0xFF, u8DenominatorH = u16Denominator >> 8; + if (bPipe == eCAP_PACKET) + { + outp32(REG_CAP_PKTSL, (inp32(REG_CAP_PKTSL) & ~(PKTSHNL | PKTSHML)) + | ((u8NumeratorL << 8) + | u8DenominatorL)); + outp32(REG_CAP_PKTSM, (inp32(REG_CAP_PKTSM) & ~(PKTSHNH | PKTSHMH)) + | ((u8NumeratorH << 8) + | u8DenominatorH)); + } + else if (bPipe == eCAP_PLANAR) + { + outp32(REG_CAP_PLNSL, (inp32(REG_CAP_PLNSL) & ~(PKTSHNL | PKTSHML)) + | ((u8NumeratorL << 8) + | u8DenominatorL)); + outp32(REG_CAP_PLNSM, (inp32(REG_CAP_PLNSM) & ~(PKTSHNH | PKTSHMH)) + | ((u8NumeratorH << 8) + | u8DenominatorH)); + } + else + return E_CAP_INVALID_PIPE; + return Successful; +} + +/** + * @brief Get packet/planar scaling horizontal factor. + * + * @param[in] bPipe Pipe type.Including. + * - \ref eCAP_PACKET. + * - \ref eCAP_PLANAR. + * @param[out] pu16Numerator Scaling Horizontal Factor N. + * @param[out] pu16Denominator Scaling Horizontal Factor M. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to get packet/planar scaling horizontal factor. + * The output image width will be equal to the image width * N/M. + * Note: The value of N must be equal to or less than M. + */ +INT32 CAP_GetHorizontalScaleFactor(E_CAP_PIPE bPipe, PUINT16 pu16Numerator, PUINT16 pu16Denominator) +{ + UINT32 u32Temp1, u32Temp2; + if (bPipe == eCAP_PACKET) + { + u32Temp1 = inp32(REG_CAP_PKTSL); + u32Temp2 = inp32(REG_CAP_PKTSM); + } + else if (bPipe == eCAP_PLANAR) + { + u32Temp1 = inp32(REG_CAP_PLNSL); + u32Temp2 = inp32(REG_CAP_PLNSM); + } + else + return E_CAP_INVALID_PIPE; + *pu16Numerator = ((u32Temp1 & PKTSHNL) >> 8) | (u32Temp2 & PKTSHNH); + *pu16Denominator = (u32Temp1 & PKTSHML) | ((u32Temp2 & PKTSHMH) << 8); + return Successful; +} + +/** + * @brief Set scaling frame rate factor. + * + * @param[in] u8Numerator Scaling Frame Rate Factor N. + * @param[in] u8Denominator Scaling Frame Rate Factor M. + * + * @return None. + * + * @details This function is used to set scaling frame rate factor.. + * The output image frame rate will be equal to input image frame rate * (N/M). + * Note: The value of N must be equal to or less than M. + */ +void DrvCAP_SetFrameRateScaleFactor(UINT8 u8Numerator, UINT8 u8Denominator) +{ + outp32(REG_CAP_FRCTL, (inp32(REG_CAP_FRCTL) & ~(FRN | FRM)) + | (((u8Numerator << 8) & FRN) + | (u8Denominator & FRM))); +} // DrvVideoIn_SetFrameRateScaleFactor + +/** + * @brief Get scaling frame rate factor. + * + * @param[out] pu8Numerator Scaling Frame Rate Factor N. + * @param[out] pu8Denominator Scaling Frame Rate Factor M. + * + * @return None. + * + * @details This function is used to get scaling frame rate factor.. + * The output image frame rate will be equal to input image frame rate * (N/M). + * Note: The value of N must be equal to or less than M. + */ +void DrvCAP_GetFrameRateScaleFactor(PUINT8 pu8Numerator, PUINT8 pu8Denominator) +{ + UINT32 u32Temp = inp32(REG_CAP_FRCTL); + + *pu8Numerator = (u32Temp & FRN) >> 8; + *pu8Denominator = u32Temp & FRM; +} + +/** + * @brief Set address match + * + * @param[in] u32AddressMatch Compare Memory Base Address.It should be 0~0xFFFFFFFF. + * + * @return None. + * + * @details This function is used to set compare memory base address. + */ +void DrvCAP_SetAddressMatch(UINT32 u32AddressMatch) +{ + outp32(REG_CAP_CMPADDR, u32AddressMatch); +} + +/** + * @brief Get address match + * + * @param[out] pu32AddressMatch Compare Memory Base Address.It should be 0~0xFFFFFFFF. + * + * @return None. + * + * @details This function is used to get compare memory base address. + */ +void CAP_GetAddressMatch(PUINT32 pu32AddressMatch) +{ + *pu32AddressMatch = inp32(REG_CAP_CMPADDR); +} + +/** + * @brief Set frame output pixel stride width. + * + * @param[in] u32PacketStride Packet frame output pixel stride width.It should be 0~0x3FFF. + * @param[in] u32PlanarStride Planar frame output pixel stride width.It should be 0~0x3FFF. + * + * @return None. + * + * @details This function is used to set frame output pixel stride width. + */ +void CAP_SetStride(UINT32 u32PacketStride, UINT32 u32PlanarStride) +{ + outp32(REG_CAP_STRIDE, ((u32PlanarStride << 16) & PLNSTRIDE) | + (u32PacketStride & PKTSTRIDE)); +} + +/** + * @brief Get frame output pixel stride width. + * + * @param[out] pu32PacketStride Packet frame output pixel stride width.It should be 0~0x3FFF. + * @param[out] pu32PlanarStride Planar frame output pixel stride width.It should be 0~0x3FFF. + * + * @return None. + * + * @details This function is used to get frame output pixel stride width. + */ +void CAP_GetStride(PUINT32 pu32PacketStride, PUINT32 pu32PlanarStride) +{ + UINT32 u32Tmp = inp32(REG_CAP_STRIDE); + *pu32PlanarStride = (u32Tmp & PLNSTRIDE) >> 16; + *pu32PacketStride = u32Tmp & PKTSTRIDE; +} + +/** + * @brief Set system memory packet/planar base address. + * + * @param[in] ePipe Pipe type.Including: + * - \ref eCAP_PACKET + * - \ref eCAP_PLANAR + * + * @param[in] eBuf Packet/Planar buffer address. + * - \ref eCAP_BUF0 : + * Packet : Packet base address 0 + * Planar : Planar Y base address + * - \ref eCAP_BUF1 + * Packet : Packet base address 1 + * Planar : Planar U base address + * - \ref eCAP_BUF2 + * Packet : None. + * Planar : Planar V base address + * + * @param[in] u32BaseStartAddr System Memory Base Address.It should be 0~0xFFFFFFFF. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to set system memory packet/planar base address. + */ +INT32 CAP_SetBaseStartAddress(E_CAP_PIPE ePipe, E_CAP_BUFFER eBuf, UINT32 u32BaseStartAddr) +{ + if (ePipe == eCAP_PACKET) + { + if (eBuf > eCAP_BUF1) + return E_CAP_INVALID_BUF; + outp32(REG_CAP_PKTBA0 + eBuf * 4, u32BaseStartAddr); + } + else if (ePipe == eCAP_PLANAR) + { + if (eBuf > eCAP_BUF2) + return E_CAP_INVALID_BUF; + outp32(REG_CAP_YBA + eBuf * 4, u32BaseStartAddr); + } + else + return E_CAP_INVALID_PIPE; + return Successful; +} + +/** + * @brief Get system memory packet/planar base address. + * + * @param[in] ePipe Pipe type.Including: + * - \ref eCAP_PACKET + * - \ref eCAP_PLANAR + * + * @param[in] eBuf Packet/Planar buffer address. + * - \ref eCAP_BUF0 : + * Packet : Packet base address 0 + * Planar : Planar Y base address + * - \ref eCAP_BUF1 + * Packet : Packet base address 1 + * Planar : Planar U base address + * - \ref eCAP_BUF2 + * Packet : None. + * Planar : Planar V base address + * + * @param[out] pu32BaseStartAddr System Memory Base Address.It should be 0~0xFFFFFFFF. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to get system memory packet/planar base address. + */ +INT32 CAP_GetBaseStartAddress(E_CAP_PIPE ePipe, E_CAP_BUFFER eBuf, PUINT32 pu32BaseStartAddr) +{ + if (ePipe == eCAP_PACKET) + { + if (eBuf > eCAP_BUF1) + return E_CAP_INVALID_BUF; + *pu32BaseStartAddr = inp32(REG_CAP_PKTBA0 + eBuf * 4); + } + else if (ePipe == eCAP_PLANAR) + { + if (eBuf > eCAP_BUF2) + return E_CAP_INVALID_BUF; + *pu32BaseStartAddr = inp32(REG_CAP_YBA + eBuf * 4); + } + else + return E_CAP_INVALID_PIPE; + return Successful; +} + +/** + * @brief Set standard CCIR656. + * + * @param[in] bIsStandard Standard CCIR656. + * - 1 : Standard CCIR656 mode. + * - 0 : Non-Standard CCIR656 mode. (OV7725 or Hynix 702) + * @return None. + * + * @details This function is used to set standard CCIR65/non-standard CCIR65. + */ +void CAP_SetStandardCCIR656(BOOL bIsStandard) +{ + if (bIsStandard == TRUE) + outp32(REG_CAP_PAR, inp32(REG_CAP_PAR) & ~FBB); // Standard + else + outp32(REG_CAP_PAR, inp32(REG_CAP_PAR) | FBB); // Non-Standard +} + +/** + * @brief Set color effect + * + * @param[in] eColorMode Available as following. + * - \ref eCAP_CEF_NORMAL : Normal Color. + * - \ref eCAP_CEF_SEPIA : Sepia effect, + * corresponding U,V component value is set at register - \ref REG_CAP_SEPIA. + * - \ref eCAP_CEF_NEGATIVE : Negative picture. + * - \ref eCAP_CEF_POSTERIZE : Posterize image, + * the Y, U, V components posterizing factor are set at register - \ref REG_CAP_POSTERIZE. + * + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to set color effect. + */ +INT32 CAP_SetColorEffect(E_CAP_CEF eColorMode) +{ + if (eColorMode > eCAP_CEF_POSTERIZE) + return E_CAP_INVALID_COLOR_MODE; + outp32(REG_CAP_PAR, (inp32(REG_CAP_PAR) & ~COLORCTL) | + (eColorMode << 11)); + return Successful; +} + +/** + * @brief Get color effect + * + * @param[out] peColorMode Available as following. + * - \ref eCAP_CEF_NORMAL : Normal Color. + * - \ref eCAP_CEF_SEPIA : Sepia effect, + * corresponding U,V component value is set at register - \ref REG_CAP_SEPIA. + * - \ref eCAP_CEF_NEGATIVE : Negative picture. + * - \ref eCAP_CEF_POSTERIZE : Posterize image, + * the Y, U, V components posterizing factor are set at register - \ref REG_CAP_POSTERIZE. + * + * @return None. + * + * @details This function is used to get color effect. + */ +void DrvCAP_GetColorEffect(E_CAP_CEF *peColorMode) +{ + UINT32 u32Tmp = inp32(REG_CAP_PAR); + *peColorMode = (E_CAP_CEF)((u32Tmp & COLORCTL) >> 11); +} + +/** + * @brief Set color effect parameter + * + * @param[in] u8YComp The constant Y component.If eColorMode is set to + * eCAP_CEF_SEPIA : the constant Y component in - \ref REG_CAP_SEPIA. + * eCAP_CEF_POSTERIZE : the constant Y component in - \ref REG_CAP_POSTERIZE. + * @param[in] u8UComp The constant U component. + * eCAP_CEF_SEPIA : the constant U component in - \ref REG_CAP_SEPIA. + * eCAP_CEF_POSTERIZE : the constant U component in - \ref REG_CAP_POSTERIZE. + * @param[in] u8VComp The constant V component. + * eCAP_CEF_SEPIA : the constant V component in - \ref REG_CAP_SEPIA. + * eCAP_CEF_POSTERIZE : the constant V component in - \ref REG_CAP_POSTERIZE. + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to set color effect parameter. + */ +INT32 CAP_SetColorEffectParameter(UINT8 u8YComp, UINT8 u8UComp, UINT8 u8VComp) +{ + UINT32 u32Tmp = inp32(REG_CAP_PAR); + UINT32 u32ColorMode = (u32Tmp & COLORCTL) >> 11; + if (u32ColorMode == eCAP_CEF_SEPIA) + { + outp32(REG_CAP_SEPIA, (((UINT32)u8UComp << 8) | u8VComp)); + } + else if (u32ColorMode == eCAP_CEF_POSTERIZE) + { + outp32(REG_CAP_POSTERIZE, (((UINT32)u8YComp << 16) | ((UINT32)u8UComp << 8) | u8VComp)); + } + else + { + return E_CAP_WRONG_COLOR_PARAMETER; + } + return Successful; +} + +/** + * @brief Get color effect parameter + * + * @param[out] pu8YComp The constant Y component.If eColorMode is set to + * eCAP_CEF_SEPIA : the constant Y component in - \ref REG_CAP_SEPIA. + * eCAP_CEF_POSTERIZE : the constant Y component in - \ref REG_CAP_POSTERIZE. + * @param[out] pu8UComp The constant U component. + * eCAP_CEF_SEPIA : the constant U component in - \ref REG_CAP_SEPIA. + * eCAP_CEF_POSTERIZE : the constant U component in - \ref REG_CAP_POSTERIZE. + * @param[out] pu8VComp The constant V component. + * eCAP_CEF_SEPIA : the constant V component in - \ref REG_CAP_SEPIA. + * eCAP_CEF_POSTERIZE : the constant V component in - \ref REG_CAP_POSTERIZE. + * @retval 0 Success + * @retval <0 Error code + * + * @details This function is used to get color effect parameter. + */ +INT32 CAP_GetColorEffectParameter(PUINT8 pu8YComp, PUINT8 pu8UComp, PUINT8 pu8VComp) +{ + UINT32 u32Tmp = inp32(REG_CAP_PAR); + UINT32 u32ColorMode = (u32Tmp & COLORCTL) >> 11; + if (u32ColorMode == eCAP_CEF_SEPIA) + { + u32Tmp = inp32(REG_CAP_SEPIA); + *pu8UComp = (u32Tmp & 0xFF00) >> 8; + *pu8VComp = u32Tmp & 0xFF; + } + else if (u32ColorMode == eCAP_CEF_POSTERIZE) + { + u32Tmp = inp32(REG_CAP_POSTERIZE); + *pu8YComp = (u32Tmp & 0xFF0000) >> 16; + *pu8UComp = (u32Tmp & 0xFF00) >> 8; + *pu8VComp = u32Tmp & 0xFF; + } + else + { + return E_CAP_WRONG_COLOR_PARAMETER; + } + return Successful; +} + +/// @cond HIDDEN_SYMBOLS +CAPDEV_T CAP = +{ + CAP_Init, // void (*Init)(BOOL bIsEnableSnrClock, E_CAP_SNR_SRC eSnrSrc, UINT32 u32SensorFreqKHz, E_CAP_DEV_TYPE eDevType): + CAP_Open, // INT32 (*Open)(UINT32 u32SensorFreqKHz); + CAP_Close, // void (*Close)(void); + CAP_SetPipeEnable, // void (*SetPipeEnable)(BOOL bEngEnable, E_CAP_PIPE ePipeEnable); + CAP_SetPlanarFormat, // void (*SetPlanarFormat)(E_CAP_PLANAR_FORMAT ePlanarFmt); + CAP_SetCropWinSize, // void (*SetCropWinSize)(UINT32 u32height, UINT32 u32width); + CAP_SetCropWinStartAddr, // void (*SetCropWinStartAddr)(UINT32 u32VerticalStart, UINT32 u32HorizontalStart); + CAP_SetStride, // void (*SetStride)(UINT32 u16packetstride, UINT32 u32planarstride); + CAP_GetStride, // void (*GetStride)(PUINT32 pu32PacketStride, PUINT32 pu32PlanarStride); + CAP_EnableInt, // INT32 (*EnableInt)(E_CAP_INT_TYPE eIntType); + CAP_DisableInt, // INT32 (*DisableInt)(E_CAP_INT_TYPE eIntType); + CAP_InstallCallback, // INT32 (*InstallCallback)(E_CAP_INT_TYPE eIntType, PFN_CAP_CALLBACK pfnCallback, PFN_CAP_CALLBACK *pfnOldCallback); + CAP_SetBaseStartAddress, // INT32 (*SetBaseStartAddress(E_CAP_PIPE ePipe, E_CAP_BUFFER eBuf, UINT32 u32BaseStartAddr); + CAP_SetOperationMode, // void (*SetOperationMode(BOOL bIsOneSutterMode); + CAP_GetOperationMode, // BOOL (*GetOperationMode)(void); + CAP_SetPacketFrameBufferControl, // void (*videoIn1_SetPacketFrameBufferControl)(BOOL bFrameSwitch, BOOL bFrameBufferSel); + CAP_SetSensorPolarity, // void (*videoIn1_SetSensorPolarity)(BOOL bVsync, BOOL bHsync, BOOL bPixelClk); + CAP_SetColorEffectParameter, // INT32 (*SetColorEffectParameter)(UINT8 u8YComp, UINT8 u8UComp, UINT8 u8VComp); + CAP_SetDataFormatAndOrder, // void (*SetDataFormatAndOrder)(E_CAP_ORDER eInputOrder, E_CAP_IN_FORMAT eInputFormat, E_CAP_OUT_FORMAT eOutputFormat) + CAP_SetMotionDet, // void (*SetMotionDet)(BOOL bEnable, BOOL bBlockSize,BOOL bSaveMode); + CAP_SetMotionDetEx, // void (*SetMotionDetEx)(UINT32 u32Threshold, UINT32 u32OutBuffer, UINT32 u32LumBuffer); + CAP_SetStandardCCIR656, // void (*SetStandardCcir656)(BOOL); + CAP_SetShadowRegister // void (*SetShadowRegister)(void); +}; +/// @endcond HIDDEN_SYMBOLS + +/*@}*/ /* end of group N9H30_CAP_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_CAP_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_crypto.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..498b333e62608a47bc032565ee501ca9d9b8ce5e --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_crypto.c @@ -0,0 +1,394 @@ +/**************************************************************************//** + * @file crypto.c + * @version V1.10 + * $Revision: 3 $ + * $Date: 15/06/12 9:42a $ + * @brief Cryptographic Accelerator driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include "N9H30.h" +#include "nu_crypto.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_CRYPTO_Driver CRYPTO Driver + @{ +*/ + + +/** @addtogroup N9H30_CRYPTO_EXPORTED_FUNCTIONS CRYPTO Exported Functions + @{ +*/ + +/// @cond HIDDEN_SYMBOLS + +static uint32_t g_AES_CTL[4]; +static uint32_t g_TDES_CTL[4]; + +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief Open PRNG function + * @param[in] u32KeySize is PRNG key size, including: + * - \ref PRNG_KEY_SIZE_64 + * - \ref PRNG_KEY_SIZE_128 + * - \ref PRNG_KEY_SIZE_192 + * - \ref PRNG_KEY_SIZE_256 + * @param[in] u32SeedReload is PRNG seed reload or not, including: + * - \ref PRNG_SEED_CONT + * - \ref PRNG_SEED_RELOAD + * @param[in] u32Seed The new seed. Only valid when u32SeedReload is PRNG_SEED_RELOAD. + * @return None + */ +void PRNG_Open(uint32_t u32KeySize, uint32_t u32SeedReload, uint32_t u32Seed) +{ + if (u32SeedReload) + CRPT->PRNG_SEED = u32Seed; + + CRPT->PRNG_CTL = (u32KeySize << CRPT_PRNG_CTL_KEYSZ_Pos) | + (u32SeedReload << CRPT_PRNG_CTL_SEEDRLD_Pos); +} + +/** + * @brief Start to generate one PRNG key. + * @return None + */ +void PRNG_Start(void) +{ + CRPT->PRNG_CTL |= CRPT_PRNG_CTL_START_Msk; +} + +/** + * @brief Read the PRNG key. + * @param[out] u32RandKey The key buffer to store newly generated PRNG key. + * @return None + */ +void PRNG_Read(uint32_t u32RandKey[]) +{ + uint32_t i, wcnt; + + wcnt = (((CRPT->PRNG_CTL & CRPT_PRNG_CTL_KEYSZ_Msk) >> CRPT_PRNG_CTL_KEYSZ_Pos) + 1U) * 2U; + + for (i = 0U; i < wcnt; i++) + { + u32RandKey[i] = CRPT->PRNG_KEY[i]; + } + + CRPT->PRNG_CTL &= ~CRPT_PRNG_CTL_SEEDRLD_Msk; +} + + +/** + * @brief Open AES encrypt/decrypt function. + * @param[in] u32Channel AES channel. Must be 0~3. + * @param[in] u32EncDec 1: AES encode; 0: AES decode + * @param[in] u32OpMode AES operation mode, including: + * - \ref AES_MODE_ECB + * - \ref AES_MODE_CBC + * - \ref AES_MODE_CFB + * - \ref AES_MODE_OFB + * - \ref AES_MODE_CTR + * - \ref AES_MODE_CBC_CS1 + * - \ref AES_MODE_CBC_CS2 + * - \ref AES_MODE_CBC_CS3 + * @param[in] u32KeySize is AES key size, including: + * - \ref AES_KEY_SIZE_128 + * - \ref AES_KEY_SIZE_192 + * - \ref AES_KEY_SIZE_256 + * @param[in] u32SwapType is AES input/output data swap control, including: + * - \ref AES_NO_SWAP + * - \ref AES_OUT_SWAP + * - \ref AES_IN_SWAP + * - \ref AES_IN_OUT_SWAP + * @return None + */ +void AES_Open(uint32_t u32Channel, uint32_t u32EncDec, + uint32_t u32OpMode, uint32_t u32KeySize, uint32_t u32SwapType) +{ + CRPT->AES_CTL = (u32Channel << CRPT_AES_CTL_CHANNEL_Pos) | + (u32EncDec << CRPT_AES_CTL_ENCRPT_Pos) | + (u32OpMode << CRPT_AES_CTL_OPMODE_Pos) | + (u32KeySize << CRPT_AES_CTL_KEYSZ_Pos) | + (u32SwapType << CRPT_AES_CTL_OUTSWAP_Pos); + g_AES_CTL[u32Channel] = CRPT->AES_CTL; +} + +/** + * @brief Start AES encrypt/decrypt + * @param[in] u32Channel AES channel. Must be 0~3. + * @param[in] u32DMAMode AES DMA control, including: + * - \ref CRYPTO_DMA_ONE_SHOT One shop AES encrypt/decrypt. + * - \ref CRYPTO_DMA_CONTINUE Continuous AES encrypt/decrypt. + * - \ref CRYPTO_DMA_LAST Last AES encrypt/decrypt of a series of AES_Start. + * @return None + */ +void AES_Start(int32_t u32Channel, uint32_t u32DMAMode) +{ + CRPT->AES_CTL = g_AES_CTL[u32Channel]; + CRPT->AES_CTL |= CRPT_AES_CTL_START_Msk | (u32DMAMode << CRPT_AES_CTL_DMALAST_Pos); +} + +/** + * @brief Set AES keys + * @param[in] u32Channel AES channel. Must be 0~3. + * @param[in] au32Keys An word array contains AES keys. + * @param[in] u32KeySize is AES key size, including: + * - \ref AES_KEY_SIZE_128 + * - \ref AES_KEY_SIZE_192 + * - \ref AES_KEY_SIZE_256 + * @return None + */ +void AES_SetKey(uint32_t u32Channel, uint32_t au32Keys[], uint32_t u32KeySize) +{ + int i, wcnt; + uint32_t *key_ptr; + + key_ptr = (uint32_t *)((uint32_t)&CRPT->AES0_KEY0 + (u32Channel * 0x3C)); + wcnt = 4 + u32KeySize * 2; + for (i = 0; i < wcnt; i++, key_ptr++) + *key_ptr = au32Keys[i]; +} + +/** + * @brief Set AES initial vectors + * @param[in] u32Channel AES channel. Must be 0~3. + * @param[in] au32IV A four entry word array contains AES initial vectors. + * @return None + */ +void AES_SetInitVect(uint32_t u32Channel, uint32_t au32IV[]) +{ + int i; + uint32_t *key_ptr; + + key_ptr = (uint32_t *)((uint32_t)&CRPT->AES0_IV0 + (u32Channel * 0x3C)); + for (i = 0; i < 4; i++, key_ptr++) + *key_ptr = au32IV[i]; +} + +/** + * @brief Set AES DMA transfer configuration. + * @param[in] u32Channel AES channel. Must be 0~3. + * @param[in] u32SrcAddr AES DMA source address + * @param[in] u32DstAddr AES DMA destination address + * @param[in] u32TransCnt AES DMA transfer byte count + * @return None + */ +void AES_SetDMATransfer(uint32_t u32Channel, uint32_t u32SrcAddr, + uint32_t u32DstAddr, uint32_t u32TransCnt) +{ + *(uint32_t *)((uint32_t)&CRPT->AES0_SADDR + (u32Channel * 0x3C)) = u32SrcAddr; + *(uint32_t *)((uint32_t)&CRPT->AES0_DADDR + (u32Channel * 0x3C)) = u32DstAddr; + *(uint32_t *)((uint32_t)&CRPT->AES0_CNT + (u32Channel * 0x3C)) = u32TransCnt; +} + +/** + * @brief Open TDES encrypt/decrypt function. + * @param[in] u32Channel TDES channel. Must be 0~3. + * @param[in] u32EncDec 1: TDES encode; 0: TDES decode + * @param[in] u32OpMode TDES operation mode, including: + * - \ref TDES_MODE_ECB + * - \ref TDES_MODE_CBC + * - \ref TDES_MODE_CFB + * - \ref TDES_MODE_OFB + * - \ref TDES_MODE_CTR + * @param[in] u32SwapType is TDES input/output data swap control and word swap control, including: + * - \ref TDES_NO_SWAP + * - \ref TDES_WHL_SWAP + * - \ref TDES_OUT_SWAP + * - \ref TDES_OUT_WHL_SWAP + * - \ref TDES_IN_SWAP + * - \ref TDES_IN_WHL_SWAP + * - \ref TDES_IN_OUT_SWAP + * - \ref TDES_IN_OUT_WHL_SWAP + * @return None + */ +void TDES_Open(uint32_t u32Channel, uint32_t u32EncDec, int32_t Is3DES, int32_t Is3Key, + uint32_t u32OpMode, uint32_t u32SwapType) +{ + g_TDES_CTL[u32Channel] = (u32Channel << CRPT_TDES_CTL_CHANNEL_Pos) | + (u32EncDec << CRPT_TDES_CTL_ENCRPT_Pos) | + u32OpMode | (u32SwapType << CRPT_TDES_CTL_BLKSWAP_Pos); + if (Is3DES) + { + g_TDES_CTL[u32Channel] |= CRPT_TDES_CTL_TMODE_Msk; + } + if (Is3Key) + { + g_TDES_CTL[u32Channel] |= CRPT_TDES_CTL_3KEYS_Msk; + } +} + +/** + * @brief Start TDES encrypt/decrypt + * @param[in] u32Channel TDES channel. Must be 0~3. + * @param[in] u32DMAMode TDES DMA control, including: + * - \ref CRYPTO_DMA_ONE_SHOT One shop TDES encrypt/decrypt. + * - \ref CRYPTO_DMA_CONTINUE Continuous TDES encrypt/decrypt. + * - \ref CRYPTO_DMA_LAST Last TDES encrypt/decrypt of a series of TDES_Start. + * @return None + */ +void TDES_Start(int32_t u32Channel, uint32_t u32DMAMode) +{ + g_TDES_CTL[u32Channel] |= CRPT_TDES_CTL_START_Msk | (u32DMAMode << CRPT_TDES_CTL_DMALAST_Pos); + CRPT->TDES_CTL = g_TDES_CTL[u32Channel]; +} + +/** + * @brief Set TDES keys + * @param[in] u32Channel TDES channel. Must be 0~3. + * @param[in] au8Keys The TDES keys. + * @return None + */ +void TDES_SetKey(uint32_t u32Channel, uint32_t au32Keys[3][2]) +{ + int i; + uint32_t *pu32TKey; + + pu32TKey = (uint32_t *)((uint32_t)&CRPT->TDES0_KEY1H + (0x40 * u32Channel)); + for (i = 0; i < 3; i++) + { + *pu32TKey = au32Keys[i][0]; /* TDESn_KEYxH */ + pu32TKey++; + *pu32TKey = au32Keys[i][1]; /* TDESn_KEYxL */ + pu32TKey++; + } +} + +/** + * @brief Set TDES initial vectors + * @param[in] u32Channel TDES channel. Must be 0~3. + * @param[in] u32IVH TDES initial vector high word. + * @param[in] u32IVL TDES initial vector low word. + * @return None + */ +void TDES_SetInitVect(uint32_t u32Channel, uint32_t u32IVH, uint32_t u32IVL) +{ + *(uint32_t *)((uint32_t)&CRPT->TDES0_IVH + 0x40 * u32Channel) = u32IVH; + *(uint32_t *)((uint32_t)&CRPT->TDES0_IVL + 0x40 * u32Channel) = u32IVL; +} + +/** + * @brief Set TDES DMA transfer configuration. + * @param[in] u32Channel TDES channel. Must be 0~3. + * @param[in] u32SrcAddr TDES DMA source address + * @param[in] u32DstAddr TDES DMA destination address + * @param[in] u32TransCnt TDES DMA transfer byte count + * @return None + */ +void TDES_SetDMATransfer(uint32_t u32Channel, uint32_t u32SrcAddr, + uint32_t u32DstAddr, uint32_t u32TransCnt) +{ + *(uint32_t *)((uint32_t)&CRPT->TDES0_SADDR + (u32Channel * 0x40)) = u32SrcAddr; + *(uint32_t *)((uint32_t)&CRPT->TDES0_DADDR + (u32Channel * 0x40)) = u32DstAddr; + *(uint32_t *)((uint32_t)&CRPT->TDES0_CNT + (u32Channel * 0x40)) = u32TransCnt; +} + +/** + * @brief Open SHA encrypt function. + * @param[in] u32OpMode SHA operation mode, including: + * - \ref SHA_MODE_SHA1 + * - \ref SHA_MODE_SHA224 + * - \ref SHA_MODE_SHA256 + * - \ref SHA_MODE_SHA384 + * - \ref SHA_MODE_SHA512 + * @param[in] u32SwapType is SHA input/output data swap control, including: + * - \ref SHA_NO_SWAP + * - \ref SHA_OUT_SWAP + * - \ref SHA_IN_SWAP + * - \ref SHA_IN_OUT_SWAP + * @param[in] hmac_key_len The length of HMAC key if HMAC is employed. + * If HMAC is not used, just give hmac_key_len a zero value. + * @return None + */ +void SHA_Open(uint32_t u32OpMode, uint32_t u32SwapType, int hmac_key_len) +{ + CRPT->HMAC_CTL = (u32OpMode << CRPT_HMAC_CTL_OPMODE_Pos) | + (u32SwapType << CRPT_HMAC_CTL_OUTSWAP_Pos); + + if (hmac_key_len > 0) + { + CRPT->HMAC_KEYCNT = hmac_key_len; + CRPT->HMAC_CTL |= CRPT_HMAC_CTL_HMACEN_Msk; + } +} + + +/** + * @brief Start SHA encrypt + * @param[in] u32DMAMode TDES DMA control, including: + * - \ref CRYPTO_DMA_ONE_SHOT One shop SHA encrypt. + * - \ref CRYPTO_DMA_CONTINUE Continuous SHA encrypt. + * - \ref CRYPTO_DMA_LAST Last SHA encrypt of a series of SHA_Start. + * @return None + */ +void SHA_Start(uint32_t u32DMAMode) +{ + CRPT->HMAC_CTL &= ~(0x7 << CRPT_HMAC_CTL_DMALAST_Pos); + CRPT->HMAC_CTL |= CRPT_HMAC_CTL_START_Msk | (u32DMAMode << CRPT_HMAC_CTL_DMALAST_Pos); +} + +/** + * @brief Set SHA DMA transfer + * @param[in] u32SrcAddr SHA DMA source address + * @param[in] u32TransCnt SHA DMA transfer byte count + * @return None + */ +void SHA_SetDMATransfer(uint32_t u32SrcAddr, uint32_t u32TransCnt) +{ + CRPT->HMAC_SADDR = u32SrcAddr; + CRPT->HMAC_DMACNT = u32TransCnt; +} + +/** + * @brief Read the SHA digest. + * @param[out] u32Digest The SHA encrypt output digest. + * @return None + */ +void SHA_Read(uint32_t u32Digest[]) +{ + uint32_t i, wcnt; + + i = (CRPT->HMAC_CTL & CRPT_HMAC_CTL_OPMODE_Msk) >> CRPT_HMAC_CTL_OPMODE_Pos; + if (i == SHA_MODE_SHA1) + { + wcnt = 5UL; + } + else if (i == SHA_MODE_SHA224) + { + wcnt = 7UL; + } + else if (i == SHA_MODE_SHA256) + { + wcnt = 8UL; + } + else if (i == SHA_MODE_SHA384) + { + wcnt = 12UL; + } + else + { + /* SHA_MODE_SHA512 */ + wcnt = 16UL; + } + + for (i = 0; i < wcnt; i++) + u32Digest[i] = *(uint32_t *)((uint32_t) & (CRPT->HMAC_DGST0) + (i * 4)); +} + + +/*@}*/ /* end of group N9H30_CRYPTO_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_CRYPTO_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_emac.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_emac.c new file mode 100644 index 0000000000000000000000000000000000000000..703c686311cfe5dc6fda730ff8247e0caf25a132 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_emac.c @@ -0,0 +1,1158 @@ +/**************************************************************************//** + * @file emac.c + * @version V1.00 + * @brief M480 EMAC driver source file + * + * SPDX-License-Identifier: Apache-2.0 + * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include +#include +#include "NuMicro.h" + +/** @addtogroup Standard_Driver Standard Driver + @{ +*/ + +/** @addtogroup EMAC_Driver EMAC Driver + @{ +*/ + + +/* Below are structure, definitions, static variables used locally by EMAC driver and does not want to parse by doxygen unless HIDDEN_SYMBOLS is defined */ +/** @cond HIDDEN_SYMBOLS */ + +/** @addtogroup EMAC_EXPORTED_CONSTANTS EMAC Exported Constants + @{ +*/ + +/* PHY Register Description */ +#define PHY_CNTL_REG 0x00UL /*!< PHY control register address */ +#define PHY_STATUS_REG 0x01UL /*!< PHY status register address */ +#define PHY_ID1_REG 0x02UL /*!< PHY ID1 register */ +#define PHY_ID2_REG 0x03UL /*!< PHY ID2 register */ +#define PHY_ANA_REG 0x04UL /*!< PHY auto-negotiation advertisement register */ +#define PHY_ANLPA_REG 0x05UL /*!< PHY auto-negotiation link partner availability register */ +#define PHY_ANE_REG 0x06UL /*!< PHY auto-negotiation expansion register */ + +/* PHY Control Register */ +#define PHY_CNTL_RESET_PHY (1UL << 15UL) +#define PHY_CNTL_DR_100MB (1UL << 13UL) +#define PHY_CNTL_ENABLE_AN (1UL << 12UL) +#define PHY_CNTL_POWER_DOWN (1UL << 11UL) +#define PHY_CNTL_RESTART_AN (1UL << 9UL) +#define PHY_CNTL_FULLDUPLEX (1UL << 8UL) + +/* PHY Status Register */ +#define PHY_STATUS_AN_COMPLETE (1UL << 5UL) +#define PHY_STATUS_LINK_VALID (1UL << 2UL) + +/* PHY Auto-negotiation Advertisement Register */ +#define PHY_ANA_DR100_TX_FULL (1UL << 8UL) +#define PHY_ANA_DR100_TX_HALF (1UL << 7UL) +#define PHY_ANA_DR10_TX_FULL (1UL << 6UL) +#define PHY_ANA_DR10_TX_HALF (1UL << 5UL) +#define PHY_ANA_IEEE_802_3_CSMA_CD (1UL << 0UL) + +/* PHY Auto-negotiation Link Partner Advertisement Register */ +#define PHY_ANLPA_DR100_TX_FULL (1UL << 8UL) +#define PHY_ANLPA_DR100_TX_HALF (1UL << 7UL) +#define PHY_ANLPA_DR10_TX_FULL (1UL << 6UL) +#define PHY_ANLPA_DR10_TX_HALF (1UL << 5UL) + +/* EMAC Tx/Rx descriptor's owner bit */ +#define EMAC_DESC_OWN_EMAC 0x80000000UL /*!< Set owner to EMAC */ +#define EMAC_DESC_OWN_CPU 0x00000000UL /*!< Set owner to CPU */ + +/* Rx Frame Descriptor Status */ +#define EMAC_RXFD_RTSAS 0x0080UL /*!< Time Stamp Available */ +#define EMAC_RXFD_RP 0x0040UL /*!< Runt Packet */ +#define EMAC_RXFD_ALIE 0x0020UL /*!< Alignment Error */ +#define EMAC_RXFD_RXGD 0x0010UL /*!< Receiving Good packet received */ +#define EMAC_RXFD_PTLE 0x0008UL /*!< Packet Too Long Error */ +#define EMAC_RXFD_CRCE 0x0002UL /*!< CRC Error */ +#define EMAC_RXFD_RXINTR 0x0001UL /*!< Interrupt on receive */ + +/* Tx Frame Descriptor's Control bits */ +#define EMAC_TXFD_TTSEN 0x08UL /*!< Tx time stamp enable */ +#define EMAC_TXFD_INTEN 0x04UL /*!< Tx interrupt enable */ +#define EMAC_TXFD_CRCAPP 0x02UL /*!< Append CRC */ +#define EMAC_TXFD_PADEN 0x01UL /*!< Padding mode enable */ + +/* Tx Frame Descriptor Status */ +#define EMAC_TXFD_TXINTR 0x0001UL /*!< Interrupt on Transmit */ +#define EMAC_TXFD_DEF 0x0002UL /*!< Transmit deferred */ +#define EMAC_TXFD_TXCP 0x0008UL /*!< Transmission Completion */ +#define EMAC_TXFD_EXDEF 0x0010UL /*!< Exceed Deferral */ +#define EMAC_TXFD_NCS 0x0020UL /*!< No Carrier Sense Error */ +#define EMAC_TXFD_TXABT 0x0040UL /*!< Transmission Abort */ +#define EMAC_TXFD_LC 0x0080UL /*!< Late Collision */ +#define EMAC_TXFD_TXHA 0x0100UL /*!< Transmission halted */ +#define EMAC_TXFD_PAU 0x0200UL /*!< Paused */ +#define EMAC_TXFD_SQE 0x0400UL /*!< SQE error */ +#define EMAC_TXFD_TTSAS 0x0800UL /*!< Time Stamp available */ + +/*@}*/ /* end of group EMAC_EXPORTED_CONSTANTS */ + +/** @addtogroup EMAC_EXPORTED_TYPEDEF EMAC Exported Type Defines + @{ +*/ + +/*@}*/ /* end of group EMAC_EXPORTED_TYPEDEF */ + +/* local variables */ +static uint32_t s_u32EnableTs = 0UL; + +static void EMAC_MdioWrite(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data); +static uint32_t EMAC_MdioRead(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr); + +static uint32_t EMAC_Subsec2Nsec(uint32_t subsec); +static uint32_t EMAC_Nsec2Subsec(uint32_t nsec); +static void EMAC_TxDescInit(EMAC_MEMMGR_T *psMemMgr); +static void EMAC_RxDescInit(EMAC_MEMMGR_T *psMemMgr); + +/** @addtogroup EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions + @{ +*/ + + +/** + * @brief Write PHY register + * @param[in] u32Reg PHY register number + * @param[in] u32Addr PHY address, this address is board dependent + * @param[in] u32Data data to write to PHY register + * @return None + */ +static void EMAC_MdioWrite(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr, uint32_t u32Data) +{ + /* Set data register */ + EMAC->MIIMDAT = u32Data ; + /* Set PHY address, PHY register address, busy bit and write bit */ + EMAC->MIIMCTL = u32Reg | (u32Addr << 8) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk; + + /* Wait write complete by polling busy bit. */ + while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk) + { + ; + } + +} + +/** + * @brief Read PHY register + * @param[in] u32Reg PHY register number + * @param[in] u32Addr PHY address, this address is board dependent + * @return Value read from PHY register + */ +static uint32_t EMAC_MdioRead(EMAC_T *EMAC, uint32_t u32Reg, uint32_t u32Addr) +{ + /* Set PHY address, PHY register address, busy bit */ + EMAC->MIIMCTL = u32Reg | (u32Addr << EMAC_MIIMCTL_PHYADDR_Pos) | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk; + + /* Wait read complete by polling busy bit */ + while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk) + { + ; + } + + /* Get return data */ + return EMAC->MIIMDAT; +} + +void EMAC_Reset(EMAC_T *EMAC) +{ + /* Reset MAC */ + EMAC->CTL = 0x1000000; +} + +/** + * @brief Initialize PHY chip, check for the auto-negotiation result. + * @param None + * @return None + */ +void EMAC_PhyInit(EMAC_T *EMAC) +{ + uint32_t reg; + uint32_t i = 0UL; + + /* Reset Phy Chip */ + EMAC_MdioWrite(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR, PHY_CNTL_RESET_PHY); + + /* Wait until reset complete */ + while (1) + { + reg = EMAC_MdioRead(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR) ; + + if ((reg & PHY_CNTL_RESET_PHY) == 0UL) + { + break; + } + } + + while (!(EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID)) + { + if (i++ > 10000UL) /* Cable not connected */ + { + EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk; + EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk; + break; + } + } + + if (i <= 10000UL) + { + /* Configure auto negotiation capability */ + EMAC_MdioWrite(EMAC, PHY_ANA_REG, EMAC_PHY_ADDR, PHY_ANA_DR100_TX_FULL | + PHY_ANA_DR100_TX_HALF | + PHY_ANA_DR10_TX_FULL | + PHY_ANA_DR10_TX_HALF | + PHY_ANA_IEEE_802_3_CSMA_CD); + /* Restart auto negotiation */ + EMAC_MdioWrite(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR, EMAC_MdioRead(EMAC, PHY_CNTL_REG, EMAC_PHY_ADDR) | PHY_CNTL_RESTART_AN); + + /* Wait for auto-negotiation complete */ + while (!(EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_AN_COMPLETE)) + { + ; + } + + /* Check link valid again. Some PHYs needs to check result after link valid bit set */ + while (!(EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID)) + { + ; + } + + /* Check link partner capability */ + reg = EMAC_MdioRead(EMAC, PHY_ANLPA_REG, EMAC_PHY_ADDR) ; + + if (reg & PHY_ANLPA_DR100_TX_FULL) + { + EMAC->CTL |= EMAC_CTL_OPMODE_Msk; + EMAC->CTL |= EMAC_CTL_FUDUP_Msk; + } + else if (reg & PHY_ANLPA_DR100_TX_HALF) + { + EMAC->CTL |= EMAC_CTL_OPMODE_Msk; + EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk; + } + else if (reg & PHY_ANLPA_DR10_TX_FULL) + { + EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk; + EMAC->CTL |= EMAC_CTL_FUDUP_Msk; + } + else + { + EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk; + EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk; + } + } +} + +/** + * @brief Initial EMAC Tx descriptors and get Tx descriptor base address + * @param EMAC_MEMMGR_T pointer + * @return None + */ +static void EMAC_TxDescInit(EMAC_MEMMGR_T *psMemMgr) +{ + uint32_t i; + + /* Get Frame descriptor's base address. */ + psMemMgr->psNextTxDesc = psMemMgr->psCurrentTxDesc = (EMAC_DESCRIPTOR_T *)((uint32_t)&psMemMgr->psTXDescs[0] | BIT31); + + for (i = 0UL; i < psMemMgr->u32TxDescSize; i++) + { + + if (s_u32EnableTs) + { + psMemMgr->psTXDescs[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN; + } + else + { + psMemMgr->psTXDescs[i].u32Status1 = EMAC_TXFD_PADEN | EMAC_TXFD_CRCAPP | EMAC_TXFD_INTEN | EMAC_TXFD_TTSEN; + } + + psMemMgr->psTXDescs[i].u32Data = (uint32_t)& psMemMgr->psTXFrames[i] | BIT31; + psMemMgr->psTXDescs[i].u32Status2 = 0UL; + psMemMgr->psTXDescs[i].u32Next = (uint32_t)(&psMemMgr->psTXDescs[(i + 1UL) % EMAC_TX_DESC_SIZE]) | BIT31; + psMemMgr->psTXDescs[i].u32Backup1 = psMemMgr->psTXDescs[i].u32Data; + psMemMgr->psTXDescs[i].u32Backup2 = psMemMgr->psTXDescs[i].u32Next; + } + psMemMgr->psEmac->TXDSA = (uint32_t)psMemMgr->psCurrentTxDesc; +} + + +/** + * @brief Initial EMAC Rx descriptors and get Rx descriptor base address + * @param EMAC_MEMMGR_T pointer + * @return None + */ +static void EMAC_RxDescInit(EMAC_MEMMGR_T *psMemMgr) +{ + + uint32_t i; + + /* Get Frame descriptor's base address. */ + psMemMgr->psCurrentRxDesc = (EMAC_DESCRIPTOR_T *)((uint32_t)&psMemMgr->psRXDescs[0] | BIT31); + + for (i = 0UL; i < psMemMgr->u32RxDescSize; i++) + { + psMemMgr->psRXDescs[i].u32Status1 = EMAC_DESC_OWN_EMAC; + psMemMgr->psRXDescs[i].u32Data = (uint32_t)&psMemMgr->psRXFrames[i] | BIT31; + psMemMgr->psRXDescs[i].u32Status2 = 0UL; + psMemMgr->psRXDescs[i].u32Next = (uint32_t)(&psMemMgr->psRXDescs[(i + 1UL) % EMAC_RX_DESC_SIZE]) | BIT31; + psMemMgr->psRXDescs[i].u32Backup1 = psMemMgr->psRXDescs[i].u32Data; + psMemMgr->psRXDescs[i].u32Backup2 = psMemMgr->psRXDescs[i].u32Next; + } + psMemMgr->psEmac->RXDSA = (uint32_t)psMemMgr->psCurrentRxDesc; +} + +/** + * @brief Convert subsecond value to nano second + * @param[in] subsec Subsecond value to be convert + * @return Nano second + */ +static uint32_t EMAC_Subsec2Nsec(uint32_t subsec) +{ + /* 2^31 subsec == 10^9 ns */ + uint64_t i; + i = 1000000000ull * (uint64_t)subsec; + i >>= 31; + return ((uint32_t)i); +} + +/** + * @brief Convert nano second to subsecond value + * @param[in] nsec Nano second to be convert + * @return Subsecond + */ +static uint32_t EMAC_Nsec2Subsec(uint32_t nsec) +{ + /* 10^9 ns = 2^31 subsec */ + uint64_t i; + i = (1ull << 31) * nsec; + i /= 1000000000ull; + return ((uint32_t)i); +} + + +/*@}*/ /* end of group EMAC_EXPORTED_FUNCTIONS */ + + + +/** @endcond HIDDEN_SYMBOLS */ + + +/** @addtogroup EMAC_EXPORTED_FUNCTIONS EMAC Exported Functions + @{ +*/ + + +/** + * @brief Initialize EMAC interface, including descriptors, MAC address, and PHY. + * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address + * @return None + * @note This API configures EMAC to receive all broadcast and multicast packets, but could configure to other settings with + * \ref EMAC_ENABLE_RECV_BCASTPKT, \ref EMAC_DISABLE_RECV_BCASTPKT, \ref EMAC_ENABLE_RECV_MCASTPKT, and \ref EMAC_DISABLE_RECV_MCASTPKT + * @note Receive(RX) and transmit(TX) are not enabled yet, application must call \ref EMAC_ENABLE_RX and \ref EMAC_ENABLE_TX to + * enable receive and transmit function. + */ +void EMAC_Open(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8MacAddr) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + + /* Enable transmit and receive descriptor */ + EMAC_TxDescInit(psMemMgr); + EMAC_RxDescInit(psMemMgr); + + /* Set the CAM Control register and the MAC address value */ + EMAC_SetMacAddr(EMAC, pu8MacAddr); + + /* Configure the MAC interrupt enable register. */ + EMAC->INTEN = EMAC_INTEN_RXIEN_Msk | + EMAC_INTEN_TXIEN_Msk | + EMAC_INTEN_RXGDIEN_Msk | + EMAC_INTEN_TXCPIEN_Msk | + EMAC_INTEN_RXBEIEN_Msk | + EMAC_INTEN_TXBEIEN_Msk | + EMAC_INTEN_RDUIEN_Msk | + EMAC_INTEN_TSALMIEN_Msk | + EMAC_INTEN_WOLIEN_Msk; + + /* Configure the MAC control register. */ + EMAC->CTL = EMAC_CTL_STRIPCRC_Msk | + EMAC_CTL_RMIIEN_Msk; + + /* Accept packets for us and all broadcast and multicast packets */ + EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk | + EMAC_CAMCTL_AMP_Msk | + EMAC_CAMCTL_ABP_Msk; + + /* Limit the max receive frame length */ + EMAC->MRFL = EMAC_MAX_PKT_SIZE; +} + +/** + * @brief This function stop all receive and transmit activity and disable MAC interface + * @param None + * @return None + */ + +void EMAC_Close(EMAC_T *EMAC) +{ + EMAC->CTL |= EMAC_CTL_RST_Msk; + + while (EMAC->CTL & EMAC_CTL_RST_Msk) {} +} + +/** + * @brief Set the device MAC address + * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address + * @return None + */ +void EMAC_SetMacAddr(EMAC_T *EMAC, uint8_t *pu8MacAddr) +{ + EMAC_EnableCamEntry(EMAC, 0UL, pu8MacAddr); +} + +/** + * @brief Fill a CAM entry for MAC address comparison. + * @param[in] u32Entry MAC entry to fill. Entry 0 is used to store device MAC address, do not overwrite the setting in it. + * @param[in] pu8MacAddr Pointer to uint8_t array holds MAC address + * @return None + */ +void EMAC_EnableCamEntry(EMAC_T *EMAC, uint32_t u32Entry, uint8_t pu8MacAddr[]) +{ + uint32_t u32Lsw, u32Msw; + uint32_t reg; + u32Lsw = (uint32_t)(((uint32_t)pu8MacAddr[4] << 24) | + ((uint32_t)pu8MacAddr[5] << 16)); + u32Msw = (uint32_t)(((uint32_t)pu8MacAddr[0] << 24) | + ((uint32_t)pu8MacAddr[1] << 16) | + ((uint32_t)pu8MacAddr[2] << 8) | + (uint32_t)pu8MacAddr[3]); + + reg = (uint32_t)&EMAC->CAM0M + u32Entry * 2UL * 4UL; + *(uint32_t volatile *)reg = u32Msw; + reg = (uint32_t)&EMAC->CAM0L + u32Entry * 2UL * 4UL; + *(uint32_t volatile *)reg = u32Lsw; + + EMAC->CAMEN |= (1UL << u32Entry); +} + +/** + * @brief Disable a specified CAM entry + * @param[in] u32Entry CAM entry to be disabled + * @return None + */ +void EMAC_DisableCamEntry(EMAC_T *EMAC, uint32_t u32Entry) +{ + EMAC->CAMEN &= ~(1UL << u32Entry); +} + + +/** + * @brief Receive an Ethernet packet + * @param[in] pu8Data Pointer to a buffer to store received packet (4 byte CRC removed) + * @param[in] pu32Size Received packet size (without 4 byte CRC). + * @return Packet receive success or not + * @retval 0 No packet available for receive + * @retval 1 A packet is received + * @note Return 0 doesn't guarantee the packet will be sent and received successfully. + */ +uint32_t EMAC_RecvPkt(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t *pu32Size) +{ + uint32_t reg; + uint32_t u32Count = 0UL; + EMAC_T *EMAC = psMemMgr->psEmac; + + /* Clear Rx interrupt flags */ + reg = EMAC->INTSTS; + EMAC->INTSTS = reg & 0xFFFFUL; /* Clear all RX related interrupt status */ + + if (reg & EMAC_INTSTS_RXBEIF_Msk) + { + /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */ + while (1) {} + } + else + { + /* Get Rx Frame Descriptor */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc; + + /* If we reach last recv Rx descriptor, leave the loop */ + if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */ + { + uint32_t status = desc->u32Status1 >> 16; + + /* If Rx frame is good, process received frame */ + if (status & EMAC_RXFD_RXGD) + { + /* lower 16 bit in descriptor status1 stores the Rx packet length */ + *pu32Size = desc->u32Status1 & 0xFFFFUL; + memcpy(pu8Data, (uint8_t *)desc->u32Data, *pu32Size); + u32Count = 1UL; + } + else + { + /* Save Error status if necessary */ + if (status & EMAC_RXFD_RP) {} + + if (status & EMAC_RXFD_ALIE) {} + + if (status & EMAC_RXFD_PTLE) {} + + if (status & EMAC_RXFD_CRCE) {} + } + } + } + + return (u32Count); +} + +/** + * @brief Receive an Ethernet packet and the time stamp while it's received + * @param[out] pu8Data Pointer to a buffer to store received packet (4 byte CRC removed) + * @param[out] pu32Size Received packet size (without 4 byte CRC). + * @param[out] pu32Sec Second value while packet received + * @param[out] pu32Nsec Nano second value while packet received + * @return Packet receive success or not + * @retval 0 No packet available for receive + * @retval 1 A packet is received + * @note Return 0 doesn't guarantee the packet will be sent and received successfully. + * @note Largest Ethernet packet is 1514 bytes after stripped CRC, application must give + * a buffer large enough to store such packet + */ +uint32_t EMAC_RecvPktTS(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t *pu32Size, uint32_t *pu32Sec, uint32_t *pu32Nsec) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + uint32_t reg; + uint32_t u32Count = 0UL; + + /* Clear Rx interrupt flags */ + reg = EMAC->INTSTS; + EMAC->INTSTS = reg & 0xFFFFUL; /* Clear all Rx related interrupt status */ + + if (reg & EMAC_INTSTS_RXBEIF_Msk) + { + /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */ + while (1) {} + } + else + { + /* Get Rx Frame Descriptor */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc; + + /* If we reach last recv Rx descriptor, leave the loop */ + if (EMAC->CRXDSA != (uint32_t)desc) + { + if ((desc->u32Status1 | EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */ + { + + uint32_t status = desc->u32Status1 >> 16; + + /* If Rx frame is good, process received frame */ + if (status & EMAC_RXFD_RXGD) + { + /* lower 16 bit in descriptor status1 stores the Rx packet length */ + *pu32Size = desc->u32Status1 & 0xFFFFUL; + memcpy(pu8Data, (uint8_t *)desc->u32Data, *pu32Size); + + *pu32Sec = desc->u32Next; /* second stores in descriptor's NEXT field */ + *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); /* Sub nano second store in DATA field */ + + u32Count = 1UL; + } + else + { + /* Save Error status if necessary */ + if (status & EMAC_RXFD_RP) {} + + if (status & EMAC_RXFD_ALIE) {} + + if (status & EMAC_RXFD_PTLE) {} + + if (status & EMAC_RXFD_CRCE) {} + } + } + } + } + + return (u32Count); +} + +/** + * @brief Clean up process after a packet is received + * @param None + * @return None + * @details EMAC Rx interrupt service routine \b must call this API to release the resource use by receive process + * @note Application can only call this function once every time \ref EMAC_RecvPkt or \ref EMAC_RecvPktTS returns 1 + */ +void EMAC_RecvPktDone(EMAC_MEMMGR_T *psMemMgr) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + /* Get Rx Frame Descriptor */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc; + + /* Restore descriptor link list and data pointer they will be overwrite if time stamp enabled */ + desc->u32Data = desc->u32Backup1; + desc->u32Next = desc->u32Backup2; + + /* Change ownership to DMA for next use */ + desc->u32Status1 |= EMAC_DESC_OWN_EMAC; + + /* Get Next Frame Descriptor pointer to process */ + desc = (EMAC_DESCRIPTOR_T *)desc->u32Next; + + /* Save last processed Rx descriptor */ + psMemMgr->psCurrentRxDesc = desc; + + EMAC_TRIGGER_RX(EMAC); +} + + +/** + * @brief Send an Ethernet packet + * @param[in] pu8Data Pointer to a buffer holds the packet to transmit + * @param[in] u32Size Packet size (without 4 byte CRC). + * @return Packet transmit success or not + * @retval 0 Transmit failed due to descriptor unavailable. + * @retval 1 Packet is copied to descriptor and triggered to transmit. + * @note Return 1 doesn't guarantee the packet will be sent and received successfully. + */ +uint32_t EMAC_SendPkt(EMAC_MEMMGR_T *psMemMgr, uint8_t *pu8Data, uint32_t u32Size) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + + /* Get Tx frame descriptor & data pointer */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psNextTxDesc; + uint32_t status = desc->u32Status1; + uint32_t ret = 0UL; + + /* Check descriptor ownership */ + if ((status & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) + { + memcpy((uint8_t *)desc->u32Data, pu8Data, u32Size); + + /* Set Tx descriptor transmit byte count */ + desc->u32Status2 = u32Size; + + /* Change descriptor ownership to EMAC */ + desc->u32Status1 |= EMAC_DESC_OWN_EMAC; + + /* Get next Tx descriptor */ + psMemMgr->psNextTxDesc = (EMAC_DESCRIPTOR_T *)(desc->u32Next); + + /* Trigger EMAC to send the packet */ + EMAC_TRIGGER_TX(EMAC); + ret = 1UL; + } + + return (ret); +} + + +/** + * @brief Clean up process after packet(s) are sent + * @param None + * @return Number of packet sent between two function calls + * @details EMAC Tx interrupt service routine \b must call this API or \ref EMAC_SendPktDoneTS to + * release the resource use by transmit process + */ +uint32_t EMAC_SendPktDone(EMAC_MEMMGR_T *psMemMgr) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + + uint32_t status, reg; + uint32_t last_tx_desc; + uint32_t u32Count = 0UL; + + reg = EMAC->INTSTS; + /* Clear Tx interrupt flags */ + EMAC->INTSTS = reg & (0xFFFF0000UL & ~EMAC_INTSTS_TSALMIF_Msk); + + + if (reg & EMAC_INTSTS_TXBEIF_Msk) + { + /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */ + while (1) {} + } + else + { + /* Get our first descriptor to process */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentTxDesc; + + /* Process the descriptor(s). */ + last_tx_desc = EMAC->CTXDSA ; + + do + { + /* Descriptor ownership is still EMAC, so this packet haven't been send. */ + if (desc->u32Status1 & EMAC_DESC_OWN_EMAC) + { + break; + } + + /* Get Tx status stored in descriptor */ + status = desc->u32Status2 >> 16UL; + + if (status & EMAC_TXFD_TXCP) + { + u32Count++; + } + else + { + /* Do nothing here on error. */ + if (status & EMAC_TXFD_TXABT) {} + + if (status & EMAC_TXFD_DEF) {} + + if (status & EMAC_TXFD_PAU) {} + + if (status & EMAC_TXFD_EXDEF) {} + + if (status & EMAC_TXFD_NCS) {} + + if (status & EMAC_TXFD_SQE) {} + + if (status & EMAC_TXFD_LC) {} + + if (status & EMAC_TXFD_TXHA) {} + } + + /* restore descriptor link list and data pointer they will be overwrite if time stamp enabled */ + desc->u32Data = desc->u32Backup1; + desc->u32Next = desc->u32Backup2; + /* go to next descriptor in link */ + desc = (EMAC_DESCRIPTOR_T *)desc->u32Next; + } + while (last_tx_desc != (uint32_t)desc); /* If we reach last sent Tx descriptor, leave the loop */ + + /* Save last processed Tx descriptor */ + psMemMgr->psCurrentTxDesc = (EMAC_DESCRIPTOR_T *)desc; + } + + return (u32Count); +} + +/** + * @brief Clean up process after a packet is sent, and get the time stamp while packet is sent + * @param[in] pu32Sec Second value while packet sent + * @param[in] pu32Nsec Nano second value while packet sent + * @return If a packet sent successfully + * @retval 0 No packet sent successfully, and the value in *pu32Sec and *pu32Nsec are meaningless + * @retval 1 A packet sent successfully, and the value in *pu32Sec and *pu32Nsec is the time stamp while packet sent + * @details EMAC Tx interrupt service routine \b must call this API or \ref EMAC_SendPktDone to + * release the resource use by transmit process + */ +uint32_t EMAC_SendPktDoneTS(EMAC_MEMMGR_T *psMemMgr, uint32_t *pu32Sec, uint32_t *pu32Nsec) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + uint32_t reg; + uint32_t u32Count = 0UL; + + reg = EMAC->INTSTS; + /* Clear Tx interrupt flags */ + EMAC->INTSTS = reg & (0xFFFF0000UL & ~EMAC_INTSTS_TSALMIF_Msk); + + + if (reg & EMAC_INTSTS_TXBEIF_Msk) + { + /* Bus error occurred, this is usually a bad sign about software bug and will occur again... */ + while (1) {} + } + else + { + /* Process the descriptor. + Get our first descriptor to process */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentTxDesc; + + /* Descriptor ownership is still EMAC, so this packet haven't been send. */ + if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) + { + /* Get Tx status stored in descriptor */ + uint32_t status = desc->u32Status2 >> 16UL; + + if (status & EMAC_TXFD_TXCP) + { + u32Count = 1UL; + *pu32Sec = desc->u32Next; /* second stores in descriptor's NEXT field */ + *pu32Nsec = EMAC_Subsec2Nsec(desc->u32Data); /* Sub nano second store in DATA field */ + } + else + { + /* Do nothing here on error. */ + if (status & EMAC_TXFD_TXABT) {} + + if (status & EMAC_TXFD_DEF) {} + + if (status & EMAC_TXFD_PAU) {} + + if (status & EMAC_TXFD_EXDEF) {} + + if (status & EMAC_TXFD_NCS) {} + + if (status & EMAC_TXFD_SQE) {} + + if (status & EMAC_TXFD_LC) {} + + if (status & EMAC_TXFD_TXHA) {} + } + + /* restore descriptor link list and data pointer they will be overwrite if time stamp enabled */ + desc->u32Data = desc->u32Backup1; + desc->u32Next = desc->u32Backup2; + /* go to next descriptor in link */ + desc = (EMAC_DESCRIPTOR_T *)desc->u32Next; + + /* Save last processed Tx descriptor */ + psMemMgr->psCurrentTxDesc = desc; + } + } + + return (u32Count); +} + +/** + * @brief Enable IEEE1588 time stamp function and set current time + * @param[in] u32Sec Second value + * @param[in] u32Nsec Nano second value + * @return None + */ +void EMAC_EnableTS(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec) +{ +#if 0 + double f; + uint32_t reg; + EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk; + EMAC->UPDSEC = u32Sec; /* Assume current time is 0 sec + 0 nano sec */ + EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec); + + /* PTP source clock is 160MHz (Real chip using PLL). Each tick is 6.25ns + Assume we want to set each tick to 100ns. + Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7 + Addend register = 2^32 * tick_freq / (160MHz), where tick_freq = (2^31 / 215) MHz + From above equation, addend register = 2^63 / (160M * 215) ~= 268121280 = 0xFFB34C0 + So: + EMAC->TSIR = 0xD7; + EMAC->TSAR = 0x1E70C600; */ + f = (100.0 * 2147483648.0) / (1000000000.0) + 0.5; + EMAC->TSINC = (reg = (uint32_t)f); + f = (double)9223372036854775808.0 / ((double)(CLK_GetHCLKFreq()) * (double)reg); + EMAC->TSADDEND = (uint32_t)f; + EMAC->TSCTL |= (EMAC_TSCTL_TSUPDATE_Msk | EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk); /* Fine update */ +#endif +} + +/** + * @brief Disable IEEE1588 time stamp function + * @param None + * @return None + */ +void EMAC_DisableTS(EMAC_T *EMAC) +{ +#if 0 + EMAC->TSCTL = 0UL; +#endif +} + +/** + * @brief Get current time stamp + * @param[out] pu32Sec Current second value + * @param[out] pu32Nsec Current nano second value + * @return None + */ +void EMAC_GetTime(EMAC_T *EMAC, uint32_t *pu32Sec, uint32_t *pu32Nsec) +{ + /* Must read TSLSR firstly. Hardware will preserve TSMSR value at the time TSLSR read. */ + *pu32Nsec = EMAC_Subsec2Nsec(EMAC->TSSUBSEC); + *pu32Sec = EMAC->TSSEC; +} + +/** + * @brief Set current time stamp + * @param[in] u32Sec Second value + * @param[in] u32Nsec Nano second value + * @return None + */ +void EMAC_SetTime(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec) +{ + /* Disable time stamp counter before update time value (clear EMAC_TSCTL_TSIEN_Msk) */ + EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk; + EMAC->UPDSEC = u32Sec; + EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec); + EMAC->TSCTL |= (EMAC_TSCTL_TSIEN_Msk | EMAC_TSCTL_TSMODE_Msk); + +} + +/** + * @brief Enable alarm function and set alarm time + * @param[in] u32Sec Second value to trigger alarm + * @param[in] u32Nsec Nano second value to trigger alarm + * @return None + */ +void EMAC_EnableAlarm(EMAC_T *EMAC, uint32_t u32Sec, uint32_t u32Nsec) +{ + + EMAC->ALMSEC = u32Sec; + EMAC->ALMSUBSEC = EMAC_Nsec2Subsec(u32Nsec); + EMAC->TSCTL |= EMAC_TSCTL_TSALMEN_Msk; + +} + +/** + * @brief Disable alarm function + * @param None + * @return None + */ +void EMAC_DisableAlarm(EMAC_T *EMAC) +{ + + EMAC->TSCTL &= ~EMAC_TSCTL_TSALMEN_Msk; + +} + +/** + * @brief Add a offset to current time + * @param[in] u32Neg Offset is negative value (u32Neg == 1) or positive value (u32Neg == 0). + * @param[in] u32Sec Second value to add to current time + * @param[in] u32Nsec Nano second value to add to current time + * @return None + */ +void EMAC_UpdateTime(EMAC_T *EMAC, uint32_t u32Neg, uint32_t u32Sec, uint32_t u32Nsec) +{ + EMAC->UPDSEC = u32Sec; + EMAC->UPDSUBSEC = EMAC_Nsec2Subsec(u32Nsec); + + if (u32Neg) + { + EMAC->UPDSUBSEC |= BIT31; /* Set bit 31 indicates this is a negative value */ + } + + EMAC->TSCTL |= EMAC_TSCTL_TSUPDATE_Msk; + +} + +/** + * @brief Check Ethernet link status + * @param None + * @return Current link status, could be one of following value. + * - \ref EMAC_LINK_DOWN + * - \ref EMAC_LINK_100F + * - \ref EMAC_LINK_100H + * - \ref EMAC_LINK_10F + * - \ref EMAC_LINK_10H + * @note This API should be called regularly to sync EMAC setting with real connection status + */ +uint32_t EMAC_CheckLinkStatus(EMAC_T *EMAC) +{ + uint32_t reg, ret = EMAC_LINK_DOWN; + + /* Check link valid again */ + if (EMAC_MdioRead(EMAC, PHY_STATUS_REG, EMAC_PHY_ADDR) & PHY_STATUS_LINK_VALID) + { + /* Check link partner capability */ + reg = EMAC_MdioRead(EMAC, PHY_ANLPA_REG, EMAC_PHY_ADDR) ; + + if (reg & PHY_ANLPA_DR100_TX_FULL) + { + EMAC->CTL |= EMAC_CTL_OPMODE_Msk; + EMAC->CTL |= EMAC_CTL_FUDUP_Msk; + ret = EMAC_LINK_100F; + } + else if (reg & PHY_ANLPA_DR100_TX_HALF) + { + EMAC->CTL |= EMAC_CTL_OPMODE_Msk; + EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk; + ret = EMAC_LINK_100H; + } + else if (reg & PHY_ANLPA_DR10_TX_FULL) + { + EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk; + EMAC->CTL |= EMAC_CTL_FUDUP_Msk; + ret = EMAC_LINK_10F; + } + else + { + EMAC->CTL &= ~EMAC_CTL_OPMODE_Msk; + EMAC->CTL &= ~EMAC_CTL_FUDUP_Msk; + ret = EMAC_LINK_10H; + } + } + + return ret; +} + +/** + * @brief Fill a MAC address to list and enable. + * @param A MAC address + * @return The CAM index + * @retval -1 Failed to fill the MAC address. + * @retval 0~(EMAC_CAMENTRY_NB-1) The index number of entry location. + */ +int32_t EMAC_FillCamEntry(EMAC_T *EMAC, uint8_t pu8MacAddr[]) +{ + uint32_t *EMAC_CAMxM; + uint32_t *EMAC_CAMxL; + int32_t index; + uint8_t mac[6]; + + for (index = 0; index < EMAC_CAMENTRY_NB; index ++) + { + EMAC_CAMxM = (uint32_t *)((uint32_t)&EMAC->CAM0M + (index * 8)); + EMAC_CAMxL = (uint32_t *)((uint32_t)&EMAC->CAM0L + (index * 8)); + + mac[0] = (*EMAC_CAMxM >> 24) & 0xff; + mac[1] = (*EMAC_CAMxM >> 16) & 0xff; + mac[2] = (*EMAC_CAMxM >> 8) & 0xff; + mac[3] = (*EMAC_CAMxM) & 0xff; + mac[4] = (*EMAC_CAMxL >> 24) & 0xff; + mac[5] = (*EMAC_CAMxL >> 16) & 0xff; + + if (memcmp(mac, pu8MacAddr, sizeof(mac)) == 0) + { + goto exit_emac_fillcamentry; + } + + if (*EMAC_CAMxM == 0 && *EMAC_CAMxL == 0) + { + break; + } + } + + if (index < EMAC_CAMENTRY_NB) + { + EMAC_EnableCamEntry(EMAC, index, pu8MacAddr); + goto exit_emac_fillcamentry; + } + + return -1; + +exit_emac_fillcamentry: + + return index; +} + +/** + * @brief Send an Ethernet packet + * @param[in] u32Size Packet size (without 4 byte CRC). + * @return Packet transmit success or not + * @retval 0 Transmit failed due to descriptor unavailable. + * @retval 1 Triggered to transmit. + * @note Return 1 doesn't guarantee the packet will be sent and received successfully. + */ +uint32_t EMAC_SendPktWoCopy(EMAC_MEMMGR_T *psMemMgr, uint32_t u32Size) +{ + EMAC_T *EMAC = psMemMgr->psEmac; + + /* Get Tx frame descriptor & data pointer */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psNextTxDesc; + uint32_t status = desc->u32Status1; + uint32_t ret = 0UL; + + /* Check descriptor ownership */ + if ((status & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) + { + /* Set Tx descriptor transmit byte count */ + desc->u32Status2 = u32Size; + + /* Change descriptor ownership to EMAC */ + desc->u32Status1 |= EMAC_DESC_OWN_EMAC; + + /* Get next Tx descriptor */ + psMemMgr->psNextTxDesc = (EMAC_DESCRIPTOR_T *)(desc->u32Next); + + /* Trigger EMAC to send the packet */ + EMAC_TRIGGER_TX(EMAC); + ret = 1UL; + } + + return (ret); +} + +/** + * @brief Get avaiable TX buffer address + * @param None + * @return An avaiable TX buffer. + * @note This API should be called before EMAC_SendPkt_WoCopy calling. Caller will do data-copy. + */ +uint8_t *EMAC_ClaimFreeTXBuf(EMAC_MEMMGR_T *psMemMgr) +{ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psNextTxDesc; + + if (desc->u32Status1 & EMAC_DESC_OWN_EMAC) + { + return (NULL); + } + else + { + return (uint8_t *)desc->u32Data; + } +} + +/** + * @brief Get data length of avaiable RX buffer. + * @param None + * @return An data length of avaiable RX buffer. + * @note This API should be called before EMAC_RecvPktDone_WoTrigger calling. Caller will do data-copy. + */ +uint32_t EMAC_GetAvailRXBufSize(EMAC_MEMMGR_T *psMemMgr, uint8_t **ppuDataBuf) +{ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc; + + if ((desc->u32Status1 & EMAC_DESC_OWN_EMAC) != EMAC_DESC_OWN_EMAC) /* ownership=CPU */ + { + uint32_t status = desc->u32Status1 >> 16; + + /* It is good and no CRC error. */ + if ((status & EMAC_RXFD_RXGD) && !(status & EMAC_RXFD_CRCE)) + { + *ppuDataBuf = (uint8_t *)desc->u32Data; + return desc->u32Status1 & 0xFFFFUL; + } + else + { + // Drop it + EMAC_RecvPktDone(psMemMgr); + } + } + + return 0; +} + + +/** + * @brief Clean up process after a packet is received. + * @param None + * @return None + * @details Caller must call the function to release the resource. + * @note Application can only call this function once every time \ref EMAC_RecvPkt or \ref EMAC_RecvPktTS returns 1 + * @note This function is without doing EMAC_TRIGGER_RX. + */ +void EMAC_RecvPktDoneWoRxTrigger(EMAC_MEMMGR_T *psMemMgr) +{ + /* Get Rx Frame Descriptor */ + EMAC_DESCRIPTOR_T *desc = (EMAC_DESCRIPTOR_T *)psMemMgr->psCurrentRxDesc; + + /* Restore descriptor link list and data pointer they will be overwrite if time stamp enabled */ + desc->u32Data = desc->u32Backup1; + desc->u32Next = desc->u32Backup2; + + /* Change ownership to DMA for next use */ + desc->u32Status1 |= EMAC_DESC_OWN_EMAC; + + /* Get Next Frame Descriptor pointer to process */ + desc = (EMAC_DESCRIPTOR_T *)desc->u32Next; + + /* Save last processed Rx descriptor */ + psMemMgr->psCurrentRxDesc = desc; +} + + +/*@}*/ /* end of group EMAC_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group EMAC_Driver */ + +/*@}*/ /* end of group Standard_Driver */ + +/*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_etimer.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_etimer.c new file mode 100644 index 0000000000000000000000000000000000000000..f34db44f6f3ef556b56d8093330aa7f174635de6 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_etimer.c @@ -0,0 +1,341 @@ +/**************************************************************************//** + * @file etimer.c + * @brief N9H30 series ETIMER driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "N9H30.h" +#include "nu_sys.h" + +/// @cond HIDDEN_SYMBOLS +/** + * @brief This API is used to get the clock frequency of Timer + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return Timer clock frequency + * @note This API cannot return correct clock rate if timer source is external clock input. + */ +UINT ETIMER_GetModuleClock(UINT timer) +{ + UINT src; + + src = (inpw(REG_CLK_DIVCTL8) >> (16 + timer * 4)) & 0x3; + + if (src == 0) + return 12000000; + else if (src == 1) + return (sysGetClock(SYS_PCLK) * 1000000); + else if (src == 2) + return (sysGetClock(SYS_PCLK) * 1000000 / 4096); + else + return 32768; + +} + +/// @endcond /* HIDDEN_SYMBOLS */ + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_ETIMER_Driver ETIMER Driver + @{ +*/ + + +/** @addtogroup N9H30_ETIMER_EXPORTED_FUNCTIONS ETIMER Exported Functions + @{ +*/ + +/** + * @brief This API is used to configure timer to operate in specified mode + * and frequency. If timer cannot work in target frequency, a closest + * frequency will be chose and returned. + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @param[in] u32Mode Operation mode. Possible options are + * - \ref ETIMER_ONESHOT_MODE + * - \ref ETIMER_PERIODIC_MODE + * - \ref ETIMER_TOGGLE_MODE + * - \ref ETIMER_CONTINUOUS_MODE + * @param[in] u32Freq Target working frequency + * @return Real Timer working frequency + * @note After calling this API, Timer is \b NOT running yet. But could start timer running be calling + * \ref ETIMER_Start macro or program registers directly + */ +UINT ETIMER_Open(UINT timer, UINT u32Mode, UINT u32Freq) +{ + UINT u32Clk = ETIMER_GetModuleClock(timer); + UINT u32Cmpr = 0, u32Prescale = 0; + + // Fastest possible timer working freq is u32Clk / 2. While cmpr = 2, pre-scale = 0 + if (u32Freq > (u32Clk / 2)) + { + u32Cmpr = 2; + } + else + { + if (u32Clk >= 0x4000000) + { + u32Prescale = 7; // real prescaler value is 8 + u32Clk >>= 3; + } + else if (u32Clk >= 0x2000000) + { + u32Prescale = 3; // real prescaler value is 4 + u32Clk >>= 2; + } + else if (u32Clk >= 0x1000000) + { + u32Prescale = 1; // real prescaler value is 2 + u32Clk >>= 1; + } + u32Cmpr = u32Clk / u32Freq; + } + + if (timer == 0) + { + outpw(REG_ETMR0_CMPR, u32Cmpr); + outpw(REG_ETMR0_PRECNT, u32Prescale); + outpw(REG_ETMR0_CTL, 1 | u32Mode); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CMPR, u32Cmpr); + outpw(REG_ETMR1_PRECNT, u32Prescale); + outpw(REG_ETMR1_CTL, 1 | u32Mode); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CMPR, u32Cmpr); + outpw(REG_ETMR2_PRECNT, u32Prescale); + outpw(REG_ETMR2_CTL, 1 | u32Mode); + } + else + { + outpw(REG_ETMR3_CMPR, u32Cmpr); + outpw(REG_ETMR3_PRECNT, u32Prescale); + outpw(REG_ETMR3_CTL, 1 | u32Mode); + } + + return (u32Clk / (u32Cmpr * (u32Prescale + 1))); +} + +/** + * @brief This API stops Timer counting and disable the Timer interrupt function + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +void ETIMER_Close(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, 0); + outpw(REG_ETMR0_IER, 0); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, 0); + outpw(REG_ETMR1_IER, 0); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, 0); + outpw(REG_ETMR2_IER, 0); + } + else + { + outpw(REG_ETMR3_CTL, 0); + outpw(REG_ETMR3_IER, 0); + } +} + +/** + * @brief This API is used to create a delay loop for u32usec micro seconds + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @param[in] u32Usec Delay period in micro seconds with 10 usec every step. Valid values are between 10~1000000 (10 micro second ~ 1 second) + * @return None + * @note This API overwrites the register setting of the timer used to count the delay time. + * @note This API use polling mode. So there is no need to enable interrupt for the timer module used to generate delay + */ +void ETIMER_Delay(UINT timer, UINT u32Usec) +{ + UINT u32Clk = ETIMER_GetModuleClock(timer); + UINT u32Prescale = 0, delay = 300000000 / u32Clk; + float fCmpr; + + // Clear current timer configuration + if (timer == 0) + { + outpw(REG_ETMR0_CTL, 0); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, 0); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, 0); + } + else + { + outpw(REG_ETMR3_CTL, 0); + } + + if (u32Clk == 10000) // min delay is 100us if timer clock source is LIRC 10k + { + u32Usec = ((u32Usec + 99) / 100) * 100; + } + else // 10 usec every step + { + u32Usec = ((u32Usec + 9) / 10) * 10; + } + + if (u32Clk >= 0x4000000) + { + u32Prescale = 7; // real prescaler value is 8 + u32Clk >>= 3; + } + else if (u32Clk >= 0x2000000) + { + u32Prescale = 3; // real prescaler value is 4 + u32Clk >>= 2; + } + else if (u32Clk >= 0x1000000) + { + u32Prescale = 1; // real prescaler value is 2 + u32Clk >>= 1; + } + + // u32Usec * u32Clk might overflow if using UINT + fCmpr = ((float)u32Usec * (float)u32Clk) / 1000000.0; + + if (timer == 0) + { + outpw(REG_ETMR0_CMPR, (UINT)fCmpr); + outpw(REG_ETMR0_PRECNT, u32Prescale); + outpw(REG_ETMR0_CTL, 1); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CMPR, (UINT)fCmpr); + outpw(REG_ETMR1_PRECNT, u32Prescale); + outpw(REG_ETMR1_CTL, 1); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CMPR, (UINT)fCmpr); + outpw(REG_ETMR2_PRECNT, u32Prescale); + outpw(REG_ETMR2_CTL, 1); + } + else + { + outpw(REG_ETMR3_CMPR, (UINT)fCmpr); + outpw(REG_ETMR3_PRECNT, u32Prescale); + outpw(REG_ETMR3_CTL, 1); + } + + // When system clock is faster than timer clock, it is possible timer active bit cannot set in time while we check it. + // And the while loop below return immediately, so put a tiny delay here allowing timer start counting and raise active flag. + for (; delay > 0; delay--) + { +#if defined (__GNUC__) && !(__CC_ARM) + __asm__ __volatile__ + ( + "nop \n" + ); +#else + __asm + { + NOP + } +#endif + } + + if (timer == 0) + { + while (inpw(REG_ETMR0_CTL) & 0x80); + } + else if (timer == 1) + { + while (inpw(REG_ETMR1_CTL) & 0x80); + } + else if (timer == 2) + { + while (inpw(REG_ETMR2_CTL) & 0x80); + } + else + { + while (inpw(REG_ETMR3_CTL) & 0x80); + } +} + +/** + * @brief This API is used to enable timer capture function with specified mode and capture edge + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @param[in] u32CapMode Timer capture mode. Could be + * - \ref ETIMER_CAPTURE_FREE_COUNTING_MODE + * - \ref ETIMER_CAPTURE_TRIGGER_COUNTING_MODE + * - \ref ETIMER_CAPTURE_COUNTER_RESET_MODE + * @param[in] u32Edge Timer capture edge. Possible values are + * - \ref ETIMER_CAPTURE_FALLING_EDGE + * - \ref ETIMER_CAPTURE_RISING_EDGE + * - \ref ETIMER_CAPTURE_FALLING_THEN_RISING_EDGE + * - \ref ETIMER_CAPTURE_RISING_THEN_FALLING_EDGE + * @return None + * @note Timer frequency should be configured separately by using \ref ETIMER_Open API, or program registers directly + */ +void ETIMER_EnableCapture(UINT timer, UINT u32CapMode, UINT u32Edge) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, (inpw(REG_ETMR0_CTL) & ~0x1E0000) | u32CapMode | u32Edge | 0x10000); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, (inpw(REG_ETMR1_CTL) & ~0x1E0000) | u32CapMode | u32Edge | 0x10000); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, (inpw(REG_ETMR2_CTL) & ~0x1E0000) | u32CapMode | u32Edge | 0x10000); + } + else + { + outpw(REG_ETMR3_CTL, (inpw(REG_ETMR3_CTL) & ~0x1E0000) | u32CapMode | u32Edge | 0x10000); + } +} + +/** + * @brief This API is used to disable the Timer capture function + * @param[in] timer ETIMER number. Range from 0 ~ 3 + * @return None + */ +void ETIMER_DisableCapture(UINT timer) +{ + if (timer == 0) + { + outpw(REG_ETMR0_CTL, inpw(REG_ETMR0_CTL) & ~0x10000); + } + else if (timer == 1) + { + outpw(REG_ETMR1_CTL, inpw(REG_ETMR1_CTL) & ~0x10000); + } + else if (timer == 2) + { + outpw(REG_ETMR2_CTL, inpw(REG_ETMR2_CTL) & ~0x10000); + } + else + { + outpw(REG_ETMR3_CTL, inpw(REG_ETMR3_CTL) & ~0x10000); + } + +} + + +/*@}*/ /* end of group N9H30_ETIMER_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_ETIMER_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_fmi.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_fmi.c new file mode 100644 index 0000000000000000000000000000000000000000..3f80d5fbb2718a1c4e421c8b2156b90d595b4aec --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_fmi.c @@ -0,0 +1,920 @@ +/**************************************************************************//** + * @file fmi.c + * @brief N9H30 FMI eMMC driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include +#include +#include +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_fmi.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_FMI_Driver FMI Driver + @{ +*/ + + +/** @addtogroup N9H30_FMI_EXPORTED_FUNCTIONS FMI Exported Functions + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +#define FMI_BLOCK_SIZE 512 + +// global variables +// For response R3 (such as ACMD41, CRC-7 is invalid; but FMI controller will still +// calculate CRC-7 and get an error result, software should ignore this error and clear INTSTS [CRC_IF] flag +// _fmi_uR3_CMD is the flag for it. 1 means software should ignore CRC-7 error +unsigned int _fmi_uR3_CMD = 0; +unsigned int _fmi_uR7_CMD = 0; +unsigned char volatile _fmi_eMMCDataReady = FALSE; + +unsigned char *_fmi_peMMCBuffer; +unsigned int gFMIReferenceClock; + +#ifdef __ICCARM__ + #pragma data_alignment = 4096 + unsigned char _fmi_uceMMCBuffer[512]; +#else + unsigned char _fmi_uceMMCBuffer[512] __attribute__((aligned(4096))); +#endif + +int emmc_ok = 0; + +unsigned char peMMC_offset = 0; + +EMMC_INFO_T eMMC; + +void eMMC_CheckRB() +{ + while (1) + { + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk); + if (inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_DAT0STS_Msk) + break; + } +} + + +int eMMC_Command(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg) +{ + volatile int buf; + + outpw(REG_FMI_EMMCCMD, uArg); + buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk); + outpw(REG_FMI_EMMCCTL, buf); + + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_COEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + return 0; +} + + +int eMMC_CmdAndRsp(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg, int ntickCount) +{ + volatile int buf; + + outpw(REG_FMI_EMMCCMD, uArg); + buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk); + outpw(REG_FMI_EMMCCTL, buf); + + if (ntickCount > 0) + { + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_RIEN_Msk) + { + if (ntickCount-- == 0) + { + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CTLRST_Msk); // reset SD engine + return 2; + } + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + } + else + { + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_RIEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + } + + if (_fmi_uR7_CMD) + { + if (((inpw(REG_FMI_EMMCRESP1) & 0xff) != 0x55) && ((inpw(REG_FMI_EMMCRESP0) & 0xf) != 0x01)) + { + _fmi_uR7_CMD = 0; + return EMMC_CMD8_ERROR; + } + } + + if (!_fmi_uR3_CMD) + { + if (inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk) // check CRC7 + return 0; + else + return EMMC_CRC7_ERROR; + } + else // ignore CRC error for R3 case + { + _fmi_uR3_CMD = 0; + outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk); + return 0; + } +} + +int eMMC_Swap32(int val) +{ + int buf; + + buf = val; + val <<= 24; + val |= (buf << 8) & 0xff0000; + val |= (buf >> 8) & 0xff00; + val |= (buf >> 24) & 0xff; + return val; +} + +// Get 16 bytes CID or CSD +int eMMC_CmdAndRsp2(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg, unsigned int *puR2ptr) +{ + unsigned int i, buf; + unsigned int tmpBuf[5]; + + outpw(REG_FMI_EMMCCMD, uArg); + buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_R2EN_Msk); + outpw(REG_FMI_EMMCCTL, buf); + + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_R2EN_Msk) + { + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + if (inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk) + { + for (i = 0; i < 5; i++) + tmpBuf[i] = eMMC_Swap32(*(int *)(FMI_BA + i * 4)); + for (i = 0; i < 4; i++) + *puR2ptr++ = ((tmpBuf[i] & 0x00ffffff) << 8) | ((tmpBuf[i + 1] & 0xff000000) >> 24); + return 0; + } + else + return EMMC_CRC7_ERROR; +} + + +int eMMC_CmdAndRspDataIn(EMMC_INFO_T *pSD, unsigned char ucCmd, unsigned int uArg) +{ + volatile int buf; + + outpw(REG_FMI_EMMCCMD, uArg); + buf = (inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk)) | (ucCmd << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DIEN_Msk); + outpw(REG_FMI_EMMCCTL, buf); + + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_RIEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DIEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)) // check CRC7 + { + return EMMC_CRC7_ERROR; + } + + if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC16_Msk)) // check CRC16 + { + return EMMC_CRC16_ERROR; + } + return 0; +} + +// there are 3 bits for divider N0, maximum is 8 +#define EMMC_CLK_DIV0_MAX 8 +// there are 8 bits for divider N1, maximum is 256 +#define EMMC_CLK_DIV1_MAX 256 + +void eMMC_Set_clock(unsigned int clock_khz) +{ + UINT32 rate, div0, div1, i; + + //--- calculate the rate that 2 divider have to divide + // _fmi_uFMIReferenceClock is the input clock with unit KHz like as APLL/UPLL and + if (clock_khz > gFMIReferenceClock) + { + //sysprintf("ERROR: wrong eMMC clock %dKHz since it is faster than input clock %dKHz !\n", clock_khz, gFMIReferenceClock); + return; + } + rate = gFMIReferenceClock / clock_khz; + // choose slower clock if system clock cannot divisible by wanted clock + if (gFMIReferenceClock % clock_khz != 0) + rate++; + + if (rate > (EMMC_CLK_DIV0_MAX * EMMC_CLK_DIV1_MAX)) // the maximum divider for EMMC_CLK is (EMMC_CLK_DIV0_MAX * EMMC_CLK_DIV1_MAX) + { + //sysprintf("ERROR: wrong SD clock %dKHz since it is slower than input clock %dKHz/%d !\n", clock_khz, gFMIReferenceClock, EMMC_CLK_DIV0_MAX * EMMC_CLK_DIV1_MAX); + return; + } + + //--- choose a suitable value for first divider + for (div0 = EMMC_CLK_DIV0_MAX; div0 > 0; div0--) // choose the maximum value if can exact division + { + if (rate % div0 == 0) + break; + } + if (div0 == 0) // cannot exact division + { + // if rate <= EMMC_CLK_DIV1_MAX, set div0 to 1 since div1 can exactly divide input clock + div0 = (rate <= EMMC_CLK_DIV1_MAX) ? 1 : EMMC_CLK_DIV0_MAX; + } + + //--- calculate the second divider + div1 = rate / div0; + div1 &= 0xFF; + + //sysprintf("Set_clock(): wanted clock=%d, rate=%d, div0=%d, div1=%d\n", clock_khz, rate, div0, div1); + + //--- setup register + outpw(REG_CLK_DIVCTL3, (inpw(REG_CLK_DIVCTL3) & ~0x18) | (0x3 << 3)); + outpw(REG_CLK_DIVCTL3, (inpw(REG_CLK_DIVCTL3) & ~0x7) | (div0 - 1)); + outpw(REG_CLK_DIVCTL3, (inpw(REG_CLK_DIVCTL3) & ~0xff00) | ((div1 - 1) << 8)); + for (i = 0; i < 1000; i++); // waiting for clock become stable + return; +} + +// Initial +int eMMC_Init(EMMC_INFO_T *pSD) +{ + int volatile i, status; + unsigned int resp; + unsigned int CIDBuffer[4]; + unsigned int volatile u32CmdTimeOut; + + // set the clock to 300KHz + eMMC_Set_clock(300); + + // power ON 74 clock + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK74OEN_Msk); + + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK74OEN_Msk); + + eMMC_Command(pSD, 0, 0); // reset all cards + for (i = 0x1000; i > 0; i--); + + // initial SDHC + _fmi_uR7_CMD = 1; + u32CmdTimeOut = 5000; + + i = eMMC_CmdAndRsp(pSD, 8, 0x00000155, u32CmdTimeOut); + if (i == 0) + { + // SD 2.0 + eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); + _fmi_uR3_CMD = 1; + eMMC_CmdAndRsp(pSD, 41, 0x40ff8000, u32CmdTimeOut); // 2.7v-3.6v + resp = inpw(REG_FMI_EMMCRESP0); + + while (!(resp & 0x00800000)) // check if card is ready + { + eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); + _fmi_uR3_CMD = 1; + eMMC_CmdAndRsp(pSD, 41, 0x40ff8000, u32CmdTimeOut); // 3.0v-3.4v + resp = inpw(REG_FMI_EMMCRESP0); + } + if (resp & 0x00400000) + pSD->CardType = EMMC_TYPE_SD_HIGH; + else + pSD->CardType = EMMC_TYPE_SD_LOW; + } + else + { + // SD 1.1 + eMMC_Command(pSD, 0, 0); // reset all cards + for (i = 0x100; i > 0; i--); + + i = eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); + if (i == 2) // MMC memory + { + + eMMC_Command(pSD, 0, 0); // reset + for (i = 0x100; i > 0; i--); + + _fmi_uR3_CMD = 1; + + if (eMMC_CmdAndRsp(pSD, 1, 0x40ff8000, u32CmdTimeOut) != 2) // eMMC memory + { + resp = inpw(REG_FMI_EMMCRESP0); + while (!(resp & 0x00800000)) // check if card is ready + { + _fmi_uR3_CMD = 1; + + eMMC_CmdAndRsp(pSD, 1, 0x40ff8000, u32CmdTimeOut); // high voltage + resp = inpw(REG_FMI_EMMCRESP0); + } + + if (resp & 0x00400000) + pSD->CardType = EMMC_TYPE_EMMC; + else + pSD->CardType = EMMC_TYPE_MMC; + } + else + { + pSD->CardType = EMMC_TYPE_UNKNOWN; + return EMMC_ERR_DEVICE; + } + } + else if (i == 0) // SD Memory + { + _fmi_uR3_CMD = 1; + eMMC_CmdAndRsp(pSD, 41, 0x00ff8000, u32CmdTimeOut); // 3.0v-3.4v + resp = inpw(REG_FMI_EMMCRESP0); + while (!(resp & 0x00800000)) // check if card is ready + { + eMMC_CmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); + _fmi_uR3_CMD = 1; + eMMC_CmdAndRsp(pSD, 41, 0x00ff8000, u32CmdTimeOut); // 3.0v-3.4v + resp = inpw(REG_FMI_EMMCRESP0); + } + pSD->CardType = EMMC_TYPE_SD_LOW; + } + else + { + pSD->CardType = EMMC_TYPE_UNKNOWN; + return EMMC_INIT_ERROR; + } + } + + // CMD2, CMD3 + if (pSD->CardType != EMMC_TYPE_UNKNOWN) + { + eMMC_CmdAndRsp2(pSD, 2, 0x00, CIDBuffer); + if ((pSD->CardType == EMMC_TYPE_MMC) || (pSD->CardType == EMMC_TYPE_EMMC)) + { + if ((status = eMMC_CmdAndRsp(pSD, 3, 0x10000, 0)) != 0) // set RCA + return status; + pSD->RCA = 0x10000; + } + else + { + if ((status = eMMC_CmdAndRsp(pSD, 3, 0x00, 0)) != 0) // get RCA + return status; + else + pSD->RCA = (inpw(REG_FMI_EMMCRESP0) << 8) & 0xffff0000; + } + } + +#if 0 + if (pSD->CardType == EMMC_TYPE_SD_HIGH) + sysprintf("This is high capacity SD memory card\n"); + if (pSD->CardType == EMMC_TYPE_SD_LOW) + sysprintf("This is standard capacity SD memory card\n"); + if (pSD->CardType == EMMC_TYPE_EMMC) + sysprintf("This is eMMC memory card\n"); +#endif + return 0; +} + + +int eMMC_SwitchToHighSpeed(EMMC_INFO_T *pSD) +{ + int volatile status = 0; + unsigned short current_comsumption, busy_status0; + + outpw(REG_FMI_DMASA, (unsigned int)_fmi_peMMCBuffer); // set DMA transfer starting address + outpw(REG_FMI_EMMCBLEN, 63); // 512 bit + + if ((status = eMMC_CmdAndRspDataIn(pSD, 6, 0x00ffff01)) != 0) + return 1; + + current_comsumption = _fmi_peMMCBuffer[0] << 8 | _fmi_peMMCBuffer[1]; + if (!current_comsumption) + return 1; + + busy_status0 = _fmi_peMMCBuffer[28] << 8 | _fmi_peMMCBuffer[29]; + + if (!busy_status0) // function ready + { + outpw(REG_FMI_DMASA, (unsigned int)_fmi_peMMCBuffer); // set DMA transfer starting address + outpw(REG_FMI_EMMCBLEN, 63); // 512 bit + + if ((status = eMMC_CmdAndRspDataIn(pSD, 6, 0x80ffff01)) != 0) + return 1; + + // function change timing: 8 clocks + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk); + + current_comsumption = _fmi_peMMCBuffer[0] << 8 | _fmi_peMMCBuffer[1]; + if (!current_comsumption) + return 1; + + return 0; + } + else + return 1; +} + + +int eMMC_SelectCardType(EMMC_INFO_T *pSD) +{ + int volatile status = 0; + //unsigned int arg; + + if ((status = eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0)) != 0) + return status; + + eMMC_CheckRB(); + + // if SD card set 4bit + if (pSD->CardType == EMMC_TYPE_SD_HIGH) + { + _fmi_peMMCBuffer = (unsigned char *)((unsigned int)_fmi_uceMMCBuffer); + outpw(REG_FMI_DMASA, (unsigned int)_fmi_peMMCBuffer); // set DMA transfer starting address + outpw(REG_FMI_EMMCBLEN, 0x07); // 64 bit + + if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0) + return status; + if ((status = eMMC_CmdAndRspDataIn(pSD, 51, 0x00)) != 0) + return status; + + if ((_fmi_uceMMCBuffer[0] & 0xf) == 0x2) + { + status = eMMC_SwitchToHighSpeed(pSD); + if (status == 0) + { + /* divider */ + eMMC_Set_clock(SDHC_FREQ); + } + } + + if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0) + return status; + if ((status = eMMC_CmdAndRsp(pSD, 6, 0x02, 0)) != 0) // set bus width + return status; + + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_DBW_Msk); + } + else if (pSD->CardType == EMMC_TYPE_SD_LOW) + { + _fmi_peMMCBuffer = (unsigned char *)((unsigned int)_fmi_uceMMCBuffer); + outpw(REG_FMI_DMASA, (unsigned int) _fmi_peMMCBuffer); // set DMA transfer starting address + outpw(REG_FMI_EMMCBLEN, 0x07); // 64 bit + + if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0) + return status; + if ((status = eMMC_CmdAndRspDataIn(pSD, 51, 0x00)) != 0) + return status; + + // set data bus width. ACMD6 for SD card, SDCR_DBW for host. + if ((status = eMMC_CmdAndRsp(pSD, 55, pSD->RCA, 0)) != 0) + return status; + + if ((status = eMMC_CmdAndRsp(pSD, 6, 0x02, 0)) != 0) // set bus width + return status; + + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_DBW_Msk); + } + else if (pSD->CardType == EMMC_TYPE_MMC) + { + + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) & ~FMI_EMMCCTL_DBW_Msk); + + } + else if (pSD->CardType == EMMC_TYPE_EMMC) + { + + //--- sent CMD6 to MMC card to set bus width to 4 bits mode, skymedi only support 1-bit + // set CMD6 argument Access field to 3, Index to 183, Value to 1 (4-bit mode) +// arg = (3 << 24) | (183 << 16) | (1 << 8); +// if ((status = eMMC_CmdAndRsp(pSD, 6, arg, 0)) != 0) +// return status; +// eMMC_CheckRB(); + +// outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL)| FMI_EMMCCTL_DBW_Msk); + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) & ~FMI_EMMCCTL_DBW_Msk); + } + + if ((status = eMMC_CmdAndRsp(pSD, 16, FMI_BLOCK_SIZE, 0)) != 0) // set block length + return status; + outpw(REG_FMI_EMMCBLEN, FMI_BLOCK_SIZE - 1); // set the block size + + eMMC_Command(pSD, 7, 0); + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk); + + outpw(REG_FMI_EMMCINTEN, inpw(REG_FMI_EMMCINTEN) | FMI_EMMCINTEN_BLKDIEN_Msk); + + return 0; +} + +void eMMC_Get_info(EMMC_INFO_T *pSD) +{ + unsigned int R_LEN, C_Size, MULT, size; + unsigned int Buffer[4]; + unsigned char *ptr; + + eMMC_CmdAndRsp2(pSD, 9, pSD->RCA, Buffer); + + if ((pSD->CardType == EMMC_TYPE_MMC) || (pSD->CardType == EMMC_TYPE_EMMC)) + { + // for MMC/eMMC card + if ((Buffer[0] & 0xc0000000) == 0xc0000000) + { + // CSD_STRUCTURE [127:126] is 3 + // CSD version depend on EXT_CSD register in eMMC v4.4 for card size > 2GB + eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0); + + ptr = (unsigned char *)((unsigned int)_fmi_uceMMCBuffer); + outpw(REG_FMI_DMASA, (unsigned int)ptr); // set DMA transfer starting address + outpw(REG_FMI_EMMCBLEN, 511); // read 512 bytes for EXT_CSD + + if (eMMC_CmdAndRspDataIn(pSD, 8, 0x00) != 0) + return; + + eMMC_Command(pSD, 7, 0); + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk); + + pSD->totalSectorN = (*(unsigned int *)(ptr + 212)); + pSD->diskSize = pSD->totalSectorN / 2; + } + else + { + // CSD version v1.0/1.1/1.2 in eMMC v4.4 spec for card size <= 2GB + R_LEN = (Buffer[1] & 0x000f0000) >> 16; + C_Size = ((Buffer[1] & 0x000003ff) << 2) | ((Buffer[2] & 0xc0000000) >> 30); + MULT = (Buffer[2] & 0x00038000) >> 15; + size = (C_Size + 1) * (1 << (MULT + 2)) * (1 << R_LEN); + + pSD->diskSize = size / 1024; + pSD->totalSectorN = size / 512; + } + } + else + { + if (Buffer[0] & 0xc0000000) + { + C_Size = ((Buffer[1] & 0x0000003f) << 16) | ((Buffer[2] & 0xffff0000) >> 16); + size = (C_Size + 1) * 512; // Kbytes + + pSD->diskSize = size; + pSD->totalSectorN = size << 1; + } + else + { + R_LEN = (Buffer[1] & 0x000f0000) >> 16; + C_Size = ((Buffer[1] & 0x000003ff) << 2) | ((Buffer[2] & 0xc0000000) >> 30); + MULT = (Buffer[2] & 0x00038000) >> 15; + size = (C_Size + 1) * (1 << (MULT + 2)) * (1 << R_LEN); + + pSD->diskSize = size / 1024; + pSD->totalSectorN = size / 512; + } + } + pSD->sectorSize = 512; + //sysprintf("The size is %d KB\n", pSD->diskSize); +} + +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief This function use to tell FMI eMMC engine clock. + * + * @param[in] u32Clock Set current eMMC engine clock + * + * @return None + */ +void FMI_SetReferenceClock(unsigned int u32Clock) +{ + gFMIReferenceClock = u32Clock; // kHz +} + +/** + * @brief This function use to reset FMI eMMC function. + * + * @return None + */ +void eMMC_Open(void) +{ + // enable DMAC + outpw(REG_FMI_DMACTL, FMI_DMACTL_DMARST_Msk); + while (inpw(REG_FMI_DMACTL) & FMI_DMACTL_DMARST_Msk); + + outpw(REG_FMI_DMACTL, FMI_DMACTL_DMAEN_Msk); + + //Reset Global + outpw(REG_FMI_CTL, FMI_CTL_CTLRST_Msk); + while (inpw(REG_FMI_CTL) & FMI_CTL_CTLRST_Msk); + + // enable eMMC + outpw(REG_FMI_CTL, FMI_CTL_EMMCEN_Msk); + + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CTLRST_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CTLRST_Msk); + + memset(&eMMC, 0, sizeof(EMMC_INFO_T)); + eMMC.IsCardInsert = 1; +} + +/** + * @brief This function use to initial eMMC card. + * + * @return None + */ +void eMMC_Probe(void) +{ + // Disable FMI interrupt + outpw(REG_FMI_INTEN, 0); + + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) & ~(FMI_EMMCCTL_SDNWR_Msk | FMI_EMMCCTL_BLKCNT_Msk | FMI_EMMCCTL_DBW_Msk)); + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | (0x09 << FMI_EMMCCTL_SDNWR_Pos) | (0x01 << FMI_EMMCCTL_BLKCNT_Pos)); + + if (eMMC_Init(&eMMC) < 0) + return; + + /* divider */ + if ((eMMC.CardType == EMMC_TYPE_MMC) || (eMMC.CardType == EMMC_TYPE_EMMC)) + eMMC_Set_clock(MMC_FREQ); + else + eMMC_Set_clock(SD_FREQ); + + eMMC_Get_info(&eMMC); + + if (eMMC_SelectCardType(&eMMC)) + return; + + emmc_ok = 1; +} + +/** + * @brief This function use to read data from eMMC card. + * + * @param[out] pu8BufAddr The buffer to receive the data from eMMC card. + * @param[in] u32StartSec The start read sector address. + * @param[in] u32SecCount The the read sector number of data + * + * @return None + */ +unsigned int eMMC_Read(unsigned char *pu8BufAddr, unsigned int u32StartSec, unsigned int u32SecCount) +{ + char volatile bIsSendCmd = FALSE; + unsigned int volatile reg; + int volatile i, loop, status; + unsigned int blksize = FMI_BLOCK_SIZE; + + EMMC_INFO_T *pSD; + pSD = &eMMC; + + //--- check input parameters + if (u32SecCount == 0) + return EMMC_SELECT_ERROR; + + if ((status = eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0)) != 0) + return status; + eMMC_CheckRB(); + + outpw(REG_FMI_EMMCBLEN, blksize - 1); // the actual byte count is equal to (BLEN+1) + + if ((pSD->CardType == EMMC_TYPE_SD_HIGH) || (pSD->CardType == EMMC_TYPE_EMMC)) + outpw(REG_FMI_EMMCCMD, u32StartSec); + else + outpw(REG_FMI_EMMCCMD, u32StartSec * blksize); + + outpw(REG_FMI_DMASA, (unsigned int)pu8BufAddr); + + loop = u32SecCount / 255; + for (i = 0; i < loop; i++) + { + _fmi_eMMCDataReady = FALSE; + + reg = inpw(REG_FMI_EMMCCTL) & ~FMI_EMMCCTL_CMDCODE_Msk; + reg = reg | 0xff0000; + if (bIsSendCmd == FALSE) + { + outpw(REG_FMI_EMMCCTL, reg | (18 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DIEN_Msk)); + bIsSendCmd = TRUE; + } + else + outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DIEN_Msk); + + while (!_fmi_eMMCDataReady) + { +// if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DIEN_Msk))) { +// outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk); +// break; +// } + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)) // check CRC7 + { + return EMMC_CRC7_ERROR; + } + + if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC16_Msk)) // check CRC16 + { + return EMMC_CRC16_ERROR; + } + } + + loop = u32SecCount % 255; + if (loop != 0) + { + _fmi_eMMCDataReady = FALSE; + + reg = inpw(REG_FMI_EMMCCTL) & (~FMI_EMMCCTL_CMDCODE_Msk); + reg = reg & (~FMI_EMMCCTL_BLKCNT_Msk); + reg |= (loop << 16); + + if (bIsSendCmd == FALSE) + { + outpw(REG_FMI_EMMCCTL, reg | (18 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DIEN_Msk)); + bIsSendCmd = TRUE; + } + else + outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DIEN_Msk); + + while (!_fmi_eMMCDataReady) + { +// if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DIEN_Msk))) { +// outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk); +// break; +// } + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC7_Msk)) // check CRC7 + { + return EMMC_CRC7_ERROR; + } + + if (!(inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRC16_Msk)) // check CRC16 + { + return EMMC_CRC16_ERROR; + } + } + + if (eMMC_CmdAndRsp(pSD, 12, 0, 0)) // stop command + { + //sysprintf("stop command fail !!\n"); + return EMMC_CRC7_ERROR; + } + eMMC_CheckRB(); + + eMMC_Command(pSD, 7, 0); + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk); + + return 0; +} + + +/** + * @brief This function use to write data to eMMC card. + * + * @param[in] pu8BufAddr The buffer to send the data to SD card. + * @param[in] u32StartSec The start write sector address. + * @param[in] u32SecCount The the write sector number of data. + * + * @return - \ref EMMC_SELECT_ERROR u32SecCount is zero. + * - \ref EMMC_NO_CARD SD card be removed. + * - \ref EMMC_CRC_ERROR CRC error happen. + * - \ref EMMC_CRC7_ERROR CRC7 error happen. + * - \ref Successful Write data to eMMC card success. + */ +unsigned int eMMC_Write(unsigned char *pu8BufAddr, unsigned int u32StartSec, unsigned int u32SecCount) +{ + char volatile bIsSendCmd = FALSE; + unsigned int volatile reg; + int volatile i, loop, status; + + EMMC_INFO_T *pSD; + pSD = &eMMC; + + //--- check input parameters + if (u32SecCount == 0) + return EMMC_SELECT_ERROR; + + if ((status = eMMC_CmdAndRsp(pSD, 7, pSD->RCA, 0)) != 0) + return status; + + eMMC_CheckRB(); + + // According to SD Spec v2.0/ eMMC v4.4, the write CMD block size MUST be 512, and the start address MUST be 512*n. + outpw(REG_FMI_EMMCBLEN, FMI_BLOCK_SIZE - 1); // set the block size + + if ((pSD->CardType == EMMC_TYPE_SD_HIGH) || (pSD->CardType == EMMC_TYPE_EMMC)) + outpw(REG_FMI_EMMCCMD, u32StartSec); + else + outpw(REG_FMI_EMMCCMD, u32StartSec * FMI_BLOCK_SIZE); // set start address for CMD + + outpw(REG_FMI_DMASA, (unsigned int)pu8BufAddr); + loop = u32SecCount / 255; // the maximum block count is 0xFF=255 + for (i = 0; i < loop; i++) + { + _fmi_eMMCDataReady = FALSE; + + reg = inpw(REG_FMI_EMMCCTL) & 0xff00c080; + reg = reg | 0xff0000; + if (!bIsSendCmd) + { + outpw(REG_FMI_EMMCCTL, reg | (25 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DOEN_Msk)); + bIsSendCmd = TRUE; + } + else + outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DOEN_Msk); + + while (!_fmi_eMMCDataReady) + { +// if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DOEN_Msk))) { +// outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk); +// break; +// } + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRCIF_Msk) != 0) // check CRC + { + outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk); + return EMMC_CRC_ERROR; + } + } + + loop = u32SecCount % 255; + if (loop != 0) + { + _fmi_eMMCDataReady = FALSE; + + reg = (inpw(REG_FMI_EMMCCTL) & 0xff00c080) | (loop << 16); + if (!bIsSendCmd) + { + outpw(REG_FMI_EMMCCTL, reg | (25 << 8) | (FMI_EMMCCTL_COEN_Msk | FMI_EMMCCTL_RIEN_Msk | FMI_EMMCCTL_DOEN_Msk)); + bIsSendCmd = TRUE; + } + else + outpw(REG_FMI_EMMCCTL, reg | FMI_EMMCCTL_DOEN_Msk); + + while (!_fmi_eMMCDataReady) + { +// if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_BLKDIF_Msk) && (!(inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_DOEN_Msk))) { +// outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_BLKDIF_Msk); +// break; +// } + if (pSD->IsCardInsert == FALSE) + return EMMC_NO_CARD; + } + + if ((inpw(REG_FMI_EMMCINTSTS) & FMI_EMMCINTSTS_CRCIF_Msk) != 0) // check CRC + { + outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk); + return EMMC_CRC_ERROR; + } + } + outpw(REG_FMI_EMMCINTSTS, FMI_EMMCINTSTS_CRCIF_Msk); + + if (eMMC_CmdAndRsp(pSD, 12, 0, 0)) // stop command + { + return EMMC_CRC7_ERROR; + } + eMMC_CheckRB(); + + eMMC_Command(pSD, 7, 0); + outpw(REG_FMI_EMMCCTL, inpw(REG_FMI_EMMCCTL) | FMI_EMMCCTL_CLK8OEN_Msk); + while (inpw(REG_FMI_EMMCCTL) & FMI_EMMCCTL_CLK8OEN_Msk); + + return 0; +} + + +/*@}*/ /* end of group N9H30_FMI_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_FMI_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_gpio.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..3d4fd76105ccd0ba107028ece391d517f909659d --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_gpio.c @@ -0,0 +1,500 @@ +/**************************************************************************//** +* @file gpio.c +* @version V1.00 +* @brief N9H30 GPIO driver source file +* +* SPDX-License-Identifier: Apache-2.0 +* @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_gpio.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_GPIO_Driver GPIO Driver + @{ +*/ + +/** @addtogroup N9H30_GPIO_EXPORTED_FUNCTIONS GPIO Exported Functions + @{ +*/ + +/** + * @brief Set GPIO Port + * + * @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ + * @param[in] bitMap GPIO port. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 + * + * @retval <0 Fail + * @retval 0 Success + * + * @details This function is used to set GPIO port output data. + */ +INT32 GPIO_Set(GPIO_PORT port, UINT32 bitMap) +{ + INT32 offset; + INT32 reg; + + offset = (INT32)port; + + reg = inpw(REG_GPIOA_DATAOUT + offset); + reg = reg | bitMap; + outpw(REG_GPIOA_DATAOUT + offset, reg); + + return SUCCESSFUL; +} + +/** +* @brief Clear GPIO port OUT Data +* +* @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ +* @param[in] bitMap GPIO port data. It could be 0x00 ~ 0xFF. +* +* @retval <0 Fail +* @retval 0 Success +* +* @details Clear GPIO port output data to 0. +*/ +INT32 GPIO_Clr(GPIO_PORT port, UINT32 bitMap) +{ + INT32 offset; + INT32 reg; + + offset = (INT32)port; + + reg = inpw(REG_GPIOA_DATAOUT + offset); + reg = reg & (~bitMap); + outpw(REG_GPIOA_DATAOUT + offset, reg); + + return SUCCESSFUL; +} + + + +/** + * @brief Open GPIO bit + * + * @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ + * @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 + * @param[in] direction GPIO direction. It could be \ref DIR_INPUT or \ref DIR_OUTPUT + * @param[in] pull GPIO pull-up. It could be \ref NO_PULL_UP or \ref PULL_UP + * + * @retval <0 Fail + * @retval 0 Success + * + * @details This function is used to open gpio pin. + */ +INT32 GPIO_OpenBit(GPIO_PORT port, UINT32 bit, GPIO_DIR direction, GPIO_PULL pull) +{ + UINT32 reg; + UINT32 mask; + INT32 offset; + + offset = (INT32)port; + + mask = (UINT32)bit; + + reg = inpw(REG_GPIOA_DIR + offset); + reg = reg & (~mask); + + if (direction == DIR_OUTPUT) + { + reg = reg | mask; + } + + outpw(REG_GPIOA_DIR + offset, reg); + + reg = inpw(REG_GPIOA_PUEN + offset); + reg = reg & (~mask); + + if (pull == PULL_UP) + { + reg = reg | mask; + outpw(REG_GPIOA_PUEN + offset, reg); + } + else if (pull == PULL_DOWN) + { + reg = reg | mask; + outpw(REG_GPIOA_PDEN + offset, reg); + } + else + { + outpw(REG_GPIOA_PUEN + offset, reg); + outpw(REG_GPIOA_PDEN + offset, reg); + } + + return SUCCESSFUL; +} + +/** +* @brief Set GPIO pin OUT Data +* +* @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ +* @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 +* +* @retval <0 Fail +* @retval 0 Success +* +* @details Set the Data into specified GPIO pin. +*/ +INT32 GPIO_CloseBit(GPIO_PORT port, UINT32 bit) +{ + UINT32 reg; + UINT32 mask; + INT32 offset; + + offset = (INT32)port; + mask = (UINT32)bit; + + reg = inpw(REG_GPIOA_DIR + offset); + reg = reg & (~mask); + outpw(REG_GPIOA_DIR + offset, reg); + + reg = inpw(REG_GPIOA_PUEN + offset); + reg = reg & (~mask); + outpw(REG_GPIOA_PUEN + offset, reg); + + return SUCCESSFUL; +} + + +/** + * @brief Set GPIO pin OUT Data + * + * @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ + * @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 + * + * @retval <0 Fail + * @retval 0 Success + * + * @details Set the Data into specified GPIO pin. + */ +INT32 GPIO_SetBit(GPIO_PORT port, UINT32 bit) +{ + UINT32 bitMap; + INT32 offset; + INT32 reg; + + offset = (INT32)port; + bitMap = (UINT32)bit; + + reg = inpw(REG_GPIOA_DATAOUT + offset); + reg = reg | bitMap; + outpw(REG_GPIOA_DATAOUT + offset, reg); + + return SUCCESSFUL; +} + +/** +* @brief Clear GPIO port Interrupt Flag +* +* @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ +* @param[in] bitMap GPIO port data. It could be 0x00 ~ 0xFF. +* +* @retval <0 Fail +* @retval 0 Success +* +* @details Clear the interrupt status of specified GPIO port. +*/ +INT32 GPIO_ClrISR(GPIO_PORT port, UINT32 bitMap) +{ + INT32 offset; + + offset = (INT32)port; + + outpw(REG_GPIOA_ISR + offset, bitMap); + + return SUCCESSFUL; +} + +/** + * @brief Clear GPIO Pin Interrupt Flag + * + * @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ + * @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 + * + * @retval <0 Fail + * @retval 0 Success + * + * @details Clear the interrupt status of specified GPIO pin. + */ +INT32 GPIO_ClrISRBit(GPIO_PORT port, UINT32 bit) +{ + UINT32 bitMap; + INT32 offset; + + offset = (INT32)port; + bitMap = (UINT32)bit; + + outpw(REG_GPIOA_ISR + offset, bitMap); + + return SUCCESSFUL; +} + +/** +* @brief Clear GPIO pin OUT Data +* +* @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ +* @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 +* +* @retval <0 Fail +* @retval 0 Success +* +* @details Set the Data into specified GPIO pin. +*/ +INT32 GPIO_ClrBit(GPIO_PORT port, UINT32 bit) +{ + UINT32 bitMap; + INT32 offset; + INT32 reg; + + offset = (INT32)port; + bitMap = (UINT32)bit; + + reg = inpw(REG_GPIOA_DATAOUT + offset); + reg = reg & (~bitMap); + outpw(REG_GPIOA_DATAOUT + offset, reg); + + return SUCCESSFUL; +} + +/** +* @brief Read GPIO pin In Data +* +* @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ +* @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 +* +* @retval 1/0 GPIO pin input data. +* +* @details Read the In Data from GPIO pin. +*/ +INT32 GPIO_ReadBit(GPIO_PORT port, UINT32 bit) +{ + UINT32 reg; + UINT32 bitMap; + INT32 offset; + + offset = (INT32)port; + bitMap = (UINT32)bit; + + reg = inpw(REG_GPIOA_DATAIN + offset); + + return ((reg & bitMap) ? 1 : 0); +} + +/** +* @brief Set GPIO pin direction +* +* @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ +* @param[in] bit GPIO pin. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 +* @param[in] direction GPIO direction. It could be \ref DIR_INPUT, \ref DIR_OUTPUT. +* +* @retval <0 Fail +* @retval 0 Success +* +* @details Set the GPIO direction into specified GPIO pin. +*/ +INT32 GPIO_SetBitDir(GPIO_PORT port, UINT32 bit, GPIO_DIR direction) +{ + UINT32 reg; + UINT32 bitMap; + INT32 offset; + + offset = (INT32)port; + bitMap = (UINT32)bit; + + reg = inpw(REG_GPIOA_DIR + offset); + reg = reg & (~bitMap); + + if (direction == DIR_OUTPUT) + { + reg = reg | bitMap; + } + + outpw(REG_GPIOA_DIR + offset, reg); + + return SUCCESSFUL; +} + +/** + * @brief Enable GPIO trigger type. + * + * @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ + * @param[in] bitMap GPIO port. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 + * @param[in] triggerType The triggerType of specified GPIO pin. It could be \n + * \ref RISING, \ref FALLING, \ref BOTH_EDGE, \ref HIGH, \ref LOW. + * + * @retval <0 Fail + * @retval 0 Success + * + * @details This function is used to enable trigger type. + */ +INT32 GPIO_EnableTriggerType(GPIO_PORT port, UINT32 bitMap, GPIO_TRIGGER_TYPE triggerType) +{ + UINT32 reg; + INT32 offset; + + offset = (INT32)port; + + switch (triggerType) + { + case LOW: + reg = inpw(REG_GPIOA_IMD + offset); + outpw(REG_GPIOA_IMD + offset, reg | bitMap); + + reg = inpw(REG_GPIOA_IREN + offset); + outpw(REG_GPIOA_IREN + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IFEN + offset); + outpw(REG_GPIOA_IFEN + offset, reg | bitMap); + break; + case HIGH: + reg = inpw(REG_GPIOA_IMD + offset); + outpw(REG_GPIOA_IMD + offset, reg | bitMap); + + reg = inpw(REG_GPIOA_IREN + offset); + outpw(REG_GPIOA_IREN + offset, reg | bitMap); + + reg = inpw(REG_GPIOA_IFEN + offset); + outpw(REG_GPIOA_IFEN + offset, reg & ~bitMap); + break; + case FALLING: + reg = inpw(REG_GPIOA_IMD + offset); + outpw(REG_GPIOA_IMD + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IREN + offset); + outpw(REG_GPIOA_IREN + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IFEN + offset); + outpw(REG_GPIOA_IFEN + offset, reg | bitMap); + break; + case RISING: + reg = inpw(REG_GPIOA_IMD + offset); + outpw(REG_GPIOA_IMD + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IREN + offset); + outpw(REG_GPIOA_IREN + offset, reg | bitMap); + + reg = inpw(REG_GPIOA_IFEN + offset); + outpw(REG_GPIOA_IFEN + offset, reg & ~bitMap); + break; + case BOTH_EDGE: + reg = inpw(REG_GPIOA_IMD + offset); + outpw(REG_GPIOA_IMD + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IREN + offset); + outpw(REG_GPIOA_IREN + offset, reg | bitMap); + + reg = inpw(REG_GPIOA_IFEN + offset); + outpw(REG_GPIOA_IFEN + offset, reg | bitMap); + break; + } + return SUCCESSFUL; +} + +/** + * @brief Disable GPIO trigger type. + * + * @param[in] port GPIO port. It could be \ref GPIOA, \ref GPIOB, ... or \ref GPIOJ + * @param[in] bitMap GPIO port. It could be \ref BIT0 \ref BIT1, ... or \ref BIT31 + * + * @retval <0 Fail + * @retval 0 Success + * + * @details This function is used to disable trigger type. + */ +INT32 GPIO_DisableTriggerType(GPIO_PORT port, UINT32 bitMap) +{ + UINT32 reg; + INT32 offset; + + offset = (INT32)port; + + reg = inpw(REG_GPIOA_IMD + offset); + outpw(REG_GPIOA_IMD + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IREN + offset); + outpw(REG_GPIOA_IREN + offset, reg & ~bitMap); + + reg = inpw(REG_GPIOA_IFEN + offset); + outpw(REG_GPIOA_IFEN + offset, reg & ~bitMap); + + return SUCCESSFUL; +} + +/** + * @brief Enable GPIO De-bounce Function + * + * @param[in] debounceClkSel The de-bounce sampling cycle selection. It could be 0~0xF. \n + * 0 = Sample interrupt input once per 1 clocks. \n + * 1 = Sample interrupt input once per 2 clocks. \n + * 2 = Sample interrupt input once per 4 clocks. \n + * 3 = Sample interrupt input once per 8 clocks. \n + * 4 = Sample interrupt input once per 16 clocks. \n + * 5 = Sample interrupt input once per 32 clocks. \n + * 6 = Sample interrupt input once per 64 clocks. \n + * 7 = Sample interrupt input once per 128 clocks. \n + * 8 = Sample interrupt input once per 256 clocks. \n + * 9 = Sample interrupt input once per 2*256 clocks. \n + * 10 = Sample interrupt input once per 4*256 clocks. \n + * 11 = Sample interrupt input once per 8*256 clocks. \n + * 12 = Sample interrupt input once per 16*256 clocks. \n + * 13 = Sample interrupt input once per 32*256 clocks. \n + * 14 = Sample interrupt input once per 64*256 clocks. \n + * 15 = Sample interrupt input once per 128*256 clocks + * + * @retval <0 Fail + * @retval 0 Success + * + * @details Enable the interrupt de-bounce function of specified GPIO. + */ +INT32 GPIO_EnableDebounce(INT32 debounceClkSel) +{ + UINT32 reg; + + reg = inpw(REG_GPIO_DBNCECON); + + /* Setting the debounce timing */ + reg = ((reg & ~0xf) | debounceClkSel); + + /* Enable the debounce function */ + reg = reg | 0x20; + outpw(REG_GPIO_DBNCECON, reg); + + return SUCCESSFUL; +} + +/** + * @brief Disable GPIO De-bounce Function. + * + * @retval <0 Fail + * @retval 0 Success + * + * @details Disable the interrupt de-bounce function of specified GPIO. + */ +INT32 GPIO_DisableDebounce(void) +{ + UINT32 reg; + + reg = inpw(REG_GPIO_DBNCECON); + + /* Setting the debounce timing */ + reg = ((reg & ~0xf)); + + /* Enable the debounce function */ + reg = reg | 0x20; + outpw(REG_GPIO_DBNCECON, reg); + + return SUCCESSFUL; +} + +/*@}*/ /* end of group N9H30_GPIO_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_GPIO_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_i2s.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_i2s.c new file mode 100644 index 0000000000000000000000000000000000000000..f53870352606857f026e6ed6d176f0c25d234dfa --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_i2s.c @@ -0,0 +1,461 @@ +/**************************************************************************//** +* @file i2s.c +* @brief N9H30 I2S driver source file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include +#include +#include + +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_i2s.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_I2S_Driver I2S Driver + @{ +*/ + +/** @addtogroup N9H30_I2S_EXPORTED_CONSTANTS I2S Exported Constants + @{ +*/ + +/// @cond HIDDEN_SYMBOLS + +typedef uint32_t (AU_CB_FUNC_T)(uint32_t); + +static AU_CB_FUNC_T *g_fnPlayCallBack; +static AU_CB_FUNC_T *g_fnRecCallBack; +static uint8_t i2sOpened = 0; + +/// @endcond /* HIDDEN_SYMBOLS */ + +/*@}*/ /* end of group N9H30_I2S_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_I2S_EXPORTED_FUNCTIONS I2S Exported Functions + @{ +*/ + +/// @cond HIDDEN_SYMBOLS +/** + * @brief Start to play + * @param None + * @return None + */ +static void i2sStartPlay(void) +{ + /* start playing */ + //sysprintf("IIS start playing...\n"); + + outpw(REG_ACTL_PSR, 0x1); + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (1 << 5)); +} + +/** + * @brief Stop to play + * @param None + * @return None + */ +static void i2sStopPlay(void) +{ + //sysprintf("IIS stop playing\n"); + + /* stop playing */ + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(1 << 5)); +} + +/** + * @brief Start to record + * @param None + * @return None + */ +static void i2sStartRecord(void) +{ + /* start recording */ + //sysprintf("IIS start recording...\n"); + + outpw(REG_ACTL_RSR, 0x1); + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (1 << 6)); +} + +/** + * @brief Stop to record + * @param None + * @return None + */ +static void i2sStopRecord(void) +{ + //sysprintf("I2S stop recording\n"); + + /* stop recording */ + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(1 << 6)); +} + +/** + * @brief Delay function + * @param None + * @return None + */ +static void Delay(int nCnt) +{ + int volatile loop; + for (loop = 0; loop < nCnt * 10; loop++); +} + +/** + * @brief Interrupt service routine for i2s + * @param None + * @return None + */ +static void i2sISR(void) +{ + uint8_t u8SN; + + if (inpw(REG_ACTL_CON) & (1 << 10)) + { + outpw(REG_ACTL_CON, inpw(REG_ACTL_CON) | (1 << 10)); //Clear TX INT + + if (inpw(REG_ACTL_PSR) & (1 << 4)) + { + outpw(REG_ACTL_PSR, (1 << 4)); + //sysprintf("\ndebug:DMA_COUNTER_IRQ occur"); + } + + if (inpw(REG_ACTL_PSR) & (1 << 3)) + { + outpw(REG_ACTL_PSR, (1 << 3)); + //sysprintf("\ndebug:DMA_DATA_ZERO_IRQ occur"); + } + + if (inpw(REG_ACTL_PSR) & 0x1) + { + outpw(REG_ACTL_PSR, 0x1); + u8SN = (inpw(REG_ACTL_PSR) >> 5) & 0x7; + g_fnPlayCallBack(u8SN); + } + } + + if (inpw(REG_ACTL_CON) & (1 << 11)) + { + outpw(REG_ACTL_CON, inpw(REG_ACTL_CON) | (1 << 11)); //Clear RX INT + + if (inpw(REG_ACTL_RSR) & 0x1) + { + outpw(REG_ACTL_RSR, 0x1); + u8SN = (inpw(REG_ACTL_RSR) >> 5) & 0x7; + g_fnRecCallBack(u8SN); + } + } +} +/// @endcond /* HIDDEN_SYMBOLS */ + +/** + * @brief Open i2s interface + * @return open status + * @retval I2S_ERR_BUSY error. + * @retval 0 success. + */ +int32_t i2sOpen(void) +{ + if (i2sOpened) + return I2S_ERR_BUSY; + + /* reset audio interface */ + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (1 << 16)); + Delay(100); + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(1 << 16)); + Delay(100); + + /* reset IIS interface */ + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | 0x1); + Delay(100); + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~0x1); + Delay(100); + + outpw(REG_ACTL_CON, inpw(REG_ACTL_CON) | (1 << 21) | (1 << 20)); + + i2sOpened = 1; + + return 0; +} + +/** + * @brief Close i2s interface + * @return None + */ +void i2sClose(void) +{ + // reset some variables + i2sOpened = 0; + g_fnPlayCallBack = NULL; + g_fnRecCallBack = NULL; + + // reset i2s interface + outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) | (1 << 8)); + outpw(REG_SYS_AHBIPRST, inpw(REG_SYS_AHBIPRST) & ~(1 << 8)); +} + +/** + * @brief Initialize i2s interface and setup interrupt + * @return None + */ +void i2sInit(void) +{ + // enable i2s engine clock + outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | (1 << 24)); + + // enable interrupt and set ISR + sysSetInterruptType(ACTL_IRQn, HIGH_LEVEL_SENSITIVE); + sysInstallISR(IRQ_LEVEL_1, ACTL_IRQn, (PVOID)i2sISR); + sysEnableInterrupt(ACTL_IRQn); + sysSetLocalInterrupt(ENABLE_IRQ); +} + +/** + * @brief IO control for i2s interface + * @param[in] cmd Command for io control, value could be + * - \ref I2S_SET_PLAY + * - \ref I2S_SET_RECORD + * - \ref I2S_SELECT_BLOCK + * - \ref I2S_SELECT_BIT + * - \ref I2S_SET_PLAY_DMA_INT_SEL + * - \ref I2S_SET_REC_DMA_INT_SEL + * - \ref I2S_SET_ZEROCROSS + * - \ref I2S_SET_DMACOUNTER + * - \ref I2S_SET_CHANNEL + * - \ref I2S_SET_MODE + * - \ref I2S_SET_SPLITDATA + * - \ref I2S_SET_DMA_ADDRESS + * - \ref I2S_SET_DMA_LENGTH + * - \ref I2S_GET_DMA_CUR_ADDRESS + * - \ref I2S_SET_I2S_FORMAT + * - \ref I2S_SET_I2S_CALLBACKFUN + * - \ref I2S_SET_PCMSLOT + * @param[in] arg0 argument 0 for io control + * @param[in] arg1 argument 1 for io control + * @retval I2S_ERR_IO Command error. + * @retval 0 success. + */ +int32_t i2sIoctl(uint32_t cmd, uint32_t arg0, uint32_t arg1) +{ + uint32_t *buf; + AU_CB_FUNC_T *ptr; + + switch (cmd) + { + // #define I2S_START_PLAY 0 + // #define I2S_STOP_PLAY 1 + case I2S_SET_PLAY: + if (arg0 == I2S_START_PLAY) + i2sStartPlay(); + else + i2sStopPlay(); + break; + // #define I2S_START_REC 0 + // #define I2S_STOP_REC 1 + case I2S_SET_RECORD: + if (arg0 == I2S_START_REC) + i2sStartRecord(); + else + i2sStopRecord(); + break; + // #define I2S_BLOCK_I2S 0 + // #define I2S_BLOCK_PCM 1 + case I2S_SELECT_BLOCK: + if (arg0 == I2S_BLOCK_I2S) + outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x3) | 0x1); + else + outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x3) | 0x2); + break; + // #define I2S_BIT_WIDTH_8 0 + // #define I2S_BIT_WIDTH_16 1 + // #define I2S_BIT_WIDTH_24 2 + case I2S_SELECT_BIT: + outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x300) | (arg0 << 8)); + break; + // #define I2S_DMA_INT_END 0 + // #define I2S_DMA_INT_HALF 1 + // #define I2S_DMA_INT_QUARTER 2 + // #define I2S_DMA_INT_EIGTH 3 + case I2S_SET_PLAY_DMA_INT_SEL: + outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0x3000) | (arg0 << 12)); + break; + + case I2S_SET_REC_DMA_INT_SEL: + outpw(REG_ACTL_CON, (inpw(REG_ACTL_CON) & ~0xc000) | (arg0 << 14)); + break; + + case I2S_SET_ZEROCROSS: + if (arg0 == I2S_ENABLE) + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | 0x8); + else + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~0x8); + break; + + case I2S_SET_DMACOUNTER: + if (arg0 == I2S_ENABLE) + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | 0x10); + else + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~0x10); + break; + // #define I2S_CHANNEL_I2S_ONE 2 + // #define I2S_CHANNEL_I2S_TWO 3 + // #define I2S_CHANNEL_PCM_TWO 3 + // #define I2S_CHANNEL_PCM_TWO_SLOT1 0 + // #define I2S_CHANNEL_PCM_TWO_SLOT0 1 + // #define I2S_CHANNEL_PCM_ONE_SLOT0 2 + case I2S_SET_CHANNEL: + if (arg0 == I2S_PLAY) + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(0x3 << 12) | (arg1 << 12)); + else + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(0x3 << 14) | (arg1 << 14)); + break; + // #define I2S_MODE_MASTER 0 + // #define I2S_MODE_SLAVE 1 + case I2S_SET_MODE: + if (arg0 == I2S_MODE_MASTER) + outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) & ~(0x1 << 20)); + else + outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) | (0x1 << 20)); + break; + + case I2S_SET_SPLITDATA: + if (arg0 == I2S_ENABLE) + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) | (0x1 << 20)); + else + outpw(REG_ACTL_RESET, inpw(REG_ACTL_RESET) & ~(0x1 << 20)); + break; + + case I2S_SET_DMA_ADDRESS: + if (arg0 == I2S_PLAY) + outpw(REG_ACTL_PDESB, arg1 | 0x80000000); + else if (arg0 == I2S_REC) + outpw(REG_ACTL_RDESB, arg1 | 0x80000000); + else if (arg0 == PCM_PLAY) + outpw(REG_ACTL_PDESB2, arg1 | 0x80000000); + else + outpw(REG_ACTL_RDESB2, arg1 | 0x80000000); + break; + + case I2S_SET_DMA_LENGTH: + if (arg0 == I2S_PLAY) + outpw(REG_ACTL_PDES_LENGTH, arg1); + else + outpw(REG_ACTL_RDES_LENGTH, arg1); + break; + + case I2S_GET_DMA_CUR_ADDRESS: + buf = (uint32_t *)arg0; + if (arg0 == I2S_PLAY) + *buf = inpw(REG_ACTL_PDESC); + else + *buf = inpw(REG_ACTL_RDESC); + break; + + // #define I2S_FORMAT_I2S 0 + // #define I2S_FORMAT_MSB 1 + case I2S_SET_I2S_FORMAT: + if (arg0 == I2S_FORMAT_I2S) + outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) & ~ 0x8); + else + outpw(REG_ACTL_I2SCON, inpw(REG_ACTL_I2SCON) | 0x8); + break; + + case I2S_SET_I2S_CALLBACKFUN: + ptr = (AU_CB_FUNC_T *)arg1; + if (arg0 == I2S_PLAY) + g_fnPlayCallBack = ptr; + else + g_fnRecCallBack = ptr; + break; + // #define PCM_SLOT1_IN 0 + // #define PCM_SLOT1_OUT 1 + // #define PCM_SLOT2_IN 2 + // #define PCM_SLOT2_OUT 3 + case I2S_SET_PCMSLOT: + if (arg0 == PCM_SLOT1_IN) + outpw(REG_ACTL_PCMS1ST, (inpw(REG_ACTL_PCMS1ST) & ~0x3ff) | (arg1 & 0x3ff)); + else if (arg0 == PCM_SLOT1_OUT) + outpw(REG_ACTL_PCMS1ST, (inpw(REG_ACTL_PCMS1ST) & ~0x3ff0000) | ((arg1 & 0x3ff) << 16)); + else if (arg0 == PCM_SLOT2_IN) + outpw(REG_ACTL_PCMS2ST, (inpw(REG_ACTL_PCMS2ST) & ~0x3ff) | (arg1 & 0x3ff)); + else + outpw(REG_ACTL_PCMS2ST, (inpw(REG_ACTL_PCMS2ST) & ~0x3ff0000) | ((arg1 & 0x3ff) << 16)); + break; + + case I2S_SET_PCM_FS_PERIOD: + outpw(REG_ACTL_PCMCON, (inpw(REG_ACTL_PCMCON) & ~0x03FF0000 | (((arg0 - 1) & 0x3ff) << 16))); + break; + + default: + return I2S_ERR_IO; + } + return 0; +} + +/** + * @brief Configure sampling rate for audio + * @param[in] u32SourceClockRate source speed to i2s interface + * @param[in] u32SampleRate sampling rate + * @param[in] u32DataBit data width + * @param[in] u32Channel channel number + * @return None + */ +void i2sSetSampleRate(uint32_t u32SourceClockRate, uint32_t u32SampleRate, uint32_t u32DataBit, uint32_t u32Channel) +{ + uint32_t u32BCLKDiv; + uint32_t u32MCLK, u32MCLKDiv; + + u32MCLK = (u32SampleRate * 256); + u32MCLKDiv = u32SourceClockRate / u32MCLK; + outpw(REG_ACTL_I2SCON, (inpw(REG_ACTL_I2SCON) & ~0x000F0000) | (u32MCLKDiv - 1) << 16); + + u32BCLKDiv = u32MCLK / (u32SampleRate * u32DataBit * u32Channel); + u32BCLKDiv = u32BCLKDiv / 2 - 1; + outpw(REG_ACTL_I2SCON, (inpw(REG_ACTL_I2SCON) & ~0xF0) | u32BCLKDiv << 5); +} + +/** + * @brief Configure MCLK frequency (master mode) + * @param[in] u32SourceClockRate source clock rate + * @param[in] u32SampleRate sampling rate + * @return None + */ +void i2sSetMCLKFrequency(uint32_t u32SourceClockRate, uint32_t u32SampleRate) +{ + uint32_t u32MCLK, u32MCLKDiv; + + u32MCLK = (u32SampleRate * 256); + u32MCLKDiv = u32SourceClockRate / u32MCLK; + outpw(REG_ACTL_I2SCON, (inpw(REG_ACTL_I2SCON) & ~0x000F0000) | (u32MCLKDiv - 1) << 16); +} + +/** + * @brief Configure PCM BCLK frequency (master mode) + * @param[in] u32SourceClockRate source clock rate + * @param[in] u32Rate target rate + * @return None + */ +void i2sSetPCMBCLKFrequency(uint32_t u32SourceClockRate, uint32_t u32Rate) +{ + uint32_t u32BCLKDiv; + + u32BCLKDiv = (u32SourceClockRate / (2 * u32Rate)) - 1; + outpw(REG_ACTL_PCMCON, (inpw(REG_ACTL_PCMCON) & ~0x0000FF00) | (u32BCLKDiv << 8)); +} + + +/*@}*/ /* end of group N9H30_I2S_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_I2S_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_lcd.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_lcd.c new file mode 100644 index 0000000000000000000000000000000000000000..138641f00254643f0e8f8cd70db13df291c7fcff --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_lcd.c @@ -0,0 +1,764 @@ +/**************************************************************************//** +* @file lcd.c +* @brief N9H30 LCD driver source file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include +#include +#include +#include + +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_lcd.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_LCD_Driver LCD Driver + @{ +*/ + +/** @addtogroup N9H30_LCD_EXPORTED_CONSTANTS LCD Exported Constants + @{ +*/ + +/// @cond HIDDEN_SYMBOLS + +/* LCD attributes */ +static VPOST_T DEF_E50A2V1 = +{ + 800, /*!< Panel width */ + 480, /*!< Panel height */ + 0, /*!< MPU command line low indicator */ + 0, /*!< MPU command width */ + 0, /*!< MPU bus width */ + VPOSTB_DATA16or18, /*!< Display bus width */ + 0, /*!< MPU mode */ + VPOSTB_COLORTYPE_64K, /*!< Display colors */ + VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */ + 0x020d03a0, /*!< CRTCSIZE register value */ + 0x01e00320, /*!< CRTCDEND register value */ + 0x03250321, /*!< CRTCHR register value */ + 0x03780348, /*!< CRTCHSYNC register value */ + 0x01f001ed /*!< CRTCVR register value */ +}; + +static VPOST_T DEF_ILI9341_MPU80 = +{ + 240, /*!< Panel width */ + 320, /*!< Panel height */ + VPOSTB_CMDLOW, /*!< MPU command line low indicator */ + VPOSTB_CM16t18HIGH, /*!< MPU command width */ + VPOSTB_CMD8, /*!< MPU bus width */ + VPOSTB_DATA16or18, /*!< Display bus width */ + VPOSTB_MPU80, /*!< MPU mode */ + VPOSTB_COLORTYPE_64K, /*!< Display colors */ + VPOSTB_DEVICE_MPU, /*!< Type of display panel */ + 0x01600100, /*!< CRTCSIZE register value */ + 0x014000F0, /*!< CRTCDEND register value */ + 0x00FA00F5, /*!< CRTCHR register value */ + 0x00FC00FA, /*!< CRTCHSYNC register value */ + 0x01500145 /*!< CRTCVR register value */ +}; + +static VPOST_T DEF_LSA40AT9001 = +{ + 800, /*!< Panel width */ + 600, /*!< Panel height */ + 0, /*!< MPU command line low indicator */ + 0, /*!< MPU command width */ + 0, /*!< MPU bus width */ + VPOSTB_DATA16or18, /*!< Display bus width */ + 0, /*!< MPU mode */ + VPOSTB_COLORTYPE_64K, /*!< Display colors */ + VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */ + 0x02800425, /*!< CRTCSIZE register value */ + 0x02580320, /*!< CRTCDEND register value */ + 0x032F032A, /*!< CRTCHR register value */ + 0x0334032A, /*!< CRTCHSYNC register value */ + 0x026C0262 /*!< CRTCVR register value */ +}; + + +static VPOST_T DEF_FW070TFT = +{ + 800, /*!< Panel width */ + 480, /*!< Panel height */ + 0, /*!< MPU command line low indicator */ + 0, /*!< MPU command width */ + 0, /*!< MPU bus width */ + VPOSTB_DATA16or18, /*!< Display bus width */ + 0, /*!< MPU mode */ + VPOSTB_COLORTYPE_16M, /*!< Display colors */ + VPOSTB_DEVICE_SYNC_HIGHCOLOR, /*!< Type of display panel */ + 0x020d0420, /*!< CRTCSIZE register value */ + 0x01e00320, /*!< CRTCDEND register value */ + 0x033e0339, /*!< CRTCHR register value */ + 0x040c03f8, /*!< CRTCHSYNC register value */ + 0x020001f6 /*!< CRTCVR register value */ +}; + +/* LCD build-in support list */ +static VPOST_T *DisplayDevList[4] = {&DEF_E50A2V1, &DEF_ILI9341_MPU80, &DEF_LSA40AT9001, &DEF_FW070TFT}; +static VPOST_T curDisplayDev; +static OSDFORMATEX curOSDDev = {0}; +static LCDFORMATEX curVADev = {0}; + +/// @endcond /* HIDDEN_SYMBOLS */ + +/*@}*/ /* end of group N9H30_I2C_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_LCD_EXPORTED_FUNCTIONS LCD Exported Functions + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +/* For align 32 */ +static uint32_t shift_pointer(uint32_t ptr, uint32_t align) +{ + uint32_t alignedPTR; + uint32_t remain; + + //printf("pointer position is %x\n",ptr); + if ((ptr % align) != 0) + { + remain = ptr % align; + alignedPTR = ptr + (align - remain); + return alignedPTR; + } + return ptr; +} + +/// @endcond /* HIDDEN_SYMBOLS */ + +/** + * @brief Configure attributes of LCD panel,install interrupt handler and enable LCD engine clock + * @param[in] u32DisplayPanelID is panel id to configure. + * @return none + */ +void vpostLCMInit(uint32_t u32DisplayPanelID) +{ + // enable lcd engine clock + outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | (1 << 25)); + + memset((void *)&curDisplayDev, 0, sizeof(curDisplayDev)); + memcpy((void *)&curDisplayDev, DisplayDevList[u32DisplayPanelID], sizeof(curDisplayDev)); + + outpw(REG_LCM_DEV_CTRL, curDisplayDev.u32CmdLow + | curDisplayDev.u32Cmd16t18 + | curDisplayDev.u32CmdBusWidth + | curDisplayDev.u32DataBusWidth + | curDisplayDev.u32MPU_Mode + | curDisplayDev.u32DisplayColors + | curDisplayDev.u32DevType); + + outpw(REG_LCM_CRTC_SIZE, curDisplayDev.u32Reg_CRTCSIZE); + outpw(REG_LCM_CRTC_DEND, curDisplayDev.u32Reg_CRTCDEND); + outpw(REG_LCM_CRTC_HR, curDisplayDev.u32Reg_CRTCHR); + outpw(REG_LCM_CRTC_HSYNC, curDisplayDev.u32Reg_CRTCHSYNC); + outpw(REG_LCM_CRTC_VR, curDisplayDev.u32Reg_CRTCVR); + +} + +/** + * @brief Query LCM capacity and configuration by ID + * @param[in] u32DisplayPanelID is panel id to configure. + * @return LCM instance + */ +VPOST_T *vpostLCMGetInstance(uint32_t u32DisplayPanelID) +{ + if (u32DisplayPanelID > (sizeof(DisplayDevList) / sizeof(VPOST_T *))) + return NULL; + + return DisplayDevList[u32DisplayPanelID]; +} + +/** + * @brief Disable LCD engine + * @param none + * @return none + */ +void vpostLCMDeinit(void) +{ + // disable lcd engine clock + outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) & ~(1 << 25)); + + //sysDisableInterrupt(LCD_IRQn); +} + +/** + * @brief Get the pointer of frame buffer + * @param none + * @return pointer of frame buffer + * @retval NULL fail. + * @note before calling this function, display width, height and source format must be set first. + */ +uint8_t *vpostGetFrameBuffer(void) +{ + uint8_t *u8BufPtr; + uint8_t u32BytePerPixel; + + if ((curDisplayDev.u32DevWidth == 0) || (curDisplayDev.u32DevHeight == 0)) + return NULL; + + switch (curVADev.ucVASrcFormat) + { + case VA_SRC_YUV422: + case VA_SRC_YCBCR422: + case VA_SRC_RGB565: + u32BytePerPixel = 2; + break; + + case VA_SRC_RGB666: + case VA_SRC_RGB888: + u32BytePerPixel = 4; + break; + + default: + u32BytePerPixel = 2; + } + + u8BufPtr = (uint8_t *)malloc((curDisplayDev.u32DevWidth * curDisplayDev.u32DevHeight * u32BytePerPixel) + 32); + if (u8BufPtr == NULL) + return NULL; + u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32); + + outpw(REG_LCM_VA_BADDR0, (uint32_t)((uint32_t)u8BufPtr | 0x80000000)); + outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~(1 << 30) & ~VPOSTB_DB_EN); + + return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000); +} + + +/** + * @brief Get the pointer of frame buffer + * @param[in] u32Cnt is the frame buffer count to allocate. Min value is 1. + * @return pointer of frame buffer + * @retval NULL fail. + * @note before calling this function, display width, height and source format must be set first. + */ +uint8_t *vpostGetMultiFrameBuffer(uint32_t u32Cnt) +{ + uint8_t *u8BufPtr; + uint8_t u32BytePerPixel; + + if ((curDisplayDev.u32DevWidth == 0) || (curDisplayDev.u32DevHeight == 0) || (u32Cnt == 0)) + return NULL; + + switch (curVADev.ucVASrcFormat) + { + case VA_SRC_YUV422: + case VA_SRC_YCBCR422: + case VA_SRC_RGB565: + u32BytePerPixel = 2; + break; + + case VA_SRC_RGB666: + case VA_SRC_RGB888: + u32BytePerPixel = 4; + break; + + default: + u32BytePerPixel = 2; + } + + u8BufPtr = (uint8_t *)malloc((curDisplayDev.u32DevWidth * curDisplayDev.u32DevHeight * u32BytePerPixel) * u32Cnt + 32); + if (u8BufPtr == NULL) + return NULL; + u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32); + + outpw(REG_LCM_VA_BADDR0, (uint32_t)((uint32_t)u8BufPtr | 0x80000000)); + outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~(1 << 30) & ~VPOSTB_DB_EN); + + return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000); +} + +/** + * @brief Set active display window + * @param[in] u16StartY is y start position + * @param[in] u16EndY is y end position + * @param[in] u8BGColorR is background R color + * @param[in] u8BGColorG is background G color + * @param[in] u8BGColorB is background B color + * @return none + */ +void vpostSetActiveWindow(uint16_t u16StartY, uint16_t u16EndY, uint8_t u8BGColorR, uint8_t u8BGColorG, uint8_t u8BGColorB) +{ + outpw(REG_LCM_VA_WIN, (u16StartY << 16) | u16EndY); + outpw(REG_LCM_VA_STUFF, (u8BGColorR << 16) | (u8BGColorG << 8) | u8BGColorB); +} + +/** + * @brief Configure LCD display mode + * @param[in] u8DisplayMode is display mode, value could be + * - \ref VPOST_DISPLAY_SINGLE + * - \ref VPOST_DISPLAY_CONTINUOUS + * @return none + */ +void vpostSetDisplayMode(uint8_t u8DisplayMode) +{ + if (u8DisplayMode == 0) + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(1 << 7)); //clear setting + else + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | (u8DisplayMode) << 7); +} + +/** + * @brief Configure display attributes of video interface, + * @param[in] u32VASrcType is display type, value could be + * - \ref VA_SRC_YUV422 + * - \ref VA_SRC_YCBCR422 + * - \ref VA_SRC_RGB888 + * - \ref VA_SRC_RGB666 + * - \ref VA_SRC_RGB565 + * - \ref VA_SRC_RGB444_LOW + * - \ref VA_SRC_RGB444_HIGH + * @return none + */ +void vpostSetVASrc(uint32_t u32VASrcType) +{ + uint32_t u32BytePerPixel, VA_FF, VA_Sride; + + curVADev.ucVASrcFormat = u32VASrcType; + + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(7 << 8)); + if (u32VASrcType != 0) + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | u32VASrcType); + else + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(7 << 8)); + + if ((u32VASrcType == VA_SRC_RGB888) || (u32VASrcType == VA_SRC_RGB666)) + outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~0x7ff07ff | (curDisplayDev.u32DevWidth << 16) | curDisplayDev.u32DevWidth); + else + outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~0x7ff07ff | ((curDisplayDev.u32DevWidth / 2) << 16) | (curDisplayDev.u32DevWidth / 2)); + + switch (u32VASrcType) + { + case VA_SRC_YUV422: + case VA_SRC_YCBCR422: + case VA_SRC_RGB565: + u32BytePerPixel = 2; + break; + + case VA_SRC_RGB666: + case VA_SRC_RGB888: + u32BytePerPixel = 4; + break; + + default: + u32BytePerPixel = 2; + } + + /* set video stream frame buffer control */ + VA_FF = curDisplayDev.u32DevWidth * u32BytePerPixel / 4; + VA_Sride = curDisplayDev.u32DevWidth * u32BytePerPixel / 4; + outpw(REG_LCM_VA_FBCTRL, inpw(REG_LCM_VA_FBCTRL) & ~0x7ff07ff | (VA_FF << 16) | VA_Sride); +} + +/** + * @brief Start to display + * @param none + * @return none + */ +void vpostVAStartTrigger(void) +{ + if ((inpw(REG_LCM_DCCS) & VPOSTB_SINGLE) == VPOSTB_SINGLE) + while ((inpw(REG_LCM_DCCS) & VPOSTB_VA_EN) == VPOSTB_VA_EN); //wait VA_EN low + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_DISP_OUT_EN); //display_out-enable + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_VA_EN); //va-enable +} + +/** + * @brief Stop to display + * @param none + * @return none + */ +void vpostVAStopTrigger(void) +{ + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(VPOSTB_DISP_OUT_EN | VPOSTB_VA_EN)); //OSD disable +} + +/** + * @brief Configure LCD scaling attribute + * @param[in] u8HIntegral is horizontal integral + * @param[in] u16HDecimal is horizontal decimal + * @param[in] u8VIntegral is vertical integral + * @param[in] u16VDecimal is vertical decimal + * @param[in] u32Mode is scale mode, value could be + * - \ref VA_SCALE_INTERPOLATION + * - \ref VA_SCALE_DUPLICATION + * @return none + */ +void vpostVAScalingCtrl(uint8_t u8HIntegral, uint16_t u16HDecimal, uint8_t u8VIntegral, uint16_t u16VDecimal, uint32_t u32Mode) +{ + outpw(REG_LCM_VA_SCALE, ((((uint32_t)u8VIntegral << 10) + ((uint32_t)ceil((double)1024 / 10)*u16VDecimal)) << 16) + | (((uint32_t)u8HIntegral << 10) + ((uint32_t)ceil((double)1024 / 10)*u16HDecimal)) | u32Mode); +} + +/** + * @brief Set OSD color key + * @param[in] u8CKeyColorR is color key R color + * @param[in] u8CKeyColorG is color key G color + * @param[in] u8CKeyColorB is color key B color + * @return none + */ +void vpostOSDSetColKey(uint8_t u8CKeyColorR, uint8_t u8CKeyColorG, uint8_t u8CKeyColorB) +{ + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & ~(VPOSTB_BLI_ON | VPOSTB_CKEY_ON)); //blinking disable, color-key disable + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | VPOSTB_CKEY_ON);//color-key enable + outpw(REG_LCM_OSD_CKEY, ((uint32_t)(u8CKeyColorR << 16) | (uint32_t)(u8CKeyColorG << 8) | u8CKeyColorB)); +} + +/** + * @brief Set OSD color mask, OSD data only will be displayed if the mask bit is set as 1. + * @param[in] u8MaskColorR is color key R color + * @param[in] u8MaskColorG is color key G color + * @param[in] u8MaskColorB is color key B color + * @return none + */ +void vpostOSDSetColMask(uint8_t u8MaskColorR, uint8_t u8MaskColorG, uint8_t u8MaskColorB) +{ + outpw(REG_LCM_OSD_CMASK, ((u8MaskColorR << 16) | (u8MaskColorG << 8) | u8MaskColorB)); +} + +/** + * @brief Set OSD blinking function + * @param[in] u8OSDBlinkVcnt is blinking cycle time, unit is VSync + * @return none + */ +void vpostOSDSetBlinking(uint8_t u8OSDBlinkVcnt) +{ + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & ~(VPOSTB_BLI_ON | VPOSTB_CKEY_ON)); //blinking disable, color-key disable + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | VPOSTB_BLI_ON); + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | ((uint32_t)(u8OSDBlinkVcnt) << 16)); +} + +/** + * @brief Disable OSD blinking function + * @param none + * @return none + */ +void vpostOSDDisableBlinking(void) +{ + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & ~ VPOSTB_BLI_ON); +} + +/** + * @brief Configure display attributes of OSD + * @param[in] u32OSDSrcType is display type, value could be + * - \ref OSD_SRC_YUV422 + * - \ref OSD_SRC_YCBCR422 + * - \ref OSD_SRC_RGB888 + * - \ref OSD_SRC_RGB666 + * - \ref OSD_SRC_RGB565 + * - \ref OSD_SRC_RGB444_LOW + * - \ref OSD_SRC_RGB444_HIGH + * - \ref OSD_SRC_RGB332 + * @return none + */ +void vpostSetOSDSrc(uint32_t u32OSDSrcType) +{ + uint32_t u32BytePerPixel, VA_FF, VA_Sride; + + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(7 << 12) | u32OSDSrcType); + curOSDDev.ucOSDSrcFormat = u32OSDSrcType; + + switch (u32OSDSrcType) + { + case OSD_SRC_YUV422: + case OSD_SRC_YCBCR422: + case OSD_SRC_RGB565: + u32BytePerPixel = 2; + break; + + case OSD_SRC_RGB666: + case OSD_SRC_RGB888: + u32BytePerPixel = 4; + break; + + default: + u32BytePerPixel = 2; + } + + /* set video stream frame buffer control */ + VA_FF = curOSDDev.nOSDWidth * u32BytePerPixel / 4; + VA_Sride = curOSDDev.nOSDWidth * u32BytePerPixel / 4; + outpw(REG_LCM_OSD_FBCTRL, inpw(REG_LCM_OSD_FBCTRL) & ~0x7ff07ff | (VA_FF << 16) | VA_Sride); +} + +/** + * @brief Get the pointer of OSD frame buffer + * @param none + * @return pointer of OSD frame buffer + * @retval NULL fail. + * @note Must call \ref vpostOSDSetWindow and \ref vpostSetOSDSrc before calling this function + */ +uint8_t *vpostGetOSDBuffer(void) +{ + uint32_t u32BytePerPixel; + uint8_t *u8BufPtr; + + if ((curOSDDev.nOSDWidth == 0) || (curOSDDev.nOSDHeight == 0)) + { + return NULL; + } + + switch (curOSDDev.ucOSDSrcFormat) + { + case OSD_SRC_YUV422: + case OSD_SRC_YCBCR422: + case OSD_SRC_RGB565: + u32BytePerPixel = 2; + break; + + case OSD_SRC_RGB666: + case OSD_SRC_RGB888: + u32BytePerPixel = 4; + break; + + default: + u32BytePerPixel = 2; + } + + u8BufPtr = (uint8_t *)malloc((curOSDDev.nOSDWidth * curOSDDev.nOSDHeight * u32BytePerPixel) + 32); + if (u8BufPtr == NULL) + return NULL; + u8BufPtr = (uint8_t *)shift_pointer((uint32_t)u8BufPtr, 32); + + outpw(REG_LCM_OSD_BADDR, (uint32_t)((uint32_t)u8BufPtr | 0x80000000)); + + return (uint8_t *)((uint32_t)u8BufPtr | 0x80000000); +} + +/** + * @brief Enable OSD function + * @param none + * @return none + */ +void vpostOSDEnable(void) +{ + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_OSD_EN); //OSD enable +} + +/** + * @brief Disable OSD function + * @param none + * @return none + */ +void vpostOSDDisable(void) +{ + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~VPOSTB_OSD_EN); //OSD disable +} + +/** + * @brief Configure OSD scaling attribute + * @param[in] u8HIntegral is horizontal integral + * @param[in] u16HDecimal is horizontal decimal + * @param[in] u8VScall is scale mode, value could be + * - \ref VPOSTB_OSD_VUP_1X + * - \ref VPOSTB_OSD_VUP_2X + * - \ref VPOSTB_OSD_VUP_4X + * @return none + */ +void vpostOSDScalingCtrl(uint8_t u8HIntegral, uint16_t u16HDecimal, uint8_t u8VScall) +{ + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & 0xfff0ffff); //clear OSD scaling setting + if (u8VScall != 0) + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | (u8VScall << 16)); + outpw(REG_LCM_OSD_SCALE, ((uint32_t)u8HIntegral << 10) | ((uint32_t)ceil((double)1024 / 10 * u16HDecimal)) << 6); +} + +/** + * @brief Set OSD display window, including start position, width and height. + * @param[in] u32XStart is X start position + * @param[in] u32YStart is Y start position + * @param[in] u32Width is OSD display width + * @param[in] u32Height is OSD display height + * @return none + */ +void vpostOSDSetWindow(uint32_t u32XStart, uint32_t u32YStart, uint32_t u32Width, uint32_t u32Height) +{ + outpw(REG_LCM_OSD_WINS, ((u32YStart + 1) << 16) | (u32XStart + 1)); + outpw(REG_LCM_OSD_WINE, ((u32YStart + u32Height) << 16) | (u32XStart + u32Width)); + + curOSDDev.nOSDWidth = u32Width; + curOSDDev.nOSDHeight = u32Height; +} + +/** + * @brief Initialize hardware cursor function + * @param[in] u32CursorBMPBuff is pointer of hardware cursor image + * @param[in] ucMode is hardware cursor mode, value could be + * - \ref HC_MODE0 + * - \ref HC_MODE1 + * - \ref HC_MODE2 + * - \ref HC_MODE3 + * - \ref HC_MODE4 + * - \ref HC_MODE5 + * @return none + */ +void vpostHCInit(uint32_t *u32CursorBMPBuff, VA_HCMODE_E ucMode) +{ + int bpp = 2; + int BlockWidth = 32; + int bpw = 32; + + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x003f3f00 | (0x00 << 8) | (0x00 << 16)); //set TIP + if (ucMode == HC_MODE0) + { + bpp = 2; + BlockWidth = 32; + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7); //set mode 0 32X32X2bpp 4 color + + } + else if (ucMode == HC_MODE1) + { + bpp = 2; + BlockWidth = 32; + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x1); //set mode 1 32X32X2bpp 3 color and 1 transparent + } + else if (ucMode == HC_MODE2) + { + bpp = 2; + BlockWidth = 64; + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x2); //set mode 2 64X64X2bpp 4 color + } + else if (ucMode == HC_MODE3) + { + bpp = 2; + BlockWidth = 64; + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x3); //set mode 3 64X64X2bpp 3 color and 1 transparent + } + else if (ucMode == HC_MODE4) + { + bpp = 1; + BlockWidth = 128; + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x4); //set mode 4 128X128X1bpp 2 color + } + else if (ucMode == HC_MODE5) + { + bpp = 1; + BlockWidth = 128; + outpw(REG_LCM_HC_CTRL, inpw(REG_LCM_HC_CTRL) & ~0x7 | 0x5); //set mode 5 128X128X1bpp 1 color and 1 transparent + } + + outpw(REG_LCM_HC_WBCTRL, ((bpp * BlockWidth / bpw) << 16) | (bpp * BlockWidth / bpw)); + outpw(REG_LCM_HC_BADDR, (uint32_t)u32CursorBMPBuff); + outpw(REG_LCM_HC_COLOR0, 0x00ff0000); // RED color + outpw(REG_LCM_HC_COLOR1, 0x0000ff00); // GREEN color + outpw(REG_LCM_HC_COLOR2, 0x000000ff); // BLUE color + outpw(REG_LCM_HC_COLOR3, 0x00ffff00); // YELLOW color + outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_HC_EN); +} + +/** + * @brief Set the position of hardware cursor + * @param[in] u32CursorX is X position + * @param[in] u32CursorY is Y position + * @return none + */ +void vpostHCPosCtrl(uint32_t u32CursorX, uint32_t u32CursorY) +{ + outpw(REG_LCM_HC_POS, (u32CursorY << 16) | u32CursorX); //set Cursor position +} + +/** + * @brief Set OSD overlay condition + * @param[in] u8OSDDisplayMatch is display method when mask bit is matched, value could be + * - \ref DISPLAY_VIDEO + * - \ref DISPLAY_OSD + * - \ref DISPLAY_SYNTHESIZED + * @param[in] u8OSDDisplayUnMatch is display method when mask bit is unmatched + * - \ref DISPLAY_VIDEO + * - \ref DISPLAY_OSD + * - \ref DISPLAY_SYNTHESIZED + * @param[in] u8OSDSynW is synthesis video weighting, based on match condition + * @return none + */ +void vpostOSDSetOverlay(uint8_t u8OSDDisplayMatch, uint8_t u8OSDDisplayUnMatch, uint8_t u8OSDSynW) +{ + /* clear OCR0 and OCR1 */ + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & 0xfffffff0); + + /* match condition */ + if (u8OSDDisplayMatch != 0) + { + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | (u8OSDDisplayMatch << 2)); + } + + /* unmatch condition */ + if (u8OSDDisplayUnMatch != 0) + { + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | (u8OSDDisplayUnMatch)); + } + + /* synthesized weight */ + if (u8OSDDisplayMatch == DISPLAY_SYNTHESIZED || u8OSDDisplayUnMatch == DISPLAY_SYNTHESIZED) + { + outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) | (u8OSDSynW << 4)); + } +} + +/** + * @brief Write MPU command + * @param[in] uscmd MPU command code + * @return none + */ +void vpostMPUWriteAddr(uint16_t uscmd) +{ + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & ~(1 << 30)); //RS=0 + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & ~(1 << 29)); //w + + outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 5))); //CMD ON + outpw(REG_LCM_MPU_CMD, (inpw(REG_LCM_MPU_CMD) & 0xffff0000 | uscmd)); + while (inpw(REG_LCM_MPU_CMD) & (1UL << 31)); + outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) & ~(1 << 5))); //CMD OFF +} + +/** + * @brief Write MPU data + * @param[in] usdata MPU data + * @return none + */ +void vpostMPUWriteData(uint16_t usdata) +{ + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) | (1 << 30)); //RS=1 + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & ~(1 << 29)); //w + outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 5))); //CMD ON + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) & 0xffff0000 | usdata); + while (inpw(REG_LCM_MPU_CMD) & (1UL << 31)); + outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) & ~(1 << 5))); //CMD OFF +} + +/** + * @brief Read MPU data + * @param none + * @return MPU data + */ +uint32_t vpostMPUReadData(void) +{ + uint32_t udata; + + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) | (1 << 30)); //RS=1 + outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 5))); //CMD ON + outpw(REG_LCM_MPU_CMD, inpw(REG_LCM_MPU_CMD) | (1 << 29)); //r + while (inpw(REG_LCM_MPU_CMD) & (1UL << 31)); + udata = inpw(REG_LCM_MPU_CMD) & 0xffff; + outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) & ~(1 << 5))); //CMD OFF + + return udata; +} + +/*@}*/ /* end of group N9H30_LCD_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_LCD_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_pwm.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_pwm.c new file mode 100644 index 0000000000000000000000000000000000000000..a4e11b69f127b0f47afe155cf926957be3917947 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_pwm.c @@ -0,0 +1,1117 @@ +/**************************************************************************//** + * @file pwm.c + * @brief N9H30 series PWM driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_pwm.h" +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_PWM_Driver PWM Driver + @{ +*/ + + +/** @addtogroup N9H30_PWM_EXPORTED_FUNCTIONS PWM Exported Functions + @{ +*/ + +//Internal function definition +/// @cond HIDDEN_SYMBOLS + +void pwmISR(PVOID pvParam); + + +static INT pwmInitGPIO(const INT nTimerIdentity, const INT nValue); +static INT pwmInitTimer(const INT nTimerIdentity); +static INT pwmStartTimer(const INT nTimerIdentity); +static INT pwmStopTimer(const INT nTimerIdentity, const INT nMethod); +// Register operation +static INT pwmSetCP(const INT nTimerIdentity, const INT nValue); +static INT pwmSetDZI(const INT nTimerIdentity, const INT nValue); +static INT pwmSetCSR(const INT nTimerIdentity, const INT nValue); +static INT pwmSetDZGenerator(const INT nTimerIdentity, const INT nStatus); +static INT pwmSetTimerState(const INT nTimerIdentity, const INT nStatus); +static INT pwmSetInverter(const INT nTimerIdentity, const INT nStatus); +static INT pwmSetMode(const INT nTimerIdentity, const INT nStatus); +static INT pwmSetCNR(const INT nTimerIdentity, const INT nValue); +static INT pwmSetCMR(const INT nTimerIdentity, const INT nValue); +static UINT pwmGetPDR(const INT nTimerIdentity); +static INT pwmSetPIER(const INT nTimerIdentity, const INT value); +static INT pwmCleanPIIR(const INT nTimerIdentity); + +//Global variable +static BOOL bPWMIRQFlag = FALSE; //IRQ enable flag, set after PWM IRQ enable +static BOOL bPWMTimerOpenStatus[PWM_TIMER_NUM]; //timer flag which set after open(for disable IRQ decision) +static BOOL bPWMTimerStartStatus[PWM_TIMER_NUM]; //timer flag which set after Start count(to avoid incorrectly stop procedure) +static BOOL bPWMTimerMode[PWM_TIMER_NUM]; //PWM timer toggle/one shot mode +static BOOL volatile bPWMIntFlag[PWM_TIMER_NUM]; //interrupt flag which set by ISR +/// @endcond /* HIDDEN_SYMBOLS */ + + +/** + * @brief The init function of PWM device driver + */ +INT pwmInit(void) +{ + UINT temp; + // Enable PWM clock + temp = inpw(REG_CLK_PCLKEN1); + temp = temp | 0x8000000; + outpw(REG_CLK_PCLKEN1, temp); + + sysInstallISR(IRQ_LEVEL_1, PWM_IRQn, (PVOID)pwmISR); + sysSetLocalInterrupt(ENABLE_IRQ); // Enable CPSR I bit + + return 0; +} + +/** + * @brief The exit function of PWM device driver + */ +INT pwmExit(void) +{ + return 0; +} + +/** + * @brief The open function of PWM device driver + * @param[in] nTimerIdentity PWM Timer channel identity + * @retval Successful PWM successfully opened + * @retval pwmTimerBusy PWM timer already open + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +INT pwmOpen(const INT nTimerIdentity) +{ + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + if (bPWMTimerOpenStatus[nTimerIdentity] == TRUE) + { + return pwmTimerBusy; + } + if (bPWMIRQFlag == FALSE) + { + + sysEnableInterrupt(PWM_IRQn); + + bPWMIRQFlag = TRUE; + } + bPWMTimerOpenStatus[nTimerIdentity] = TRUE; + + // Set PWM timer default value(CSR->PPR->PCR->CMR->CNR) + pwmInitTimer(nTimerIdentity); + + //Enable PIER + pwmSetPIER(nTimerIdentity, PWM_ENABLE); + + //Reset PIIR + pwmCleanPIIR(nTimerIdentity); + + //Reset PWM timer start count flag + bPWMTimerStartStatus[nTimerIdentity] = FALSE; + + return Successful; + +} + +/** + * @brief The close function of PWM device driver + * @param[in] nTimerIdentity PWM Timer channel identity + * @retval Successful PWM successfully closed + * @retval pwmTimerNotOpen PWM timer not open + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +INT pwmClose(const INT nTimerIdentity) +{ + INT nLoop; + BOOL uAllTimerClose = TRUE; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + if (bPWMTimerOpenStatus[nTimerIdentity] == FALSE) + { + return pwmTimerNotOpen; + } + bPWMTimerOpenStatus[nTimerIdentity] = FALSE; + //Check if all timer stop, IRQ can be disable + for (nLoop = PWM_TIMER_MIN; nLoop < PWM_TIMER_NUM; nLoop++) + { + if (bPWMTimerOpenStatus[nLoop] == TRUE) + { + uAllTimerClose = FALSE; + } + } + //All timer stop, disable IRQs + if (uAllTimerClose == TRUE) + { + + sysDisableInterrupt(PWM_IRQn); + bPWMIRQFlag = FALSE; + } + + pwmSetPIER(nTimerIdentity, PWM_DISABLE); + pwmCleanPIIR(nTimerIdentity); + + + return Successful; + +} + +/** + * @brief The read function of PWM device driver + * @param[in] nTimerIdentity PWM Timer channel identity + * @param[out] pucStatusValue The point of typePWMSTATUS + * @param[in] uLength The length of typePWMSTATUS + * @retval Successful Read PWM value successfully + * @retval pwmTimerNotOpen PWM timer not open + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidStructLength Struct length error(struct type error) + */ +INT pwmRead(const INT nTimerIdentity, PUCHAR pucStatusValue, const UINT uLength) +{ + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + if (bPWMTimerOpenStatus[nTimerIdentity] == FALSE) + { + return pwmTimerNotOpen; + } + if (uLength != sizeof(typePWMSTATUS)) + { + return pwmInvalidStructLength;// Struct length error(struct type error) + } + if (sizeof(*((typePWMSTATUS *)pucStatusValue)) != sizeof(typePWMSTATUS)) + { + return pwmInvalidStructLength;// Struct length error(struct type error) + } + ((typePWMSTATUS *)pucStatusValue)->PDR = pwmGetPDR(nTimerIdentity); + if (bPWMIntFlag[nTimerIdentity] == TRUE) + { + bPWMIntFlag[nTimerIdentity] = FALSE; + ((typePWMSTATUS *)pucStatusValue)->InterruptFlag = TRUE; + } + else + { + ((typePWMSTATUS *)pucStatusValue)->InterruptFlag = FALSE; + } + + return Successful; + +} + +/** + * @brief The write function of PWM device driver + * @param[in] nTimerIdentity PWM Timer channel identity + * @param[in] pucCNRCMRValue The value of CNR and CMR + * @param[in] uLength For future usage + * @retval Successful Write PWM setting successfully + * @retval pwmTimerNotOpen PWM timer not open + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +INT pwmWrite(const INT nTimerIdentity, PUCHAR pucCNRCMRValue, const UINT uLength) +{ + typePWMVALUE pwmvalue; + INT nStatus; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + if (bPWMTimerOpenStatus[nTimerIdentity] == FALSE) + { + return pwmTimerNotOpen; + } + if (uLength != sizeof(typePWMVALUE)) + { + return pwmInvalidStructLength;// Struct length error(struct type error) + } + pwmvalue.value = ((typePWMVALUE *)pucCNRCMRValue)->value; + nStatus = pwmSetCNR(nTimerIdentity, pwmvalue.field.cnr); + + if (nStatus != Successful) + { + return nStatus; + } + nStatus = pwmSetCMR(nTimerIdentity, pwmvalue.field.cmr); + + if (nStatus != Successful) + { + return nStatus; + } + return Successful; + +} + +/** + * @brief The ioctl function of PWM device driver + * @param[in] nTimerIdentity PWM Timer channel identity + * @param[in] uCommand Ioctl command which indicates different operation + * @param[in] uIndication Not use in PWM + * @param[in] uValue The value which use with uCommand + * @retval Successful PWM ioctl execute successfully + * @retval pwmTimerNotOpen PWM timer not open + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidIoctlCommand Ioctl command error + * @retval Others Error according to different uCommand + */ +INT pwmIoctl(const INT nTimerIdentity, const UINT uCommand, const UINT uIndication, UINT uValue) +{ + INT nStatus; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + if (bPWMTimerOpenStatus[nTimerIdentity] == FALSE) + { + return pwmTimerNotOpen; + } + switch (uCommand) + { + case START_PWMTIMER: + { + nStatus = pwmStartTimer(nTimerIdentity); + break; + } + case STOP_PWMTIMER: + { + // default stop method is 2 + nStatus = pwmStopTimer(nTimerIdentity, PWM_STOP_METHOD2); + break; + } + case SET_CSR: + { + nStatus = pwmSetCSR(nTimerIdentity, uValue); + break; + } + case SET_CP: + { + nStatus = pwmSetCP(nTimerIdentity, uValue); + break; + } + case SET_DZI: + { + nStatus = pwmSetDZI(nTimerIdentity, uValue); + break; + } + case SET_INVERTER: + { + nStatus = pwmSetInverter(nTimerIdentity, uValue); + break; + } + case SET_MODE: + { + nStatus = pwmSetMode(nTimerIdentity, uValue); + break; + } + case ENABLE_DZ_GENERATOR: + { + nStatus = pwmSetDZGenerator(nTimerIdentity, PWM_ENABLE); + break; + } + case DISABLE_DZ_GENERATOR: + { + nStatus = pwmSetDZGenerator(nTimerIdentity, PWM_DISABLE); + break; + } + case ENABLE_PWMGPIOOUTPUT: + { + nStatus = pwmInitGPIO(nTimerIdentity, uValue); + break; + } + default: + { + return pwmInvalidIoctlCommand; + } + } + return nStatus; +} + + +/// @cond HIDDEN_SYMBOLS + +/** + * @brief The interrupt service routines of PWM + * @param[in] pvParam IRQ Parameter(not use in PWM) + */ +VOID pwmISR(PVOID pvParam) +{ + INT i; + + UINT32 uRegisterValue = 0; + uRegisterValue = inpw(REG_PWM_PIIR);// Get PIIR value + for (i = 0; i < PWM_TIMER_NUM ; i++) + { + if (uRegisterValue & (1 << i)) + { + bPWMIntFlag[i] = 1; + outpw(REG_PWM_PIIR, (1 << i)); + } + } +} + +/** + * @brief This function set corresponding GPIO as PWM function according to the + * parameter nTimerIdentity + * @param[in] nTimerIdentity Timer channel number + * @retval Successful PWM init GPIO successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidPin PWM output pin setting error + */ +static INT pwmInitGPIO(const INT nTimerIdentity, const INT nValue) +{ + UINT temp = 0; + + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + + if (nTimerIdentity == PWM_TIMER0) + { + if (nValue == PWM0_GPA12) + { + temp = inpw(REG_SYS_GPA_MFPH); + temp = (temp & ~0x000F0000) | 0xD0000; + outpw(REG_SYS_GPA_MFPH, temp); + } + else if (nValue == PWM0_GPB2) + { + temp = inpw(REG_SYS_GPB_MFPL); + temp = (temp & ~0xF00) | 0xD00; + outpw(REG_SYS_GPB_MFPL, temp); + } + else + return pwmInvalidPin; + } + else if (nTimerIdentity == PWM_TIMER1) + { + if (nValue == PWM1_GPA13) + { + temp = inpw(REG_SYS_GPA_MFPH); + temp = (temp & ~0x00F00000) | 0xD00000; + outpw(REG_SYS_GPA_MFPH, temp); + } + else if (nValue == PWM1_GPB3) + { + temp = inpw(REG_SYS_GPB_MFPL); + temp = (temp & ~0xF000) | 0xD000; + outpw(REG_SYS_GPB_MFPL, temp); + } + else + return pwmInvalidPin; + } + else if (nTimerIdentity == PWM_TIMER2) + { + if (nValue == PWM2_GPA14) + { + temp = inpw(REG_SYS_GPA_MFPH); + temp = (temp & ~0x0F000000) | 0xD000000; + outpw(REG_SYS_GPA_MFPH, temp); + } + else if (nValue == PWM2_GPH2) + { + temp = inpw(REG_SYS_GPH_MFPL); + temp = (temp & ~0xF00) | 0xD00; + outpw(REG_SYS_GPH_MFPL, temp); + } + else + return pwmInvalidPin; + } + else + { + if (nValue == PWM3_GPA15) + { + temp = inpw(REG_SYS_GPA_MFPH); + temp = (temp & ~0xF0000000) | 0xD0000000; + outpw(REG_SYS_GPA_MFPH, temp); + } + else if (nValue == PWM3_GPH3) + { + temp = inpw(REG_SYS_GPH_MFPL); + temp = (temp & ~0xF000) | 0xD000; + outpw(REG_SYS_GPH_MFPL, temp); + } + else + return pwmInvalidPin; + } + + return Successful; +} + + +/** + * @brief This function initiates PWM timer n and set the default setting to CSR, + * PPR, PCR, CNR, CMR + * @param[in] nTimerIdentity Timer channel number + * @retval Successful PWM init timer successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +static INT pwmInitTimer(const INT nTimerIdentity) +{ + typePPR PWMPPR; + INT nStatus; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + + //Set CSR + nStatus = pwmSetCSR(nTimerIdentity, DEFAULT_CSR); + + if (nStatus != Successful) + { + return nStatus; + } + + //Set PPR + PWMPPR.value = (UINT)inpw(REG_PWM_PPR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + if (PWMPPR.field.cp0 == 0) + { + pwmSetCP(nTimerIdentity, DEFAULT_CP); + } + break; + } + case PWM_TIMER1: + { + if (PWMPPR.field.cp0 == 0) + { + pwmSetCP(nTimerIdentity, DEFAULT_CP); + } + break; + } + case PWM_TIMER2: + { + if (PWMPPR.field.cp1 == 0) + { + pwmSetCP(nTimerIdentity, DEFAULT_CP); + } + break; + } + case PWM_TIMER3: + { + if (PWMPPR.field.cp1 == 0) + { + pwmSetCP(nTimerIdentity, DEFAULT_CP); + } + break; + } + } + + //Set PCR + nStatus = pwmSetMode(nTimerIdentity, DEFAULT_MODE); + + if (nStatus != Successful) + { + return nStatus; + } + bPWMTimerMode[nTimerIdentity] = DEFAULT_MODE; + + //Set CMR + nStatus = pwmSetCMR(nTimerIdentity, DEFAULT_CMR); + + if (nStatus != Successful) + { + return nStatus; + } + + //Set CNR + nStatus = pwmSetCNR(nTimerIdentity, DEFAULT_CNR); + + if (nStatus != Successful) + { + return nStatus; + } + + return Successful; + +} + + +/** + * @brief This function starts PWM timer according to the parameter + * @param[in] nTimerIdentity Timer channel number + * @retval Successful PWM start timer successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +static INT pwmStartTimer(const INT nTimerIdentity) +{ + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + pwmSetTimerState(nTimerIdentity, PWM_ENABLE); + if (bPWMTimerMode[nTimerIdentity] == PWM_TOGGLE) + { + bPWMTimerStartStatus[nTimerIdentity] = TRUE; + } + + return Successful; +} + +/** + * @brief This function stops PWM timer n using method 1, 2, or 3 according to the + * parameter nTimerIdentity and nStatus + * @param[in] nTimerIdentity Timer channel number + * @param[in] nMethod Stop PWM timer method + * @retval Successful PWM stop timer successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidStopMethod Stop method error + */ +static INT pwmStopTimer(const INT nTimerIdentity, INT nMethod) +{ + typeCNR PWMCNR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + // Timer_num value error + return pwmInvalidTimerChannel; + } + //Can't stop before open PWM timer + if (bPWMTimerOpenStatus[nTimerIdentity] == FALSE) + { + return Successful; + } + // one shot mode didn't need stop procedure + if (bPWMTimerMode[nTimerIdentity] == PWM_ONESHOT) + { + return Successful; + } + // Timer stop already, no need to stop again + if (bPWMTimerStartStatus[nTimerIdentity] == FALSE) + { + return Successful; + } + + // Set CNR as 0 + PWMCNR.field.cnr = 0; + outpw(REG_PWM_CNR0 + (PWM_OFFSET * nTimerIdentity), PWMCNR.value); + + switch (nMethod) + { + case PWM_STOP_METHOD1: + { + while (1) + { + if (pwmGetPDR(nTimerIdentity) == 0) // Wait PDR reach to 0 + { + pwmSetTimerState(nTimerIdentity, PWM_DISABLE);// Disable pwm timer + bPWMIntFlag[nTimerIdentity] = FALSE; + bPWMTimerStartStatus[nTimerIdentity] = FALSE; + break; + } + } + break; + } + case PWM_STOP_METHOD2: + { + while (1) + { + if (bPWMIntFlag[nTimerIdentity] == TRUE) // Wait interrupt happen + { + pwmSetTimerState(nTimerIdentity, PWM_DISABLE);// Disable pwm timer + bPWMIntFlag[nTimerIdentity] = FALSE; + bPWMTimerStartStatus[nTimerIdentity] = FALSE; + break; + } + } + break; + } + /*case PWM_STOP_METHOD3: + { + pwmSetPCRState(nTimerIdentity, PWM_DISABLE);// Disable pwm timer + bPWMIntFlag[nTimerIdentity] = FALSE; + bPWMTimerStartStatus[nTimerIdentity] = FALSE; + break; + }*/ + default: + { + return pwmInvalidStopMethod;// Stop method value error + } + } + + return Successful; +} + +/** + * @brief This function set CPn value according to the parameter nTimerIdentity and nValue + * @param[in] nTimerIdentity Timer channel number + * @param[in] nValue The value which want to set in CSRn + * @retval Successful Set CPn successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidCPValue PWM_PPR CPn value out of range + */ +static INT pwmSetCP(const INT nTimerIdentity, const INT nValue) +{ + typePPR PWMPPR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nValue < CP_MIN || nValue > CP_MAX) + { + return pwmInvalidCPValue;// CP value error + } + PWMPPR.value = (UINT)inpw(REG_PWM_PPR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMPPR.field.cp0 = nValue; + break; + } + case PWM_TIMER1: + { + PWMPPR.field.cp0 = nValue; + break; + } + case PWM_TIMER2: + { + PWMPPR.field.cp1 = nValue; + break; + } + case PWM_TIMER3: + { + PWMPPR.field.cp1 = nValue; + break; + } + } + outpw(REG_PWM_PPR, PWMPPR.value); + + return Successful; +} + +/** + * @brief This function set DZIn value according to the parameter nTimerIdentity and nValue + * @param[in] nTimerIdentity Timer channel number + * @param[in] nValue The value which want to set in DZIn + * @retval Successful Set DZIn successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidDZIValue PWM_PPR DZIn value out of range + */ +static INT pwmSetDZI(const INT nTimerIdentity, const INT nValue) +{ + typePPR PWMPPR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nValue < DZI_MIN || nValue > DZI_MAX) + { + return pwmInvalidDZIValue;// CSR value error + } + PWMPPR.value = (UINT)inpw(REG_PWM_PPR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMPPR.field.dzi0 = nValue; + break; + } + case PWM_TIMER1: + { + PWMPPR.field.dzi0 = nValue; + break; + } + case PWM_TIMER2: + { + PWMPPR.field.dzi1 = nValue; + break; + } + case PWM_TIMER3: + { + PWMPPR.field.dzi1 = nValue; + break; + } + } + outpw(REG_PWM_PPR, PWMPPR.value); + + return Successful; +} + +/** + * @brief This function set CSRn value according to the parameter nTimerIdentity and nValue + * @param[in] nTimerIdentity Timer channel number + * @param[in] nValue The value which want to set in CSRn + * @retval Successful Set CSRn successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +static INT pwmSetCSR(const INT nTimerIdentity, const INT nValue) +{ + typeCSR PWMCSR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nValue < CSR_MIN || nValue > CSR_MAX) + { + return pwmInvalidCSRValue;// CSR value error + } + PWMCSR.value = (UINT)inpw(REG_PWM_CSR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMCSR.field.csr0 = nValue; + break; + } + case PWM_TIMER1: + { + PWMCSR.field.csr1 = nValue; + break; + } + case PWM_TIMER2: + { + PWMCSR.field.csr2 = nValue; + break; + } + case PWM_TIMER3: + { + PWMCSR.field.csr3 = nValue; + break; + } + } + outpw(REG_PWM_CSR, PWMCSR.value); + + return Successful; +} + +/** + * @brief This function enable/disable PWM channel n dead zone function according to the + * parameter nTimerIdentity and nStatus + * @param[in] nTimerIdentity Timer channel number + * @param[in] nStatus PWMDZG_ENABLE/PWMDZG_DISABLE + * @retval Successful Set dead zone successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidDZGStatus PWM Dead-Zone Generator enable/disable status error + */ +static INT pwmSetDZGenerator(const INT nTimerIdentity, INT nStatus) +{ + typePCR PWMPCR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nStatus != PWMDZG_ENABLE && nStatus != PWMDZG_DISABLE) + { + return pwmInvalidDZGStatus;// PCR inverter value error + } + PWMPCR.value = (UINT)inpw(REG_PWM_PCR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMPCR.field.grpup0_dzen = nStatus; + break; + } + case PWM_TIMER1: + { + PWMPCR.field.grpup0_dzen = nStatus; + break; + } + case PWM_TIMER2: + { + PWMPCR.field.grpup1_dzen = nStatus; + break; + } + case PWM_TIMER3: + { + PWMPCR.field.grpup1_dzen = nStatus; + break; + } + } + outpw(REG_PWM_PCR, PWMPCR.value); + + return Successful; +} + +/** + * @brief This function set PWM channel n enable/disable according to the + * parameter nTimerIdentity and nStatus + * @param[in] nTimerIdentity Timer channel number + * @param[in] nStatus PWM_ENABLE/PWMDISABLE + * @retval Successful Set channel enable/disable successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +static INT pwmSetTimerState(const INT nTimerIdentity, INT nStatus) +{ + typePCR PWMPCR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nStatus != PWM_ENABLE && nStatus != PWM_DISABLE) + { + return pwmInvalidTimerStatus; + } + PWMPCR.value = (UINT)inpw(REG_PWM_PCR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMPCR.field.ch0_en = nStatus; + break; + } + case PWM_TIMER1: + { + PWMPCR.field.ch1_en = nStatus; + break; + } + case PWM_TIMER2: + { + PWMPCR.field.ch2_en = nStatus; + break; + } + case PWM_TIMER3: + { + PWMPCR.field.ch3_en = nStatus; + break; + } + } + outpw(REG_PWM_PCR, PWMPCR.value); + + return Successful; +} + + +/** + * @brief This function set PWM channel n inverter on/off according to the + * parameter nTimerIdentity and nStatus + * @param[in] nTimerIdentity Timer channel number + * @param[in] nStatus PWM_ENABLE/PWM_DISABLE + * @retval Successful Set inverter successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidInverterValue Inverter value error + */ +static INT pwmSetInverter(const INT nTimerIdentity, INT nStatus) +{ + typePCR PWMPCR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nStatus != PWM_INVON && nStatus != PWM_INVOFF) + { + return pwmInvalidInverterValue;// PCR inverter value error + } + PWMPCR.value = (UINT)inpw(REG_PWM_PCR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMPCR.field.ch0_inverter = nStatus; + break; + } + case PWM_TIMER1: + { + PWMPCR.field.ch1_inverter = nStatus; + break; + } + case PWM_TIMER2: + { + PWMPCR.field.ch2_inverter = nStatus; + break; + } + case PWM_TIMER3: + { + PWMPCR.field.ch3_inverter = nStatus; + break; + } + } + outpw(REG_PWM_PCR, PWMPCR.value); + + return Successful; +} + +/** + * @brief This function set PWM channel n toggle/one shot mode according to the + * parameter nTimerIdentity and nStatus + * @param[in] nTimerIdentity Timer channel number + * @param[in] nStatus PWM_TOGGLE/PWM_ONESHOT + * @retval Successful Set operation mode successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidModeStatus Operating mode error + */ +static INT pwmSetMode(const INT nTimerIdentity, INT nStatus) +{ + typePCR PWMPCR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nStatus != PWM_TOGGLE && nStatus != PWM_ONESHOT) + { + return pwmInvalidModeStatus;// PCR inverter value error + } + PWMPCR.value = (UINT)inpw(REG_PWM_PCR); + switch (nTimerIdentity) + { + case PWM_TIMER0: + { + PWMPCR.field.ch0_mode = nStatus; + break; + } + case PWM_TIMER1: + { + PWMPCR.field.ch1_mode = nStatus; + break; + } + case PWM_TIMER2: + { + PWMPCR.field.ch2_mode = nStatus; + break; + } + case PWM_TIMER3: + { + PWMPCR.field.ch3_mode = nStatus; + break; + } + } + outpw(REG_PWM_PCR, PWMPCR.value); + bPWMTimerMode[nTimerIdentity] = nStatus; + + return Successful; +} + + +/** + * @brief This function set PWM_CNRn value according to the parameter nTimerIdentity and nValue + * @param[in] nTimerIdentity Timer channel number + * @param[in] nValue CNR value + * @retval Successful Set CNR successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidCNRValue Invalid CNR value + */ +static INT pwmSetCNR(const INT nTimerIdentity, INT nValue) +{ + typeCNR PWMCNR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nValue < CNR_MIN || nValue > CNR_MAX) + { + return pwmInvalidCNRValue;// PCR inverter value error + } + PWMCNR.field.cnr = nValue; + outpw(REG_PWM_CNR0 + (PWM_OFFSET * nTimerIdentity), PWMCNR.value); + + return Successful; +} + +/** + * @brief This function set PWM_CMRn value according to the parameter nTimerIdentity and nValue + * @param[in] nTimerIdentity Timer channel number + * @param[in] nValue CMR value + * @retval Successful Set CMR successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval pwmInvalidCMRValue Invalid CMR value + */ +static INT pwmSetCMR(const INT nTimerIdentity, INT nValue) +{ + typeCMR PWMCMR; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + if (nValue < CMR_MIN || nValue > CMR_MAX) + { + return pwmInvalidCMRValue;// CMR value error + } + PWMCMR.field.cmr = nValue; + outpw(REG_PWM_CMR0 + (PWM_OFFSET * nTimerIdentity), PWMCMR.value); + + return Successful; +} + +/** + * @brief This function return the PDR value of PWM timer n + * @param[in] nTimerIdentity Timer channel number + * @retval pwmInvalidTimerChannel PWM Timer channel number error + * @retval Others Current PDR value + */ +static UINT pwmGetPDR(const INT nTimerIdentity) +{ + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + else + { + return (UINT)inpw(REG_PWM_PDR0 + (PWM_OFFSET * nTimerIdentity)); // Return PDR value + } +} + +/** + * @brief This function set the PIERn bit of PWM timer n as 1 or 0 according to the + * parameter nTimerIdentity and nValue + * @param[in] nTimerIdentity Timer channel number + * @param[in] nValue PWM_ENABLE/PWM_DISABLE + * @retval Successful Set PIER successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +static INT pwmSetPIER(const INT nTimerIdentity, INT nValue) +{ + UINT uRegisterValue = 0;; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// Timer_num value error + } + else + { + uRegisterValue = (UINT)inpw(REG_PWM_PIER); + if (nValue == PWM_ENABLE) + { + uRegisterValue = uRegisterValue | (1 << nTimerIdentity); // Set PIER + } + else + { + uRegisterValue = uRegisterValue & (0 << nTimerIdentity); // Clear PIER + } + outpw(REG_PWM_PIER, uRegisterValue);// Write value to PIER + + return Successful; + } +} + + +/** + * @brief This function clear PIIRn bit according to the parameter nTimerIdentity + * @param[in] nTimerIdentity Timer channel number + * @retval Successful Clear PIIR successfully + * @retval pwmInvalidTimerChannel PWM Timer channel number error + */ +static INT pwmCleanPIIR(const INT nTimerIdentity) +{ + UINT uRegisterValue = 0; + if (nTimerIdentity < PWM_TIMER_MIN || nTimerIdentity > PWM_TIMER_MAX) + { + return pwmInvalidTimerChannel;// nTimerIdentity value error + } + uRegisterValue = (UINT)inpw(REG_PWM_PIIR); + uRegisterValue = uRegisterValue & ~(1 << nTimerIdentity); + outpw(REG_PWM_PIIR, uRegisterValue); + + return Successful; +} + +/// @endcond /* HIDDEN_SYMBOLS */ + +/*@}*/ /* end of group N9H30_PWM_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_PWM_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_rtc.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_rtc.c new file mode 100644 index 0000000000000000000000000000000000000000..4ec0cdf5068e35ec8186de53eb238c731628b877 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_rtc.c @@ -0,0 +1,1153 @@ +/**************************************************************************//** +* @file RTC.c +* @brief N9H30 RTC driver source file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_rtc.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_RTC_Driver RTC Driver + @{ +*/ + +/** @addtogroup N9H30_RTC_EXPORTED_FUNCTIONS RTC Exported Functions + @{ +*/ + +/// @cond HIDDEN_SYMBOLS + +static CHAR g_chHourMode = 0; +static BOOL volatile g_bIsEnableTickInt = FALSE; +static BOOL volatile g_bIsEnableAlarmInt = FALSE; + +static UINT32 volatile g_u32Reg, g_u32Reg1, g_u32hiYear, g_u32loYear, g_u32hiMonth, g_u32loMonth, g_u32hiDay, g_u32loDay; +static UINT32 volatile g_u32hiHour, g_u32loHour, g_u32hiMin, g_u32loMin, g_u32hiSec, g_u32loSec; +UINT32 volatile i, Wait; + +VOID RTC_Check(void) +{ + i = 0; + + Wait = inp32(REG_RTC_INTSTS) & RTC_INTSTS_REGWRBUSY_Msk; + + while (Wait == RTC_INTSTS_REGWRBUSY_Msk) + { + + Wait = inp32(REG_RTC_INTSTS) & RTC_INTSTS_REGWRBUSY_Msk; + + i++; + + if (i > RTC_WAIT_COUNT) + { + break; + } + } +} + +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief Set 32k Frequency Compensation Data + * + * @param[in] i32FrequencyX100 Specify the RTC clock X100, ex: 3277365 means 32773.65. + * + * @return E_RTC_ERR_FCR_VALUE Wrong Compensation VALUE + * E_RTC_SUCCESS Success + * + * @details This API is used to compensate the 32 kHz frequency by current LXT frequency for RTC application. + */ +UINT32 RTC_DoFrequencyCompensation(INT32 i32FrequencyX100) +{ + INT32 i32RegInt, i32RegFra; + UINT32 u32Reg; + + /* Compute integer and fraction for RTC FCR register */ + i32RegInt = (i32FrequencyX100 / 100) - RTC_FCR_REFERENCE; + i32RegFra = (((i32FrequencyX100 % 100)) * 60) / 100; + + /* Judge Integer part is reasonable */ + if ((i32RegInt < 0) | (i32RegInt > 15)) + { + return E_RTC_ERR_FCR_VALUE; + } + + u32Reg = (uint32_t)((i32RegInt << 8) | i32RegFra); + + RTC_WriteEnable(1); + outp32(REG_RTC_FREQADJ, u32Reg); + RTC_Check(); + + return E_RTC_SUCCESS; +} + +/** + * @brief RTC access register enable + * + * @param[in] bEnable 1: Enable access register + * 0: Disable access register + * + * @retval E_RTC_ERR_EIO Time-out error + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_WriteEnable(BOOL bEnable) +{ + INT32 volatile i32i; + + RTC_Check(); + + if (bEnable) + { + outp32(REG_RTC_RWEN, RTC_WRITE_KEY); + RTC_Check(); + + for (i32i = 0 ; i32i < RTC_WAIT_COUNT ; i32i++) + { + /*-------------------------------------------------------------------------------------------------*/ + /* check RTC_RWEN[16] to find out RTC write enable */ + /*-------------------------------------------------------------------------------------------------*/ + if (inp32(REG_RTC_RWEN) & 0x10000) + { + break; + } + } + + if (i32i == RTC_WAIT_COUNT) + { + //sysprintf ("\nRTC: 3, set write enable FAILED!\n"); + + return E_RTC_ERR_EIO; + } + } + else + { + for (i32i = 0 ; i32i < RTC_WAIT_COUNT ; i32i++) + { + if (inp32(REG_RTC_RWEN) == 0) + { + break; + } + } + } + + return E_RTC_SUCCESS; +} + +/** + * @brief Initial RTC and install ISR + * @retval E_RTC_ERR_EIO Initial RTC time-out + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_Init(void) +{ + INT32 i32i; + + /*-----------------------------------------------------------------------------------------------------*/ + /* When RTC is power on, write 0xa5eb1357 to RTC_INIR to reset all logic. */ + /*-----------------------------------------------------------------------------------------------------*/ + + outp32(REG_RTC_INIT, RTC_INIT_KEY); + RTC_Check(); + + for (i32i = 0 ; i32i < RTC_WAIT_COUNT ; i32i++) + { + if (inp32(REG_RTC_INIT) & 0x01) + { + /* Check RTC_INIR[0] to find out RTC reset signal */ + break; + } + } + + if (i32i == RTC_WAIT_COUNT) + { + return E_RTC_ERR_EIO; + } + + /*-----------------------------------------------------------------------------------------------------*/ + /* Install RTC ISR */ + /*-----------------------------------------------------------------------------------------------------*/ + + outp32(REG_RTC_RWEN, RTC_WRITE_KEY); + RTC_Check(); + + for (i32i = 0 ; i32i < RTC_WAIT_COUNT ; i32i++) + { + /*-------------------------------------------------------------------------------------------------*/ + /* check RTC_RWEN[16] to find out RTC write enable */ + /*-------------------------------------------------------------------------------------------------*/ + if (inp32(REG_RTC_RWEN) & 0x10000) + { + break; + } + } + + if (i32i == RTC_WAIT_COUNT) + { + return E_RTC_ERR_EIO; + } + + return E_RTC_SUCCESS; +} + +/** + * @brief Set Current Timer + * + * @param[in] *sPt Specify the time property and current time. It includes: + * - u8cClockDisplay: \ref RTC_CLOCK_12 / \ref RTC_CLOCK_24 + * - u8cAmPm: \ref RTC_AM / \ref RTC_PM + * - u32cSecond: Second value + * - u32cMinute: Minute value + * - u32cHour: Hour value + * - u32cDayOfWeek: Day of week + * - u32cDay: Day value + * - u32cMonth: Month value + * - u32Year: Year value + * - u32AlarmMaskSecond: Mask second alarm + * - u32AlarmMaskMinute: Mask minute alarm + * - u32AlarmMaskHour: Mask hour alarm + * - *pfnAlarmCallBack: Call back function + * + * @retval E_RTC_ERR_EIO Initial RTC time-out + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_Open(S_RTC_TIME_DATA_T *sPt) +{ + UINT32 volatile u32Reg; + + /*-----------------------------------------------------------------------------------------------------*/ + /* DO BASIC JUDGEMENT TO Check RTC time data value is reasonable or not. */ + /*-----------------------------------------------------------------------------------------------------*/ + if (((sPt->u32Year - RTC_YEAR2000) > 99) | + ((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12)) | + ((sPt->u32cDay == 0) || (sPt->u32cDay > 31))) + { + return E_RTC_ERR_CALENDAR_VALUE; + } + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + if ((sPt->u32cHour == 0) || (sPt->u32cHour > 12)) + { + return E_RTC_ERR_TIMESACLE_VALUE ; + } + } + else if (sPt->u8cClockDisplay == RTC_CLOCK_24) + { + if (sPt->u32cHour > 23) + { + return E_RTC_ERR_TIMESACLE_VALUE ; + } + } + else + { + return E_RTC_ERR_TIMESACLE_VALUE ; + } + + if ((sPt->u32cMinute > 59) | + (sPt->u32cSecond > 59) | + (sPt->u32cSecond > 59)) + { + return E_RTC_ERR_TIME_VALUE ; + } + if (sPt->u32cDayOfWeek > 6) + { + return E_RTC_ERR_DWR_VALUE ; + } + + /*-----------------------------------------------------------------------------------------------------*/ + /* Second, set RTC time data. */ + /*-----------------------------------------------------------------------------------------------------*/ + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + g_chHourMode = RTC_CLOCK_12; + + RTC_WriteEnable(1); + outp32(REG_RTC_TIMEFMT, RTC_CLOCK_12); + RTC_Check(); + + /*-------------------------------------------------------------------------------------------------*/ + /* important, range of 12-hour PM mode is 21 upto 32 */ + /*-------------------------------------------------------------------------------------------------*/ + if (sPt->u8cAmPm == RTC_PM) + sPt->u32cHour += 20; + } + else /* RTC_CLOCK_24 */ + { + g_chHourMode = RTC_CLOCK_24; + + RTC_WriteEnable(1); + outp32(REG_RTC_TIMEFMT, RTC_CLOCK_24); + RTC_Check(); + } + + + g_u32hiHour = sPt->u32cHour / 10; + g_u32loHour = sPt->u32cHour % 10; + g_u32hiMin = sPt->u32cMinute / 10; + g_u32loMin = sPt->u32cMinute % 10; + g_u32hiSec = sPt->u32cSecond / 10; + g_u32loSec = sPt->u32cSecond % 10; + u32Reg = (g_u32hiHour << 20); + u32Reg |= (g_u32loHour << 16); + u32Reg |= (g_u32hiMin << 12); + u32Reg |= (g_u32loMin << 8); + u32Reg |= (g_u32hiSec << 4); + u32Reg |= g_u32loSec; + g_u32Reg = u32Reg; + + RTC_WriteEnable(1); + outp32(REG_RTC_TIME, (UINT32)g_u32Reg); + RTC_Check(); + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + if (sPt->u8cAmPm == RTC_PM) + sPt->u32cHour -= 20; + } + + g_u32hiYear = (sPt->u32Year - RTC_YEAR2000) / 10; + g_u32loYear = (sPt->u32Year - RTC_YEAR2000) % 10; + g_u32hiMonth = sPt->u32cMonth / 10; + g_u32loMonth = sPt->u32cMonth % 10; + g_u32hiDay = sPt->u32cDay / 10; + g_u32loDay = sPt->u32cDay % 10; + u32Reg = (g_u32hiYear << 20); + u32Reg |= (g_u32loYear << 16); + u32Reg |= (g_u32hiMonth << 12); + u32Reg |= (g_u32loMonth << 8); + u32Reg |= (g_u32hiDay << 4); + u32Reg |= g_u32loDay; + g_u32Reg = u32Reg; + + RTC_WriteEnable(1); + outp32(REG_RTC_CAL, (UINT32)g_u32Reg); + RTC_Check(); + + RTC_WriteEnable(1); + outp32(REG_RTC_WEEKDAY, (UINT32)sPt->u32cDayOfWeek); + RTC_Check(); + + return E_RTC_SUCCESS; +} + + +/** + * @brief Read current date/time or alarm date/time from RTC + * + * @param[in] eTime \ref RTC_CURRENT_TIME / \ref RTC_ALARM_TIME + * @param[out] *sPt Specify the time property and current time. It includes: + * - u8cClockDisplay: \ref RTC_CLOCK_12 / \ref RTC_CLOCK_24 + * - u8cAmPm: \ref RTC_AM / \ref RTC_PM + * - u32cSecond: Second value + * - u32cMinute: Minute value + * - u32cHour: Hour value + * - u32cDayOfWeek: Day of week + * - u32cDay: Day value + * - u32cMonth: Month value + * - u32Year: Year value + * - u32AlarmMaskSecond: Mask second alarm + * - u32AlarmMaskMinute: Mask minute alarm + * - u32AlarmMaskHour: Mask hour alarm + * - *pfnAlarmCallBack: Call back function + * + * @retval E_RTC_ERR_ENOTTY Wrong select time + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_Read(E_RTC_TIME_SELECT eTime, S_RTC_TIME_DATA_T *sPt) +{ + UINT32 u32Tmp; + + sPt->u8cClockDisplay = inp32(REG_RTC_TIMEFMT); /* 12/24-hour */ + sPt->u32cDayOfWeek = inp32(REG_RTC_WEEKDAY); /* Day of week */ + + switch (eTime) + { + case RTC_CURRENT_TIME: + { + g_u32Reg = inp32(REG_RTC_CAL); + g_u32Reg1 = inp32(REG_RTC_TIME); + break; + } + case RTC_ALARM_TIME: + { + g_u32Reg = inp32(REG_RTC_CALM); + g_u32Reg1 = inp32(REG_RTC_TALM); + break; + } + default: + { + return E_RTC_ERR_ENOTTY; + } + } + + g_u32hiYear = (g_u32Reg & 0xF00000) >> 20; + g_u32loYear = (g_u32Reg & 0xF0000) >> 16; + g_u32hiMonth = (g_u32Reg & 0x1000) >> 12; + g_u32loMonth = (g_u32Reg & 0xF00) >> 8; + g_u32hiDay = (g_u32Reg & 0x30) >> 4; + g_u32loDay = g_u32Reg & 0xF; + + u32Tmp = (g_u32hiYear * 10); + u32Tmp += g_u32loYear; + sPt->u32Year = u32Tmp + RTC_YEAR2000; + + u32Tmp = (g_u32hiMonth * 10); + sPt->u32cMonth = u32Tmp + g_u32loMonth; + + u32Tmp = (g_u32hiDay * 10); + sPt->u32cDay = u32Tmp + g_u32loDay; + + g_u32hiHour = (g_u32Reg1 & 0x300000) >> 20; + g_u32loHour = (g_u32Reg1 & 0xF0000) >> 16; + g_u32hiMin = (g_u32Reg1 & 0x7000) >> 12; + g_u32loMin = (g_u32Reg1 & 0xF00) >> 8; + g_u32hiSec = (g_u32Reg1 & 0x70) >> 4; + g_u32loSec = g_u32Reg1 & 0xF; + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + u32Tmp = (g_u32hiHour * 10); + u32Tmp += g_u32loHour; + sPt->u32cHour = u32Tmp; /* AM: 1~12. PM: 21~32. */ + + if (eTime == RTC_CURRENT_TIME) + { + if (sPt->u32cHour >= 21) + { + sPt->u8cAmPm = RTC_PM; + sPt->u32cHour -= 20; + } + else + { + sPt->u8cAmPm = RTC_AM; + } + } + else + { + if (sPt->u32cHour < 12) + { + if (sPt->u32cHour == 0) + sPt->u32cHour = 12; + sPt->u8cAmPm = RTC_AM; + } + else + { + sPt->u32cHour -= 12; + sPt->u8cAmPm = RTC_PM; + } + } + + u32Tmp = (g_u32hiMin * 10); + u32Tmp += g_u32loMin; + sPt->u32cMinute = u32Tmp; + + u32Tmp = (g_u32hiSec * 10); + u32Tmp += g_u32loSec; + sPt->u32cSecond = u32Tmp; + + } + else + { + /* RTC_CLOCK_24 */ + u32Tmp = (g_u32hiHour * 10); + u32Tmp += g_u32loHour; + sPt->u32cHour = u32Tmp; + + u32Tmp = (g_u32hiMin * 10); + u32Tmp += g_u32loMin; + sPt->u32cMinute = u32Tmp; + + u32Tmp = (g_u32hiSec * 10); + u32Tmp += g_u32loSec; + sPt->u32cSecond = u32Tmp; + } + + return E_RTC_SUCCESS; + +} + + +/** + * @brief Write current date/time or alarm date/time from RTC + * + * @param[in] eTime \ref RTC_CURRENT_TIME / \ref RTC_ALARM_TIME + * @param[in] *sPt Specify the time property and current time. It includes: + * - u8cClockDisplay: \ref RTC_CLOCK_12 / \ref RTC_CLOCK_24 + * - u8cAmPm: \ref RTC_AM / \ref RTC_PM + * - u32cSecond: Second value + * - u32cMinute: Minute value + * - u32cHour: Hour value + * - u32cDayOfWeek: Day of week + * - u32cDay: Day value + * - u32cMonth: Month value + * - u32Year: Year value + * - u32AlarmMaskSecond: Mask second alarm + * - u32AlarmMaskMinute: Mask minute alarm + * - u32AlarmMaskHour: Mask hour alarm + * - *pfnAlarmCallBack: Call back function + * + * @retval E_RTC_ERR_ENOTTY Wrong select time + * @retval E_RTC_ERR_CALENDAR_VALUE Wrong calender value + * @retval E_RTC_ERR_TIME_VALUE Wrong time value + * @retval E_RTC_ERR_DWR_VALUE Wrong day of week value + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_Write(E_RTC_TIME_SELECT eTime, S_RTC_TIME_DATA_T *sPt) +{ + UINT32 u32Reg; + + /*-----------------------------------------------------------------------------------------------------*/ + /* Check RTC time data value is reasonable or not. */ + /*-----------------------------------------------------------------------------------------------------*/ + if (((sPt->u32Year - RTC_YEAR2000) > 99) | + ((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12)) | + ((sPt->u32cDay == 0) || (sPt->u32cDay > 31))) + { + return E_RTC_ERR_CALENDAR_VALUE; + } + + if ((sPt->u32Year - RTC_YEAR2000) > 99) + { + return E_RTC_ERR_CALENDAR_VALUE; + } + + if ((sPt->u32cMonth == 0) || (sPt->u32cMonth > 12)) + { + return E_RTC_ERR_CALENDAR_VALUE; + } + + if ((sPt->u32cDay == 0) || (sPt->u32cDay > 31)) + { + return E_RTC_ERR_CALENDAR_VALUE; + } + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + if ((sPt->u32cHour == 0) || (sPt->u32cHour > 12)) + { + return E_RTC_ERR_TIME_VALUE; + } + } + else if (sPt->u8cClockDisplay == RTC_CLOCK_24) + { + if (sPt->u32cHour > 23) + { + return E_RTC_ERR_TIME_VALUE; + } + } + else + { + return E_RTC_ERR_TIME_VALUE; + } + + if (sPt->u32cMinute > 59) + { + return E_RTC_ERR_TIME_VALUE; + } + + if (sPt->u32cSecond > 59) + { + return E_RTC_ERR_TIME_VALUE; + } + + if (sPt->u32cDayOfWeek > 6) + { + return E_RTC_ERR_DWR_VALUE; + } + + switch (eTime) + { + + case RTC_CURRENT_TIME: + { + /*---------------------------------------------------------------------------------------------*/ + /* Second, set RTC time data. */ + /*---------------------------------------------------------------------------------------------*/ + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + g_chHourMode = RTC_CLOCK_12; + + RTC_WriteEnable(1); + outp32(REG_RTC_TIMEFMT, RTC_CLOCK_12); + RTC_Check(); + + /*-----------------------------------------------------------------------------------------*/ + /* important, range of 12-hour PM mode is 21 upto 32 */ + /*-----------------------------------------------------------------------------------------*/ + if (sPt->u8cAmPm == RTC_PM) + { + sPt->u32cHour += 20; + } + } + else /* RTC_CLOCK_24 */ + { + g_chHourMode = RTC_CLOCK_24; + + RTC_WriteEnable(1); + outp32(REG_RTC_TIMEFMT, RTC_CLOCK_24); + RTC_Check(); + + } + + g_u32hiHour = sPt->u32cHour / 10; + g_u32loHour = sPt->u32cHour % 10; + g_u32hiMin = sPt->u32cMinute / 10; + g_u32loMin = sPt->u32cMinute % 10; + g_u32hiSec = sPt->u32cSecond / 10; + g_u32loSec = sPt->u32cSecond % 10; + + u32Reg = (g_u32hiHour << 20); + u32Reg |= (g_u32loHour << 16); + u32Reg |= (g_u32hiMin << 12); + u32Reg |= (g_u32loMin << 8); + u32Reg |= (g_u32hiSec << 4); + u32Reg |= g_u32loSec; + g_u32Reg = u32Reg; + + RTC_WriteEnable(1); + outp32(REG_RTC_TIME, (UINT32)g_u32Reg); + RTC_Check(); + + g_u32hiYear = (sPt->u32Year - RTC_YEAR2000) / 10; + g_u32loYear = (sPt->u32Year - RTC_YEAR2000) % 10; + g_u32hiMonth = sPt->u32cMonth / 10; + g_u32loMonth = sPt->u32cMonth % 10; + g_u32hiDay = sPt->u32cDay / 10; + g_u32loDay = sPt->u32cDay % 10; + + u32Reg = (g_u32hiYear << 20); + u32Reg |= (g_u32loYear << 16); + u32Reg |= (g_u32hiMonth << 12); + u32Reg |= (g_u32loMonth << 8); + u32Reg |= (g_u32hiDay << 4); + u32Reg |= g_u32loDay; + g_u32Reg = u32Reg; + + RTC_WriteEnable(1); + outp32(REG_RTC_CAL, (UINT32)g_u32Reg); + RTC_Check(); + + RTC_WriteEnable(1); + outp32(REG_RTC_WEEKDAY, (UINT32) sPt->u32cDayOfWeek); + RTC_Check(); + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + if (sPt->u8cAmPm == RTC_PM) + { + sPt->u32cHour -= 20; + } + } + + return E_RTC_SUCCESS; + + } + case RTC_ALARM_TIME: + { + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, inp32(REG_RTC_PWRCTL) & ~RTC_PWRCTL_ALARM_EN_Msk); + RTC_Check(); + + /*---------------------------------------------------------------------------------------------*/ + /* Second, set alarm time data. */ + /*---------------------------------------------------------------------------------------------*/ + g_u32hiYear = (sPt->u32Year - RTC_YEAR2000) / 10; + g_u32loYear = (sPt->u32Year - RTC_YEAR2000) % 10; + g_u32hiMonth = sPt->u32cMonth / 10; + g_u32loMonth = sPt->u32cMonth % 10; + g_u32hiDay = sPt->u32cDay / 10; + g_u32loDay = sPt->u32cDay % 10; + + //u32Reg = ((sPt->u32AlarmMaskDayOfWeek & 0x1) << 31); + u32Reg = ((sPt->u32cDayOfWeek & 0x7) << 24); + //u32Reg|= ((sPt->u32AlarmMaskYear & 0x1) << 30); + u32Reg |= (g_u32hiYear << 20); + u32Reg |= (g_u32loYear << 16); + //u32Reg|= ((sPt->u32AlarmMaskMonth & 0x1) << 29); + u32Reg |= (g_u32hiMonth << 12); + u32Reg |= (g_u32loMonth << 8); + //u32Reg|= ((sPt->u32AlarmMaskDay & 0x1) << 28); + u32Reg |= (g_u32hiDay << 4); + u32Reg |= g_u32loDay; + + g_u32Reg = u32Reg; + + RTC_WriteEnable(1); + outp32(REG_RTC_CALM, (UINT32)g_u32Reg); + RTC_Check(); + + + if (g_chHourMode == RTC_CLOCK_12) + { + if (sPt->u8cAmPm == RTC_PM) /* important, range of 12-hour PM mode is 21 upto 32 */ + { + sPt->u32cHour += 20; + } + } + g_u32hiHour = sPt->u32cHour / 10; + g_u32loHour = sPt->u32cHour % 10; + g_u32hiMin = sPt->u32cMinute / 10; + g_u32loMin = sPt->u32cMinute % 10; + g_u32hiSec = sPt->u32cSecond / 10; + g_u32loSec = sPt->u32cSecond % 10; + + u32Reg = ((sPt->u32AlarmMaskHour & 0x1) << 30); + u32Reg |= (g_u32hiHour << 20); + u32Reg |= (g_u32loHour << 16); + u32Reg |= ((sPt->u32AlarmMaskMinute & 0x1) << 29); + u32Reg |= (g_u32hiMin << 12); + u32Reg |= (g_u32loMin << 8); + u32Reg |= ((sPt->u32AlarmMaskSecond & 0x1) << 28); + u32Reg |= (g_u32hiSec << 4); + u32Reg |= g_u32loSec; + + g_u32Reg = u32Reg; + + RTC_WriteEnable(1); + outp32(REG_RTC_TALM, (UINT32)g_u32Reg); + RTC_Check(); + + if (sPt->u8cClockDisplay == RTC_CLOCK_12) + { + if (sPt->u8cAmPm == RTC_PM) + { + sPt->u32cHour -= 20; + } + } + /*---------------------------------------------------------------------------------------------*/ + /* Finally, enable alarm interrupt. */ + /*---------------------------------------------------------------------------------------------*/ + + RTC_Ioctl(0, RTC_IOC_ENABLE_INT, RTC_ALARM_INT, 0); + + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, inp32(REG_RTC_PWRCTL) | RTC_PWRCTL_ALARM_EN_Msk); + RTC_Check(); + + return E_RTC_SUCCESS; + } + default: + { + return E_RTC_ERR_ENOTTY; + } + } + +} + + +/** + * @brief Support some commands for application. + * + * @param[in] i32Num Interface number. always set 0 + * @param[in] eCmd Command + * @param[in] u32Arg0 Arguments for the command + * @param[in] u32Arg1 Arguments for the command. + * + * @retval E_RTC_ERR_ENOTTY Wrong command or argument + * @retval E_RTC_ERR_ENODEV Interface number incorrect + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_Ioctl(INT32 i32Num, E_RTC_CMD eCmd, UINT32 u32Arg0, UINT32 u32Arg1) +{ + INT32 i32Ret; + UINT32 u32Reg; + RTC_TICK_T *ptick; + UINT32 u32Tmp; + + if (i32Num != 0) + return E_RTC_ERR_ENODEV; + + switch (eCmd) + { + + case RTC_IOC_IDENTIFY_LEAP_YEAR: + { + u32Reg = inp32(REG_RTC_LEAPYEAR); + if (u32Reg & 0x01) + { + *(PUINT32)u32Arg0 = RTC_LEAP_YEAR; + } + else + { + *(PUINT32)u32Arg0 = 0; + } + break; + } + case RTC_IOC_SET_TICK_MODE: + { + ptick = (RTC_TICK_T *) u32Arg0; + + if (g_bIsEnableTickInt == TRUE) + { + RTC_Ioctl(0, RTC_IOC_DISABLE_INT, RTC_TICK_INT, 0); + g_bIsEnableTickInt = TRUE; + } + + if (ptick->ucMode > RTC_TICK_1_128_SEC) /*Tick mode 0 to 7 */ + { + return E_RTC_ERR_ENOTTY ; + } + + RTC_WriteEnable(1); + outp32(REG_RTC_TICK, ptick->ucMode); + RTC_Check(); + + /*---------------------------------------------------------------------------------------------*/ + /* Reset tick interrupt status if program enable tick interrupt before. */ + /*---------------------------------------------------------------------------------------------*/ + if (g_bIsEnableTickInt == TRUE) + { + + RTC_Ioctl(0, RTC_IOC_ENABLE_INT, RTC_TICK_INT, 0); + + return E_RTC_SUCCESS; + } + break; + } + + case RTC_IOC_GET_TICK: + { + break; + } + + case RTC_IOC_RESTORE_TICK: + { + break; + } + + case RTC_IOC_ENABLE_INT: + { + + switch ((RTC_INT_SOURCE)u32Arg0) + { + + case RTC_TICK_INT: + { + g_bIsEnableTickInt = TRUE; + u32Tmp = inp32(REG_RTC_INTEN) | RTC_TICK_INT; + break; + } + case RTC_ALARM_INT: + { + g_bIsEnableAlarmInt = TRUE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_PWRCTL) | RTC_PWRCTL_ALARM_EN_Msk; + + outp32(REG_RTC_PWRCTL, u32Tmp); + outp32(REG_RTC_INTEN, inp32(REG_RTC_INTEN) | RTC_INTEN_ALMIEN_Msk); + + RTC_Check(); + + u32Tmp = inp32(REG_RTC_INTEN) | RTC_ALARM_INT; + + break; + } + case RTC_RELATIVE_ALARM_INT: + { + g_bIsEnableAlarmInt = TRUE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_PWRCTL) | RTC_PWRCTL_REL_ALARM_EN_Msk; + + outp32(REG_RTC_PWRCTL, u32Tmp); + RTC_Check(); + + u32Tmp = inp32(REG_RTC_INTEN) | RTC_RELATIVE_ALARM_INT; + break; + } + case RTC_PSWI_INT: + { + g_bIsEnableAlarmInt = TRUE; + u32Tmp = inp32(REG_RTC_INTEN) | RTC_PSWI_INT; + break; + } + default: + { + return E_RTC_ERR_ENOTTY; + + } + } + + RTC_WriteEnable(1); + outp32(REG_RTC_INTEN, u32Tmp); + RTC_Check(); + + break; + } + case RTC_IOC_DISABLE_INT: + { + + switch ((RTC_INT_SOURCE)u32Arg0) + { + case RTC_TICK_INT: + { + g_bIsEnableTickInt = FALSE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_INTEN) & (~RTC_TICK_INT); + + outp32(REG_RTC_INTEN, u32Tmp); + + outp32(REG_RTC_INTSTS, RTC_TICK_INT); + RTC_Check(); + + break; + } + case RTC_ALARM_INT: + { + g_bIsEnableAlarmInt = FALSE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_INTEN) & (~RTC_ALARM_INT); + + outp32(REG_RTC_INTEN, u32Tmp); + RTC_Check(); + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_PWRCTL) & ~RTC_PWRCTL_ALARM_EN_Msk; + + outp32(REG_RTC_PWRCTL, u32Tmp); + RTC_Check(); + + outp32(REG_RTC_INTSTS, RTC_ALARM_INT); + + break; + } + case RTC_RELATIVE_ALARM_INT: + { + g_bIsEnableAlarmInt = FALSE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_INTEN) & (~RTC_RELATIVE_ALARM_INT); + + outp32(REG_RTC_INTEN, u32Tmp); + RTC_Check(); + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_PWRCTL) & ~RTC_PWRCTL_REL_ALARM_EN_Msk; + + outp32(REG_RTC_PWRCTL, u32Tmp); + RTC_Check(); + + outp32(REG_RTC_INTSTS, RTC_RELATIVE_ALARM_INT); + + break; + } + case RTC_PSWI_INT: + { + g_bIsEnableAlarmInt = FALSE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_INTEN) & (~RTC_PSWI_INT); + + outp32(REG_RTC_INTEN, u32Tmp); + RTC_Check(); + + outp32(REG_RTC_INTSTS, RTC_PSWI_INT); + + break; + } + + case RTC_ALL_INT: + { + g_bIsEnableTickInt = FALSE; + g_bIsEnableAlarmInt = FALSE; + + RTC_WriteEnable(1); + outp32(REG_RTC_INTEN, 0); + outp32(REG_RTC_INTSTS, RTC_ALL_INT); + RTC_Check(); + + break; + } + default: + { + return E_RTC_ERR_ENOTTY; + } + } + + + break; + } + + case RTC_IOC_SET_FREQUENCY: + { + i32Ret = RTC_DoFrequencyCompensation(u32Arg0) ; + if (i32Ret != 0) + { + return E_RTC_ERR_ENOTTY; + } + break; + } + case RTC_IOC_SET_POWER_ON: + { + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_PWRCTL) | 0x01; + + outp32(REG_RTC_PWRCTL, u32Tmp); + RTC_Check(); + + while ((inp32(REG_RTC_PWRCTL) & 0x01) != 0x1); + + break; + } + case RTC_IOC_SET_POWER_OFF: + { + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, (inp32(REG_RTC_PWRCTL) & ~0x01) | 2); + RTC_Check(); + + while (1); + + //break; + } + case RTC_IOC_SET_POWER_OFF_PERIOD: + { + if (u32Arg0 < 4) u32Arg0 = 4; + + u32Arg0 = u32Arg0 - 4; + + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, (inp32(REG_RTC_PWRCTL) & ~0xF000) | ((u32Arg0 & 0xF) << 12)); + RTC_Check(); + + break; + } + case RTC_IOC_ENABLE_HW_POWEROFF: + { + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, (inp32(REG_RTC_PWRCTL) | 0x04)); + RTC_Check(); + + break; + } + case RTC_IOC_DISABLE_HW_POWEROFF: + { + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, (inp32(REG_RTC_PWRCTL) & ~0x04)); + RTC_Check(); + + break; + } + case RTC_IOC_SET_PSWI_CALLBACK: + { + + RTC_Ioctl(0, RTC_IOC_ENABLE_INT, RTC_PSWI_INT, 0); + + break; + } + case RTC_IOC_GET_POWERKEY_STATUS: + { + RTC_WriteEnable(1); + if (inp32(REG_RTC_PWRCTL) & 0x80) + *(PUINT32)u32Arg0 = 1; + else + *(PUINT32)u32Arg0 = 0; + + break; + } + case RTC_IOC_SET_RELEATIVE_ALARM: + { + g_bIsEnableAlarmInt = TRUE; + + RTC_WriteEnable(1); + outp32(REG_RTC_PWRCTL, (inp32(REG_RTC_PWRCTL) & ~0xFFF0010)); + RTC_Check(); + + RTC_WriteEnable(1); + u32Tmp = (inp32(REG_RTC_PWRCTL) & ~0xFFF0000) | ((u32Arg0 & 0xFFF) << 16) | RTC_PWRCTL_REL_ALARM_EN_Msk; + + outp32(REG_RTC_PWRCTL, u32Tmp); + RTC_Check(); + + g_bIsEnableAlarmInt = TRUE; + + RTC_WriteEnable(1); + u32Tmp = inp32(REG_RTC_INTEN) | RTC_RELATIVE_ALARM_INT; + + outp32(REG_RTC_INTEN, u32Tmp); + RTC_Check(); + + break; + + } + + default: + { + return E_RTC_ERR_ENOTTY; + } + } + + return E_RTC_SUCCESS; +} + +/** + * @brief Disable AIC channel of RTC and both tick and alarm interrupt. + * + * @param[in] None + * + * @retval E_RTC_SUCCESS Success + * + */ +UINT32 RTC_Close(void) +{ + + g_bIsEnableTickInt = FALSE; + + sysDisableInterrupt(RTC_IRQn); + + + RTC_Ioctl(0, RTC_IOC_DISABLE_INT, RTC_ALL_INT, 0); + + + return E_RTC_SUCCESS; +} + +/** + * @brief Enable RTC clock. + * + * @param[in] bEnable 1: Enable \n + * 2: Disable + * + * @return None + * + */ +void RTC_EnableClock(BOOL bEnable) +{ + if (bEnable) + outp32(REG_CLK_PCLKEN0, inp32(REG_CLK_PCLKEN0) | (1 << 2)); + else + outp32(REG_CLK_PCLKEN0, inp32(REG_CLK_PCLKEN0) & ~(1 << 2)); + +} + + + +/*@}*/ /* end of group N9H30_RTC_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_RTC_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_scuart.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_scuart.c new file mode 100644 index 0000000000000000000000000000000000000000..6656e0fe0e9aa3640297fbfe82b9ca6b7630984a --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_scuart.c @@ -0,0 +1,246 @@ +/**************************************************************************//** + * @file scuart.c + * @brief N9H30 series Smartcard UART mode (SCUART) driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "N9H30.h" +#include "nu_scuart.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_SCUART_Driver SCUART Driver + @{ +*/ + + +/** @addtogroup N9H30_SCUART_EXPORTED_FUNCTIONS SCUART Exported Functions + @{ +*/ + +/** + * @brief Disable smartcard uart interface. + * @param sc Smartcard module number + * @return None + * @details The function is used to disable smartcard interface UART mode. + */ +void SCUART_Close(UINT sc) +{ + if (sc == 0) + { + outpw(REG_SC0_INTEN, 0); + outpw(REG_SC0_UARTCTL, 0); + outpw(REG_SC0_CTL, 0); + } + else + { + outpw(REG_SC1_INTEN, 0); + outpw(REG_SC1_UARTCTL, 0); + outpw(REG_SC1_CTL, 0); + } +} + +/// @cond HIDDEN_SYMBOLS +/** + * @brief This function returns module clock of specified SC interface + * @param[in] sc Smartcard module number + * @return Module clock of specified SC interface + */ +static uint32_t SCUART_GetClock(UINT sc) +{ + uint32_t u32Div; + + if (sc == 0) + u32Div = ((inpw(REG_CLK_DIVCTL6) >> 24) & 0xF) + 1; + else + u32Div = ((inpw(REG_CLK_DIVCTL6) >> 28) & 0xF) + 1; + + return 12000000 / u32Div; +} +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief Enable smartcard uart interface. + * @param[in] sc Smartcard module number + * @param[in] u32baudrate Target baudrate of smartcard module. + * @return Actual baudrate of smartcard mode. + * @details This function use to enable smartcard module UART mode and set baudrate. + * @note This function configures character width to 8 bits, 1 stop bit, and no parity. + * And can use \ref SCUART_SetLineConfig function to update these settings. + */ +UINT SCUART_Open(UINT sc, UINT u32baudrate) +{ + uint32_t u32Clk = SCUART_GetClock(sc), u32Div; + + // Calculate divider for target baudrate + u32Div = (u32Clk + (u32baudrate >> 1) - 1) / u32baudrate - 1; + + if (sc == 0) + { + outpw(REG_SC0_CTL, SC_CTL_SCEN_Msk | SC_CTL_NSB_Msk); // Enable smartcard interface and stop bit = 1 + outpw(REG_SC0_UARTCTL, SCUART_CHAR_LEN_8 | SCUART_PARITY_NONE | SC_UARTCTL_UARTEN_Msk); // Enable UART mode, disable parity and 8 bit per character + outpw(REG_SC0_ETUCTL, u32Div); + } + else + { + outpw(REG_SC1_CTL, SC_CTL_SCEN_Msk | SC_CTL_NSB_Msk); // Enable smartcard interface and stop bit = 1 + outpw(REG_SC1_UARTCTL, SCUART_CHAR_LEN_8 | SCUART_PARITY_NONE | SC_UARTCTL_UARTEN_Msk); // Enable UART mode, disable parity and 8 bit per character + outpw(REG_SC1_ETUCTL, u32Div); + } + + return (u32Clk / (u32Div + 1)); +} + +/** + * @brief Read data from smartcard UART interface. + * @param[in] sc Smartcard module number + * @param[in] pu8RxBuf The buffer to store receive the data. + * @param[in] u32ReadBytes Target number of characters to receive. + * @return Actual character number reads to buffer. + * @details The function is used to read Rx data from RX FIFO. + * @note This function does not block and return immediately if there's no data available. + */ +UINT SCUART_Read(UINT sc, char *pu8RxBuf, UINT u32ReadBytes) +{ + uint32_t u32Count; + + if (sc == 0) + { + for (u32Count = 0; u32Count < u32ReadBytes; u32Count++) + { + if (inpw(REG_SC0_STATUS) & SC_STATUS_RXEMPTY_Msk) // no data available + { + break; + } + pu8RxBuf[u32Count] = inpw(REG_SC0_DAT); // get data from FIFO + } + } + else + { + for (u32Count = 0; u32Count < u32ReadBytes; u32Count++) + { + if (inpw(REG_SC1_STATUS) & SC_STATUS_RXEMPTY_Msk) // no data available + { + break; + } + pu8RxBuf[u32Count] = inpw(REG_SC1_DAT); // get data from FIFO + } + + } + + return u32Count; +} + +/** + * @brief This function use to config smartcard UART mode line setting. + * @param[in] sc Smartcard module number + * @param[in] u32Baudrate Target baudrate of smartcard module. If this value is 0, UART baudrate will not change. + * @param[in] u32DataWidth The data length, could be: + * - \ref SCUART_CHAR_LEN_5 + * - \ref SCUART_CHAR_LEN_6 + * - \ref SCUART_CHAR_LEN_7 + * - \ref SCUART_CHAR_LEN_8 + * @param[in] u32Parity The parity setting, could be: + * - \ref SCUART_PARITY_NONE + * - \ref SCUART_PARITY_ODD + * - \ref SCUART_PARITY_EVEN + * @param[in] u32StopBits The stop bit length, could be: + * - \ref SCUART_STOP_BIT_1 + * - \ref SCUART_STOP_BIT_2 + * @return Actual baudrate of smartcard. + * @details Smartcard UART mode is operated in LIN data frame. + */ +UINT SCUART_SetLineConfig(UINT sc, UINT u32Baudrate, UINT u32DataWidth, UINT u32Parity, UINT u32StopBits) +{ + + uint32_t u32Clk = SCUART_GetClock(sc), u32Div; + + if (u32Baudrate == 0) // keep original baudrate setting + { + u32Div = (sc == 0) ? inpw(REG_SC0_ETUCTL) & 0xFFF : inpw(REG_SC1_ETUCTL) & 0xFFF; + } + else + { + // Calculate divider for target baudrate + u32Div = (u32Clk + (u32Baudrate >> 1) - 1) / u32Baudrate - 1; + if (sc == 0) + outpw(REG_SC0_ETUCTL, u32Div); + else + outpw(REG_SC1_ETUCTL, u32Div); + } + + if (sc == 0) + { + outpw(REG_SC0_CTL, u32StopBits | SC_CTL_SCEN_Msk); // Set stop bit + outpw(REG_SC0_UARTCTL, u32Parity | u32DataWidth | SC_UARTCTL_UARTEN_Msk); // Set character width and parity + } + else + { + outpw(REG_SC1_CTL, u32StopBits | SC_CTL_SCEN_Msk); // Set stop bit + outpw(REG_SC1_UARTCTL, u32Parity | u32DataWidth | SC_UARTCTL_UARTEN_Msk); // Set character width and parity + } + return (u32Clk / (u32Div + 1)); +} + +/** + * @brief This function use to set receive timeout count. + * @param[in] sc Smartcard module number + * @param[in] u32TOC Rx timeout counter, using baudrate as counter unit. Valid range are 0~0x1FF, + * set this value to 0 will disable timeout counter. + * @return None + * @details The time-out counter resets and starts counting whenever the RX buffer received a + * new data word. Once the counter decrease to 1 and no new data is received or CPU + * does not read any data from FIFO, a receiver time-out interrupt will be generated. + */ +void SCUART_SetTimeoutCnt(UINT sc, UINT u32TOC) +{ + if (sc == 0) + outpw(REG_SC0_RXTOUT, u32TOC); + else + outpw(REG_SC1_RXTOUT, u32TOC); +} + + +/** + * @brief Write data to smartcard UART interface. + * @param[in] sc Smartcard module number + * @param[in] pu8TxBuf The buffer containing data to send to transmit FIFO. + * @param[in] u32WriteBytes Number of data to send. + * @return None + * @details This function is to write data into transmit FIFO to send data out. + * @note This function blocks until all data write into FIFO. + */ +void SCUART_Write(UINT sc, char *pu8TxBuf, UINT u32WriteBytes) +{ + uint32_t u32Count; + + if (sc == 0) + { + for (u32Count = 0; u32Count != u32WriteBytes; u32Count++) + { + while (inpw(REG_SC0_STATUS) & SC_STATUS_TXFULL_Msk); // Wait 'til FIFO not full + outpw(REG_SC0_DAT, pu8TxBuf[u32Count]); // Write 1 byte to FIFO + } + } + else + { + for (u32Count = 0; u32Count != u32WriteBytes; u32Count++) + { + while (inpw(REG_SC0_STATUS) & SC_STATUS_TXFULL_Msk); // Wait 'til FIFO not full + outpw(REG_SC1_DAT, pu8TxBuf[u32Count]); // Write 1 byte to FIFO + } + } +} + + +/*@}*/ /* end of group N9H30_SCUART_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SCUART_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sdh.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sdh.c new file mode 100644 index 0000000000000000000000000000000000000000..3d0306b43f2d2ab15a7807b1f151cc5a69bf5504 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sdh.c @@ -0,0 +1,1193 @@ +/**************************************************************************//** + * @file sdh.c + * @brief N9H30 SDH driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include +#include +#include +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_sdh.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_SDH_Driver SDH Driver + @{ +*/ + + +/** @addtogroup N9H30_SDH_EXPORTED_FUNCTIONS SDH Exported Functions + @{ +*/ +#define SDH_BLOCK_SIZE 512ul + +/** @cond HIDDEN_SYMBOLS */ + +/* global variables */ +/* For response R3 (such as ACMD41, CRC-7 is invalid; but SD controller will still */ +/* calculate CRC-7 and get an error result, software should ignore this error and clear SDISR [CRC_IF] flag */ +/* _sd_uR3_CMD is the flag for it. 1 means software should ignore CRC-7 error */ + +#ifdef __ICCARM__ + #pragma data_alignment = 32 + static uint8_t _SDH0_ucSDHCBuffer[512]; + static uint8_t _SDH1_ucSDHCBuffer[512]; +#else + static uint8_t _SDH0_ucSDHCBuffer[512] __attribute__((aligned(32))); + static uint8_t _SDH1_ucSDHCBuffer[512] __attribute__((aligned(32))); +#endif + +SDH_INFO_T SD0, SD1; + +void SDH_CheckRB(SDH_T *sdh) +{ + while (1) + { + sdh->CTL |= SDH_CTL_CLK8OEN_Msk; + while ((sdh->CTL & SDH_CTL_CLK8OEN_Msk) == SDH_CTL_CLK8OEN_Msk) + { + } + if ((sdh->INTSTS & SDH_INTSTS_DAT0STS_Msk) == SDH_INTSTS_DAT0STS_Msk) + { + break; + } + } +} + + +uint32_t SDH_SDCommand(SDH_T *sdh, uint32_t ucCmd, uint32_t uArg) +{ + volatile uint32_t buf, val = 0ul; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + sdh->CMDARG = uArg; + buf = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (ucCmd << 8ul) | (SDH_CTL_COEN_Msk); + sdh->CTL = buf; + + while ((sdh->CTL & SDH_CTL_COEN_Msk) == SDH_CTL_COEN_Msk) + { + if (pSD->IsCardInsert == 0ul) + { + val = SDH_NO_SD_CARD; + } + } + return val; +} + + +uint32_t SDH_SDCmdAndRsp(SDH_T *sdh, uint32_t ucCmd, uint32_t uArg, uint32_t ntickCount) +{ + volatile uint32_t buf; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + sdh->CMDARG = uArg; + buf = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (ucCmd << 8ul) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk); + sdh->CTL = buf; + + if (ntickCount > 0ul) + { + while ((sdh->CTL & SDH_CTL_RIEN_Msk) == SDH_CTL_RIEN_Msk) + { + if (ntickCount-- == 0ul) + { + sdh->CTL |= SDH_CTL_CTLRST_Msk; /* reset SD engine */ + return 2ul; + } + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + } + else + { + while ((sdh->CTL & SDH_CTL_RIEN_Msk) == SDH_CTL_RIEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + } + + if (pSD->R7Flag) + { + uint32_t tmp0 = 0ul, tmp1 = 0ul; + tmp1 = sdh->RESP1 & 0xfful; + tmp0 = sdh->RESP0 & 0xful; + if ((tmp1 != 0x55ul) && (tmp0 != 0x01ul)) + { + pSD->R7Flag = 0ul; + return SDH_CMD8_ERROR; + } + } + + if (!pSD->R3Flag) + { + if ((sdh->INTSTS & SDH_INTSTS_CRC7_Msk) == SDH_INTSTS_CRC7_Msk) /* check CRC7 */ + { + return Successful; + } + else + { + return SDH_CRC7_ERROR; + } + } + else + { + /* ignore CRC error for R3 case */ + pSD->R3Flag = 0ul; + sdh->INTSTS = SDH_INTSTS_CRCIF_Msk; + return Successful; + } +} + + +uint32_t SDH_Swap32(uint32_t val) +{ + uint32_t buf; + + buf = val; + val <<= 24; + val |= (buf << 8) & 0xff0000ul; + val |= (buf >> 8) & 0xff00ul; + val |= (buf >> 24) & 0xfful; + return val; +} + +/* Get 16 bytes CID or CSD */ +uint32_t SDH_SDCmdAndRsp2(SDH_T *sdh, uint32_t ucCmd, uint32_t uArg, uint32_t puR2ptr[]) +{ + uint32_t i, buf; + uint32_t tmpBuf[5]; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + sdh->CMDARG = uArg; + buf = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (ucCmd << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_R2EN_Msk); + sdh->CTL = buf; + + while ((sdh->CTL & SDH_CTL_R2EN_Msk) == SDH_CTL_R2EN_Msk) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC7_Msk) == SDH_INTSTS_CRC7_Msk) + { + for (i = 0ul; i < 5ul; i++) + { + tmpBuf[i] = SDH_Swap32(sdh->FB[i]); + } + for (i = 0ul; i < 4ul; i++) + { + puR2ptr[i] = ((tmpBuf[i] & 0x00fffffful) << 8) | ((tmpBuf[i + 1ul] & 0xff000000ul) >> 24); + } + } + else + { + return SDH_CRC7_ERROR; + } + return Successful; +} + + +uint32_t SDH_SDCmdAndRspDataIn(SDH_T *sdh, uint32_t ucCmd, uint32_t uArg) +{ + volatile uint32_t buf; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + sdh->CMDARG = uArg; + buf = (sdh->CTL & (~SDH_CTL_CMDCODE_Msk)) | (ucCmd << 8ul) | + (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DIEN_Msk); + + sdh->CTL = buf; + + while ((sdh->CTL & SDH_CTL_RIEN_Msk) == SDH_CTL_RIEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + while ((sdh->CTL & SDH_CTL_DIEN_Msk) == SDH_CTL_DIEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC7_Msk) != SDH_INTSTS_CRC7_Msk) + { + /* check CRC7 */ + return SDH_CRC7_ERROR; + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC16_Msk) != SDH_INTSTS_CRC16_Msk) + { + /* check CRC16 */ + return SDH_CRC16_ERROR; + } + return 0ul; +} + +/* there are 8 bits for divider0, maximum is 256 */ +#define SDH_CLK_DIV0_MAX 256ul + +void SDH_Set_clock(SDH_T *sdh, uint32_t sd_clock_khz) +{ + UINT32 div; + uint32_t SDH_ReferenceClock; + + if (sd_clock_khz <= 2000) + { + SDH_ReferenceClock = 12000; + if (sdh == SDH0) + { + outpw(REG_CLK_DIVCTL9, (inpw(REG_CLK_DIVCTL9) & ~0x18) | (0x0 << 3)); // SD clock from XIN [4:3] + } + else + { + //fixme outpw(REG_CLK_DIVCTL9, (inpw(REG_CLK_DIVCTL9) & ~0x18) | (0x0 << 3)); // SD clock from XIN [4:3] + } + } + else + { + SDH_ReferenceClock = 300000; + if (sdh == SDH0) + { + outpw(REG_CLK_DIVCTL9, (inpw(REG_CLK_DIVCTL9) & ~0x18) | (0x3 << 3)); // SD clock from UPLL [4:3] + } + else + { + //fixme outpw(REG_CLK_DIVCTL9, (inpw(REG_CLK_DIVCTL9) & ~0x18) | (0x3 << 3)); // SD clock from UPLL [4:3] + } + } + div = (SDH_ReferenceClock / sd_clock_khz) - 1; + + if (div >= SDH_CLK_DIV0_MAX) + { + div = 0xff; + } + outpw(REG_CLK_DIVCTL9, (inpw(REG_CLK_DIVCTL9) & ~0xff00) | ((div) << 8)); // SD clock divided by CLKDIV3[SD_N] [15:8] +} + +uint32_t SDH_CardDetection(SDH_T *sdh) +{ + uint32_t i, val = TRUE; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + + if ((sdh->INTEN & SDH_INTEN_CDSRC_Msk) == SDH_INTEN_CDSRC_Msk) /* Card detect pin from GPIO */ + { + if ((sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) == SDH_INTSTS_CDSTS_Msk) /* Card remove */ + { + pSD->IsCardInsert = (uint8_t)FALSE; + val = FALSE; + } + else + { + pSD->IsCardInsert = (uint8_t)TRUE; + } + } + else if ((sdh->INTEN & SDH_INTEN_CDSRC_Msk) != SDH_INTEN_CDSRC_Msk) + { + sdh->CTL |= SDH_CTL_CLKKEEP_Msk; + for (i = 0ul; i < 5000ul; i++) + { + } + + if ((sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) == SDH_INTSTS_CDSTS_Msk) /* Card insert */ + { + pSD->IsCardInsert = (uint8_t)TRUE; + } + else + { + pSD->IsCardInsert = (uint8_t)FALSE; + val = FALSE; + } + + sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk; + } + + return val; +} + +uint32_t SDH_Init(SDH_T *sdh) +{ + uint32_t volatile i, status; + uint32_t resp; + uint32_t CIDBuffer[4]; + uint32_t volatile u32CmdTimeOut; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + /* set the clock to 300KHz */ + SDH_Set_clock(sdh, 300ul); + + /* power ON 74 clock */ + sdh->CTL |= SDH_CTL_CLK74OEN_Msk; + + while ((sdh->CTL & SDH_CTL_CLK74OEN_Msk) == SDH_CTL_CLK74OEN_Msk) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + SDH_SDCommand(sdh, 0ul, 0ul); /* reset all cards */ + for (i = 0x1000ul; i > 0ul; i--) + { + } + + /* initial SDHC */ + pSD->R7Flag = 1ul; + u32CmdTimeOut = 0xFFFFFul; + + i = SDH_SDCmdAndRsp(sdh, 8ul, 0x00000155ul, u32CmdTimeOut); + if (i == Successful) + { + /* SD 2.0 */ + SDH_SDCmdAndRsp(sdh, 55ul, 0x00ul, u32CmdTimeOut); + pSD->R3Flag = 1ul; + SDH_SDCmdAndRsp(sdh, 41ul, 0x40ff8000ul, u32CmdTimeOut); /* 2.7v-3.6v */ + resp = sdh->RESP0; + + while ((resp & 0x00800000ul) != 0x00800000ul) /* check if card is ready */ + { + SDH_SDCmdAndRsp(sdh, 55ul, 0x00ul, u32CmdTimeOut); + pSD->R3Flag = 1ul; + SDH_SDCmdAndRsp(sdh, 41ul, 0x40ff8000ul, u32CmdTimeOut); /* 3.0v-3.4v */ + resp = sdh->RESP0; + } + if ((resp & 0x00400000ul) == 0x00400000ul) + { + pSD->CardType = SDH_TYPE_SD_HIGH; + } + else + { + pSD->CardType = SDH_TYPE_SD_LOW; + } + } + else + { + /* SD 1.1 */ + SDH_SDCommand(sdh, 0ul, 0ul); /* reset all cards */ + for (i = 0x100ul; i > 0ul; i--) + { + } + + i = SDH_SDCmdAndRsp(sdh, 55ul, 0x00ul, u32CmdTimeOut); + if (i == 2ul) /* MMC memory */ + { + + SDH_SDCommand(sdh, 0ul, 0ul); /* reset */ + for (i = 0x100ul; i > 0ul; i--) + { + } + + pSD->R3Flag = 1ul; + + if (SDH_SDCmdAndRsp(sdh, 1ul, 0x40ff8000ul, u32CmdTimeOut) != 2ul) /* eMMC memory */ + { + resp = sdh->RESP0; + while ((resp & 0x00800000ul) != 0x00800000ul) + { + /* check if card is ready */ + pSD->R3Flag = 1ul; + + SDH_SDCmdAndRsp(sdh, 1ul, 0x40ff8000ul, u32CmdTimeOut); /* high voltage */ + resp = sdh->RESP0; + } + + if ((resp & 0x00400000ul) == 0x00400000ul) + { + pSD->CardType = SDH_TYPE_EMMC; + } + else + { + pSD->CardType = SDH_TYPE_MMC; + } + } + else + { + pSD->CardType = SDH_TYPE_UNKNOWN; + return SDH_ERR_DEVICE; + } + } + else if (i == 0ul) /* SD Memory */ + { + pSD->R3Flag = 1ul; + SDH_SDCmdAndRsp(sdh, 41ul, 0x00ff8000ul, u32CmdTimeOut); /* 3.0v-3.4v */ + resp = sdh->RESP0; + while ((resp & 0x00800000ul) != 0x00800000ul) /* check if card is ready */ + { + SDH_SDCmdAndRsp(sdh, 55ul, 0x00ul, u32CmdTimeOut); + pSD->R3Flag = 1ul; + SDH_SDCmdAndRsp(sdh, 41ul, 0x00ff8000ul, u32CmdTimeOut); /* 3.0v-3.4v */ + resp = sdh->RESP0; + } + pSD->CardType = SDH_TYPE_SD_LOW; + } + else + { + pSD->CardType = SDH_TYPE_UNKNOWN; + return SDH_INIT_ERROR; + } + } + + if (pSD->CardType != SDH_TYPE_UNKNOWN) + { + SDH_SDCmdAndRsp2(sdh, 2ul, 0x00ul, CIDBuffer); + if ((pSD->CardType == SDH_TYPE_MMC) || (pSD->CardType == SDH_TYPE_EMMC)) + { + if ((status = SDH_SDCmdAndRsp(sdh, 3ul, 0x10000ul, 0ul)) != Successful) /* set RCA */ + { + return status; + } + pSD->RCA = 0x10000ul; + } + else + { + if ((status = SDH_SDCmdAndRsp(sdh, 3ul, 0x00ul, 0ul)) != Successful) /* get RCA */ + { + return status; + } + else + { + pSD->RCA = (sdh->RESP0 << 8) & 0xffff0000; + } + } + } + return Successful; +} + + +uint32_t SDH_SwitchToHighSpeed(SDH_T *sdh, SDH_INFO_T *pSD) +{ + uint32_t volatile status = 0ul; + uint16_t current_comsumption, busy_status0; + + sdh->DMASA = (uint32_t)pSD->dmabuf; + sdh->BLEN = 63ul; + + if ((status = SDH_SDCmdAndRspDataIn(sdh, 6ul, 0x00ffff01ul)) != Successful) + { + return Fail; + } + + current_comsumption = (uint16_t)(*pSD->dmabuf) << 8; + current_comsumption |= (uint16_t)(*(pSD->dmabuf + 1)); + if (!current_comsumption) + { + return Fail; + } + + busy_status0 = (uint16_t)(*(pSD->dmabuf + 28)) << 8; + busy_status0 |= (uint16_t)(*(pSD->dmabuf + 29)); + + if (!busy_status0) /* function ready */ + { + sdh->DMASA = (uint32_t)pSD->dmabuf; + sdh->BLEN = 63ul; /* 512 bit */ + + if ((status = SDH_SDCmdAndRspDataIn(sdh, 6ul, 0x80ffff01ul)) != Successful) + { + return Fail; + } + + /* function change timing: 8 clocks */ + sdh->CTL |= SDH_CTL_CLK8OEN_Msk; + while ((sdh->CTL & SDH_CTL_CLK8OEN_Msk) == SDH_CTL_CLK8OEN_Msk) + { + } + + current_comsumption = (uint16_t)(*pSD->dmabuf) << 8; + current_comsumption |= (uint16_t)(*(pSD->dmabuf + 1)); + if (!current_comsumption) + { + return Fail; + } + + return Successful; + } + else + { + return Fail; + } +} + + +uint32_t SDH_SelectCardType(SDH_T *sdh) +{ + uint32_t volatile status = 0ul; + uint32_t param; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + if ((status = SDH_SDCmdAndRsp(sdh, 7ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + + SDH_CheckRB(sdh); + + /* if SD card set 4bit */ + if (pSD->CardType == SDH_TYPE_SD_HIGH) + { + sdh->DMASA = (uint32_t)pSD->dmabuf; + sdh->BLEN = 0x07ul; /* 64 bit */ + sdh->DMACTL |= SDH_DMACTL_DMARST_Msk; + while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == 0x2); + + if ((status = SDH_SDCmdAndRsp(sdh, 55ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + if ((status = SDH_SDCmdAndRspDataIn(sdh, 51ul, 0x00ul)) != Successful) + { + return status; + } + + if ((*pSD->dmabuf & 0xful) == 0x2ul) + { + status = SDH_SwitchToHighSpeed(sdh, pSD); + if (status == Successful) + { + /* divider */ + SDH_Set_clock(sdh, SDHC_FREQ); + } + } + + if ((status = SDH_SDCmdAndRsp(sdh, 55ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + if ((status = SDH_SDCmdAndRsp(sdh, 6ul, 0x02ul, 0ul)) != Successful) /* set bus width */ + { + return status; + } + + sdh->CTL |= SDH_CTL_DBW_Msk; + } + else if (pSD->CardType == SDH_TYPE_SD_LOW) + { + sdh->DMASA = (uint32_t)pSD->dmabuf;; + sdh->BLEN = 0x07ul; + + if ((status = SDH_SDCmdAndRsp(sdh, 55ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + if ((status = SDH_SDCmdAndRspDataIn(sdh, 51ul, 0x00ul)) != Successful) + { + return status; + } + + /* set data bus width. ACMD6 for SD card, SDCR_DBW for host. */ + if ((status = SDH_SDCmdAndRsp(sdh, 55ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + + if ((status = SDH_SDCmdAndRsp(sdh, 6ul, 0x02ul, 0ul)) != Successful) + { + return status; + } + + sdh->CTL |= SDH_CTL_DBW_Msk; + } + else if ((pSD->CardType == SDH_TYPE_MMC) || (pSD->CardType == SDH_TYPE_EMMC)) + { + + if (pSD->CardType == SDH_TYPE_MMC) + { + sdh->CTL &= ~SDH_CTL_DBW_Msk; + } + + /*--- sent CMD6 to MMC card to set bus width to 4 bits mode */ + /* set CMD6 argument Access field to 3, Index to 183, Value to 1 (4-bit mode) */ + param = (3ul << 24) | (183ul << 16) | (1ul << 8); + if ((status = SDH_SDCmdAndRsp(sdh, 6ul, param, 0ul)) != Successful) + { + return status; + } + SDH_CheckRB(sdh); + + sdh->CTL |= SDH_CTL_DBW_Msk; /* set bus width to 4-bit mode for SD host controller */ + + } + + if ((status = SDH_SDCmdAndRsp(sdh, 16ul, SDH_BLOCK_SIZE, 0ul)) != Successful) + { + return status; + } + sdh->BLEN = SDH_BLOCK_SIZE - 1ul; + + SDH_SDCommand(sdh, 7ul, 0ul); + sdh->CTL |= SDH_CTL_CLK8OEN_Msk; + while ((sdh->CTL & SDH_CTL_CLK8OEN_Msk) == SDH_CTL_CLK8OEN_Msk) + { + } + + sdh->INTEN |= SDH_INTEN_BLKDIEN_Msk; + + return Successful; +} + +void SDH_Get_SD_info(SDH_T *sdh) +{ + unsigned int R_LEN, C_Size, MULT, size; + uint32_t Buffer[4]; + //unsigned char *ptr; + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + SDH_SDCmdAndRsp2(sdh, 9ul, pSD->RCA, Buffer); + + if ((pSD->CardType == SDH_TYPE_MMC) || (pSD->CardType == SDH_TYPE_EMMC)) + { + /* for MMC/eMMC card */ + if ((Buffer[0] & 0xc0000000) == 0xc0000000) + { + /* CSD_STRUCTURE [127:126] is 3 */ + /* CSD version depend on EXT_CSD register in eMMC v4.4 for card size > 2GB */ + SDH_SDCmdAndRsp(sdh, 7ul, pSD->RCA, 0ul); + + //ptr = (uint8_t *)((uint32_t)_SDH_ucSDHCBuffer ); + sdh->DMASA = (uint32_t)pSD->dmabuf;; + sdh->BLEN = 511ul; /* read 512 bytes for EXT_CSD */ + + if (SDH_SDCmdAndRspDataIn(sdh, 8ul, 0x00ul) == Successful) + { + SDH_SDCommand(sdh, 7ul, 0ul); + sdh->CTL |= SDH_CTL_CLK8OEN_Msk; + while ((sdh->CTL & SDH_CTL_CLK8OEN_Msk) == SDH_CTL_CLK8OEN_Msk) + { + } + + pSD->totalSectorN = (uint32_t)(*(pSD->dmabuf + 215)) << 24; + pSD->totalSectorN |= (uint32_t)(*(pSD->dmabuf + 214)) << 16; + pSD->totalSectorN |= (uint32_t)(*(pSD->dmabuf + 213)) << 8; + pSD->totalSectorN |= (uint32_t)(*(pSD->dmabuf + 212)); + pSD->diskSize = pSD->totalSectorN / 2ul; + } + } + else + { + /* CSD version v1.0/1.1/1.2 in eMMC v4.4 spec for card size <= 2GB */ + R_LEN = (Buffer[1] & 0x000f0000ul) >> 16; + C_Size = ((Buffer[1] & 0x000003fful) << 2) | ((Buffer[2] & 0xc0000000ul) >> 30); + MULT = (Buffer[2] & 0x00038000ul) >> 15; + size = (C_Size + 1ul) * (1ul << (MULT + 2ul)) * (1ul << R_LEN); + + pSD->diskSize = size / 1024ul; + pSD->totalSectorN = size / 512ul; + } + } + else + { + if ((Buffer[0] & 0xc0000000) != 0x0ul) + { + C_Size = ((Buffer[1] & 0x0000003ful) << 16) | ((Buffer[2] & 0xffff0000ul) >> 16); + size = (C_Size + 1ul) * 512ul; /* Kbytes */ + + pSD->diskSize = size; + pSD->totalSectorN = size << 1; + } + else + { + R_LEN = (Buffer[1] & 0x000f0000ul) >> 16; + C_Size = ((Buffer[1] & 0x000003fful) << 2) | ((Buffer[2] & 0xc0000000ul) >> 30); + MULT = (Buffer[2] & 0x00038000ul) >> 15; + size = (C_Size + 1ul) * (1ul << (MULT + 2ul)) * (1ul << R_LEN); + + pSD->diskSize = size / 1024ul; + pSD->totalSectorN = size / 512ul; + } + } + pSD->sectorSize = (int)512; +// printf("The size is %d KB\n", pSD->diskSize); +} + +/** @endcond HIDDEN_SYMBOLS */ + + +/** + * @brief This function use to reset SD function and select card detection source and pin. + * + * @param[in] sdh Select SDH0 or SDH1. + * @param[in] u32CardDetSrc Select card detection pin from GPIO or DAT3 pin. ( \ref CardDetect_From_GPIO / \ref CardDetect_From_DAT3) + * + * @return None + */ +void SDH_Open(SDH_T *sdh, uint32_t u32CardDetSrc) +{ + volatile int i; + sdh->DMACTL = SDH_DMACTL_DMARST_Msk; + while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) + { + } + + sdh->DMACTL = SDH_DMACTL_DMAEN_Msk; + + sdh->GCTL = SDH_GCTL_GCTLRST_Msk | SDH_GCTL_SDEN_Msk; + while ((sdh->GCTL & SDH_GCTL_GCTLRST_Msk) == SDH_GCTL_GCTLRST_Msk) + { + } + + if (sdh == SDH0) + { + memset(&SD0, 0, sizeof(SDH_INFO_T)); + SD0.dmabuf = (unsigned char *)((uint32_t)_SDH0_ucSDHCBuffer | 0x80000000); + } + else if (sdh == SDH1) + { + memset(&SD1, 0, sizeof(SDH_INFO_T)); + SD1.dmabuf = (unsigned char *)((uint32_t)_SDH1_ucSDHCBuffer | 0x80000000); + } + else + { + } + + sdh->GCTL = SDH_GCTL_SDEN_Msk; + + if ((u32CardDetSrc & CardDetect_From_DAT3) == CardDetect_From_DAT3) + { + sdh->INTEN &= ~SDH_INTEN_CDSRC_Msk; + } + else + { + sdh->INTEN |= SDH_INTEN_CDSRC_Msk; + } + for (i = 0; i < 0x100; i++); + sdh->INTSTS = SDH_INTSTS_CDIF_Msk; + sdh->INTEN |= SDH_INTEN_CDIEN_Msk; + + sdh->CTL |= SDH_CTL_CTLRST_Msk; + while ((sdh->CTL & SDH_CTL_CTLRST_Msk) == SDH_CTL_CTLRST_Msk) + { + } +} + +/** + * @brief This function use to initial SD card. + * + * @param[in] sdh Select SDH0 or SDH1. + * + * @return None + * + * @details This function is used to initial SD card. + * SD initial state needs 400KHz clock output, driver will use HIRC for SD initial clock source. + * And then switch back to the user's setting. + */ +uint32_t SDH_Probe(SDH_T *sdh) +{ + uint32_t val; + + sdh->GINTEN = 0ul; + sdh->CTL &= ~SDH_CTL_SDNWR_Msk; + sdh->CTL |= 0x09ul << SDH_CTL_SDNWR_Pos; /* set SDNWR = 9 */ + sdh->CTL &= ~SDH_CTL_BLKCNT_Msk; + sdh->CTL |= 0x01ul << SDH_CTL_BLKCNT_Pos; /* set BLKCNT = 1 */ + sdh->CTL &= ~SDH_CTL_DBW_Msk; /* SD 1-bit data bus */ + + if (!(SDH_CardDetection(sdh))) + { + return SDH_NO_SD_CARD; + } + + if ((val = SDH_Init(sdh)) != 0ul) + { + return val; + } + + /* divider */ + if ((SD0.CardType == SDH_TYPE_MMC) || (SD1.CardType == SDH_TYPE_MMC)) + { + SDH_Set_clock(sdh, MMC_FREQ); + } + else + { + SDH_Set_clock(sdh, SD_FREQ); + } + SDH_Get_SD_info(sdh); + + if ((val = SDH_SelectCardType(sdh)) != 0ul) + { + return val; + } + + return 0ul; +} + +/** + * @brief This function use to read data from SD card. + * + * @param[in] sdh Select SDH0 or SDH1. + * @param[out] pu8BufAddr The buffer to receive the data from SD card. + * @param[in] u32StartSec The start read sector address. + * @param[in] u32SecCount The the read sector number of data + * + * @return None + */ +uint32_t SDH_Read(SDH_T *sdh, uint8_t *pu8BufAddr, uint32_t u32StartSec, uint32_t u32SecCount) +{ + uint32_t volatile bIsSendCmd = FALSE, buf; + uint32_t volatile reg; + uint32_t volatile i, loop, status; + uint32_t blksize = SDH_BLOCK_SIZE; + + SDH_INFO_T *pSD; + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + if (u32SecCount == 0ul) + { + return SDH_SELECT_ERROR; + } + + if ((status = SDH_SDCmdAndRsp(sdh, 7ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + SDH_CheckRB(sdh); + + sdh->BLEN = blksize - 1ul; /* the actual byte count is equal to (SDBLEN+1) */ + + if ((pSD->CardType == SDH_TYPE_SD_HIGH) || (pSD->CardType == SDH_TYPE_EMMC)) + { + sdh->CMDARG = u32StartSec; + } + else + { + sdh->CMDARG = u32StartSec * blksize; + } + + sdh->DMASA = (uint32_t)pu8BufAddr; + + loop = u32SecCount / 255ul; + for (i = 0ul; i < loop; i++) + { + pSD->DataReadyFlag = (uint8_t)FALSE; + reg = sdh->CTL & ~SDH_CTL_CMDCODE_Msk; + reg = reg | 0xff0000ul; /* set BLK_CNT to 255 */ + if (bIsSendCmd == FALSE) + { + sdh->CTL = reg | (18ul << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DIEN_Msk); + bIsSendCmd = TRUE; + } + else + { + sdh->CTL = reg | SDH_CTL_DIEN_Msk; + } + + while (!pSD->DataReadyFlag) + { + if (pSD->DataReadyFlag) + { + break; + } + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC7_Msk) != SDH_INTSTS_CRC7_Msk) /* check CRC7 */ + { + return SDH_CRC7_ERROR; + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC16_Msk) != SDH_INTSTS_CRC16_Msk) /* check CRC16 */ + { + return SDH_CRC16_ERROR; + } + } + + loop = u32SecCount % 255ul; + if (loop != 0ul) + { + pSD->DataReadyFlag = (uint8_t)FALSE; + reg = sdh->CTL & (~SDH_CTL_CMDCODE_Msk); + reg = reg & (~SDH_CTL_BLKCNT_Msk); + reg |= (loop << 16); /* setup SDCR_BLKCNT */ + + if (bIsSendCmd == FALSE) + { + sdh->CTL = reg | (18ul << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DIEN_Msk); + bIsSendCmd = TRUE; + } + else + { + sdh->CTL = reg | SDH_CTL_DIEN_Msk; + } + + while (!pSD->DataReadyFlag) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC7_Msk) != SDH_INTSTS_CRC7_Msk) /* check CRC7 */ + { + return SDH_CRC7_ERROR; + } + + if ((sdh->INTSTS & SDH_INTSTS_CRC16_Msk) != SDH_INTSTS_CRC16_Msk) /* check CRC16 */ + { + return SDH_CRC16_ERROR; + } + } + + if (SDH_SDCmdAndRsp(sdh, 12ul, 0ul, 0ul)) /* stop command */ + { + return SDH_CRC7_ERROR; + } + SDH_CheckRB(sdh); + + SDH_SDCommand(sdh, 7ul, 0ul); + sdh->CTL |= SDH_CTL_CLK8OEN_Msk; + while ((sdh->CTL & SDH_CTL_CLK8OEN_Msk) == SDH_CTL_CLK8OEN_Msk) + { + } + + return Successful; +} + + +/** + * @brief This function use to write data to SD card. + * + * @param[in] sdh Select SDH0 or SDH1. + * @param[in] pu8BufAddr The buffer to send the data to SD card. + * @param[in] u32StartSec The start write sector address. + * @param[in] u32SecCount The the write sector number of data. + * + * @return \ref SDH_SELECT_ERROR : u32SecCount is zero. \n + * \ref SDH_NO_SD_CARD : SD card be removed. \n + * \ref SDH_CRC_ERROR : CRC error happen. \n + * \ref SDH_CRC7_ERROR : CRC7 error happen. \n + * \ref Successful : Write data to SD card success. + */ +uint32_t SDH_Write(SDH_T *sdh, uint8_t *pu8BufAddr, uint32_t u32StartSec, uint32_t u32SecCount) +{ + uint32_t volatile bIsSendCmd = FALSE; + uint32_t volatile reg; + uint32_t volatile i, loop, status; + + SDH_INFO_T *pSD; + + if (sdh == SDH0) + { + pSD = &SD0; + } + else + { + pSD = &SD1; + } + + if (u32SecCount == 0ul) + { + return SDH_SELECT_ERROR; + } + + if ((status = SDH_SDCmdAndRsp(sdh, 7ul, pSD->RCA, 0ul)) != Successful) + { + return status; + } + + SDH_CheckRB(sdh); + + /* According to SD Spec v2.0, the write CMD block size MUST be 512, and the start address MUST be 512*n. */ + sdh->BLEN = SDH_BLOCK_SIZE - 1ul; + + if ((pSD->CardType == SDH_TYPE_SD_HIGH) || (pSD->CardType == SDH_TYPE_EMMC)) + { + sdh->CMDARG = u32StartSec; + } + else + { + sdh->CMDARG = u32StartSec * SDH_BLOCK_SIZE; /* set start address for SD CMD */ + } + + sdh->DMASA = (uint32_t)pu8BufAddr; + loop = u32SecCount / 255ul; /* the maximum block count is 0xFF=255 for register SDCR[BLK_CNT] */ + for (i = 0ul; i < loop; i++) + { + pSD->DataReadyFlag = (uint8_t)FALSE; + reg = sdh->CTL & 0xff00c080; + reg = reg | 0xff0000ul; /* set BLK_CNT to 0xFF=255 */ + if (!bIsSendCmd) + { + sdh->CTL = reg | (25ul << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DOEN_Msk); + bIsSendCmd = TRUE; + } + else + { + sdh->CTL = reg | SDH_CTL_DOEN_Msk; + } + + while (!pSD->DataReadyFlag) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + if ((sdh->INTSTS & SDH_INTSTS_CRCIF_Msk) != 0ul) + { + sdh->INTSTS = SDH_INTSTS_CRCIF_Msk; + return SDH_CRC_ERROR; + } + } + + loop = u32SecCount % 255ul; + if (loop != 0ul) + { + pSD->DataReadyFlag = (uint8_t)FALSE; + reg = (sdh->CTL & 0xff00c080) | (loop << 16); + if (!bIsSendCmd) + { + sdh->CTL = reg | (25ul << 8) | (SDH_CTL_COEN_Msk | SDH_CTL_RIEN_Msk | SDH_CTL_DOEN_Msk); + bIsSendCmd = TRUE; + } + else + { + sdh->CTL = reg | SDH_CTL_DOEN_Msk; + } + + while (!pSD->DataReadyFlag) + { + if (pSD->IsCardInsert == FALSE) + { + return SDH_NO_SD_CARD; + } + } + + if ((sdh->INTSTS & SDH_INTSTS_CRCIF_Msk) != 0ul) + { + sdh->INTSTS = SDH_INTSTS_CRCIF_Msk; + return SDH_CRC_ERROR; + } + } + sdh->INTSTS = SDH_INTSTS_CRCIF_Msk; + + if (SDH_SDCmdAndRsp(sdh, 12ul, 0ul, 0ul)) /* stop command */ + { + return SDH_CRC7_ERROR; + } + SDH_CheckRB(sdh); + + SDH_SDCommand(sdh, 7ul, 0ul); + sdh->CTL |= SDH_CTL_CLK8OEN_Msk; + while ((sdh->CTL & SDH_CTL_CLK8OEN_Msk) == SDH_CTL_CLK8OEN_Msk) + { + } + + return Successful; +} + +/*@}*/ /* end of group N9H30_SD_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SD_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + + + + + + + + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_spi.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..3f631238fa3993c013e7a45bcfaaba4b82cbeac1 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_spi.c @@ -0,0 +1,336 @@ +/**************************************************************************//** +* @file spi.c +* @brief N9H30 SPI driver source file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +/* Header files */ +#include +#include + +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_spi.h" +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_SPI_Driver SPI Driver + @{ +*/ + +/** @addtogroup N9H30_SPI_EXPORTED_CONSTANTS SPI Exported Constants + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +#define spi_out(dev, byte, addr) outpw((dev)->base + addr, byte) +#define spi_in(dev, addr) inpw((dev)->base + addr) + +typedef struct +{ + uint32_t base; /* spi bus number */ + uint8_t openflag; + uint8_t intflag; +} spi_dev; + +/// @endcond HIDDEN_SYMBOLS +/*@}*/ /* end of group N9H30_EMAC_EXPORTED_CONSTANTS */ + +/** @addtogroup N9H30_SPI_EXPORTED_FUNCTIONS SPI Exported Functions + @{ +*/ +/// @cond HIDDEN_SYMBOLS + +static spi_dev spi_device[SPI_NUMBER]; + +#if 0 +/** + * @brief SPI-0 Interrupt handler + * @param None + * @return None + */ +static void spi0ISR(void) +{ + // clear interrupt flag + outpw(REG_SPI0_CNTRL, spi_in((spi_dev *)((uint32_t)&spi_device[0]), CNTRL) | 0x1 << 16); + spi_device[0].intflag = 1; +} + +/** + * @brief SPI-1 Interrupt handler + * @param None + * @return None + */ +static void spi1ISR(void) +{ + // clear interrupt flag + outpw(REG_SPI1_CNTRL, spi_in((spi_dev *)((uint32_t)&spi_device[1]), CNTRL) | 0x1 << 16); + spi_device[1].intflag = 1; +} +#endif + +/** + * @brief Set SPI divider + * @param[in] dev pointer to spi interface structure + * @param[in] speed desire spi speed + * @return speed set actually + */ +static uint32_t spiSetSpeed(spi_dev *dev, uint32_t speed) +{ + uint16_t div = (uint16_t)(SPI_INPUT_CLOCK / (2 * speed)) - 1; + + spi_out(dev, div, DIVIDER); + return (SPI_INPUT_CLOCK / (2 * (div + 1))); +} + +/// @endcond /* HIDDEN_SYMBOLS */ + +/** + * @brief Initialize spi interface and install interrupt callback function + * @return always 0. + * @retval 0 Success. + */ +int32_t spiInit(int32_t fd) +{ +#if 0 + if (fd == 0) + { + sysInstallISR(IRQ_LEVEL_1, SPI0_IRQn, (PVOID)spi0ISR); + sysEnableInterrupt(SPI0_IRQn); + memset((void *)&spi_device[0], 0, sizeof(spi_dev)); + } + else + { + sysInstallISR(IRQ_LEVEL_1, SPI1_IRQn, (PVOID)spi1ISR); + sysEnableInterrupt(SPI1_IRQn); + memset((void *)&spi_device[1], 0, sizeof(spi_dev)); + } + + sysSetLocalInterrupt(ENABLE_IRQ); +#endif + + return (0); +} + +/** + * @brief Support some spi driver commands for application. + * @param[in] fd is interface number. + * @param[in] cmd is command. + * @param[in] arg0 is the first argument of command. + * @param[in] arg1 is the second argument of command. + * @return command status. + * @retval 0 Success otherwise fail. Fail value could be + * - \ref SPI_ERR_NODEV + * - \ref SPI_ERR_IO + * - \ref SPI_ERR_ARG + */ +int32_t spiIoctl(int32_t fd, uint32_t cmd, uint32_t arg0, uint32_t arg1) +{ + spi_dev *dev; + + if (fd != 0 && fd != 1) + return (SPI_ERR_NODEV); + + dev = (spi_dev *)((uint32_t)&spi_device[fd]); + if (dev->openflag == 0) + return (SPI_ERR_IO); + + switch (cmd) + { + case SPI_IOC_TRIGGER: + dev->intflag = 0; + spi_out(dev, spi_in(dev, CNTRL) | 0x1, CNTRL); + break; + +#if 0 + case SPI_IOC_SET_INTERRUPT: + if (arg0 == SPI_ENABLE_INTERRUPT) + spi_out(dev, spi_in(dev, CNTRL) | (0x1 << 17), CNTRL); + else + spi_out(dev, spi_in(dev, CNTRL) & ~(0x1 << 17), CNTRL); + break; +#endif + + case SPI_IOC_SET_SPEED: + return spiSetSpeed(dev, (uint32_t)arg0); + + case SPI_IOC_SET_DUAL_QUAD_MODE: + if (arg0 == SPI_DISABLE_DUAL_QUAD) + { + spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 21)), CNTRL); + break; + } + + if (arg0 == SPI_DUAL_MODE) + spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 21)) | (0x1 << 22), CNTRL); + else + spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 21)) | (0x1 << 21), CNTRL); + break; + + case SPI_IOC_SET_DUAL_QUAD_DIR: + if (arg0 == SPI_DUAL_QUAD_INPUT) + spi_out(dev, spi_in(dev, CNTRL) & ~(0x1 << 20), CNTRL); + else + spi_out(dev, spi_in(dev, CNTRL) | (0x1 << 20), CNTRL); + break; + + case SPI_IOC_SET_LSB_MSB: + if (arg0 == SPI_MSB) + spi_out(dev, spi_in(dev, CNTRL) & ~(0x1 << 10), CNTRL); + else + spi_out(dev, spi_in(dev, CNTRL) | (0x1 << 10), CNTRL); + break; + + case SPI_IOC_SET_TX_NUM: + if (arg0 < 4) + spi_out(dev, (spi_in(dev, CNTRL) & ~(0x3 << 8)) | (arg0 << 8), CNTRL); + else + return SPI_ERR_ARG; + break; + + case SPI_IOC_SET_TX_BITLEN: + if (arg0 < 32) + spi_out(dev, (spi_in(dev, CNTRL) & ~(0x1f << 3)) | (arg0 << 3), CNTRL); + else + return SPI_ERR_ARG; + break; + + case SPI_IOC_SET_MODE: + if (arg0 > SPI_MODE_3) + return SPI_ERR_ARG; + + if (arg0 == SPI_MODE_0) + spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | (1 << 2), CNTRL); + else if (arg0 == SPI_MODE_1) + spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | (1 << 1), CNTRL); + else if (arg0 == SPI_MODE_2) + spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | ((1UL << 31) | (1 << 2)), CNTRL); + else + spi_out(dev, (spi_in(dev, CNTRL) & ~((0x3 << 1) | (1UL << 31))) | ((1UL << 31) | (1 << 1)), CNTRL); + break; + + case SPI_IOC_ENABLE_SS: + if (arg0 == SPI_SS_SS0) + spi_out(dev, (spi_in(dev, SSR) & ~(0x3)) | 0x1, SSR); + else if (arg0 == SPI_SS_SS1) + spi_out(dev, (spi_in(dev, SSR) & ~(0x3)) | 0x2, SSR); + else if (arg0 == SPI_SS_BOTH) + spi_out(dev, (spi_in(dev, SSR) & ~(0x3)) | 0x3, SSR); + else + return SPI_ERR_ARG; + break; + + case SPI_IOC_DISABLE_SS: + if (arg0 == SPI_SS_SS0) + spi_out(dev, (spi_in(dev, SSR) & ~(0x1)), SSR); + else if (arg0 == SPI_SS_SS1) + spi_out(dev, (spi_in(dev, SSR) & ~(0x2)), SSR); + else if (arg0 == SPI_SS_BOTH) + spi_out(dev, (spi_in(dev, SSR) & ~(0x3)), SSR); + else + return SPI_ERR_ARG; + break; + + case SPI_IOC_SET_AUTOSS: + if (arg0 == SPI_DISABLE_AUTOSS) + spi_out(dev, spi_in(dev, SSR) & ~(0x1 << 3), SSR); + else + spi_out(dev, spi_in(dev, SSR) | (0x1 << 3), SSR); + break; + + case SPI_IOC_SET_SS_ACTIVE_LEVEL: + if (arg0 == SPI_SS_ACTIVE_LOW) + spi_out(dev, spi_in(dev, SSR) & ~(0x1 << 2), SSR); + else + spi_out(dev, spi_in(dev, SSR) | (0x1 << 2), SSR); + default: + break; + } + + return 0; +} + +/** + * @brief Open spi interface and initialize some variables + * @param[in] fd is interface number. + * @return always 0 + * @retval 0 success. + */ +int spiOpen(int32_t fd) +{ + spi_dev *dev; + + if ((uint32_t)fd >= SPI_NUMBER) + return SPI_ERR_NODEV; + + dev = (spi_dev *)((uint32_t)&spi_device[fd]); + + if (dev->openflag != 0) /* a card slot can open only once */ + return (SPI_ERR_BUSY); + + memset(dev, 0, sizeof(spi_dev)); + dev->base = ((uint32_t)fd) ? SPI1_BA : SPI0_BA; + dev->openflag = 1; + dev->intflag = 0; + + return 0; +} + +/** + * @brief Get busy status of spi interface + * @param[in] fd is interface number. + * @return busy or not + * @retval 0 not busy. + * @retval 1 busy. + */ +uint8_t spiGetBusyStatus(int32_t fd) +{ + spi_dev *dev; + + dev = (spi_dev *)((uint32_t)&spi_device[fd]); + + if (spi_in(dev, CNTRL) & (0x1 << 17)) + return (!dev->intflag); + else + return ((spi_in(dev, CNTRL) & 0x1) == 0x1 ? 1 : 0); +} + +/** + * @brief Read data form spi interface + * @param[in] fd is interface number. + * @param[in] buff_id is buffer number. If transfer number is 4, application needs read 4 times (buff_id is from 0 to 3) from buffer. + * @return data + */ +uint32_t spiRead(int32_t fd, uint8_t buff_id) +{ + spi_dev *dev; + + dev = (spi_dev *)((uint32_t)&spi_device[fd]); + return spi_in(dev, (RX0 + 4 * buff_id)); +} + +/** + * @brief Write data to spi interface + * @param[in] fd is interface number. + * @param[in] buff_id is buffer number. If transfer number is 4, application needs write 4 times (buff_id is from 0 to 3) to buffer. + * @param[in] data is data to be written. + * @return none + */ +void spiWrite(int32_t fd, uint8_t buff_id, uint32_t data) +{ + spi_dev *dev; + + dev = (spi_dev *)((uint32_t)&spi_device[fd]); + spi_out(dev, data, (TX0 + 4 * buff_id)); +} + +/*@}*/ /* end of group N9H30_SPI_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_SPI_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sys.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sys.c new file mode 100644 index 0000000000000000000000000000000000000000..ef3772b025ca87e40b82a75d32e0b1756ee09eb2 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_sys.c @@ -0,0 +1,675 @@ +/**************************************************************************//** +* @file sys.c +* @brief N9H30 SYS driver source file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include "N9H30.h" +#include "nu_sys.h" + +/// @cond HIDDEN_SYMBOLS + +#define SYS_MIN_INT_SOURCE 1 +#define SYS_MAX_INT_SOURCE 62 +#define SYS_NUM_OF_AICREG 16 + +/* Global variables */ +BOOL volatile _sys_bIsAICInitial = FALSE; + +/* declaration the function prototype */ +extern void SYS_Interrupt_Shell(void); + +/* Interrupt Handler Table */ +//typedef void (*sys_pvFunPtr)(); /* function pointer */ +sys_pvFunPtr sysIrqHandlerTable[] = { 0, /* 0 */ + SYS_Interrupt_Shell, /* 1 */ + SYS_Interrupt_Shell, /* 2 */ + SYS_Interrupt_Shell, /* 3 */ + SYS_Interrupt_Shell, /* 4 */ + SYS_Interrupt_Shell, /* 5 */ + SYS_Interrupt_Shell, /* 6 */ + SYS_Interrupt_Shell, /* 7 */ + SYS_Interrupt_Shell, /* 8 */ + SYS_Interrupt_Shell, /* 9 */ + SYS_Interrupt_Shell, /* 10 */ + SYS_Interrupt_Shell, /* 11 */ + SYS_Interrupt_Shell, /* 12 */ + SYS_Interrupt_Shell, /* 13 */ + SYS_Interrupt_Shell, /* 14 */ + SYS_Interrupt_Shell, /* 15 */ + SYS_Interrupt_Shell, /* 16 */ + SYS_Interrupt_Shell, /* 17 */ + SYS_Interrupt_Shell, /* 18 */ + SYS_Interrupt_Shell, /* 19 */ + SYS_Interrupt_Shell, /* 20 */ + SYS_Interrupt_Shell, /* 21 */ + SYS_Interrupt_Shell, /* 22 */ + SYS_Interrupt_Shell, /* 23 */ + SYS_Interrupt_Shell, /* 24 */ + SYS_Interrupt_Shell, /* 25 */ + SYS_Interrupt_Shell, /* 26 */ + SYS_Interrupt_Shell, /* 27 */ + SYS_Interrupt_Shell, /* 28 */ + SYS_Interrupt_Shell, /* 29 */ + SYS_Interrupt_Shell, /* 30 */ + SYS_Interrupt_Shell, /* 31 */ + SYS_Interrupt_Shell, /* 32 */ + SYS_Interrupt_Shell, /* 33 */ + SYS_Interrupt_Shell, /* 34 */ + SYS_Interrupt_Shell, /* 35 */ + SYS_Interrupt_Shell, /* 36 */ + SYS_Interrupt_Shell, /* 37 */ + SYS_Interrupt_Shell, /* 38 */ + SYS_Interrupt_Shell, /* 39 */ + SYS_Interrupt_Shell, /* 40 */ + SYS_Interrupt_Shell, /* 41 */ + SYS_Interrupt_Shell, /* 42 */ + SYS_Interrupt_Shell, /* 43 */ + SYS_Interrupt_Shell, /* 44 */ + SYS_Interrupt_Shell, /* 45 */ + SYS_Interrupt_Shell, /* 46 */ + SYS_Interrupt_Shell, /* 47 */ + SYS_Interrupt_Shell, /* 48 */ + SYS_Interrupt_Shell, /* 49 */ + SYS_Interrupt_Shell, /* 50 */ + SYS_Interrupt_Shell, /* 51 */ + SYS_Interrupt_Shell, /* 52 */ + SYS_Interrupt_Shell, /* 53 */ + SYS_Interrupt_Shell, /* 54 */ + SYS_Interrupt_Shell, /* 55 */ + SYS_Interrupt_Shell, /* 56 */ + SYS_Interrupt_Shell, /* 57 */ + SYS_Interrupt_Shell, /* 58 */ + SYS_Interrupt_Shell, /* 59 */ + SYS_Interrupt_Shell, /* 60 */ + SYS_Interrupt_Shell /* 61 */ + }; + +sys_pvFunPtr sysFiqHandlerTable[] = { 0, + SYS_Interrupt_Shell, /* 1 */ + SYS_Interrupt_Shell, /* 2 */ + SYS_Interrupt_Shell, /* 3 */ + SYS_Interrupt_Shell, /* 4 */ + SYS_Interrupt_Shell, /* 5 */ + SYS_Interrupt_Shell, /* 6 */ + SYS_Interrupt_Shell, /* 7 */ + SYS_Interrupt_Shell, /* 8 */ + SYS_Interrupt_Shell, /* 9 */ + SYS_Interrupt_Shell, /* 10 */ + SYS_Interrupt_Shell, /* 11 */ + SYS_Interrupt_Shell, /* 12 */ + SYS_Interrupt_Shell, /* 13 */ + SYS_Interrupt_Shell, /* 14 */ + SYS_Interrupt_Shell, /* 15 */ + SYS_Interrupt_Shell, /* 16 */ + SYS_Interrupt_Shell, /* 17 */ + SYS_Interrupt_Shell, /* 18 */ + SYS_Interrupt_Shell, /* 19 */ + SYS_Interrupt_Shell, /* 20 */ + SYS_Interrupt_Shell, /* 21 */ + SYS_Interrupt_Shell, /* 22 */ + SYS_Interrupt_Shell, /* 23 */ + SYS_Interrupt_Shell, /* 24 */ + SYS_Interrupt_Shell, /* 25 */ + SYS_Interrupt_Shell, /* 26 */ + SYS_Interrupt_Shell, /* 27 */ + SYS_Interrupt_Shell, /* 28 */ + SYS_Interrupt_Shell, /* 29 */ + SYS_Interrupt_Shell, /* 30 */ + SYS_Interrupt_Shell, /* 31 */ + SYS_Interrupt_Shell, /* 32 */ + SYS_Interrupt_Shell, /* 33 */ + SYS_Interrupt_Shell, /* 34 */ + SYS_Interrupt_Shell, /* 35 */ + SYS_Interrupt_Shell, /* 36 */ + SYS_Interrupt_Shell, /* 37 */ + SYS_Interrupt_Shell, /* 38 */ + SYS_Interrupt_Shell, /* 39 */ + SYS_Interrupt_Shell, /* 40 */ + SYS_Interrupt_Shell, /* 41 */ + SYS_Interrupt_Shell, /* 42 */ + SYS_Interrupt_Shell, /* 43 */ + SYS_Interrupt_Shell, /* 44 */ + SYS_Interrupt_Shell, /* 45 */ + SYS_Interrupt_Shell, /* 46 */ + SYS_Interrupt_Shell, /* 47 */ + SYS_Interrupt_Shell, /* 48 */ + SYS_Interrupt_Shell, /* 49 */ + SYS_Interrupt_Shell, /* 50 */ + SYS_Interrupt_Shell, /* 51 */ + SYS_Interrupt_Shell, /* 52 */ + SYS_Interrupt_Shell, /* 53 */ + SYS_Interrupt_Shell, /* 54 */ + SYS_Interrupt_Shell, /* 55 */ + SYS_Interrupt_Shell, /* 56 */ + SYS_Interrupt_Shell, /* 57 */ + SYS_Interrupt_Shell, /* 58 */ + SYS_Interrupt_Shell, /* 59 */ + SYS_Interrupt_Shell, /* 60 */ + SYS_Interrupt_Shell /* 61 */ + }; + +/* Interrupt Handler */ +#if defined ( __GNUC__ ) && !(__CC_ARM) + static void __attribute__((interrupt("IRQ"))) sysIrqHandler(void) +#else + __irq void sysIrqHandler() +#endif +{ + UINT32 volatile _mIPER, _mISNR; + + _mIPER = (inpw(REG_AIC_IPER) >> 2) & 0x3f; + _mISNR = inpw(REG_AIC_ISNR); + if (_mIPER != 0) + { + if (_mISNR != 0) + (*sysIrqHandlerTable[_mIPER])(); + outpw(REG_AIC_EOSCR, 1); + } +} + +#if defined ( __GNUC__ ) && !(__CC_ARM) + static void __attribute__((interrupt("FIQ"))) sysFiqHandler(void) +#else + __irq void sysFiqHandler() +#endif +{ + UINT32 volatile _mIPER, _mISNR; + + _mIPER = (inpw(REG_AIC_IPER) >> 2) & 0x3f; + _mISNR = inpw(REG_AIC_ISNR); + if (_mIPER != 0) + { + if (_mISNR != 0) + (*sysFiqHandlerTable[_mIPER])(); + outpw(REG_AIC_EOSCR, 1); + } +} + +void SYS_Interrupt_Shell() +{ + //sysprintf("ISR not found! ISNR=%d\n", inpw(REG_AIC_ISNR)); +} + +void sysInitializeAIC() +{ + *(unsigned int volatile *)0x38 = (unsigned int)sysIrqHandler; + + *(unsigned int volatile *)0x3C = (unsigned int)sysFiqHandler; +} +/// @endcond HIDDEN_SYMBOLS + + +/* Interrupt library functions */ +/** + * @brief system AIC - disable interrupt + * + * @param[in] eIntNo Select interrupt source. \ref IRQn_Type + * + * @return 0 + */ +INT32 sysDisableInterrupt(IRQn_Type eIntNo) +{ + if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE)) + return 1; + + if (eIntNo < 32) + outpw(REG_AIC_MDCR, (1 << eIntNo)); + else + outpw(REG_AIC_MDCRH, (1 << (eIntNo - 32))); + + return 0; +} + + +/** + * @brief system AIC - enable interrupt + * + * @param[in] eIntNo Select interrupt source. \ref IRQn_Type + * + * @return 0 + */ +INT32 sysEnableInterrupt(IRQn_Type eIntNo) +{ + if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE)) + return 1; + + if (eIntNo < 32) + outpw(REG_AIC_MECR, (1 << eIntNo)); + else + outpw(REG_AIC_MECRH, (1 << (eIntNo - 32))); + + return 0; +} + + +/** + * @brief system AIC - install exception handler + * + * @param[in] nExceptType exception type. ( \ref SYS_SWI / \ref SYS_D_ABORT / \ref SYS_I_ABORT / \ref SYS_UNDEFINE) + * @param[in] pvNewHandler own exception handler + * + * @return old handler + */ +PVOID sysInstallExceptionHandler(INT32 nExceptType, PVOID pvNewHandler) +{ + PVOID _mOldVect = NULL; + + switch (nExceptType) + { + case SYS_SWI: + _mOldVect = *(PVOID volatile *)0x28; + *(PVOID volatile *)0x28 = pvNewHandler; + break; + + case SYS_D_ABORT: + _mOldVect = *(PVOID volatile *)0x30; + *(PVOID volatile *)0x30 = pvNewHandler; + break; + + case SYS_I_ABORT: + _mOldVect = *(PVOID volatile *)0x2C; + *(PVOID volatile *)0x2C = pvNewHandler; + break; + + case SYS_UNDEFINE: + _mOldVect = *(PVOID volatile *)0x24; + *(PVOID volatile *)0x24 = pvNewHandler; + break; + + default: + ; + } + return _mOldVect; +} + +/** + * @brief system AIC - install FIQ handler + * + * @param[in] pvNewISR own fiq handler + * + * @return old handler + */ +PVOID sysInstallFiqHandler(PVOID pvNewISR) +{ + PVOID _mOldVect; + + _mOldVect = *(PVOID volatile *)0x3C; + *(PVOID volatile *)0x3C = pvNewISR; + return _mOldVect; +} + +/** + * @brief system AIC - install IRQ handler + * + * @param[in] pvNewISR own irq handler + * + * @return old handler + */ +PVOID sysInstallIrqHandler(PVOID pvNewISR) +{ + PVOID _mOldVect; + + _mOldVect = *(PVOID volatile *)0x38; + *(PVOID volatile *)0x38 = pvNewISR; + return _mOldVect; +} + + +/** + * @brief system AIC - install Own IRQ service routine + * + * @param[in] nIntTypeLevel Interrupt Level. ( \ref FIQ_LEVEL_0 / \ref IRQ_LEVEL_1 / \ref IRQ_LEVEL_2 / \ref IRQ_LEVEL_3 / + * \ref IRQ_LEVEL_4 / \ref IRQ_LEVEL_5 / \ref IRQ_LEVEL_6 / \ref IRQ_LEVEL_7 ) + * @param[in] eIntNo Interrupt number. \ref IRQn_Type + * @param[in] pvNewISR own irq handler + * + * @return old handler + */ +PVOID sysInstallISR(INT32 nIntTypeLevel, IRQn_Type eIntNo, PVOID pvNewISR) +{ + PVOID _mOldVect; + UINT32 _mRegAddr/*, _mRegValue*/; + INT shift; + + if (!_sys_bIsAICInitial) + { + sysInitializeAIC(); + _sys_bIsAICInitial = TRUE; + } + + _mRegAddr = REG_AIC_SCR1 + ((eIntNo / 4) * 4); + shift = (eIntNo % 4) * 8; + nIntTypeLevel &= 0xff; + outpw(_mRegAddr, (inpw(_mRegAddr) & ~(0x07 << shift)) | (nIntTypeLevel << shift)); + + if ((nIntTypeLevel & 0x7) == FIQ_LEVEL_0) + { + _mOldVect = (PVOID) sysFiqHandlerTable[eIntNo]; + sysFiqHandlerTable[eIntNo] = (sys_pvFunPtr)pvNewISR; + } + else + { + _mOldVect = (PVOID) sysIrqHandlerTable[eIntNo]; + sysIrqHandlerTable[eIntNo] = (sys_pvFunPtr)pvNewISR; + } + return _mOldVect; +} + + +INT32 sysSetGlobalInterrupt(INT32 nIntState) +{ + switch (nIntState) + { + case ENABLE_ALL_INTERRUPTS: + outpw(REG_AIC_MECR, 0xFFFFFFFF); + outpw(REG_AIC_MECRH, 0xFFFFFFFF); + break; + + case DISABLE_ALL_INTERRUPTS: + outpw(REG_AIC_MDCR, 0xFFFFFFFF); + outpw(REG_AIC_MDCRH, 0xFFFFFFFF); + break; + + default: + ; + } + return 0; +} + + +/** + * @brief system AIC - Change interrupt level + * + * @param[in] eIntNo Interrupt number. \ref IRQn_Type + * @param[in] uIntLevel Interrupt Level. ( \ref FIQ_LEVEL_0 / \ref IRQ_LEVEL_1 / \ref IRQ_LEVEL_2 / \ref IRQ_LEVEL_3 / + * \ref IRQ_LEVEL_4 / \ref IRQ_LEVEL_5 / \ref IRQ_LEVEL_6 / \ref IRQ_LEVEL_7 ) + * + * @return 0 + */ +INT32 sysSetInterruptPriorityLevel(IRQn_Type eIntNo, UINT32 uIntLevel) +{ + UINT32 _mRegAddr; + INT shift; + + if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE)) + return 1; + + _mRegAddr = REG_AIC_SCR1 + ((eIntNo / 4) * 4); + shift = (eIntNo % 4) * 8; + uIntLevel &= 0x7; + outpw(_mRegAddr, (inpw(_mRegAddr) & ~(0x07 << shift)) | (uIntLevel << shift)); + + return 0; +} + + +INT32 sysSetInterruptType(IRQn_Type eIntNo, UINT32 uIntSourceType) +{ + UINT32 _mRegAddr; + INT shift; + + if ((eIntNo > SYS_MAX_INT_SOURCE) || (eIntNo < SYS_MIN_INT_SOURCE)) + return 1; + + _mRegAddr = REG_AIC_SCR1 + ((eIntNo / 4) * 4); + shift = (eIntNo % 4) * 8; + uIntSourceType &= 0xC0; + outpw(_mRegAddr, (inpw(_mRegAddr) & ~(0xC0 << shift)) | (uIntSourceType << shift)); + + return 0; +} + + +/** + * @brief system AIC - Set CP15 Interrupt Type + * + * @param[in] nIntState Interrupt state. ( \ref ENABLE_IRQ / \ref ENABLE_FIQ / \ref ENABLE_FIQ_IRQ / + * \ref DISABLE_IRQ / \ref DISABLE_FIQ / \ref DISABLE_FIQ_IRQ) + * + * @return 0 + */ +INT32 sysSetLocalInterrupt(INT32 nIntState) +{ +#if defined ( __GNUC__ ) && !(__CC_ARM) + +# else + INT32 temp; +#endif + + switch (nIntState) + { + case ENABLE_IRQ: + case ENABLE_FIQ: + case ENABLE_FIQ_IRQ: +#if defined ( __GNUC__ ) && !(__CC_ARM) + asm + ( + "mrs r0, CPSR \n" + "bic r0, r0, #0x80 \n" + "msr CPSR_c, r0 \n" + ); +#else + __asm + { + MRS temp, CPSR + AND temp, temp, nIntState + MSR CPSR_c, temp + } +#endif + break; + case DISABLE_IRQ: + case DISABLE_FIQ: + case DISABLE_FIQ_IRQ: +#if defined ( __GNUC__ ) && !(__CC_ARM) + asm + ( + "MRS r0, CPSR \n" + "ORR r0, r0, #0x80 \n" + "MSR CPSR_c, r0 \n" + ); +#else + __asm + { + MRS temp, CPSR + ORR temp, temp, nIntState + MSR CPSR_c, temp + } +#endif + break; + + default: + ; + } + return 0; +} + +UINT32 sysGetInterruptEnableStatus(void) +{ + return (inpw(REG_AIC_IMR)); +} + + +UINT32 sysGetInterruptEnableStatusH(void) +{ + return (inpw(REG_AIC_IMRH)); +} + +/// @cond HIDDEN_SYMBOLS +BOOL sysGetIBitState() +{ + INT32 temp; + +#if defined ( __GNUC__ ) && !(__CC_ARM) + asm + ( + "MRS %0, CPSR \n" + :"=r"(temp) : : + ); +#else + __asm + { + MRS temp, CPSR + } +#endif + + if (temp & 0x80) + return FALSE; + else + return TRUE; +} + +INT32 sysGetPLL(UINT32 reg) +{ + UINT32 N, M, P; + + N = ((inpw(reg) & 0x007F) >> 0) + 1; + M = ((inpw(reg) & 0x1F80) >> 7) + 1; + P = ((inpw(reg) & 0xE000) >> 13) + 1; + + return (12 * N / (M * P)); /* 12MHz HXT */ +} +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief system Timer - install WDT interrupt handler + * + * @param[in] clk clock source. \ref CLK_Type + * + * @return MHz + */ +UINT32 sysGetClock(CLK_Type clk) +{ + UINT32 src, divS, divN, reg, div; + + switch (clk) + { + case SYS_UPLL: + return sysGetPLL(REG_CLK_UPLLCON); + + case SYS_APLL: + return sysGetPLL(REG_CLK_APLLCON); + + case SYS_SYSTEM: + { + reg = inpw(REG_CLK_DIVCTL0); + switch (reg & 0x18) + { + case 0x0: + src = 12; /* HXT */ + break; + case 0x10: + src = sysGetPLL(REG_CLK_APLLCON); + break; + case 0x18: + src = sysGetPLL(REG_CLK_UPLLCON); + break; + default: + return 0; + } + divS = (reg & 0x7) + 1; + divN = ((reg & 0xf00) >> 8) + 1; + return (src / divS / divN); + } + + case SYS_HCLK1: + { + reg = inpw(REG_CLK_DIVCTL0); + switch (reg & 0x18) + { + case 0x0: + src = 12; /* HXT */ + break; + case 0x10: + src = sysGetPLL(REG_CLK_APLLCON); + break; + case 0x18: + src = sysGetPLL(REG_CLK_UPLLCON); + break; + default: + return 0; + } + divS = (reg & 0x7) + 1; + divN = ((reg & 0xf00) >> 8) + 1; + return (src / divS / divN / 2); + } + + case SYS_HCLK234: + { + reg = inpw(REG_CLK_DIVCTL0); + switch (reg & 0x18) + { + case 0x0: + src = 12; /* HXT */ + break; + case 0x10: + src = sysGetPLL(REG_CLK_APLLCON); + break; + case 0x18: + src = sysGetPLL(REG_CLK_UPLLCON); + break; + default: + return 0; + } + divS = (reg & 0x7) + 1; + divN = ((reg & 0xf00) >> 8) + 1; + div = ((reg & 0xf00000) >> 20) + 1; + return (src / divS / divN / 2 / div); + } + + case SYS_PCLK: + { + reg = inpw(REG_CLK_DIVCTL0); + switch (reg & 0x18) + { + case 0x0: + src = 12; /* HXT */ + break; + case 0x10: + src = sysGetPLL(REG_CLK_APLLCON); + break; + case 0x18: + src = sysGetPLL(REG_CLK_UPLLCON); + break; + default: + return 0; + } + divS = (reg & 0x7) + 1; + divN = ((reg & 0xf00) >> 8) + 1; + div = ((reg & 0xf000000) >> 24) + 1; + return (src / divS / divN / 2 / div); + } + case SYS_CPU: + { + reg = inpw(REG_CLK_DIVCTL0); + switch (reg & 0x18) + { + case 0x0: + src = 12; /* HXT */ + break; + case 0x10: + src = sysGetPLL(REG_CLK_APLLCON); + break; + case 0x18: + src = sysGetPLL(REG_CLK_UPLLCON); + break; + default: + return 0; + } + divS = (reg & 0x7) + 1; + divN = ((reg & 0xf00) >> 8) + 1; + div = ((reg & 0xf0000) >> 16) + 1; + return (src / divS / divN / div); + } + + default: + ; + } + return 0; +} + + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_timer.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..a5931660a445ad9320afc6b952f480c1734d8537 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_timer.c @@ -0,0 +1,146 @@ +/**************************************************************************//** + * @file timer.c + * @brief N9H30 series TIMER driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_timer.h" + +void TIMER_SET_CMP_VALUE(uint32_t timer, uint32_t u32Cmpr) +{ + uint32_t u32TmrCMPROffset; + + u32TmrCMPROffset = REG_TMR0_CMPR + timer * 0x10; + + outpw(u32TmrCMPROffset, u32Cmpr); +} + +void TIMER_SET_OPMODE(uint32_t timer, uint32_t u32OpMode) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, (inpw(u32TmrCSROffset) & ~(0x3UL << 27)) | u32OpMode); +} + +void TIMER_SET_PRESCALE_VALUE(uint32_t timer, uint32_t u32PreScale) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, (inpw(u32TmrCSROffset) & ~(0xFFUL)) | u32PreScale); +} + +uint32_t TIMER_GetModuleClock(uint32_t timer) +{ + return 12000000; +} + +void TIMER_Start(uint32_t timer) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, inpw(u32TmrCSROffset) | TIMER_COUNTER_ENABLE); +} + +void TIMER_Stop(uint32_t timer) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, inpw(u32TmrCSROffset) & ~TIMER_COUNTER_ENABLE); +} + +void TIMER_ClearCounter(uint32_t timer) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, inpw(u32TmrCSROffset) | TIMER_COUNTER_RESET); +} + +uint32_t TIMER_GetCounter(uint32_t timer) +{ + uint32_t u32TmrDROffset; + + u32TmrDROffset = REG_TMR0_DR + timer * 0x10; + + return inpw(u32TmrDROffset); +} + +uint32_t TIMER_GetCompareData(uint32_t timer) +{ + uint32_t u32TmrCMPROffset; + + u32TmrCMPROffset = REG_TMR0_CMPR + timer * 0x10; + + return inpw(u32TmrCMPROffset); +} + +void TIMER_EnableInt(uint32_t timer) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, inpw(u32TmrCSROffset) | TIMER_INTERRUPT_ENABLE); +} + +void TIMER_DisableInt(uint32_t timer) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, inpw(u32TmrCSROffset) & ~TIMER_INTERRUPT_ENABLE); +} + +void TIMER_Close(uint32_t timer) +{ + uint32_t u32TmrCSROffset; + + u32TmrCSROffset = REG_TMR0_CSR + timer * 0x10; + + outpw(u32TmrCSROffset, 0); +} + +uint32_t TIMER_Open(uint32_t timer, uint32_t u32Mode, uint32_t u32Freq) +{ + uint32_t u32Clk = TIMER_GetModuleClock(timer); + uint32_t u32Cmpr = 0, u32Prescale = 0; + uint32_t u32TmrOffset = 0; + + // Fastest possible timer working freq is u32Clk / 2. While cmpr = 2, pre-scale = 0 + if (u32Freq > (u32Clk / 2)) + { + u32Cmpr = 2; + } + else + { + /* Clock source is only XIN. */ + u32Cmpr = u32Clk / u32Freq; + } + + u32TmrOffset = timer * 0x10; + + TIMER_Close(timer); /* disable timer */ + TIMER_DisableInt(timer); /* clear for safety */ + + outpw(REG_TMR0_CMPR + u32TmrOffset, u32Cmpr); + outpw(REG_TMR0_CSR + u32TmrOffset, u32Mode | u32Prescale); + + return (u32Clk / (u32Cmpr * (u32Prescale + 1))); +} + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_uart.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_uart.c new file mode 100644 index 0000000000000000000000000000000000000000..9122b80d63fe59d466d6f68b6dbef5bb62ca3f1a --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_uart.c @@ -0,0 +1,2200 @@ +/**************************************************************************//** +* @file uart.c +* @version V1.00 +* @brief N9H30 UART driver source file +* +* SPDX-License-Identifier: Apache-2.0 +* @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#if 0 +#include +#include +#include +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_uart.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_UART_Driver UART Driver + @{ +*/ + +/** @addtogroup N9H30_UART_EXPORTED_CONSTANTS UART Exported Constants + @{ +*/ + +/*@}*/ /* end of group N9H30_UART_EXPORTED_CONSTANTS */ + +/// @cond HIDDEN_SYMBOLS + +/*-----------------------------------------*/ +/* marco, type and constant definitions */ +/*-----------------------------------------*/ +/* + Define debug level +*/ +//#define UART_DEBUG +//#define UART_FLOWCONTROL_DEBUG +//#define UART1_DEBUG +//#define UART2_DEBUG + +#ifdef UART_DEBUG + #define UDEBUG sysprintf +#else + #define UDEBUG(...) +#endif /* UART_DEBUG */ + +#ifdef UART_FLOWCONTROL_DEBUG + #define FDEBUG sysprintf +#else + #define FDEBUG(...) +#endif /* UART_FLOWCONTROL_DEBUG */ + +#ifdef UART1_DEBUG + #define U1DEBUG sysprintf +#else + #define U1DEBUG(...) +#endif /* UART1_DEBUG */ + +#ifdef UART2_DEBUG + #define U2DEBUG sysprintf +#else + #define U2DEBUG(...) +#endif /* UART1_DEBUG */ + +/*-----------------------------------------*/ +/* global file scope (static) variables */ +/*-----------------------------------------*/ +static UART_BUFFER_T UART_DEV[UART_NUM]; + +static UINT32 UARTTXBUFSIZE[UART_NUM] = {500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500}; /* UART0~10 Tx buffer size */ +static UINT32 UARTRXBUFSIZE[UART_NUM] = {500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500}; /* UART0~10 Rx buffer size */ + + +/* + UART flag declarations. +*/ +static volatile CHAR _uart_cDSRState0 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState1 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState2 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState3 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState4 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState5 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState6 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState7 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState8 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState9 = 0; /* set 1, state change */ +static volatile CHAR _uart_cDSRState10 = 0; /* set 1, state change */ +static volatile CHAR _uart_cBIIState_0 = 0; /* set 1, UART channel 0 break interrupt occur */ +static volatile CHAR _uart_cBIIState_1 = 0; /* set 1, UART channel 1 break interrupt occur */ +static volatile CHAR _uart_cBIIState_2 = 0; /* set 1, UART channel 2 break interrupt occur */ +static volatile CHAR _uart_cBIIState_3 = 0; /* set 1, UART channel 3 break interrupt occur */ +static volatile CHAR _uart_cBIIState_4 = 0; /* set 1, UART channel 4 break interrupt occur */ +static volatile CHAR _uart_cBIIState_5 = 0; /* set 1, UART channel 0 break interrupt occur */ +static volatile CHAR _uart_cBIIState_6 = 0; /* set 1, UART channel 1 break interrupt occur */ +static volatile CHAR _uart_cBIIState_7 = 0; /* set 1, UART channel 2 break interrupt occur */ +static volatile CHAR _uart_cBIIState_8 = 0; /* set 1, UART channel 3 break interrupt occur */ +static volatile CHAR _uart_cBIIState_9 = 0; /* set 1, UART channel 4 break interrupt occur */ +static volatile CHAR _uart_cBIIState_10 = 0; /* set 1, UART channel 4 break interrupt occur */ +static volatile CHAR _uart_cCTSState0 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState1 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState2 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState3 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState4 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState5 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState6 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState7 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState8 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState9 = 0; /* set 1, state change */ +static volatile CHAR _uart_cCTSState10 = 0; /* set 1, state change */ + +/* + Define flow control flags & parameters. +*/ +#define HWFLOWCONTROL 1 +#define SWFLOWCONTROL 2 +static volatile CHAR _uart_cFlowControlMode = 0; /* default no flow control */ +static volatile CHAR _uart_cHWTXStopped = 0; /* Use for H/W flow control. Set 1, stop TX. Set 0, start TX. */ +static volatile CHAR _uart_cHWRXStopped = 0; /* Use for H/W flow control. Set 1, stop RX. Set 0, start RX. */ +static volatile CHAR _uart_cSWTXStopped = 0; /* Use for S/W flow control. Set 1, rec Xoff. Set 0, rec Xon. */ +static volatile CHAR _uart_cSWRXStopped = 0; /* Use for S/W flow control. Set 1, send Xoff. Set 0, send Xon. */ +//static INT _uart_nMaxRxBuf = 0; /* used in uartReceiveChars() */ +//static INT _uart_nMinRxBuf = 0; /* used in uartReadRxBuf() */ + + +/*-----------------------------------------*/ +/* prototypes of static functions */ +/*-----------------------------------------*/ +static UINT32 _uartTxBufGetNextOne(INT nNum, UINT32 uPointer); +static UINT32 _uartRxBufGetNextOne(INT nNum, UINT32 uPointer); +static void _uartEnableInterrupt(INT nNum, UINT32 uVal); +static void _uartDisableInterrupt(INT nNum, UINT32 uVal); +static void _uartReceiveChars(INT nNum); +static void _uartTransmitChars(INT nNum); +static void _uartCheckModemStatus(INT nNum); +static INT _uartSetBaudRate(INT nNum, UART_T *val); +static void _uartInstallISR(UINT8 ucNum); +static BOOL _uartBUFSpaceAlloc(INT nNum); +static BOOL _uartCheckTxBufSpace(INT nNum, UINT32 uHead, UINT32 uTail, UINT32 uLen); +static INT32 _uartReadRxBuf(INT nNum, PUINT8 pucBuf, UINT32 uLen); +static void _uartWriteTxBuf(INT nNum, PUINT8 pucBuf, UINT32 uLen); +static INT _uartConfigureUART(PVOID pvParam); +static INT _uartPerformIrDA(INT nNum, UINT32 uCmd, UINT32 uCmd1); +static INT _uartGetRegisterValue(INT nNum, PVOID pvReg); + + +void RS485_HANDLE(INT nNum) +{ + UINT32 volatile uRegISR, uRegFSR, uRegALT_CSR; + + uRegISR = inpw(REG_UART0_ISR + (nNum * UARTOFFSET)); + uRegFSR = inpw(REG_UART0_FSR + (nNum * UARTOFFSET)); + + if ((uRegISR & UART_ISR_RLS_IF_Msk) && (uRegISR & UART_ISR_RDA_IF_Msk)) /* RLS INT & RDA INT */ //For RS485 Detect Address + { + if (uRegFSR & UART_FSR_RS485_ADD_DETF_Msk) /* ADD_IF, RS485 mode */ + { + _uartReceiveChars(nNum); + outpw((REG_UART0_FSR + (nNum * UARTOFFSET)), UART_FSR_RS485_ADD_DETF_Msk); /* clear ADD_IF flag */ + } + } + else if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Rx Ready or Time-out INT*/ + { + /* Handle received data */ + _uartReceiveChars(nNum); + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART0_FSR + (nNum * UARTOFFSET)); + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_0 = 1; + } +} + +void uart0ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR; + + uRegISR = inpw(REG_UART0_ISR) & 0xff; + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART0); + + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART0); + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART0_FSR); + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_0 = 1; + } + +} + +void uart1ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART1_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART1_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART1); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART1); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART1); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART1_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState1 = 1; + } + else + _uartCheckModemStatus(UART1); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART1_FSR); + U1DEBUG("U1 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_1 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U1 OEI!\n"); + } + } +} + +void uart2ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART2_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART2_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART2); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART2); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART2); + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART2_FSR); + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_2 = 1; + } + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART2_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState2 = 1; + } + else + _uartCheckModemStatus(UART2); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART2_FSR); + U1DEBUG("U2 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_2 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U2 OEI!\n"); + } + } +} + +void uart3ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART3_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART3_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART3); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART3); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) + _uartReceiveChars(UART3); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART3_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState3 = 1; + } + else + _uartCheckModemStatus(UART3); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART3_FSR); + U1DEBUG("U3 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_3 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U3 OEI!\n"); + } + } + +} + +void uart4ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART4_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART4_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART4); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART4); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART4); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART4_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState4 = 1; + } + else + _uartCheckModemStatus(UART4); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART4_FSR); + U1DEBUG("U4 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_4 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U4 OEI!\n"); + } + } + +} + +void uart5ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART5_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART5_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART5); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART5); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART5); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART5_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState5 = 1; + } + else + _uartCheckModemStatus(UART5); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART5_FSR); + U1DEBUG("U5 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_5 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U5 OEI!\n"); + } + } + +} + +void uart6ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART6_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART6_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART6); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART6); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART6); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART6_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState6 = 1; + } + else + _uartCheckModemStatus(UART6); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART6_FSR); + U1DEBUG("U6 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_6 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U6 OEI!\n"); + } + } + +} + +void uart7ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART7_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART7_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART7); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART7); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART7); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART7_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState7 = 1; + } + else + _uartCheckModemStatus(UART7); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART7_FSR); + U1DEBUG("U7 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_7 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U7 OEI!\n"); + } + } + +} + +void uart8ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART8_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART8_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART8); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART8); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART8); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART8_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState8 = 1; + } + else + _uartCheckModemStatus(UART8); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART8_FSR); + U1DEBUG("U8 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_8 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U8 OEI!\n"); + } + } + +} + +void uart9ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UART9_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UART9_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UART9); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UART9); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UART9); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UART9_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState9 = 1; + } + else + _uartCheckModemStatus(UART9); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UART9_FSR); + U1DEBUG("U9 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_9 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U9 OEI!\n"); + } + } + +} + +void uart10ISR(void) +{ + UINT32 volatile uRegISR, uRegFSR, uRegMSR, uRegFUN_SEL; + + uRegISR = inpw(REG_UARTA_ISR) & 0xff; + uRegFUN_SEL = inpw(REG_UARTA_FUN_SEL); + + if (uRegISR & UART_ISR_THRE_IF_Msk) /* TX empty interrupt, check LSR 4 kinds of error further */ + _uartTransmitChars(UARTA); + + if (uRegFUN_SEL == 0x3) + { + RS485_HANDLE(UARTA); + } + else + { + if (uRegISR & (UART_ISR_RDA_IF_Msk | UART_ISR_TOUT_IF_Msk)) /* Received Data Available interrupt */ + _uartReceiveChars(UARTA); + + if (uRegISR & UART_ISR_MODEM_IF_Msk) + { + if (_uart_cFlowControlMode == 0) + { + uRegMSR = inpw(REG_UARTA_MSR); + + if (uRegMSR & 0x01) + _uart_cCTSState10 = 1; + } + else + _uartCheckModemStatus(UARTA); /* H/W flow control */ + } + + if (uRegISR & UART_ISR_RLS_IF_Msk) + { + uRegFSR = inpw(REG_UARTA_FSR); + U1DEBUG("U10 Irpt_RLS [0x%x]!\n", uRegFSR); + + if (uRegFSR & UART_FSR_BIF_Msk) + _uart_cBIIState_10 = 1; + + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + U1DEBUG("U10 OEI!\n"); + } + } + +} + +static UINT32 _uartTxBufGetNextOne(INT nNum, UINT32 uPointer) +{ + if ((uPointer + 1) == UARTTXBUFSIZE[nNum]) + return (UINT32)NULL; + else + return (uPointer + 1); +} + +static UINT32 _uartRxBufGetNextOne(INT nNum, UINT32 uPointer) +{ + if ((uPointer + 1) == UARTRXBUFSIZE[nNum]) + return (UINT32)NULL; + else + return (uPointer + 1); +} + +static void _uartEnableInterrupt(INT nNum, UINT32 uVal) +{ + UINT32 uReg = 0; + + uReg = inpw(REG_UART0_IER + (nNum * UARTOFFSET)); + uReg |= uVal; + outpw(REG_UART0_IER + (nNum * UARTOFFSET), uReg); +} + +static void _uartDisableInterrupt(INT nNum, UINT32 uVal) +{ + UINT32 uReg = 0; + + if (uVal == DISABLEALLIER) + outpw(REG_UART0_IER + (nNum * UARTOFFSET), 0); + else + { + uReg = inpw(REG_UART0_IER + (nNum * UARTOFFSET)); + uReg &= ~uVal; + outpw(REG_UART0_IER + (nNum * UARTOFFSET), uReg); + } +} + +static void _uartReceiveChars(INT nNum) +{ + //UINT32 volatile uRegLSR, uBuf = 0; + UINT32 volatile uRegFSR, uRegALT_CSR, uRegFUN_SEL, uRegFCR, uRegLINSR, uRegISR; + UINT32 volatile uBuf = 0; + UINT32 volatile uOffset = nNum * UARTOFFSET; + INT nMaxCount = 256; + UCHAR ucChar; + + UART_BUFFER_T *dev; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + //uRegFSR = inpw(REG_UART0_FSR+(nNum * UARTOFFSET)); + uRegFUN_SEL = inpw(REG_UART0_FUN_SEL + uOffset); + + do + { + uRegFSR = inpw(REG_UART0_FSR + uOffset); + uRegLINSR = inpw(REG_UART0_LIN_SR + uOffset); + uRegISR = inpw(REG_UART0_ISR + uOffset); + ucChar = inpb(REG_UART0_RBR + uOffset); + + if ((uRegFSR & UART_FSR_RS485_ADD_DETF_Msk) && (uRegFUN_SEL == 0x3)) + { + uRegALT_CSR = inpw(REG_UART0_ALT_CSR + (nNum * UARTOFFSET)); + uRegFCR = inpw(REG_UART0_FCR + (nNum * UARTOFFSET)); + if (uRegALT_CSR & UART_ALT_CSR_RS485_NMM_Msk) + { + if (ucChar == (uRegALT_CSR >> UART_ALT_CSR_ADDR_MATCH_Pos)) + { + uRegFCR &= ~UART_FCR_RX_DIS_Msk; /* Enable RS485 RX */ + outpw((REG_UART0_FCR + (nNum * UARTOFFSET)), uRegFCR); + } + else + { + uRegFCR |= UART_FCR_RX_DIS_Msk; /* Disable RS485 RX */ + uRegFCR |= UART_FCR_RFR_Msk; /* Clear data from RX FIFO */ + outpw((REG_UART0_FCR + (nNum * UARTOFFSET)), uRegFCR); + break; + } + } + } + + + uBuf = _uartRxBufGetNextOne(nNum, dev->uUartRxTail); + if (uBuf == dev->uUartRxHead) /* Rx buffer full */ + { + //ucChar = inpb(REG_UART0_RBR+(nNum * UARTOFFSET)); + + if (_uart_cHWRXStopped) + U1DEBUG("[%d] buf full!\n", nNum); + + break; + } + + //ucChar = inpb(REG_UART0_RBR+(nNum * UARTOFFSET)); + + dev->pucUartRxBuf[dev->uUartRxTail] = ucChar; + + /* Check LSR for BII, FEI, PEI, OEI */ + dev->pucUARTFlag[dev->uUartRxTail] = 0; + + if (uRegFSR & UART_FSR_BIF_Msk) + { + dev->pucUARTFlag[dev->uUartRxTail] = UART_FSR_BIF_Msk; + U1DEBUG("BIF!\n"); + } + else if (uRegFSR & UART_FSR_FEF_Msk) + { + dev->pucUARTFlag[dev->uUartRxTail] = UART_FSR_FEF_Msk; + U1DEBUG("FEF!\n"); + } + else if (uRegFSR & UART_FSR_PEF_Msk) + { + dev->pucUARTFlag[dev->uUartRxTail] = UART_FSR_PEF_Msk; + U1DEBUG("PEF!\n"); + } + else if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + { + dev->pucUARTFlag[dev->uUartRxTail] = UART_FSR_RX_OVER_IF_Msk; + U1DEBUG("OVER_IF!\n"); + } + else if (uRegFSR & UART_FSR_RS485_ADD_DETF_Msk) + { + dev->pucUARTFlag[dev->uUartRxTail] = UART_FSR_RS485_ADD_DETF_Msk; + U1DEBUG("RS485_ADD_DET_IF!\n"); + } + + if (uRegFUN_SEL == 0x1) + { + if (uRegISR & UART_ISR_LIN_RX_BREAK_IF_Msk) + { + dev->pucLINFlag[dev->uUartRxTail] = uRegLINSR; + + // Clear ISR and LIN Status + outpw(REG_UART0_ISR, UART_ISR_LIN_RX_BREAK_IF_Msk); + outpw(REG_UART0_LIN_SR, 0x30F); + } + } + + dev->uUartRxTail = _uartRxBufGetNextOne(nNum, dev->uUartRxTail); + + /* overrun error is special case, H/W ignore the character */ + if (uRegFSR & UART_FSR_RX_OVER_IF_Msk) + { + dev->pucUARTFlag[dev->uUartRxTail] = UART_FSR_RX_OVER_IF_Msk; + dev->uUartRxTail = _uartRxBufGetNextOne(nNum, dev->uUartRxTail); + } + + uRegFSR = inpw(REG_UART0_FSR + (nNum * UARTOFFSET)); + } + while ((!(uRegFSR & UART_FSR_RX_EMPTY_Msk)) && (nMaxCount-- > 0)); + +} + +static void _uartTransmitChars(INT nNum) +{ + UINT32 volatile i; + + UART_BUFFER_T *dev; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + if (dev->uUartTxHead != dev->uUartTxTail) /* buffer is not empty */ + { + for (i = 0; i < 8; i++) + { + outpw(REG_UART0_THR + (nNum * UARTOFFSET), dev->pucUartTxBuf[dev->uUartTxHead]); + dev->uUartTxHead = _uartTxBufGetNextOne(nNum, dev->uUartTxHead); + + if (dev->uUartTxHead == dev->uUartTxTail) /* buffer empty */ + { + _uartDisableInterrupt(nNum, UART_IER_THRE_IEN_Msk); + break; + } + } + } +} + +/* + Call by uart1ISR(). +*/ +static void _uartCheckModemStatus(INT nNum) +{ + UINT32 volatile uRegMSR; + UINT32 uOffset = nNum * UARTOFFSET; + + UART_BUFFER_T *dev; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + FDEBUG("\n Modem INT\n"); + uRegMSR = inpw(REG_UART0_MSR + uOffset); + if (_uart_cHWTXStopped) + { + if (!(uRegMSR & 0x10)) /* CTS high, external signal is low */ + { + _uart_cHWTXStopped = 0; + FDEBUG("H/W flow control ...\n"); + + /* 2007.11.12 modify, PT23 HHWu */ + if (dev->uUartTxHead != dev->uUartTxTail) /* buffer is not empty */ + { + _uartEnableInterrupt(nNum, UART_IER_THRE_IEN_Msk); /* enable TX empty interrupt */ + FDEBUG("buf not empty, TX continued\n"); + } + } + } + else + { + if (!(uRegMSR & 0x10)) /* CTS low, external signal is high */ + { + _uart_cHWTXStopped = 1; + _uartDisableInterrupt(nNum, UART_IER_THRE_IEN_Msk); /* disable TX empty interrupt */ + FDEBUG("H/W flow control, TX stopped\n"); + } + } +} + +static INT _uartSetBaudRate(INT nNum, UART_T *val) +{ + UINT32 u32Reg; + UINT32 uOffset = nNum * UARTOFFSET; + UINT32 u32Baud_Div; + UINT32 u32Clk = val->uFreq; + UINT32 u32baudrate = val->uBaudRate; + + //if (val->uFreq > 200000000) /* Max frequency 200MHz */ + // return -1; + + u32Baud_Div = UART_BAUD_MODE2_DIVIDER(u32Clk, u32baudrate); + + if (u32Baud_Div > 0xFFFF) + u32Reg = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER(u32Clk, u32baudrate)); + else + u32Reg = (UART_BAUD_MODE2 | u32Baud_Div); + + outpw(REG_UART0_BAUD + uOffset, u32Reg); + + return 0; +} + +static void _uartInstallISR(UINT8 ucNum) +{ + UART_BUFFER_T *dev; + + IRQn_Type IRQ; + + dev = (UART_BUFFER_T *) &UART_DEV[ucNum]; + + if (ucNum == UART0) + { + IRQ = UART0_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart0ISR); + } + else if (ucNum == UART1) + { + IRQ = UART1_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart1ISR); + } + else if (ucNum == UART2) + { + IRQ = UART2_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart2ISR); + } + else if (ucNum == UART3) + { + IRQ = UART3_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart3ISR); + } + else if (ucNum == UART4) + { + IRQ = UART4_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart4ISR); + } + else if (ucNum == UART5) + { + IRQ = UART5_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart5ISR); + } + else if (ucNum == UART6) + { + IRQ = UART6_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart6ISR); + } + else if (ucNum == UART7) + { + IRQ = UART7_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart7ISR); + } + else if (ucNum == UART8) + { + IRQ = UART8_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart8ISR); + } + else if (ucNum == UART9) + { + IRQ = UART9_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart9ISR); + } + else if (ucNum == UARTA) + { + IRQ = UART10_IRQn; + dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)uart10ISR); + } + else + { + return; + } + + //dev->pvUartVector = sysInstallISR((IRQ_LEVEL_1 | HIGH_LEVEL_SENSITIVE), IRQ, (PVOID)pvNewISR); + sysSetLocalInterrupt(ENABLE_IRQ); /* enable CPSR I bit */ + sysEnableInterrupt(IRQ); + //DrvUART_EnableInt(TEST_PORT,(DRVUART_RLSINT|DRVUART_THREINT|DRVUART_RDAINT)); + + +} + +static BOOL _uartBUFSpaceAlloc(INT nNum) +{ + UART_BUFFER_T *dev; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + /* Memory allocate Tx buffer */ + dev->pucUartTxBuf = (PUINT8) malloc(UARTTXBUFSIZE[nNum] * sizeof(UINT8)); + if (dev->pucUartTxBuf == NULL) + return FALSE; + + /* Memory allocate Rx buffer */ + dev->pucUartRxBuf = (PUINT8) malloc(UARTRXBUFSIZE[nNum] * sizeof(UINT8)); + if (dev->pucUartRxBuf == NULL) + { + free(dev->pucUartTxBuf); + return FALSE; + } + + /* Memory allocate Rx character flag */ + dev->pucUARTFlag = (PINT) malloc(UARTRXBUFSIZE[nNum] * sizeof(INT)); + if (dev->pucUARTFlag == NULL) + { + free(dev->pucUartTxBuf); + free(dev->pucUartRxBuf); + return FALSE; + } + + /* initial memory */ + memset(dev->pucUartTxBuf, 0, UARTTXBUFSIZE[nNum] * sizeof(UINT8)); + memset(dev->pucUartRxBuf, 0, UARTRXBUFSIZE[nNum] * sizeof(UINT8)); + memset(dev->pucUARTFlag, 0, UARTRXBUFSIZE[nNum] * sizeof(INT)); + + /* inital struct UART_BUFFER_STRUCT, uUartTxHead, uUartTxTail, uUartRxHead, uUartRxTail */ + dev->uUartTxHead = dev->uUartTxTail = (UINT32)NULL; + dev->uUartRxHead = dev->uUartRxTail = (UINT32)NULL; + + return TRUE; +} + +static BOOL _uartCheckTxBufSpace(INT nNum, UINT32 uHead, UINT32 uTail, UINT32 uLen) +{ + UINT32 uBuf; + + uBuf = _uartTxBufGetNextOne(nNum, uTail); + if (uBuf == uHead) /* Tx buffer full */ + return FALSE; + + if (uHead == uTail) /* Tx buffer empty */ + return TRUE; + + if (uTail > uHead) + { + if (uLen >= (UARTTXBUFSIZE[nNum] - (uTail - uHead))) /* 2007.10.29 fix pointer bug, PT23 HHWu */ + return FALSE; /* Tx buffer space isn't enough */ + else + return TRUE; + } + else + { + /* case: uTail < uHead */ + if (uLen >= (uHead - uTail)) /* 2007.10.29 fix pointer bug, PT23 HHWu */ + return FALSE; /* Tx buffer space isn't enough */ + else + return TRUE; + } + + //return TRUE; +} + +static INT32 _uartReadRxBuf(INT nNum, PUINT8 pucBuf, UINT32 uLen) +{ + UINT32 i; + UINT32 uOffset = nNum * UARTOFFSET; + UART_BUFFER_T *dev; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + if (dev->bIsUseUARTRxInt == TRUE) + { + + // disable Rx interrupt ... + + if (dev->uUartRxHead == dev->uUartRxTail) + return 0; + + for (i = uLen ; i > 0 ; i--) + { + *pucBuf++ = dev->pucUartRxBuf[dev->uUartRxHead]; + dev->uUartRxHead = _uartRxBufGetNextOne(nNum, dev->uUartRxHead); + + if (dev->uUartRxHead == dev->uUartRxTail) + break; + } + + uLen = uLen - i + 1; + } + else /* pooling mode */ + { + for (i = 0 ; i < uLen; i++) + { + while (!(inpw(REG_UART0_FSR + uOffset) & UART_FSR_RX_EMPTY_Msk)); + *pucBuf++ = inpb(REG_UART0_RBR + uOffset); + } + } + + return (uLen); +} + +static void _uartWriteTxBuf(INT nNum, PUINT8 pucBuf, UINT32 uLen) +{ + UINT32 i; + UINT32 uOffset = nNum * UARTOFFSET; + UART_BUFFER_T *dev; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + /* Check interrupt or polling mode first */ + if (dev->bIsUseUARTTxInt == TRUE) + { + while (uLen--) + { + dev->pucUartTxBuf[dev->uUartTxTail] = *pucBuf++; + dev->uUartTxTail = _uartTxBufGetNextOne(nNum, dev->uUartTxTail); + } + + if (!(inpw(REG_UART0_IER + uOffset) & UART_IER_THRE_IEN_Msk)) /* Enable Tx empty interrupt */ + _uartEnableInterrupt(nNum, UART_IER_THRE_IEN_Msk); + } + else /* pooling mode */ + { + for (i = 0 ; i < uLen ; i++) + { + /* Wait until the transmitter buffer is empty */ + while (!(inpw(REG_UART0_FSR + uOffset) & UART_FSR_TE_FLAG_Msk)); + outpw(REG_UART0_THR + uOffset, *pucBuf++); + } + } +} + +static INT _uartConfigureUART(PVOID pvParam) +{ + INT retval; + BOOL bIsMemoryAllocOk; + UINT32 u32Reg; + UINT32 uOffset; + UINT32 uNum = 0; + + UART_T *param = (UART_T *) pvParam; + + uOffset = param->ucUartNo * UARTOFFSET; + uNum = param->ucUartNo; + + /* Check UART channel */ + if (uNum > UARTA) + return UART_ERR_CHANNEL_INVALID; + + /* Check the supplied parity */ + if ((param->ucParity != NU_PARITY_NONE) && + (param->ucParity != NU_PARITY_EVEN) && + (param->ucParity != NU_PARITY_ODD) && + (param->ucParity != (NU_PARITY_ODD | NU_PARITY_STICK)) && + (param->ucParity != (NU_PARITY_EVEN | NU_PARITY_STICK))) + return UART_ERR_PARITY_INVALID; + + /* Check the supplied number of data bits */ + if ((param->ucDataBits != NU_DATA_BITS_5) && + (param->ucDataBits != NU_DATA_BITS_6) && + (param->ucDataBits != NU_DATA_BITS_7) && + (param->ucDataBits != NU_DATA_BITS_8)) + return UART_ERR_DATA_BITS_INVALID; + + /* Check the supplied number of stop bits */ + if ((param->ucStopBits != NU_STOP_BITS_1) && + (param->ucStopBits != NU_STOP_BITS_2)) + return UART_ERR_STOP_BITS_INVALID; + + /* Check the supplied number of trigger level bytes */ + if ((param -> ucUartNo == UART1) || (param -> ucUartNo == UART2) || (param -> ucUartNo == UART4) || + (param -> ucUartNo == UART6) || (param -> ucUartNo == UART8) || (param -> ucUartNo == UARTA)) + { + /* UART1,2,4,6,8,A */ + if ((param->ucRxTriggerLevel != UART_FCR_RFITL_1BYTE) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_4BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_8BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_14BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_30BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_46BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_62BYTES)) + return UART_ERR_TRIGGERLEVEL_INVALID; + } + else + { + /* UART0,3,5,7,9 */ + if ((param->ucRxTriggerLevel != UART_FCR_RFITL_1BYTE) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_4BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_8BYTES) && + (param->ucRxTriggerLevel != UART_FCR_RFITL_30BYTES)) + return UART_ERR_TRIGGERLEVEL_INVALID; + } + + /* Enable UART clock */ + if (param->ucUartNo < ALLCHANNEL) + { + outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << (16 + param->ucUartNo))); + } + + /* Reset TX/RX FIFOs */ + u32Reg = inpw(REG_UART0_FCR + uOffset); + outpw(REG_UART0_FCR + uOffset, (u32Reg | (0x03 << 1))); + + /* Setup baud rate */ + retval = _uartSetBaudRate(param->ucUartNo, param); + if (retval < 0) + return UART_ERR_SET_BAUDRATE_FAIL; + + /* Setup parity, data bits, and stop bits */ + outpw(REG_UART0_LCR + uOffset, (param->ucParity | param->ucDataBits | param->ucStopBits)); + + /* Setup Rx time out value */ + outpw(REG_UART0_TOR + uOffset, 0x80 + 0x20); + + /* Setup FIFO trigger level */ + outpw(REG_UART0_FCR + uOffset, param->ucRxTriggerLevel); + + /* only exec once unless call uartClose() */ + if (UART_DEV[param->ucUartNo].bIsUARTInitial == FALSE) + { + /* Configure GPIO function */ + //_uartConfigureGPIO(param->ucUartNo); + + /* Allocate Tx, Rx buffer */ + bIsMemoryAllocOk = _uartBUFSpaceAlloc(param->ucUartNo); + if (bIsMemoryAllocOk == FALSE) + return UART_ERR_ALLOC_MEMORY_FAIL; + + /* Hook UART interrupt service routine */ + _uartInstallISR(param->ucUartNo); + + /* Enable Rx interrupt */ + if (UART_DEV[param->ucUartNo].bIsUseUARTRxInt == TRUE) + _uartEnableInterrupt(param->ucUartNo, UART_IER_RDA_IEN_Msk); + + } + + UART_DEV[param->ucUartNo].bIsUARTInitial = TRUE; /* it's important to set TRUE */ + return 0; +} + +static INT _uartPerformIrDA(INT nNum, UINT32 uCmd, UINT32 uCmd1) /* UART2 only */ +{ + UINT32 uOffset = nNum * UARTOFFSET; + UINT32 baud; + + switch (uCmd) + { + case ENABLEIrDA: + //_uart_bIsPerformIrDA = TRUE; + + baud = inpw(REG_UART0_BAUD + uOffset); + baud = baud & (0x0000ffff); + baud = baud + 2; + baud = baud / 16; + baud = baud - 2; + + outpw(REG_UART0_BAUD + uOffset, baud); + + if (uCmd1 == IrDA_TX) + outpw(REG_UART0_IRCR + uOffset, UART_IRCR_TX_SELECT_Msk); + else if (uCmd1 == IrDA_RX) + outpw(REG_UART0_IRCR + uOffset, 0x0); + else + return UART_ERR_IrDA_COMMAND_INVALID; + + outpw(REG_UART0_FUN_SEL + uOffset, 0x2); // Select IrDA mode + + break; + + case DISABLEIrDA: + //_uart_bIsPerformIrDA = FALSE; + outpw(REG_UART0_IRCR + uOffset, 0x40); /* Set default value, INV_TX set 0, INV_RX set 1 */ + outpw(REG_UART0_FUN_SEL + uOffset, 0x0); // Select UART mode + break; + + default: + return UART_ERR_IrDA_COMMAND_INVALID; + } + + return 0; +} + +/* + Remark: + 1. LCR & LSR aren't support yet. +*/ +static INT _uartGetRegisterValue(INT nNum, PVOID pvReg) +{ + INT nCnt = 0; + UINT32 uOffset = nNum * UARTOFFSET; + + UART_REGISTER_T *reg = (UART_REGISTER_T *) pvReg; + + memset(reg, 0, sizeof(UART_REGISTER_T)); + + /* Read IER */ + reg->uUartReg[nCnt][0] = REG_UART0_IER + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_IER + uOffset); + + /* Read FCR */ + reg->uUartReg[nCnt][0] = REG_UART0_FCR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_FCR + uOffset); + + /* Read LCR */ + reg->uUartReg[nCnt][0] = REG_UART0_LCR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_LCR + uOffset); + + /* Read MCR, MSR */ + reg->uUartReg[nCnt][0] = REG_UART0_MCR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_MCR + uOffset); + reg->uUartReg[nCnt][0] = REG_UART0_MSR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_MSR + uOffset); + + /* Read FSR */ + reg->uUartReg[nCnt][0] = REG_UART0_FSR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_FSR + uOffset); + + /* Read ISR */ + reg->uUartReg[nCnt][0] = REG_UART0_ISR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_ISR + uOffset); + + /* Read TOR */ + reg->uUartReg[nCnt][0] = REG_UART0_TOR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_TOR + uOffset); + + /* Read BAUD */ + reg->uUartReg[nCnt][0] = REG_UART0_BAUD + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_BAUD + uOffset); + + /* Read IRCR */ + reg->uUartReg[nCnt][0] = REG_UART0_IRCR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_IRCR + uOffset); + + /* Read ALT_CSR */ + reg->uUartReg[nCnt][0] = REG_UART0_ALT_CSR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_ALT_CSR + uOffset); + + /* Read FUN_SEL */ + reg->uUartReg[nCnt][0] = REG_UART0_FUN_SEL + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_FUN_SEL + uOffset); + + /* Read LIN_CTL */ + reg->uUartReg[nCnt][0] = REG_UART0_LIN_CTL + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_LIN_CTL + uOffset); + + /* Read LIN_SR */ + reg->uUartReg[nCnt][0] = REG_UART0_LIN_SR + uOffset; + reg->uUartReg[nCnt++][1] = inpw(REG_UART0_LIN_SR + uOffset); + + return (nCnt); +} + +/// @endcond HIDDEN_SYMBOLS + +/** @addtogroup N9H30_UART_EXPORTED_FUNCTIONS UART Exported Functions + @{ +*/ + +/** + * @brief The function is used to initial device struct parameters. + * + * @return 0 + */ +INT uartInit(void) +{ + INT i; + + /* Initial UART_BUFFER_T struct */ + for (i = 0; i < UART_NUM ; i++) + UART_DEV[i].bIsUARTInitial = FALSE; + + for (i = 0; i < UART_NUM ; i++) + UART_DEV[i].bIsUseUARTTxInt = TRUE; + + for (i = 0; i < UART_NUM ; i++) + UART_DEV[i].bIsUseUARTRxInt = TRUE; + + return 0; +} + +/** + * @brief The function is used to config UART channel. + * + * @param[in] uart: UART Port. ( UART0 / UART1 / UART2 / UART3 / UART 4 /UART 5 / + * UART6 / UART7 / UART8 / UART9 / UARTA ) + * + * @return UART_EIO: UART config Fail + * Successful: UART config success + */ +INT uartOpen(PVOID uart) +{ + INT nValue = 0; + UART_T *dev = (UART_T *) uart; + + if ((nValue = _uartConfigureUART(uart)) < 0) + { + if (nValue != UART_ERR_CHANNEL_INVALID) + UART_DEV[dev->ucUartNo].nErrno = nValue; + + return UART_EIO; + } + else + UART_DEV[dev->ucUartNo].nErrno = 0; + + return Successful; +} + +/** + * @brief The function is used to read RX FIFO returned data or RX driver buffer. + * + * @param[in] nNum: UART Port. ( UART0 / UART1 / UART2 / UART3 / UART 4 /UART 5 / + * UART6 / UART7 / UART8 / UART9 / UARTA ) + * @param[out] pucBuf: The buffer to receive. + * + * @param[in] uLen: The the read bytes number of data. + * + * @return UART_EIO: UART read Fail + * DataLength: Receive byte count + */ +INT32 uartRead(INT nNum, PUINT8 pucBuf, UINT32 uLen) +{ + UART_BUFFER_T *dev; + INT32 DataLength; + + //if((nNum < UART0) || (nNum > UART4)) + // return UART_ENODEV; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + /* Check UART initial status */ + if (dev->bIsUARTInitial == FALSE) + return UART_EIO; + + /* Check uLen value */ + if ((uLen > UARTRXBUFSIZE[nNum]) || (uLen == 0)) + return UART_EIO; + + DataLength = _uartReadRxBuf(nNum, pucBuf, uLen); + + return (DataLength); + +} + + +/** + * @brief The function is used to write data to TX FIFO directly or TX driver buffer. + * + * @param[in] nNum: UART channel. ( UART0 / UART1 / UART2 / UART3 / UART 4 /UART 5 / + * UART6 / UART7 / UART8 / UART9 / UARTA ) + * @param[out] pucBuf: Transmit buffer pointer. + * + * @param[in] uLen: Transmit buffer length. + * + * @return UART_EIO: UART transmit Fail + * uLen: write length on success + */ +INT32 uartWrite(INT nNum, PUINT8 pucBuf, UINT32 uLen) +{ + BOOL bIsTxBufEnough; + + UART_BUFFER_T *dev; + + //if((nNum < UART0) || (nNum > UART4)) + // return UART_ENODEV; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + dev->nErrno = 0; + + /* Check UART initial status */ + if (dev->bIsUARTInitial == FALSE) + return UART_EIO; + + /* Check uLen value */ + if ((uLen > UARTWRITESIZE) || (uLen == 0)) + return UART_EIO; + + /* Check UART Tx buffer */ + if (dev->bIsUseUARTTxInt == TRUE) + { + bIsTxBufEnough = _uartCheckTxBufSpace(nNum, dev->uUartTxHead, dev->uUartTxTail, uLen); + if (bIsTxBufEnough == FALSE) + { + //sysprintf("Tx buf not enough\n"); + dev->nErrno = UART_ERR_TX_BUF_NOT_ENOUGH; + return UART_EIO; + } + } + + /* Move data to UART Tx buffer then transmit */ + _uartWriteTxBuf(nNum, pucBuf, uLen); + + return (uLen); +} + +/** + * @brief Support some UART driver commands for application. + * + * @param[in] nNum: UART channel. ( UART0 / UART1 / UART2 / UART3 / UART 4 /UART 5 / + * UART6 / UART7 / UART8 / UART9 / UARTA ) + * + * @param[in] uCmd: Command. + * + * @param[in] uArg0: Arguments for the command. + * + * @param[in] uArg1: Arguments for the command. + * + * @return UART_ENODEV: UART channel out of range + * UART_EIO: No activated or argument error or configure UART fail + * Successful: Success + */ +INT uartIoctl(INT nNum, UINT32 uCmd, UINT32 uArg0, UINT32 uArg1) +{ + INT32 retval; + UINT32 uReg; + UINT32 uOffset = nNum * UARTOFFSET; + + UART_BUFFER_T *dev; + + if ((nNum < UART0) || (nNum > UARTA)) + return UART_ENODEV; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + /* Check UART initial status */ + if (dev->bIsUARTInitial == FALSE) + { + if ((uCmd != UART_IOC_GETERRNO) && + (uCmd != UART_IOC_GETUARTREGISTERVALUE)) + return UART_EIO; + } + + switch (uCmd) + { + case UART_IOC_SETTXMODE: + if (uArg0 == UARTINTMODE) + dev->bIsUseUARTTxInt = TRUE; + else if (uArg0 == UARTPOLLMODE) + dev->bIsUseUARTTxInt = FALSE; + else + { + dev->nErrno = UART_ERR_OPERATE_MODE_INVALID; + return UART_EIO; + } + + break; + + case UART_IOC_SETRXMODE: + if (uArg0 == UARTINTMODE) + { + dev->bIsUseUARTRxInt = TRUE; + _uartEnableInterrupt(nNum, UART_IER_RDA_IEN_Msk); + } + else if (uArg0 == UARTPOLLMODE) + { + dev->bIsUseUARTRxInt = FALSE; + _uartDisableInterrupt(nNum, UART_IER_RDA_IEN_Msk); + } + else + { + dev->nErrno = UART_ERR_OPERATE_MODE_INVALID; + return UART_EIO; + } + + break; + + case UART_IOC_GETRECCHARINFO: // ..... not test yet + memcpy((PVOID) uArg0, (PVOID) dev, sizeof(struct UART_BUFFER_STRUCT)); + break; + + case UART_IOC_SETUARTPARAMETER: // ..... not test yet + if ((retval = _uartConfigureUART((PVOID) uArg0)) < 0) + { + dev->nErrno = retval; + return UART_EIO; + } + + break; + + case UART_IOC_PERFORMIrDA: + + if ((retval = _uartPerformIrDA(nNum, uArg0, uArg1)) < 0) + { + dev->nErrno = retval; + return UART_EIO; + } + + break; + + case UART_IOC_GETUARTREGISTERVALUE: + return (_uartGetRegisterValue(nNum, (PVOID) uArg0)); + //break; + + case UART_IOC_GETERRNO: + *(PUINT32)uArg0 = dev->nErrno; + break; + + case UART_IOC_SETMODEMINTERRUPT: + + if (uArg0 == UART_ENABLE_MODEM_INT) + _uartEnableInterrupt(nNum, UART_IER_MODEM_IEN_Msk); + else if (uArg0 == UART_DISABLE_MODEM_INT) + _uartDisableInterrupt(nNum, UART_IER_MODEM_IEN_Msk); + else + return UART_EIO; + + break; + + case UART_IOC_GETCTSSTATE: + + if (nNum == UART1) + { + *(PUINT32)uArg0 = _uart_cCTSState1; /* CTS state */ + _uart_cCTSState1 = 0; + } + else if (nNum == UART2) + { + *(PUINT32)uArg0 = _uart_cCTSState2; /* CTS state */ + _uart_cCTSState2 = 0; + } + else if (nNum == UART3) + { + *(PUINT32)uArg0 = _uart_cCTSState3; /* CTS state */ + _uart_cCTSState3 = 0; + } + else if (nNum == UART4) + { + *(PUINT32)uArg0 = _uart_cCTSState4; /* CTS state */ + _uart_cCTSState4 = 0; + } + else if (nNum == UART5) + { + *(PUINT32)uArg0 = _uart_cCTSState5; /* CTS state */ + _uart_cCTSState5 = 0; + } + else if (nNum == UART6) + { + *(PUINT32)uArg0 = _uart_cCTSState6; /* CTS state */ + _uart_cCTSState6 = 0; + } + else if (nNum == UART7) + { + *(PUINT32)uArg0 = _uart_cCTSState7; /* CTS state */ + _uart_cCTSState7 = 0; + } + else if (nNum == UART8) + { + *(PUINT32)uArg0 = _uart_cCTSState8; /* CTS state */ + _uart_cCTSState8 = 0; + } + else if (nNum == UART9) + { + *(PUINT32)uArg0 = _uart_cCTSState9; /* CTS state */ + _uart_cCTSState9 = 0; + } + else if (nNum == UARTA) + { + *(PUINT32)uArg0 = _uart_cCTSState10; /* CTS state */ + _uart_cCTSState10 = 0; + } + + *(PUINT32)uArg1 = (inpw(REG_UART0_MSR + uOffset) & (1 << 4)) >> 4; /* get CTS# value */ + + break; + + case UART_IOC_SETRTSSIGNAL: + + if (uArg0 == UART_RTS_HIGH) /* set RTS signal high */ + outpw(REG_UART0_MCR + uOffset, inpw(REG_UART0_MCR + uOffset) & ~0x02); + else if (uArg0 == UART_RTS_LOW) /* set RTS signal low */ + outpw(REG_UART0_MCR + uOffset, inpw(REG_UART0_MCR + uOffset) | 0x02); + else + return UART_EIO; + + break; + + case UART_IOC_SETINTERRUPT: + if (uArg0 == 1) /* enable interrupt */ + _uartEnableInterrupt(nNum, uArg1); + else if (uArg0 == 0) /* disable interrupt */ + _uartDisableInterrupt(nNum, uArg1); + else + return UART_EIO; + + break; + + case UART_IOC_SETBREAKCONTROL: + uReg = inpw(REG_UART0_LCR + uOffset); + if (uArg0 == 1) /* set break contorl bit */ + { + uReg |= UART_LCR_BCB_Msk; + outpw(REG_UART0_LCR + uOffset, uReg); + } + else if (uArg0 == 0) /* clear break contorl bit */ + { + uReg &= ~UART_LCR_BCB_Msk; + outpw(REG_UART0_LCR + uOffset, uReg); + } + else + return UART_EIO; + + break; + + case UART_IOC_GETBIISTATE: + switch (nNum) + { + case UART0: + *(PUINT32)uArg0 = _uart_cBIIState_0; + break; + case UART1: + *(PUINT32)uArg0 = _uart_cBIIState_1; + break; + case UART2: + *(PUINT32)uArg0 = _uart_cBIIState_2; + break; + case UART3: + *(PUINT32)uArg0 = _uart_cBIIState_3; + break; + case UART4: + *(PUINT32)uArg0 = _uart_cBIIState_4; + break; + case UART5: + *(PUINT32)uArg0 = _uart_cBIIState_5; + break; + case UART6: + *(PUINT32)uArg0 = _uart_cBIIState_6; + break; + case UART7: + *(PUINT32)uArg0 = _uart_cBIIState_7; + break; + case UART8: + *(PUINT32)uArg0 = _uart_cBIIState_8; + break; + case UART9: + *(PUINT32)uArg0 = _uart_cBIIState_9; + break; + case UARTA: + *(PUINT32)uArg0 = _uart_cBIIState_10; + break; + + default: + break; + } + break; + + /* H/W S/W flow control function */ + case UART_IOC_ENABLEHWFLOWCONTROL: + + /* H/W & S/W are alternative */ + if (_uart_cFlowControlMode == SWFLOWCONTROL) + return UART_EIO; + + _uart_cFlowControlMode = HWFLOWCONTROL; + + /* Implement H/W flow control on TX & RX interrupt mode. */ + //dev->bIsUseUARTTxInt = TRUE; + //dev->bIsUseUARTRxInt = TRUE; + _uartEnableInterrupt(nNum, UART_IER_RDA_IEN_Msk); + + /* + Set up RTS mechanism. + In uartReceiveChars(), if uRecCnt >= _uart_nMaxRxBuf then set RTS high to stop RX. + In uartReadRxBuf(), if uRecCnt <= _uart_nMinRxBuf then set RTS low to re-start RX. + */ + //_uart_nMaxRxBuf = (UARTRXBUFSIZE[nNum] * 3) / 4; + //_uart_nMinRxBuf = UARTRXBUFSIZE[nNum] / 2; + //FDEBUG("max[%d] min[%d]\n", _uart_nMaxRxBuf, _uart_nMinRxBuf); + + /* Set RTS high level trigger */ + outpw(REG_UART0_MCR + uOffset, (inpw(REG_UART0_MCR + uOffset) | UART_RTS_IS_HIGH_LEV_TRG)); + /* Set RTS high level trigger */ + outpw(REG_UART0_MSR + uOffset, (inpw(REG_UART0_MSR + uOffset) | UART_CTS_IS_HIGH_LEV_TRG)); + + /* Set Auto CTS/RTS */ + outpw(REG_UART0_IER + uOffset, inpw(REG_UART0_IER + uOffset) | (0x3 << 12)); + + /* Enable MODEM status interrupt */ + //_uartEnableInterrupt(nNum, UART_IER_MODEM_IEN_Msk); + + /* + Maintain H/W flow control flag by read Modem Status Register. + If CTS high, stop TX. + If CTS low, start TX. + */ + //if( inpw(REG_UART0_MSR+uOffset) & 0x10 ) /* CTS external signal is low */ + // _uart_cHWTXStopped = 0; /* TX started */ + //else /* CTS external signal is high */ + // _uart_cHWTXStopped = 1; /* TX stopped */ + + /* Set RTS as logic 0, RX re-start */ + //outpb(REG_UART0_MCR+uOffset, inpb(REG_UART0_MCR+uOffset) | 0x02); /* set RTS signal low */ + //_uart_cHWRXStopped = 0; // RX started + break; + + case UART_IOC_DISABLEHWFLOWCONTROL: + + /* Disable MODEM status interrupt */ + _uartDisableInterrupt(nNum, UART_IER_MODEM_IEN_Msk); + _uart_cFlowControlMode = 0; + _uart_cHWTXStopped = 0; + _uart_cHWRXStopped = 0; + break; + + case UART_IOC_FLUSH_TX_BUFFER: + dev->uUartTxTail = 0; + dev->uUartTxHead = 0; + break; + + case UART_IOC_FLUSH_RX_BUFFER: + dev->uUartRxTail = 0; + dev->uUartRxHead = 0; + break; + + case UART_IOC_SET_RS485_MODE: + outpw((REG_UART0_FUN_SEL + uOffset), 0x3); + outpw((REG_UART0_MCR + uOffset), 0x0); + outpw((REG_UART0_LCR + uOffset), (UART_LCR_SPE_Msk | UART_LCR_EPE_Msk | UART_LCR_PBE_Msk | (0x3 << UART_LCR_WLS_Pos))); + outpw((REG_UART0_ALT_CSR + uOffset), uArg0 | (uArg1 << UART_ALT_CSR_ADDR_MATCH_Pos)); + break; + + case UART_IOC_SEND_RS485_ADDRESS: + + while (!((inpw(REG_UART0_FSR + uOffset)) & UART_FSR_TE_FLAG_Msk)); + uReg = inpw(REG_UART0_LCR + uOffset); + outpw((REG_UART0_LCR + uOffset), (UART_LCR_SPE_Msk | UART_LCR_PBE_Msk | (0x3 << UART_LCR_WLS_Pos))); + outpw((REG_UART0_THR + uOffset), uArg0); + while (!((inpw(REG_UART0_FSR + uOffset)) & UART_FSR_TE_FLAG_Msk)); + + outpw((REG_UART0_LCR + uOffset), uReg); + + break; + + case UART_IOC_SET_RS485_RXOFF: + uReg = inpw(REG_UART0_FCR + uOffset); + if (uArg0 == 1) + uReg |= UART_FCR_RX_DIS_Msk; + else + uReg &= ~UART_FCR_RX_DIS_Msk; + + outpw((REG_UART0_FCR + uOffset), uReg); + + break; + + case UART_IOC_SET_ALTCTL_REG: + + outpw((REG_UART0_ALT_CSR + uOffset), uArg0); + + break; + + case UART_IOC_GET_ALTCTL_REG: + + *(PUINT32)uArg0 = inpw(REG_UART0_ALT_CSR + uOffset); + + break; + + case UART_IOC_SET_LIN_MODE: + + outpw((REG_UART0_FUN_SEL + uOffset), 0x1); // Select LIN function + + /* Select LIN function setting : Tx enable, Rx enable and break field length */ + uReg = inpw(REG_UART0_ALT_CSR + uOffset); + uReg &= ~(UART_ALT_CSR_LIN_TX_EN_Msk | UART_ALT_CSR_LIN_RX_EN_Msk | UART_ALT_CSR_UA_LIN_BKFL_Msk); + uReg |= (uArg0 | (uArg1 << UART_ALT_CSR_UA_LIN_BKFL_Pos)); + outpw((REG_UART0_ALT_CSR + uOffset), uReg); + + break; + + default: + return UART_ENOTTY; + } + + return Successful; +} + +/** + * @brief Release memory resource, disable interrupt. + * + * @param[in] nNum: UART channel. ( UART0 / UART1 / UART2 / UART3 / UART 4 /UART 5 / + * UART6 / UART7 / UART8 / UART9 / UARTA ) + * + * @return UART_ENODEV: UART channel out of range + * UART_EIO: No activated + * Successful: Success + */ +INT32 uartRelease(INT nNum) +{ + UART_BUFFER_T *dev; + + if ((nNum < UART0) || (nNum > UARTA)) + return UART_ENODEV; + + dev = (UART_BUFFER_T *) &UART_DEV[nNum]; + + /* Check UART initial status */ + if (dev->bIsUARTInitial == FALSE) + return UART_EIO; + + /* Disable all interrupt of the specific UART */ + _uartDisableInterrupt(nNum, DISABLEALLIER); + + /* Free memory */ + free(dev->pucUartTxBuf); + free(dev->pucUartRxBuf); + free(dev->pucUARTFlag); + + /* Initial parameter */ + dev->bIsUARTInitial = FALSE; /* it's important */ + + return Successful; +} + +/*@}*/ /* end of group N9H30_UART_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_UART_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ +#else +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_uart.h" + +/** + * @brief Open and set UART function + * + * @param[in] uart The pointer of the specified UART module. + * @param[in] u32baudrate The baudrate of UART module. + * + * @return None + * + * @details This function use to enable UART function and set baud-rate. + */ +void UART_Open(UART_T *uart, uint32_t u32baudrate) +{ + uint32_t u32UartClkSrcSel = 0ul, u32UartClkDivNum = 0ul; + //uint32_t u32ClkTbl[4] = {XIN, LXT, ACLK, UCLK}; + uint32_t u32ClkTbl[4] = {12000000, 0, 75000000, 150000000}; + uint32_t u32Baud_Div = 0ul; + + if ((uint32_t)uart == UART0_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 3)) >> 3; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 5)) >> 5; + } + else if ((uint32_t)uart == UART1_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 11)) >> 11; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 13)) >> 13; + } + else if ((uint32_t)uart == UART2_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 19)) >> 19; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 21)) >> 21; + } + else if ((uint32_t)uart == UART3_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 27)) >> 27; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 29)) >> 29; + } + else if ((uint32_t)uart == UART4_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 3)) >> 3; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 5)) >> 5; + } + else if ((uint32_t)uart == UART5_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 11)) >> 11; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 13)) >> 13; + } + else if ((uint32_t)uart == UART6_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 19)) >> 19; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 21)) >> 21; + } + else if ((uint32_t)uart == UART7_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 27)) >> 27; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 29)) >> 29; + } + else if ((uint32_t)uart == UART8_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL6) & (0x3ul << 3)) >> 3; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL6) & (0x7ul << 5)) >> 5; + } + else if ((uint32_t)uart == UART9_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL6) & (0x3ul << 11)) >> 11; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL6) & (0x7ul << 13)) >> 13; + } + else if ((uint32_t)uart == UARTA_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL6) & (0x3ul << 19)) >> 19; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL6) & (0x7ul << 21)) >> 21; + } + + /* Select UART function */ + uart->FUNCSEL = UART_FUNCSEL_UART; + + /* Set UART line configuration */ + uart->LINE = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1; + + /* Set UART Rx and RTS trigger level */ + uart->FIFO &= ~(UART_FIFO_RFITL_Msk | UART_FIFO_RTSTRGLV_Msk); + + /* Get PLL clock frequency if UART clock source selection is PLL */ + if (u32UartClkSrcSel == 2ul) // ACLK + { + //u32ClkTbl[u32UartClkSrcSel] = CLK_GetPLLClockFreq(); + } + + if (u32UartClkSrcSel == 3ul) // PCLK + { + //u32ClkTbl[u32UartClkSrcSel] = CLK_GetPLLClockFreq(); + } + + /* Set UART baud rate */ + if (u32baudrate != 0ul) + { + u32Baud_Div = UART_BAUD_MODE2_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate); + + if (u32Baud_Div > 0xFFFFul) + { + uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate)); + } + else + { + uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div); + } + } +} + +void UART_Close(UART_T *uart) +{ + uart->INTEN = 0ul; +} + +/** + * @brief Set UART line configuration + * + * @param[in] uart The pointer of the specified UART module. + * @param[in] u32baudrate The register value of baudrate of UART module. + * If u32baudrate = 0, UART baudrate will not change. + * @param[in] u32data_width The data length of UART module. + * - \ref UART_WORD_LEN_5 + * - \ref UART_WORD_LEN_6 + * - \ref UART_WORD_LEN_7 + * - \ref UART_WORD_LEN_8 + * @param[in] u32parity The parity setting (none/odd/even/mark/space) of UART module. + * - \ref UART_PARITY_NONE + * - \ref UART_PARITY_ODD + * - \ref UART_PARITY_EVEN + * - \ref UART_PARITY_MARK + * - \ref UART_PARITY_SPACE + * @param[in] u32stop_bits The stop bit length (1/1.5/2 bit) of UART module. + * - \ref UART_STOP_BIT_1 + * - \ref UART_STOP_BIT_1_5 + * - \ref UART_STOP_BIT_2 + * + * @return None + * + * @details This function use to config UART line setting. + */ +void UART_SetLineConfig(UART_T *uart, uint32_t u32baudrate, uint32_t u32data_width, uint32_t u32parity, uint32_t u32stop_bits) +{ + uint32_t u32UartClkSrcSel = 0ul, u32UartClkDivNum = 0ul; + //uint32_t u32ClkTbl[4] = {XIN, LXT, ACLK, UCLK}; + uint32_t u32ClkTbl[4] = {12000000, 32768, 75000000, 150000000}; + uint32_t u32Baud_Div = 0ul; + + + if ((uint32_t)uart == UART0_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 3)) >> 3; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 5)) >> 5; + } + else if ((uint32_t)uart == UART1_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 11)) >> 11; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 13)) >> 13; + } + else if ((uint32_t)uart == UART2_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 19)) >> 19; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 21)) >> 21; + } + else if ((uint32_t)uart == UART3_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL4) & (0x3ul << 27)) >> 27; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL4) & (0x7ul << 29)) >> 29; + } + else if ((uint32_t)uart == UART4_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 3)) >> 3; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 5)) >> 5; + } + else if ((uint32_t)uart == UART5_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 11)) >> 11; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 13)) >> 13; + } + else if ((uint32_t)uart == UART6_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 19)) >> 19; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 21)) >> 21; + } + else if ((uint32_t)uart == UART7_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL5) & (0x3ul << 27)) >> 27; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL5) & (0x7ul << 29)) >> 29; + } + else if ((uint32_t)uart == UART8_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL6) & (0x3ul << 3)) >> 3; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL6) & (0x7ul << 5)) >> 5; + } + else if ((uint32_t)uart == UART9_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL6) & (0x3ul << 11)) >> 11; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL6) & (0x7ul << 13)) >> 13; + } + else if ((uint32_t)uart == UARTA_BA) + { + /* Get UART clock source selection */ + u32UartClkSrcSel = (inp32(REG_CLK_DIVCTL6) & (0x3ul << 19)) >> 19; + /* Get UART clock divider number */ + u32UartClkDivNum = (inp32(REG_CLK_DIVCTL6) & (0x7ul << 21)) >> 21; + } + + /* Get PLL clock frequency if UART clock source selection is PLL */ + if (u32UartClkSrcSel == 2ul) // ACLK + { + //u32ClkTbl[u32UartClkSrcSel] = CLK_GetPLLClockFreq(); + } + + if (u32UartClkSrcSel == 3ul) // PCLK + { + //u32ClkTbl[u32UartClkSrcSel] = CLK_GetPLLClockFreq(); + } + + /* Set UART baud rate */ + if (u32baudrate != 0ul) + { + u32Baud_Div = UART_BAUD_MODE2_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate); + + if (u32Baud_Div > 0xFFFFul) + { + uart->BAUD = (UART_BAUD_MODE0 | UART_BAUD_MODE0_DIVIDER((u32ClkTbl[u32UartClkSrcSel]) / (u32UartClkDivNum + 1ul), u32baudrate)); + } + else + { + uart->BAUD = (UART_BAUD_MODE2 | u32Baud_Div); + } + } + + /* Set UART line configuration */ + uart->LINE = u32data_width | u32parity | u32stop_bits; +} +#endif + + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_usbd.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_usbd.c new file mode 100644 index 0000000000000000000000000000000000000000..1ed8a1670a7c959e1e1b20cffe0f8538cdb778d4 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_usbd.c @@ -0,0 +1,619 @@ +/**************************************************************************//** + * @file usbd.c + * @brief N9H30 USBD driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "N9H30.h" +#include "nu_usbd.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_USBD_Driver USBD Driver + @{ +*/ + + +/** @addtogroup N9H30_USBD_EXPORTED_FUNCTIONS USBD Exported Functions + @{ +*/ +/*--------------------------------------------------------------------------*/ +/// @cond HIDDEN_SYMBOLS + +/*!< Global variables for Control Pipe */ +S_USBD_CMD_T gUsbCmd; +S_USBD_INFO_T *g_usbd_sInfo; + +VENDOR_REQ g_usbd_pfnVendorRequest = 0; +CLASS_REQ g_usbd_pfnClassRequest = 0; +SET_INTERFACE_REQ g_usbd_pfnSetInterface = 0; +uint32_t g_u32EpStallLock = 0; /*!< Bit map flag to lock specified EP when SET_FEATURE */ + +static uint8_t *g_usbd_CtrlInPointer = 0; +static uint32_t g_usbd_CtrlMaxPktSize = 64; +static uint8_t g_usbd_UsbConfig = 0; +static uint8_t g_usbd_UsbAltInterface = 0; +static uint8_t g_usbd_EnableTestMode = 0; +static uint8_t g_usbd_TestSelector = 0; + +#ifdef __ICCARM__ + #pragma data_alignment=4 + static uint8_t g_usbd_buf[12]; +#else + static uint8_t g_usbd_buf[12] __attribute__((aligned(4))); +#endif + + +uint8_t volatile g_usbd_Configured = 0; +uint8_t g_usbd_CtrlZero = 0; +uint8_t g_usbd_UsbAddr = 0; +uint8_t g_usbd_ShortPacket = 0; +uint32_t volatile g_usbd_DmaDone = 0; +uint32_t g_usbd_CtrlInSize = 0; +/// @endcond HIDDEN_SYMBOLS + +/** + * @brief USBD Initial + * + * @param[in] param Descriptor + * @param[in] pfnClassReq Class Request Callback Function + * @param[in] pfnSetInterface SetInterface Request Callback Function + * + * @return None + * + * @details This function is used to initial USBD. + */ +void USBD_Open(S_USBD_INFO_T *param, CLASS_REQ pfnClassReq, SET_INTERFACE_REQ pfnSetInterface) +{ + /* Select Vbus detect pin -> GPH0 */ + outpw(REG_SYS_GPH_MFPL, (inpw(REG_SYS_GPH_MFPL) & ~0xf) | 0x7); + /* Enable USB device clock */ + outpw(REG_CLK_HCLKEN, inpw(REG_CLK_HCLKEN) | 0x80000); + + g_usbd_sInfo = param; + g_usbd_pfnClassRequest = pfnClassReq; + g_usbd_pfnSetInterface = pfnSetInterface; + + /* get EP0 maximum packet size */ + g_usbd_CtrlMaxPktSize = g_usbd_sInfo->gu8DevDesc[7]; + + /* Initial USB engine */ + /* Enable PHY */ + USBD_ENABLE_PHY(); + /* wait PHY clock ready */ + while (1) + { + USBD->EP[EPA].EPMPS = 0x20; + if (USBD->EP[EPA].EPMPS == 0x20) + break; + } + /* Force SE0, and then clear it to connect*/ + USBD_SET_SE0(); +} + +/** + * @brief USBD Start + * + * @return None + * + * @details This function is used to start transfer + */ +void USBD_Start(void) +{ + USBD_CLR_SE0(); +} + +/** + * @brief Process Setup Packet + * + * @return None + * + * @details This function is used to process Setup packet. + */ +void USBD_ProcessSetupPacket(void) +{ + // Setup packet process + gUsbCmd.bmRequestType = (uint8_t)(USBD->SETUP1_0 & 0xff); + gUsbCmd.bRequest = (int8_t)(USBD->SETUP1_0 >> 8) & 0xff; + gUsbCmd.wValue = (uint16_t)USBD->SETUP3_2; + gUsbCmd.wIndex = (uint16_t)USBD->SETUP5_4; + gUsbCmd.wLength = (uint16_t)USBD->SETUP7_6; + + /* USB device request in setup packet: offset 0, D[6..5]: 0=Standard, 1=Class, 2=Vendor, 3=Reserved */ + switch (gUsbCmd.bmRequestType & 0x60) + { + case REQ_STANDARD: // Standard + { + USBD_StandardRequest(); + break; + } + case REQ_CLASS: // Class + { + if (g_usbd_pfnClassRequest != NULL) + { + g_usbd_pfnClassRequest(); + } + break; + } + case REQ_VENDOR: // Vendor + { + if (g_usbd_pfnVendorRequest != NULL) + { + g_usbd_pfnVendorRequest(); + } + break; + } + default: // reserved + { + /* Setup error, stall the device */ + USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk); + break; + } + } +} + +/** + * @brief Get Descriptor request + * + * @return None + * + * @details This function is used to process GetDescriptor request. + */ +int USBD_GetDescriptor(void) +{ + uint32_t u32Len; + + u32Len = gUsbCmd.wLength; + g_usbd_CtrlZero = 0; + + switch ((gUsbCmd.wValue & 0xff00) >> 8) + { + // Get Device Descriptor + case DESC_DEVICE: + { + u32Len = Minimum(u32Len, LEN_DEVICE); + USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len); + break; + } + // Get Configuration Descriptor + case DESC_CONFIG: + { + uint32_t u32TotalLen; + + u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3]; + u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8); + + u32Len = Minimum(u32Len, u32TotalLen); + if ((u32Len % g_usbd_CtrlMaxPktSize) == 0) + g_usbd_CtrlZero = 1; + + USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len); + break; + } + // Get Qualifier Descriptor + case DESC_QUALIFIER: + { + u32Len = Minimum(u32Len, LEN_QUALIFIER); + USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8QualDesc, u32Len); + break; + } + // Get Other Speed Descriptor - Full speed + case DESC_OTHERSPEED: + { + uint32_t u32TotalLen; + + u32TotalLen = g_usbd_sInfo->gu8OtherConfigDesc[3]; + u32TotalLen = g_usbd_sInfo->gu8OtherConfigDesc[2] + (u32TotalLen << 8); + + u32Len = Minimum(u32Len, u32TotalLen); + if ((u32Len % g_usbd_CtrlMaxPktSize) == 0) + g_usbd_CtrlZero = 1; + + USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8OtherConfigDesc, u32Len); + break; + } + // Get HID Descriptor + case DESC_HID: + { + u32Len = Minimum(u32Len, LEN_HID); + USBD_MemCopy(g_usbd_buf, (uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[LEN_CONFIG + LEN_INTERFACE], u32Len); + USBD_PrepareCtrlIn(g_usbd_buf, u32Len); + break; + } + // Get Report Descriptor + case DESC_HID_RPT: + { + if ((u32Len % g_usbd_CtrlMaxPktSize) == 0) + g_usbd_CtrlZero = 1; + + u32Len = Minimum(u32Len, g_usbd_sInfo->gu32HidReportSize[gUsbCmd.wIndex & 0xff]); + USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8HidReportDesc[gUsbCmd.wIndex & 0xff], u32Len); + break; + } + // Get String Descriptor + case DESC_STRING: + { + // Get String Descriptor + if ((gUsbCmd.wValue & 0xff) < 4) + { + u32Len = Minimum(u32Len, g_usbd_sInfo->gu8StringDesc[gUsbCmd.wValue & 0xff][0]); + if ((u32Len % g_usbd_CtrlMaxPktSize) == 0) + g_usbd_CtrlZero = 1; + USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8StringDesc[gUsbCmd.wValue & 0xff], u32Len); + } + else + { + USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk); + return 1; + } + break; + } + default: + // Not support. Reply STALL. + USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk); + return 1; + } + return 0; +} + + +/** + * @brief Process USB standard request + * + * @return None + * + * @details This function is used to process USB Standard Request. + */ +void USBD_StandardRequest(void) +{ + /* clear global variables for new request */ + g_usbd_CtrlInPointer = 0; + g_usbd_CtrlInSize = 0; + + if (gUsbCmd.bmRequestType & 0x80) /* request data transfer direction */ + { + // Device to host + switch (gUsbCmd.bRequest) + { + case GET_CONFIGURATION: + { + // Return current configuration setting + USBD_PrepareCtrlIn((uint8_t *)&g_usbd_UsbConfig, 1); + + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_INTKIEN_Msk); + break; + } + case GET_DESCRIPTOR: + { + if (!USBD_GetDescriptor()) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_INTKIEN_Msk); + } + break; + } + case GET_INTERFACE: + { + // Return current interface setting + USBD_PrepareCtrlIn((uint8_t *)&g_usbd_UsbAltInterface, 1); + + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_INTKIEN_Msk); + break; + } + case GET_STATUS: + { + // Device + if (gUsbCmd.bmRequestType == 0x80) + { + if (g_usbd_sInfo->gu8ConfigDesc[7] & 0x40) + g_usbd_buf[0] = 1; // Self-Powered + else + g_usbd_buf[0] = 0; // bus-Powered + } + // Interface + else if (gUsbCmd.bmRequestType == 0x81) + g_usbd_buf[0] = 0; + // Endpoint + else if (gUsbCmd.bmRequestType == 0x82) + { + uint8_t ep = gUsbCmd.wIndex & 0xF; + g_usbd_buf[0] = USBD_GetStall(ep) ? 1 : 0; + } + g_usbd_buf[1] = 0; + USBD_PrepareCtrlIn(g_usbd_buf, 2); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_INTKIEN_Msk); + break; + } + default: + { + /* Setup error, stall the device */ + USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk); + break; + } + } + } + else + { + // Host to device + switch (gUsbCmd.bRequest) + { + case CLEAR_FEATURE: + { + if ((gUsbCmd.wValue & 0xff) == FEATURE_ENDPOINT_HALT) + { + + int32_t epNum, i; + + /* EP number stall is not allow to be clear in MSC class "Error Recovery Test". + a flag: g_u32EpStallLock is added to support it */ + epNum = gUsbCmd.wIndex & 0xF; + for (i = 0; i < USBD_MAX_EP; i++) + { + if ((((USBD->EP[i].EPCFG & 0xf0) >> 4) == epNum) && ((g_u32EpStallLock & (1 << i)) == 0)) + { + USBD->EP[i].EPRSPCTL = (USBD->EP[i].EPRSPCTL & 0xef) | USB_EP_RSPCTL_TOGGLE; + } + } + } + /* Status stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + break; + } + case SET_ADDRESS: + { + g_usbd_UsbAddr = (uint8_t)gUsbCmd.wValue; + + // DATA IN for end of setup + /* Status Stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + break; + } + case SET_CONFIGURATION: + { + g_usbd_UsbConfig = (uint8_t)gUsbCmd.wValue; + g_usbd_Configured = 1; + // DATA IN for end of setup + /* Status stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + break; + } + case SET_FEATURE: + { + if ((gUsbCmd.wValue & 0x3) == 2) /* TEST_MODE*/ + { + g_usbd_EnableTestMode = 1; + g_usbd_TestSelector = gUsbCmd.wIndex >> 8; + } + /* Status stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + break; + } + case SET_INTERFACE: + { + g_usbd_UsbAltInterface = (uint8_t)gUsbCmd.wValue; + if (g_usbd_pfnSetInterface != NULL) + g_usbd_pfnSetInterface(g_usbd_UsbAltInterface); + /* Status stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + break; + } + default: + { + /* Setup error, stall the device */ + USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk); + break; + } + } + } +} + +#define TEST_J 0x01 /*!< TEST J \hideinitializer */ +#define TEST_K 0x02 /*!< TEST K \hideinitializer */ +#define TEST_SE0_NAK 0x03 /*!< TEST SE0 \hideinitializer */ +#define TEST_PACKET 0x04 /*!< TEST Packet \hideinitializer */ +#define TEST_FORCE_ENABLE 0x05 /*!< TEST Force enable \hideinitializer */ + + +/** + * @brief Update Device State + * + * @return None + * + * @details This function is used to update Device state when Setup packet complete + */ +void USBD_UpdateDeviceState(void) +{ + switch (gUsbCmd.bRequest) + { + case SET_ADDRESS: + { + USBD_SET_ADDR(g_usbd_UsbAddr); + break; + } + case SET_CONFIGURATION: + { + if (g_usbd_UsbConfig == 0) + { + int volatile i; + /* Reset PID DATA0 */ + for (i = 0; i < USBD_MAX_EP; i++) + { + if (USBD->EP[i].EPCFG & 0x1) + { + USBD->EP[i].EPRSPCTL = USB_EP_RSPCTL_TOGGLE; + } + } + } + break; + } + case SET_FEATURE: + { + if (gUsbCmd.wValue == FEATURE_ENDPOINT_HALT) + USBD_SetStall(gUsbCmd.wIndex & 0xF); + else if (g_usbd_EnableTestMode) + { + g_usbd_EnableTestMode = 0; + if (g_usbd_TestSelector == TEST_J) + USBD->TEST = TEST_J; + else if (g_usbd_TestSelector == TEST_K) + USBD->TEST = TEST_K; + else if (g_usbd_TestSelector == TEST_SE0_NAK) + USBD->TEST = TEST_SE0_NAK; + else if (g_usbd_TestSelector == TEST_PACKET) + USBD->TEST = TEST_PACKET; + else if (g_usbd_TestSelector == TEST_FORCE_ENABLE) + USBD->TEST = TEST_FORCE_ENABLE; + } + break; + } + case CLEAR_FEATURE: + { + if (gUsbCmd.wValue == FEATURE_ENDPOINT_HALT) + USBD_ClearStall(gUsbCmd.wIndex & 0xF); + break; + } + default: + ; + } +} + + +/** + * @brief Prepare Control IN transaction + * + * @param[in] pu8Buf Control IN data pointer + * @param[in] u32Size IN transfer size + * + * @return None + * + * @details This function is used to prepare Control IN transfer + */ +void USBD_PrepareCtrlIn(uint8_t *pu8Buf, uint32_t u32Size) +{ + g_usbd_CtrlInPointer = pu8Buf; + g_usbd_CtrlInSize = u32Size; +} + + + +/** + * @brief Start Control IN transfer + * + * @return None + * + * @details This function is used to start Control IN + */ +void USBD_CtrlIn(void) +{ + int volatile i; + uint32_t volatile count; + + // Process remained data + if (g_usbd_CtrlInSize >= g_usbd_CtrlMaxPktSize) + { + // Data size > MXPLD + for (i = 0; i < (g_usbd_CtrlMaxPktSize >> 2); i++, g_usbd_CtrlInPointer += 4) + USBD->cep.CEPDAT = *(uint32_t *)g_usbd_CtrlInPointer; + USBD_START_CEP_IN(g_usbd_CtrlMaxPktSize); + g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize; + } + else + { + // Data size <= MXPLD + for (i = 0; i < (g_usbd_CtrlInSize >> 2); i++, g_usbd_CtrlInPointer += 4) + USBD->cep.CEPDAT = *(uint32_t *)g_usbd_CtrlInPointer; + + count = g_usbd_CtrlInSize % 4; + for (i = 0; i < count; i++) + USBD->cep.CEPDAT_BYTE = *(uint8_t *)(g_usbd_CtrlInPointer + i); + + USBD_START_CEP_IN(g_usbd_CtrlInSize); + g_usbd_CtrlInPointer = 0; + g_usbd_CtrlInSize = 0; + } +} + +/** + * @brief Start Control OUT transaction + * + * @param[in] pu8Buf Control OUT data pointer + * @param[in] u32Size OUT transfer size + * + * @return None + * + * @details This function is used to start Control OUT transfer + */ +void USBD_CtrlOut(uint8_t *pu8Buf, uint32_t u32Size) +{ + int volatile i; + + while (1) + { + if (USBD->CEPINTSTS & USBD_CEPINTSTS_RXPKIF_Msk) + { + for (i = 0; i < u32Size; i++) + *(uint8_t *)(pu8Buf + i) = USBD->cep.CEPDAT_BYTE; + USBD->CEPINTSTS = USBD_CEPINTSTS_RXPKIF_Msk; + break; + } + } +} + +/** + * @brief Clear all software flags + * + * @return None + * + * @details This function is used to clear all software control flag + */ +void USBD_SwReset(void) +{ + // Reset all variables for protocol + g_usbd_UsbAddr = 0; + g_usbd_DmaDone = 0; + g_usbd_ShortPacket = 0; + g_usbd_Configured = 0; + + // Reset USB device address + USBD_SET_ADDR(0); +} + +/** + * @brief USBD Set Vendor Request + * + * @param[in] pfnVendorReq Vendor Request Callback Function + * + * @return None + * + * @details This function is used to set USBD vendor request callback function + */ +void USBD_SetVendorRequest(VENDOR_REQ pfnVendorReq) +{ + g_usbd_pfnVendorRequest = pfnVendorReq; +} + + +/*@}*/ /* end of group N9H30_USBD_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_USBD_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_wdt.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_wdt.c new file mode 100644 index 0000000000000000000000000000000000000000..70bb6f5a67ebc7ef1b0a6db2aab2cdee317c5984 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_wdt.c @@ -0,0 +1,66 @@ +/**************************************************************************//** + * @file wdt.c + * @brief NUC980 series WDT driver source file + * + * SPDX-License-Identifier: Apache-2.0 + * @copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "nu_wdt.h" + +/** @addtogroup Standard_Driver Standard Driver + @{ +*/ + +/** @addtogroup WDT_Driver WDT Driver + @{ +*/ + +/** @addtogroup WDT_EXPORTED_FUNCTIONS WDT Exported Functions + @{ +*/ + +/** + * @brief Initialize WDT and start counting + * + * @param[in] u32TimeoutInterval Time-out interval period of WDT module. Valid values are: + * - \ref WDT_TIMEOUT_2POW4 + * - \ref WDT_TIMEOUT_2POW6 + * - \ref WDT_TIMEOUT_2POW8 + * - \ref WDT_TIMEOUT_2POW10 + * - \ref WDT_TIMEOUT_2POW12 + * - \ref WDT_TIMEOUT_2POW14 + * - \ref WDT_TIMEOUT_2POW16 + * - \ref WDT_TIMEOUT_2POW18 + * @param[in] u32ResetDelay Configure WDT time-out reset delay period. Valid values are: + * - \ref WDT_RESET_DELAY_1026CLK + * - \ref WDT_RESET_DELAY_130CLK + * - \ref WDT_RESET_DELAY_18CLK + * - \ref WDT_RESET_DELAY_3CLK + * @param[in] u32EnableReset Enable WDT time-out reset system function. Valid values are TRUE and FALSE. + * @param[in] u32EnableWakeup Enable WDT time-out wake-up system function. Valid values are TRUE and FALSE. + * + * @return None + * + * @details This function makes WDT module start counting with different time-out interval, reset delay period and choose to \n + * enable or disable WDT time-out reset system or wake-up system. + * @note Please make sure that Register Write-Protection Function has been disabled before using this function. + */ +void WDT_Open(UINT32 u32TimeoutInterval, + UINT32 u32ResetDelay, + UINT32 u32EnableReset, + UINT32 u32EnableWakeup) +{ + + outpw(REG_WDT_ALTCTL, u32ResetDelay); + outpw(REG_WDT_CTL, u32TimeoutInterval | 0x80 | + (u32EnableReset << 1) | + (u32EnableWakeup << 4)); + return; +} + +/*@}*/ /* end of group WDT_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group WDT_Driver */ + +/*@}*/ /* end of group Standard_Driver */ + diff --git a/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_wwdt.c b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_wwdt.c new file mode 100644 index 0000000000000000000000000000000000000000..56eafed69d30bd462ecdfbb6effa012dc343aee2 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/Driver/Source/nu_wwdt.c @@ -0,0 +1,72 @@ +/**************************************************************************//** + * @file wwdt.c + * @brief N9H30 WWDT driver source file + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "N9H30.h" +#include "nu_sys.h" +#include "nu_wwdt.h" + +/** @addtogroup N9H30_Device_Driver N9H30 Device Driver + @{ +*/ + +/** @addtogroup N9H30_WWDT_Driver WWDT Driver + @{ +*/ + + +/** @addtogroup N9H30_WWDT_EXPORTED_FUNCTIONS WWDT Exported Functions + @{ +*/ + + +/** + * @brief This function make WWDT module start counting with different counter period and compared window value + * @param[in] u32PreScale Prescale period for the WWDT counter period. Valid values are: + * - \ref WWDT_PRESCALER_1 + * - \ref WWDT_PRESCALER_2 + * - \ref WWDT_PRESCALER_4 + * - \ref WWDT_PRESCALER_8 + * - \ref WWDT_PRESCALER_16 + * - \ref WWDT_PRESCALER_32 + * - \ref WWDT_PRESCALER_64 + * - \ref WWDT_PRESCALER_128 + * - \ref WWDT_PRESCALER_192 + * - \ref WWDT_PRESCALER_256 + * - \ref WWDT_PRESCALER_384 + * - \ref WWDT_PRESCALER_512 + * - \ref WWDT_PRESCALER_768 + * - \ref WWDT_PRESCALER_1024 + * - \ref WWDT_PRESCALER_1536 + * - \ref WWDT_PRESCALER_2048 + * @param[in] u32CmpValue Window compared value. Valid values are between 0x0 to 0x3F + * @param[in] u32EnableInt Enable WWDT interrupt or not. Valid values are \ref TRUE and \ref FALSE + * @return None + * @note Application can call this function can only once after boot up + */ +void WWDT_Open(UINT u32PreScale, UINT u32CmpValue, UINT u32EnableInt) +{ + UINT reg; + reg = u32PreScale | + (u32CmpValue << 16) | + 0x1 | // enable + (u32EnableInt ? 0x2 : 0); + outpw(REG_WWDT_CTL, reg); + + return; +} + + + + +/*@}*/ /* end of group N9H30_WWDT_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group N9H30_WWDT_Driver */ + +/*@}*/ /* end of group N9H30_Device_Driver */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/README.md b/bsp/nuvoton/libraries/n9h30/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a0e0561d75c324ad1baea113164f58875ccd9e01 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/README.md @@ -0,0 +1,32 @@ +# N9H30 Series + +## Supported drivers + +| Peripheral | rt_device_class_type | Device name | +| ------ | ---- | :------: | +| ADC | RT_Device_Class_Miscellaneous (ADC) | ***adc*** | +| ADC_TOUCH | RT_Device_Class_Touch | ***adc_touch*** | +| CAN | RT_Device_Class_CAN | ***can[0-1]*** | +| CRYPTO | RT_Device_Class_Miscellaneous (HW Crypto) | ***hwcryto*** | +| EMAC | RT_Device_Class_NetIf | ***e[0-1]*** | +| ETIMER | RT_Device_Class_Timer | ***etimer[0-3]*** | +| ETIMER_CAPTURE | RT_Device_Class_Miscellaneous(inputcapture) | ***etmr[0-3]i0*** | +| GE2D | N/A | ***N/A*** | +| GPIO | RT_Device_Class_Miscellaneous (Pin) | ***gpio*** | +| I2C | RT_Device_Class_I2CBUS | ***i2c[0-1]*** | +| I2S | RT_Device_Class_Sound | ***sound0*** | +| JPEGCODEC | N/A | ***N/A*** | +| PWM | RT_Device_Class_Miscellaneous (PWM) | ***pwm0*** | +| QSPI | RT_Device_Class_SPIBUS | ***qspi[0-1]*** | +| RTC | RT_Device_Class_RTC | ***rtc*** | +| SC (UART function) | RT_Device_Class_Char | ***scuart[0-1]*** | +| SDH | RT_Device_Class_Block | ***sdh[0-1]*** | +| SOFTI2C | RT_Device_Class_I2CBUS | ***softi2c[0-1]*** | +| SYS | N/A | ***N/A*** | +| SYSTICK | N/A | ***N/A*** | +| TIMER | RT_Device_Class_Timer | ***timer[0-3]*** | +| UART | RT_Device_Class_Char | ***uart[0-9]*** | +| USBD | RT_Device_Class_USBDevice | ***usbd*** | +| USBHOST | RT_Device_Class_USBHost | ***usbh*** | +| VPOST | RT_Device_Class_Graphic | ***lcd,osd*** | +| WDT | RT_Device_Class_Miscellaneous (Watchdog) | ***wdt*** | diff --git a/bsp/nuvoton/libraries/n9h30/SConscript b/bsp/nuvoton/libraries/n9h30/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..c7ef7659ecea92b1dd9b71a97736a8552ee02551 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/SConscript @@ -0,0 +1,14 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/SConscript b/bsp/nuvoton/libraries/n9h30/UsbHostLib/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..6bcad4b6300e2cb34bb4641b9c9046a2c22f2830 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/SConscript @@ -0,0 +1,12 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +group = [] +if GetDepend('BSP_USING_HSUSBH') or GetDepend('BSP_USING_USBH'): + src = Glob('*src/*.c') + Glob('src/*.cpp') + CPPPATH = [cwd + '/inc'] + group = DefineGroup('n9h30_usbhostlib', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/config.h b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/config.h new file mode 100644 index 0000000000000000000000000000000000000000..be7c96dade7a49759c6957609a3c09275e60131f --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/config.h @@ -0,0 +1,1524 @@ +/**************************************************************************//** + * @file config.h + * @version V1.00 + * @brief This header file defines the configuration of USB Host library. + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ + +#ifndef _USBH_CONFIG_H_ +#define _USBH_CONFIG_H_ + + +/// @cond HIDDEN_SYMBOLS + +#include +#include "N9H30.h" +#include "nu_sys.h" +#include "drv_sys.h" + + +/*----------------------------------------------------------------------------------------*/ +/* Hardware settings */ +/*----------------------------------------------------------------------------------------*/ +#define HCLK_MHZ 300 /* used for loop-delay. must be larger than + true HCLK clock MHz */ + +#define NON_CACHE_MASK (0x80000000) + +#define ENABLE_OHCI_IRQ() rt_hw_interrupt_umask(IRQ_OHCI) +#define DISABLE_OHCI_IRQ() rt_hw_interrupt_mask(IRQ_OHCI) +#define IS_OHCI_IRQ_ENABLED() ((inpw(REG_AIC_IMR)>>OHCI_IRQn) & 0x1) +#define ENABLE_EHCI_IRQ() rt_hw_interrupt_umask(IRQ_EHCI) +#define DISABLE_EHCI_IRQ() rt_hw_interrupt_mask(IRQ_EHCI) +#define IS_EHCI_IRQ_ENABLED() ((inpw(REG_AIC_IMR)>>EHCI_IRQn) & 0x1) + +#define ENABLE_OHCI /* Enable OHCI host controller */ +#define ENABLE_EHCI /* Enable EHCI host controller */ + +#define EHCI_PORT_CNT 2 /* Number of EHCI roothub ports */ +#define OHCI_PORT_CNT 2 /* Number of OHCI roothub ports */ +//#define OHCI_PER_PORT_POWER /* OHCI root hub per port powered */ + +#define OHCI_ISO_DELAY 4 /* preserved number frames while scheduling + OHCI isochronous transfer */ + +#define EHCI_ISO_DELAY 2 /* preserved number of frames while + scheduling EHCI isochronous transfer */ + +#define EHCI_ISO_RCLM_RANGE 32 /* When inspecting activated iTD/siTD, + unconditionally reclaim iTD/isTD scheduled + in just elapsed EHCI_ISO_RCLM_RANGE ms. */ + +#define MAX_DESC_BUFF_SIZE 4096 /* To hold the configuration descriptor, USB + core will allocate a buffer with this size + for each connected device. USB core does + not release it until device disconnected. */ + +/*----------------------------------------------------------------------------------------*/ +/* Memory allocation settings */ +/*----------------------------------------------------------------------------------------*/ + +#define STATIC_MEMORY_ALLOC 0 /* pre-allocate static memory blocks. No dynamic memory aloocation. + But the maximum number of connected devices and transfers are + limited. */ + +#define MAX_UDEV_DRIVER 8 /*!< Maximum number of registered drivers */ +#define MAX_ALT_PER_IFACE 12 /*!< maximum number of alternative interfaces per interface */ +#define MAX_EP_PER_IFACE 8 /*!< maximum number of endpoints per interface */ +#define MAX_HUB_DEVICE 8 /*!< Maximum number of hub devices */ + +/* Host controller hardware transfer descriptors memory pool. ED/TD/ITD of OHCI and QH/QTD of EHCI + are all allocated from this pool. Allocated unit size is determined by MEM_POOL_UNIT_SIZE. + May allocate one or more units depend on hardware descriptor type. */ + +#define MEM_POOL_UNIT_SIZE 128 /*!< A fixed hard coding setting. Do not change it! */ +#define MEM_POOL_UNIT_NUM 256 /*!< Increase this or heap size if memory allocate failed. */ + +/*----------------------------------------------------------------------------------------*/ +/* Re-defined staff for various compiler */ +/*----------------------------------------------------------------------------------------*/ +#ifdef __ICCARM__ + #define __inline inline +#endif + + +/*----------------------------------------------------------------------------------------*/ +/* Debug settings */ +/*----------------------------------------------------------------------------------------*/ +#define ENABLE_ERROR_MSG /* enable debug messages */ +#define ENABLE_DEBUG_MSG /* enable debug messages */ +//#define ENABLE_VERBOSE_DEBUG /* verbos debug messages */ +//#define DUMP_DESCRIPTOR /* dump descriptors */ + +#ifdef ENABLE_ERROR_MSG + #define USB_error rt_kprintf +#else + #define USB_error(...) +#endif + +#ifdef ENABLE_DEBUG_MSG + #define USB_debug rt_kprintf + #ifdef ENABLE_VERBOSE_DEBUG + #define USB_vdebug rt_kprintf + #else + #define USB_vdebug(...) + #endif +#else + #define USB_debug(...) + #define USB_vdebug(...) +#endif + + +#define __I volatile const /*!< Defines 'read only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + + +//typedef unsigned int uint32_t; +//typedef unsigned short uint16_t; +//typedef unsigned char uint8_t; + + + +/*---------------------- USB Host Controller -------------------------*/ +/** + @addtogroup USBH USB Host Controller(USBH) + Memory Mapped Structure for USBH Controller +@{ */ + +typedef struct +{ + + /** + * @var USBH_T::HcRevision + * Offset: 0x00 Host Controller Revision Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |REV |Revision Number + * | | |Indicates the Open HCI Specification revision number implemented by the Hardware + * | | |Host Controller supports 1.1 specification. + * | | |(X.Y = XYh). + * @var USBH_T::HcControl + * Offset: 0x04 Host Controller Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[1:0] |CBSR |Control Bulk Service Ratio + * | | |This specifies the service ratio between Control and Bulk EDs + * | | |Before processing any of the non-periodic lists, HC must compare the ratio specified with its internal count on how many nonempty Control EDs have been processed, in determining whether to continue serving another Control ED or switching to Bulk EDs + * | | |The internal count will be retained when crossing the frame boundary + * | | |In case of reset, HCD is responsible for restoring this + * | | |Value. + * | | |00 = Number of Control EDs over Bulk EDs served is 1:1. + * | | |01 = Number of Control EDs over Bulk EDs served is 2:1. + * | | |10 = Number of Control EDs over Bulk EDs served is 3:1. + * | | |11 = Number of Control EDs over Bulk EDs served is 4:1. + * |[2] |PLE |Periodic List Enable Bit + * | | |When set, this bit enables processing of the Periodic (interrupt and isochronous) list + * | | |The Host Controller checks this bit prior to attempting any periodic transfers in a frame. + * | | |0 = Processing of the Periodic (Interrupt and Isochronous) list after next SOF (Start-Of-Frame) Disabled. + * | | |1 = Processing of the Periodic (Interrupt and Isochronous) list in the next frame Enabled. + * | | |Note: To enable the processing of the Isochronous list, user has to set both PLE and IE (HcControl[3]) high. + * |[3] |IE |Isochronous List Enable Bit + * | | |Both ISOEn and PLE (HcControl[2]) high enables Host Controller to process the Isochronous list + * | | |Either ISOEn or PLE (HcControl[2]) is low disables Host Controller to process the Isochronous list. + * | | |0 = Processing of the Isochronous list after next SOF (Start-Of-Frame) Disabled. + * | | |1 = Processing of the Isochronous list in the next frame Enabled, if the PLE (HcControl[2]) is high, too. + * |[4] |CLE |Control List Enable Bit + * | | |0 = Processing of the Control list after next SOF (Start-Of-Frame) Disabled. + * | | |1 = Processing of the Control list in the next frame Enabled. + * |[5] |BLE |Bulk List Enable Bit + * | | |0 = Processing of the Bulk list after next SOF (Start-Of-Frame) Disabled. + * | | |1 = Processing of the Bulk list in the next frame Enabled. + * |[7:6] |HCFS |Host Controller Functional State + * | | |This field sets the Host Controller state + * | | |The Controller may force a state change from USBSUSPEND to USBRESUME after detecting resume signaling from a downstream port + * | | |States are: + * | | |00 = USBSUSPEND. + * | | |01 = USBOPERATIONAL. + * | | |10 = USBRESUME. + * | | |11 = USBRESET. + * @var USBH_T::HcCommandStatus + * Offset: 0x08 Host Controller Command Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |HCR |Host Controller Reset + * | | |This bit is set to initiate the software reset of Host Controller + * | | |This bit is cleared by the Host Controller, upon completed of the reset operation. + * | | |This bit, when set, didn't reset the Root Hub and no subsequent reset signaling be asserted to its downstream ports. + * | | |0 = Host Controller is not in software reset state. + * | | |1 = Host Controller is in software reset state. + * |[1] |CLF |Control List Filled + * | | |Set high to indicate there is an active TD on the Control List + * | | |It may be set by either software or the Host Controller and cleared by the Host Controller each time it begins processing the head of the Control List. + * | | |0 = No active TD found or Host Controller begins to process the head of the Control list. + * | | |1 = An active TD added or found on the Control list. + * |[2] |BLF |Bulk List Filled + * | | |Set high to indicate there is an active TD on the Bulk list + * | | |This bit may be set by either software or the Host Controller and cleared by the Host Controller each time it begins processing the head of the Bulk list. + * | | |0 = No active TD found or Host Controller begins to process the head of the Bulk list. + * | | |1 = An active TD added or found on the Bulk list. + * |[17:16] |SOC |Schedule Overrun Count + * | | |These bits are incremented on each scheduling overrun error + * | | |It is initialized to 00b and wraps around at 11b + * | | |This will be incremented when a scheduling overrun is detected even if SO (HcInterruptStatus[0]) has already been set. + * @var USBH_T::HcInterruptStatus + * Offset: 0x0C Host Controller Interrupt Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |SO |Scheduling Overrun + * | | |Set when the List Processor determines a Schedule Overrun has occurred. + * | | |0 = Schedule Overrun didn't occur. + * | | |1 = Schedule Overrun has occurred. + * |[1] |WDH |Write Back Done Head + * | | |Set after the Host Controller has written HcDoneHead to HccaDoneHead + * | | |Further updates of the HccaDoneHead will not occur until this bit has been cleared. + * | | |0 =.Host Controller didn't update HccaDoneHead. + * | | |1 =.Host Controller has written HcDoneHead to HccaDoneHead. + * |[2] |SF |Start of Frame + * | | |Set when the Frame Management functional block signals a 'Start of Frame' event + * | | |Host Control generates a SOF token at the same time. + * | | |0 =.Not the start of a frame. + * | | |1 =.Indicate the start of a frame and Host Controller generates a SOF token. + * |[3] |RD |Resume Detected + * | | |Set when Host Controller detects resume signaling on a downstream port. + * | | |0 = No resume signaling detected on a downstream port. + * | | |1 = Resume signaling detected on a downstream port. + * |[5] |FNO |Frame Number Overflow + * | | |This bit is set when bit 15 of Frame Number changes from 1 to 0 or from 0 to 1. + * | | |0 = The bit 15 of Frame Number didn't change. + * | | |1 = The bit 15 of Frame Number changes from 1 to 0 or from 0 to 1. + * |[6] |RHSC |Root Hub Status Change + * | | |This bit is set when the content of HcRhStatus or the content of HcRhPortStatus register has changed. + * | | |0 = The content of HcRhStatus and the content of HcRhPortStatus register didn't change. + * | | |1 = The content of HcRhStatus or the content of HcRhPortStatus register has changed. + * @var USBH_T::HcInterruptEnable + * Offset: 0x10 Host Controller Interrupt Enable Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |SO |Scheduling Overrun Enable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to SO (HcInterruptStatus[0]) Enabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to SO (HcInterruptStatus[0]) Disabled. + * | | |1 = Interrupt generation due to SO (HcInterruptStatus[0]) Enabled. + * |[1] |WDH |Write Back Done Head Enable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to WDH (HcInterruptStatus[1]) Enabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to WDH (HcInterruptStatus[1]) Disabled. + * | | |1 = Interrupt generation due to WDH (HcInterruptStatus[1]) Enabled. + * |[2] |SF |Start of Frame Enable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to SF (HcInterruptStatus[2]) Enabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to SF (HcInterruptStatus[2]) Disabled. + * | | |1 = Interrupt generation due to SF (HcInterruptStatus[2]) Enabled. + * |[3] |RD |Resume Detected Enable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to RD (HcInterruptStatus[3]) Enabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to RD (HcInterruptStatus[3]) Disabled. + * | | |1 = Interrupt generation due to RD (HcInterruptStatus[3]) Enabled. + * |[5] |FNO |Frame Number Overflow Enable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to FNO (HcInterruptStatus[5]) Enabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to FNO (HcInterruptStatus[5]) Disabled. + * | | |1 = Interrupt generation due to FNO (HcInterruptStatus[5]) Enabled. + * |[6] |RHSC |Root Hub Status Change Enable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]) Enabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to RHSC (HcInterruptStatus[6]) Disabled. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]) Enabled. + * |[31] |MIE |Master Interrupt Enable Bit + * | | |This bit is a global interrupt enable + * | | |A write of '1' allows interrupts to be enabled via the specific enable bits listed above. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]), FNO (HcInterruptStatus[5]), RD (HcInterruptStatus[3]), SF (HcInterruptStatus[2]), WDH (HcInterruptStatus[1]) or SO (HcInterruptStatus[0]) Enabled if the corresponding bit in HcInterruptEnable is high. + * | | |Read Operation: + * | | |0 = Interrupt generation due to RHSC (HcInterruptStatus[6]), FNO (HcInterruptStatus[5]), RD (HcInterruptStatus[3]), SF (HcInterruptStatus[2]), WDH (HcInterruptStatus[1]) or SO (HcInterruptStatus[0]) Disabled even if the corresponding bit in HcInterruptEnable is high. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]), FNO (HcInterruptStatus[5]), RD (HcInterruptStatus[3]), SF (HcInterruptStatus[2]), WDH (HcInterruptStatus[1]) or SO (HcInterruptStatus[0]) Enabled if the corresponding bit in HcInterruptEnable is high. + * @var USBH_T::HcInterruptDisable + * Offset: 0x14 Host Controller Interrupt Disable Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |SO |Scheduling Overrun Disable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to SO (HcInterruptStatus[0]) Disabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to SO (HcInterruptStatus[0]) Disabled. + * | | |1 = Interrupt generation due to SO (HcInterruptStatus[0]) Enabled. + * |[1] |WDH |Write Back Done Head Disable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to WDH (HcInterruptStatus[1]) Disabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to WDH (HcInterruptStatus[1]) Disabled. + * | | |1 = Interrupt generation due to WDH (HcInterruptStatus[1]) Enabled. + * |[2] |SF |Start of Frame Disable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to SF (HcInterruptStatus[2]) Disabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to SF (HcInterruptStatus[2]) Disabled. + * | | |1 = Interrupt generation due to SF (HcInterruptStatus[2]) Enabled. + * |[3] |RD |Resume Detected Disable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to RD (HcInterruptStatus[3]) Disabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to RD (HcInterruptStatus[3]) Disabled. + * | | |1 = Interrupt generation due to RD (HcInterruptStatus[3]) Enabled. + * |[5] |FNO |Frame Number Overflow Disable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to FNO (HcInterruptStatus[5]) Disabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to FNO (HcInterruptStatus[5]) Disabled. + * | | |1 = Interrupt generation due to FNO (HcInterruptStatus[5]) Enabled. + * |[6] |RHSC |Root Hub Status Change Disable Bit + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]) Disabled. + * | | |Read Operation: + * | | |0 = Interrupt generation due to RHSC (HcInterruptStatus[6]) Disabled. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]) Enabled. + * |[31] |MIE |Master Interrupt Disable Bit + * | | |Global interrupt disable. Writing '1' to disable all interrupts. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]), FNO (HcInterruptStatus[5]), RD (HcInterruptStatus[3]), SF (HcInterruptStatus[2]), WDH (HcInterruptStatus[1]) or SO (HcInterruptStatus[0]) Disabled if the corresponding bit in HcInterruptEnable is high. + * | | |Read Operation: + * | | |0 = Interrupt generation due to RHSC (HcInterruptStatus[6]), FNO (HcInterruptStatus[5]), RD (HcInterruptStatus[3]), SF (HcInterruptStatus[2]), WDH (HcInterruptStatus[1]) or SO (HcInterruptStatus[0]) Disabled even if the corresponding bit in HcInterruptEnable is high. + * | | |1 = Interrupt generation due to RHSC (HcInterruptStatus[6]), FNO (HcInterruptStatus[5]), RD (HcInterruptStatus[3]), SF (HcInterruptStatus[2]), WDH (HcInterruptStatus[1]) or SO (HcInterruptStatus[0]) Enabled if the corresponding bit in HcInterruptEnable is high. + * @var USBH_T::HcHCCA + * Offset: 0x18 Host Controller Communication Area Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:8] |HCCA |Host Controller Communication Area + * | | |Pointer to indicate base address of the Host Controller Communication Area (HCCA). + * @var USBH_T::HcPeriodCurrentED + * Offset: 0x1C Host Controller Period Current ED Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:4] |PCED |Periodic Current ED + * | | |Pointer to indicate physical address of the current Isochronous or Interrupt Endpoint Descriptor. + * @var USBH_T::HcControlHeadED + * Offset: 0x20 Host Controller Control Head ED Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:4] |CHED |Control Head ED + * | | |Pointer to indicate physical address of the first Endpoint Descriptor of the Control list. + * @var USBH_T::HcControlCurrentED + * Offset: 0x24 Host Controller Control Current ED Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:4] |CCED |Control Current Head ED + * | | |Pointer to indicate the physical address of the current Endpoint Descriptor of the Control list. + * @var USBH_T::HcBulkHeadED + * Offset: 0x28 Host Controller Bulk Head ED Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:4] |BHED |Bulk Head ED + * | | |Pointer to indicate the physical address of the first Endpoint Descriptor of the Bulk list. + * @var USBH_T::HcBulkCurrentED + * Offset: 0x2C Host Controller Bulk Current ED Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:4] |BCED |Bulk Current Head ED + * | | |Pointer to indicate the physical address of the current endpoint of the Bulk list. + * @var USBH_T::HcDoneHead + * Offset: 0x30 Host Controller Done Head Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:4] |DH |Done Head + * | | |Pointer to indicate the physical address of the last completed Transfer Descriptor that was added to the Done queue. + * @var USBH_T::HcFmInterval + * Offset: 0x34 Host Controller Frame Interval Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[13:0] |FI |Frame Interval + * | | |This field specifies the length of a frame as (bit times - 1) + * | | |For 12,000 bit times in a frame, a value of 11,999 is stored here. + * |[30:16] |FSMPS |FS Largest Data Packet + * | | |This field specifies a value that is loaded into the Largest Data Packet Counter at the beginning of each frame. + * |[31] |FIT |Frame Interval Toggle + * | | |This bit is toggled by Host Controller Driver when it loads a new value into FI (HcFmInterval[13:0]). + * | | |0 = Host Controller Driver didn't load new value into FI (HcFmInterval[13:0]). + * | | |1 = Host Controller Driver loads a new value into FI (HcFmInterval[13:0]). + * @var USBH_T::HcFmRemaining + * Offset: 0x38 Host Controller Frame Remaining Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[13:0] |FR |Frame Remaining + * | | |When the Host Controller is in the USBOPERATIONAL state, this 14-bit field decrements each 12 MHz clock period + * | | |When the count reaches 0, (end of frame) the counter reloads with Frame Interval + * | | |In addition, the counter loads when the Host Controller transitions into USBOPERATIONAL. + * |[31] |FRT |Frame Remaining Toggle + * | | |This bit is loaded from the FIT (HcFmInterval[31]) whenever FR (HcFmRemaining[13:0]) reaches 0. + * @var USBH_T::HcFmNumber + * Offset: 0x3C Host Controller Frame Number Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[15:0] |FN |Frame Number + * | | |This 16-bit incrementing counter field is incremented coincident with the re-load of FR (HcFmRemaining[13:0]) + * | | |The count rolls over from 'FFFFh' to '0h.' + * @var USBH_T::HcPeriodicStart + * Offset: 0x40 Host Controller Periodic Start Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[13:0] |PS |Periodic Start + * | | |This field contains a value used by the List Processor to determine where in a frame the Periodic List processing must begin. + * @var USBH_T::HcLSThreshold + * Offset: 0x44 Host Controller Low-speed Threshold Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[11:0] |LST |Low-speed Threshold + * | | |This field contains a value which is compared to the FR (HcFmRemaining[13:0]) field prior to initiating a Low-speed transaction + * | | |The transaction is started only if FR (HcFmRemaining[13:0]) >= this field + * | | |The value is calculated by Host Controller Driver with the consideration of transmission and setup overhead. + * @var USBH_T::HcRhDescriptorA + * Offset: 0x48 Host Controller Root Hub Descriptor A Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |NDP |Number Downstream Ports + * | | |USB host control supports two downstream ports and only one port is available in this series of chip. + * |[8] |PSM |Power Switching Mode + * | | |This bit is used to specify how the power switching of the Root Hub ports is controlled. + * | | |0 = Global Switching. + * | | |1 = Individual Switching. + * |[11] |OCPM |over Current Protection Mode + * | | |This bit describes how the over current status for the Root Hub ports reported + * | | |This bit is only valid when NOCP (HcRhDescriptorA[12]) is cleared. + * | | |0 = Global Over current. + * | | |1 = Individual Over current. + * |[12] |NOCP |No over Current Protection + * | | |This bit describes how the over current status for the Root Hub ports reported. + * | | |0 = Over current status is reported. + * | | |1 = Over current status is not reported. + * @var USBH_T::HcRhDescriptorB + * Offset: 0x4C Host Controller Root Hub Descriptor B Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:16] |PPCM |Port Power Control Mask + * | | |Global power switching + * | | |This field is only valid if PowerSwitchingMode is set (individual port switching) + * | | |When set, the port only responds to individual port power switching commands (Set/ClearPortPower) + * | | |When cleared, the port only responds to global power switching commands (Set/ClearGlobalPower). + * | | |0 = Port power controlled by global power switching. + * | | |1 = Port power controlled by port power switching. + * | | |Note: PPCM[15:2] and PPCM[0] are reserved. + * @var USBH_T::HcRhStatus + * Offset: 0x50 Host Controller Root Hub Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |LPS |Clear Global Power + * | | |In global power mode (PSM (HcRhDescriptorA[8]) = 0), this bit is written to one to clear all ports' power. + * | | |This bit always read as zero. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Clear global power. + * |[1] |OCI |over Current Indicator + * | | |This bit reflects the state of the over current status pin + * | | |This field is only valid if NOCP (HcRhDesA[12]) and OCPM (HcRhDesA[11]) are cleared. + * | | |0 = No over current condition. + * | | |1 = Over current condition. + * |[15] |DRWE |Device Remote Wakeup Enable Bit + * | | |This bit controls if port's Connect Status Change as a remote wake-up event. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Connect Status Change as a remote wake-up event Enabled. + * | | |Read Operation: + * | | |0 = Connect Status Change as a remote wake-up event Disabled. + * | | |1 = Connect Status Change as a remote wake-up event Enabled. + * |[16] |LPSC |Set Global Power + * | | |In global power mode (PSM (HcRhDescriptorA[8]) = 0), this bit is written to one to enable power to all ports. + * | | |This bit always read as zero. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Set global power. + * |[17] |OCIC |over Current Indicator Change + * | | |This bit is set by hardware when a change has occurred in OCI (HcRhStatus[1]). + * | | |Write 1 to clear this bit to zero. + * | | |0 = OCI (HcRhStatus[1]) didn't change. + * | | |1 = OCI (HcRhStatus[1]) change. + * |[31] |CRWE |Clear Remote Wake-up Enable Bit + * | | |This bit is use to clear DRWE (HcRhStatus[15]). + * | | |This bit always read as zero. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Clear DRWE (HcRhStatus[15]). + * @var USBH_T::HcRhPortStatus[2] + * Offset: 0x54 Host Controller Root Hub Port Status + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |CCS |CurrentConnectStatus (Read) or ClearPortEnable Bit (Write) + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Clear port enable. + * | | |Read Operation: + * | | |0 = No device connected. + * | | |1 = Device connected. + * |[1] |PES |Port Enable Status + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Set port enable. + * | | |Read Operation: + * | | |0 = Port Disabled. + * | | |1 = Port Enabled. + * |[2] |PSS |Port Suspend Status + * | | |This bit indicates the port is suspended + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Set port suspend. + * | | |Read Operation: + * | | |0 = Port is not suspended. + * | | |1 = Port is selectively suspended. + * |[3] |POCI |Port over Current Indicator (Read) or Clear Port Suspend (Write) + * | | |This bit reflects the state of the over current status pin dedicated to this port + * | | |This field is only valid if NOCP (HcRhDescriptorA[12]) is cleared and OCPM (HcRhDescriptorA[11]) is set. + * | | |This bit is also used to initiate the selective result sequence for the port. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Clear port suspend. + * | | |Read Operation: + * | | |0 = No over current condition. + * | | |1 = Over current condition. + * |[4] |PRS |Port Reset Status + * | | |This bit reflects the reset state of the port. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Set port reset. + * | | |Read Operation + * | | |0 = Port reset signal is not active. + * | | |1 = Port reset signal is active. + * |[8] |PPS |Port Power Status + * | | |This bit reflects the power state of the port regardless of the power switching mode. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Port Power Enabled. + * | | |Read Operation: + * | | |0 = Port power is Disabled. + * | | |1 = Port power is Enabled. + * |[9] |LSDA |Low Speed Device Attached (Read) or Clear Port Power (Write) + * | | |This bit defines the speed (and bud idle) of the attached device + * | | |It is only valid when CCS (HcRhPortStatus1[0]) is set. + * | | |This bit is also used to clear port power. + * | | |Write Operation: + * | | |0 = No effect. + * | | |1 = Clear PPS (HcRhPortStatus1[8]). + * | | |Read Operation: + * | | |0 = Full Speed device. + * | | |1 = Low-speed device. + * |[16] |CSC |Connect Status Change + * | | |This bit indicates connect or disconnect event has been detected (CCS (HcRhPortStatus1[0]) changed). + * | | |Write 1 to clear this bit to zero. + * | | |0 = No connect/disconnect event (CCS (HcRhPortStatus1[0]) didn't change). + * | | |1 = Hardware detection of connect/disconnect event (CCS (HcRhPortStatus1[0]) changed). + * |[17] |PESC |Port Enable Status Change + * | | |This bit indicates that the port has been disabled (PES (HcRhPortStatus1[1]) cleared) due to a hardware event. + * | | |Write 1 to clear this bit to zero. + * | | |0 = PES (HcRhPortStatus1[1]) didn't change. + * | | |1 = PES (HcRhPortStatus1[1]) changed. + * |[18] |PSSC |Port Suspend Status Change + * | | |This bit indicates the completion of the selective resume sequence for the port. + * | | |Write 1 to clear this bit to zero. + * | | |0 = Port resume is not completed. + * | | |1 = Port resume completed. + * |[19] |OCIC |Port over Current Indicator Change + * | | |This bit is set when POCI (HcRhPortStatus1[3]) changes. + * | | |Write 1 to clear this bit to zero. + * | | |0 = POCI (HcRhPortStatus1[3]) didn't change. + * | | |1 = POCI (HcRhPortStatus1[3]) changes. + * |[20] |PRSC |Port Reset Status Change + * | | |This bit indicates that the port reset signal has completed. + * | | |Write 1 to clear this bit to zero. + * | | |0 = Port reset is not complete. + * | | |1 = Port reset is complete. + * @var USBH_T::HcPhyControl + * Offset: 0x200 Host Controller PHY Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[27] |STBYEN |USB Transceiver Standby Enable Bit + * | | |This bit controls if USB transceiver could enter the standby mode to reduce power consumption. + * | | |0 = The USB transceiver would never enter the standby mode. + * | | |1 = The USB transceiver will enter standby mode while port is in power off state (port power is inactive). + * @var USBH_T::HcMiscControl + * Offset: 0x204 Host Controller Miscellaneous Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[1] |ABORT |AHB Bus ERROR Response + * | | |This bit indicates there is an ERROR response received in AHB bus. + * | | |0 = No ERROR response received. + * | | |1 = ERROR response received. + * |[3] |OCAL |over Current Active Low + * | | |This bit controls the polarity of over current flag from external power IC. + * | | |0 = Over current flag is high active. + * | | |1 = Over current flag is low active. + * |[16] |DPRT1 |Disable Port 1 + * | | |This bit controls if the connection between USB host controller and transceiver of port 1 is disabled + * | | |If the connection is disabled, the USB host controller will not recognize any event of USB bus. + * | | |Set this bit high, the transceiver of port 1 will also be forced into the standby mode no matter what USB host controller operation is. + * | | |0 = The connection between USB host controller and transceiver of port 1 Enabled. + * | | |1 = The connection between USB host controller and transceiver of port 1 Disabled and the transceiver of port 1 will also be forced into the standby mode. + */ + __I uint32_t HcRevision; /*!< [0x0000] Host Controller Revision Register */ + __IO uint32_t HcControl; /*!< [0x0004] Host Controller Control Register */ + __IO uint32_t HcCommandStatus; /*!< [0x0008] Host Controller Command Status Register */ + __IO uint32_t HcInterruptStatus; /*!< [0x000c] Host Controller Interrupt Status Register */ + __IO uint32_t HcInterruptEnable; /*!< [0x0010] Host Controller Interrupt Enable Register */ + __IO uint32_t HcInterruptDisable; /*!< [0x0014] Host Controller Interrupt Disable Register */ + __IO uint32_t HcHCCA; /*!< [0x0018] Host Controller Communication Area Register */ + __IO uint32_t HcPeriodCurrentED; /*!< [0x001c] Host Controller Period Current ED Register */ + __IO uint32_t HcControlHeadED; /*!< [0x0020] Host Controller Control Head ED Register */ + __IO uint32_t HcControlCurrentED; /*!< [0x0024] Host Controller Control Current ED Register */ + __IO uint32_t HcBulkHeadED; /*!< [0x0028] Host Controller Bulk Head ED Register */ + __IO uint32_t HcBulkCurrentED; /*!< [0x002c] Host Controller Bulk Current ED Register */ + __IO uint32_t HcDoneHead; /*!< [0x0030] Host Controller Done Head Register */ + __IO uint32_t HcFmInterval; /*!< [0x0034] Host Controller Frame Interval Register */ + __I uint32_t HcFmRemaining; /*!< [0x0038] Host Controller Frame Remaining Register */ + __I uint32_t HcFmNumber; /*!< [0x003c] Host Controller Frame Number Register */ + __IO uint32_t HcPeriodicStart; /*!< [0x0040] Host Controller Periodic Start Register */ + __IO uint32_t HcLSThreshold; /*!< [0x0044] Host Controller Low-speed Threshold Register */ + __IO uint32_t HcRhDescriptorA; /*!< [0x0048] Host Controller Root Hub Descriptor A Register */ + __IO uint32_t HcRhDescriptorB; /*!< [0x004c] Host Controller Root Hub Descriptor B Register */ + __IO uint32_t HcRhStatus; /*!< [0x0050] Host Controller Root Hub Status Register */ + __IO uint32_t HcRhPortStatus[2]; /*!< [0x0054] Host Controller Root Hub Port Status [1] */ + __I uint32_t RESERVE0[105]; + __IO uint32_t HcPhyControl; /*!< [0x0200] Host Controller PHY Control Register */ + __IO uint32_t HcMiscControl; /*!< [0x0204] Host Controller Miscellaneous Control Register */ + +} USBH_T; + +/** + @addtogroup USBH_CONST USBH Bit Field Definition + Constant Definitions for USBH Controller +@{ */ + +#define USBH_HcRevision_REV_Pos (0) /*!< USBH_T::HcRevision: REV Position */ +#define USBH_HcRevision_REV_Msk (0xfful << USBH_HcRevision_REV_Pos) /*!< USBH_T::HcRevision: REV Mask */ + +#define USBH_HcControl_CBSR_Pos (0) /*!< USBH_T::HcControl: CBSR Position */ +#define USBH_HcControl_CBSR_Msk (0x3ul << USBH_HcControl_CBSR_Pos) /*!< USBH_T::HcControl: CBSR Mask */ + +#define USBH_HcControl_PLE_Pos (2) /*!< USBH_T::HcControl: PLE Position */ +#define USBH_HcControl_PLE_Msk (0x1ul << USBH_HcControl_PLE_Pos) /*!< USBH_T::HcControl: PLE Mask */ + +#define USBH_HcControl_IE_Pos (3) /*!< USBH_T::HcControl: IE Position */ +#define USBH_HcControl_IE_Msk (0x1ul << USBH_HcControl_IE_Pos) /*!< USBH_T::HcControl: IE Mask */ + +#define USBH_HcControl_CLE_Pos (4) /*!< USBH_T::HcControl: CLE Position */ +#define USBH_HcControl_CLE_Msk (0x1ul << USBH_HcControl_CLE_Pos) /*!< USBH_T::HcControl: CLE Mask */ + +#define USBH_HcControl_BLE_Pos (5) /*!< USBH_T::HcControl: BLE Position */ +#define USBH_HcControl_BLE_Msk (0x1ul << USBH_HcControl_BLE_Pos) /*!< USBH_T::HcControl: BLE Mask */ + +#define USBH_HcControl_HCFS_Pos (6) /*!< USBH_T::HcControl: HCFS Position */ +#define USBH_HcControl_HCFS_Msk (0x3ul << USBH_HcControl_HCFS_Pos) /*!< USBH_T::HcControl: HCFS Mask */ + +#define USBH_HcCommandStatus_HCR_Pos (0) /*!< USBH_T::HcCommandStatus: HCR Position */ +#define USBH_HcCommandStatus_HCR_Msk (0x1ul << USBH_HcCommandStatus_HCR_Pos) /*!< USBH_T::HcCommandStatus: HCR Mask */ + +#define USBH_HcCommandStatus_CLF_Pos (1) /*!< USBH_T::HcCommandStatus: CLF Position */ +#define USBH_HcCommandStatus_CLF_Msk (0x1ul << USBH_HcCommandStatus_CLF_Pos) /*!< USBH_T::HcCommandStatus: CLF Mask */ + +#define USBH_HcCommandStatus_BLF_Pos (2) /*!< USBH_T::HcCommandStatus: BLF Position */ +#define USBH_HcCommandStatus_BLF_Msk (0x1ul << USBH_HcCommandStatus_BLF_Pos) /*!< USBH_T::HcCommandStatus: BLF Mask */ + +#define USBH_HcCommandStatus_SOC_Pos (16) /*!< USBH_T::HcCommandStatus: SOC Position */ +#define USBH_HcCommandStatus_SOC_Msk (0x3ul << USBH_HcCommandStatus_SOC_Pos) /*!< USBH_T::HcCommandStatus: SOC Mask */ + +#define USBH_HcInterruptStatus_SO_Pos (0) /*!< USBH_T::HcInterruptStatus: SO Position */ +#define USBH_HcInterruptStatus_SO_Msk (0x1ul << USBH_HcInterruptStatus_SO_Pos) /*!< USBH_T::HcInterruptStatus: SO Mask */ + +#define USBH_HcInterruptStatus_WDH_Pos (1) /*!< USBH_T::HcInterruptStatus: WDH Position*/ +#define USBH_HcInterruptStatus_WDH_Msk (0x1ul << USBH_HcInterruptStatus_WDH_Pos) /*!< USBH_T::HcInterruptStatus: WDH Mask */ + +#define USBH_HcInterruptStatus_SF_Pos (2) /*!< USBH_T::HcInterruptStatus: SF Position */ +#define USBH_HcInterruptStatus_SF_Msk (0x1ul << USBH_HcInterruptStatus_SF_Pos) /*!< USBH_T::HcInterruptStatus: SF Mask */ + +#define USBH_HcInterruptStatus_RD_Pos (3) /*!< USBH_T::HcInterruptStatus: RD Position */ +#define USBH_HcInterruptStatus_RD_Msk (0x1ul << USBH_HcInterruptStatus_RD_Pos) /*!< USBH_T::HcInterruptStatus: RD Mask */ + +#define USBH_HcInterruptStatus_FNO_Pos (5) /*!< USBH_T::HcInterruptStatus: FNO Position*/ +#define USBH_HcInterruptStatus_FNO_Msk (0x1ul << USBH_HcInterruptStatus_FNO_Pos) /*!< USBH_T::HcInterruptStatus: FNO Mask */ + +#define USBH_HcInterruptStatus_RHSC_Pos (6) /*!< USBH_T::HcInterruptStatus: RHSC Position*/ +#define USBH_HcInterruptStatus_RHSC_Msk (0x1ul << USBH_HcInterruptStatus_RHSC_Pos) /*!< USBH_T::HcInterruptStatus: RHSC Mask */ + +#define USBH_HcInterruptEnable_SO_Pos (0) /*!< USBH_T::HcInterruptEnable: SO Position */ +#define USBH_HcInterruptEnable_SO_Msk (0x1ul << USBH_HcInterruptEnable_SO_Pos) /*!< USBH_T::HcInterruptEnable: SO Mask */ + +#define USBH_HcInterruptEnable_WDH_Pos (1) /*!< USBH_T::HcInterruptEnable: WDH Position*/ +#define USBH_HcInterruptEnable_WDH_Msk (0x1ul << USBH_HcInterruptEnable_WDH_Pos) /*!< USBH_T::HcInterruptEnable: WDH Mask */ + +#define USBH_HcInterruptEnable_SF_Pos (2) /*!< USBH_T::HcInterruptEnable: SF Position */ +#define USBH_HcInterruptEnable_SF_Msk (0x1ul << USBH_HcInterruptEnable_SF_Pos) /*!< USBH_T::HcInterruptEnable: SF Mask */ + +#define USBH_HcInterruptEnable_RD_Pos (3) /*!< USBH_T::HcInterruptEnable: RD Position */ +#define USBH_HcInterruptEnable_RD_Msk (0x1ul << USBH_HcInterruptEnable_RD_Pos) /*!< USBH_T::HcInterruptEnable: RD Mask */ + +#define USBH_HcInterruptEnable_FNO_Pos (5) /*!< USBH_T::HcInterruptEnable: FNO Position*/ +#define USBH_HcInterruptEnable_FNO_Msk (0x1ul << USBH_HcInterruptEnable_FNO_Pos) /*!< USBH_T::HcInterruptEnable: FNO Mask */ + +#define USBH_HcInterruptEnable_RHSC_Pos (6) /*!< USBH_T::HcInterruptEnable: RHSC Position*/ +#define USBH_HcInterruptEnable_RHSC_Msk (0x1ul << USBH_HcInterruptEnable_RHSC_Pos) /*!< USBH_T::HcInterruptEnable: RHSC Mask */ + +#define USBH_HcInterruptEnable_MIE_Pos (31) /*!< USBH_T::HcInterruptEnable: MIE Position*/ +#define USBH_HcInterruptEnable_MIE_Msk (0x1ul << USBH_HcInterruptEnable_MIE_Pos) /*!< USBH_T::HcInterruptEnable: MIE Mask */ + +#define USBH_HcInterruptDisable_SO_Pos (0) /*!< USBH_T::HcInterruptDisable: SO Position*/ +#define USBH_HcInterruptDisable_SO_Msk (0x1ul << USBH_HcInterruptDisable_SO_Pos) /*!< USBH_T::HcInterruptDisable: SO Mask */ + +#define USBH_HcInterruptDisable_WDH_Pos (1) /*!< USBH_T::HcInterruptDisable: WDH Position*/ +#define USBH_HcInterruptDisable_WDH_Msk (0x1ul << USBH_HcInterruptDisable_WDH_Pos) /*!< USBH_T::HcInterruptDisable: WDH Mask */ + +#define USBH_HcInterruptDisable_SF_Pos (2) /*!< USBH_T::HcInterruptDisable: SF Position*/ +#define USBH_HcInterruptDisable_SF_Msk (0x1ul << USBH_HcInterruptDisable_SF_Pos) /*!< USBH_T::HcInterruptDisable: SF Mask */ + +#define USBH_HcInterruptDisable_RD_Pos (3) /*!< USBH_T::HcInterruptDisable: RD Position*/ +#define USBH_HcInterruptDisable_RD_Msk (0x1ul << USBH_HcInterruptDisable_RD_Pos) /*!< USBH_T::HcInterruptDisable: RD Mask */ + +#define USBH_HcInterruptDisable_FNO_Pos (5) /*!< USBH_T::HcInterruptDisable: FNO Position*/ +#define USBH_HcInterruptDisable_FNO_Msk (0x1ul << USBH_HcInterruptDisable_FNO_Pos) /*!< USBH_T::HcInterruptDisable: FNO Mask */ + +#define USBH_HcInterruptDisable_RHSC_Pos (6) /*!< USBH_T::HcInterruptDisable: RHSC Position*/ +#define USBH_HcInterruptDisable_RHSC_Msk (0x1ul << USBH_HcInterruptDisable_RHSC_Pos) /*!< USBH_T::HcInterruptDisable: RHSC Mask */ + +#define USBH_HcInterruptDisable_MIE_Pos (31) /*!< USBH_T::HcInterruptDisable: MIE Position*/ +#define USBH_HcInterruptDisable_MIE_Msk (0x1ul << USBH_HcInterruptDisable_MIE_Pos) /*!< USBH_T::HcInterruptDisable: MIE Mask */ + +#define USBH_HcHCCA_HCCA_Pos (8) /*!< USBH_T::HcHCCA: HCCA Position */ +#define USBH_HcHCCA_HCCA_Msk (0xfffffful << USBH_HcHCCA_HCCA_Pos) /*!< USBH_T::HcHCCA: HCCA Mask */ + +#define USBH_HcPeriodCurrentED_PCED_Pos (4) /*!< USBH_T::HcPeriodCurrentED: PCED Position*/ +#define USBH_HcPeriodCurrentED_PCED_Msk (0xffffffful << USBH_HcPeriodCurrentED_PCED_Pos) /*!< USBH_T::HcPeriodCurrentED: PCED Mask */ + +#define USBH_HcControlHeadED_CHED_Pos (4) /*!< USBH_T::HcControlHeadED: CHED Position */ +#define USBH_HcControlHeadED_CHED_Msk (0xffffffful << USBH_HcControlHeadED_CHED_Pos) /*!< USBH_T::HcControlHeadED: CHED Mask */ + +#define USBH_HcControlCurrentED_CCED_Pos (4) /*!< USBH_T::HcControlCurrentED: CCED Position*/ +#define USBH_HcControlCurrentED_CCED_Msk (0xffffffful << USBH_HcControlCurrentED_CCED_Pos) /*!< USBH_T::HcControlCurrentED: CCED Mask */ + +#define USBH_HcBulkHeadED_BHED_Pos (4) /*!< USBH_T::HcBulkHeadED: BHED Position */ +#define USBH_HcBulkHeadED_BHED_Msk (0xffffffful << USBH_HcBulkHeadED_BHED_Pos) /*!< USBH_T::HcBulkHeadED: BHED Mask */ + +#define USBH_HcBulkCurrentED_BCED_Pos (4) /*!< USBH_T::HcBulkCurrentED: BCED Position */ +#define USBH_HcBulkCurrentED_BCED_Msk (0xffffffful << USBH_HcBulkCurrentED_BCED_Pos) /*!< USBH_T::HcBulkCurrentED: BCED Mask */ + +#define USBH_HcDoneHead_DH_Pos (4) /*!< USBH_T::HcDoneHead: DH Position */ +#define USBH_HcDoneHead_DH_Msk (0xffffffful << USBH_HcDoneHead_DH_Pos) /*!< USBH_T::HcDoneHead: DH Mask */ + +#define USBH_HcFmInterval_FI_Pos (0) /*!< USBH_T::HcFmInterval: FI Position */ +#define USBH_HcFmInterval_FI_Msk (0x3ffful << USBH_HcFmInterval_FI_Pos) /*!< USBH_T::HcFmInterval: FI Mask */ + +#define USBH_HcFmInterval_FSMPS_Pos (16) /*!< USBH_T::HcFmInterval: FSMPS Position */ +#define USBH_HcFmInterval_FSMPS_Msk (0x7ffful << USBH_HcFmInterval_FSMPS_Pos) /*!< USBH_T::HcFmInterval: FSMPS Mask */ + +#define USBH_HcFmInterval_FIT_Pos (31) /*!< USBH_T::HcFmInterval: FIT Position */ +#define USBH_HcFmInterval_FIT_Msk (0x1ul << USBH_HcFmInterval_FIT_Pos) /*!< USBH_T::HcFmInterval: FIT Mask */ + +#define USBH_HcFmRemaining_FR_Pos (0) /*!< USBH_T::HcFmRemaining: FR Position */ +#define USBH_HcFmRemaining_FR_Msk (0x3ffful << USBH_HcFmRemaining_FR_Pos) /*!< USBH_T::HcFmRemaining: FR Mask */ + +#define USBH_HcFmRemaining_FRT_Pos (31) /*!< USBH_T::HcFmRemaining: FRT Position */ +#define USBH_HcFmRemaining_FRT_Msk (0x1ul << USBH_HcFmRemaining_FRT_Pos) /*!< USBH_T::HcFmRemaining: FRT Mask */ + +#define USBH_HcFmNumber_FN_Pos (0) /*!< USBH_T::HcFmNumber: FN Position */ +#define USBH_HcFmNumber_FN_Msk (0xfffful << USBH_HcFmNumber_FN_Pos) /*!< USBH_T::HcFmNumber: FN Mask */ + +#define USBH_HcPeriodicStart_PS_Pos (0) /*!< USBH_T::HcPeriodicStart: PS Position */ +#define USBH_HcPeriodicStart_PS_Msk (0x3ffful << USBH_HcPeriodicStart_PS_Pos) /*!< USBH_T::HcPeriodicStart: PS Mask */ + +#define USBH_HcLSThreshold_LST_Pos (0) /*!< USBH_T::HcLSThreshold: LST Position */ +#define USBH_HcLSThreshold_LST_Msk (0xffful << USBH_HcLSThreshold_LST_Pos) /*!< USBH_T::HcLSThreshold: LST Mask */ + +#define USBH_HcRhDescriptorA_NDP_Pos (0) /*!< USBH_T::HcRhDescriptorA: NDP Position */ +#define USBH_HcRhDescriptorA_NDP_Msk (0xfful << USBH_HcRhDescriptorA_NDP_Pos) /*!< USBH_T::HcRhDescriptorA: NDP Mask */ + +#define USBH_HcRhDescriptorA_PSM_Pos (8) /*!< USBH_T::HcRhDescriptorA: PSM Position */ +#define USBH_HcRhDescriptorA_PSM_Msk (0x1ul << USBH_HcRhDescriptorA_PSM_Pos) /*!< USBH_T::HcRhDescriptorA: PSM Mask */ + +#define USBH_HcRhDescriptorA_OCPM_Pos (11) /*!< USBH_T::HcRhDescriptorA: OCPM Position */ +#define USBH_HcRhDescriptorA_OCPM_Msk (0x1ul << USBH_HcRhDescriptorA_OCPM_Pos) /*!< USBH_T::HcRhDescriptorA: OCPM Mask */ + +#define USBH_HcRhDescriptorA_NOCP_Pos (12) /*!< USBH_T::HcRhDescriptorA: NOCP Position */ +#define USBH_HcRhDescriptorA_NOCP_Msk (0x1ul << USBH_HcRhDescriptorA_NOCP_Pos) /*!< USBH_T::HcRhDescriptorA: NOCP Mask */ + +#define USBH_HcRhDescriptorB_PPCM_Pos (16) /*!< USBH_T::HcRhDescriptorB: PPCM Position */ +#define USBH_HcRhDescriptorB_PPCM_Msk (0xfffful << USBH_HcRhDescriptorB_PPCM_Pos) /*!< USBH_T::HcRhDescriptorB: PPCM Mask */ + +#define USBH_HcRhStatus_LPS_Pos (0) /*!< USBH_T::HcRhStatus: LPS Position */ +#define USBH_HcRhStatus_LPS_Msk (0x1ul << USBH_HcRhStatus_LPS_Pos) /*!< USBH_T::HcRhStatus: LPS Mask */ + +#define USBH_HcRhStatus_OCI_Pos (1) /*!< USBH_T::HcRhStatus: OCI Position */ +#define USBH_HcRhStatus_OCI_Msk (0x1ul << USBH_HcRhStatus_OCI_Pos) /*!< USBH_T::HcRhStatus: OCI Mask */ + +#define USBH_HcRhStatus_DRWE_Pos (15) /*!< USBH_T::HcRhStatus: DRWE Position */ +#define USBH_HcRhStatus_DRWE_Msk (0x1ul << USBH_HcRhStatus_DRWE_Pos) /*!< USBH_T::HcRhStatus: DRWE Mask */ + +#define USBH_HcRhStatus_LPSC_Pos (16) /*!< USBH_T::HcRhStatus: LPSC Position */ +#define USBH_HcRhStatus_LPSC_Msk (0x1ul << USBH_HcRhStatus_LPSC_Pos) /*!< USBH_T::HcRhStatus: LPSC Mask */ + +#define USBH_HcRhStatus_OCIC_Pos (17) /*!< USBH_T::HcRhStatus: OCIC Position */ +#define USBH_HcRhStatus_OCIC_Msk (0x1ul << USBH_HcRhStatus_OCIC_Pos) /*!< USBH_T::HcRhStatus: OCIC Mask */ + +#define USBH_HcRhStatus_CRWE_Pos (31) /*!< USBH_T::HcRhStatus: CRWE Position */ +#define USBH_HcRhStatus_CRWE_Msk (0x1ul << USBH_HcRhStatus_CRWE_Pos) /*!< USBH_T::HcRhStatus: CRWE Mask */ + +#define USBH_HcRhPortStatus_CCS_Pos (0) /*!< USBH_T::HcRhPortStatus1: CCS Position */ +#define USBH_HcRhPortStatus_CCS_Msk (0x1ul << USBH_HcRhPortStatus_CCS_Pos) /*!< USBH_T::HcRhPortStatus1: CCS Mask */ + +#define USBH_HcRhPortStatus_PES_Pos (1) /*!< USBH_T::HcRhPortStatus1: PES Position */ +#define USBH_HcRhPortStatus_PES_Msk (0x1ul << USBH_HcRhPortStatus_PES_Pos) /*!< USBH_T::HcRhPortStatus1: PES Mask */ + +#define USBH_HcRhPortStatus_PSS_Pos (2) /*!< USBH_T::HcRhPortStatus1: PSS Position */ +#define USBH_HcRhPortStatus_PSS_Msk (0x1ul << USBH_HcRhPortStatus_PSS_Pos) /*!< USBH_T::HcRhPortStatus1: PSS Mask */ + +#define USBH_HcRhPortStatus_POCI_Pos (3) /*!< USBH_T::HcRhPortStatus1: POCI Position */ +#define USBH_HcRhPortStatus_POCI_Msk (0x1ul << USBH_HcRhPortStatus_POCI_Pos) /*!< USBH_T::HcRhPortStatus1: POCI Mask */ + +#define USBH_HcRhPortStatus_PRS_Pos (4) /*!< USBH_T::HcRhPortStatus1: PRS Position */ +#define USBH_HcRhPortStatus_PRS_Msk (0x1ul << USBH_HcRhPortStatus_PRS_Pos) /*!< USBH_T::HcRhPortStatus1: PRS Mask */ + +#define USBH_HcRhPortStatus_PPS_Pos (8) /*!< USBH_T::HcRhPortStatus1: PPS Position */ +#define USBH_HcRhPortStatus_PPS_Msk (0x1ul << USBH_HcRhPortStatus_PPS_Pos) /*!< USBH_T::HcRhPortStatus1: PPS Mask */ + +#define USBH_HcRhPortStatus_LSDA_Pos (9) /*!< USBH_T::HcRhPortStatus1: LSDA Position */ +#define USBH_HcRhPortStatus_LSDA_Msk (0x1ul << USBH_HcRhPortStatus_LSDA_Pos) /*!< USBH_T::HcRhPortStatus1: LSDA Mask */ + +#define USBH_HcRhPortStatus_CSC_Pos (16) /*!< USBH_T::HcRhPortStatus1: CSC Position */ +#define USBH_HcRhPortStatus_CSC_Msk (0x1ul << USBH_HcRhPortStatus_CSC_Pos) /*!< USBH_T::HcRhPortStatus1: CSC Mask */ + +#define USBH_HcRhPortStatus_PESC_Pos (17) /*!< USBH_T::HcRhPortStatus1: PESC Position */ +#define USBH_HcRhPortStatus_PESC_Msk (0x1ul << USBH_HcRhPortStatus_PESC_Pos) /*!< USBH_T::HcRhPortStatus1: PESC Mask */ + +#define USBH_HcRhPortStatus_PSSC_Pos (18) /*!< USBH_T::HcRhPortStatus1: PSSC Position */ +#define USBH_HcRhPortStatus_PSSC_Msk (0x1ul << USBH_HcRhPortStatus_PSSC_Pos) /*!< USBH_T::HcRhPortStatus1: PSSC Mask */ + +#define USBH_HcRhPortStatus_OCIC_Pos (19) /*!< USBH_T::HcRhPortStatus1: OCIC Position */ +#define USBH_HcRhPortStatus_OCIC_Msk (0x1ul << USBH_HcRhPortStatus_OCIC_Pos) /*!< USBH_T::HcRhPortStatus1: OCIC Mask */ + +#define USBH_HcRhPortStatus_PRSC_Pos (20) /*!< USBH_T::HcRhPortStatus1: PRSC Position */ +#define USBH_HcRhPortStatus_PRSC_Msk (0x1ul << USBH_HcRhPortStatus_PRSC_Pos) /*!< USBH_T::HcRhPortStatus1: PRSC Mask */ + +#define USBH_HcPhyControl_STBYEN_Pos (27) /*!< USBH_T::HcPhyControl: STBYEN Position */ +#define USBH_HcPhyControl_STBYEN_Msk (0x1ul << USBH_HcPhyControl_STBYEN_Pos) /*!< USBH_T::HcPhyControl: STBYEN Mask */ + +#define USBH_HcMiscControl_ABORT_Pos (1) /*!< USBH_T::HcMiscControl: ABORT Position */ +#define USBH_HcMiscControl_ABORT_Msk (0x1ul << USBH_HcMiscControl_ABORT_Pos) /*!< USBH_T::HcMiscControl: ABORT Mask */ + +#define USBH_HcMiscControl_OCAL_Pos (3) /*!< USBH_T::HcMiscControl: OCAL Position */ +#define USBH_HcMiscControl_OCAL_Msk (0x1ul << USBH_HcMiscControl_OCAL_Pos) /*!< USBH_T::HcMiscControl: OCAL Mask */ + +#define USBH_HcMiscControl_DPRT1_Pos (16) /*!< USBH_T::HcMiscControl: DPRT1 Position */ +#define USBH_HcMiscControl_DPRT1_Msk (0x1ul << USBH_HcMiscControl_DPRT1_Pos) /*!< USBH_T::HcMiscControl: DPRT1 Mask */ + +/**@}*/ /* USBH_CONST */ +/**@}*/ /* end of USBH register group */ + + +/*---------------------- HSUSBH HSUSB Host Controller -------------------------*/ +/** + @addtogroup HSUSBH High Speed USB Host Controller (HSUSBH) + Memory Mapped Structure for HSUSBH Controller +@{ */ + +typedef struct +{ + + + /** + * @var HSUSBH_T::EHCVNR + * Offset: 0x00 EHCI Version Number Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[7:0] |CRLEN |Capability Registers Length + * | | |This register is used as an offset to add to register base to find the beginning of the Operational Register Space. + * |[31:16] |VERSION |Host Controller Interface Version Number + * | | |This is a two-byte register containing a BCD encoding of the EHCI revision number supported by this host controller + * | | |The most significant byte of this register represents a major revision and the least significant byte is the minor revision. + * @var HSUSBH_T::EHCSPR + * Offset: 0x04 EHCI Structural Parameters Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[3:0] |N_PORTS |Number of Physical Downstream Ports + * | | |This field specifies the number of physical downstream ports implemented on this host controller + * | | |The value of this field determines how many port registers are addressable in the Operational Register Space (see Table 2-8) + * | | |Valid values are in the range of 1H to FH. + * | | |A zero in this field is undefined. + * |[4] |PPC |Port Power Control + * | | |This field indicates whether the host controller implementation includes port power control + * | | |A one in this bit indicates the ports have port power switches + * | | |A zero in this bit indicates the port do not have port power stitches + * | | |The value of this field affects the functionality of the Port Power field in each port status and control register. + * |[11:8] |N_PCC |Number of Ports Per Companion Controller + * | | |This field indicates the number of ports supported per companion host controller + * | | |It is used to indicate the port routing configuration to system software. + * | | |For example, if N_PORTS has a value of 6 and N_CC has a value of 2 then N_PCC could have a value of 3 + * | | |The convention is that the first N_PCC ports are assumed to be routed to companion controller 1, the next N_PCC ports to companion controller 2, etc + * | | |In the previous example, the N_PCC could have been 4, where the first 4 are routed to companion controller 1 and the last two are routed to companion controller 2. + * | | |The number in this field must be consistent with N_PORTS and N_CC. + * |[15:12] |N_CC |Number of Companion Controller + * | | |This field indicates the number of companion controllers associated with this USB 2.0 host controller. + * | | |A zero in this field indicates there are no companion host controllers + * | | |Port-ownership hand-off is not supported + * | | |Only high-speed devices are supported on the host controller root ports. + * | | |A value larger than zero in this field indicates there are companion USB 1.1 host controller(s) + * | | |Port-ownership hand-offs are supported + * | | |High, Full- and Low-speed devices are supported on the host controller root ports. + * @var HSUSBH_T::EHCCPR + * Offset: 0x08 EHCI Capability Parameters Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |AC64 |64-bit Addressing Capability + * | | |0 = Data structure using 32-bit address memory pointers. + * |[1] |PFLF |Programmable Frame List Flag + * | | |0 = System software must use a frame list length of 1024 elements with this EHCI host controller. + * |[2] |ASPC |Asynchronous Schedule Park Capability + * | | |0 = This EHCI host controller doesn't support park feature of high-speed queue heads in the Asynchronous Schedule. + * |[7:4] |IST |Isochronous Scheduling Threshold + * | | |This field indicates, relative to the current position of the executing host controller, where software can reliably update the isochronous schedule. + * | | |When bit [7] is zero, the value of the least significant 3 bits indicates the number of micro-frames a host controller can hold a set of isochronous data structures (one or more) before flushing the state. + * |[15:8] |EECP |EHCI Extended Capabilities Pointer (EECP) + * | | |0 = No extended capabilities are implemented. + * @var HSUSBH_T::UCMDR + * Offset: 0x20 USB Command Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |RUN |Run/Stop (R/W) + * | | |When set to a 1, the Host Controller proceeds with execution of the schedule + * | | |The Host Controller continues execution as long as this bit is set to a 1 + * | | |When this bit is set to 0, the Host Controller completes the current and any actively pipelined transactions on the USB and then halts + * | | |The Host Controller must halt within 16 micro-frames after software clears the Run bit + * | | |The HC Halted bit in the status register indicates when the Host Controller has finished its pending pipelined transactions and has entered the stopped state + * | | |Software must not write a one to this field unless the host controller is in the Halted state (i.e. + * | | |HCHalted in the USBSTS register is a one) + * | | |Doing so will yield undefined results. + * | | |0 = Stop. + * | | |1 = Run. + * |[1] |HCRST |Host Controller Reset (HCRESET) (R/W) + * | | |This control bit is used by software to reset the host controller + * | | |The effects of this on Root Hub registers are similar to a Chip Hardware Reset. + * | | |When software writes a one to this bit, the Host Controller resets its internal pipelines, timers, counters, state machines, etc + * | | |to their initial value + * | | |Any transaction currently in progress on USB is immediately terminated + * | | |A USB reset is not driven on downstream ports. + * | | |All operational registers, including port registers and port state machines are set to their initial values + * | | |Port ownership reverts to the companion host controller(s), with the side effects + * | | |Software must reinitialize the host controller in order to return the host controller to an operational state. + * | | |This bit is set to zero by the Host Controller when the reset process is complete + * | | |Software cannot terminate the reset process early by writing a zero to this register. + * | | |Software should not set this bit to a one when the HCHalted bit in the USBSTS register is a zero + * | | |Attempting to reset an actively running host controller will result in undefined behavior. + * |[3:2] |FLSZ |Frame List Size (R/W or RO) + * | | |This field is R/W only if Programmable Frame List Flag in the HCCPARAMS registers is set to a one + * | | |This field specifies the size of the frame list + * | | |The size the frame list controls which bits in the Frame Index Register should be used for the Frame List Current index + * | | |Values mean: + * | | |00 = 1024 elements (4096 bytes) Default value. + * | | |01 = 512 elements (2048 bytes). + * | | |10 = 256 elements (1024 bytes) u2013 for resource-constrained environment. + * | | |11 = Reserved. + * |[4] |PSEN |Periodic Schedule Enable (R/W) + * | | |This bit controls whether the host controller skips processing the Periodic Schedule. Values mean: + * | | |0 = Do not process the Periodic Schedule. + * | | |1 = Use the PERIODICLISTBASE register to access the Periodic Schedule. + * |[5] |ASEN |Asynchronous Schedule Enable (R/W) + * | | |This bit controls whether the host controller skips processing the Asynchronous Schedule. Values mean: + * | | |0 = Do not process the Asynchronous Schedule. + * | | |1 = Use the ASYNCLISTADDR register to access the Asynchronous Schedule. + * |[6] |IAAD |Interrupt on Asynchronous Advance Doorbell (R/W) + * | | |This bit is used as a doorbell by software to tell the host controller to issue an interrupt the next time it advances asynchronous schedule + * | | |Software must write a 1 to this bit to ring the doorbell. + * | | |When the host controller has evicted all appropriate cached schedule state, it sets the Interrupt on Asynchronous Advance status bit in the USBSTS register + * | | |If the Interrupt on Asynchronous Advance Enable bit in the USBINTR register is a one then the host controller will assert an interrupt at the next interrupt threshold. + * | | |The host controller sets this bit to a zero after it has set the Interrupt on Asynchronous Advance status bit in the USBSTS register to a one. + * | | |Software should not write a one to this bit when the asynchronous schedule is disabled + * | | |Doing so will yield undefined results. + * |[23:16] |ITC |Interrupt Threshold Control (R/W) + * | | |This field is used by system software to select the maximum rate at which the host controller will issue interrupts + * | | |The only valid values are defined below + * | | |If software writes an invalid value to this register, the results are undefined + * | | |Value Maximum Interrupt Interval + * | | |0x00 = Reserved. + * | | |0x01 = 1 micro-frame. + * | | |0x02 = 2 micro-frames. + * | | |0x04 = 4 micro-frames. + * | | |0x08 = 8 micro-frames (default, equates to 1 ms). + * | | |0x10 = 16 micro-frames (2 ms). + * | | |0x20 = 32 micro-frames (4 ms). + * | | |0x40 = 64 micro-frames (8 ms). + * | | |Any other value in this register yields undefined results. + * | | |Software modifications to this bit while HCHalted bit is equal to zero results in undefined behavior. + * @var HSUSBH_T::USTSR + * Offset: 0x24 USB Status Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |USBINT |USB Interrupt (USBINT) (R/WC) + * | | |The Host Controller sets this bit to 1 on the completion of a USB transaction, which results in the retirement of a Transfer Descriptor that had its IOC bit set. + * | | |The Host Controller also sets this bit to 1 when a short packet is detected (actual number of bytes received was less than the expected number of bytes). + * |[1] |UERRINT |USB Error Interrupt (USBERRINT) (R/WC) + * | | |The Host Controller sets this bit to 1 when completion of a USB transaction results in an error condition (e.g., error counter underflow) + * | | |If the TD on which the error interrupt occurred also had its IOC bit set, both this bit and USBINT bit are set. + * |[2] |PCD |Port Change Detect (R/WC) + * | | |The Host Controller sets this bit to a one when any port for which the Port Owner bit is set to zero has a change bit transition from a zero to a one or a Force Port Resume bit transition from a zero to a one as a result of a J-K transition detected on a suspended port + * | | |This bit will also be set as a result of the Connect Status Change being set to a one after system software has relinquished ownership of a connected port by writing a one to a port's Port Owner bit. + * | | |This bit is allowed to be maintained in the Auxiliary power well + * | | |Alternatively, it is also acceptable that on a D3 to D0 transition of the EHCI HC device, this bit is loaded with the OR of all of the PORTSC change bits (including: Force port resume, over-current change, enable/disable change and connect status change). + * |[3] |FLR |Frame List Rollover (R/WC) + * | | |The Host Controller sets this bit to a one when the Frame List Index rolls over from its maximum value to zero + * | | |The exact value at which the rollover occurs depends on the frame list size + * | | |For example, if the frame list size (as programmed in the Frame List Size field of the USBCMD register) is 1024, the Frame Index Register rolls over every time FRINDEX[13] toggles + * | | |Similarly, if the size is 512, the Host Controller sets this bit to a one every time FRINDEX[12] toggles. + * |[4] |HSERR |Host System Error (R/WC) + * | | |The Host Controller sets this bit to 1 when a serious error occurs during a host system access involving the Host Controller module. + * |[5] |IAA |Interrupt on Asynchronous Advance (R/WC) + * | | |System software can force the host controller to issue an interrupt the next time the host controller advances the asynchronous schedule by writing a one to the Interrupt on Asynchronous Advance Doorbell bit in the USBCMD register + * | | |This status bit indicates the assertion of that interrupt source. + * |[12] |HCHalted |HCHalted (RO) + * | | |This bit is a zero whenever the Run/Stop bit is a one + * | | |The Host Controller sets this bit to one after it has stopped executing as a result of the Run/Stop bit being set to 0, either by software or by the Host Controller hardware (e.g. + * | | |internal error). + * |[13] |RECLA |Reclamation (RO) + * | | |This is a read-only status bit, which is used to detect an empty asynchronous schedule. + * |[14] |PSS |Periodic Schedule Status (RO) + * | | |The bit reports the current real status of the Periodic Schedule + * | | |If this bit is a zero then the status of the Periodic Schedule is disabled + * | | |If this bit is a one then the status of the Periodic Schedule is enabled + * | | |The Host Controller is not required to immediately disable or enable the Periodic Schedule when software transitions the Periodic Schedule Enable bit in the USBCMD register + * | | |When this bit and the Periodic Schedule Enable bit are the same value, the Periodic Schedule is either enabled (1) or disabled (0). + * |[15] |ASS |Asynchronous Schedule Status (RO) + * | | |The bit reports the current real status of the Asynchronous Schedule + * | | |If this bit is a zero then the status of them Asynchronous Schedule is disabled + * | | |If this bit is a one then the status of the Asynchronous Schedule is enabled + * | | |The Host Controller is not required to immediately disable or enable the Asynchronous Schedule when software transitions the Asynchronous Schedule Enable bit in the USBCMD register + * | | |When this bit and the Asynchronous Schedule Enable bit are the same value, the Asynchronous Schedule is either enabled (1) or disabled (0). + * @var HSUSBH_T::UIENR + * Offset: 0x28 USB Interrupt Enable Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |USBIEN |USB Interrupt Enable or Disable Bit + * | | |When this bit is a one, and the USBINT bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold + * | | |The interrupt is acknowledged by software clearing the USBINT bit. + * | | |0 = USB interrupt Disabled. + * | | |1 = USB interrupt Enabled. + * |[1] |UERRIEN |USB Error Interrupt Enable or Disable Bit + * | | |When this bit is a one, and the USBERRINT bit in the USBSTS register is a one, the host t controller will issue an interrupt at the next interrupt threshold + * | | |The interrupt is acknowledged by software clearing the USBERRINT bit. + * | | |0 = USB Error interrupt Disabled. + * | | |1 = USB Error interrupt Enabled. + * |[2] |PCIEN |Port Change Interrupt Enable or Disable Bit + * | | |When this bit is a one, and the Port Change Detect bit in the USBSTS register is a one, the host controller will issue an interrupt + * | | |The interrupt is acknowledged by software clearing the Port Change Detect bit. + * | | |0 = Port Change interrupt Disabled. + * | | |1 = Port Change interrupt Enabled. + * |[3] |FLREN |Frame List Rollover Enable or Disable Bit + * | | |When this bit is a one, and the Frame List Rollover bit in the USBSTS register is a one, the host controller will issue an interrupt + * | | |The interrupt is acknowledged by software clearing the Frame List Rollover bit. + * | | |0 = Frame List Rollover interrupt Disabled. + * | | |1 = Frame List Rollover interrupt Enabled. + * |[4] |HSERREN |Host System Error Enable or Disable Bit + * | | |When this bit is a one, and the Host System Error Status bit in the USBSTS register is a one, the host controller will issue an interrupt + * | | |The interrupt is acknowledged by software clearing the Host System Error bit. + * | | |0 = Host System Error interrupt Disabled. + * | | |1 = Host System Error interrupt Enabled. + * |[5] |IAAEN |Interrupt on Asynchronous Advance Enable or Disable Bit + * | | |When this bit is a one, and the Interrupt on Asynchronous Advance bit in the USBSTS register is a one, the host controller will issue an interrupt at the next interrupt threshold + * | | |The interrupt is acknowledged by software clearing the Interrupt on Asynchronous Advance bit. + * | | |0 = Interrupt on Asynchronous Advance Disabled. + * | | |1 = Interrupt on Asynchronous Advance Enabled. + * @var HSUSBH_T::UFINDR + * Offset: 0x2C USB Frame Index Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[13:0] |FI |Frame Index + * | | |The value in this register increment at the end of each time frame (e.g. + * | | |micro-frame) + * | | |Bits [N:3] are used for the Frame List current index + * | | |This means that each location of the frame list is accessed 8 times (frames or micro-frames) before moving to the next index + * | | |The following illustrates values of N based on the value of the Frame List Size field in the USBCMD register. + * | | |FLSZ (UCMDR[3:2] Number Elements N + * | | |0x0 1024 12 + * | | |0x1 512 11 + * | | |0x2 256 10 + * | | |0x3 Reserved + * @var HSUSBH_T::UPFLBAR + * Offset: 0x34 USB Periodic Frame List Base Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:12] |BADDR |Base Address + * | | |These bits correspond to memory address signals [31:12], respectively. + * @var HSUSBH_T::UCALAR + * Offset: 0x38 USB Current Asynchronous List Address Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[31:5] |LPL |Link Pointer Low (LPL) + * | | |These bits correspond to memory address signals [31:5], respectively + * | | |This field may only reference a Queue Head (QH). + * @var HSUSBH_T::UASSTR + * Offset: 0x3C USB Asynchronous Schedule Sleep Timer Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[11:0] |ASSTMR |Asynchronous Schedule Sleep Timer + * | | |This field defines the AsyncSchedSleepTime of EHCI spec. + * | | |The asynchronous schedule sleep timer is used to control how often the host controller fetches asynchronous schedule list from system memory while the asynchronous schedule is empty. + * | | |The default value of this timer is 12'hBD6 + * | | |Because this timer is implemented in UTMI clock (30MHz) domain, the default sleeping time will be about 100us. + * @var HSUSBH_T::UCFGR + * Offset: 0x60 USB Configure Flag Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |CF |Configure Flag (CF) + * | | |Host software sets this bit as the last action in its process of configuring the Host Controller + * | | |This bit controls the default port-routing control logic + * | | |Bit values and side-effects are listed below. + * | | |0 = Port routing control logic default-routes each port to an implementation dependent classic host controller. + * | | |1 = Port routing control logic default-routes all ports to this host controller. + * @var HSUSBH_T::UPSCR[2] + * Offset: 0x64~0x68 USB Port 0~1 Status and Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[0] |CCS |Current Connect Status (RO) + * | | |This value reflects the current state of the port, and may not correspond directly to the event that caused the Connect Status Change bit (Bit 1) to be set. + * | | |This field is zero if Port Power is zero. + * | | |0 = No device is present. + * | | |1 = Device is present on port. + * |[1] |CSC |Connect Status Change (R/W) + * | | |Indicates a change has occurred in the port's Current Connect Status + * | | |The host controller sets this bit for all changes to the port device connect status, even if system software has not cleared an existing connect status change + * | | |For example, the insertion status changes twice before system software has cleared the changed condition, hub hardware will be "setting" an already-set bit (i.e., the bit will remain set).Software sets this bit to 0 by writing a 1 to it. + * | | |This field is zero if Port Power is zero. + * | | |0 = No change. + * | | |1 = Change in Current Connect Status. + * |[2] |PE |Port Enabled/Disabled (R/W) + * | | |Ports can only be enabled by the host controller as a part of the reset and enable + * | | |Software cannot enable a port by writing a one to this field + * | | |The host controller will only set this bit to a one when the reset sequence determines that the attached device is a high-speed device. + * | | |Ports can be disabled by either a fault condition (disconnect event or other fault condition) or by host software + * | | |Note that the bit status does not change until the port state actually changes + * | | |There may be a delay in disabling or enabling a port due to other host controller and bus events. + * | | |When the port is disabled (0b) downstream propagation of data is blocked on this port, except for reset. + * | | |This field is zero if Port Power is zero. + * | | |0 = Port Disabled. + * | | |1 = Port Enabled. + * |[3] |PEC |Port Enable/Disable Change (R/WC) + * | | |For the root hub, this bit gets set to a one only when a port is disabled due to the appropriate conditions existing at the EOF2 point (See Chapter 11 of the USB Specification for the definition of a Port Error) + * | | |Software clears this bit by writing a 1 to it. + * | | |This field is zero if Port Power is zero. + * | | |0 = No change. + * | | |1 = Port enabled/disabled status has changed. + * |[4] |OCA |Over-current Active (RO) + * | | |This bit will automatically transition from a one to a zero when the over current condition is removed. + * | | |0 = This port does not have an over-current condition. + * | | |1 = This port currently has an over-current condition. + * |[5] |OCC |Over-current Change (R/WC) + * | | |1 = This bit gets set to a one when there is a change to Over-current Active + * | | |Software clears this bit by writing a one to this bit position. + * |[6] |FPR |Force Port Resume (R/W) + * | | |This functionality defined for manipulating this bit depends on the value of the Suspend bit + * | | |For example, if the port is not suspended (Suspend and Enabled bits are a one) and software transitions this bit to a one, then the effects on the bus are undefined. + * | | |Software sets this bit to a 1 to drive resume signaling + * | | |The Host Controller sets this bit to a 1 if a J-to-K transition is detected while the port is in the Suspend state + * | | |When this bit transitions to a one because a J-to-K transition is detected, the Port Change Detect bit in the USBSTS register is also set to a one + * | | |If software sets this bit to a one, the host controller must not set the Port Change Detect bit. + * | | |Note that when the EHCI controller owns the port, the resume sequence follows the defined sequence documented in the USB Specification Revision 2.0 + * | | |The resume signaling (Full-speed 'K') is driven on the port as long as this bit remains a one + * | | |Software must appropriately time the Resume and set this bit to a zero when the appropriate amount of time has elapsed + * | | |Writing a zero (from one) causes the port to return to high-speed mode (forcing the bus below the port into a high-speed idle) + * | | |This bit will remain a one until the port has switched to the high-speed idle + * | | |The host controller must complete this transition within 2 milliseconds of software setting this bit to a zero. + * | | |This field is zero if Port Power is zero. + * | | |0 = No resume (K-state) detected/driven on port. + * | | |1 = Resume detected/driven on port. + * |[7] |SUSPEND |Suspend (R/W) + * | | |Port Enabled Bit and Suspend bit of this register define the port states as follows: + * | | |Port enable is 0 and suspend is 0 = Disable. + * | | |Port enable is 0 and suspend is 1 = Disable. + * | | |Port enable is 1 and suspend is 0 = Enable. + * | | |Port enable is 1 and suspend is 1 = Suspend. + * | | |When in suspend state, downstream propagation of data is blocked on this port, except for port reset + * | | |The blocking occurs at the end of the current transaction, if a transaction was in progress when this bit was written to 1 + * | | |In the suspend state, the port is sensitive to resume detection + * | | |Note that the bit status does not change until the port is suspended and that there may be a delay in suspending a port if there is a transaction currently in progress on the USB. + * | | |A write of zero to this bit is ignored by the host controller + * | | |The host controller will unconditionally set this bit to a zero when: + * | | |Software sets the Force Port Resume bit to a zero (from a one). + * | | |Software sets the Port Reset bit to a one (from a zero). + * | | |If host software sets this bit to a one when the port is not enabled (i.e. + * | | |Port enabled bit is a zero) the results are undefined. + * | | |This field is zero if Port Power is zero. + * | | |0 = Port not in suspend state. + * | | |1 = Port in suspend state. + * |[8] |PRST |Port Reset (R/W) + * | | |When software writes a one to this bit (from a zero), the bus reset sequence as defined in the USB Specification Revision 2.0 is started + * | | |Software writes a zero to this bit to terminate the bus reset sequence + * | | |Software must keep this bit at a one long enough to ensure the reset sequence, as specified in the USB Specification Revision 2.0, completes + * | | |Note: when software writes this bit to a one, it must also write a zero to the Port Enable bit. + * | | |Note that when software writes a zero to this bit there may be a delay before the bit status changes to a zero + * | | |The bit status will not read as a zero until after the reset has completed + * | | |If the port is in high-speed mode after reset is complete, the host controller will automatically enable this port (e.g. + * | | |set the Port Enable bit to a one) + * | | |A host controller must terminate the reset and stabilize the state of the port within 2 milliseconds of software transitioning this bit from a one to a zero + * | | |For example: if the port detects that the attached device is high-speed during reset, then the host controller must have the port in the enabled state within 2ms of software writing this bit to a zero. + * | | |The HCHalted bit in the USBSTS register should be a zero before software attempts to use this bit + * | | |The host controller may hold Port Reset asserted to a one when the HCHalted bit is a one. + * | | |This field is zero if Port Power is zero. + * | | |0 = Port is not in Reset. + * | | |1 = Port is in Reset. + * |[11:10] |LSTS |Line Status (RO) + * | | |These bits reflect the current logical levels of the D+ (bit 11) and D- (bit 10) signal lines + * | | |These bits are used for detection of low-speed USB devices prior to the port reset and enable sequence + * | | |This field is valid only when the port enable bit is zero and the current connect status bit is set to a one. + * | | |The encoding of the bits are: + * | | |Bits[11:10] USB State Interpretation + * | | |00 = SE0 Not Low-speed device, perform EHCI reset. + * | | |01 = K-state Low-speed device, release ownership of port. + * | | |10 = J-state Not Low-speed device, perform EHCI reset. + * | | |11 = Undefined Not Low-speed device, perform EHCI reset. + * | | |This value of this field is undefined if Port Power is zero. + * |[12] |PP |Port Power (PP) + * | | |Host controller has port power control switches + * | | |This bit represents the Current setting of the switch (0 = off, 1 = on) + * | | |When power is not available on a port (i.e. + * | | |PP equals a 0), the port is nonfunctional and will not report attaches, detaches, etc. + * | | |When an over-current condition is detected on a powered port and PPC is a one, the PP bit in each affected port may be transitioned by the host controller from a 1 to 0 (removing power from the port). + * |[13] |PO |Port Owner (R/W) + * | | |This bit unconditionally goes to a 0b when the Configured bit in the CONFIGFLAG register makes a 0 to 1 transition + * | | |This bit unconditionally goes to 1 whenever the Configured bit is zero. + * | | |System software uses this field to release ownership of the port to a selected host controller (in the event that the attached device is not a high-speed device) + * | | |Software writes a one to this bit when the attached device is not a high-speed device + * | | |A one in this bit means that a companion host controller owns and controls the port. + * |[19:16] |PTC |Port Test Control (R/W) + * | | |When this field is zero, the port is NOT operating in a test mode + * | | |A non-zero value indicates that it is operating in test mode and the specific test mode is indicated by the specific value + * | | |The encoding of the test mode bits are (0x6 ~ 0xF are reserved): + * | | |Bits Test Mode + * | | |0x0 = Test mode not enabled. + * | | |0x1 = Test J_STATE. + * | | |0x2 = Test K_STATE. + * | | |0x3 = Test SE0_NAK. + * | | |0x4 = Test Packet. + * | | |0x5 = Test FORCE_ENABLE. + * @var HSUSBH_T::USBPCR0 + * Offset: 0xC4 USB PHY 0 Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[8] |SUSPEND |Suspend Assertion + * | | |This bit controls the suspend mode of USB PHY 0. + * | | |While PHY was suspended, all circuits of PHY were powered down and outputs are tri-state. + * | | |This bit is 1'b0 in default + * | | |This means the USB PHY 0 is suspended in default + * | | |It is necessary to set this bit 1'b1 to make USB PHY 0 leave suspend mode before doing configuration of USB host. + * | | |0 = USB PHY 0 was suspended. + * | | |1 = USB PHY 0 was not suspended. + * |[11] |CLKVALID |UTMI Clock Valid + * | | |This bit is a flag to indicate if the UTMI clock from USB 2.0 PHY is ready + * | | |S/W program must prevent to write other control registers before this UTMI clock valid flag is active. + * | | |0 = UTMI clock is not valid. + * | | |1 = UTMI clock is valid. + * @var HSUSBH_T::USBPCR1 + * Offset: 0xC8 USB PHY 1 Control Register + * --------------------------------------------------------------------------------------------------- + * |Bits |Field |Descriptions + * | :----: | :----: | :---- | + * |[8] |SUSPEND |Suspend Assertion + * | | |This bit controls the suspend mode of USB PHY 1. + * | | |While PHY was suspended, all circuits of PHY were powered down and outputs are tri-state. + * | | |This bit is 1'b0 in default + * | | |This means the USB PHY 0 is suspended in default + * | | |It is necessary to set this bit 1'b1 to make USB PHY 0 leave suspend mode before doing configuration of USB host. + * | | |0 = USB PHY 1 was suspended. + * | | |1 = USB PHY 1 was not suspended. + */ + __I uint32_t EHCVNR; /*!< [0x0000] EHCI Version Number Register */ + __I uint32_t EHCSPR; /*!< [0x0004] EHCI Structural Parameters Register */ + __I uint32_t EHCCPR; /*!< [0x0008] EHCI Capability Parameters Register */ + __I uint32_t RESERVE0[5]; + __IO uint32_t UCMDR; /*!< [0x0020] USB Command Register */ + __IO uint32_t USTSR; /*!< [0x0024] USB Status Register */ + __IO uint32_t UIENR; /*!< [0x0028] USB Interrupt Enable Register */ + __IO uint32_t UFINDR; /*!< [0x002c] USB Frame Index Register */ + __I uint32_t RESERVE1[1]; + __IO uint32_t UPFLBAR; /*!< [0x0034] USB Periodic Frame List Base Address Register */ + __IO uint32_t UCALAR; /*!< [0x0038] USB Current Asynchronous List Address Register */ + __IO uint32_t UASSTR; /*!< [0x003c] USB Asynchronous Schedule Sleep Timer Register */ + __I uint32_t RESERVE2[8]; + __IO uint32_t UCFGR; /*!< [0x0060] USB Configure Flag Register */ + __IO uint32_t UPSCR[2]; /*!< [0x0064] ~ [0x0068] USB Port 0 & 1 Status and Control Register */ + __I uint32_t RESERVE3[22]; + __IO uint32_t USBPCR0; /*!< [0x00c4] USB PHY 0 Control Register */ + __IO uint32_t USBPCR1; /*!< [0x00c8] USB PHY 1 Control Register */ + +} HSUSBH_T; + +/** + @addtogroup HSUSBH_CONST HSUSBH Bit Field Definition + Constant Definitions for HSUSBH Controller +@{ */ + +#define HSUSBH_EHCVNR_CRLEN_Pos (0) /*!< HSUSBH_T::EHCVNR: CRLEN Position */ +#define HSUSBH_EHCVNR_CRLEN_Msk (0xfful << HSUSBH_EHCVNR_CRLEN_Pos) /*!< HSUSBH_T::EHCVNR: CRLEN Mask */ + +#define HSUSBH_EHCVNR_VERSION_Pos (16) /*!< HSUSBH_T::EHCVNR: VERSION Position */ +#define HSUSBH_EHCVNR_VERSION_Msk (0xfffful << HSUSBH_EHCVNR_VERSION_Pos) /*!< HSUSBH_T::EHCVNR: VERSION Mask */ + +#define HSUSBH_EHCSPR_N_PORTS_Pos (0) /*!< HSUSBH_T::EHCSPR: N_PORTS Position */ +#define HSUSBH_EHCSPR_N_PORTS_Msk (0xful << HSUSBH_EHCSPR_N_PORTS_Pos) /*!< HSUSBH_T::EHCSPR: N_PORTS Mask */ + +#define HSUSBH_EHCSPR_PPC_Pos (4) /*!< HSUSBH_T::EHCSPR: PPC Position */ +#define HSUSBH_EHCSPR_PPC_Msk (0x1ul << HSUSBH_EHCSPR_PPC_Pos) /*!< HSUSBH_T::EHCSPR: PPC Mask */ + +#define HSUSBH_EHCSPR_N_PCC_Pos (8) /*!< HSUSBH_T::EHCSPR: N_PCC Position */ +#define HSUSBH_EHCSPR_N_PCC_Msk (0xful << HSUSBH_EHCSPR_N_PCC_Pos) /*!< HSUSBH_T::EHCSPR: N_PCC Mask */ + +#define HSUSBH_EHCSPR_N_CC_Pos (12) /*!< HSUSBH_T::EHCSPR: N_CC Position */ +#define HSUSBH_EHCSPR_N_CC_Msk (0xful << HSUSBH_EHCSPR_N_CC_Pos) /*!< HSUSBH_T::EHCSPR: N_CC Mask */ + +#define HSUSBH_EHCCPR_AC64_Pos (0) /*!< HSUSBH_T::EHCCPR: AC64 Position */ +#define HSUSBH_EHCCPR_AC64_Msk (0x1ul << HSUSBH_EHCCPR_AC64_Pos) /*!< HSUSBH_T::EHCCPR: AC64 Mask */ + +#define HSUSBH_EHCCPR_PFLF_Pos (1) /*!< HSUSBH_T::EHCCPR: PFLF Position */ +#define HSUSBH_EHCCPR_PFLF_Msk (0x1ul << HSUSBH_EHCCPR_PFLF_Pos) /*!< HSUSBH_T::EHCCPR: PFLF Mask */ + +#define HSUSBH_EHCCPR_ASPC_Pos (2) /*!< HSUSBH_T::EHCCPR: ASPC Position */ +#define HSUSBH_EHCCPR_ASPC_Msk (0x1ul << HSUSBH_EHCCPR_ASPC_Pos) /*!< HSUSBH_T::EHCCPR: ASPC Mask */ + +#define HSUSBH_EHCCPR_IST_Pos (4) /*!< HSUSBH_T::EHCCPR: IST Position */ +#define HSUSBH_EHCCPR_IST_Msk (0xful << HSUSBH_EHCCPR_IST_Pos) /*!< HSUSBH_T::EHCCPR: IST Mask */ + +#define HSUSBH_EHCCPR_EECP_Pos (8) /*!< HSUSBH_T::EHCCPR: EECP Position */ +#define HSUSBH_EHCCPR_EECP_Msk (0xfful << HSUSBH_EHCCPR_EECP_Pos) /*!< HSUSBH_T::EHCCPR: EECP Mask */ + +#define HSUSBH_UCMDR_RUN_Pos (0) /*!< HSUSBH_T::UCMDR: RUN Position */ +#define HSUSBH_UCMDR_RUN_Msk (0x1ul << HSUSBH_UCMDR_RUN_Pos) /*!< HSUSBH_T::UCMDR: RUN Mask */ + +#define HSUSBH_UCMDR_HCRST_Pos (1) /*!< HSUSBH_T::UCMDR: HCRST Position */ +#define HSUSBH_UCMDR_HCRST_Msk (0x1ul << HSUSBH_UCMDR_HCRST_Pos) /*!< HSUSBH_T::UCMDR: HCRST Mask */ + +#define HSUSBH_UCMDR_FLSZ_Pos (2) /*!< HSUSBH_T::UCMDR: FLSZ Position */ +#define HSUSBH_UCMDR_FLSZ_Msk (0x3ul << HSUSBH_UCMDR_FLSZ_Pos) /*!< HSUSBH_T::UCMDR: FLSZ Mask */ + +#define HSUSBH_UCMDR_PSEN_Pos (4) /*!< HSUSBH_T::UCMDR: PSEN Position */ +#define HSUSBH_UCMDR_PSEN_Msk (0x1ul << HSUSBH_UCMDR_PSEN_Pos) /*!< HSUSBH_T::UCMDR: PSEN Mask */ + +#define HSUSBH_UCMDR_ASEN_Pos (5) /*!< HSUSBH_T::UCMDR: ASEN Position */ +#define HSUSBH_UCMDR_ASEN_Msk (0x1ul << HSUSBH_UCMDR_ASEN_Pos) /*!< HSUSBH_T::UCMDR: ASEN Mask */ + +#define HSUSBH_UCMDR_IAAD_Pos (6) /*!< HSUSBH_T::UCMDR: IAAD Position */ +#define HSUSBH_UCMDR_IAAD_Msk (0x1ul << HSUSBH_UCMDR_IAAD_Pos) /*!< HSUSBH_T::UCMDR: IAAD Mask */ + +#define HSUSBH_UCMDR_ITC_Pos (16) /*!< HSUSBH_T::UCMDR: ITC Position */ +#define HSUSBH_UCMDR_ITC_Msk (0xfful << HSUSBH_UCMDR_ITC_Pos) /*!< HSUSBH_T::UCMDR: ITC Mask */ + +#define HSUSBH_USTSR_USBINT_Pos (0) /*!< HSUSBH_T::USTSR: USBINT Position */ +#define HSUSBH_USTSR_USBINT_Msk (0x1ul << HSUSBH_USTSR_USBINT_Pos) /*!< HSUSBH_T::USTSR: USBINT Mask */ + +#define HSUSBH_USTSR_UERRINT_Pos (1) /*!< HSUSBH_T::USTSR: UERRINT Position */ +#define HSUSBH_USTSR_UERRINT_Msk (0x1ul << HSUSBH_USTSR_UERRINT_Pos) /*!< HSUSBH_T::USTSR: UERRINT Mask */ + +#define HSUSBH_USTSR_PCD_Pos (2) /*!< HSUSBH_T::USTSR: PCD Position */ +#define HSUSBH_USTSR_PCD_Msk (0x1ul << HSUSBH_USTSR_PCD_Pos) /*!< HSUSBH_T::USTSR: PCD Mask */ + +#define HSUSBH_USTSR_FLR_Pos (3) /*!< HSUSBH_T::USTSR: FLR Position */ +#define HSUSBH_USTSR_FLR_Msk (0x1ul << HSUSBH_USTSR_FLR_Pos) /*!< HSUSBH_T::USTSR: FLR Mask */ + +#define HSUSBH_USTSR_HSERR_Pos (4) /*!< HSUSBH_T::USTSR: HSERR Position */ +#define HSUSBH_USTSR_HSERR_Msk (0x1ul << HSUSBH_USTSR_HSERR_Pos) /*!< HSUSBH_T::USTSR: HSERR Mask */ + +#define HSUSBH_USTSR_IAA_Pos (5) /*!< HSUSBH_T::USTSR: IAA Position */ +#define HSUSBH_USTSR_IAA_Msk (0x1ul << HSUSBH_USTSR_IAA_Pos) /*!< HSUSBH_T::USTSR: IAA Mask */ + +#define HSUSBH_USTSR_HCHalted_Pos (12) /*!< HSUSBH_T::USTSR: HCHalted Position */ +#define HSUSBH_USTSR_HCHalted_Msk (0x1ul << HSUSBH_USTSR_HCHalted_Pos) /*!< HSUSBH_T::USTSR: HCHalted Mask */ + +#define HSUSBH_USTSR_RECLA_Pos (13) /*!< HSUSBH_T::USTSR: RECLA Position */ +#define HSUSBH_USTSR_RECLA_Msk (0x1ul << HSUSBH_USTSR_RECLA_Pos) /*!< HSUSBH_T::USTSR: RECLA Mask */ + +#define HSUSBH_USTSR_PSS_Pos (14) /*!< HSUSBH_T::USTSR: PSS Position */ +#define HSUSBH_USTSR_PSS_Msk (0x1ul << HSUSBH_USTSR_PSS_Pos) /*!< HSUSBH_T::USTSR: PSS Mask */ + +#define HSUSBH_USTSR_ASS_Pos (15) /*!< HSUSBH_T::USTSR: ASS Position */ +#define HSUSBH_USTSR_ASS_Msk (0x1ul << HSUSBH_USTSR_ASS_Pos) /*!< HSUSBH_T::USTSR: ASS Mask */ + +#define HSUSBH_UIENR_USBIEN_Pos (0) /*!< HSUSBH_T::UIENR: USBIEN Position */ +#define HSUSBH_UIENR_USBIEN_Msk (0x1ul << HSUSBH_UIENR_USBIEN_Pos) /*!< HSUSBH_T::UIENR: USBIEN Mask */ + +#define HSUSBH_UIENR_UERRIEN_Pos (1) /*!< HSUSBH_T::UIENR: UERRIEN Position */ +#define HSUSBH_UIENR_UERRIEN_Msk (0x1ul << HSUSBH_UIENR_UERRIEN_Pos) /*!< HSUSBH_T::UIENR: UERRIEN Mask */ + +#define HSUSBH_UIENR_PCIEN_Pos (2) /*!< HSUSBH_T::UIENR: PCIEN Position */ +#define HSUSBH_UIENR_PCIEN_Msk (0x1ul << HSUSBH_UIENR_PCIEN_Pos) /*!< HSUSBH_T::UIENR: PCIEN Mask */ + +#define HSUSBH_UIENR_FLREN_Pos (3) /*!< HSUSBH_T::UIENR: FLREN Position */ +#define HSUSBH_UIENR_FLREN_Msk (0x1ul << HSUSBH_UIENR_FLREN_Pos) /*!< HSUSBH_T::UIENR: FLREN Mask */ + +#define HSUSBH_UIENR_HSERREN_Pos (4) /*!< HSUSBH_T::UIENR: HSERREN Position */ +#define HSUSBH_UIENR_HSERREN_Msk (0x1ul << HSUSBH_UIENR_HSERREN_Pos) /*!< HSUSBH_T::UIENR: HSERREN Mask */ + +#define HSUSBH_UIENR_IAAEN_Pos (5) /*!< HSUSBH_T::UIENR: IAAEN Position */ +#define HSUSBH_UIENR_IAAEN_Msk (0x1ul << HSUSBH_UIENR_IAAEN_Pos) /*!< HSUSBH_T::UIENR: IAAEN Mask */ + +#define HSUSBH_UFINDR_FI_Pos (0) /*!< HSUSBH_T::UFINDR: FI Position */ +#define HSUSBH_UFINDR_FI_Msk (0x3ffful << HSUSBH_UFINDR_FI_Pos) /*!< HSUSBH_T::UFINDR: FI Mask */ + +#define HSUSBH_UPFLBAR_BADDR_Pos (12) /*!< HSUSBH_T::UPFLBAR: BADDR Position */ +#define HSUSBH_UPFLBAR_BADDR_Msk (0xffffful << HSUSBH_UPFLBAR_BADDR_Pos) /*!< HSUSBH_T::UPFLBAR: BADDR Mask */ + +#define HSUSBH_UCALAR_LPL_Pos (5) /*!< HSUSBH_T::UCALAR: LPL Position */ +#define HSUSBH_UCALAR_LPL_Msk (0x7fffffful << HSUSBH_UCALAR_LPL_Pos) /*!< HSUSBH_T::UCALAR: LPL Mask */ + +#define HSUSBH_UASSTR_ASSTMR_Pos (0) /*!< HSUSBH_T::UASSTR: ASSTMR Position */ +#define HSUSBH_UASSTR_ASSTMR_Msk (0xffful << HSUSBH_UASSTR_ASSTMR_Pos) /*!< HSUSBH_T::UASSTR: ASSTMR Mask */ + +#define HSUSBH_UCFGR_CF_Pos (0) /*!< HSUSBH_T::UCFGR: CF Position */ +#define HSUSBH_UCFGR_CF_Msk (0x1ul << HSUSBH_UCFGR_CF_Pos) /*!< HSUSBH_T::UCFGR: CF Mask */ + +#define HSUSBH_UPSCR_CCS_Pos (0) /*!< HSUSBH_T::UPSCR[2]: CCS Position */ +#define HSUSBH_UPSCR_CCS_Msk (0x1ul << HSUSBH_UPSCR_CCS_Pos) /*!< HSUSBH_T::UPSCR[2]: CCS Mask */ + +#define HSUSBH_UPSCR_CSC_Pos (1) /*!< HSUSBH_T::UPSCR[2]: CSC Position */ +#define HSUSBH_UPSCR_CSC_Msk (0x1ul << HSUSBH_UPSCR_CSC_Pos) /*!< HSUSBH_T::UPSCR[2]: CSC Mask */ + +#define HSUSBH_UPSCR_PE_Pos (2) /*!< HSUSBH_T::UPSCR[2]: PE Position */ +#define HSUSBH_UPSCR_PE_Msk (0x1ul << HSUSBH_UPSCR_PE_Pos) /*!< HSUSBH_T::UPSCR[2]: PE Mask */ + +#define HSUSBH_UPSCR_PEC_Pos (3) /*!< HSUSBH_T::UPSCR[2]: PEC Position */ +#define HSUSBH_UPSCR_PEC_Msk (0x1ul << HSUSBH_UPSCR_PEC_Pos) /*!< HSUSBH_T::UPSCR[2]: PEC Mask */ + +#define HSUSBH_UPSCR_OCA_Pos (4) /*!< HSUSBH_T::UPSCR[2]: OCA Position */ +#define HSUSBH_UPSCR_OCA_Msk (0x1ul << HSUSBH_UPSCR_OCA_Pos) /*!< HSUSBH_T::UPSCR[2]: OCA Mask */ + +#define HSUSBH_UPSCR_OCC_Pos (5) /*!< HSUSBH_T::UPSCR[2]: OCC Position */ +#define HSUSBH_UPSCR_OCC_Msk (0x1ul << HSUSBH_UPSCR_OCC_Pos) /*!< HSUSBH_T::UPSCR[2]: OCC Mask */ + +#define HSUSBH_UPSCR_FPR_Pos (6) /*!< HSUSBH_T::UPSCR[2]: FPR Position */ +#define HSUSBH_UPSCR_FPR_Msk (0x1ul << HSUSBH_UPSCR_FPR_Pos) /*!< HSUSBH_T::UPSCR[2]: FPR Mask */ + +#define HSUSBH_UPSCR_SUSPEND_Pos (7) /*!< HSUSBH_T::UPSCR[2]: SUSPEND Position */ +#define HSUSBH_UPSCR_SUSPEND_Msk (0x1ul << HSUSBH_UPSCR_SUSPEND_Pos) /*!< HSUSBH_T::UPSCR[2]: SUSPEND Mask */ + +#define HSUSBH_UPSCR_PRST_Pos (8) /*!< HSUSBH_T::UPSCR[2]: PRST Position */ +#define HSUSBH_UPSCR_PRST_Msk (0x1ul << HSUSBH_UPSCR_PRST_Pos) /*!< HSUSBH_T::UPSCR[2]: PRST Mask */ + +#define HSUSBH_UPSCR_LSTS_Pos (10) /*!< HSUSBH_T::UPSCR[2]: LSTS Position */ +#define HSUSBH_UPSCR_LSTS_Msk (0x3ul << HSUSBH_UPSCR_LSTS_Pos) /*!< HSUSBH_T::UPSCR[2]: LSTS Mask */ + +#define HSUSBH_UPSCR_PP_Pos (12) /*!< HSUSBH_T::UPSCR[2]: PP Position */ +#define HSUSBH_UPSCR_PP_Msk (0x1ul << HSUSBH_UPSCR_PP_Pos) /*!< HSUSBH_T::UPSCR[2]: PP Mask */ + +#define HSUSBH_UPSCR_PO_Pos (13) /*!< HSUSBH_T::UPSCR[2]: PO Position */ +#define HSUSBH_UPSCR_PO_Msk (0x1ul << HSUSBH_UPSCR_PO_Pos) /*!< HSUSBH_T::UPSCR[2]: PO Mask */ + +#define HSUSBH_UPSCR_PTC_Pos (16) /*!< HSUSBH_T::UPSCR[2]: PTC Position */ +#define HSUSBH_UPSCR_PTC_Msk (0xful << HSUSBH_UPSCR_PTC_Pos) /*!< HSUSBH_T::UPSCR[2]: PTC Mask */ + +#define HSUSBH_USBPCR0_SUSPEND_Pos (8) /*!< HSUSBH_T::USBPCR0: SUSPEND Position */ +#define HSUSBH_USBPCR0_SUSPEND_Msk (0x1ul << HSUSBH_USBPCR0_SUSPEND_Pos) /*!< HSUSBH_T::USBPCR0: SUSPEND Mask */ + +#define HSUSBH_USBPCR0_CLKVALID_Pos (11) /*!< HSUSBH_T::USBPCR0: CLKVALID Position */ +#define HSUSBH_USBPCR0_CLKVALID_Msk (0x1ul << HSUSBH_USBPCR0_CLKVALID_Pos) /*!< HSUSBH_T::USBPCR0: CLKVALID Mask */ + +#define HSUSBH_USBPCR1_SUSPEND_Pos (8) /*!< HSUSBH_T::USBPCR1: SUSPEND Position */ +#define HSUSBH_USBPCR1_SUSPEND_Msk (0x1ul << HSUSBH_USBPCR1_SUSPEND_Pos) /*!< HSUSBH_T::USBPCR1: SUSPEND Mask */ + +/**@}*/ /* HSUSBH_CONST */ +/**@}*/ /* end of HSUSBH register group */ + +#define USBH ((USBH_T *)0xB0007000) +#define HSUSBH ((HSUSBH_T *)0xB0005000) + + +/// @endcond /*HIDDEN_SYMBOLS*/ + +#endif /* _USBH_CONFIG_H_ */ + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/ehci.h b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/ehci.h new file mode 100644 index 0000000000000000000000000000000000000000..4d09ed9b8fceedb2a93f9f90415a4647032487e9 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/ehci.h @@ -0,0 +1,279 @@ +/**************************************************************************//** + * @file ehci.h + * @version V1.00 + * @brief USB EHCI host controller driver header file. + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ + +#ifndef _USBH_EHCI_H_ +#define _USBH_EHCI_H_ + +/// @cond HIDDEN_SYMBOLS + +struct utr_t; +struct udev_t; +struct qh_t; +struct iso_ep_t; +struct ep_info_t; + +/*----------------------------------------------------------------------------------------*/ +/* Periodic Frame List Size (256, 512, or 1024) */ +/*----------------------------------------------------------------------------------------*/ +#define FL_SIZE 1024 /* frame list size can be 256, 512, or 1024 */ +#define NUM_IQH 11 /* depends on FL_SIZE, 256:9, 512:10, 1024:11 */ + + +/*----------------------------------------------------------------------------------------*/ +/* Interrupt Threshold Control (1, 2, 4, 6, .. 64) */ +/*----------------------------------------------------------------------------------------*/ +#define UCMDR_INT_THR_CTRL (0x1< of QH */ +} qTD_T; + + +#define QTD_LIST_END 0x1 /* Indicate the terminate of qTD list. */ +#define QTD_PTR(x) ((qTD_T *)((uint32_t)(x) & ~0x1F)) + +/* + * Status: qTD Token[7:0] + */ +#define QTD_STS_PS_OUT (0<<0) /* directs the HC to issue an OUT PID */ +#define QTD_STS_PS_PING (1<<0) /* directs the HC to issue an PING PID */ +#define QTD_STS_SPLIT_STRAT (0<<1) /* directs the HC to issue an Start split */ +#define QTD_STS_SPLIT_COMPLETE (1<<1) /* directs the HC to issue an Complete split */ +#define QTD_STS_MISS_MF (1<<2) /* miss a required complete-split transaction */ +#define QTD_STS_XactErr (1<<3) /* Transaction Error occurred */ +#define QTD_STS_BABBLE (1<<4) /* Babble Detected */ +#define QTD_STS_DATA_BUFF_ERR (1<<5) /* Data Buffer Error */ +#define QTD_STS_HALT (1<<6) /* Halted */ +#define QTD_STS_ACTIVE (1<<7) /* Active */ + +/* + * PID: qTD Token[9:8] + */ +#define QTD_PID_Msk (0x3<<8) +#define QTD_PID_OUT (0<<8) /* generates token (E1H) */ +#define QTD_PID_IN (1<<8) /* generates token (69H) */ +#define QTD_PID_SETUP (2<<8) /* generates token (2DH) */ + +#define QTD_ERR_COUNTER (3<<10) /* Token[11:10] */ +#define QTD_IOC (1<<15) /* Token[15] - Interrupt On Complete */ +#define QTD_TODO_LEN_Pos 16 /* Token[31:16] - Total Bytes to Transfer */ +#define QTD_TODO_LEN(x) (((x)>>16) & 0x7FFF) +#define QTD_DT (1UL<<31) /* Token[31] - Data Toggle */ + +/*----------------------------------------------------------------------------------------*/ +/* Queue Head (QH) */ +/*----------------------------------------------------------------------------------------*/ +typedef struct qh_t +{ + /* OHCI spec. Endpoint descriptor */ + uint32_t HLink; /* Queue Head Horizontal Link Pointer */ + uint32_t Chrst; /* Endpoint Characteristics: QH DWord 1 */ + uint32_t Cap; /* Endpoint Capabilities: QH DWord 2 */ + uint32_t Curr_qTD; /* Current qTD Pointer */ + /* + * The followings are qTD Transfer Overlay + */ + uint32_t OL_Next_qTD; /* Next qTD Pointer */ + uint32_t OL_Alt_Next_qTD; /* Alternate Next qTD Pointer */ + uint32_t OL_Token; /* qTD Token */ + uint32_t OL_Bptr[5]; /* qTD Buffer Page Pointer List */ + /* + * The following members are used by USB Host libary. + */ + qTD_T *qtd_list; /* currently linked qTD transfers */ + qTD_T *done_list; /* currently linked qTD transfers */ + struct qh_t *next; /* point to the next QH in remove list */ +} QH_T; + +/* HLink[0] T field of "Queue Head Horizontal Link Pointer" */ +#define QH_HLNK_END 0x1 + +/* + * HLink[2:1] Typ field of "Queue Head Horizontal Link Pointer" + */ +#define QH_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0) +#define QH_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2) +#define QH_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4) +#define QH_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6) +#define QH_PTR(x) ((QH_T *)((uint32_t)(x) & ~0x1F)) + +/* + * Bit fields of "Endpoint Characteristics" + */ +#define QH_NAK_RL (4L<<28) /* Chrst[31:28] - NAK Count Reload */ +#define QH_CTRL_EP_FLAG (1<<27) /* Chrst[27] - Control Endpoint Flag */ +#define QH_RCLM_LIST_HEAD (1<<15) /* Chrst[15] - Head of Reclamation List Flag */ +#define QH_DTC (1<<14) /* Chrst[14] - Data Toggle Control */ +#define QH_EPS_FULL (0<<12) /* Chrst[13:12] - Endpoint Speed (Full) */ +#define QH_EPS_LOW (1<<12) /* Chrst[13:12] - Endpoint Speed (Low) */ +#define QH_EPS_HIGH (2<<12) /* Chrst[13:12] - Endpoint Speed (High) */ +#define QH_I_NEXT (1<<7) /* Chrst[7] - Inactivate on Next Transaction */ + +/* + * Bit fields of "Endpoint Capabilities" + */ +#define QH_MULT_Pos 30 /* Cap[31:30] - High-Bandwidth Pipe Multiplier */ +#define QH_HUB_PORT_Pos 23 /* Cap[29:23] - Hub Port Number */ +#define QH_HUB_ADDR_Pos 16 /* Cap[22:16] - Hub Addr */ +#define QH_C_MASK_Msk 0xFF00 /* Cap[15:8] - uFrame C-mask */ +#define QH_S_MASK_Msk 0x00FF /* Cap[7:0] - uFrame S-mask */ + + +/*----------------------------------------------------------------------------------------*/ +/* Isochronous (High-Speed) Transfer Descriptor (iTD) */ +/*----------------------------------------------------------------------------------------*/ +typedef struct itd_t +{ + uint32_t Next_Link; /* Next Link Pointer */ + uint32_t Transaction[8]; /* Transaction Status and Control */ + uint32_t Bptr[7]; /* Buffer Page Pointer List */ + /* + * The following members are used by USB Host libary. + */ + struct iso_ep_t *iso_ep; /* associated isochronous information block */ + struct utr_t *utr; /* associated UTR */ + uint32_t buff_base; /* buffer base address */ + uint8_t fidx; /* iTD's first index to UTR iso frames */ + uint8_t trans_mask; /* mask of activated transactions in iTD */ + uint32_t sched_frnidx; /* scheduled frame index */ + struct itd_t *next; /* used by software to maintain iTD list */ +} iTD_T; + +/* + * Next_Link[2:1] Typ field of "Next Schedule Element Pointer" Typ field + */ +#define ITD_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0) +#define ITD_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2) +#define ITD_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4) +#define ITD_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6) +#define ITD_PTR(x) ((iTD_T *)((uint32_t)(x) & ~0x1F)) + +/* + * Transaction[8] + */ +#define ITD_STATUS(x) (((x)>>28)&0xF) +#define ITD_STATUS_ACTIVE (0x80000000UL) /* Active */ +#define ITD_STATUS_BUFF_ERR (0x40000000UL) /* Data Buffer Error */ +#define ITD_STATUS_BABBLE (0x20000000UL) /* Babble Detected */ +#define ITD_STATUS_XACT_ERR (0x10000000UL) /* Transcation Error */ + +#define ITD_XLEN_Pos 16 +#define ITD_XFER_LEN(x) (((x)>>16)&0xFFF) +#define ITD_IOC (1<<15) +#define ITD_PG_Pos 12 +#define ITD_XFER_OFF_Msk 0xFFF + +/* + * Bptr[7] + */ +#define ITD_BUFF_PAGE_Pos 12 +/* Bptr[0] */ +#define ITD_EP_NUM_Pos 8 +#define ITD_EP_NUM(itd) (((itd)->Bptr[0]>>8)&0xF) +#define ITD_DEV_ADDR_Pos 0 +#define ITD_DEV_ADDR(itd) ((itd)->Bptr[0]&0x7F) +/* Bptr[1] */ +#define ITD_DIR_IN (1<<11) +#define ITD_DIR_OUT (0<<11) +#define ITD_MAX_PKTSZ_Pos 0 +#define ITD_MAX_PKTSZ(itd) ((itd)->Bptr[1]&0x7FF) + +/*----------------------------------------------------------------------------------------*/ +/* Split Isochronous (Full-Speed) Transfer Descriptor (siTD) */ +/*----------------------------------------------------------------------------------------*/ +typedef struct sitd_t +{ + uint32_t Next_Link; /* Next Link Pointer */ + uint32_t Chrst; /* Endpoint and Transaction Translator Characteristics */ + uint32_t Sched; /* Micro-frame Schedule Control */ + uint32_t StsCtrl; /* siTD Transfer Status and Control */ + uint32_t Bptr[2]; /* Buffer Page Pointer List */ + uint32_t BackLink; /* siTD Back Link Pointer */ + /* + * The following members are used by USB Host libary. + */ + struct iso_ep_t *iso_ep; /* associated isochronous information block */ + struct utr_t *utr; /* associated UTR */ + uint8_t fidx; /* iTD's first index to UTR iso frames */ + uint32_t sched_frnidx; /* scheduled frame index */ + struct sitd_t *next; /* used by software to maintain siTD list */ +} siTD_T; + +#define SITD_LIST_END 0x1 /* Indicate the terminate of siTD list. */ + +#define SITD_XFER_IO_Msk (1UL<<31) +#define SITD_XFER_IN (1UL<<31) +#define SITD_XFER_OUT (0UL<<31) + +#define SITD_PORT_NUM_Pos 24 +#define SITD_HUB_ADDR_Pos 16 +#define SITD_EP_NUM_Pos 8 +#define SITD_DEV_ADDR_Pos 0 + +#define SITD_IOC (1UL<<31) +#define SITD_XFER_CNT_Pos 16 +#define SITD_XFER_CNT_Msk (0x3FF<>28) & 0x0F) +#define TD_CC_SET(td, cc) (td) = ((td) & 0x0FFFFFFF) | (((cc) & 0x0F) << 28) +#define TD_T_DATA0 0x02000000 +#define TD_T_DATA1 0x03000000 +#define TD_R 0x00040000 +#define TD_DP 0x00180000 +#define TD_DP_IN 0x00100000 +#define TD_DP_OUT 0x00080000 +#define MAXPSW 8 +/* steel TD reserved bits to keep driver data */ +#define TD_TYPE_Msk (0x3<<16) +#define TD_TYPE_CTRL (0x0<<16) +#define TD_TYPE_BULK (0x1<<16) +#define TD_TYPE_INT (0x2<<16) +#define TD_TYPE_ISO (0x3<<16) +#define TD_CTRL_Msk (0x7<<15) +#define TD_CTRL_DATA (1<<15) + + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of. It must be 256-byte aligned. + */ +typedef struct +{ + uint32_t int_table[32]; /* Interrupt ED table */ + uint16_t frame_no; /* current frame number */ + uint16_t pad1; /* set to 0 on each frame_no change */ + uint32_t done_head; /* info returned for an interrupt */ + uint8_t reserved_for_hc[116]; +} HCCA_T; + + +/// @endcond + +#endif /* _USBH_OHCI_H_ */ diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/usb.h b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/usb.h new file mode 100644 index 0000000000000000000000000000000000000000..4f99d4e6c9936984bddce7c95bfd98febaf56495 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/usb.h @@ -0,0 +1,394 @@ +/**************************************************************************//** + * @file usb.h + * @version V1.00 + * @brief USB Host library header file. + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved. + *****************************************************************************/ + +#ifndef _USBH_H_ +#define _USBH_H_ + +#include "config.h" +#include "usbh_lib.h" +#include "ehci.h" +#include "ohci.h" + +/// @cond HIDDEN_SYMBOLS + +struct utr_t; +struct udev_t; +struct hub_dev_t; +struct iface_t; +struct ep_info_t; + +/*----------------------------------------------------------------------------------*/ +/* USB device request setup packet */ +/*----------------------------------------------------------------------------------*/ +typedef struct __attribute__((__packed__)) +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} +DEV_REQ_T; + +/* + * bmRequestType[7] - Data transfer direction + */ +#define REQ_TYPE_OUT 0x00 +#define REQ_TYPE_IN 0x80 +/* + * bmRequestType[6:5] - Type + */ +#define REQ_TYPE_STD_DEV 0x00 +#define REQ_TYPE_CLASS_DEV 0x20 +#define REQ_TYPE_VENDOR_DEV 0x40 +/* + * bmRequestType[4:0] - Recipient + */ +#define REQ_TYPE_TO_DEV 0x00 +#define REQ_TYPE_TO_IFACE 0x01 +#define REQ_TYPE_TO_EP 0x02 +#define REQ_TYPE_TO_OTHER 0x03 +/* + * Standard Requests + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_SET_INTERFACE 0x0B +/* + * Descriptor Types + */ +#define USB_DT_STANDARD 0x00 +#define USB_DT_CLASS 0x20 +#define USB_DT_VENDOR 0x40 + +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIGURATION 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONF 0x07 +#define USB_DT_IFACE_POWER 0x08 + + + +/*----------------------------------------------------------------------------------*/ +/* USB standard descriptors */ +/*----------------------------------------------------------------------------------*/ + +/* Descriptor header */ +typedef struct __attribute__((__packed__)) +{ + uint8_t bLength; + uint8_t bDescriptorType; +} +DESC_HDR_T; + +/*----------------------------------------------------------------------------------*/ +/* USB device descriptor */ +/*----------------------------------------------------------------------------------*/ +typedef struct __attribute__((__packed__)) /*!< device descriptor structure */ +{ + uint8_t bLength; /*!< Length of device descriptor */ + uint8_t bDescriptorType; /*!< Device descriptor type */ + uint16_t bcdUSB; /*!< USB version number */ + uint8_t bDeviceClass; /*!< Device class code */ + uint8_t bDeviceSubClass; /*!< Device subclass code */ + uint8_t bDeviceProtocol; /*!< Device protocol code */ + uint8_t bMaxPacketSize0; /*!< Maximum packet size of control endpoint*/ + uint16_t idVendor; /*!< Vendor ID */ + uint16_t idProduct; /*!< Product ID */ + uint16_t bcdDevice; /*!< Device ID */ + uint8_t iManufacturer; /*!< Manufacture description string ID */ + uint8_t iProduct; /*!< Product description string ID */ + uint8_t iSerialNumber; /*!< Serial number description string ID */ + uint8_t bNumConfigurations; /*!< Total number of configurations */ +} +DESC_DEV_T; /*!< device descriptor structure */ + +/* + * Configuration Descriptor + */ +typedef struct __attribute__((__packed__)) usb_config_descriptor /*!< Configuration descriptor structure */ +{ + uint8_t bLength; /*!< Length of configuration descriptor */ + uint8_t bDescriptorType; /*!< Descriptor type */ + uint16_t wTotalLength; /*!< Total length of this configuration */ + uint8_t bNumInterfaces; /*!< Total number of interfaces */ + uint8_t bConfigurationValue; /*!< Configuration descriptor number */ + uint8_t iConfiguration; /*!< String descriptor ID */ + uint8_t bmAttributes; /*!< Configuration characteristics */ + uint8_t MaxPower; /*!< Maximum power consumption */ +} DESC_CONF_T; /*!< Configuration descriptor structure */ + +/* + * Interface Descriptor + */ +typedef struct __attribute__((__packed__))usb_interface_descriptor /*!< Interface descriptor structure */ +{ + uint8_t bLength; /*!< Length of interface descriptor */ + uint8_t bDescriptorType; /*!< Descriptor type */ + uint8_t bInterfaceNumber; /*!< Interface number */ + uint8_t bAlternateSetting; /*!< Alternate setting number */ + uint8_t bNumEndpoints; /*!< Number of endpoints */ + uint8_t bInterfaceClass; /*!< Interface class code */ + uint8_t bInterfaceSubClass; /*!< Interface subclass code */ + uint8_t bInterfaceProtocol; /*!< Interface protocol code */ + uint8_t iInterface; /*!< Interface ID */ +} DESC_IF_T; /*!< Interface descriptor structure */ + +/* + * Endpoint Descriptor + */ +typedef struct __attribute__((__packed__)) usb_endpoint_descriptor /*!< Endpoint descriptor structure */ +{ + uint8_t bLength; /*!< Length of endpoint descriptor */ + uint8_t bDescriptorType; /*!< Descriptor type */ + uint8_t bEndpointAddress; /*!< Endpoint address */ + uint8_t bmAttributes; /*!< Endpoint attribute */ + uint16_t wMaxPacketSize; /*!< Maximum packet size */ + uint8_t bInterval; /*!< Synchronous transfer interval */ + uint8_t bRefresh; /*!< Refresh */ + uint8_t bSynchAddress; /*!< Sync address */ +} DESC_EP_T; /*!< Endpoint descriptor structure */ + +/* + * Endpoint descriptor bEndpointAddress[7] - direction + */ +#define EP_ADDR_DIR_MASK 0x80 +#define EP_ADDR_DIR_IN 0x80 +#define EP_ADDR_DIR_OUT 0x00 + +/* + * Endpoint descriptor bmAttributes[1:0] - transfer type + */ +#define EP_ATTR_TT_MASK 0x03 +#define EP_ATTR_TT_CTRL 0x00 +#define EP_ATTR_TT_ISO 0x01 +#define EP_ATTR_TT_BULK 0x02 +#define EP_ATTR_TT_INT 0x03 + + +/*----------------------------------------------------------------------------------*/ +/* USB Host controller driver */ +/*----------------------------------------------------------------------------------*/ +typedef struct +{ + int (*init)(void); + void (*shutdown)(void); + void (*suspend)(void); + void (*resume)(void); + int (*ctrl_xfer)(struct utr_t *utr); + int (*bulk_xfer)(struct utr_t *utr); + int (*int_xfer)(struct utr_t *utr); + int (*iso_xfer)(struct utr_t *utr); + int (*quit_xfer)(struct utr_t *utr, struct ep_info_t *ep); + + /* root hub support */ + int (*rthub_port_reset)(int port); + int (*rthub_polling)(void); +} HC_DRV_T; + + +/*----------------------------------------------------------------------------------*/ +/* USB device driver */ +/*----------------------------------------------------------------------------------*/ +typedef struct +{ + int (*probe)(struct iface_t *iface); + void (*disconnect)(struct iface_t *iface); + void (*suspend)(struct iface_t *iface); + void (*resume)(struct iface_t *iface); +} UDEV_DRV_T; + + +/*----------------------------------------------------------------------------------*/ +/* USB device */ +/*----------------------------------------------------------------------------------*/ + +typedef enum +{ + SPEED_LOW, + SPEED_FULL, + SPEED_HIGH +} SPEED_E; + +typedef struct ep_info_t +{ + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t bInterval; + uint8_t bToggle; + uint16_t wMaxPacketSize; + void *hw_pipe; /*!< point to the HC assocaied endpoint \hideinitializer */ +} EP_INFO_T; + +typedef struct udev_t +{ + DESC_DEV_T descriptor; /*!< Device descriptor. \hideinitializer */ + struct hub_dev_t *parent; /*!< parent hub device \hideinitializer */ + uint8_t port_num; /*!< The hub port this device connected on \hideinitializer */ + uint8_t dev_num; /*!< device number \hideinitializer */ + int8_t cur_conf; /*!< Currentll selected configuration \hideinitializer */ + SPEED_E speed; /*!< device speed (low/full/high) \hideinitializer */ + /* + * The followings are lightweight USB stack internal used . + */ + uint8_t *cfd_buff; /*!< Configuration descriptor buffer. \hideinitializer */ + EP_INFO_T ep0; /*!< Endpoint 0 \hideinitializer */ + HC_DRV_T *hc_driver; /*!< host controller driver \hideinitializer */ + struct iface_t *iface_list; /*!< Working interface list \hideinitializer */ + struct udev_t *next; /*!< link for global usb device list \hideinitializer */ +} UDEV_T; + +typedef struct alt_iface_t +{ + DESC_IF_T *ifd; /*!< point to the location of this alternative interface descriptor in UDEV_T->cfd_buff */ + EP_INFO_T ep[MAX_EP_PER_IFACE]; /*!< endpoints of this alternative interface */ +} ALT_IFACE_T; + +typedef struct iface_t +{ + UDEV_T *udev; /*!< USB device \hideinitializer */ + uint8_t if_num; /*!< Interface number \hideinitializer */ + uint8_t num_alt; /*!< Number of alternative interface \hideinitializer */ + ALT_IFACE_T *aif; /*!< Point to the active alternative interface */ + ALT_IFACE_T alt[MAX_ALT_PER_IFACE]; /*!< List of alternative interface \hideinitializer */ + UDEV_DRV_T *driver; /*!< Interface associated driver \hideinitializer */ + void *context; /*!< Reference to device context \hideinitializer */ + struct iface_t *next; /*!< Point to next interface of the same device. Started from UDEV_T->iface_list \hideinitializer */ +} IFACE_T; + + +/*----------------------------------------------------------------------------------*/ +/* URB (USB Request Block) */ +/*----------------------------------------------------------------------------------*/ + +#define IF_PER_UTR 8 /* number of frames per UTR isochronous transfer (DO NOT modify it!) */ + +typedef void (*FUNC_UTR_T)(struct utr_t *); + +typedef struct utr_t +{ + UDEV_T *udev; /*!< point to associated USB device \hideinitializer */ + DEV_REQ_T setup; /*!< buffer for setup packet \hideinitializer */ + EP_INFO_T *ep; /*!< associated endpoint \hideinitializer */ + uint8_t *buff; /*!< transfer buffer \hideinitializer */ + uint8_t bIsTransferDone; /*!< tansfer done? \hideinitializer */ + uint32_t data_len; /*!< length of data to be transferred \hideinitializer */ + uint32_t xfer_len; /*!< length of transferred data \hideinitializer */ + uint8_t bIsoNewSched; /*!< New schedule isochronous transfer \hideinitializer */ + uint16_t iso_sf; /*!< Isochronous start frame number \hideinitializer */ + uint16_t iso_xlen[IF_PER_UTR]; /*!< transfer length of isochronous frames \hideinitializer */ + uint8_t *iso_buff[IF_PER_UTR]; /*!< transfer buffer address of isochronous frames \hideinitializer */ + int iso_status[IF_PER_UTR]; /*!< transfer status of isochronous frames \hideinitializer */ + int td_cnt; /*!< number of transfer descriptors \hideinitializer */ + int status; /*!< return status \hideinitializer */ + int interval; /*!< interrupt/isochronous interval \hideinitializer */ + void *context; /*!< point to deivce proprietary data area \hideinitializer */ + FUNC_UTR_T func; /*!< tansfer done call-back function \hideinitializer */ + struct utr_t *next; /* point to the next UTR of the same endpoint. \hideinitializer */ +} UTR_T; + + +/*----------------------------------------------------------------------------------*/ +/* Global variables */ +/*----------------------------------------------------------------------------------*/ +extern USBH_T *_ohci; +extern HSUSBH_T *_ehci; + +extern HC_DRV_T ohci_driver; +extern HC_DRV_T ehci_driver; + +extern UDEV_T *g_udev_list; + +extern volatile int _IsInUsbInterrupt; + +/*----------------------------------------------------------------------------------*/ +/* USB stack exported functions */ +/*----------------------------------------------------------------------------------*/ +extern void usbh_delay_ms(int msec); + +extern void dump_ohci_regs(void); +extern void dump_ohci_ports(void); +extern void dump_ohci_int_table(void); +extern void dump_ehci_regs(void); +extern void dump_ehci_qtd(qTD_T *qtd); +extern void dump_ehci_asynclist(void); +extern void dump_ehci_period_frame_list_simple(void); +extern void usbh_dump_buff_bytes(uint8_t *buff, int nSize); +extern void usbh_dump_interface_descriptor(DESC_IF_T *if_desc); +extern void usbh_dump_endpoint_descriptor(DESC_EP_T *ep_desc); +extern void usbh_dump_iface(IFACE_T *iface); +extern void usbh_dump_ep_info(EP_INFO_T *ep); + +/* + * Memory management functions + */ +extern void USB_InitializeMemoryPool(void); +extern void *USB_malloc(int wanted_size, int boundary); +extern void USB_free(void *); +extern int USB_available_memory(void); +extern int USB_allocated_memory(void); +extern void usbh_memory_init(void); +extern uint32_t usbh_memory_used(void); +extern void *usbh_alloc_mem(int size); +extern void usbh_free_mem(void *p, int size); +extern int alloc_dev_address(void); +extern void free_dev_address(int dev_addr); +extern UDEV_T *alloc_device(void); +extern void free_device(UDEV_T *udev); +extern UTR_T *alloc_utr(UDEV_T *udev); +extern void free_utr(UTR_T *utr); +extern ED_T *alloc_ohci_ED(void); +extern void free_ohci_ED(ED_T *ed); +extern TD_T *alloc_ohci_TD(UTR_T *utr); +extern void free_ohci_TD(TD_T *td); +extern QH_T *alloc_ehci_QH(void); +extern void free_ehci_QH(QH_T *qh); +extern qTD_T *alloc_ehci_qTD(UTR_T *utr); +extern void free_ehci_qTD(qTD_T *qtd); +extern iTD_T *alloc_ehci_iTD(void); +extern void free_ehci_iTD(iTD_T *itd); +extern siTD_T *alloc_ehci_siTD(void); +extern void free_ehci_siTD(siTD_T *sitd); + + +extern void usbh_hub_init(void); +extern int usbh_connect_device(UDEV_T *); +extern void usbh_disconnect_device(UDEV_T *); +extern int usbh_register_driver(UDEV_DRV_T *driver); +extern EP_INFO_T *usbh_iface_find_ep(IFACE_T *iface, uint8_t ep_addr, uint8_t dir_type); +extern int usbh_reset_device(UDEV_T *); +extern int usbh_reset_port(UDEV_T *); + +/* + * USB Standard Request functions + */ +extern int usbh_get_device_descriptor(UDEV_T *udev, DESC_DEV_T *desc_buff); +extern int usbh_get_config_descriptor(UDEV_T *udev, uint8_t *desc_buff, int buff_len); +extern int usbh_set_configuration(UDEV_T *udev, uint8_t conf_val); +extern int usbh_set_interface(IFACE_T *iface, uint16_t alt_setting); +extern int usbh_clear_halt(UDEV_T *udev, uint16_t ep_addr); + +extern int usbh_ctrl_xfer(UDEV_T *udev, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *buff, uint32_t *xfer_len, uint32_t timeout); +extern int usbh_bulk_xfer(UTR_T *utr); +extern int usbh_int_xfer(UTR_T *utr); +extern int usbh_iso_xfer(UTR_T *utr); +extern int usbh_quit_utr(UTR_T *utr); +extern int usbh_quit_xfer(UDEV_T *udev, EP_INFO_T *ep); + + +/// @endcond HIDDEN_SYMBOLS + +#endif /* _USBH_H_ */ diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/usbh_lib.h b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/usbh_lib.h new file mode 100644 index 0000000000000000000000000000000000000000..ecf336e4749424a7c5542b353b3ef646ee871252 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/inc/usbh_lib.h @@ -0,0 +1,188 @@ +/**************************************************************************//** + * @file usbh_lib.h + * @version V1.10 + * $Revision: 4 $ + * $Date: 15/06/10 2:06p $ + * @brief USB Host library exported header file. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved. + ******************************************************************************/ +#ifndef _USBH_LIB_H_ +#define _USBH_LIB_H_ + +#include "N9H30.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @addtogroup Library Library + @{ +*/ + +/** @addtogroup USBH_Library USB Host Library + @{ +*/ + +/** @addtogroup USBH_EXPORTED_CONSTANTS USB Host Exported Constants + @{ +*/ + +#define USBH_OK 0 /*!< No error. */ +#define USBH_ERR_MEMORY_OUT -10 /*!< Out of memory. */ +#define USBH_ERR_IF_ALT_LIMIT -11 /*!< Number of alternative interface > MAX_ALT_PER_IFACE */ +#define USBH_ERR_IF_EP_LIMIT -15 /*!< Number of endpoints > MAX_EP_PER_IFACE */ +#define USBH_ERR_NOT_SUPPORTED -101 /*!< Device/Class/Transfer not supported */ +#define USBH_ERR_NOT_MATCHED -103 /*!< Not macthed */ +#define USBH_ERR_NOT_EXPECTED -104 /*!< Unknown or unexpected */ +#define USBH_ERR_INVALID_PARAM -105 /*!< Invalid parameter */ +#define USBH_ERR_NOT_FOUND -106 /*!< Device or interface not found */ +#define USBH_ERR_EP_NOT_FOUND -107 /*!< Endpoint not found */ +#define USBH_ERR_DESCRIPTOR -137 /*!< Failed to parse USB descriptors */ +#define USBH_ERR_SET_DEV_ADDR -139 /*!< Failed to set device address */ +#define USBH_ERR_SET_CONFIG -151 /*!< Failed to set device configuration */ + +#define USBH_ERR_TRANSFER -201 /*!< USB transfer error */ +#define USBH_ERR_TIMEOUT -203 /*!< USB transfer time-out */ +#define USBH_ERR_ABORT -205 /*!< USB transfer aborted due to disconnect or reset */ +#define USBH_ERR_PORT_RESET -255 /*!< Hub port reset failed */ +#define USBH_ERR_SCH_OVERRUN -257 /*!< USB isochronous schedule overrun */ +#define USBH_ERR_DISCONNECTED -259 /*!< USB device was disconnected */ + +#define USBH_ERR_TRANSACTION -271 /*!< USB transaction timeout, CRC, Bad PID, etc. */ +#define USBH_ERR_BABBLE_DETECTED -272 /*!< A ¡§babble¡¨ is detected during the transaction */ +#define USBH_ERR_DATA_BUFF -274 /*!< Data buffer overrun or underrun */ + +#define USBH_ERR_CC_NO_ERR -280 /*!< OHCI CC code - no error */ +#define USBH_ERR_CRC -281 /*!< USB trasfer CRC error */ +#define USBH_ERR_BIT_STUFF -282 /*!< USB transfer bit stuffing error */ +#define USBH_ERR_DATA_TOGGLE -283 /*!< USB trasfer data toggle error */ +#define USBH_ERR_STALL -284 /*!< USB trasfer STALL error */ +#define USBH_ERR_DEV_NO_RESP -285 /*!< USB trasfer device no response error */ +#define USBH_ERR_PID_CHECK -286 /*!< USB trasfer PID check failure */ +#define USBH_ERR_UNEXPECT_PID -287 /*!< USB trasfer unexpected PID error */ +#define USBH_ERR_DATA_OVERRUN -288 /*!< USB trasfer data overrun error */ +#define USBH_ERR_DATA_UNDERRUN -289 /*!< USB trasfer data underrun error */ +#define USBH_ERR_BUFF_OVERRUN -292 /*!< USB trasfer buffer overrun error */ +#define USBH_ERR_BUFF_UNDERRUN -293 /*!< USB trasfer buffer underrun error */ +#define USBH_ERR_NOT_ACCESS0 -294 /*!< USB trasfer not accessed error */ +#define USBH_ERR_NOT_ACCESS1 -295 /*!< USB trasfer not accessed error */ + +#define USBH_ERR_OHCI_INIT -301 /*!< Failed to initialize OHIC controller. */ +#define USBH_ERR_OHCI_EP_BUSY -303 /*!< The endpoint is under transfer. */ + +#define USBH_ERR_EHCI_INIT -501 /*!< Failed to initialize EHCI controller. */ +#define USBH_ERR_EHCI_QH_BUSY -503 /*!< the Queue Head is busy. */ + +#define UMAS_OK 0 /*!< No error. */ +#define UMAS_ERR_NO_DEVICE -1031 /*!< No Mass Stroage Device found. */ +#define UMAS_ERR_IO -1033 /*!< Device read/write failed. */ +#define UMAS_ERR_INIT_DEVICE -1035 /*!< failed to init MSC device */ +#define UMAS_ERR_CMD_STATUS -1037 /*!< SCSI command status failed */ +#define UMAS_ERR_IVALID_PARM -1038 /*!< Invalid parameter. */ +#define UMAS_ERR_DRIVE_NOT_FOUND -1039 /*!< drive not found */ + +#define HID_RET_OK 0 /*!< Return with no errors. */ +#define HID_RET_DEV_NOT_FOUND -1081 /*!< HID device not found or removed. */ +#define HID_RET_IO_ERR -1082 /*!< USB transfer failed. */ +#define HID_RET_INVALID_PARAMETER -1083 /*!< Invalid parameter. */ +#define HID_RET_OUT_OF_MEMORY -1084 /*!< Out of memory. */ +#define HID_RET_NOT_SUPPORTED -1085 /*!< Function not supported. */ +#define HID_RET_EP_NOT_FOUND -1086 /*!< Endpoint not found. */ +#define HID_RET_PARSING -1087 /*!< Failed to parse HID descriptor */ +#define HID_RET_XFER_IS_RUNNING -1089 /*!< The transfer has been enabled. */ +#define HID_RET_REPORT_NOT_FOUND -1090 /*!< The transfer has been enabled. */ + +#define UAC_RET_OK 0 /*!< Return with no errors. */ +#define UAC_RET_DEV_NOT_FOUND -2001 /*!< Audio Class device not found or removed. */ +#define UAC_RET_FUNC_NOT_FOUND -2002 /*!< Audio device has no this function. */ +#define UAC_RET_IO_ERR -2003 /*!< USB transfer failed. */ +#define UAC_RET_DATA_LEN -2004 /*!< Unexpected transfer length */ +#define UAC_RET_INVALID -2005 /*!< Invalid parameter or usage. */ +#define UAC_RET_OUT_OF_MEMORY -2007 /*!< Out of memory. */ +#define UAC_RET_DRV_NOT_SUPPORTED -2009 /*!< Function not supported by this UAC driver. */ +#define UAC_RET_DEV_NOT_SUPPORTED -2011 /*!< Function not supported by the UAC device. */ +#define UAC_RET_PARSER -2013 /*!< Failed to parse UAC descriptor */ +#define UAC_RET_IS_STREAMING -2015 /*!< Audio pipe is on streaming. */ + + +/*@}*/ /* end of group USBH_EXPORTED_CONSTANTS */ + + +/** @addtogroup USBH_EXPORTED_TYPEDEF USB Host Typedef + @{ +*/ +struct udev_t; +typedef void (CONN_FUNC)(struct udev_t *udev, int param); + +struct line_coding_t; +struct cdc_dev_t; +typedef void (CDC_CB_FUNC)(struct cdc_dev_t *cdev, uint8_t *rdata, int data_len); + +struct usbhid_dev; +typedef void (HID_IR_FUNC)(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *rdata, uint32_t data_len); /*!< interrupt in callback function \hideinitializer */ +typedef void (HID_IW_FUNC)(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *wbuff, uint32_t *data_len); /*!< interrupt out callback function \hideinitializer */ + +struct uac_dev_t; +typedef int (UAC_CB_FUNC)(struct uac_dev_t *dev, uint8_t *data, int len); /*!< audio in callback function \hideinitializer */ + +/*@}*/ /* end of group USBH_EXPORTED_STRUCT */ + + + +/** @addtogroup USBH_EXPORTED_FUNCTIONS USB Host Exported Functions + @{ +*/ + +/*------------------------------------------------------------------*/ +/* */ +/* USB Core Library APIs */ +/* */ +/*------------------------------------------------------------------*/ +extern void usbh_core_init(void); +extern int usbh_polling_root_hubs(void); +extern void usbh_install_conn_callback(CONN_FUNC *conn_func, CONN_FUNC *disconn_func); +extern void usbh_suspend(void); +extern void usbh_resume(void); +extern struct udev_t *usbh_find_device(char *hub_id, int port); + +/** + * @brief A function return current tick count. + * @return Current tick. + * @details User application must provide this function to return current tick. + * The tick should increase by 1 for every 10 ms. + */ +extern uint32_t usbh_get_ticks(void); /* This function must be provided by user application. */ +extern uint32_t usbh_tick_from_millisecond(uint32_t msec); /* This function must be provided by user application. */ + + +/// @cond HIDDEN_SYMBOLS + +extern void dump_ohci_regs(void); +extern void dump_ehci_regs(void); +extern void dump_ohci_ports(void); +extern void dump_ehci_ports(void); +extern uint32_t usbh_memory_used(void); + +/// @endcond HIDDEN_SYMBOLS + + +/*@}*/ /* end of group USBH_EXPORTED_FUNCTIONS */ + +/*@}*/ /* end of group USBH_Library */ + +/*@}*/ /* end of group LIBRARY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _USBH_LIB_H_ */ + +/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/ + + + diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ehci.c b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ehci.c new file mode 100644 index 0000000000000000000000000000000000000000..dbcda521967a5a00c58f0979605385df65896e51 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ehci.c @@ -0,0 +1,1288 @@ +/**************************************************************************//** + * @file ehci.c + * @version V1.10 + * $Revision: 11 $ + * $Date: 14/10/03 1:54p $ + * @brief USB Host library EHCI (USB 2.0) host controller driver. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include + +#include "usb.h" +#include "hub.h" + + +/// @cond HIDDEN_SYMBOLS + +static QH_T *_H_qh; /* head of reclamation list */ +static qTD_T *_ghost_qtd; /* used as a terminator qTD */ +static QH_T *qh_remove_list; + +extern ISO_EP_T *iso_ep_list; /* list of activated isochronous pipes */ +extern int ehci_iso_xfer(UTR_T *utr); /* EHCI isochronous transfer function */ +extern int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep); + +uint32_t _PFList_mem[FL_SIZE] __attribute__((aligned(4096)));/* Periodic frame list (Keil) */ + +uint32_t *_PFList; + + +QH_T *_Iqh[NUM_IQH]; + + +#ifdef ENABLE_ERROR_MSG +void dump_ehci_regs() +{ + USB_debug("Dump HSUSBH(EHCI) registers:\n"); + USB_debug(" UCMDR = 0x%x\n", _ehci->UCMDR); + USB_debug(" USTSR = 0x%x\n", _ehci->USTSR); + USB_debug(" UIENR = 0x%x\n", _ehci->UIENR); + USB_debug(" UFINDR = 0x%x\n", _ehci->UFINDR); + USB_debug(" UPFLBAR = 0x%x\n", _ehci->UPFLBAR); + USB_debug(" UCALAR = 0x%x\n", _ehci->UCALAR); + USB_debug(" UASSTR = 0x%x\n", _ehci->UASSTR); + USB_debug(" UCFGR = 0x%x\n", _ehci->UCFGR); + USB_debug(" UPSCR = 0x%x\n", _ehci->UPSCR[0]); + USB_debug(" PHYCTL0 = 0x%x\n", _ehci->USBPCR0); + USB_debug(" PHYCTL1 = 0x%x\n", _ehci->USBPCR1); +} + +void dump_ehci_ports() +{ + USB_debug("_ehci port0=0x%x, port1=0x%x\n", _ehci->UPSCR[0], _ehci->UPSCR[1]); +} + +void dump_ehci_qtd(qTD_T *qtd) +{ + USB_debug(" [qTD] - 0x%08x\n", (int)qtd); + USB_debug(" 0x%08x (Next qtd Pointer)\n", qtd->Next_qTD); + USB_debug(" 0x%08x (Alternate Next qtd Pointer)\n", qtd->Alt_Next_qTD); + USB_debug(" 0x%08x (qtd Token) PID: %s, Bytes: %d, IOC: %d\n", qtd->Token, (((qtd->Token >> 8) & 0x3) == 0) ? "OUT" : ((((qtd->Token >> 8) & 0x3) == 1) ? "IN" : "SETUP"), (qtd->Token >> 16) & 0x7FFF, (qtd->Token >> 15) & 0x1); + USB_debug(" 0x%08x (Buffer Pointer (page 0))\n", qtd->Bptr[0]); + //USB_debug(" 0x%08x (Buffer Pointer (page 1))\n", qtd->Bptr[1]); + //USB_debug(" 0x%08x (Buffer Pointer (page 2))\n", qtd->Bptr[2]); + //USB_debug(" 0x%08x (Buffer Pointer (page 3))\n", qtd->Bptr[3]); + //USB_debug(" 0x%08x (Buffer Pointer (page 4))\n", qtd->Bptr[4]); + USB_debug("\n"); +} + +void dump_ehci_asynclist(void) +{ + QH_T *qh = _H_qh; + qTD_T *qtd; + + USB_debug(">>> Dump EHCI Asynchronous List <<<\n"); + do + { + USB_debug("[QH] - 0x%08x\n", (int)qh); + USB_debug(" 0x%08x (Queue Head Horizontal Link Pointer, Queue Head DWord 0)\n", qh->HLink); + USB_debug(" 0x%08x (Endpoint Characteristics) DevAddr: %d, EP: 0x%x, PktSz: %d, Speed: %s\n", qh->Chrst, qh->Chrst & 0x7F, (qh->Chrst >> 8) & 0xF, (qh->Chrst >> 16) & 0x7FF, ((qh->Chrst >> 12) & 0x3 == 0) ? "Full" : (((qh->Chrst >> 12) & 0x3 == 1) ? "Low" : "High")); + USB_debug(" 0x%08x (Endpoint Capabilities: Queue Head DWord 2)\n", qh->Cap); + USB_debug(" 0x%08x (Current qtd Pointer)\n", qh->Curr_qTD); + USB_debug(" --- Overlay Area ---\n"); + USB_debug(" 0x%08x (Next qtd Pointer)\n", qh->OL_Next_qTD); + USB_debug(" 0x%08x (Alternate Next qtd Pointer)\n", qh->OL_Alt_Next_qTD); + USB_debug(" 0x%08x (qtd Token)\n", qh->OL_Token); + USB_debug(" 0x%08x (Buffer Pointer (page 0))\n", qh->OL_Bptr[0]); + USB_debug("\n"); + + qtd = QTD_PTR(qh->Curr_qTD); + while (qtd != NULL) + { + dump_ehci_qtd(qtd); + qtd = QTD_PTR(qtd->Next_qTD); + } + qh = QH_PTR(qh->HLink); + } + while (qh != _H_qh); +} + +void dump_ehci_asynclist_simple(void) +{ + QH_T *qh = _H_qh; + + USB_debug(">>> EHCI Asynchronous List <<<\n"); + USB_debug("[QH] => "); + do + { + USB_debug("0x%08x ", (int)qh); + qh = QH_PTR(qh->HLink); + } + while (qh != _H_qh); + USB_debug("\n"); +} + +void dump_ehci_period_frame_list_simple(void) +{ + QH_T *qh = _Iqh[NUM_IQH - 1]; + + USB_debug(">>> EHCI period frame list simple <<<\n"); + USB_debug("[FList] => "); + do + { + USB_debug("0x%08x ", (int)qh); + qh = QH_PTR(qh->HLink); + } + while (qh != NULL); + USB_debug("\n"); +} + +void dump_ehci_period_frame_list() +{ + int i; + QH_T *qh; + + for (i = 0; i < FL_SIZE; i++) + { + USB_debug("!%02d: ", i); + qh = QH_PTR(_PFList[i]);; + while (qh != NULL) + { + // USB_debug("0x%x (0x%x) => ", (int)qh, qh->HLink); + USB_debug("0x%x => ", (int)qh); + qh = QH_PTR(qh->HLink); + } + USB_debug("0\n"); + } +} + +#endif /* ENABLE_ERROR_MSG */ + +static void init_periodic_frame_list() +{ + QH_T *qh_p; + int i, idx, interval; + + _PFList = (uint32_t *)((uint32_t)_PFList_mem | NON_CACHE_MASK); + memset(_PFList, 0, sizeof(_PFList_mem)); + + iso_ep_list = NULL; + + for (i = NUM_IQH - 1; i >= 0; i--) /* interval = i^2 */ + { + _Iqh[i] = alloc_ehci_QH(); + + _Iqh[i]->HLink = QH_HLNK_END; + _Iqh[i]->Curr_qTD = (uint32_t)_ghost_qtd; + _Iqh[i]->OL_Next_qTD = QTD_LIST_END; + _Iqh[i]->OL_Alt_Next_qTD = (uint32_t)_ghost_qtd; + _Iqh[i]->OL_Token = QTD_STS_HALT; + + interval = 0x1 << i; + + for (idx = interval - 1; idx < FL_SIZE; idx += interval) + { + if (_PFList[idx] == 0) /* is empty list, insert directly */ + { + _PFList[idx] = QH_HLNK_QH(_Iqh[i]); + } + else + { + qh_p = QH_PTR(_PFList[idx]); + + while (1) + { + if (qh_p == _Iqh[i]) + break; /* already chained by previous visit */ + + if (qh_p->HLink == QH_HLNK_END) /* reach end of list? */ + { + qh_p->HLink = QH_HLNK_QH(_Iqh[i]); + break; + } + qh_p = QH_PTR(qh_p->HLink); + } + } + } + } +} + +static QH_T *get_int_tree_head_node(int interval) +{ + int i; + + interval /= 8; /* each frame list entry for 8 micro-frame */ + + for (i = 0; i < NUM_IQH - 1; i++) + { + interval >>= 1; + if (interval == 0) + return _Iqh[i]; + } + return _Iqh[NUM_IQH - 1]; +} + +static int make_int_s_mask(int bInterval) +{ + int order, interval; + + interval = 1; + while (bInterval > 1) + { + interval *= 2; + bInterval--; + } + + if (interval < 2) + return 0xFF; /* interval 1 */ + if (interval < 4) + return 0x55; /* interval 2 */ + if (interval < 8) + return 0x22; /* interval 4 */ + for (order = 0; (interval > 1); order++) + { + interval >>= 1; + } + return (0x1 << (order % 8)); +} + +static int ehci_init(void) +{ + int timeout = 250 * 1000; /* EHCI reset time-out 250 ms */ + + /*------------------------------------------------------------------------------------*/ + /* Reset EHCI host controller */ + /*------------------------------------------------------------------------------------*/ + _ehci->UCMDR = HSUSBH_UCMDR_HCRST_Msk; + while ((_ehci->UCMDR & HSUSBH_UCMDR_HCRST_Msk) && (timeout > 0)) + { + usbh_delay_ms(1); + timeout -= 1000; + } + if (_ehci->UCMDR & HSUSBH_UCMDR_HCRST_Msk) + return USBH_ERR_EHCI_INIT; + + _ehci->UCMDR = UCMDR_INT_THR_CTRL | HSUSBH_UCMDR_RUN_Msk; + + _ghost_qtd = alloc_ehci_qTD(NULL); + _ghost_qtd->Token = 0x11197B7F; //QTD_STS_HALT; visit_qtd() will not remove a qTD with this mark. It represents a qhost qTD. + + /*------------------------------------------------------------------------------------*/ + /* Initialize asynchronous list */ + /*------------------------------------------------------------------------------------*/ + qh_remove_list = NULL; + + /* Create the QH list head with H-bit 1 */ + _H_qh = alloc_ehci_QH(); + _H_qh->HLink = QH_HLNK_QH(_H_qh); /* circular link to itself, the only one QH */ + _H_qh->Chrst = QH_RCLM_LIST_HEAD; /* it's the head of reclamation list */ + _H_qh->Curr_qTD = (uint32_t)_ghost_qtd; + _H_qh->OL_Next_qTD = QTD_LIST_END; + _H_qh->OL_Alt_Next_qTD = (uint32_t)_ghost_qtd; + _H_qh->OL_Token = QTD_STS_HALT; + _ehci->UCALAR = (uint32_t)_H_qh; + + /*------------------------------------------------------------------------------------*/ + /* Initialize periodic list */ + /*------------------------------------------------------------------------------------*/ + if (FL_SIZE == 256) + _ehci->UCMDR |= (0x2 << HSUSBH_UCMDR_FLSZ_Pos); + else if (FL_SIZE == 512) + _ehci->UCMDR |= (0x1 << HSUSBH_UCMDR_FLSZ_Pos); + else if (FL_SIZE == 1024) + _ehci->UCMDR |= (0x0 << HSUSBH_UCMDR_FLSZ_Pos); + else + return USBH_ERR_EHCI_INIT; /* Invalid FL_SIZE setting! */ + + /*------------------------------------------------------------------------------------*/ + /* start run */ + /*------------------------------------------------------------------------------------*/ + + _ehci->UCFGR = 0x1; /* enable port routing to EHCI */ + _ehci->UIENR = HSUSBH_UIENR_USBIEN_Msk | HSUSBH_UIENR_UERRIEN_Msk | HSUSBH_UIENR_HSERREN_Msk | HSUSBH_UIENR_IAAEN_Msk; + + usbh_delay_ms(1); /* delay 1 ms */ + + _ehci->UPSCR[0] = HSUSBH_UPSCR_PP_Msk; /* enable port 1 port power */ + _ehci->UPSCR[1] = HSUSBH_UPSCR_PP_Msk; /* enable port 2 port power */ + + init_periodic_frame_list(); + + _ehci->UPFLBAR = (uint32_t)_PFList; + usbh_delay_ms(10); /* delay 10 ms */ + + return 0; +} + +static void ehci_suspend(void) +{ + if (_ehci->UPSCR[0] & 0x1) + _ehci->UPSCR[0] |= HSUSBH_UPSCR_SUSPEND_Msk; +} + +static void ehci_resume(void) +{ + if (_ehci->UPSCR[0] & 0x1) + _ehci->UPSCR[0] = (HSUSBH->UPSCR[0] & ~HSUSBH_UPSCR_SUSPEND_Msk) | HSUSBH_UPSCR_FPR_Msk; +} + +static void ehci_shutdown(void) +{ + ehci_suspend(); +} + +static void move_qh_to_remove_list(QH_T *qh) +{ + QH_T *q; + + // USB_debug("move_qh_to_remove_list - 0x%x (0x%x)\n", (int)qh, qh->Chrst); + + /* check if this ED found in ed_remove_list */ + q = qh_remove_list; + while (q) + { + if (q == qh) /* This QH found in qh_remove_list. */ + { + return; /* Do nothing, return... */ + } + q = q->next; + } + + DISABLE_EHCI_IRQ(); + + /*------------------------------------------------------------------------------------*/ + /* Search asynchronous frame list and remove qh if found in list. */ + /*------------------------------------------------------------------------------------*/ + q = _H_qh; /* find and remove it from asynchronous list */ + while (QH_PTR(q->HLink) != _H_qh) + { + if (QH_PTR(q->HLink) == qh) + { + /* q's next QH is qh, found... */ + q->HLink = qh->HLink; /* remove qh from list */ + + qh->next = qh_remove_list; /* add qh to qh_remove_list */ + qh_remove_list = qh; + _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA interrupt */ + ENABLE_EHCI_IRQ(); + return; /* done */ + } + q = QH_PTR(q->HLink); /* advance to next QH in asynchronous list */ + } + + /*------------------------------------------------------------------------------------*/ + /* Search periodic frame list and remove qh if found in list. */ + /*------------------------------------------------------------------------------------*/ + q = _Iqh[NUM_IQH - 1]; + while (q->HLink != QH_HLNK_END) + { + if (QH_PTR(q->HLink) == qh) + { + /* q's next QH is qh, found... */ + q->HLink = qh->HLink; /* remove qh from list */ + + qh->next = qh_remove_list; /* add qh to qh_remove_list */ + qh_remove_list = qh; + _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA interrupt */ + ENABLE_EHCI_IRQ(); + return; /* done */ + } + q = QH_PTR(q->HLink); /* advance to next QH in asynchronous list */ + } + ENABLE_EHCI_IRQ(); +} + +static void append_to_qtd_list_of_QH(QH_T *qh, qTD_T *qtd) +{ + qTD_T *q; + + if (qh->qtd_list == NULL) + { + qh->qtd_list = qtd; + } + else + { + q = qh->qtd_list; + while (q->next != NULL) + { + q = q->next; + } + q->next = qtd; + } +} + +/* + * If ep==NULL, it's a control endpoint QH. + */ +static void write_qh(UDEV_T *udev, EP_INFO_T *ep, QH_T *qh) +{ + uint32_t chrst, cap; + + /*------------------------------------------------------------------------------------*/ + /* Write QH DWord 1 - Endpoint Characteristics */ + /*------------------------------------------------------------------------------------*/ + if (ep == NULL) /* is control endpoint? */ + { + if (udev->descriptor.bMaxPacketSize0 == 0) + { + if (udev->speed == SPEED_LOW) /* give a default maximum packet size */ + udev->descriptor.bMaxPacketSize0 = 8; + else + udev->descriptor.bMaxPacketSize0 = 64; + } + chrst = QH_DTC | QH_NAK_RL | (udev->descriptor.bMaxPacketSize0 << 16); + if (udev->speed != SPEED_HIGH) + chrst |= QH_CTRL_EP_FLAG; /* non-high-speed control endpoint */ + } + else /* not a control endpoint */ + { + chrst = QH_NAK_RL | (ep->wMaxPacketSize << 16); + chrst |= ((ep->bEndpointAddress & 0xf) << 8); /* Endpoint Address */ + } + + if (udev->speed == SPEED_LOW) + chrst |= QH_EPS_LOW; + else if (udev->speed == SPEED_FULL) + chrst |= QH_EPS_FULL; + else + chrst |= QH_EPS_HIGH; + + chrst |= udev->dev_num; + + qh->Chrst = chrst; + + /*------------------------------------------------------------------------------------*/ + /* Write QH DWord 2 - Endpoint Capabilities */ + /*------------------------------------------------------------------------------------*/ + if (udev->speed == SPEED_HIGH) + { + cap = 0; + } + else + { + /* + * Backtrace device tree until the USB 2.0 hub found + */ + HUB_DEV_T *hub; + int port_num; + + port_num = udev->port_num; + hub = udev->parent; + + while ((hub != NULL) && (hub->iface->udev->speed != SPEED_HIGH)) + { + port_num = hub->iface->udev->port_num; + hub = hub->iface->udev->parent; + } + + cap = (port_num << QH_HUB_PORT_Pos) | + (hub->iface->udev->dev_num << QH_HUB_ADDR_Pos); + } + + qh->Cap = cap; +} + +static void write_qtd_bptr(qTD_T *qtd, uint32_t buff_addr, int xfer_len) +{ + int i; + + qtd->xfer_len = xfer_len; + qtd->Bptr[0] = buff_addr; + + buff_addr = (buff_addr + 0x1000) & ~0xFFF; + + for (i = 1; i < 5; i++) + { + qtd->Bptr[i] = buff_addr; + buff_addr += 0x1000; + } +} + +static int ehci_ctrl_xfer(UTR_T *utr) +{ + UDEV_T *udev; + QH_T *qh; + qTD_T *qtd_setup, *qtd_data, *qtd_status; + uint32_t token; + int is_new_qh = 0; + + udev = utr->udev; + + if (utr->data_len > 0) + { + if (((uint32_t)utr->buff + utr->data_len) > (((uint32_t)utr->buff & ~0xFFF) + 0x5000)) + return USBH_ERR_BUFF_OVERRUN; + } + + /*------------------------------------------------------------------------------------*/ + /* Allocate and link QH */ + /*------------------------------------------------------------------------------------*/ + if (udev->ep0.hw_pipe != NULL) + { + qh = (QH_T *)udev->ep0.hw_pipe; + if (qh->qtd_list) + return USBH_ERR_EHCI_QH_BUSY; + } + else + { + qh = alloc_ehci_QH(); + if (qh == NULL) + return USBH_ERR_MEMORY_OUT; + + udev->ep0.hw_pipe = (void *)qh; /* driver can find QH from EP */ + is_new_qh = 1; + } + write_qh(udev, NULL, qh); + utr->ep = &udev->ep0; /* driver can find EP from UTR */ + + /*------------------------------------------------------------------------------------*/ + /* Allocate qTDs */ + /*------------------------------------------------------------------------------------*/ + qtd_setup = alloc_ehci_qTD(utr); /* allocate qTD for SETUP */ + + if (utr->data_len > 0) + qtd_data = alloc_ehci_qTD(utr); /* allocate qTD for DATA */ + else + qtd_data = NULL; + + qtd_status = alloc_ehci_qTD(utr); /* allocate qTD for USTSR */ + + if (qtd_status == NULL) /* out of memory? */ + { + if (qtd_setup) + free_ehci_qTD(qtd_setup); /* free memory */ + if (qtd_data) + free_ehci_qTD(qtd_data); /* free memory */ + return USBH_ERR_MEMORY_OUT; /* out of memory */ + } + + //USB_debug("qh=0x%x, qtd_setup=0x%x, qtd_data=0x%x, qtd_status=0x%x\n", (int)qh, (int)qtd_setup, (int)qtd_data, (int)qtd_status); + + /*------------------------------------------------------------------------------------*/ + /* prepare SETUP stage qTD */ + /*------------------------------------------------------------------------------------*/ + qtd_setup->qh = qh; + //qtd_setup->utr = utr; + write_qtd_bptr(qtd_setup, (uint32_t)&utr->setup, 8); + append_to_qtd_list_of_QH(qh, qtd_setup); + qtd_setup->Token = (8 << 16) | QTD_ERR_COUNTER | QTD_PID_SETUP | QTD_STS_ACTIVE; + + /*------------------------------------------------------------------------------------*/ + /* prepare DATA stage qTD */ + /*------------------------------------------------------------------------------------*/ + if (utr->data_len > 0) + { + qtd_setup->Next_qTD = (uint32_t)qtd_data; + qtd_data->Next_qTD = (uint32_t)qtd_status; + + if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT) + token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE; + else + token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE; + + qtd_data->qh = qh; + //qtd_data->utr = utr; + write_qtd_bptr(qtd_data, (uint32_t)utr->buff, utr->data_len); + append_to_qtd_list_of_QH(qh, qtd_data); + qtd_data->Token = QTD_DT | (utr->data_len << 16) | token; + } + else + { + qtd_setup->Next_qTD = (uint32_t)qtd_status; + } + + /*------------------------------------------------------------------------------------*/ + /* prepare USTSR stage qTD */ + /*------------------------------------------------------------------------------------*/ + qtd_status->Next_qTD = (uint32_t)_ghost_qtd; + qtd_status->Alt_Next_qTD = QTD_LIST_END; + + if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT) + token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE; + else + token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE; + + qtd_status->qh = qh; + //qtd_status->utr = utr; + append_to_qtd_list_of_QH(qh, qtd_status); + qtd_status->Token = QTD_DT | QTD_IOC | token; + + /*------------------------------------------------------------------------------------*/ + /* Update QH overlay */ + /*------------------------------------------------------------------------------------*/ + qh->Curr_qTD = 0; + qh->OL_Next_qTD = (uint32_t)qtd_setup; + qh->OL_Alt_Next_qTD = QTD_LIST_END; + qh->OL_Token = 0; + + /*------------------------------------------------------------------------------------*/ + /* Link QH and start asynchronous transfer */ + /*------------------------------------------------------------------------------------*/ + if (is_new_qh) + { + qh->HLink = _H_qh->HLink; + _H_qh->HLink = QH_HLNK_QH(qh); + } + + /* Start transfer */ + _ehci->UCMDR |= HSUSBH_UCMDR_ASEN_Msk; /* start asynchronous transfer */ + return 0; +} + +static int ehci_bulk_xfer(UTR_T *utr) +{ + UDEV_T *udev; + EP_INFO_T *ep = utr->ep; + QH_T *qh; + qTD_T *qtd, *qtd_pre; + uint32_t data_len, xfer_len; + uint8_t *buff; + uint32_t token; + int is_new_qh = 0; + + //USB_debug("Bulk XFER =>\n"); + // dump_ehci_asynclist_simple(); + + udev = utr->udev; + + if (ep->hw_pipe != NULL) + { + qh = (QH_T *)ep->hw_pipe ; + if (qh->qtd_list) + { + return USBH_ERR_EHCI_QH_BUSY; + } + } + else + { + qh = alloc_ehci_QH(); + if (qh == NULL) + return USBH_ERR_MEMORY_OUT; + is_new_qh = 1; + write_qh(udev, ep, qh); + ep->hw_pipe = (void *)qh; /* associate QH with endpoint */ + } + + /*------------------------------------------------------------------------------------*/ + /* Prepare qTDs */ + /*------------------------------------------------------------------------------------*/ + data_len = utr->data_len; + buff = utr->buff; + qtd_pre = NULL; + + while (data_len > 0) + { + qtd = alloc_ehci_qTD(utr); + if (qtd == NULL) /* failed to allocate a qTD */ + { + qtd = qh->qtd_list; + while (qtd != NULL) + { + qtd_pre = qtd; + qtd = qtd->next; + free_ehci_qTD(qtd_pre); + } + if (is_new_qh) + { + free_ehci_QH(qh); + ep->hw_pipe = NULL; + } + return USBH_ERR_MEMORY_OUT; + } + + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT) + token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE; + else + token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE; + + if (data_len > 0x4000) /* force maximum x'fer length 16K per qTD */ + xfer_len = 0x4000; + else + xfer_len = data_len; /* remaining data length < 4K */ + + qtd->qh = qh; + qtd->Next_qTD = (uint32_t)_ghost_qtd; + qtd->Alt_Next_qTD = QTD_LIST_END; //(uint32_t)_ghost_qtd; + write_qtd_bptr(qtd, (uint32_t)buff, xfer_len); + append_to_qtd_list_of_QH(qh, qtd); + qtd->Token = (xfer_len << 16) | token; + + buff += xfer_len; /* advanced buffer pointer */ + data_len -= xfer_len; + + if (data_len == 0) /* is this the latest qTD? */ + { + qtd->Token |= QTD_IOC; /* ask to raise an interrupt on the last qTD */ + qtd->Next_qTD = (uint32_t)_ghost_qtd; /* qTD list end */ + } + + if (qtd_pre != NULL) + qtd_pre->Next_qTD = (uint32_t)qtd; + qtd_pre = qtd; + } + + //USB_debug("utr=0x%x, qh=0x%x, qtd=0x%x\n", (int)utr, (int)qh, (int)qh->qtd_list); + + qtd = qh->qtd_list; + + qh->OL_Next_qTD = (uint32_t)qtd; + + /*------------------------------------------------------------------------------------*/ + /* Link QH and start asynchronous transfer */ + /*------------------------------------------------------------------------------------*/ + if (is_new_qh) + { + memcpy(&(qh->OL_Bptr[0]), &(qtd->Bptr[0]), 20); + qh->Curr_qTD = (uint32_t)qtd; + + qh->OL_Token = 0; //qtd->Token; + + if (utr->ep->bToggle) + qh->OL_Token |= QTD_DT; + + qh->HLink = _H_qh->HLink; + _H_qh->HLink = QH_HLNK_QH(qh); + } + + /* Start transfer */ + _ehci->UCMDR |= HSUSBH_UCMDR_ASEN_Msk; /* start asynchronous transfer */ + + return 0; +} + +static int ehci_int_xfer(UTR_T *utr) +{ + UDEV_T *udev = utr->udev; + EP_INFO_T *ep = utr->ep; + QH_T *qh, *iqh; + qTD_T *qtd; + uint32_t token; + int8_t is_new_qh = 0; + + if (ep->hw_pipe != NULL) + { + qh = (QH_T *)ep->hw_pipe ; + if (qh->qtd_list) + return USBH_ERR_EHCI_QH_BUSY; + } + else + { + qh = alloc_ehci_QH(); + if (qh == NULL) + return USBH_ERR_MEMORY_OUT; + is_new_qh = 1; + write_qh(udev, ep, qh); + qh->Chrst &= ~0xF0000000; + + if (udev->speed == SPEED_HIGH) + { + qh->Cap = (0x1 << QH_MULT_Pos) | (qh->Cap & 0xff) | make_int_s_mask(ep->bInterval); + } + else + { + qh->Cap = (0x1 << QH_MULT_Pos) | (qh->Cap & ~(QH_C_MASK_Msk | QH_S_MASK_Msk)) | 0x7802; + } + ep->hw_pipe = (void *)qh; /* associate QH with endpoint */ + } + + /*------------------------------------------------------------------------------------*/ + /* Prepare qTD */ + /*------------------------------------------------------------------------------------*/ + qtd = alloc_ehci_qTD(utr); + if (qtd == NULL) /* failed to allocate a qTD */ + { + if (is_new_qh) + { + free_ehci_QH(qh); + ep->hw_pipe = NULL; + } + return USBH_ERR_MEMORY_OUT; + } + + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT) + token = QTD_ERR_COUNTER | QTD_PID_OUT | QTD_STS_ACTIVE; + else + token = QTD_ERR_COUNTER | QTD_PID_IN | QTD_STS_ACTIVE; + + qtd->qh = qh; + qtd->Next_qTD = QTD_LIST_END; //(uint32_t)_ghost_qtd; + qtd->Alt_Next_qTD = QTD_LIST_END; //(uint32_t)_ghost_qtd; + write_qtd_bptr(qtd, (uint32_t)utr->buff, utr->data_len); + append_to_qtd_list_of_QH(qh, qtd); + qtd->Token = QTD_IOC | (utr->data_len << 16) | token; + + DISABLE_EHCI_IRQ(); + + USB_debug("ehci_int_xfer - qh: 0x%x, 0x%x, 0x%x, qtd: 0x%x\n", (int)qh, (int)qh->Chrst, (int)qh->Cap, (int)qtd); + + qh->OL_Next_qTD = (uint32_t)qtd; + + if (is_new_qh) + { + memcpy(&(qh->OL_Bptr[0]), &(qtd->Bptr[0]), 20); + qh->Curr_qTD = (uint32_t)qtd; + qh->OL_Token = qtd->Token; + + if (udev->speed == SPEED_HIGH) /* get head node of this interval */ + iqh = get_int_tree_head_node(ep->bInterval); + else + iqh = get_int_tree_head_node(ep->bInterval * 8); + qh->HLink = iqh->HLink; /* Add to list of the same interval */ + iqh->HLink = QH_HLNK_QH(qh); + } + + ENABLE_EHCI_IRQ(); + + _ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */ + return 0; +} + +/* + * Quit current trasnfer via UTR or hardware EP. + */ +static int ehci_quit_xfer(UTR_T *utr, EP_INFO_T *ep) +{ + QH_T *qh; + + // USB_debug("ehci_quit_xfer - utr: 0x%x, ep: 0x%x\n", (int)utr, (int)ep); + + DISABLE_EHCI_IRQ(); + if (ehci_quit_iso_xfer(utr, ep) == 0) + { + ENABLE_EHCI_IRQ(); + return 0; + } + ENABLE_EHCI_IRQ(); + + if (utr != NULL) + { + if (utr->ep == NULL) + return USBH_ERR_NOT_FOUND; + + qh = (QH_T *)(utr->ep->hw_pipe); + + if (!qh) + return USBH_ERR_NOT_FOUND; + + /* add the QH to remove list, it will be removed on the next IAAD interrupt */ + move_qh_to_remove_list(qh); + utr->ep->hw_pipe = NULL; + } + + if ((ep != NULL) && (ep->hw_pipe != NULL)) + { + qh = (QH_T *)(ep->hw_pipe); + /* add the QH to remove list, it will be removed on the next IAAD interrupt */ + move_qh_to_remove_list(qh); + ep->hw_pipe = NULL; + } + usbh_delay_ms(2); + + return 0; +} + +static int visit_qtd(qTD_T *qtd) +{ + if ((qtd->Token == 0x11197B7F) || (qtd->Token == 0x1197B7F)) + return 0; /* A Dummy qTD or qTD on writing, don't touch it. */ + + // USB_debug("Visit qtd 0x%x - 0x%x\n", (int)qtd, qtd->Token); + + if ((qtd->Token & QTD_STS_ACTIVE) == 0) + { + if (qtd->Token & (QTD_STS_HALT | QTD_STS_DATA_BUFF_ERR | QTD_STS_BABBLE | QTD_STS_XactErr | QTD_STS_MISS_MF)) + { + USB_error("qTD 0x%x error token=0x%x! 0x%x\n", (int)qtd, qtd->Token, qtd->Bptr[0]); + if (qtd->utr->status == 0) + qtd->utr->status = USBH_ERR_TRANSACTION; + } + else + { + if ((qtd->Token & QTD_PID_Msk) != QTD_PID_SETUP) + { + qtd->utr->xfer_len += qtd->xfer_len - QTD_TODO_LEN(qtd->Token); + // USB_debug("0x%x utr->xfer_len += %d\n", qtd->Token, qtd->xfer_len - QTD_TODO_LEN(qtd->Token)); + } + } + return 1; + } + return 0; +} + +static void scan_asynchronous_list() +{ + QH_T *qh, *qh_tmp; + qTD_T *q_pre, *qtd, *qtd_tmp; + UTR_T *utr; + + qh = QH_PTR(_H_qh->HLink); + while (qh != _H_qh) + { + // USB_debug("Scan qh=0x%x, 0x%x\n", (int)qh, qh->OL_Token); + + utr = NULL; + qtd = qh->qtd_list; + while (qtd != NULL) + { + if (visit_qtd(qtd)) /* if TRUE, reclaim this qtd */ + { + /* qTD is completed, will remove it */ + utr = qtd->utr; + if (qtd == qh->qtd_list) + qh->qtd_list = qtd->next; /* unlink the qTD from qtd_list */ + else + q_pre->next = qtd->next; /* unlink the qTD from qtd_list */ + + qtd_tmp = qtd; /* remember this qTD for freeing later */ + qtd = qtd->next; /* advance to the next qTD */ + + qtd_tmp->next = qh->done_list; /* push this qTD to QH's done list */ + qh->done_list = qtd_tmp; + } + else + { + q_pre = qtd; /* remember this qTD as a preceder */ + qtd = qtd->next; /* advance to next qTD */ + } + } + + qh_tmp = qh; + qh = QH_PTR(qh->HLink); /* advance to the next QH */ + + /* If all TDs are done, call-back to requester and then remove this QH. */ + if ((qh_tmp->qtd_list == NULL) && utr) + { + // printf("T %d [%d]\n", (qh_tmp->Chrst>>8)&0xf, (qh_tmp->OL_Token&QTD_DT) ? 1 : 0); + if (qh_tmp->OL_Token & QTD_DT) + utr->ep->bToggle = 1; + else + utr->ep->bToggle = 0; + + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + + _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA to reclaim done_list */ + } + } +} + +static void scan_periodic_frame_list() +{ + QH_T *qh; + qTD_T *qtd; + UTR_T *utr; + + /*------------------------------------------------------------------------------------*/ + /* Scan interrupt frame list */ + /*------------------------------------------------------------------------------------*/ + qh = _Iqh[NUM_IQH - 1]; + while (qh != NULL) + { + qtd = qh->qtd_list; /* There's only one qTD in list at most. */ + + if (qtd == NULL) + { + /* empty QH */ + qh = QH_PTR(qh->HLink); /* advance to the next QH */ + continue; + } + + if (visit_qtd(qtd)) /* if TRUE, reclaim this qtd */ + { + qtd->next = qh->done_list; /* push qTD into the done list */ + qh->done_list = qtd; + qh->qtd_list = NULL; /* qtd_list becomes empty */ + } + + qtd = qh->done_list; + + /* If all TDs are done, call-back to requester and then remove this QH. */ + if ((qtd != NULL) && (qh->qtd_list == NULL)) + { + utr = qtd->utr; + + if (qh->OL_Token & QTD_DT) + utr->ep->bToggle = 1; + else + utr->ep->bToggle = 0; + + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + + _ehci->UCMDR |= HSUSBH_UCMDR_IAAD_Msk; /* trigger IAA to reclaim done_list */ + } + + qh = QH_PTR(qh->HLink); /* advance to the next QH */ + } + + /*------------------------------------------------------------------------------------*/ + /* Scan isochronous frame list */ + /*------------------------------------------------------------------------------------*/ + + scan_isochronous_list(); +} + +void iaad_remove_qh() +{ + QH_T *qh; + qTD_T *qtd; + UTR_T *utr; + + /*------------------------------------------------------------------------------------*/ + /* Remove all QHs in qh_remove_list... */ + /*------------------------------------------------------------------------------------*/ + while (qh_remove_list != NULL) + { + qh = qh_remove_list; + qh_remove_list = qh->next; + + // USB_debug("iaad_remove_qh - remove QH 0x%x\n", (int)qh); + + while (qh->done_list) /* we can free the qTDs now */ + { + qtd = qh->done_list; + qh->done_list = qtd->next; + free_ehci_qTD(qtd); + } + + if (qh->qtd_list != NULL) /* still have incomplete qTDs? */ + { + utr = qh->qtd_list->utr; + while (qh->qtd_list) + { + qtd = qh->qtd_list; + qh->qtd_list = qtd->next; + free_ehci_qTD(qtd); + } + utr->status = USBH_ERR_ABORT; + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); /* call back */ + } + free_ehci_QH(qh); /* free the QH */ + } + + /*------------------------------------------------------------------------------------*/ + /* Free all qTD in done_list of each asynchronous QH */ + /*------------------------------------------------------------------------------------*/ + qh = QH_PTR(_H_qh->HLink); + while (qh != _H_qh) + { + while (qh->done_list) /* we can free the qTDs now */ + { + qtd = qh->done_list; + qh->done_list = qtd->next; + free_ehci_qTD(qtd); + } + qh = QH_PTR(qh->HLink); /* advance to the next QH */ + } + + /*------------------------------------------------------------------------------------*/ + /* Free all qTD in done_list of each QH of periodic frame list */ + /*------------------------------------------------------------------------------------*/ + qh = _Iqh[NUM_IQH - 1]; + while (qh != NULL) + { + while (qh->done_list) /* we can free the qTDs now */ + { + qtd = qh->done_list; + qh->done_list = qtd->next; + free_ehci_qTD(qtd); + } + qh = QH_PTR(qh->HLink); /* advance to the next QH */ + } +} + +//void EHCI_IRQHandler(void) +void nu_ehci_isr(int vector, void *param) +{ + uint32_t intsts; + + intsts = _ehci->USTSR; + _ehci->USTSR = intsts; /* clear interrupt status */ + + //USB_debug("ehci int_sts = 0x%x\n", intsts); + + if (intsts & HSUSBH_USTSR_UERRINT_Msk) + { + USB_error("Transfer error!\n"); + } + + if (intsts & HSUSBH_USTSR_USBINT_Msk) + { + /* some transfers completed, travel asynchronous */ + /* and periodic lists to find and reclaim them. */ + scan_asynchronous_list(); + + scan_periodic_frame_list(); + } + + if (intsts & HSUSBH_USTSR_IAA_Msk) + { + iaad_remove_qh(); + } +} + +static UDEV_T *ehci_find_device_by_port(int port) +{ + UDEV_T *udev; + + udev = g_udev_list; + while (udev != NULL) + { + if ((udev->parent == NULL) && (udev->port_num == port) && (udev->speed == SPEED_HIGH)) + return udev; + udev = udev->next; + } + return NULL; +} + +static int ehci_rh_port_reset(int port) +{ + int retry; + int reset_time; + uint32_t t0; + + reset_time = usbh_tick_from_millisecond(PORT_RESET_TIME_MS); + + for (retry = 0; retry < PORT_RESET_RETRY; retry++) + { + _ehci->UPSCR[port] = (_ehci->UPSCR[port] | HSUSBH_UPSCR_PRST_Msk) & ~HSUSBH_UPSCR_PE_Msk; + + t0 = usbh_get_ticks(); + while (usbh_get_ticks() - t0 < (reset_time) + 1) ; /* wait at least 50 ms */ + + _ehci->UPSCR[port] &= ~HSUSBH_UPSCR_PRST_Msk; + + t0 = usbh_get_ticks(); + while (usbh_get_ticks() - t0 < (reset_time) + 1) + { + if (!(_ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk) || + ((_ehci->UPSCR[port] & (HSUSBH_UPSCR_CCS_Msk | HSUSBH_UPSCR_PE_Msk)) == (HSUSBH_UPSCR_CCS_Msk | HSUSBH_UPSCR_PE_Msk))) + goto port_reset_done; + } + reset_time += PORT_RESET_RETRY_INC_MS; + } + + USB_debug("EHCI port %d - port reset failed!\n", port + 1); + return USBH_ERR_PORT_RESET; + +port_reset_done: + if ((_ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk) == 0) /* check again if device disconnected */ + { + _ehci->UPSCR[port] |= HSUSBH_UPSCR_CSC_Msk; /* clear CSC */ + return USBH_ERR_DISCONNECTED; + } + _ehci->UPSCR[port] |= HSUSBH_UPSCR_PEC_Msk; /* clear port enable change status */ + return USBH_OK; /* port reset success */ +} + +static int ehci_rh_polling(void) +{ + UDEV_T *udev; + int ret, change = 0; + int port; + int connect_status, t0, debounce_tick; + + for (port = 0; port < EHCI_PORT_CNT; port++) + { + if (!(_ehci->UPSCR[port] & HSUSBH_UPSCR_CSC_Msk)) + continue; + + change = 1; + USB_debug("EHCI port%d status change: 0x%x\n", port + 1, _ehci->UPSCR[port]); + + /*--------------------------------------------------------------------------------*/ + /* Disconnect the devices attached to this port. */ + /*--------------------------------------------------------------------------------*/ + while (1) + { + udev = ehci_find_device_by_port(port + 1); + if (udev == NULL) + break; + usbh_disconnect_device(udev); + } + + /*--------------------------------------------------------------------------------*/ + /* Port de-bounce */ + /*--------------------------------------------------------------------------------*/ + t0 = usbh_get_ticks(); + debounce_tick = usbh_tick_from_millisecond(HUB_DEBOUNCE_TIME); + connect_status = _ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk; + while (usbh_get_ticks() - t0 < debounce_tick) + { + if (connect_status != (_ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk)) + { + /* reset stable time counting */ + t0 = usbh_get_ticks(); + connect_status = _ehci->UPSCR[port] & HSUSBH_UPSCR_CCS_Msk; + } + } + + _ehci->UPSCR[port] |= HSUSBH_UPSCR_CSC_Msk; /* clear connect status change bit */ + + if (connect_status == HSUSBH_UPSCR_CCS_Msk) + { + /*----------------------------------------------------------------------------*/ + /* A new device connected. */ + /*----------------------------------------------------------------------------*/ + if (ehci_rh_port_reset(port) != USBH_OK) + { + /* port reset failed, maybe an USB 1.1 device */ + _ehci->UPSCR[port] |= HSUSBH_UPSCR_PO_Msk; /* change port owner to OHCI */ + _ehci->UPSCR[port] |= HSUSBH_UPSCR_CSC_Msk; /* clear all status change bits */ + return 0; + } + + /* + * Port reset success. Start to enumerate this new device. + */ + udev = alloc_device(); + if (udev == NULL) + return 0; /* out-of-memory, do nothing... */ + + udev->parent = NULL; + udev->port_num = port + 1; + udev->speed = SPEED_HIGH; + udev->hc_driver = &ehci_driver; + + ret = usbh_connect_device(udev); + if (ret < 0) + { + USB_error("connect_device error! [%d]\n", ret); + free_device(udev); + } + } + else + { + /* Device disconnected */ + while (1) + { + udev = ehci_find_device_by_port(port + 1); + if (udev == NULL) + break; + usbh_disconnect_device(udev); + } + } + } + return change; +} + + +HC_DRV_T ehci_driver = +{ + ehci_init, /* init */ + ehci_shutdown, /* shutdown */ + ehci_suspend, /* suspend */ + ehci_resume, /* resume */ + ehci_ctrl_xfer, /* ctrl_xfer */ + ehci_bulk_xfer, /* bulk_xfer */ + ehci_int_xfer, /* int_xfer */ + ehci_iso_xfer, /* iso_xfer */ + ehci_quit_xfer, /* quit_xfer */ + ehci_rh_port_reset, /* rthub_port_reset */ + ehci_rh_polling /* rthub_polling */ +}; + + +/// @endcond HIDDEN_SYMBOLS + +/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ehci_iso.c b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ehci_iso.c new file mode 100644 index 0000000000000000000000000000000000000000..3ba835d4d8e7c7abc1f94756b649b28e90a57f35 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ehci_iso.c @@ -0,0 +1,918 @@ +/**************************************************************************//** + * @file ehci_iso.c + * @version V1.10 + * $Revision: 11 $ + * $Date: 14/10/03 1:54p $ + * @brief USB EHCI isochornous transfer driver. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include + +#include "N9H30.h" + +#include "usb.h" +#include "hub.h" + + +/// @cond HIDDEN_SYMBOLS + +uint32_t g_flr_cnt; /* frame list rollover counter */ + +ISO_EP_T *iso_ep_list; /* list of activated isochronous pipes */ + +extern uint32_t *_PFList; /* Periodic frame list */ + +static const uint16_t sitd_OUT_Smask [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f }; + +static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep); + +/* + * Inspect the iTD can be reclaimed or not. If yes, collect the transaction results. + * Return: 1 - reclaimed + * 0 - not completed + */ +static int review_itd(iTD_T *itd) +{ + UTR_T *utr; + uint32_t frnidx = itd->sched_frnidx; + uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF; + int i, fidx; + + // printf("R - %d %d, 0x%x\n", now_frame, frnidx, itd->Transaction[0]); + + if (now_frame == frnidx) + { + for (i = 0; i < 8; i++) + { + if (itd->Transaction[i] & ITD_STATUS_ACTIVE) + return 0; /* have any not completed frames */ + } + } + else if (now_frame > frnidx) + { + if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE) + return 0; /* don't touch it */ + } + else + { + if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE) + return 0; /* don't touch it */ + } + + /* + * Reclaim this iTD + */ + utr = itd->utr; + fidx = itd->fidx; + for (i = 0; i < 8; i++) + { + if (!(itd->trans_mask & (0x1 << i))) + continue; /* not scheduled micro-frame */ + + if (ITD_STATUS(itd->Transaction[i])) + { + if (itd->Transaction[i] & ITD_STATUS_ACTIVE) + { + utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0; + utr->status = USBH_ERR_NOT_ACCESS0; + } + else if (itd->Transaction[i] & ITD_STATUS_BABBLE) + { + utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED; + utr->status = USBH_ERR_TRANSFER; + } + else if (itd->Transaction[i] & ITD_STATUS_BUFF_ERR) + { + utr->iso_status[fidx] = USBH_ERR_DATA_BUFF; + utr->status = USBH_ERR_TRANSFER; + } + else + { + utr->iso_status[fidx] = USBH_ERR_TRANSACTION; + utr->status = USBH_ERR_TRANSFER; + } + } + else + { + utr->iso_status[fidx] = 0; + utr->iso_xlen[fidx] = ITD_XFER_LEN(itd->Transaction[i]); + } + fidx++; + } + utr->td_cnt--; + + if (utr->td_cnt == 0) /* All iTD of this UTR done */ + { + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + } + + return 1; /* to be reclaimed */ +} + +/* + * Inspect the siTD can be reclaimed or not. If yes, collect the transaction results. + * Return: 1 - reclaimed + * 0 - not completed + */ +static int review_sitd(siTD_T *sitd) +{ + UTR_T *utr; + uint32_t frnidx = sitd->sched_frnidx; + uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF; + int fidx; + uint32_t TotalBytesToTransfer; + + if (now_frame == frnidx) + { + if (SITD_STATUS(sitd->StsCtrl) == SITD_STATUS_ACTIVE) + return 0; + } + else if (now_frame > frnidx) + { + if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE) + return 0; /* don't touch it */ + } + else + { + if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE) + return 0; /* don't touch it */ + } + + /* + * Reclaim this siTD + */ + utr = sitd->utr; + fidx = sitd->fidx; + + if (SITD_STATUS(sitd->StsCtrl)) + { + if (sitd->StsCtrl & SITD_STATUS_ACTIVE) + { + utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0; + } + else if (sitd->StsCtrl & SITD_BABBLE_DETECTED) + { + utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED; + utr->status = USBH_ERR_TRANSFER; + } + else if (sitd->StsCtrl & SITD_STATUS_BUFF_ERR) + { + utr->iso_status[fidx] = USBH_ERR_DATA_BUFF; + utr->status = USBH_ERR_TRANSFER; + } + else + { + utr->iso_status[fidx] = USBH_ERR_TRANSACTION; + utr->status = USBH_ERR_TRANSFER; + } + } + else + { + TotalBytesToTransfer = (sitd->StsCtrl & SITD_XFER_CNT_Msk) >> SITD_XFER_CNT_Pos; + utr->iso_xlen[fidx] = utr->iso_xlen[fidx] - TotalBytesToTransfer; + utr->iso_status[fidx] = 0; + } + utr->td_cnt--; + + if (utr->td_cnt == 0) /* All iTD of this UTR done */ + { + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + } + return 1; /* to be reclaimed */ +} + +/* + * Some iTD/siTD may be scheduled but not serviced due to time missed. + * This function scan several earlier frames and drop unserviced iTD/siTD if found. + */ +void scan_isochronous_list(void) +{ + ISO_EP_T *iso_ep = iso_ep_list; + iTD_T *itd, *itd_pre, *p; + siTD_T *sitd, *sitd_pre, *sp; + uint32_t frnidx; + + DISABLE_EHCI_IRQ(); + + while (iso_ep != NULL) /* Search all activated iso endpoints */ + { + /*--------------------------------------------------------------------------------*/ + /* Scan all iTDs */ + /*--------------------------------------------------------------------------------*/ + itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */ + itd_pre = NULL; + while (itd != NULL) /* traverse all iTDs of itd list */ + { + if (review_itd(itd)) /* inspect and reclaim iTD */ + { + /*------------------------------------------------------------------------*/ + /* Remove this iTD from period frame list */ + /*------------------------------------------------------------------------*/ + frnidx = itd->sched_frnidx; + if (_PFList[frnidx] == ITD_HLNK_ITD(itd)) + { + /* is the first entry, just change to next */ + _PFList[frnidx] = itd->Next_Link; + } + else + { + p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */ + while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL)) + { + p = ITD_PTR(p->Next_Link); + } + + if (p == NULL) /* link list out of control! */ + { + USB_error("An iTD lost refernece to periodic frame list! 0x%x -> %d\n", (int)itd, frnidx); + } + else /* remove iTD from list */ + { + p->Next_Link = itd->Next_Link; + } + } + + /*------------------------------------------------------------------------*/ + /* Remove this iTD from iso_ep's iTD list */ + /*------------------------------------------------------------------------*/ + if (itd_pre == NULL) + { + iso_ep->itd_list = itd->next; + } + else + { + itd_pre->next = itd->next; + } + p = itd->next; + free_ehci_iTD(itd); + itd = p; + } + else + { + itd_pre = itd; + itd = itd->next; /* traverse to the next iTD of iTD list */ + } + } + + /*--------------------------------------------------------------------------------*/ + /* Scan all siTDs */ + /*--------------------------------------------------------------------------------*/ + sitd = iso_ep->sitd_list; /* get the first siTD from iso_ep's siTD list */ + sitd_pre = NULL; + while (sitd != NULL) /* traverse all siTDs of sitd list */ + { + if (review_sitd(sitd)) /* inspect and reclaim siTD */ + { + /*------------------------------------------------------------------------*/ + /* Remove this siTD from period frame list */ + /*------------------------------------------------------------------------*/ + frnidx = sitd->sched_frnidx; + if (_PFList[frnidx] == SITD_HLNK_SITD(sitd)) + { + /* is the first entry, just change to next */ + _PFList[frnidx] = sitd->Next_Link; + } + else + { + sp = SITD_PTR(_PFList[frnidx]); /* find the preceding siTD */ + while ((SITD_PTR(sp->Next_Link) != sitd) && (sp != NULL)) + { + sp = SITD_PTR(sp->Next_Link); + } + + if (sp == NULL) /* link list out of control! */ + { + USB_error("An siTD lost reference to periodic frame list! 0x%x -> %d\n", (int)sitd, frnidx); + } + else /* remove iTD from list */ + { + sp->Next_Link = sitd->Next_Link; + } + } + + /*------------------------------------------------------------------------*/ + /* Remove this siTD from iso_ep's siTD list */ + /*------------------------------------------------------------------------*/ + if (sitd_pre == NULL) + { + iso_ep->sitd_list = sitd->next; + } + else + { + sitd_pre->next = sitd->next; + } + sp = sitd->next; + free_ehci_siTD(sitd); + sitd = sp; + } + else + { + sitd_pre = sitd; + sitd = sitd->next; /* traverse to the next siTD of siTD list */ + } + } + + iso_ep = iso_ep->next; + } + + ENABLE_EHCI_IRQ(); +} + + +static void write_itd_info(UTR_T *utr, iTD_T *itd) +{ + UDEV_T *udev = utr->udev; + EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */ + uint32_t buff_page_addr; + int i; + + buff_page_addr = itd->buff_base & 0xFFFFF000; /* 4K page */ + + for (i = 0; i < 7; i++) + { + itd->Bptr[i] = buff_page_addr + (0x1000 * i); + } + /* EndPtr R Device Address */ + itd->Bptr[0] |= (udev->dev_num) | ((ep->bEndpointAddress & 0xF) << ITD_EP_NUM_Pos); + itd->Bptr[1] |= ep->wMaxPacketSize; /* Maximum Packet Size */ + + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */ + itd->Bptr[1] |= ITD_DIR_IN; + else + itd->Bptr[1] |= ITD_DIR_OUT; + + itd->Bptr[2] |= (ep->wMaxPacketSize + 1023) / 1024; /* Mult */ +} + +static void write_itd_micro_frame(UTR_T *utr, int fidx, iTD_T *itd, int mf) +{ + uint32_t buff_addr; + + buff_addr = (uint32_t)(utr->iso_buff[fidx]); /* xfer buffer start address of this frame */ + + itd->Transaction[mf] = ITD_STATUS_ACTIVE | /* Status */ + ((utr->iso_xlen[fidx] & 0xFFF) << ITD_XLEN_Pos) | /* Transaction Length */ + ((buff_addr & 0xFFFFF000) - (itd->buff_base & 0xFFFFF000)) | /* PG */ + (buff_addr & 0xFFF); /* Transaction offset */ +} + + +static void remove_iso_ep_from_list(ISO_EP_T *iso_ep) +{ + ISO_EP_T *p; + + if (iso_ep_list == iso_ep) + { + iso_ep_list = iso_ep->next; /* it's the first entry, remove it */ + return; + } + + p = iso_ep_list; /* find the previous entry of iso_ep */ + while (p->next != NULL) + { + if (p->next == iso_ep) + { + break; + } + p = p->next; + } + + if (p->next == NULL) + { + return; /* not found */ + } + p->next = iso_ep->next; /* remove iso_ep from list */ +} + + +static __inline void add_itd_to_iso_ep(ISO_EP_T *iso_ep, iTD_T *itd) +{ + iTD_T *p; + + itd->next = NULL; + + if (iso_ep->itd_list == NULL) + { + iso_ep->itd_list = itd; + return; + } + + /* + * Find the tail entry of iso_ep->itd_list + */ + p = iso_ep->itd_list; + while (p->next != NULL) + { + p = p->next; + } + p->next = itd; +} + +int ehci_iso_xfer(UTR_T *utr) +{ + EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */ + ISO_EP_T *iso_ep; /* software iso endpoint descriptor */ + iTD_T *itd, *itd_next, *itd_list = NULL; + int i, itd_cnt; + int trans_mask; /* bit mask of used xfer in an iTD */ + int fidx; /* index to the 8 iso frames of UTR */ + int interval; /* frame interval of iTD */ + + if (ep->hw_pipe != NULL) + { + iso_ep = (ISO_EP_T *)ep->hw_pipe; /* get reference of the isochronous endpoint */ + + if (utr->bIsoNewSched) + iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF; + } + else + { + /* first time transfer of this iso endpoint */ + iso_ep = usbh_alloc_mem(sizeof(*iso_ep)); + if (iso_ep == NULL) + return USBH_ERR_MEMORY_OUT; + + memset(iso_ep, 0, sizeof(*iso_ep)); + iso_ep->ep = ep; + iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF; + + ep->hw_pipe = iso_ep; + + /* + * Add this iso_ep into iso_ep_list + */ + DISABLE_EHCI_IRQ(); + iso_ep->next = iso_ep_list; + iso_ep_list = iso_ep; + ENABLE_EHCI_IRQ(); + } + + if (utr->udev->speed == SPEED_FULL) + return ehci_iso_split_xfer(utr, iso_ep); + + /*------------------------------------------------------------------------------------*/ + /* Allocate iTDs */ + /*------------------------------------------------------------------------------------*/ + + if (ep->bInterval < 2) /* transfer interval is 1 micro-frame */ + { + trans_mask = 0xFF; + itd_cnt = 1; /* required 1 iTD for one UTR */ + interval = 1; /* iTD frame interval of this endpoint */ + } + else if (ep->bInterval < 4) /* transfer interval is 2 micro-frames */ + { + trans_mask = 0x55; + itd_cnt = 2; /* required 2 iTDs for one UTR */ + interval = 1; /* iTD frame interval of this endpoint */ + } + else if (ep->bInterval < 8) /* transfer interval is 4 micro-frames */ + { + trans_mask = 0x44; + itd_cnt = 4; /* required 4 iTDs for one UTR */ + interval = 1; /* iTD frame interval of this endpoint */ + } + else if (ep->bInterval < 16) /* transfer interval is 8 micro-frames */ + { + trans_mask = 0x08; /* there's 1 transfer in one iTD */ + itd_cnt = 8; /* required 8 iTDs for one UTR */ + interval = 1; /* iTD frame interval of this endpoint */ + } + else if (ep->bInterval < 32) /* transfer interval is 16 micro-frames */ + { + trans_mask = 0x10; /* there's 1 transfer in one iTD */ + itd_cnt = 8; /* required 8 iTDs for one UTR */ + interval = 2; /* iTD frame interval of this endpoint */ + } + else if (ep->bInterval < 64) /* transfer interval is 32 micro-frames */ + { + trans_mask = 0x02; /* there's 1 transfer in one iTD */ + itd_cnt = 8; /* required 8 iTDs for one UTR */ + interval = 4; /* iTD frame interval of this endpoint */ + } + else /* transfer interval is 64 micro-frames */ + { + trans_mask = 0x04; /* there's 1 transfer in one iTD */ + itd_cnt = 8; /* required 8 iTDs for one UTR */ + interval = 8; /* iTD frame interval of this endpoint */ + } + + for (i = 0; i < itd_cnt; i++) /* allocate all iTDs required by UTR */ + { + itd = alloc_ehci_iTD(); + if (itd == NULL) + goto malloc_failed; + + if (itd_list == NULL) /* link all iTDs */ + { + itd_list = itd; + } + else + { + itd->next = itd_list; + itd_list = itd; + } + } + + utr->td_cnt = itd_cnt; + + /*------------------------------------------------------------------------------------*/ + /* Fill and link all iTDs */ + /*------------------------------------------------------------------------------------*/ + + utr->iso_sf = iso_ep->next_frame; + fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */ + + for (itd = itd_list; (itd != NULL);) + { + if (fidx >= IF_PER_UTR) /* unlikely */ + { + USB_error("EHCI driver ITD bug!?\n"); + goto malloc_failed; + } + + itd->utr = utr; + itd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */ + itd->buff_base = (uint32_t)(utr->iso_buff[fidx]); /* iTD buffer base is buffer of the first UTR iso frame serviced by this iTD */ + itd->trans_mask = trans_mask; + + write_itd_info(utr, itd); + + for (i = 0; i < 8; i++) /* settle xfer into micro-frames */ + { + if (!(trans_mask & (0x1 << i))) + { + itd->Transaction[i] = 0; /* not accesed */ + continue; /* not scheduled micro-frame */ + } + + write_itd_micro_frame(utr, fidx, itd, i); + + fidx++; /* preceed to next UTR iso frame */ + + if (fidx == IF_PER_UTR) /* is the last scheduled micro-frame? */ + { + /* raise interrupt on completed */ + itd->Transaction[i] |= ITD_IOC; + break; + } + } + + itd_next = itd->next; /* remember the next itd */ + + // USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame); + /* + * Link iTD to period frame list + */ + DISABLE_EHCI_IRQ(); + itd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */ + add_itd_to_iso_ep(iso_ep, itd); /* add to software itd list */ + itd->Next_Link = _PFList[itd->sched_frnidx]; /* keep the next link */ + _PFList[itd->sched_frnidx] = ITD_HLNK_ITD(itd); + iso_ep->next_frame = (iso_ep->next_frame + interval) % FL_SIZE; + ENABLE_EHCI_IRQ(); + + itd = itd_next; + } + + _ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */ + return 0; + +malloc_failed: + + while (itd_list != NULL) + { + itd = itd_list; + itd_list = itd->next; + free_ehci_iTD(itd); + } + return USBH_ERR_MEMORY_OUT; +} + +static __inline void add_sitd_to_iso_ep(ISO_EP_T *iso_ep, siTD_T *sitd) +{ + siTD_T *p; + + sitd->next = NULL; + + if (iso_ep->sitd_list == NULL) + { + iso_ep->sitd_list = sitd; + return; + } + + /* + * Find the tail entry of iso_ep->itd_list + */ + p = iso_ep->sitd_list; + while (p->next != NULL) + { + p = p->next; + } + p->next = sitd; +} + +static void write_sitd_info(UTR_T *utr, siTD_T *sitd) +{ + UDEV_T *udev = utr->udev; + EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */ + uint32_t buff_page_addr; + int xlen = utr->iso_xlen[sitd->fidx]; + int scnt; + + sitd->Chrst = (udev->port_num << SITD_PORT_NUM_Pos) | + (udev->parent->iface->udev->dev_num << SITD_HUB_ADDR_Pos) | + ((ep->bEndpointAddress & 0xF) << SITD_EP_NUM_Pos) | + (udev->dev_num << SITD_DEV_ADDR_Pos); + + buff_page_addr = ((uint32_t)utr->iso_buff[sitd->fidx]) & 0xFFFFF000; + sitd->Bptr[0] = (uint32_t)(utr->iso_buff[sitd->fidx]); + sitd->Bptr[1] = buff_page_addr + 0x1000; + + scnt = (xlen + 187) / 188; + + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */ + { + sitd->Chrst |= SITD_XFER_IN; + sitd->Sched = (1 << (scnt + 2)) - 1; + sitd->Sched = (sitd->Sched << 10) | 0x1; + //sitd->Sched <<= 1; + } + else + { + sitd->Chrst |= SITD_XFER_OUT; + sitd->Sched = sitd_OUT_Smask[scnt - 1]; + if (scnt > 1) + { + sitd->Bptr[1] |= (0x1 << 3); /* Transaction position (TP) 01b: Begin */ + } + sitd->Bptr[1] |= scnt; /* Transaction count (T-Count) */ + } + + if (sitd->fidx == IF_PER_UTR) + { + sitd->Sched |= SITD_IOC; + } + + sitd->StsCtrl = (xlen << SITD_XFER_CNT_Pos) | SITD_STATUS_ACTIVE; + + sitd->BackLink = SITD_LIST_END; +} + + +static void ehci_sitd_adjust_schedule(siTD_T *sitd) +{ + siTD_T *hlink = (siTD_T *)_PFList[sitd->sched_frnidx]; + uint32_t uframe_mask = 0x00; + + while (hlink && !HLINK_IS_TERMINATED(hlink) && HLINK_IS_SITD(hlink)) + { + hlink = SITD_PTR(hlink); + if (hlink != sitd) + { + if ((hlink->Chrst & SITD_XFER_IO_Msk) == SITD_XFER_IN) + { + uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by IN S-mask */ + uframe_mask |= ((hlink->Sched >> 8) & 0xFF); /* mark micro-frames used by IN C-mask */ + } + else + { + uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by OUT S-mask */ + } + } + hlink = SITD_PTR(hlink->Next_Link); + } + + uframe_mask = uframe_mask | (uframe_mask << 8); /* mark both S-mask and C-mask */ + + if (uframe_mask) + { + /* + * Shift afterward one micro-frame until no conflicts. + */ + while (1) + { + if (sitd->Sched & uframe_mask) + { + sitd->Sched = (sitd->Sched & 0xFFFF0000) | ((sitd->Sched << 1) & 0xFFFF); + } + else + { + break; /* no conflit, done. */ + } + } + } +} + + +static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep) +{ + EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */ + siTD_T *sitd, *sitd_next, *sitd_list = NULL; + int i; + int fidx; /* index to the 8 iso frames of UTR */ + + if (utr->udev->parent == NULL) + { + USB_error("siso xfer - parent lost!\n"); + return USBH_ERR_INVALID_PARAM; + } + + /*------------------------------------------------------------------------------------*/ + /* Allocate siTDs */ + /*------------------------------------------------------------------------------------*/ + for (i = 0; i < IF_PER_UTR; i++) /* allocate all siTDs required by UTR */ + { + sitd = alloc_ehci_siTD(); + if (sitd == NULL) + goto malloc_failed; + + if (sitd_list == NULL) /* link all siTDs */ + { + sitd_list = sitd; + } + else + { + sitd->next = sitd_list; + sitd_list = sitd; + } + } + + utr->td_cnt = IF_PER_UTR; + + /*------------------------------------------------------------------------------------*/ + /* Fill and link all siTDs */ + /*------------------------------------------------------------------------------------*/ + + utr->iso_sf = iso_ep->next_frame; + fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */ + + for (sitd = sitd_list; (sitd != NULL); fidx++) + { + if (fidx >= IF_PER_UTR) /* unlikely */ + { + USB_error("EHCI driver siTD bug!?\n"); + goto malloc_failed; + } + + sitd->utr = utr; + sitd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */ + + write_sitd_info(utr, sitd); + + sitd_next = sitd->next; /* remember the next itd */ + + // USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame); + /* + * Link iTD to period frame list + */ + sitd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */ + DISABLE_EHCI_IRQ(); + ehci_sitd_adjust_schedule(sitd); + add_sitd_to_iso_ep(iso_ep, sitd); /* add to software itd list */ + sitd->Next_Link = _PFList[sitd->sched_frnidx];/* keep the next link */ + _PFList[sitd->sched_frnidx] = SITD_HLNK_SITD(sitd); + iso_ep->next_frame = (iso_ep->next_frame + ep->bInterval) % FL_SIZE; + ENABLE_EHCI_IRQ(); + + sitd = sitd_next; + } + + _ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */ + return 0; + +malloc_failed: + + while (sitd_list != NULL) + { + sitd = sitd_list; + sitd_list = sitd->next; + free_ehci_siTD(sitd); + } + return USBH_ERR_MEMORY_OUT; +} + +/* + * If it's an isochronous endpoint, quit current transfer via UTR or hardware EP. + */ +int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep) +{ + ISO_EP_T *iso_ep; + iTD_T *itd, *itd_next, *p; + uint32_t frnidx; + uint32_t now_frame; + + if (ep == NULL) + { + if (utr == NULL) + return USBH_ERR_NOT_FOUND; + + if (utr->ep == NULL) + return USBH_ERR_NOT_FOUND; + + ep = utr->ep; + } + + if ((ep->bmAttributes & EP_ATTR_TT_MASK) != EP_ATTR_TT_ISO) + return USBH_ERR_NOT_FOUND; /* not isochronous endpoint */ + + /*------------------------------------------------------------------------------------*/ + /* It's an iso endpoint. Remove it as required. */ + /*------------------------------------------------------------------------------------*/ + iso_ep = iso_ep_list; + while (iso_ep != NULL) /* Search all activated iso endpoints */ + { + if (iso_ep->ep == ep) + break; + iso_ep = iso_ep->next; + } + if (iso_ep == NULL) + return 0; /* should have been removed */ + + itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */ + + while (itd != NULL) /* traverse all iTDs of itd list */ + { + itd_next = itd->next; /* remember the next iTD */ + utr = itd->utr; + + /*--------------------------------------------------------------------------------*/ + /* Remove this iTD from period frame list */ + /*--------------------------------------------------------------------------------*/ + frnidx = itd->sched_frnidx; + + /* + * Prevent to race with Host Controller. If the iTD to be removed is located in + * current or next frame, wait until HC passed through it. + */ + while (1) + { + now_frame = (_ehci->UFINDR >> 3) & 0x3FF; + if ((now_frame == frnidx) || (((now_frame + 1) % 1024) == frnidx)) + continue; + break; + } + + if (_PFList[frnidx] == ITD_HLNK_ITD(itd)) + { + /* is the first entry, just change to next */ + _PFList[frnidx] = itd->Next_Link; + } + else + { + p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */ + while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL)) + { + p = ITD_PTR(p->Next_Link); + } + + if (p == NULL) /* link list out of control! */ + { + USB_error("ehci_quit_iso_xfer - An iTD lost reference to periodic frame list! 0x%x on %d\n", (int)itd, frnidx); + } + else /* remove iTD from list */ + { + p->Next_Link = itd->Next_Link; + } + } + + utr->td_cnt--; + + if (utr->td_cnt == 0) /* All iTD of this UTR done */ + { + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + utr->status = USBH_ERR_ABORT; + } + free_ehci_iTD(itd); + itd = itd_next; + } + + /* + * Remove iso_ep from iso_ep_list + */ + remove_iso_ep_from_list(iso_ep); + usbh_free_mem(iso_ep, sizeof(*iso_ep)); /* free this iso_ep */ + ep->hw_pipe = NULL; + + if (iso_ep_list == NULL) + _ehci->UCMDR &= ~HSUSBH_UCMDR_PSEN_Msk; + + return 0; +} + + +/// @endcond HIDDEN_SYMBOLS + +/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/mem_alloc.c b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/mem_alloc.c new file mode 100644 index 0000000000000000000000000000000000000000..1ad3cabcb1f0409bb70a6ff37db20ea661749325 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/mem_alloc.c @@ -0,0 +1,540 @@ +/**************************************************************************//** + * @file mem_alloc.c + * @version V1.10 + * $Revision: 11 $ + * $Date: 14/10/03 1:54p $ + * @brief USB host library memory allocation functions. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include + +#include "usb.h" + + +/// @cond HIDDEN_SYMBOLS + +//#define MEM_DEBUG + +#ifdef MEM_DEBUG + #define mem_debug rt_kprintf +#else + #define mem_debug(...) +#endif + +#ifdef __ICCARM__ + #pragma data_alignment=1024 + uint8_t _mem_pool_buff[MEM_POOL_UNIT_NUM][MEM_POOL_UNIT_SIZE]; +#else + uint8_t _mem_pool_buff[MEM_POOL_UNIT_NUM][MEM_POOL_UNIT_SIZE] __attribute__((aligned(1024))); +#endif + +static uint8_t *_mem_pool[MEM_POOL_UNIT_NUM]; +static uint8_t _unit_used[MEM_POOL_UNIT_NUM]; + +static volatile int _usbh_mem_used; +static volatile int _usbh_max_mem_used; +static volatile int _mem_pool_used; + + +UDEV_T *g_udev_list; + +uint8_t _dev_addr_pool[128]; +static volatile int _device_addr; + +static int _sidx = 0;; + +/*--------------------------------------------------------------------------*/ +/* Memory alloc/free recording */ +/*--------------------------------------------------------------------------*/ + +void usbh_memory_init(void) +{ + int i; + + if (sizeof(TD_T) > MEM_POOL_UNIT_SIZE) + { + USB_error("TD_T - MEM_POOL_UNIT_SIZE too small!\n"); + while (1); + } + + if (sizeof(ED_T) > MEM_POOL_UNIT_SIZE) + { + USB_error("ED_T - MEM_POOL_UNIT_SIZE too small!\n"); + while (1); + } + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + _unit_used[i] = 0; + _mem_pool[i] = (uint8_t *)((uint32_t)&_mem_pool_buff[i] | NON_CACHE_MASK); + } + + _usbh_mem_used = 0L; + _usbh_max_mem_used = 0L; + + _mem_pool_used = 0; + _sidx = 0; + + g_udev_list = NULL; + + memset(_dev_addr_pool, 0, sizeof(_dev_addr_pool)); + _device_addr = 1; + + USB_InitializeMemoryPool(); +} + +uint32_t usbh_memory_used(void) +{ + mem_debug("USB static memory: %d/%d, heap used: %d\n", _mem_pool_used, MEM_POOL_UNIT_NUM, _usbh_mem_used); + return _usbh_mem_used; +} + +static void memory_counter(int size) +{ + _usbh_mem_used += size; + if (_usbh_mem_used > _usbh_max_mem_used) + _usbh_max_mem_used = _usbh_mem_used; +} + +void *usbh_alloc_mem(int size) +{ + void *p; + + p = USB_malloc(size, 16); + if (p == NULL) + { + USB_error("usbh_alloc_mem failed! %d\n", size); + return NULL; + } + + memset(p, 0, size); + memory_counter(size); + return p; +} + +void usbh_free_mem(void *p, int size) +{ + USB_free(p); + memory_counter(0 - size); +} + + +/*--------------------------------------------------------------------------*/ +/* USB device allocate/free */ +/*--------------------------------------------------------------------------*/ + +UDEV_T *alloc_device(void) +{ + UDEV_T *udev; + + udev = (UDEV_T *)USB_malloc(sizeof(*udev), 16); + if (udev == NULL) + { + USB_error("alloc_device failed!\n"); + return NULL; + } + + memset(udev, 0, sizeof(*udev)); + memory_counter(sizeof(*udev)); + udev->cur_conf = -1; /* must! used to identify the first SET CONFIGURATION */ + udev->next = g_udev_list; /* chain to global device list */ + g_udev_list = udev; + return udev; +} + +void free_device(UDEV_T *udev) +{ + UDEV_T *d; + + if (udev == NULL) + return; + + if (udev->cfd_buff != NULL) + usbh_free_mem(udev->cfd_buff, MAX_DESC_BUFF_SIZE); + + /* + * Remove it from the global device list + */ + if (g_udev_list == udev) + { + g_udev_list = g_udev_list->next; + } + else + { + d = g_udev_list; + while (d != NULL) + { + if (d->next == udev) + { + d->next = udev->next; + break; + } + d = d->next; + } + } + USB_free(udev); + memory_counter(-sizeof(*udev)); +} + +int alloc_dev_address(void) +{ + _device_addr++; + + if (_device_addr >= 128) + _device_addr = 1; + + while (1) + { + if (_dev_addr_pool[_device_addr] == 0) + { + _dev_addr_pool[_device_addr] = 1; + return _device_addr; + } + _device_addr++; + if (_device_addr >= 128) + _device_addr = 1; + } +} + +void free_dev_address(int dev_addr) +{ + if (dev_addr < 128) + _dev_addr_pool[dev_addr] = 0; +} + +/*--------------------------------------------------------------------------*/ +/* UTR (USB Transfer Request) allocate/free */ +/*--------------------------------------------------------------------------*/ + +UTR_T *alloc_utr(UDEV_T *udev) +{ +#if 0 + UTR_T *utr, *utr_noncache; + + utr = (UTR_T *)USB_malloc(sizeof(*utr), 16); + if (utr == NULL) + { + USB_error("alloc_utr failed!\n"); + return NULL; + } + + utr_noncache = (UTR_T *)((uint32_t)utr | NONCACHEABLE); + + memory_counter(sizeof(*utr)); + memset(utr_noncache, 0, sizeof(*utr)); + utr_noncache->udev = udev; + mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr_noncache); + return utr_noncache; +#else + UTR_T *utr; + + utr = (UTR_T *)USB_malloc(sizeof(*utr), 16); + if (utr == NULL) + { + USB_error("alloc_utr failed!\n"); + return NULL; + } + + memory_counter(sizeof(*utr)); + memset(utr, 0, sizeof(*utr)); + utr->udev = udev; + mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr_noncache); + return utr; +#endif +} + +void free_utr(UTR_T *utr) +{ + if (utr == NULL) + return; + + mem_debug("[FREE] [UTR] - 0x%x\n", (int)utr); + +#if 0 + if ((uint32_t)utr & NONCACHEABLE) + utr = (UTR_T *)((uint32_t)utr & ~NONCACHEABLE); +#endif + + USB_free(utr); + memory_counter(0 - (int)sizeof(*utr)); +} + +/*--------------------------------------------------------------------------*/ +/* OHCI ED allocate/free */ +/*--------------------------------------------------------------------------*/ + +ED_T *alloc_ohci_ED(void) +{ + int i; + ED_T *ed; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if (_unit_used[i] == 0) + { + _unit_used[i] = 1; + _mem_pool_used++; + ed = (ED_T *)_mem_pool[i]; + memset(ed, 0, sizeof(*ed)); + mem_debug("[ALLOC] [ED] - 0x%x\n", (int)ed); + return ed; + } + } + USB_error("alloc_ohci_ED failed!\n"); + return NULL; +} + +void free_ohci_ED(ED_T *ed) +{ + int i; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if ((uint32_t)_mem_pool[i] == (uint32_t)ed) + { + mem_debug("[FREE] [ED] - 0x%x\n", (int)ed); + _unit_used[i] = 0; + _mem_pool_used--; + return; + } + } + USB_debug("free_ohci_ED - not found! (ignored in case of multiple UTR)\n"); +} + +/*--------------------------------------------------------------------------*/ +/* OHCI TD allocate/free */ +/*--------------------------------------------------------------------------*/ +TD_T *alloc_ohci_TD(UTR_T *utr) +{ + int i; + TD_T *td; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if (_unit_used[i] == 0) + { + _unit_used[i] = 1; + _mem_pool_used++; + td = (TD_T *)_mem_pool[i]; + + memset(td, 0, sizeof(*td)); + td->utr = utr; + mem_debug("[ALLOC] [TD] - 0x%x\n", (int)td); + return td; + } + } + USB_error("alloc_ohci_TD failed!\n"); + return NULL; +} + +void free_ohci_TD(TD_T *td) +{ + int i; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if ((uint32_t)_mem_pool[i] == (uint32_t)td) + { + mem_debug("[FREE] [TD] - 0x%x\n", (int)td); + _unit_used[i] = 0; + _mem_pool_used--; + return; + } + } + USB_error("free_ohci_TD - not found!\n"); +} + +/*--------------------------------------------------------------------------*/ +/* EHCI QH allocate/free */ +/*--------------------------------------------------------------------------*/ +QH_T *alloc_ehci_QH(void) +{ + int i; + QH_T *qh = NULL; + + for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM) + { + if (_unit_used[i] == 0) + { + _unit_used[i] = 1; + _sidx = i; + _mem_pool_used++; + qh = (QH_T *)_mem_pool[i]; + memset(qh, 0, sizeof(*qh)); + mem_debug("[ALLOC] [QH] - 0x%x\n", (int)qh); + break; + } + } + if (qh == NULL) + { + USB_error("alloc_ehci_QH failed!\n"); + return NULL; + } + qh->Curr_qTD = QTD_LIST_END; + qh->OL_Next_qTD = QTD_LIST_END; + qh->OL_Alt_Next_qTD = QTD_LIST_END; + qh->OL_Token = QTD_STS_HALT; + return qh; +} + +void free_ehci_QH(QH_T *qh) +{ + int i; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if ((uint32_t)_mem_pool[i] == (uint32_t)qh) + { + mem_debug("[FREE] [QH] - 0x%x\n", (int)qh); + _unit_used[i] = 0; + _mem_pool_used--; + return; + } + } + USB_debug("free_ehci_QH - not found! (ignored in case of multiple UTR)\n"); +} + +/*--------------------------------------------------------------------------*/ +/* EHCI qTD allocate/free */ +/*--------------------------------------------------------------------------*/ +qTD_T *alloc_ehci_qTD(UTR_T *utr) +{ + int i; + qTD_T *qtd; + + for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM) + { + if (_unit_used[i] == 0) + { + _unit_used[i] = 1; + _sidx = i; + _mem_pool_used++; + qtd = (qTD_T *)_mem_pool[i]; + + memset(qtd, 0, sizeof(*qtd)); + qtd->Next_qTD = QTD_LIST_END; + qtd->Alt_Next_qTD = QTD_LIST_END; + qtd->Token = 0x1197B7F; // QTD_STS_HALT; visit_qtd() will not remove a qTD with this mark. It means the qTD still not ready for transfer. + qtd->utr = utr; + mem_debug("[ALLOC] [qTD] - 0x%x\n", (int)qtd); + return qtd; + } + } + USB_error("alloc_ehci_qTD failed!\n"); + return NULL; +} + +void free_ehci_qTD(qTD_T *qtd) +{ + int i; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if ((uint32_t)_mem_pool[i] == (uint32_t)qtd) + { + mem_debug("[FREE] [qTD] - 0x%x\n", (int)qtd); + _unit_used[i] = 0; + _mem_pool_used--; + return; + } + } + USB_error("free_ehci_qTD 0x%x - not found!\n", (int)qtd); +} + +/*--------------------------------------------------------------------------*/ +/* EHCI iTD allocate/free */ +/*--------------------------------------------------------------------------*/ +iTD_T *alloc_ehci_iTD(void) +{ + int i; + iTD_T *itd; + + for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM) + { + if (i + 2 >= MEM_POOL_UNIT_NUM) + continue; + + if ((_unit_used[i] == 0) && (_unit_used[i + 1] == 0)) + { + _unit_used[i] = _unit_used[i + 1] = 1; + _sidx = i + 1; + _mem_pool_used += 2; + itd = (iTD_T *)_mem_pool[i]; + memset(itd, 0, sizeof(*itd)); + mem_debug("[ALLOC] [iTD] - 0x%x\n", (int)itd); + return itd; + } + } + USB_error("alloc_ehci_iTD failed!\n"); + return NULL; +} + +void free_ehci_iTD(iTD_T *itd) +{ + int i; + + for (i = 0; i + 1 < MEM_POOL_UNIT_NUM; i++) + { + if ((uint32_t)_mem_pool[i] == (uint32_t)itd) + { + mem_debug("[FREE] [iTD] - 0x%x\n", (int)itd); + _unit_used[i] = _unit_used[i + 1] = 0; + _mem_pool_used -= 2; + return; + } + } + USB_error("free_ehci_iTD 0x%x - not found!\n", (int)itd); +} + +/*--------------------------------------------------------------------------*/ +/* EHCI iTD allocate/free */ +/*--------------------------------------------------------------------------*/ +siTD_T *alloc_ehci_siTD(void) +{ + int i; + siTD_T *sitd; + + for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM) + { + if (_unit_used[i] == 0) + { + _unit_used[i] = 1; + _sidx = i; + _mem_pool_used ++; + sitd = (siTD_T *)_mem_pool[i]; + memset(sitd, 0, sizeof(*sitd)); + mem_debug("[ALLOC] [siTD] - 0x%x\n", (int)sitd); + return sitd; + } + } + USB_error("alloc_ehci_siTD failed!\n"); + return NULL; +} + +void free_ehci_siTD(siTD_T *sitd) +{ + int i; + + for (i = 0; i < MEM_POOL_UNIT_NUM; i++) + { + if ((uint32_t)_mem_pool[i] == (uint32_t)sitd) + { + mem_debug("[FREE] [siTD] - 0x%x\n", (int)sitd); + _unit_used[i] = 0; + _mem_pool_used--; + return; + } + } + USB_error("free_ehci_siTD 0x%x - not found!\n", (int)sitd); +} + +/// @endcond HIDDEN_SYMBOLS + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ + diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ohci.c b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ohci.c new file mode 100644 index 0000000000000000000000000000000000000000..7b9e82b257c71cb0b4969adcb5e9e9d8af0f8b76 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/ohci.c @@ -0,0 +1,1301 @@ +/**************************************************************************//** + * @file ohci.c + * @version V1.10 + * $Revision: 11 $ + * $Date: 14/10/03 1:54p $ + * @brief USB Host library OHCI (USB 1.1) host controller driver. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include + +#include "N9H30.h" + +#include "usb.h" +#include "hub.h" +#include "ohci.h" + +/// @cond HIDDEN_SYMBOLS + +//#define TD_debug rt_kprintf +#define TD_debug(...) + +//#define ED_debug rt_kprintf +#define ED_debug(...) + +uint8_t _hcca_mem[256] __attribute__((aligned(256))); + +HCCA_T *_hcca; + +ED_T *_Ied[6]; + + +static ED_T *ed_remove_list; + +static void add_to_ED_remove_list(ED_T *ed) +{ + ED_T *p; + + ED_debug("add_to_ED_remove_list - 0x%x (0x%x)\n", (int)ed, ed->Info); + DISABLE_OHCI_IRQ(); + + /* check if this ED found in ed_remove_list */ + p = ed_remove_list; + while (p) + { + if (p == ed) + { + ENABLE_OHCI_IRQ(); /* This ED found in ed_remove_list */ + return; /* do nothing */ + } + p = p->next; + } + + ed->Info |= ED_SKIP; /* ask OHCI controller skip this ED */ + ed->next = ed_remove_list; + ed_remove_list = ed; /* insert to the head of ed_remove_list */ + ENABLE_OHCI_IRQ(); + _ohci->HcInterruptStatus = USBH_HcInterruptStatus_SF_Msk; + _ohci->HcInterruptEnable |= USBH_HcInterruptEnable_SF_Msk; + usbh_delay_ms(2); /* Full speed wait 2 ms is enough */ +} + +static int ohci_reset(void) +{ + volatile int t0; + + /* Disable HC interrupts */ + _ohci->HcInterruptDisable = USBH_HcInterruptDisable_MIE_Msk; + + /* HC Reset requires max 10 ms delay */ + _ohci->HcControl = 0; + _ohci->HcCommandStatus = USBH_HcCommandStatus_HCR_Msk; + + usbh_delay_ms(10); + + /* Check if OHCI reset completed? */ + if ((USBH->HcCommandStatus & USBH_HcCommandStatus_HCR_Msk) != 0) + { + USB_error("Error! - USB OHCI reset timed out!\n"); + return -1; + } + + USBH->HcRhStatus = USBH_HcRhStatus_OCI_Msk | USBH_HcRhStatus_LPS_Msk; + + USBH->HcControl = HCFS_RESET; + + usbh_delay_ms(10); + + /* Check if OHCI reset completed? */ + if ((USBH->HcCommandStatus & USBH_HcCommandStatus_HCR_Msk) != 0) + { + USB_error("Error! - USB HC reset timed out!\n"); + return -1; + } + return 0; +} + +static void init_hcca_int_table() +{ + ED_T *ed_p; + int i, idx, interval; + + memset(_hcca->int_table, 0, sizeof(_hcca->int_table)); + + for (i = 5; i >= 0; i--) /* interval = i^2 */ + { + _Ied[i] = alloc_ohci_ED(); + _Ied[i]->Info = ED_SKIP; + + interval = 0x1 << i; + + for (idx = interval - 1; idx < 32; idx += interval) + { + if (_hcca->int_table[idx] == 0) /* is empty list, insert directly */ + { + _hcca->int_table[idx] = (uint32_t)_Ied[i]; + } + else + { + ed_p = (ED_T *)_hcca->int_table[idx]; + + while (1) + { + if (ed_p == _Ied[i]) + break; /* already chained by previous visit */ + + if (ed_p->NextED == 0) /* reach end of list? */ + { + ed_p->NextED = (uint32_t)_Ied[i]; + break; + } + ed_p = (ED_T *)ed_p->NextED; + } + } + } + } +} + +static ED_T *get_int_tree_head_node(int interval) +{ + int i; + + for (i = 0; i < 5; i++) + { + interval >>= 1; + if (interval == 0) + return _Ied[i]; + } + return _Ied[5]; /* for interval >= 32 */ +} + +static int get_ohci_interval(int interval) +{ + int i, bInterval = 1; + + for (i = 0; i < 5; i++) + { + interval >>= 1; + if (interval == 0) + return bInterval; + bInterval *= 2; + } + return 32; /* for interval >= 32 */ +} + + +static int ohci_init(void) +{ + uint32_t fminterval; + volatile int i; + + _hcca = (HCCA_T *)((uint32_t)_hcca_mem | NON_CACHE_MASK); + + if (ohci_reset() < 0) + return -1; + + ed_remove_list = NULL; + + init_hcca_int_table(); + + /* Tell the controller where the control and bulk lists are + * The lists are empty now. */ + _ohci->HcControlHeadED = 0; /* control ED list head */ + _ohci->HcBulkHeadED = 0; /* bulk ED list head */ + + _ohci->HcHCCA = (uint32_t)_hcca; /* HCCA area */ + + /* periodic start 90% of frame interval */ + fminterval = 0x2edf; /* 11,999 */ + _ohci->HcPeriodicStart = (fminterval * 9) / 10; + + /* set FSLargestDataPacket, 10,104 for 0x2edf frame interval */ + fminterval |= ((((fminterval - 210) * 6) / 7) << 16); + _ohci->HcFmInterval = fminterval; + + _ohci->HcLSThreshold = 0x628; + + /* start controller operations */ + _ohci->HcControl = HCFS_OPER | (0x3 << USBH_HcControl_CBSR_Pos); + +#ifdef OHCI_PER_PORT_POWER + _ohci->HcRhDescriptorB = 0x60000; + for (i = 0; i < OHCI_PORT_CNT; i++) + _ohci->HcRhPortStatus[i] = USBH_HcRhPortStatus_PPS_Msk; +#else + _ohci->HcRhDescriptorA = (USBH->HcRhDescriptorA | (1 << 9)) & ~USBH_HcRhDescriptorA_PSM_Msk; + _ohci->HcRhStatus = USBH_HcRhStatus_LPSC_Msk; +#endif + + _ohci->HcInterruptEnable = USBH_HcInterruptEnable_MIE_Msk | USBH_HcInterruptEnable_WDH_Msk | USBH_HcInterruptEnable_SF_Msk; + + /* POTPGT delay is bits 24-31, in 20 ms units. */ + usbh_delay_ms(20); + return 0; +} + +static void ohci_suspend(void) +{ + int i; + + for (i = 0; i < OHCI_PORT_CNT; i++) + { + /* set port suspend if connected */ + if (_ohci->HcRhPortStatus[i] & 0x1) + _ohci->HcRhPortStatus[i] = 0x4; + } + + /* enable Device Remote Wakeup */ + _ohci->HcRhStatus |= USBH_HcRhStatus_DRWE_Msk; + + /* enable USBH RHSC interrupt for system wakeup */ + _ohci->HcInterruptEnable |= USBH_HcInterruptEnable_RHSC_Msk | USBH_HcInterruptEnable_RD_Msk; + + /* set Host Controller enter suspend state */ + _ohci->HcControl = (USBH->HcControl & ~USBH_HcControl_HCFS_Msk) | (3 << USBH_HcControl_HCFS_Pos); +} + +static void ohci_resume(void) +{ + int i; + + _ohci->HcControl = (USBH->HcControl & ~USBH_HcControl_HCFS_Msk) | (1 << USBH_HcControl_HCFS_Pos); + _ohci->HcControl = (USBH->HcControl & ~USBH_HcControl_HCFS_Msk) | (2 << USBH_HcControl_HCFS_Pos); + + for (i = 0; i < OHCI_PORT_CNT; i++) + { + if (_ohci->HcRhPortStatus[i] & 0x4) + _ohci->HcRhPortStatus[i] = 0x8; + } +} + +static void ohci_shutdown(void) +{ + ohci_suspend(); + DISABLE_OHCI_IRQ(); +#ifndef OHCI_PER_PORT_POWER + _ohci->HcRhStatus = USBH_HcRhStatus_LPS_Msk; +#endif +} + + +/* + * Quit current trasnfer via UTR or hardware EP. + */ +static int ohci_quit_xfer(UTR_T *utr, EP_INFO_T *ep) +{ + ED_T *ed; + + if (utr != NULL) + { + if (utr->ep == NULL) + return USBH_ERR_NOT_FOUND; + + ed = (ED_T *)(utr->ep->hw_pipe); + + if (!ed) + return USBH_ERR_NOT_FOUND; + + /* add the endpoint to remove list, it will be removed on the next start of frame */ + add_to_ED_remove_list(ed); + utr->ep->hw_pipe = NULL; + } + + if ((ep != NULL) && (ep->hw_pipe != NULL)) + { + ed = (ED_T *)(ep->hw_pipe); + /* add the endpoint to remove list, it will be removed on the next start of frame */ + add_to_ED_remove_list(ed); + ep->hw_pipe = NULL; + } + + return 0; +} + +uint32_t ed_make_info(UDEV_T *udev, EP_INFO_T *ep) +{ + uint32_t info; + + if (ep == NULL) /* is a control endpoint */ + { + /* control endpoint direction is from TD */ + if (udev->descriptor.bMaxPacketSize0 == 0) /* is 0 if device descriptor still not obtained. */ + { + if (udev->speed == SPEED_LOW) /* give a default maximum packet size */ + udev->descriptor.bMaxPacketSize0 = 8; + else + udev->descriptor.bMaxPacketSize0 = 64; + } + info = (udev->descriptor.bMaxPacketSize0 << 16) /* Control endpoint Maximum Packet Size from device descriptor */ + | ED_DIR_BY_TD /* Direction (Get direction From TD) */ + | ED_FORMAT_GENERAL /* General format */ + | (0 << ED_CTRL_EN_Pos); /* Endpoint address 0 */ + } + else /* Other endpoint direction is from endpoint descriptor */ + { + info = (ep->wMaxPacketSize << 16); /* Maximum Packet Size from endpoint */ + + info |= ((ep->bEndpointAddress & 0xf) << ED_CTRL_EN_Pos); /* Endpoint Number */ + + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) + info |= ED_DIR_IN; + else + info |= ED_DIR_OUT; + + if ((ep->bmAttributes & EP_ATTR_TT_MASK) == EP_ATTR_TT_ISO) + info |= ED_FORMAT_ISO; + else + info |= ED_FORMAT_GENERAL; + } + + info |= ((udev->speed == SPEED_LOW) ? ED_SPEED_LOW : ED_SPEED_FULL); /* Speed */ + info |= (udev->dev_num); /* Function Address */ + + return info; +} + +static void write_td(TD_T *td, uint32_t info, uint8_t *buff, uint32_t data_len) +{ + td->Info = info; + td->CBP = (uint32_t)((!buff || !data_len) ? 0 : buff); + td->BE = (uint32_t)((!buff || !data_len) ? 0 : (uint32_t)buff + data_len - 1); + td->buff_start = td->CBP; + // TD_debug("TD [0x%x]: 0x%x, 0x%x, 0x%x\n", (int)td, td->Info, td->CBP, td->BE); +} + +static int ohci_ctrl_xfer(UTR_T *utr) +{ + UDEV_T *udev; + ED_T *ed; + TD_T *td_setup, *td_data, *td_status; + uint32_t info; + + udev = utr->udev; + + /*------------------------------------------------------------------------------------*/ + /* Allocate ED and TDs */ + /*------------------------------------------------------------------------------------*/ + td_setup = alloc_ohci_TD(utr); + + if (utr->data_len > 0) + td_data = alloc_ohci_TD(utr); + else + td_data = NULL; + + td_status = alloc_ohci_TD(utr); + + if (td_status == NULL) + { + free_ohci_TD(td_setup); + if (utr->data_len > 0) + free_ohci_TD(td_data); + return USBH_ERR_MEMORY_OUT; + } + + /* Check if there's any transfer pending on this endpoint... */ + if (udev->ep0.hw_pipe == NULL) + { + ed = alloc_ohci_ED(); + if (ed == NULL) + { + free_ohci_TD(td_setup); + free_ohci_TD(td_status); + if (utr->data_len > 0) + free_ohci_TD(td_data); + return USBH_ERR_MEMORY_OUT; + } + } + else + ed = (ED_T *)udev->ep0.hw_pipe; + + /*------------------------------------------------------------------------------------*/ + /* prepare SETUP stage TD */ + /*------------------------------------------------------------------------------------*/ + info = TD_CC | TD_T_DATA0 | TD_TYPE_CTRL; + write_td(td_setup, info, (uint8_t *)&utr->setup, 8); + td_setup->ed = ed; + + /*------------------------------------------------------------------------------------*/ + /* prepare DATA stage TD */ + /*------------------------------------------------------------------------------------*/ + if (utr->data_len > 0) + { + if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT) + info = (TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA); + else + info = (TD_CC | TD_R | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL | TD_CTRL_DATA); + + write_td(td_data, info, utr->buff, utr->data_len); + td_data->ed = ed; + td_setup->NextTD = (uint32_t)td_data; + td_setup->next = td_data; + td_data->NextTD = (uint32_t)td_status; + td_data->next = td_status; + } + else + { + td_setup->NextTD = (uint32_t)td_status; + td_setup->next = td_status; + } + + /*------------------------------------------------------------------------------------*/ + /* prepare STATUS stage TD */ + /*------------------------------------------------------------------------------------*/ + ed->Info = ed_make_info(udev, NULL); + if ((utr->setup.bmRequestType & 0x80) == REQ_TYPE_OUT) + info = (TD_CC | TD_DP_IN | TD_T_DATA1 | TD_TYPE_CTRL); + else + info = (TD_CC | TD_DP_OUT | TD_T_DATA1 | TD_TYPE_CTRL); + + write_td(td_status, info, NULL, 0); + td_status->ed = ed; + td_status->NextTD = 0; + td_status->next = 0; + + /*------------------------------------------------------------------------------------*/ + /* prepare ED */ + /*------------------------------------------------------------------------------------*/ + ed->TailP = 0; + ed->HeadP = (uint32_t)td_setup; + ed->Info = ed_make_info(udev, NULL); + ed->NextED = 0; + + //TD_debug("TD SETUP [0x%x]: 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td_setup, td_setup->Info, td_setup->CBP, td_setup->BE, td_setup->NextTD); + //if (td_data) + // TD_debug("TD DATA [0x%x]: 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td_data, td_data->Info, td_data->CBP, td_data->BE, td_data->NextTD); + //TD_debug("TD STATUS [0x%x]: 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td_status, td_status->Info, td_status->CBP, td_status->BE, td_status->NextTD); + ED_debug("Xfer ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED); + + if (utr->data_len > 0) + utr->td_cnt = 3; + else + utr->td_cnt = 2; + + utr->ep = &udev->ep0; /* driver can find EP from UTR */ + udev->ep0.hw_pipe = (void *)ed; /* driver can find ED from EP */ + + /*------------------------------------------------------------------------------------*/ + /* Start transfer */ + /*------------------------------------------------------------------------------------*/ + DISABLE_OHCI_IRQ(); + _ohci->HcControlHeadED = (uint32_t)ed; /* Link ED to OHCI */ + _ohci->HcControl |= USBH_HcControl_CLE_Msk; /* enable control list */ + ENABLE_OHCI_IRQ(); + _ohci->HcCommandStatus = USBH_HcCommandStatus_CLF_Msk; /* start Control list */ + + return 0; +} + +static int ohci_bulk_xfer(UTR_T *utr) +{ + UDEV_T *udev = utr->udev; + EP_INFO_T *ep = utr->ep; + ED_T *ed; + TD_T *td, *td_p, *td_list = NULL; + uint32_t info; + uint32_t data_len, xfer_len; + int8_t bIsNewED = 0; + uint8_t *buff; + + /*------------------------------------------------------------------------------------*/ + /* Check if there's uncompleted transfer on this endpoint... */ + /* Prepare ED */ + /*------------------------------------------------------------------------------------*/ + info = ed_make_info(udev, ep); + + /* Check if there's any transfer pending on this endpoint... */ + ed = (ED_T *)_ohci->HcBulkHeadED; /* get the head of bulk endpoint list */ + while (ed != NULL) + { + if (ed->Info == info) /* have transfer of this EP not completed? */ + { + if ((ed->HeadP & 0xFFFFFFF0) != (ed->TailP & 0xFFFFFFF0)) + return USBH_ERR_OHCI_EP_BUSY; /* endpoint is busy */ + else + break; /* ED already there... */ + } + ed = (ED_T *)ed->NextED; + } + + if (ed == NULL) + { + bIsNewED = 1; + ed = alloc_ohci_ED(); /* allocate an Endpoint Descriptor */ + if (ed == NULL) + return USBH_ERR_MEMORY_OUT; + ed->Info = info; + ed->HeadP = 0; + ED_debug("Link BULK ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED); + } + + ep->hw_pipe = (void *)ed; + + /*------------------------------------------------------------------------------------*/ + /* Prepare TDs */ + /*------------------------------------------------------------------------------------*/ + utr->td_cnt = 0; + data_len = utr->data_len; + buff = utr->buff; + + do + { + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT) + info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_BULK); + else + info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_BULK); + + info &= ~(1 << 25); /* Data toggle from ED toggleCarry bit */ + + if (data_len > 4096) /* maximum transfer length is 4K for each TD */ + xfer_len = 4096; + else + xfer_len = data_len; /* remaining data length < 4K */ + + td = alloc_ohci_TD(utr); /* allocate a TD */ + if (td == NULL) + goto mem_out; + /* fill this TD */ + write_td(td, info, buff, xfer_len); + td->ed = ed; + + utr->td_cnt++; /* increase TD count, for recalim counter */ + + buff += xfer_len; /* advanced buffer pointer */ + data_len -= xfer_len; + + /* chain to end of TD list */ + if (td_list == NULL) + { + td_list = td; + } + else + { + td_p = td_list; + while (td_p->NextTD != 0) + td_p = (TD_T *)td_p->NextTD; + td_p->NextTD = (uint32_t)td; + } + + } + while (data_len > 0); + + /*------------------------------------------------------------------------------------*/ + /* Start transfer */ + /*------------------------------------------------------------------------------------*/ + utr->status = 0; + DISABLE_OHCI_IRQ(); + ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list; /* keep toggleCarry bit */ + if (bIsNewED) + { + ed->HeadP = (uint32_t)td_list; + /* Link ED to OHCI Bulk List */ + ed->NextED = _ohci->HcBulkHeadED; + _ohci->HcBulkHeadED = (uint32_t)ed; + } + ENABLE_OHCI_IRQ(); + _ohci->HcControl |= USBH_HcControl_BLE_Msk; /* enable bulk list */ + _ohci->HcCommandStatus = USBH_HcCommandStatus_BLF_Msk; /* start bulk list */ + + return 0; + +mem_out: + while (td_list != NULL) + { + td = td_list; + td_list = (TD_T *)td_list->NextTD; + free_ohci_TD(td); + } + free_ohci_ED(ed); + return USBH_ERR_MEMORY_OUT; +} + +static int ohci_int_xfer(UTR_T *utr) +{ + UDEV_T *udev = utr->udev; + EP_INFO_T *ep = utr->ep; + ED_T *ed, *ied; + TD_T *td, *td_new; + uint32_t info; + int8_t bIsNewED = 0; + + if (utr->data_len > 64) /* USB 1.1 interrupt transfer maximum packet size is 64 */ + return USBH_ERR_INVALID_PARAM; + + td_new = alloc_ohci_TD(utr); /* allocate a TD for dummy TD */ + if (td_new == NULL) + return USBH_ERR_MEMORY_OUT; + + ied = get_int_tree_head_node(ep->bInterval); /* get head node of this interval */ + + /*------------------------------------------------------------------------------------*/ + /* Find if this ED was already in the list */ + /*------------------------------------------------------------------------------------*/ + info = ed_make_info(udev, ep); + ed = ied; + while (ed != NULL) + { + if (ed->Info == info) + break; /* Endpoint found */ + ed = (ED_T *)ed->NextED; + } + + if (ed == NULL) /* ED not found, create it */ + { + bIsNewED = 1; + ed = alloc_ohci_ED(); /* allocate an Endpoint Descriptor */ + if (ed == NULL) + return USBH_ERR_MEMORY_OUT; + ed->Info = info; + ed->HeadP = 0; + ed->bInterval = ep->bInterval; + + td = alloc_ohci_TD(NULL); /* allocate the initial dummy TD for ED */ + if (td == NULL) + { + free_ohci_ED(ed); + free_ohci_TD(td_new); + return USBH_ERR_MEMORY_OUT; + } + ed->HeadP = (uint32_t)td; /* Let both HeadP and TailP point to dummy TD */ + ed->TailP = ed->HeadP; + } + else + { + td = (TD_T *)(ed->TailP & ~0xf); /* TailP always point to the dummy TD */ + } + ep->hw_pipe = (void *)ed; + + /*------------------------------------------------------------------------------------*/ + /* Prepare TD */ + /*------------------------------------------------------------------------------------*/ + if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_OUT) + info = (TD_CC | TD_R | TD_DP_OUT | TD_TYPE_INT); + else + info = (TD_CC | TD_R | TD_DP_IN | TD_TYPE_INT); + + /* Keep data toggle */ + info = (info & ~(1 << 25)) | (td->Info & (1 << 25)); + + /* fill this TD */ + write_td(td, info, utr->buff, utr->data_len); + td->ed = ed; + td->NextTD = (uint32_t)td_new; + td->utr = utr; + utr->td_cnt = 1; /* increase TD count, for recalim counter */ + utr->status = 0; + + /*------------------------------------------------------------------------------------*/ + /* Hook ED and TD list to HCCA interrupt table */ + /*------------------------------------------------------------------------------------*/ + DISABLE_OHCI_IRQ(); + + ed->TailP = (uint32_t)td_new; + if (bIsNewED) + { + /* Add to list of the same interval */ + ed->NextED = ied->NextED; + ied->NextED = (uint32_t)ed; + } + + ENABLE_OHCI_IRQ(); + + //printf("Link INT ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED); + + _ohci->HcControl |= USBH_HcControl_PLE_Msk; /* periodic list enable */ + return 0; +} + +static int ohci_iso_xfer(UTR_T *utr) +{ + UDEV_T *udev = utr->udev; + EP_INFO_T *ep = utr->ep; + ED_T *ed, *ied; + TD_T *td, *td_list, *last_td; + int i; + uint32_t info; + uint32_t buff_addr; + int8_t bIsNewED = 0; + + ied = get_int_tree_head_node(ep->bInterval); /* get head node of this interval */ + + /*------------------------------------------------------------------------------------*/ + /* Find if this ED was already in the list */ + /*------------------------------------------------------------------------------------*/ + info = ed_make_info(udev, ep); + ed = ied; + while (ed != NULL) + { + if (ed->Info == info) + break; /* Endpoint found */ + ed = (ED_T *)ed->NextED; + } + + if (ed == NULL) /* ED not found, create it */ + { + bIsNewED = 1; + ed = alloc_ohci_ED(); /* allocate an Endpoint Descriptor */ + if (ed == NULL) + return USBH_ERR_MEMORY_OUT; + ed->Info = info; + ed->HeadP = 0; + ed->bInterval = ep->bInterval; + } + else + + ep->hw_pipe = (void *)ed; + + /*------------------------------------------------------------------------------------*/ + /* Prepare TDs */ + /*------------------------------------------------------------------------------------*/ + if (utr->bIsoNewSched) /* Is the starting of isochronous streaming? */ + ed->next_sf = _hcca->frame_no + OHCI_ISO_DELAY; + + utr->td_cnt = 0; + utr->iso_sf = ed->next_sf; + + last_td = NULL; + td_list = NULL; + + for (i = 0; i < IF_PER_UTR; i++) + { + utr->iso_status[i] = USBH_ERR_NOT_ACCESS1; + + td = alloc_ohci_TD(utr); /* allocate a TD */ + if (td == NULL) + goto mem_out; + /* fill this TD */ + buff_addr = (uint32_t)(utr->iso_buff[i]); + td->Info = (TD_CC | TD_TYPE_ISO) | ed->next_sf; + ed->next_sf += get_ohci_interval(ed->bInterval); + td->CBP = buff_addr & ~0xFFF; + td->BE = buff_addr + utr->iso_xlen[i] - 1; + td->PSW[0] = 0xE000 | (buff_addr & 0xFFF); + + td->ed = ed; + utr->td_cnt++; /* increase TD count, for recalim counter */ + + /* chain to end of TD list */ + if (td_list == NULL) + td_list = td; + else + last_td->NextTD = (uint32_t)td; + + last_td = td; + }; + + /*------------------------------------------------------------------------------------*/ + /* Hook ED and TD list to HCCA interrupt table */ + /*------------------------------------------------------------------------------------*/ + utr->status = 0; + DISABLE_OHCI_IRQ(); + + if ((ed->HeadP & ~0x3) == 0) + ed->HeadP = (ed->HeadP & 0x2) | (uint32_t)td_list; /* keep toggleCarry bit */ + else + { + /* find the tail of TDs under this ED */ + td = (TD_T *)(ed->HeadP & ~0x3); + while (td->NextTD != 0) + { + td = (TD_T *)td->NextTD; + } + td->NextTD = (uint32_t)td_list; + } + + if (bIsNewED) + { + /* Add to list of the same interval */ + ed->NextED = ied->NextED; + ied->NextED = (uint32_t)ed; + } + + ENABLE_OHCI_IRQ(); + ED_debug("Link ISO ED 0x%x: 0x%x 0x%x 0x%x 0x%x\n", (int)ed, ed->Info, ed->TailP, ed->HeadP, ed->NextED); + _ohci->HcControl |= USBH_HcControl_PLE_Msk | USBH_HcControl_IE_Msk; /* enable periodic list and isochronous transfer */ + + return 0; + +mem_out: + while (td_list != NULL) + { + td = td_list; + td_list = (TD_T *)td_list->NextTD; + free_ohci_TD(td); + } + free_ohci_ED(ed); + return USBH_ERR_MEMORY_OUT; +} + +static UDEV_T *ohci_find_device_by_port(int port) +{ + UDEV_T *udev; + + udev = g_udev_list; + while (udev != NULL) + { + if ((udev->parent == NULL) && (udev->port_num == port) && + ((udev->speed == SPEED_LOW) || (udev->speed == SPEED_FULL))) + return udev; + udev = udev->next; + } + return NULL; +} + +static int ohci_rh_port_reset(int port) +{ + int retry; + int reset_time; + uint32_t t0; + + reset_time = usbh_tick_from_millisecond(PORT_RESET_TIME_MS); + + for (retry = 0; retry < PORT_RESET_RETRY; retry++) + { + _ohci->HcRhPortStatus[port] = USBH_HcRhPortStatus_PRS_Msk; + + t0 = usbh_get_ticks(); + while (usbh_get_ticks() - t0 < (reset_time) + 1) + { + /* + * If device is disconnected or port enabled, we can stop port reset. + */ + if (((_ohci->HcRhPortStatus[port] & USBH_HcRhPortStatus_CCS_Msk) == 0) || + ((_ohci->HcRhPortStatus[port] & (USBH_HcRhPortStatus_PES_Msk | USBH_HcRhPortStatus_CCS_Msk)) == (USBH_HcRhPortStatus_PES_Msk | USBH_HcRhPortStatus_CCS_Msk))) + goto port_reset_done; + } + reset_time += PORT_RESET_RETRY_INC_MS; + } + + USB_debug("OHCI port %d - port reset failed!\n", port + 1); + return USBH_ERR_PORT_RESET; + +port_reset_done: + if ((_ohci->HcRhPortStatus[port] & USBH_HcRhPortStatus_CCS_Msk) == 0) /* check again if device disconnected */ + { + _ohci->HcRhPortStatus[port] = USBH_HcRhPortStatus_CSC_Msk; /* clear CSC */ + return USBH_ERR_DISCONNECTED; + } + return USBH_OK; /* port reset success */ +} + +static int ohci_rh_polling(void) +{ + int i, change = 0; + UDEV_T *udev; + int ret; + + for (i = 0; i < OHCI_PORT_CNT; i++) + { + /* clear unwanted port change status */ + _ohci->HcRhPortStatus[i] = USBH_HcRhPortStatus_OCIC_Msk | USBH_HcRhPortStatus_PRSC_Msk | + USBH_HcRhPortStatus_PSSC_Msk | USBH_HcRhPortStatus_PESC_Msk; + + if ((_ohci->HcRhPortStatus[i] & USBH_HcRhPortStatus_CSC_Msk) == 0) + continue; + rt_kprintf("OHCI port%d status change: 0x%x\n", i + 1, _ohci->HcRhPortStatus[i]); + + /*--------------------------------------------------------------------------------*/ + /* connect status change */ + /*--------------------------------------------------------------------------------*/ + + _ohci->HcRhPortStatus[i] = USBH_HcRhPortStatus_CSC_Msk; /* clear CSC */ + + if (_ohci->HcRhPortStatus[i] & USBH_HcRhPortStatus_CCS_Msk) + { + /*----------------------------------------------------------------------------*/ + /* First of all, check if there's any previously connected device. */ + /*----------------------------------------------------------------------------*/ + while (1) + { + udev = ohci_find_device_by_port(i + 1); + if (udev == NULL) + break; + usbh_disconnect_device(udev); + } + + rt_kprintf("OHCI connect device.\n"); + + if (ohci_rh_port_reset(i) != USBH_OK) + continue; + + /* + * Port reset success... + */ + udev = alloc_device(); + if (udev == NULL) + continue; + + udev->parent = NULL; + udev->port_num = i + 1; + if (_ohci->HcRhPortStatus[i] & USBH_HcRhPortStatus_LSDA_Msk) + udev->speed = SPEED_LOW; + else + udev->speed = SPEED_FULL; + udev->hc_driver = &ohci_driver; + + ret = usbh_connect_device(udev); + if (ret < 0) + { + USB_error("connect_device error! [%d]\n", ret); + free_device(udev); + } + + change = 1; + } + else + { + /* + * Device disconnected + */ + rt_kprintf("OHCI disconnect device.\n"); + while (1) + { + udev = ohci_find_device_by_port(i + 1); + if (udev == NULL) + break; + usbh_disconnect_device(udev); + } + change = 1; + } + } + return change; +} + +void td_done(TD_T *td) +{ + UTR_T *utr = td->utr; + uint32_t info; + int cc; + + info = td->Info; + + TD_debug("td_done: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", (int)td, td->Info, td->CBP, td->NextTD, td->BE); + + /* ISO ... drivers see per-TD length/status */ + if ((info & TD_TYPE_Msk) == TD_TYPE_ISO) + { + uint16_t sf; + int idx; + + sf = info & 0xFFFF; + idx = ((sf + 0x10000 - utr->iso_sf) & 0xFFFF) / get_ohci_interval(td->ed->bInterval); + if (idx >= IF_PER_UTR) + { + USB_error("ISO invalid index!! %d, %d\n", sf, utr->iso_sf); + goto td_out; + } + + cc = (td->PSW[0] >> 12) & 0xF; + if (cc == 0xF) /* this frame was not transferred */ + { + USB_debug("ISO F %d N/A!\n", sf); + utr->iso_status[idx] = USBH_ERR_SCH_OVERRUN; + goto td_out; + } + if ((cc != 0) && (cc != CC_DATA_UNDERRUN)) + { + utr->iso_status[idx] = USBH_ERR_CC_NO_ERR - cc; + goto td_out; + } + utr->iso_status[idx] = 0; + utr->iso_xlen[idx] = td->PSW[0] & 0x7FF; + } + else + { + cc = TD_CC_GET(info); + + /* short packet is fine */ + if ((cc != CC_NOERROR) && (cc != CC_DATA_UNDERRUN)) + { + USB_error("TD error, CC = 0x%x\n", cc); + if (cc == CC_STALL) + utr->status = USBH_ERR_STALL; + else + utr->status = USBH_ERR_TRANSFER; + } + + switch (info & TD_TYPE_Msk) + { + case TD_TYPE_CTRL: + if (info & TD_CTRL_DATA) + { + if (td->CBP == 0) + utr->xfer_len += td->BE - td->buff_start + 1; + else + utr->xfer_len += td->CBP - td->buff_start; + } + break; + + case TD_TYPE_BULK: + case TD_TYPE_INT: + if (td->CBP == 0) + utr->xfer_len += td->BE - td->buff_start + 1; + else + utr->xfer_len += td->CBP - td->buff_start; + break; + } + } + +td_out: + + utr->td_cnt--; + + /* If all TDs are done, call-back to requester. */ + if (utr->td_cnt == 0) + { + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + } +} + +/* in IRQ context */ +static void remove_ed() +{ + ED_T *ed, *ed_p, *ied; + TD_T *td, *td_next; + UTR_T *utr; + int found; + + while (ed_remove_list != NULL) + { + ED_debug("Remove ED: 0x%x, %d\n", (int)ed_remove_list, ed_remove_list->bInterval); + ed_p = ed_remove_list; + found = 0; + + /*--------------------------------------------------------------------------------*/ + /* Remove endpoint from Control List if found */ + /*--------------------------------------------------------------------------------*/ + if ((ed_p->Info & ED_EP_ADDR_Msk) == 0) + { + if (_ohci->HcControlHeadED == (uint32_t)ed_p) + { + _ohci->HcControlHeadED = (uint32_t)ed_p->NextED; + found = 1; + } + else + { + ed = (ED_T *)_ohci->HcControlHeadED; + while (ed != NULL) + { + if (ed->NextED == (uint32_t)ed_p) + { + ed->NextED = ed_p->NextED; + found = 1; + } + ed = (ED_T *)ed->NextED; + } + } + } + + /*--------------------------------------------------------------------------------*/ + /* Remove INT or ISO endpoint from HCCA interrupt table */ + /*--------------------------------------------------------------------------------*/ + else if (ed_p->bInterval > 0) + { + ied = get_int_tree_head_node(ed_p->bInterval); + + ed = ied; + while (ed != NULL) + { + if (ed->NextED == (uint32_t)ed_p) + { + ed->NextED = ed_p->NextED; + found = 1; + break; + } + ed = (ED_T *)ed->NextED; + } + } + + /*--------------------------------------------------------------------------------*/ + /* Remove endpoint from Bulk List if found */ + /*--------------------------------------------------------------------------------*/ + else + { + if (_ohci->HcBulkHeadED == (uint32_t)ed_p) + { + ed = (ED_T *)ed_p; + _ohci->HcBulkHeadED = ed_p->NextED; + found = 1; + } + else + { + ed = (ED_T *)_ohci->HcBulkHeadED; + while (ed != NULL) + { + if (ed->NextED == (uint32_t)ed_p) + { + ed->NextED = ed_p->NextED; + found = 1; + } + ed = (ED_T *)ed->NextED; + } + } + } + + /*--------------------------------------------------------------------------------*/ + /* Remove and free all TDs under this endpoint */ + /*--------------------------------------------------------------------------------*/ + if (found) + { + td = (TD_T *)(ed_p->HeadP & ~0x3); + if (td != NULL) + { + while (td != NULL) + { + utr = td->utr; + td_next = (TD_T *)td->NextTD; + free_ohci_TD(td); + td = td_next; + + utr->td_cnt--; + if (utr->td_cnt == 0) + { + utr->status = USBH_ERR_ABORT; + utr->bIsTransferDone = 1; + if (utr->func) + utr->func(utr); + } + } + } + } + + /* + * Done. Remove this ED from [ed_remove_list] and free it. + */ + ed_remove_list = ed_p->next; + free_ohci_ED(ed_p); + } +} + + +//static irqreturn_t ohci_irq (struct usb_hcd *hcd) +//void OHCI_IRQHandler(void) +void nu_ohci_isr(int vector, void *param) +{ + TD_T *td, *td_prev, *td_next; + uint32_t int_sts; + + //if ( nu_sys_usb0_role() != USB0_ID_HOST ) return; + + int_sts = _ohci->HcInterruptStatus; + + //USB_debug("ohci int_sts = 0x%x\n", int_sts); + + if ((_ohci->HcInterruptEnable & USBH_HcInterruptEnable_SF_Msk) && + (int_sts & USBH_HcInterruptStatus_SF_Msk)) + { + int_sts &= ~USBH_HcInterruptStatus_SF_Msk; + + _ohci->HcInterruptDisable = USBH_HcInterruptDisable_SF_Msk; + remove_ed(); + _ohci->HcInterruptStatus = USBH_HcInterruptStatus_SF_Msk; + } + + if (int_sts & USBH_HcInterruptStatus_WDH_Msk) + { + int_sts &= ~USBH_HcInterruptStatus_WDH_Msk; + /* + * reverse done list + */ + td = (TD_T *)(_hcca->done_head & TD_ADDR_MASK); + _hcca->done_head = 0; + td_prev = NULL; + _ohci->HcInterruptStatus = USBH_HcInterruptStatus_WDH_Msk; + + while (td != NULL) + { + //TD_debug("Done list TD 0x%x => 0x%x\n", (int)td, (int)td->NextTD); + td_next = (TD_T *)(td->NextTD & TD_ADDR_MASK); + td->NextTD = (uint32_t)td_prev; + td_prev = td; + td = td_next; + } + td = td_prev; /* first TD of the reversed done list */ + + /* + * reclaim TDs + */ + while (td != NULL) + { + TD_debug("Reclaim TD 0x%x, next 0x%x\n", (int)td, td->NextTD); + td_next = (TD_T *)td->NextTD; + td_done(td); + free_ohci_TD(td); + td = td_next; + } + } + + if (int_sts & USBH_HcInterruptStatus_RHSC_Msk) + { + _ohci->HcInterruptDisable = USBH_HcInterruptDisable_RHSC_Msk; + } + + _ohci->HcInterruptStatus = int_sts; +} + +#ifdef ENABLE_DEBUG_MSG + +void dump_ohci_int_table() +{ + int i; + ED_T *ed; + + for (i = 0; i < 32; i++) +// for (i = 0; i < 1; i++) + + { + USB_debug("%02d: ", i); + + ed = (ED_T *)_hcca->int_table[i]; + + while (ed != NULL) + { + USB_debug("0x%x (0x%x) => ", (int)ed, ed->HeadP); + ed = (ED_T *)ed->NextED; + } + rt_kprintf("0\n"); + } +} + +void dump_ohci_regs() +{ + USB_debug("Dump OCHI registers:\n"); + USB_debug(" HcRevision = 0x%x\n", _ohci->HcRevision); + USB_debug(" HcControl = 0x%x\n", _ohci->HcControl); + USB_debug(" HcCommandStatus = 0x%x\n", _ohci->HcCommandStatus); + USB_debug(" HcInterruptStatus = 0x%x\n", _ohci->HcInterruptStatus); + USB_debug(" HcInterruptEnable = 0x%x\n", _ohci->HcInterruptEnable); + USB_debug(" HcInterruptDisable = 0x%x\n", _ohci->HcInterruptDisable); + USB_debug(" HcHCCA = 0x%x\n", _ohci->HcHCCA); + USB_debug(" HcPeriodCurrentED = 0x%x\n", _ohci->HcPeriodCurrentED); + USB_debug(" HcControlHeadED = 0x%x\n", _ohci->HcControlHeadED); + USB_debug(" HcControlCurrentED = 0x%x\n", _ohci->HcControlCurrentED); + USB_debug(" HcBulkHeadED = 0x%x\n", _ohci->HcBulkHeadED); + USB_debug(" HcBulkCurrentED = 0x%x\n", _ohci->HcBulkCurrentED); + USB_debug(" HcDoneHead = 0x%x\n", _ohci->HcDoneHead); + USB_debug(" HcFmInterval = 0x%x\n", _ohci->HcFmInterval); + USB_debug(" HcFmRemaining = 0x%x\n", _ohci->HcFmRemaining); + USB_debug(" HcFmNumber = 0x%x\n", _ohci->HcFmNumber); + USB_debug(" HcPeriodicStart = 0x%x\n", _ohci->HcPeriodicStart); + USB_debug(" HcLSThreshold = 0x%x\n", _ohci->HcLSThreshold); + USB_debug(" HcRhDescriptorA = 0x%x\n", _ohci->HcRhDescriptorA); + USB_debug(" HcRhDescriptorB = 0x%x\n", _ohci->HcRhDescriptorB); + USB_debug(" HcRhStatus = 0x%x\n", _ohci->HcRhStatus); + USB_debug(" HcRhPortStatus0 = 0x%x\n", _ohci->HcRhPortStatus[0]); + USB_debug(" HcRhPortStatus1 = 0x%x\n", _ohci->HcRhPortStatus[1]); + USB_debug(" HcPhyControl = 0x%x\n", _ohci->HcPhyControl); + USB_debug(" HcMiscControl = 0x%x\n", _ohci->HcMiscControl); +} + +void dump_ohci_ports() +{ + USB_debug("_ohci port0=0x%x, port1=0x%x\n", _ohci->HcRhPortStatus[0], _ohci->HcRhPortStatus[1]); +} + +#endif // ENABLE_DEBUG_MSG + +HC_DRV_T ohci_driver = +{ + ohci_init, /* init */ + ohci_shutdown, /* shutdown */ + ohci_suspend, /* suspend */ + ohci_resume, /* resume */ + ohci_ctrl_xfer, /* ctrl_xfer */ + ohci_bulk_xfer, /* bulk_xfer */ + ohci_int_xfer, /* int_xfer */ + ohci_iso_xfer, /* iso_xfer */ + ohci_quit_xfer, /* quit_xfer */ + ohci_rh_port_reset, /* rthub_port_reset */ + ohci_rh_polling /* rthub_polling */ +}; + +/// @endcond HIDDEN_SYMBOLS + +/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/ diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/support.c b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/support.c new file mode 100644 index 0000000000000000000000000000000000000000..5006034c50fce00596d6f646de428807ebb68e71 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/support.c @@ -0,0 +1,324 @@ +/**************************************************************************//** + * @file support.c + * @version V1.10 + * $Revision: 11 $ + * $Date: 14/10/03 1:54p $ + * @brief Functions to support USB host driver. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include + +#include "usb.h" + +/// @cond HIDDEN_SYMBOLS + + +#define USB_MEMORY_POOL_SIZE (32*1024) +#define USB_MEM_BLOCK_SIZE 128 + +#define BOUNDARY_WORD 4 + + +static uint32_t _FreeMemorySize; +uint32_t _AllocatedMemorySize; + + +#define USB_MEM_ALLOC_MAGIC 0x19685788 /* magic number in leading block */ + +typedef struct USB_mhdr +{ + uint32_t flag; /* 0:free, 1:allocated, 0x3:first block */ + uint32_t bcnt; /* if allocated, the block count of allocated memory block */ + uint32_t magic; + uint32_t reserved; +} USB_MHDR_T; + +uint8_t _USBMemoryPool[USB_MEMORY_POOL_SIZE] __attribute__((aligned(USB_MEM_BLOCK_SIZE))); + + +static USB_MHDR_T *_pCurrent; +uint32_t *_USB_pCurrent = (uint32_t *) &_pCurrent; + +static uint32_t _MemoryPoolBase, _MemoryPoolEnd; + + +void USB_InitializeMemoryPool() +{ + _MemoryPoolBase = (UINT32)&_USBMemoryPool[0] | NON_CACHE_MASK; + _MemoryPoolEnd = _MemoryPoolBase + USB_MEMORY_POOL_SIZE; + _FreeMemorySize = _MemoryPoolEnd - _MemoryPoolBase; + _AllocatedMemorySize = 0; + _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; + memset((char *)_MemoryPoolBase, 0, _FreeMemorySize); +} + + +int USB_available_memory() +{ + return _FreeMemorySize; +} + + +int USB_allocated_memory() +{ + return _AllocatedMemorySize; +} + + +void *USB_malloc(INT wanted_size, INT boundary) +{ + USB_MHDR_T *pPrimitivePos = _pCurrent; + USB_MHDR_T *pFound; + INT found_size = -1; + INT i, block_count; + INT wrap = 0; + int disable_ohci_irq, disable_ehci_irq; + + if (IS_OHCI_IRQ_ENABLED()) + disable_ohci_irq = 1; + else + disable_ohci_irq = 0; + + if (IS_EHCI_IRQ_ENABLED()) + disable_ehci_irq = 1; + else + disable_ehci_irq = 0; + + if (disable_ohci_irq) + DISABLE_OHCI_IRQ(); + if (disable_ehci_irq) + DISABLE_EHCI_IRQ(); + + if (wanted_size >= _FreeMemorySize) + { + rt_kprintf("USB_malloc - want=%d, free=%d\n", wanted_size, _FreeMemorySize); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return NULL; + } + + if ((UINT32)_pCurrent >= _MemoryPoolEnd) + _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */ + + do + { + if (_pCurrent->flag) /* is not a free block */ + { + if (_pCurrent->magic != USB_MEM_ALLOC_MAGIC) + { + rt_kprintf("\nUSB_malloc - incorrect magic number! C:%x F:%x, wanted:%d, Base:0x%x, End:0x%x\n", (UINT32)_pCurrent, _FreeMemorySize, wanted_size, (UINT32)_MemoryPoolBase, (UINT32)_MemoryPoolEnd); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return NULL; + } + + if (_pCurrent->flag == 0x3) + _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + _pCurrent->bcnt * USB_MEM_BLOCK_SIZE); + else + { + rt_kprintf("USB_malloc warning - not the first block!\n"); + _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE); + } + + if ((UINT32)_pCurrent > _MemoryPoolEnd) + rt_kprintf("USB_malloc - behind limit!!\n"); + + if ((UINT32)_pCurrent == _MemoryPoolEnd) + { + //rt_kprintf("USB_alloc - warp!!\n"); + wrap = 1; + _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */ + } + + found_size = -1; /* reset the accumlator */ + } + else /* is a free block */ + { + if (found_size == -1) /* the leading block */ + { + pFound = _pCurrent; + block_count = 1; + + if (boundary > BOUNDARY_WORD) + found_size = 0; /* not use the data area of the leading block */ + else + found_size = USB_MEM_BLOCK_SIZE - sizeof(USB_MHDR_T); + + /* check boundary - + * If boundary > BOUNDARY_WORD, the start of next block should + * be the beginning address of allocated memory. Thus, we check + * the boundary of the next block. The leading block will be + * used as a header only. + */ + if ((boundary > BOUNDARY_WORD) && + ((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE >= _MemoryPoolEnd) || + ((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE) % boundary != 0))) + found_size = -1; /* violate boundary, reset the accumlator */ + } + else /* not the leading block */ + { + found_size += USB_MEM_BLOCK_SIZE; + block_count++; + } + + if (found_size >= wanted_size) + { + pFound->bcnt = block_count; + pFound->magic = USB_MEM_ALLOC_MAGIC; + _FreeMemorySize -= block_count * USB_MEM_BLOCK_SIZE; + _AllocatedMemorySize += block_count * USB_MEM_BLOCK_SIZE; + _pCurrent = pFound; + for (i = 0; i < block_count; i++) + { + _pCurrent->flag = 1; /* allocate block */ + _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE); + } + pFound->flag = 0x3; + + if (boundary > BOUNDARY_WORD) + { + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + //rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size); + return (void *)((UINT32)pFound + USB_MEM_BLOCK_SIZE); + } + else + { + //USB_debug("USB_malloc(%d,%d):%x\tsize:%d, C:0x%x, %d\n", wanted_size, boundary, (UINT32)pFound + sizeof(USB_MHDR_T), block_count * USB_MEM_BLOCK_SIZE, _pCurrent, block_count); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + //rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size); + return (void *)((UINT32)pFound + sizeof(USB_MHDR_T)); + } + } + + /* advance to the next block */ + _pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE); + if ((UINT32)_pCurrent >= _MemoryPoolEnd) + { + wrap = 1; + _pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */ + found_size = -1; /* reset accumlator */ + } + } + } + while ((wrap == 0) || (_pCurrent < pPrimitivePos)); + + rt_kprintf("USB_malloc - No free memory!\n"); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return NULL; +} + + +void USB_free(void *alloc_addr) +{ + USB_MHDR_T *pMblk; + UINT32 addr = (UINT32)alloc_addr; + INT i, count; + int disable_ohci_irq, disable_ehci_irq; + + if (IS_OHCI_IRQ_ENABLED()) + disable_ohci_irq = 1; + else + disable_ohci_irq = 0; + + if (IS_EHCI_IRQ_ENABLED()) + disable_ehci_irq = 1; + else + disable_ehci_irq = 0; + + //rt_kprintf("USB_free: 0x%x\n", (int)alloc_addr); + + if ((addr < _MemoryPoolBase) || (addr >= _MemoryPoolEnd)) + { + if (addr) + { + rt_kprintf("[%s]Wrong!!\n", __func__); + //free(alloc_addr); + } + return; + } + + if (disable_ohci_irq) + DISABLE_OHCI_IRQ(); + if (disable_ehci_irq) + DISABLE_EHCI_IRQ(); + + //rt_kprintf("USB_free:%x\n", (INT)addr+USB_MEM_BLOCK_SIZE); + + /* get the leading block address */ + if (addr % USB_MEM_BLOCK_SIZE == 0) + addr -= USB_MEM_BLOCK_SIZE; + else + addr -= sizeof(USB_MHDR_T); + + if (addr % USB_MEM_BLOCK_SIZE != 0) + { + rt_kprintf("USB_free fatal error on address: %x!!\n", (UINT32)alloc_addr); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return; + } + + pMblk = (USB_MHDR_T *)addr; + if (pMblk->flag == 0) + { + rt_kprintf("USB_free(), warning - try to free a free block: %x\n", (UINT32)alloc_addr); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return; + } + if (pMblk->magic != USB_MEM_ALLOC_MAGIC) + { + rt_kprintf("USB_free(), warning - try to free an unknow block at address:%x.\n", addr); + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return; + } + + //_pCurrent = pMblk; + + //rt_kprintf("+ 0x%x, %d\n", (int)pMblk, pMblk->bcnt); + + count = pMblk->bcnt; + for (i = 0; i < count; i++) + { + pMblk->flag = 0; /* release block */ + pMblk = (USB_MHDR_T *)((UINT32)pMblk + USB_MEM_BLOCK_SIZE); + } + + _FreeMemorySize += count * USB_MEM_BLOCK_SIZE; + _AllocatedMemorySize -= count * USB_MEM_BLOCK_SIZE; + if (disable_ohci_irq) + ENABLE_OHCI_IRQ(); + if (disable_ehci_irq) + ENABLE_EHCI_IRQ(); + return; +} + + +/// @endcond HIDDEN_SYMBOLS + diff --git a/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/usb_core.c b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/usb_core.c new file mode 100644 index 0000000000000000000000000000000000000000..7bb6c30bbebcd4bfee495470cc8413fc4ee2ac4e --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/UsbHostLib/src/usb_core.c @@ -0,0 +1,312 @@ +/**************************************************************************//** + * @file usb_core.c + * @version V1.10 + * $Revision: 11 $ + * $Date: 14/10/03 1:54p $ + * @brief USB Host library core. + * + * @note + * SPDX-License-Identifier: Apache-2.0 + * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ + +#include +#include +#include + +#include "usb.h" +#include "hub.h" + + +/// @cond HIDDEN_SYMBOLS + +USBH_T *_ohci; +HSUSBH_T *_ehci; + +static UDEV_DRV_T *_drivers[MAX_UDEV_DRIVER]; + +static CONN_FUNC *g_conn_func, *g_disconn_func; + + +//extern void EHCI_IRQHandler(void); +//extern void OHCI_IRQHandler(void); +extern void nu_ohci_isr(int vector, void *param); +extern void nu_ehci_isr(int vector, void *param); + + +/// @endcond HIDDEN_SYMBOLS + + +/** + * @brief Initialize NUC980 USB Host controller and USB stack. + * + * @return None. + */ +void usbh_core_init() +{ + DISABLE_EHCI_IRQ(); + DISABLE_OHCI_IRQ(); + + _ohci = USBH; + _ehci = HSUSBH; + + memset(_drivers, 0, sizeof(_drivers)); + + g_conn_func = NULL; + g_disconn_func = NULL; + +// usbh_hub_init(); + + _ehci->USBPCR0 = 0x160; /* enable PHY 0 */ + _ehci->USBPCR1 = 0x520; /* enable PHY 1 */ + usbh_memory_init(); + + //_ohci->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; /* Over-current active low */ + _ohci->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; /* Over-current active high */ + +#ifdef ENABLE_OHCI + //sysInstallISR(IRQ_LEVEL_1, IRQ_OHCI, (PVOID)OHCI_IRQHandler); + rt_hw_interrupt_install(IRQ_OHCI, nu_ohci_isr, NULL, "ohci"); + rt_hw_interrupt_set_priority(IRQ_OHCI, IRQ_LEVEL_1); + + ohci_driver.init(); + ENABLE_OHCI_IRQ(); +#endif + +#ifdef ENABLE_EHCI + //sysInstallISR(IRQ_LEVEL_1, IRQ_EHCI, (PVOID)EHCI_IRQHandler); + rt_hw_interrupt_install(IRQ_EHCI, nu_ehci_isr, NULL, "ehci"); + rt_hw_interrupt_set_priority(IRQ_EHCI, IRQ_LEVEL_1); + + ehci_driver.init(); + ENABLE_EHCI_IRQ(); +#endif +} + + +/** + * @brief Let USB stack polls all root hubs. If there's any hub port + * change found, USB stack will manage the hub events in this function call. + * In this function, USB stack enumerates newly connected devices and remove staff + * of disconnected devices. User's application should periodically invoke this + * function. + * @return There's hub port change or not. + * @retval 0 No any hub port status changes found. + * @retval 1 There's hub port status changes. + */ +int usbh_polling_root_hubs(void) +{ + int ret, change = 0; + +#ifdef ENABLE_EHCI + do + { + ret = ehci_driver.rthub_polling(); + if (ret) + change = 1; + } + while (ret == 1); + + // scan_isochronous_list(); + +#endif + +#ifdef ENABLE_OHCI + do + { + ret = ohci_driver.rthub_polling(); + if (ret) + change = 1; + } + while (ret == 1); +#endif + + return change; +} + +/** + * @brief Force to quit an endpoint transfer. + * @param[in] udev The USB device. + * @param[in] ep The endpoint to be quit. + * @retval 0 Transfer success + * @retval < 0 Failed. Refer to error code definitions. + */ +int usbh_quit_xfer(UDEV_T *udev, EP_INFO_T *ep) +{ + return udev->hc_driver->quit_xfer(NULL, ep); +} + + +int usbh_connect_device(UDEV_T *udev) +{ + usbh_delay_ms(100); /* initially, give 100 ms delay */ + + if (g_conn_func) + g_conn_func(udev, 0); + + return 0; +} + + +void usbh_disconnect_device(UDEV_T *udev) +{ + USB_debug("disconnect device...\n"); + + if (g_disconn_func) + g_disconn_func(udev, 0); + + +#if 1 //CHECK: Maybe create a new API to quit_xfer and free udev for application + usbh_quit_xfer(udev, &(udev->ep0)); /* Quit control transfer if hw_pipe is not NULL. */ + + /* remove device from global device list */ +// free_dev_address(udev->dev_num); + free_device(udev); + +// usbh_memory_used(); +#endif +} + +/** + * @brief Install device connect and disconnect callback function. + * + * @param[in] conn_func Device connect callback function. + * @param[in] disconn_func Device disconnect callback function. + * @return None. + */ +void usbh_install_conn_callback(CONN_FUNC *conn_func, CONN_FUNC *disconn_func) +{ + g_conn_func = conn_func; + g_disconn_func = disconn_func; +} + +int usbh_reset_port(UDEV_T *udev) +{ + if (udev->parent == NULL) + { + if (udev->hc_driver) + return udev->hc_driver->rthub_port_reset(udev->port_num - 1); + else + return USBH_ERR_NOT_FOUND; + } + else + { + return udev->parent->port_reset(udev->parent, udev->port_num); + } +} + + +/** + * @brief Force to quit an UTR transfer. + * @param[in] utr The UTR transfer to be quit. + * @retval 0 Transfer success + * @retval < 0 Failed. Refer to error code definitions. + */ +int usbh_quit_utr(UTR_T *utr) +{ + if (!utr || !utr->udev) + return USBH_ERR_NOT_FOUND; + + return utr->udev->hc_driver->quit_xfer(utr, NULL); +} + + +/** + * @brief Execute an USB request in control transfer. This function returns after the request + * was done or aborted. + * @param[in] udev The target USB device. + * @param[in] bmRequestType Characteristics of request + * @param[in] bRequest Specific request + * @param[in] wValue Word-sized field that varies according to request + * @param[in] wIndex Word-sized field that varies according to request + * @param[in] wLength Number of bytes to transfer if there is a Data stage + * @param[in] buff Data buffer used in data stage + * @param[out] xfer_len Transmitted/received length of data + * @param[in] timeout Time-out limit (in 10ms - timer tick) of this transfer + * @retval 0 Transfer success + * @retval < 0 Transfer failed. Refer to error code definitions. + */ +int usbh_ctrl_xfer(UDEV_T *udev, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + uint16_t wLength, uint8_t *buff, uint32_t *xfer_len, uint32_t timeout) +{ + UTR_T *utr; + uint32_t t0, timeout_tick; + int status; + + *xfer_len = 0; + + //if (check_device(udev)) + // return USBH_ERR_INVALID_PARAM; + + utr = alloc_utr(udev); + if (utr == NULL) + return USBH_ERR_MEMORY_OUT; + + utr->setup.bmRequestType = bmRequestType; + utr->setup.bRequest = bRequest; + utr->setup.wValue = wValue; + utr->setup.wIndex = wIndex; + utr->setup.wLength = wLength; + + utr->buff = buff; + utr->data_len = wLength; + utr->bIsTransferDone = 0; + status = udev->hc_driver->ctrl_xfer(utr); + if (status < 0) + { + udev->ep0.hw_pipe = NULL; + free_utr(utr); + return status; + } + + timeout_tick = usbh_tick_from_millisecond(timeout); + t0 = usbh_get_ticks(); + while (utr->bIsTransferDone == 0) + { + if (usbh_get_ticks() - t0 > timeout_tick) + { + usbh_quit_utr(utr); + free_utr(utr); + udev->ep0.hw_pipe = NULL; + return USBH_ERR_TIMEOUT; + } + } + + status = utr->status; + + if (status == 0) + { + *xfer_len = utr->xfer_len; + } + free_utr(utr); + + return status; +} + +/** + * @brief Execute a bulk transfer request. This function will return immediately after + * issued the bulk transfer. USB stack will later call back utr->func() once the bulk + * transfer was done or aborted. + * @param[in] utr The bulk transfer request. + * @retval 0 Transfer success + * @retval < 0 Failed. Refer to error code definitions. + */ +int usbh_bulk_xfer(UTR_T *utr) +{ + return utr->udev->hc_driver->bulk_xfer(utr); +} + +/** + * @brief Execute an interrupt transfer request. This function will return immediately after + * issued the interrupt transfer. USB stack will later call back utr->func() once the + * interrupt transfer was done or aborted. + * @param[in] utr The interrupt transfer request. + * @retval 0 Transfer success + * @retval < 0 Failed. Refer to error code definitions. + */ +int usbh_int_xfer(UTR_T *utr) +{ + return utr->udev->hc_driver->int_xfer(utr); +} + + diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/Kconfig b/bsp/nuvoton/libraries/n9h30/rtt_port/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..97b1a58f2414c57bdf16799a5815a92d4a59e78d --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/Kconfig @@ -0,0 +1,500 @@ +config SOC_SERIES_N9H30 + bool + select ARCH_ARM_ARM9 + select SOC_FAMILY_NUMICRO + select RT_USING_COMPONENTS_INIT + select RT_USING_USER_MAIN + default y + + config BSP_USE_STDDRIVER_SOURCE + bool "Build StdDriver source" + default n + + config BSP_USING_MMU + bool "Enable MMU" + default y + + config BSP_USING_GPIO + bool "Enable General Purpose I/O(GPIO)" + select RT_USING_PIN + default y + + menuconfig BSP_USING_CLK + bool "Enable Clock Controller(CLK)" + select RT_USING_PM + select BSP_USING_TMR + default y + help + Choose this option if you need CLK/PM function. + Notice: Enable the option will hold timer3 resource + + if BSP_USING_CLK + config NU_CLK_INVOKE_WKTMR + bool "Enable SPD1 and DPD mode wakeup timer. (About 6.6 Secs)" + default y + endif + + menuconfig BSP_USING_EMAC + bool "Enable Ethernet MAC Controller(EMAC)" + select RT_USING_LWIP + select RT_USING_NETDEV + + if BSP_USING_EMAC + config BSP_USING_EMAC0 + bool "Enable EMAC0" + + config BSP_USING_EMAC1 + bool "Enable EMAC1" + endif + + menuconfig BSP_USING_RTC + bool "Enable Real Time Clock(RTC)" + select RT_USING_RTC + + config NU_RTC_SUPPORT_IO_RW + bool "Support device RW entry" + depends on BSP_USING_RTC && RT_USING_RTC + + config NU_RTC_SUPPORT_MSH_CMD + bool "Support module shell command" + depends on BSP_USING_RTC && RT_USING_RTC + + menuconfig BSP_USING_ADC + bool "Enable Analog-to-Digital Converter(ADC)" + select RT_USING_ADC + + if BSP_USING_ADC + config BSP_USING_ADC_TOUCH + bool "Enable ADC Touching function" + select RT_USING_TOUCH + default y + endif + + menuconfig BSP_USING_ETMR + bool "Enable Enhance Timer Controller(ETIMER)" + + if BSP_USING_ETMR + + config BSP_USING_ETIMER + bool + + config BSP_USING_ETIMER_CAPTURE + bool + + config BSP_USING_ETMR0 + bool "Enable ETIMER0" + depends on BSP_USING_ETMR + + if BSP_USING_ETMR0 + choice + prompt "Select ETIMER0 function mode" + + config BSP_USING_ETIMER0 + select BSP_USING_ETIMER + select RT_USING_HWTIMER + bool "ETIMER" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_ETIMER0_CAPTURE + select BSP_USING_ETIMER_CAPTURE + select RT_USING_INPUT_CAPTURE + bool "ETIMER CAPTURE" + help + Choose this option if you need CAPTURE function mode. + + endchoice + endif + + config BSP_USING_ETMR1 + bool "Enable ETIMER1" + depends on BSP_USING_ETMR + + if BSP_USING_ETMR1 + choice + prompt "Select ETIMER1 function mode" + + config BSP_USING_ETIMER1 + select BSP_USING_ETIMER + select RT_USING_HWTIMER + bool "ETIMER" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_ETIMER1_CAPTURE + select BSP_USING_ETIMER_CAPTURE + select RT_USING_INPUT_CAPTURE + bool "ETIMER CAPTURE" + help + Choose this option if you need CAPTURE function mode. + endchoice + endif + + config BSP_USING_ETMR2 + bool "Enable ETIMER2" + depends on BSP_USING_ETMR + + if BSP_USING_ETMR2 + choice + prompt "Select ETIMER2 function mode" + + config BSP_USING_ETIMER2 + select BSP_USING_ETIMER + select RT_USING_HWTIMER + bool "ETIMER" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_ETIMER2_CAPTURE + select BSP_USING_ETIMER_CAPTURE + select RT_USING_INPUT_CAPTURE + bool "ETIMER CAPTURE" + help + Choose this option if you need CAPTURE function mode. + endchoice + endif + + config BSP_USING_ETMR3 + bool "Enable ETIMER3" + depends on BSP_USING_ETMR + + if BSP_USING_ETMR3 + choice + prompt "Select ETIMER3 function mode" + + config BSP_USING_ETIMER3 + select BSP_USING_ETIMER + select RT_USING_HWTIMER + bool "ETIMER" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_ETIMER3_CAPTURE + select BSP_USING_ETIMER_CAPTURE + select RT_USING_INPUT_CAPTURE + bool "ETIMER CAPTURE" + help + Choose this option if you need CAPTURE function mode. + endchoice + endif + + endif + + menuconfig BSP_USING_TMR + bool "Enable Timer Controller(TIMER)" + + if BSP_USING_TMR + + config BSP_USING_TIMER + bool + + config BSP_USING_TIMER0 + select BSP_USING_TIMER + select RT_USING_HWTIMER + bool "TIMER0" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_TIMER1 + select BSP_USING_TIMER + select RT_USING_HWTIMER + bool "TIMER1" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_TIMER2 + select BSP_USING_TIMER + select RT_USING_HWTIMER + bool "TIMER2" + help + Choose this option if you need TIMER function mode. + + config BSP_USING_TIMER3 + select BSP_USING_TIMER + select RT_USING_HWTIMER + bool "TIMER3" + help + Choose this option if you need TIMER function mode. + + endif + + menuconfig BSP_USING_UART + bool "Enable Universal Asynchronous Receiver/Transmitters(UART)" + select RT_USING_SERIAL + + if BSP_USING_UART + config BSP_USING_UART0 + bool "Enable UART0" + + config BSP_USING_UART1 + bool "Enable UART1" + + config BSP_USING_UART2 + bool "Enable UART2" + + config BSP_USING_UART3 + bool "Enable UART3" + + config BSP_USING_UART4 + bool "Enable UART4" + + config BSP_USING_UART5 + bool "Enable UART5" + + config BSP_USING_UART6 + bool "Enable UART6" + + config BSP_USING_UART7 + bool "Enable UART7" + + config BSP_USING_UART8 + bool "Enable UART8" + + config BSP_USING_UART9 + bool "Enable UART9" + + config BSP_USING_UART10 + bool "Enable UART10" + + endif + + menuconfig BSP_USING_I2C + bool "Enable I2C Serial Interface Controller(I2C)" + select RT_USING_I2C + + if BSP_USING_I2C + config BSP_USING_I2C0 + bool "Enable I2C0" + + config BSP_USING_I2C1 + bool "Enable I2C1" + endif + + menuconfig BSP_USING_SDH + bool "Enable Secure Digital Host Controller(SDH)" + select RT_USING_DFS + + if BSP_USING_SDH + config BSP_USING_SDH0 + bool "Enable SDH0" + + config BSP_USING_SDH1 + bool "Enable SDH1" + + config NU_SDH_HOTPLUG + bool "Using HOTPLUG" + default y + + config NU_SDH_MOUNT_ON_ROOT + bool "Mount on root" + + endif + + menuconfig BSP_USING_CAN + bool "Enable Controller Area Network(CAN)" + select RT_USING_CAN + + if BSP_USING_CAN + config BSP_USING_CAN0 + bool "Enable CAN0" + + config BSP_USING_CAN1 + bool "Enable CAN1" + endif + + menuconfig BSP_USING_PWM + bool "Enable PWM Generator (PWM)" + select RT_USING_PWM + + if BSP_USING_PWM + config BSP_USING_PWM0 + select RT_USING_PWM + bool "Enable PWM0" + help + Choose this option if you need PWM function mode. + endif + + menuconfig BSP_USING_QSPI + bool "Enable Quad Serial Peripheral Interface(QSPI)" + select RT_USING_SPI + + if BSP_USING_QSPI + choice + prompt "Select QSPI0 function mode" + config BSP_USING_QSPI0_NONE + bool "NONE" + help + Choose this option if you need not QSPI0. + + config BSP_USING_QSPI0 + bool "Enable QSPI0" + help + Choose this option if you need QSPI function mode. + endchoice + + choice + prompt "Select QSPI1 function mode" + config BSP_USING_QSPI1_NONE + bool "NONE" + help + Choose this option if you need not QSPI1. + + config BSP_USING_QSPI1 + bool "Enable QSPI1" + help + Choose this option if you need QSPI function mode. + endchoice + + endif + + config BSP_USING_I2S + bool "Enable I2S Controller(I2S)" + select RT_USING_AUDIO + + if BSP_USING_I2S + config NU_I2S_DMA_FIFO_SIZE + int "DMA Buffer size of capture and playback" + range 2048 4096 + default 2048 + endif + + menuconfig BSP_USING_SCUART + bool "Enable Smart Card Host Interface - UART(SCUART)" + + if BSP_USING_SCUART + config BSP_USING_SCUART0 + bool "Enable SCUART0" + + config BSP_USING_SCUART1 + bool "Enable SCUART1" + endif + + menuconfig BSP_USING_CRYPTO + bool "Enable Cryptographic Accelerator(CRYPTO)" + select RT_USING_HWCRYPTO + select RT_HWCRYPTO_USING_AES + select RT_HWCRYPTO_USING_AES_ECB + select RT_HWCRYPTO_USING_AES_CBC + select RT_HWCRYPTO_USING_AES_CFB + select RT_HWCRYPTO_USING_AES_CTR + select RT_HWCRYPTO_USING_AES_CFB + select RT_HWCRYPTO_USING_AES_OFB + select RT_HWCRYPTO_USING_SHA1 + select RT_HWCRYPTO_USING_SHA2 + select RT_HWCRYPTO_USING_SHA2_224 + select RT_HWCRYPTO_USING_SHA2_256 + select RT_HWCRYPTO_USING_SHA2_384 + select RT_HWCRYPTO_USING_SHA2_512 + select RT_HWCRYPTO_USING_RNG + + if BSP_USING_CRYPTO + config NU_PRNG_USE_SEED + bool "Use specified seed value." + help + Specify the seed value to PRNG. + + if NU_PRNG_USE_SEED + config NU_PRNG_SEED_VALUE + hex "Enter seed value" + range 0 0xFFFFFFFF + default 0 + endif + endif + + menuconfig BSP_USING_SOFT_I2C + bool "Enable SOFT I2C" + + if BSP_USING_SOFT_I2C + config BSP_USING_SOFT_I2C0 + bool "Enable SOFT I2C0" + select RT_USING_I2C + select RT_USING_I2C_BITOPS + default n + + if BSP_USING_SOFT_I2C0 + config BSP_SOFT_I2C0_SCL_PIN + hex "Specify the pin index of SCL of SOFT I2C0" + range 0 0x7F + default 0x18 + + config BSP_SOFT_I2C0_SDA_PIN + hex "Specify the pin index of SDA of SOFT I2C0" + range 0 0x7F + default 0x17 + endif + + config BSP_USING_SOFT_I2C1 + bool "Enable SOFT I2C1" + select RT_USING_I2C + select RT_USING_I2C_BITOPS + default n + + if BSP_USING_SOFT_I2C1 + config BSP_SOFT_I2C1_SCL_PIN + hex "Specify the pin index of SCL of SOFT I2C1" + range 0 0x7F + default 0x0B + + config BSP_SOFT_I2C1_SDA_PIN + hex "Specify the pin index of SDA of SOFT I2C1" + range 0 0x7F + default 0x0A + endif + endif + + config BSP_USING_WDT + bool "Enable Watchdog Timer(WDT)" + select RT_USING_WDT + default y + + config BSP_USING_EBI + bool "Enable External Bus Interface(EBI)" + default n + + config BSP_USING_VPOST + bool "Enable LCD Display engine(VPOST)" + default y + + if BSP_USING_VPOST + choice + prompt "Select Supported LCM panel" + default LCM_USING_FW070TFT + config LCM_USING_E50A2V1 + bool "LCM_E50A2V1(800x480x2)" + + config LCM_USING_LSA40AT9001 + bool "LCM_LSA40AT9001(800x600x2)" + + config LCM_USING_FW070TFT + bool "LCM_FW070TFT(800x480x4)" + + endchoice + + config VPOST_USING_LCD_IDX + int + default 0 if LCM_USING_E50A2V1 + + default 2 if LCM_USING_LSA40AT9001 + default 3 if LCM_USING_FW070TFT + + config LCM_USING_BPP + int + default 2 if LCM_USING_E50A2V1 + + default 2 if LCM_USING_LSA40AT9001 + default 4 if LCM_USING_FW070TFT + + config BSP_USING_VPOST_OSD + bool "Enable VPOST OSD layer" + default n + + endif + + config BSP_USING_USBD + bool "Enable USB Device Controller(USBD)" + select RT_USING_USB_DEVICE + + config BSP_USING_USBH + bool "Enable USB Host Controller(USBH)" + select RT_USING_USB_HOST + select RT_USBH_MSTORAGE diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/SConscript b/bsp/nuvoton/libraries/n9h30/rtt_port/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..e1b907cc3c967e7c927f8bbbb0ecf9da15e8cce1 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/SConscript @@ -0,0 +1,14 @@ +# RT-Thread building script for component + +Import('RTT_ROOT') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] +group = [] + +# USB driver constrain +group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc.c new file mode 100644 index 0000000000000000000000000000000000000000..5ce1c64276b4865d3d2468952a99a5cf70bbabdf --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc.c @@ -0,0 +1,728 @@ +/**************************************************************************//** +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_ADC) + +#include +#include "NuMicro.h" +#include "drv_sys.h" +#include "nu_bitutil.h" +#include "drv_adc.h" + +/* Private define ---------------------------------------------------------------*/ +#define DEF_ADC_TOUCH_SMPL_TICK 40 + +/* Private Typedef --------------------------------------------------------------*/ +struct nu_adc +{ + struct rt_adc_device dev; + char *name; + uint32_t OpFreqKHz; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + int chn_num; + uint32_t chn_mask; + rt_sem_t m_psSem; + + rt_touch_t psRtTouch; + rt_timer_t psRtTouchMenuTimer; + + nu_adc_cb m_isr[eAdc_ISR_CNT]; + nu_adc_cb m_wkisr[eAdc_WKISR_CNT]; + + rt_mq_t m_pmqTouchXYZ; +}; +typedef struct nu_adc *nu_adc_t; + +struct nu_adc_touch_data +{ + uint16_t u16X; + uint16_t u16Y; + uint16_t u16Z0; + uint16_t u16Z1; +}; +typedef struct nu_adc_touch_data *nu_adc_touch_data_t; + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled); +static rt_err_t nu_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value); +static rt_err_t _nu_adc_control(rt_device_t dev, int cmd, void *args); + +/* Public functions ------------------------------------------------------------*/ +int rt_hw_adc_init(void); + +/* Private variables ------------------------------------------------------------*/ + +static struct nu_adc g_sNuADC = +{ + .name = "adc", + .OpFreqKHz = 4000, /* 1000 <= OpFreqKHz <= 4000 */ + .chn_num = 8, + .irqn = IRQ_ADC, + .rstidx = ADCRST, + .clkidx = ADCCKEN, + .chn_mask = 0 +}; + +static void nu_adc_isr(int vector, void *param) +{ + rt_int32_t isr, wkisr; + nu_adc_t psNuAdc = (nu_adc_t)param; + rt_int32_t irqidx; + + isr = inpw(REG_ADC_ISR); + wkisr = inpw(REG_ADC_WKISR); + + while ((irqidx = nu_ctz(isr)) < eAdc_ISR_CNT) + { + uint32_t u32IsrBitMask = 1 << irqidx ; + + if (psNuAdc->m_isr[irqidx].cbfunc != RT_NULL) + { + //rt_kprintf("[%s] %d %x\n", __func__, irqidx, psNuAdc->m_isr[irqidx].cbfunc); + psNuAdc->m_isr[irqidx].cbfunc(isr, psNuAdc->m_isr[irqidx].private_data); + } + + /* Clear sent bit */ + outpw(REG_ADC_ISR, u32IsrBitMask); + isr &= ~(u32IsrBitMask); + } //while + + while ((irqidx = nu_ctz(wkisr)) < eAdc_WKISR_CNT) + { + uint32_t u32IsrBitMask = 1 << irqidx ; + + if (psNuAdc->m_wkisr[irqidx].cbfunc != RT_NULL) + { + psNuAdc->m_wkisr[irqidx].cbfunc(wkisr, psNuAdc->m_wkisr[irqidx].private_data); + } + + /* Clear sent bit */ + outpw(REG_ADC_WKISR, u32IsrBitMask); + wkisr &= ~(u32IsrBitMask); + } //while +} + +static rt_err_t _nu_adc_init(rt_device_t dev) +{ + uint32_t div; + nu_adc_t psNuAdc = (nu_adc_t)dev; + + /* ADC Engine Clock is set to freq Khz */ + if (psNuAdc->OpFreqKHz > 4000) psNuAdc->OpFreqKHz = 4000; + if (psNuAdc->OpFreqKHz < 1000) psNuAdc->OpFreqKHz = 1000; + + div = 12000 / psNuAdc->OpFreqKHz; + + outpw(REG_CLK_DIVCTL7, inpw(REG_CLK_DIVCTL7) & ~((0x3 << 19) | (0x7 << 16) | (0xFFul << 24))); + outpw(REG_CLK_DIVCTL7, (0 << 19) | (0 << 16) | ((div - 1) << 24)); + + /* Install interrupt service routine */ + rt_hw_interrupt_install(psNuAdc->irqn, nu_adc_isr, (void *)psNuAdc, psNuAdc->name); + + return RT_EOK; +} + +void nu_adc_touch_detect(rt_bool_t bStartDetect) +{ + nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC; + + if (bStartDetect) + { + /* Start detect PenDown */ + _nu_adc_control((rt_device_t)psNuAdc, PEPOWER_ON, RT_NULL); + } + else + { + /* Stop detect PenDown */ + _nu_adc_control((rt_device_t)psNuAdc, PEPOWER_OFF, RT_NULL); + } +} + +static int32_t AdcMenuStartCallback(uint32_t status, uint32_t userData) +{ + static struct nu_adc_touch_data point; + static rt_bool_t bDrop = RT_FALSE; + static uint16_t u16LastZ0 = 0xfffful; + + nu_adc_t psNuAdc = (nu_adc_t)userData; + + if (psNuAdc->psRtTouch != RT_NULL) + { + uint32_t value; + + value = inpw(REG_ADC_XYDATA); + point.u16X = (uint16_t)(value & 0x0ffful); + point.u16Y = (uint16_t)((value >> 16) & 0x0ffful); + + value = inpw(REG_ADC_ZDATA); + point.u16Z0 = (uint16_t)(value & 0x0ffful); + point.u16Z1 = (uint16_t)((value >> 16) & 0x0ffful); + + /* Trigger next or not. */ + if (point.u16Z0 == 0) + { + /* Stop sampling procedure. */ + rt_timer_stop(g_sNuADC.psRtTouchMenuTimer); + + /* Re-start pendown detection */ + nu_adc_touch_detect(RT_TRUE); + + bDrop = RT_TRUE; + } + else + { + bDrop = RT_FALSE; + } + + /* Notify upper layer. */ + if ((!bDrop || (u16LastZ0 != 0)) && rt_mq_send(psNuAdc->m_pmqTouchXYZ, (const void *)&point, sizeof(struct nu_adc_touch_data)) == RT_EOK) + { + rt_hw_touch_isr(psNuAdc->psRtTouch); + } + + u16LastZ0 = point.u16Z0; + } + else + { + rt_err_t result = rt_sem_release(psNuAdc->m_psSem); + RT_ASSERT(result == RT_EOK); + } + + return 0; +} + + +static int32_t PenDownCallback(uint32_t status, uint32_t userData) +{ + nu_adc_touch_detect(RT_FALSE); + + rt_timer_start(g_sNuADC.psRtTouchMenuTimer); + + return 0; +} + +int32_t nu_adc_read_touch_xyz(uint16_t *bufX, uint16_t *bufY, uint16_t *bufZ0, uint16_t *bufZ1, int32_t dataCnt) +{ + int i; + struct nu_adc_touch_data value; + + for (i = 0 ; i < dataCnt; i++) + { + if (rt_mq_recv(g_sNuADC.m_pmqTouchXYZ, (void *)&value, sizeof(struct nu_adc_touch_data), 0) == -RT_ETIMEOUT) + break; + + bufX[i] = value.u16X; + bufY[i] = value.u16Y; + bufZ0[i] = value.u16Z0; + bufZ1[i] = value.u16Z1; + } + return i; +} + +static rt_err_t _nu_adc_control(rt_device_t dev, int cmd, void *args) +{ + rt_err_t ret = RT_EINVAL ; + nu_adc_t psNuAdc = (nu_adc_t)dev; + + nu_adc_cb_t psAdcCb = (nu_adc_cb_t)args; + + switch (cmd) + { + case START_MST: /* Menu Start Conversion */ + { + /* Enable interrupt */ + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_MIEN); + + /* Start conversion */ + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_MST); + + /* Wait it done */ + ret = rt_sem_take(psNuAdc->m_psSem, RT_WAITING_FOREVER); + RT_ASSERT(ret == RT_EOK); + + /* Get data: valid data is 12-bit */ + if (args != RT_NULL) + *((uint32_t *)args) = inpw(REG_ADC_DATA) & 0x00000FFF; + } + break; + + /* case START_MST_POLLING: Not supported. */ + + case VBPOWER_ON: /* Enable ADC Internal Bandgap Power */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_VBGEN); + } + break; + + case VBPOWER_OFF: /* Disable ADC Internal Bandgap Power */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_VBGEN); + } + break; + + case KPPOWER_ON: /* Enable ADC Keypad Power */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_PWKPEN); + } + break; + + case KPPOWER_OFF: /* Disable ADC Keypad Power */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_PWKPEN); + } + break; + + case PEPOWER_ON: /* Enable Pen Power */ + { + int retry = 100; + uint32_t treg = inpw(REG_ADC_IER); + outpw(REG_ADC_IER, treg & ~(ADC_IER_PEDEIEN | ADC_IER_PEUEIEN)); + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_PEDEEN); + do + { + outpw(REG_ADC_ISR, ADC_ISR_PEDEF | ADC_ISR_PEUEF); + rt_thread_mdelay(1); + if (retry-- == 0) + break; + } + while (inpw(REG_ADC_ISR) & (ADC_ISR_PEDEF | ADC_ISR_PEUEF)); + outpw(REG_ADC_IER, treg); + } + break; + + case PEPOWER_OFF: /* Disable Pen Power */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_PEDEEN); + } + break; + + case KPPRESS_ON: /* Enable Keypad press event */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_isr[eAdc_KPEF], psAdcCb, sizeof(nu_adc_cb)); + } + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_KPEIEN); + } + break; + + case KPPRESS_OFF: /* Disable Keypad press event */ + { + outpw(REG_ADC_IER, inpw(REG_ADC_IER & ~ADC_IER_KPEIEN)); + } + break; + + case KPUP_ON: /* Enable Keypad up event */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_isr[eAdc_KPUEF], psAdcCb, sizeof(nu_adc_cb)); + } + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_KPUEIEN); + } + break; + + case KPUP_OFF: /* Disable Keypad up event */ + { + outpw(REG_ADC_IER, inpw(REG_ADC_IER) & ~ADC_IER_KPUEIEN); + } + break; + + case PEDEF_ON: /* Enable Pen Down Event */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_isr[eAdc_PEDEF], psAdcCb, sizeof(nu_adc_cb)); + } + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_PEDEIEN); + } + break; + + case PEDEF_OFF: /* Disable Pen Down Event */ + { + outpw(REG_ADC_IER, inpw(REG_ADC_IER) & ~ADC_IER_PEDEIEN); + } + break; + + case WKP_ON: /* Enable Keypad Press Wake Up */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_wkisr[eAdc_WKPEF], psAdcCb, sizeof(nu_adc_cb)); + } + + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_WKPEN); + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_WKPIEN); + outpw(REG_SYS_WKUPSER, inpw(REG_SYS_WKUPSER) | (1 << 26)); + } + break; + + case WKP_OFF: /* Disable Keypad Press Wake Up */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_WKPEN); + outpw(REG_ADC_IER, inpw(REG_ADC_IER) & ~ADC_IER_WKPIEN); + outpw(REG_SYS_WKUPSER, inpw(REG_SYS_WKUPSER) & ~(1 << 26)); + } + break; + + case WKT_ON: /* Enable Touch Wake Up */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_wkisr[eAdc_WPEDEF], psAdcCb, sizeof(nu_adc_cb)); + } + + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_WKTEN); + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_WKTIEN); + outpw(REG_SYS_WKUPSER, inpw(REG_SYS_WKUPSER) | (1 << 26)); + } + break; + + case WKT_OFF: /* Disable Touch Wake Up */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_WKTEN); + outpw(REG_ADC_IER, inpw(REG_ADC_IER) & ~ADC_IER_WKTIEN); + outpw(REG_SYS_WKUPSER, inpw(REG_SYS_WKUPSER) & ~(1 << 26)); + } + break; + + case SWITCH_5WIRE_ON: /* Wire Mode Switch to 5-Wire */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_WMSWCH); + } + break; + + case SWITCH_5WIRE_OFF: /* Wire Mode Switch to 4-Wire */ + { + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_WMSWCH); + } + break; + + case T_ON: /* Enable Touch detection function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_TEN); + } + break; + + case T_OFF: /* Disable Touch detection function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_TEN); + } + break; + + case TAVG_ON: /* Enable Touch Mean average for X and Y function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_DISTMAVEN); + } + break; + + case TAVG_OFF: /* Disable Touch Mean average for X and Y function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_DISTMAVEN); + } + break; + + case Z_ON: /* Enable Press measure function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_ZEN); + } + break; + + case Z_OFF: /* Disable Press measure function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_ZEN); + rt_mq_control(psNuAdc->m_pmqTouchXYZ, RT_IPC_CMD_RESET, RT_NULL); + } + break; + + case TZAVG_ON: /* Enable Pressure Mean average for Z1 and Z2 function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_DISZMAVEN); + } + break; + + case TZAVG_OFF: /* Disable Pressure Mean average for Z1 and Z2 function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_DISZMAVEN); + } + break; + + case NAC_ON: /* Enable Normal AD Conversion */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_NACEN | ADC_CONF_REFSEL_AVDD33); + } + break; + + case NAC_OFF: /* Disable Normal AD Conversion */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_NACEN); + } + break; + + case VBAT_ON: /* Enable Voltage Battery Conversion */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_isr[eAdc_VBF], psAdcCb, sizeof(nu_adc_cb)); + } + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_VBATEN); + } + break; + + case VBAT_OFF: /* Disable Voltage Battery */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_VBATEN); + } + break; + + case KPCONV_ON: /* Enable Keypad conversion function */ + { + if (psAdcCb) + { + rt_memcpy(&psNuAdc->m_isr[eAdc_KPCF], psAdcCb, sizeof(nu_adc_cb)); + } + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_KPCEN); + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_KPEIEN); + } + break; + + case KPCONV_OFF: /* Disable Keypad conversion function */ + { + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) & ~ADC_CONF_KPCEN); + } + break; + + case SWITCH_CH: + { + int chn = (int)args; + if (chn >= psNuAdc->chn_num) + { + return -ret; + } + outpw(REG_ADC_CONF, (inpw(REG_ADC_CONF) & ~ADC_CONF_CHSEL_Msk) | (chn << ADC_CONF_CHSEL_Pos)); + } + break; + + default: + return -(ret); + } + + return RT_EOK; +} + +void nu_adc_touch_start_conv(void) +{ + nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC; + _nu_adc_control((rt_device_t)psNuAdc, START_MST, RT_NULL); +} + +rt_err_t nu_adc_touch_enable(rt_touch_t psRtTouch) +{ + nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC; + nu_adc_cb sNuAdcCb; + + rt_adc_enable((rt_adc_device_t)psNuAdc, 4); + rt_adc_enable((rt_adc_device_t)psNuAdc, 5); + rt_adc_enable((rt_adc_device_t)psNuAdc, 6); + rt_adc_enable((rt_adc_device_t)psNuAdc, 7); + + outpw(REG_ADC_CONF, (inpw(REG_ADC_CONF) & ~(0xfful << 24)) | 0xfful << 24); + + /* Register touch device. */ + psNuAdc->psRtTouch = psRtTouch; + + /* Enable TouchXY. */ + _nu_adc_control((rt_device_t)psNuAdc, T_ON, RT_NULL); + + /* Enable TouchZZ. */ + _nu_adc_control((rt_device_t)psNuAdc, Z_ON, RT_NULL); + + /* Register PenDown callback. */ + sNuAdcCb.cbfunc = PenDownCallback; + sNuAdcCb.private_data = (rt_uint32_t)psRtTouch; + _nu_adc_control((rt_device_t)psNuAdc, PEDEF_ON, (void *)&sNuAdcCb); + + nu_adc_touch_detect(RT_TRUE); + + return RT_EOK; +} + +rt_err_t nu_adc_touch_disable(void) +{ + nu_adc_t psNuAdc = (nu_adc_t)&g_sNuADC; + + nu_adc_touch_detect(RT_FALSE); + + _nu_adc_control((rt_device_t)psNuAdc, T_OFF, RT_NULL); + _nu_adc_control((rt_device_t)psNuAdc, Z_OFF, RT_NULL); + _nu_adc_control((rt_device_t)psNuAdc, PEDEF_OFF, RT_NULL); + + rt_adc_disable((rt_adc_device_t)psNuAdc, 4); + rt_adc_disable((rt_adc_device_t)psNuAdc, 5); + rt_adc_disable((rt_adc_device_t)psNuAdc, 6); + rt_adc_disable((rt_adc_device_t)psNuAdc, 7); + + return RT_EOK; +} + +static rt_err_t _nu_adc_open(rt_device_t dev, rt_uint16_t oflag) +{ + nu_adc_t psNuAdc = (nu_adc_t)dev; + + /* Enable ADC engine clock */ + nu_sys_ipclk_enable(psNuAdc->clkidx); + + /* Reset the ADC IP */ + nu_sys_ip_reset(psNuAdc->rstidx); + + /* Enable ADC Power */ + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_ADEN); + + /* Enable ADC to high speed mode */ + outpw(REG_ADC_CONF, inpw(REG_ADC_CONF) | ADC_CONF_HSPEED); + + /* Enable interrupt */ + rt_hw_interrupt_umask(psNuAdc->irqn); + + /* Enable Normal AD Conversion */ + _nu_adc_control(dev, NAC_ON, RT_NULL); + + return RT_EOK; +} + +static rt_err_t _nu_adc_close(rt_device_t dev) +{ + nu_adc_t psNuAdc = (nu_adc_t)dev; + + /* Disable Normal AD Conversion */ + _nu_adc_control(dev, NAC_OFF, RT_NULL); + + /* Disable interrupt */ + rt_hw_interrupt_mask(psNuAdc->irqn); + + /* Disable ADC Power */ + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) & ~ADC_CTL_ADEN); + + /* Disable ADC engine clock */ + nu_sys_ipclk_disable(psNuAdc->clkidx); + + return RT_EOK; +} + +static const struct rt_adc_ops nu_adc_ops = +{ + nu_adc_enabled, + nu_adc_convert, +}; + +/* nu_adc_enabled - Enable ADC clock and wait for ready */ +static rt_err_t nu_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled) +{ + nu_adc_t psNuADC = (nu_adc_t)device; + RT_ASSERT(device != RT_NULL); + + if (channel >= psNuADC->chn_num) + return -(RT_EINVAL); + + if (enabled) + { + psNuADC->chn_mask |= (1 << channel); + } + else + { + psNuADC->chn_mask &= ~(1 << channel); + } + + if (psNuADC->chn_mask > 0 && ((rt_device_t)device)->ref_count == 0) + { + _nu_adc_open((rt_device_t)device, 0); + ((rt_device_t)device)->ref_count = 1; + } + else if ((psNuADC->chn_mask == 0) && ((rt_device_t)device)->ref_count == 1) + { + _nu_adc_close((rt_device_t)device); + ((rt_device_t)device)->ref_count = 0; + } + return RT_EOK; +} + +static rt_err_t nu_adc_convert(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value) +{ + rt_err_t ret = RT_EOK; + nu_adc_t psNuAdc = (nu_adc_t)device; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(value != RT_NULL); + + if (channel >= psNuAdc->chn_num) + { + ret = RT_EINVAL; + goto exit_nu_adc_convert; + } + else if ((ret = _nu_adc_control((rt_device_t)device, SWITCH_CH, (void *)channel)) != RT_EOK) + { + goto exit_nu_adc_convert; + } + else if ((ret = _nu_adc_control((rt_device_t)device, START_MST, (void *)value)) != RT_EOK) + { + goto exit_nu_adc_convert; + } + +exit_nu_adc_convert: + + return (-ret) ; +} + +static void nu_adc_touch_smpl(void *p) +{ + /* Enable interrupt */ + outpw(REG_ADC_IER, inpw(REG_ADC_IER) | ADC_IER_MIEN); + + /* Start conversion */ + outpw(REG_ADC_CTL, inpw(REG_ADC_CTL) | ADC_CTL_MST); +} + + +int rt_hw_adc_init(void) +{ + rt_err_t result = RT_ERROR; + rt_device_t psDev = &g_sNuADC.dev.parent; + + result = rt_hw_adc_register(&g_sNuADC.dev, g_sNuADC.name, &nu_adc_ops, &g_sNuADC); + RT_ASSERT(result == RT_EOK); + + result = _nu_adc_init(psDev); + RT_ASSERT(result == RT_EOK); + + g_sNuADC.m_psSem = rt_sem_create("adc_mst_sem", 0, RT_IPC_FLAG_FIFO); + RT_ASSERT(g_sNuADC.m_psSem != RT_NULL); + + g_sNuADC.m_pmqTouchXYZ = rt_mq_create("ADC_TOUCH_XYZ", sizeof(struct nu_adc_touch_data), TOUCH_MQ_LENGTH, RT_IPC_FLAG_FIFO); + RT_ASSERT(g_sNuADC.m_pmqTouchXYZ != RT_NULL); + + g_sNuADC.psRtTouchMenuTimer = rt_timer_create("TOUCH_SMPL_TIMER", nu_adc_touch_smpl, (void *)&g_sNuADC, DEF_ADC_TOUCH_SMPL_TICK, RT_TIMER_FLAG_PERIODIC); + RT_ASSERT(g_sNuADC.psRtTouchMenuTimer != RT_NULL); + + rt_memset(&g_sNuADC.m_isr, 0, sizeof(g_sNuADC.m_isr)); + rt_memset(&g_sNuADC.m_wkisr, 0, sizeof(g_sNuADC.m_wkisr)); + + g_sNuADC.m_isr[eAdc_MF].cbfunc = AdcMenuStartCallback; + g_sNuADC.m_isr[eAdc_MF].private_data = (UINT32)&g_sNuADC; + + return (int)result; +} +INIT_BOARD_EXPORT(rt_hw_adc_init); + +#endif //#if defined(BSP_USING_ADC) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc.h new file mode 100644 index 0000000000000000000000000000000000000000..2269f1f35c5399959b21720d7796ac11655a2dc9 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc.h @@ -0,0 +1,64 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-4-7 Wayne First version +* +******************************************************************************/ + +#ifndef __DRV_ADC_H__ +#define __DRV_ADC_H__ + +#include +#include "nu_adc.h" +#include "touch.h" + +#define TOUCH_MQ_LENGTH 128 + +typedef enum +{ + eAdc_MF, //0 + eAdc_KPEF, //1 + eAdc_PEDEF, //2 + eAdc_KPUEF, //3 + eAdc_PEUEF, //4 + eAdc_TF = 8, //8 + eAdc_ZF, //9 + eAdc_NACF, //10 + eAdc_VBF, //11 + eAdc_KPCF, //12 + eAdc_SELFTF, //13 + eAdc_INTKP = 16, //16 + eAdc_INTTC, //17 + eAdc_ISR_CNT //18 +} E_ADC_ISR_EVENT; + +typedef enum +{ + eAdc_WKPEF, + eAdc_WPEDEF, + eAdc_WKISR_CNT +} E_ADC_WKISR_EVENT; + +typedef struct +{ + ADC_CALLBACK cbfunc; + uint32_t private_data; +} nu_adc_cb; + +typedef nu_adc_cb *nu_adc_cb_t; + +int32_t nu_adc_read_touch_xyz(uint16_t *bufX, uint16_t *bufY, uint16_t *bufZ0, uint16_t *bufZ1, int32_t dataCnt); +rt_err_t nu_adc_touch_enable(rt_touch_t psRtTouch); +rt_err_t nu_adc_touch_disable(void); +void nu_adc_touch_detect(rt_bool_t bStartDetect); +void nu_adc_touch_start_conv(void); + +void nu_adc_touch_update_caldata(int *psi32NewValue); +void nu_adc_touch_reset_caldata(int *psi32NewValue); + +#endif /* __DRV_ADC_H__ */ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc_touch.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc_touch.c new file mode 100644 index 0000000000000000000000000000000000000000..cefdb168ab41ebcd923fd6c2445f792dc131eaa7 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_adc_touch.c @@ -0,0 +1,274 @@ +/**************************************************************************//** +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-04-20 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_ADC_TOUCH) + +#include "NuMicro.h" +#include +#include "drv_adc.h" +#include "touch.h" + +typedef struct +{ + struct rt_touch_device dev; + rt_uint32_t x_range; + rt_uint32_t y_range; +} nu_adc_touch; +typedef nu_adc_touch *nu_adc_touch_t; + +static nu_adc_touch s_NuAdcTouch = {0}; + +#define DEF_CALDATA_LENGTH 7 +static int cal_data_a[DEF_CALDATA_LENGTH] = { 13230, -66, -1161952, -85, 8600, -1636996, 65536 }; +static const int cal_zero[DEF_CALDATA_LENGTH] = { 1, 0, 0, 0, 1, 0, 1 }; + +static void nu_adc_touch_cal(int *sumx, int *sumy) +{ + int xtemp, ytemp; + + xtemp = *sumx; + ytemp = *sumy; + *sumx = (cal_data_a[2] + + cal_data_a[0] * xtemp + + cal_data_a[1] * ytemp) / cal_data_a[6]; + *sumy = (cal_data_a[5] + + cal_data_a[3] * xtemp + + cal_data_a[4] * ytemp) / cal_data_a[6]; +} + +static rt_size_t nu_adc_touch_readpoint(struct rt_touch_device *device, void *buf, rt_size_t read_num) +{ + static int last_report_x = 0, last_report_y = 0; + struct rt_touch_data *pPoint = (struct rt_touch_data *)buf; + nu_adc_touch_t psNuAdcTouch = (nu_adc_touch_t)device; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(buf != RT_NULL); + + int i; + + for (i = 0; i < read_num; i++) + { + int bufZ0 = 0, bufZ1 = 0; + int sumx = 0, sumy = 0; + pPoint[i].timestamp = rt_touch_get_ts(); + pPoint[i].track_id = 0; + + if (nu_adc_read_touch_xyz((uint16_t *)&sumx, (uint16_t *)&sumy, (uint16_t *)&bufZ0, (uint16_t *)&bufZ1, 1) != 1) + break; + + if (bufZ0 == 0) + { + /* Workaround: In this case, x, y values are unstable. so, report last point's coordinate.*/ + pPoint[i].event = RT_TOUCH_EVENT_UP; + pPoint[i].x_coordinate = last_report_x; + pPoint[i].y_coordinate = last_report_y; + } + else + { + nu_adc_touch_cal(&sumx, &sumy); + pPoint[i].event = RT_TOUCH_EVENT_DOWN; + pPoint[i].x_coordinate = sumx; + pPoint[i].y_coordinate = sumy; + last_report_x = sumx; + last_report_y = sumy; + } + + bufZ0 = bufZ0 >> 3; + + pPoint[i].width = (bufZ0 > 255) ? 255 : bufZ0; + + //Limit max x, y coordinate if value is over its range. + pPoint[i].x_coordinate = (pPoint[i].x_coordinate > psNuAdcTouch->x_range) ? psNuAdcTouch->x_range : pPoint[i].x_coordinate; + pPoint[i].y_coordinate = (pPoint[i].y_coordinate > psNuAdcTouch->y_range) ? psNuAdcTouch->y_range : pPoint[i].y_coordinate; + } + return (rt_size_t)i; +} + +static rt_err_t nu_adc_touch_control(struct rt_touch_device *device, int cmd, void *data) +{ + nu_adc_touch_t psNuAdcTouch = (nu_adc_touch_t)device; + RT_ASSERT(psNuAdcTouch != RT_NULL); + + switch (cmd) + { + case RT_TOUCH_CTRL_SET_X_RANGE: /* set x range */ + psNuAdcTouch->x_range = *((rt_int32_t *)data); + break; + + case RT_TOUCH_CTRL_SET_Y_RANGE: /* set y range */ + psNuAdcTouch->y_range = *((rt_int32_t *)data); + break; + + case RT_TOUCH_CTRL_ENABLE_INT: /* enable pen_down interrupt */ + nu_adc_touch_detect(RT_TRUE); + break; + + case RT_TOUCH_CTRL_DISABLE_INT: /* disable pen_down interrupt */ + nu_adc_touch_detect(RT_FALSE); + break; + + case RT_TOUCH_CTRL_POWER_ON: /* Touch Power On */ + return nu_adc_touch_enable(device); + + case RT_TOUCH_CTRL_POWER_OFF: /* Touch Power Off */ + return nu_adc_touch_disable(); + + default: + return -RT_ERROR; + } + return RT_EOK; +} + +static struct rt_touch_ops touch_ops = +{ + .touch_readpoint = nu_adc_touch_readpoint, + .touch_control = nu_adc_touch_control, +}; + +void nu_adc_touch_update_caldata(int *psi32NewValue) +{ + rt_memcpy(&cal_data_a[0], &psi32NewValue[0], sizeof(cal_data_a)); +} + +void nu_adc_touch_reset_caldata(int *psi32NewValue) +{ + rt_memcpy(&cal_data_a[0], &cal_zero[0], sizeof(cal_data_a)); +} + +int rt_hw_adc_touch_init(void) +{ + /* Register touch device */ + s_NuAdcTouch.dev.info.type = RT_TOUCH_TYPE_RESISTANCE; + s_NuAdcTouch.dev.info.vendor = RT_TOUCH_VENDOR_UNKNOWN; + s_NuAdcTouch.dev.info.point_num = 1; + s_NuAdcTouch.dev.info.range_x = 800; + s_NuAdcTouch.dev.info.range_x = 480; + + s_NuAdcTouch.dev.ops = &touch_ops; + + return (int)rt_hw_touch_register(&s_NuAdcTouch.dev, "adc_touch", RT_DEVICE_FLAG_INT_RX, RT_NULL); +} +INIT_DEVICE_EXPORT(rt_hw_adc_touch_init); + + +static rt_thread_t adc_touch_thread = RT_NULL; +static rt_sem_t adc_touch_sem = RT_NULL; +static int adc_touch_worker_run = 0; +static rt_err_t adc_touch_rx_callback(rt_device_t dev, rt_size_t size) +{ + rt_sem_release(adc_touch_sem); + return 0; +} + +static void adc_touch_entry(void *parameter) +{ + struct rt_touch_data touch_point; + + rt_err_t result; + rt_device_t pdev = &s_NuAdcTouch.dev.parent; + + int max_range; + + adc_touch_sem = rt_sem_create("adc_touch_sem", 0, RT_IPC_FLAG_FIFO); + RT_ASSERT(adc_touch_sem != RT_NULL); + + result = rt_device_open(pdev, RT_DEVICE_FLAG_INT_RX); + RT_ASSERT(result == RT_EOK); + + result = rt_device_set_rx_indicate(pdev, adc_touch_rx_callback); + RT_ASSERT(result == RT_EOK); + + max_range = 800; + result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_X_RANGE, (void *)&max_range); + RT_ASSERT(result == RT_EOK); + + max_range = 480; + result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_Y_RANGE, (void *)&max_range); + RT_ASSERT(result == RT_EOK); + + // nu_adc_touch_reset_caldata(int *psi32NewValue); + // nu_adc_touch_update_caldata(int *psi32NewValue); + + result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_ON, RT_NULL); + RT_ASSERT(result == RT_EOK); + + while (adc_touch_worker_run) + { + if ((-RT_ETIMEOUT == rt_sem_take(adc_touch_sem, rt_tick_from_millisecond(100)))) + continue; + + rt_memset(&touch_point, 0, sizeof(struct rt_touch_data)); + + if (rt_device_read(pdev, 0, &touch_point, s_NuAdcTouch.dev.info.point_num) == s_NuAdcTouch.dev.info.point_num) + { + if (touch_point.event == RT_TOUCH_EVENT_DOWN + || touch_point.event == RT_TOUCH_EVENT_UP + || touch_point.event == RT_TOUCH_EVENT_MOVE) + { +#if defined(PKG_USING_LITTLEVGL2RTT) + extern void littlevgl2rtt_send_input_event(rt_int16_t x, rt_int16_t y, rt_uint8_t state); + littlevgl2rtt_send_input_event(touch_point.x_coordinate, touch_point.y_coordinate, touch_point.event); +#endif +#if defined(PKG_USING_NUEMWIN) + extern void nuemwin_send_input_event(rt_int16_t x, rt_int16_t y, rt_uint8_t state); + nuemwin_send_input_event(touch_point.x_coordinate, touch_point.y_coordinate, touch_point.event); +#endif + rt_kprintf("[%d-%d] id=%d width=%d x=%d y=%d\n", + touch_point.timestamp, + touch_point.event, + touch_point.track_id, + touch_point.width, + touch_point.x_coordinate, + touch_point.y_coordinate); + } + } + } + + result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_OFF, RT_NULL); + RT_ASSERT(result == RT_EOK); + + result = rt_device_close(pdev); + RT_ASSERT(result == RT_EOK); +} + + +/* Support "nu_touch_start" command line in msh mode */ +static rt_err_t nu_touch_start(int argc, char **argv) +{ + if (adc_touch_thread == RT_NULL) + { + adc_touch_thread = rt_thread_create("adc_touch_thread", + adc_touch_entry, + RT_NULL, + 1024, + 25, + 5); + adc_touch_worker_run = 1; + if (adc_touch_thread != RT_NULL) + rt_thread_startup(adc_touch_thread); + } + return 0; +} +MSH_CMD_EXPORT(nu_touch_start, e.g: start adc touch); + +/* Support "nu_touch_stop" command line in msh mode */ +static rt_err_t nu_touch_stop(int argc, char **argv) +{ + adc_touch_worker_run = 0; + adc_touch_thread = RT_NULL; + return 0; +} +MSH_CMD_EXPORT(nu_touch_stop, e.g: stop adc touch); + +#endif //#if defined(BSP_USING_ADC_TOUCH) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_can.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_can.c new file mode 100644 index 0000000000000000000000000000000000000000..a4da2879cf9929ac27ab850f34674e8209678918 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_can.c @@ -0,0 +1,544 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_CAN) + +#include +#include +#include "NuMicro.h" +#include + +/* Private Define ---------------------------------------------------------------*/ +#define RX_MSG_ID_INDEX 16 +#define IS_CAN_STDID(STDID) ((STDID) <= 0x7FFU) +#define IS_CAN_EXTID(EXTID) ((EXTID) <= 0x1FFFFFFFU) +#define IS_CAN_DLC(DLC) ((DLC) <= 8U) + +/* Default config for serial_configure structure */ +#define NU_CAN_CONFIG_DEFAULT \ +{ \ + CAN1MBaud, /* 1M bits/s */ \ + RT_CANMSG_BOX_SZ, /* message box max size */ \ + RT_CANSND_BOX_NUM, /* message box number */ \ + RT_CAN_MODE_NORMAL, /* Normal mode */ \ + 0, /* privmode */ \ + 0, /* reserved */ \ + 100, /* Timeout Tick */ \ +} + +enum +{ + CAN_START = -1, +#if defined(BSP_USING_CAN0) + CAN0_IDX, +#endif +#if defined(BSP_USING_CAN1) + CAN1_IDX, +#endif + CAN_CNT, +}; + +/* Private Typedef --------------------------------------------------------------*/ +struct nu_can +{ + struct rt_can_device dev; + char *name; + CAN_T *base; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; +}; +typedef struct nu_can *nu_can_t; + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_can_configure(struct rt_can_device *can, struct can_configure *cfg); +static rt_err_t nu_can_control(struct rt_can_device *can, int cmd, void *arg); +static int nu_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno); +static int nu_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno); +static void nu_can_isr(int vector, void *param); + +static struct nu_can nu_can_arr[] = +{ +#if defined(BSP_USING_CAN0) + { + .name = "can0", + .base = CAN0, + .irqn = IRQ_CAN0, + .rstidx = CAN0RST, + .clkidx = CAN0CKEN, + }, +#endif +#if defined(BSP_USING_CAN1) + { + .name = "can1", + .base = CAN1, + .irqn = IRQ_CAN1, + .rstidx = CAN1RST, + .clkidx = CAN1CKEN, + }, +#endif +}; /* struct nu_can */ + +/* Public functions ------------------------------------------------------------*/ + +/* Private variables ------------------------------------------------------------*/ +static const struct rt_can_ops nu_can_ops = +{ + .configure = nu_can_configure, + .control = nu_can_control, + .sendmsg = nu_can_sendmsg, + .recvmsg = nu_can_recvmsg, +}; + +static const struct can_configure nu_can_default_config = NU_CAN_CONFIG_DEFAULT; + +/* Interrupt Handle Function ----------------------------------------------------*/ +static void nu_can_isr(int vector, void *param) +{ + uint32_t u32IIDRstatus; + nu_can_t psNuCAN = (nu_can_t)param; + + /* Get base address of CAN register */ + CAN_T *base = psNuCAN->base; + + /* Get interrupt event */ + u32IIDRstatus = CAN_GET_INT_PENDING_STATUS(base); + + if (u32IIDRstatus == 0x00008000) /* Check Status Interrupt Flag (Error status Int and Status change Int) */ + { + /**************************/ + /* Status Change interrupt*/ + /**************************/ + if (base->STATUS & CAN_STATUS_TXOK_Msk) + { + base->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/ + //rt_kprintf("%s: TX\n", psNuCAN->name) ; +#ifndef RT_CAN_USING_HDR + /* Using as Lisen,Loopback,Loopback+Lisen mode*/ + rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_TX_DONE); +#endif + } + + if (base->STATUS & CAN_STATUS_RXOK_Msk) + { + base->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/ + //rt_kprintf("%s: RX\n", psNuCAN->name) ; +#ifndef RT_CAN_USING_HDR + /* Using as Lisen,Loopback,Loopback+Lisen mode*/ + rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_RX_IND); +#endif + } + + /**************************/ + /* Error Status interrupt */ + /**************************/ + if (base->STATUS & CAN_STATUS_EWARN_Msk) + { + rt_kprintf("%s: EWARN\n", psNuCAN->name) ; + } + + if (base->STATUS & CAN_STATUS_BOFF_Msk) + { + rt_kprintf("%s: BUSOFF\n", psNuCAN->name) ; + + /* Do Init to release busoff pin */ + base->CON = (CAN_CON_INIT_Msk | CAN_CON_CCE_Msk); + base->CON &= (~(CAN_CON_INIT_Msk | CAN_CON_CCE_Msk)); + while (base->CON & CAN_CON_INIT_Msk); + } + + if (base->STATUS & CAN_STATUS_LEC_Msk) + { + rt_kprintf("[%s] Last Error Code %03x\n", psNuCAN->name, base->STATUS & CAN_STATUS_LEC_Msk) ; + } + + } +#ifdef RT_CAN_USING_HDR + /*IntId: 0x0001-0x0020, Number of Message Object which caused the interrupt.*/ + else if (u32IIDRstatus > 0 && u32IIDRstatus <= 32) + { + /*Message RAM 0~RX_MSG_ID_INDEX for CAN Tx using*/ + if (u32IIDRstatus <= RX_MSG_ID_INDEX) + { + //rt_kprintf("[%s-Tx]IntId = %d\n", psNuCAN->name, u32IIDRstatus); + rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_TX_DONE); + } + else /*Message RAM RX_MSG_ID_INDEX~31 for CAN Rx using*/ + { + //rt_kprintf("[%s-Rx]IntId = %d\n", psNuCAN->name, u32IIDRstatus); + rt_hw_can_isr(&psNuCAN->dev, (RT_CAN_EVENT_RX_IND | ((u32IIDRstatus - 1) << 8))); + } + CAN_CLR_INT_PENDING_BIT(base, (u32IIDRstatus - 1)); /* Clear Interrupt Pending */ + } +#endif + +} + + +static rt_err_t nu_can_configure(struct rt_can_device *can, struct can_configure *cfg) +{ + nu_can_t psNuCAN = (nu_can_t)can; + + RT_ASSERT(can != RT_NULL); + RT_ASSERT(cfg != RT_NULL); + + /* Get base address of CAN register */ + CAN_T *base = psNuCAN->base; + + RT_ASSERT(base != RT_NULL); + + switch (cfg->mode) + { + /* CAN default Normal mode */ + case RT_CAN_MODE_NORMAL: + can->config.mode = CAN_NORMAL_MODE; + break; + case RT_CAN_MODE_LISEN: + can->config.mode = RT_CAN_MODE_LISEN; + break; + case RT_CAN_MODE_LOOPBACK: + can->config.mode = RT_CAN_MODE_LOOPBACK; + break; + case RT_CAN_MODE_LOOPBACKANLISEN: + can->config.mode = RT_CAN_MODE_LOOPBACKANLISEN; + break; + default: + rt_kprintf("Unsupported Operating mode"); + goto exit_nu_can_configure; + } + + nu_sys_ip_reset(psNuCAN->rstidx); + + /*Set the CAN Bit Rate and Operating mode*/ + if (CAN_Open(base, can->config.baud_rate, can->config.mode) < 1) + return -(RT_ERROR); + + + switch (cfg->mode) + { + /* CAN default Normal mode */ + case RT_CAN_MODE_NORMAL: +#ifdef RT_CAN_USING_HDR + CAN_LeaveTestMode(base); +#else + CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk); +#endif + break; + case RT_CAN_MODE_LISEN: + CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_SILENT_Msk); + break; + case RT_CAN_MODE_LOOPBACK: + CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_LBACK_Msk); + break; + case RT_CAN_MODE_LOOPBACKANLISEN: + CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_SILENT_Msk | CAN_TEST_LBACK_Msk); + break; + default: + rt_kprintf("Unsupported Operating mode"); + goto exit_nu_can_configure; + } + + + return RT_EOK; + +exit_nu_can_configure: + + CAN_Close(base); + + return -(RT_ERROR); +} + +static rt_err_t nu_can_control(struct rt_can_device *can, int cmd, void *arg) +{ + rt_uint32_t argval; + nu_can_t psNuCAN = (nu_can_t)can; + +#ifdef RT_CAN_USING_HDR + struct rt_can_filter_config *filter_cfg; +#endif + /* Get base address of CAN register */ + CAN_T *base = psNuCAN->base; + + RT_ASSERT(base != RT_NULL); + /* Check baud rate */ + RT_ASSERT(can->config.baud_rate != 0); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + argval = (rt_uint32_t) arg; + if ((argval == RT_DEVICE_FLAG_INT_RX) || (argval == RT_DEVICE_FLAG_INT_TX)) + { + /* Disable NVIC interrupt. */ + rt_hw_interrupt_mask(psNuCAN->irqn); + + /* Disable Status Change Interrupt */ + CAN_DisableInt(base, CAN_CON_IE_Msk | CAN_CON_SIE_Msk); + + } + else if (argval == RT_DEVICE_CAN_INT_ERR) + { + /* Disable interrupt. */ + rt_hw_interrupt_mask(psNuCAN->irqn); + + /* Disable Error Interrupt */ + CAN_DisableInt(base, CAN_CON_EIE_Msk); + } + break; + + case RT_DEVICE_CTRL_SET_INT: + argval = (rt_uint32_t) arg; + if (argval == RT_DEVICE_FLAG_INT_RX || (argval == RT_DEVICE_FLAG_INT_TX)) + { + /* Enable Status Change Interrupt */ + CAN_EnableInt(base, CAN_CON_IE_Msk | CAN_CON_SIE_Msk); + + /* Enable interrupt. */ + rt_hw_interrupt_umask(psNuCAN->irqn); + } + else if (argval == RT_DEVICE_CAN_INT_ERR) + { + /* Enable Error Status and Status Change Interrupt */ + CAN_EnableInt(base, CAN_CON_IE_Msk | CAN_CON_SIE_Msk | CAN_CON_EIE_Msk); + + /* Enable interrupt. */ + rt_hw_interrupt_umask(psNuCAN->irqn); + } + break; + +#ifdef RT_CAN_USING_HDR + case RT_CAN_CMD_SET_FILTER: + filter_cfg = (struct rt_can_filter_config *)arg; + + for (int i = 0; i < filter_cfg->count; i++) + { + + /*set the filter message object*/ + if (filter_cfg->items[i].mode == 1) + { + if (CAN_SetRxMsgObjAndMsk(base, MSG(filter_cfg->items[i].hdr + RX_MSG_ID_INDEX), filter_cfg->items[i].ide, filter_cfg->items[i].id, filter_cfg->items[i].mask, FALSE) == FALSE) + { + return -(RT_ERROR); + } + } + else + { + /*set the filter message object*/ + if (CAN_SetRxMsgAndMsk(base, MSG(filter_cfg->items[i].hdr + RX_MSG_ID_INDEX), filter_cfg->items[i].ide, filter_cfg->items[i].id, filter_cfg->items[i].mask) == FALSE) + { + return -(RT_ERROR); + } + } + } + break; +#endif + + case RT_CAN_CMD_SET_MODE: + argval = (rt_uint32_t) arg; + if (argval != RT_CAN_MODE_NORMAL && argval != RT_CAN_MODE_LISEN && + argval != RT_CAN_MODE_LOOPBACK && argval != RT_CAN_MODE_LOOPBACKANLISEN) + { + return -(RT_ERROR); + } + if (argval != can->config.mode) + { + can->config.mode = argval; + return nu_can_configure(can, &can->config); + } + break; + + case RT_CAN_CMD_SET_BAUD: + argval = (rt_uint32_t) arg; + if (argval != CAN1MBaud && argval != CAN800kBaud && argval != CAN500kBaud && argval != CAN250kBaud && + argval != CAN125kBaud && argval != CAN100kBaud && argval != CAN50kBaud && argval != CAN20kBaud && argval != CAN10kBaud) + { + return -(RT_ERROR); + } + if (argval != can->config.baud_rate) + { + can->config.baud_rate = argval; + return nu_can_configure(can, &can->config); + } + break; + + case RT_CAN_CMD_SET_PRIV: + argval = (rt_uint32_t) arg; + if (argval != RT_CAN_MODE_PRIV && argval != RT_CAN_MODE_NOPRIV) + { + return -(RT_ERROR); + } + if (argval != can->config.privmode) + { + can->config.privmode = argval; + return nu_can_configure(can, &can->config); + } + break; + + case RT_CAN_CMD_GET_STATUS: + { + rt_uint32_t errtype; + errtype = base->ERR; + /*Receive Error Counter*/ + can->status.rcverrcnt = (errtype >> 8); + /*Transmit Error Counter*/ + can->status.snderrcnt = ((errtype >> 24) & 0xFF); + can->status.lasterrtype = CAN_GET_INT_STATUS(base) & 0x8000; + /*status error code*/ + can->status.errcode = CAN_GET_INT_STATUS(base) & 0x07; + rt_memcpy(arg, &can->status, sizeof(can->status)); + } + break; + + default: + return -(RT_EINVAL); + + } + + return RT_EOK; +} + +static int nu_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno) +{ + STR_CANMSG_T tMsg; + struct rt_can_msg *pmsg = (struct rt_can_msg *) buf; + + /* Get base address of CAN register */ + CAN_T *base = ((nu_can_t)can)->base; + + RT_ASSERT(base != RT_NULL); + RT_ASSERT(buf != RT_NULL); + + /* Check the parameters */ + RT_ASSERT(IS_CAN_DLC(pmsg->len)); + + /* Standard ID (11 bits)*/ + if (pmsg->ide == RT_CAN_STDID) + { + tMsg.IdType = CAN_STD_ID; + RT_ASSERT(IS_CAN_STDID(pmsg->id)) + tMsg.Id = pmsg->id ; + } + else + { + /* Extended ID (29 bits)*/ + tMsg.IdType = CAN_EXT_ID; + RT_ASSERT(IS_CAN_EXTID(pmsg->id)); + tMsg.Id = pmsg->id ; + } + + if (pmsg->rtr == RT_CAN_DTR) + { + /* Data frame */ + tMsg.FrameType = CAN_DATA_FRAME; + } + else + { + /* Remote frame */ + tMsg.FrameType = CAN_REMOTE_FRAME; + } + tMsg.DLC = pmsg->len; + rt_memcpy(tMsg.Data, pmsg->data, pmsg->len); + + if (CAN_Transmit(base, MSG(boxno), &tMsg) == FALSE) // Configure Msg RAM and send the Msg in the RAM + { + return -(RT_ERROR); + } + + return RT_EOK; +} +static int nu_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno) +{ + STR_CANMSG_T tMsg; + struct rt_can_msg *pmsg = (struct rt_can_msg *) buf; + /* Get base address of CAN register */ + CAN_T *base = ((nu_can_t)can)->base; + + RT_ASSERT(base != RT_NULL); + RT_ASSERT(buf != RT_NULL); + + /* get data */ + if (CAN_Receive(base, boxno, &tMsg) == FALSE) + { + rt_kprintf("No available RX Msg.\n"); + return -(RT_ERROR); + } + +#ifdef RT_CAN_USING_HDR + /* Hardware filter messages are valid */ + pmsg->hdr = boxno - RX_MSG_ID_INDEX; + can->hdr[pmsg->hdr].connected = 1; +#endif + + /* Standard ID (11 bits)*/ + if (tMsg.IdType == CAN_STD_ID) + { + pmsg->ide = RT_CAN_STDID; + pmsg->id = tMsg.Id; + } + else /* Extended ID (29 bits)*/ + { + pmsg->ide = RT_CAN_EXTID; + pmsg->id = tMsg.Id; + } + + if (tMsg.FrameType == CAN_DATA_FRAME) + { + /* Data frame */ + pmsg->rtr = RT_CAN_DTR; + } + else + { + /* Remote frame */ + pmsg->rtr = RT_CAN_RTR; + } + + pmsg->len = tMsg.DLC ; + + rt_memcpy(pmsg->data, tMsg.Data, pmsg->len); + + return RT_EOK; +} + +/** + * Hardware CAN Initialization + */ +static int rt_hw_can_init(void) +{ + int i; + rt_err_t ret = RT_EOK; + + for (i = (CAN_START + 1); i < CAN_CNT; i++) + { + nu_can_arr[i].dev.config = nu_can_default_config; + +#ifdef RT_CAN_USING_HDR + nu_can_arr[i].dev.config.maxhdr = RT_CANMSG_BOX_SZ; +#endif + + /* Register CAN ISR */ + rt_hw_interrupt_install(nu_can_arr[i].irqn, nu_can_isr, &nu_can_arr[i], nu_can_arr[i].name); + + /* Enable IP engine clock */ + nu_sys_ipclk_enable(nu_can_arr[i].clkidx); + + /* Register can device */ + ret = rt_hw_can_register(&nu_can_arr[i].dev, nu_can_arr[i].name, &nu_can_ops, NULL); + RT_ASSERT(ret == RT_EOK); + } + + return (int)ret; +} +INIT_DEVICE_EXPORT(rt_hw_can_init); + +#endif //#if defined(BSP_USING_CAN) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c new file mode 100644 index 0000000000000000000000000000000000000000..b96c9b7b04df87a1f43a437091af7e3baacfb82b --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.c @@ -0,0 +1,78 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-11-11 Wayne First version +* +******************************************************************************/ + +#include +#include +#include "board.h" +#include "drv_uart.h" +#include "drv_sys.h" + +#if defined(BSP_USING_MMU) +static struct mem_desc hw_mem_desc[] = +{ + { 0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB }, /* None cached for 4G memory */ + { 0x00000000, BOARD_SDRAM_SIZE - 1, 0x00000000, RW_CB }, /* 64M cached DDR memory */ + { BIT31, (BIT31 | BOARD_SDRAM_SIZE) - 1, BIT31, RW_NCNB }, /* Shadow DDR Map */ + { 0x3C000000, 0x3C00E000 - 1, 0x3C000000, RW_NCNB }, /* 56K SRAM memory */ + { 0xBC000000, 0xBC00E000 - 1, 0xBC000000, RW_NCNB } /* 56K Shadow memory */ +}; +#endif + +/** + * This function will initial M487 board. + */ +RT_WEAK void rt_hw_board_init(void) +{ + /* initialize base clock */ + nu_clock_base_init(); + + /* initialize peripheral pin function */ + nu_pin_init(); + +#if defined(BSP_USING_MMU) + /* initialize mmu */ + rt_hw_mmu_init(&hw_mem_desc[0], sizeof(hw_mem_desc) / sizeof(hw_mem_desc[0])); +#else + /* disable I/D cache */ + mmu_disable_dcache(); + mmu_disable_icache(); + mmu_disable(); + mmu_invalidate_tlb(); +#endif + + /* initialize hardware interrupt */ + rt_hw_interrupt_init(); + + /* initialize systick */ + rt_hw_systick_init(); + +#ifdef RT_USING_HEAP + /* init memory system */ + rt_system_heap_init((void *)BOARD_HEAP_START, (void *)BOARD_HEAP_END); +#endif + + /* initialize uart */ + rt_hw_uart_init(); + +#ifdef RT_USING_CONSOLE + rt_console_set_device(RT_CONSOLE_DEVICE_NAME); +#endif + +#ifdef RT_USING_COMPONENTS_INIT + rt_components_board_init(); +#endif + +#ifdef RT_USING_HEAP + /* Dump heap information */ + rt_kprintf("Heap: Begin@%08x, END@%08x, SIZE:%d\n", BOARD_HEAP_START, BOARD_HEAP_END, (rt_uint32_t)BOARD_HEAP_END - (rt_uint32_t)BOARD_HEAP_START); +#endif +} diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.h new file mode 100644 index 0000000000000000000000000000000000000000..f971f871c17830308a0be42cf9ee42bbcc902b5e --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_common.h @@ -0,0 +1,20 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#ifndef __DRV_COMMON_H__ +#define __DRV_COMMON_H__ + +#include + +void nu_clock_base_dump(void); + +#endif /* __DRV_UART_H__ */ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_crypto.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_crypto.c new file mode 100644 index 0000000000000000000000000000000000000000..83f62e49cce2ca9a74f4132df746badfa798a8b9 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_crypto.c @@ -0,0 +1,996 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-4-22 Wayne First version +* +******************************************************************************/ + +#include + +#if (defined(BSP_USING_CRYPTO) && defined(RT_USING_HWCRYPTO)) + +#include +#include +#include +#include "NuMicro.h" +#include "drv_sys.h" +#include + +/* Private typedef --------------------------------------------------------------*/ +#define CACHE_LINE_SIZE 32 + +typedef struct +{ + uint8_t *pu8SHATempBuf; + uint32_t u32SHATempBufLen; + uint32_t u32DMAMode; + uint32_t u32BlockSize; +} S_SHA_CONTEXT; + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_hwcrypto_create(struct rt_hwcrypto_ctx *ctx); +static void nu_hwcrypto_destroy(struct rt_hwcrypto_ctx *ctx); +static rt_err_t nu_hwcrypto_clone(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src); +static void nu_hwcrypto_reset(struct rt_hwcrypto_ctx *ctx); + +/* Private variables ------------------------------------------------------------*/ +static const struct rt_hwcrypto_ops nu_hwcrypto_ops = +{ + .create = nu_hwcrypto_create, + .destroy = nu_hwcrypto_destroy, + .copy = nu_hwcrypto_clone, + .reset = nu_hwcrypto_reset, +}; + +/* Crypto engine operation ------------------------------------------------------------*/ + +#define NU_HWCRYPTO_DES_3KEYS 1 +#define NU_HWCRYPTO_DES_NO3KEYS 0 +#define NU_HWCRYPTO_AES_NAME "nu_AES" +#define NU_HWCRYPTO_TDES_NAME "nu_TDES" +#define NU_HWCRYPTO_SHA_NAME "nu_SHA" +#define NU_HWCRYPTO_PRNG_NAME "nu_PRNG" + +static struct rt_mutex s_AES_mutex; +static struct rt_mutex s_TDES_mutex; +static struct rt_mutex s_SHA_mutex; + +static struct rt_mutex s_PRNG_mutex; + +//Crypto engine IRQ handler +static void nu_crypto_isr(int vector, void *param) +{ + if (TDES_GET_INT_FLAG()) + { + TDES_CLR_INT_FLAG(); + } +} + +static rt_err_t nu_aes_crypt_run( + rt_bool_t bEncrypt, + uint32_t u32OpMode, + uint8_t *pu8Key, + uint32_t u32KeySize, + uint8_t *pu8IV, + uint8_t *pu8InData, + uint8_t *pu8OutData, + uint32_t u32DataLen +) +{ + uint32_t au32SwapKey[8]; + uint32_t au32SwapIV[4]; + rt_err_t result; + + au32SwapKey[0] = nu_get32_be(&pu8Key[0]); + au32SwapKey[1] = nu_get32_be(&pu8Key[4]); + au32SwapKey[2] = nu_get32_be(&pu8Key[8]); + au32SwapKey[3] = nu_get32_be(&pu8Key[12]); + + if ((u32KeySize == AES_KEY_SIZE_192) || (u32KeySize == AES_KEY_SIZE_256)) + { + au32SwapKey[4] = nu_get32_be(&pu8Key[16]); + au32SwapKey[5] = nu_get32_be(&pu8Key[20]); + } + + if (u32KeySize == AES_KEY_SIZE_256) + { + au32SwapKey[6] = nu_get32_be(&pu8Key[24]); + au32SwapKey[7] = nu_get32_be(&pu8Key[28]); + } + + au32SwapIV[0] = nu_get32_be(&pu8IV[0]); + au32SwapIV[1] = nu_get32_be(&pu8IV[4]); + au32SwapIV[2] = nu_get32_be(&pu8IV[8]); + au32SwapIV[3] = nu_get32_be(&pu8IV[12]); + + result = rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + //Using Channel 0 + AES_Open(0, bEncrypt, u32OpMode, u32KeySize, AES_IN_OUT_SWAP); + AES_SetKey(0, (uint32_t *)au32SwapKey, u32KeySize); + AES_SetInitVect(0, (uint32_t *)au32SwapIV); + + //Setup AES DMA + AES_SetDMATransfer(0, (uint32_t)pu8InData, (uint32_t)pu8OutData, u32DataLen); +#if defined(BSP_USING_MMU) + /* Writeback data in dcache to memory before transferring. */ + { + /* Flush Src buffer into memory. */ + if (pu8InData) + mmu_clean_invalidated_dcache((uint32_t)pu8InData, u32DataLen); + + /* Flush Dst buffer into memory. */ + if (pu8OutData) + mmu_clean_invalidated_dcache((uint32_t)pu8OutData, u32DataLen); + } +#endif + + /* Clear AES interrupt status */ + AES_CLR_INT_FLAG(); + + /* Start AES encryption/decryption */ + AES_Start(0, CRYPTO_DMA_ONE_SHOT); + + /* Wait done */ + while (!(CRPT->INTSTS & CRPT_INTEN_AESIEN_Msk)) {}; + + if ((u32DataLen % 16) && (CRPT->AES_STS & (CRPT_AES_STS_OUTBUFEMPTY_Msk | CRPT_AES_STS_INBUFEMPTY_Msk))) + rt_kprintf("AES WARNING - AES Data length(%d) is not enough. -> %d \n", u32DataLen, RT_ALIGN(u32DataLen, 16)); + else if (CRPT->INTSTS & (CRPT_INTSTS_AESERRIF_Msk) || (CRPT->AES_STS & (CRPT_AES_STS_BUSERR_Msk | CRPT_AES_STS_CNTERR_Msk))) + rt_kprintf("AES ERROR - CRPT->INTSTS-%08x, CRPT->AES_STS-%08x\n", CRPT->INTSTS, CRPT->AES_STS); + + /* Clear AES interrupt status */ + AES_CLR_INT_FLAG(); + + result = rt_mutex_release(&s_AES_mutex); + RT_ASSERT(result == RT_EOK); + + return RT_EOK; +} + +static void nu_prng_open(uint32_t u32Seed) +{ + rt_err_t result; + + result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + //Open PRNG 64 bits. But always return 32 bits + PRNG_Open(PRNG_KEY_SIZE_64, PRNG_SEED_RELOAD, u32Seed); + + result = rt_mutex_release(&s_PRNG_mutex); + RT_ASSERT(result == RT_EOK); +} + +static rt_uint32_t nu_prng_run(void) +{ + uint32_t au32RNGValue[2]; + rt_err_t result; + static uint32_t s_u32PRNG_Counter = 0; + result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + +#if !defined(NU_PRNG_USE_SEED) + nu_prng_open(rt_tick_get() + s_u32PRNG_Counter++); +#endif + + PRNG_Start(); + while ((CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)) {}; + + /* Clear PRNG interrupt status */ + PRNG_CLR_INT_FLAG(); + + PRNG_Read(&au32RNGValue[0]); + + result = rt_mutex_release(&s_PRNG_mutex); + RT_ASSERT(result == RT_EOK); + + return au32RNGValue[0]; +} + +static rt_err_t nu_aes_crypt(struct hwcrypto_symmetric *symmetric_ctx, struct hwcrypto_symmetric_info *symmetric_info) +{ + uint32_t u32AESOpMode; + uint32_t u32AESKeySize; + unsigned char *in, *out; + unsigned char in_align_flag = 0; + unsigned char out_align_flag = 0; + unsigned char iv_temp[16]; + RT_ASSERT(symmetric_ctx != RT_NULL); + RT_ASSERT(symmetric_info != RT_NULL); + + if ((symmetric_info->length % 4) != 0) + { + return -RT_EINVAL; + } + + //Checking key length + if (symmetric_ctx->key_bitlen == 128) + { + u32AESKeySize = AES_KEY_SIZE_128; + } + else if (symmetric_ctx->key_bitlen == 192) + { + u32AESKeySize = AES_KEY_SIZE_192; + } + else if (symmetric_ctx->key_bitlen == 256) + { + u32AESKeySize = AES_KEY_SIZE_256; + } + else + { + return -RT_EINVAL; + } + + //Select AES operation mode + switch (symmetric_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK)) + { + case HWCRYPTO_TYPE_AES_ECB: + u32AESOpMode = AES_MODE_ECB; + break; + case HWCRYPTO_TYPE_AES_CBC: + u32AESOpMode = AES_MODE_CBC; + break; + case HWCRYPTO_TYPE_AES_CFB: + u32AESOpMode = AES_MODE_CFB; + break; + case HWCRYPTO_TYPE_AES_OFB: + u32AESOpMode = AES_MODE_OFB; + break; + case HWCRYPTO_TYPE_AES_CTR: + u32AESOpMode = AES_MODE_CTR; + break; + default : + return -RT_ERROR; + } + + in = (unsigned char *)symmetric_info->in; + out = (unsigned char *)symmetric_info->out; + + //Checking in/out data buffer address not alignment + if (((rt_uint32_t)in % CACHE_LINE_SIZE) != 0) + { + in = rt_malloc_align(symmetric_info->length, CACHE_LINE_SIZE); + if (in == RT_NULL) + { + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, symmetric_info->length); + return -RT_ENOMEM; + } + + rt_memcpy(in, symmetric_info->in, symmetric_info->length); + in_align_flag = 1; + } + + if (((rt_uint32_t)out % CACHE_LINE_SIZE) != 0) + { + out = rt_malloc_align(symmetric_info->length, CACHE_LINE_SIZE); + if (out == RT_NULL) + { + if (in_align_flag) + rt_free_align(in); + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, symmetric_info->length); + return -RT_ENOMEM; + } + + out_align_flag = 1; + } + + if ((u32AESOpMode == AES_MODE_CBC) && (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT)) + { + uint32_t loop; + + loop = (symmetric_info->length - 1) / 16; + rt_memcpy(iv_temp, in + (loop * 16), 16); + } + + nu_aes_crypt_run(symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT ? TRUE : FALSE, u32AESOpMode, symmetric_ctx->key, u32AESKeySize, symmetric_ctx->iv, in, out, symmetric_info->length); + + if (u32AESOpMode == AES_MODE_CBC) + { + if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT) + { + rt_memcpy(symmetric_ctx->iv, iv_temp, 16); + } + else + { + uint32_t loop; + + loop = (symmetric_info->length - 1) / 16; + rt_memcpy(symmetric_ctx->iv, out + (loop * 16), 16); + } + } + + if (out_align_flag) + { + rt_memcpy(symmetric_info->out, out, symmetric_info->length); + rt_free_align(out); + } + + if (in_align_flag) + { + rt_free_align(in); + } + + return RT_EOK; +} + +static rt_err_t nu_des_crypt_run( + rt_bool_t bEncrypt, + uint32_t u32OpMode, + uint8_t *pu8Key, + uint32_t u32KeySize, + uint8_t *pu8IV, + uint8_t *pu8InData, + uint8_t *pu8OutData, + uint32_t u32DataLen +) +{ + rt_err_t result; + + uint32_t au32SwapKey[3][2]; + uint32_t au32SwapIV[2]; + + au32SwapKey[0][0] = nu_get32_be(&pu8Key[0]); + au32SwapKey[0][1] = nu_get32_be(&pu8Key[4]); + au32SwapKey[1][0] = nu_get32_be(&pu8Key[8]); + au32SwapKey[1][1] = nu_get32_be(&pu8Key[12]); + + if (u32KeySize == NU_HWCRYPTO_DES_3KEYS) + { + au32SwapKey[2][0] = nu_get32_be(&pu8Key[16]); + au32SwapKey[2][1] = nu_get32_be(&pu8Key[20]); + } + + au32SwapIV[0] = nu_get32_be(&pu8IV[0]); + au32SwapIV[1] = nu_get32_be(&pu8IV[4]); + + result = rt_mutex_take(&s_TDES_mutex, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + //Using Channel 0 + TDES_Open(0, bEncrypt, (u32OpMode & CRPT_TDES_CTL_TMODE_Msk), u32KeySize, u32OpMode, TDES_IN_OUT_WHL_SWAP); + TDES_SetKey(0, au32SwapKey); + TDES_SetInitVect(0, au32SwapIV[0], au32SwapIV[1]); + + //Setup TDES DMA + TDES_SetDMATransfer(0, (uint32_t)pu8InData, (uint32_t)pu8OutData, u32DataLen); + +#if defined(BSP_USING_MMU) + /* Writeback data in dcache to memory before transferring. */ + { + /* Flush Src buffer into memory. */ + if (pu8InData) + mmu_clean_invalidated_dcache((uint32_t)pu8InData, u32DataLen); + + /* Flush Dst buffer into memory. */ + if (pu8OutData) + mmu_clean_invalidated_dcache((uint32_t)pu8OutData, u32DataLen); + } +#endif + + TDES_CLR_INT_FLAG(); + + //Start TDES encryption/decryption + TDES_Start(0, CRYPTO_DMA_ONE_SHOT); + + /* Wait done */ + while (!(CRPT->INTSTS & CRPT_INTEN_TDESIEN_Msk)) {}; + + if ((u32DataLen % 16) && (CRPT->TDES_STS & (CRPT_TDES_STS_OUTBUFEMPTY_Msk | CRPT_TDES_STS_INBUFEMPTY_Msk))) + rt_kprintf("TDES WARNING - TDES Data length(%d) is not enough. -> %d \n", u32DataLen, RT_ALIGN(u32DataLen, 16)); + else if (CRPT->INTSTS & (CRPT_INTSTS_TDESERRIF_Msk) || (CRPT->TDES_STS & (CRPT_TDES_STS_BUSERR_Msk))) + rt_kprintf("AES ERROR - CRPT->INTSTS-%08x, CRPT->AES_STS-%08x\n", CRPT->INTSTS, CRPT->AES_STS); + + /* Clear TDES interrupt status */ + TDES_CLR_INT_FLAG(); + + result = rt_mutex_release(&s_TDES_mutex); + RT_ASSERT(result == RT_EOK); + + return RT_EOK; +} + +static rt_err_t nu_des_crypt(struct hwcrypto_symmetric *symmetric_ctx, struct hwcrypto_symmetric_info *symmetric_info) +{ + uint32_t u32DESOpMode; + uint32_t u32DESKeySize; + unsigned char *in, *out; + unsigned char in_align_flag = 0; + unsigned char out_align_flag = 0; + + if ((symmetric_info->length % 8) != 0) + { + return -RT_EINVAL; + } + + //Checking key length + if (symmetric_ctx->key_bitlen == 128 || symmetric_ctx->key_bitlen == 64) + { + u32DESKeySize = NU_HWCRYPTO_DES_NO3KEYS; + } + else if (symmetric_ctx->key_bitlen == 192) + { + u32DESKeySize = NU_HWCRYPTO_DES_3KEYS; + } + else + { + return -RT_EINVAL; + } + + //Select DES operation mode + switch (symmetric_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK)) + { + case HWCRYPTO_TYPE_DES_ECB: + u32DESOpMode = DES_MODE_ECB; + break; + case HWCRYPTO_TYPE_DES_CBC: + u32DESOpMode = DES_MODE_CBC; + break; + case HWCRYPTO_TYPE_3DES_ECB: + u32DESOpMode = TDES_MODE_ECB; + break; + case HWCRYPTO_TYPE_3DES_CBC: + u32DESOpMode = TDES_MODE_CBC; + break; + default : + return -RT_ERROR; + } + + in = (unsigned char *)symmetric_info->in; + out = (unsigned char *)symmetric_info->out; + + //Checking in/out data buffer address not alignment or out of SRAM + if (((rt_uint32_t)in % CACHE_LINE_SIZE) != 0) + { + in = rt_malloc_align(symmetric_info->length, CACHE_LINE_SIZE); + if (in == RT_NULL) + { + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, symmetric_info->length); + return -RT_ENOMEM; + } + + rt_memcpy(in, symmetric_info->in, symmetric_info->length); + in_align_flag = 1; + } + + if (((rt_uint32_t)out % CACHE_LINE_SIZE) != 0) + { + out = rt_malloc_align(symmetric_info->length, CACHE_LINE_SIZE); + if (out == RT_NULL) + { + if (in_align_flag) + rt_free_align(in); + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, symmetric_info->length); + return -RT_ENOMEM; + } + + out_align_flag = 1; + } + + nu_des_crypt_run(symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT ? TRUE : FALSE, u32DESOpMode, symmetric_ctx->key, u32DESKeySize, symmetric_ctx->iv, in, out, symmetric_info->length); + + if (out_align_flag) + { + rt_memcpy(symmetric_info->out, out, symmetric_info->length); + rt_free_align(out); + } + + if (in_align_flag) + { + rt_free_align(in); + } + + return RT_EOK; +} + +static void SHABlockUpdate(uint32_t u32OpMode, uint32_t u32SrcAddr, uint32_t u32Len, uint32_t u32Mode) +{ + SHA_Open(u32OpMode, SHA_IN_OUT_SWAP, 0); + + //Setup SHA DMA + SHA_SetDMATransfer(u32SrcAddr, u32Len); + + if (u32Mode == CRYPTO_DMA_FIRST) + { + u32Mode = CRYPTO_DMA_CONTINUE; + } + +#if defined(BSP_USING_MMU) + /* Writeback data in dcache to memory before transferring. */ + { + /* Flush Src buffer into memory. */ + if (u32SrcAddr) + mmu_clean_invalidated_dcache(u32SrcAddr, u32Len); + } +#endif + + //Start SHA + SHA_CLR_INT_FLAG(); + + SHA_Start(u32Mode); + + /* Wait done */ + while (!(CRPT->INTSTS & CRPT_INTSTS_SHAIF_Msk)) {}; + + if (CRPT->INTSTS & (CRPT_INTSTS_SHAERRIF_Msk) || (CRPT->HMAC_STS & (CRPT_HMAC_STS_DMAERR_Msk))) + rt_kprintf("SHA ERROR - CRPT->INTSTS-%08x, CRPT->HMAC_STS-%08x\n", CRPT->INTSTS, CRPT->HMAC_STS); + + /* Clear SHA interrupt status */ + SHA_CLR_INT_FLAG(); +} + +static rt_err_t nu_sha_hash_run( + S_SHA_CONTEXT *psSHACtx, + uint32_t u32OpMode, + uint8_t *pu8InData, + uint32_t u32DataLen +) +{ + rt_err_t result; + + RT_ASSERT(psSHACtx != RT_NULL); + RT_ASSERT(pu8InData != RT_NULL); + + result = rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + uint8_t *pu8SrcAddr = (uint8_t *)pu8InData; + uint32_t u32CopyLen = 0; + + while ((psSHACtx->u32SHATempBufLen + u32DataLen) > psSHACtx->u32BlockSize) + { + if (psSHACtx->pu8SHATempBuf) + { + if (psSHACtx->u32SHATempBufLen == psSHACtx->u32BlockSize) + { + //Trigger SHA block update + SHABlockUpdate(u32OpMode, (uint32_t)psSHACtx->pu8SHATempBuf, psSHACtx->u32BlockSize, psSHACtx->u32DMAMode); + + psSHACtx->u32DMAMode = CRYPTO_DMA_CONTINUE; + //free SHATempBuff + rt_free_align(psSHACtx->pu8SHATempBuf); + psSHACtx->pu8SHATempBuf = NULL; + psSHACtx->u32SHATempBufLen = 0; + continue; + } + else + { + u32CopyLen = psSHACtx->u32BlockSize - psSHACtx->u32SHATempBufLen; + if (u32DataLen < u32CopyLen) + u32CopyLen = u32DataLen; + rt_memcpy(psSHACtx->pu8SHATempBuf + psSHACtx->u32SHATempBufLen, pu8SrcAddr, u32CopyLen); + psSHACtx->u32SHATempBufLen += u32CopyLen; + pu8SrcAddr += u32CopyLen; + u32DataLen -= u32CopyLen; + continue; + } + } + + if ((uint32_t) pu8SrcAddr & (CACHE_LINE_SIZE - 1)) //address not aligned 32 + { + psSHACtx->pu8SHATempBuf = rt_malloc_align(psSHACtx->u32BlockSize, CACHE_LINE_SIZE); + + if (psSHACtx->pu8SHATempBuf == RT_NULL) + { + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize); + result = rt_mutex_release(&s_SHA_mutex); + RT_ASSERT(result == RT_EOK); + return -RT_ENOMEM; + } + + rt_memcpy(psSHACtx->pu8SHATempBuf, pu8SrcAddr, psSHACtx->u32BlockSize); + psSHACtx->u32SHATempBufLen = psSHACtx->u32BlockSize; + pu8SrcAddr += psSHACtx->u32BlockSize; + u32DataLen -= psSHACtx->u32BlockSize; + continue; + } + + //Trigger SHA block update + SHABlockUpdate(u32OpMode, (uint32_t)pu8SrcAddr, psSHACtx->u32BlockSize, psSHACtx->u32DMAMode); + + psSHACtx->u32DMAMode = CRYPTO_DMA_CONTINUE; + + pu8SrcAddr += psSHACtx->u32BlockSize; + u32DataLen -= psSHACtx->u32BlockSize; + } + + if (u32DataLen) + { + if (psSHACtx->pu8SHATempBuf == NULL) + { + psSHACtx->pu8SHATempBuf = rt_malloc_align(psSHACtx->u32BlockSize, CACHE_LINE_SIZE); + + if (psSHACtx->pu8SHATempBuf == RT_NULL) + { + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize); + result = rt_mutex_release(&s_SHA_mutex); + RT_ASSERT(result == RT_EOK); + return -RT_ENOMEM; + } + + psSHACtx->u32SHATempBufLen = 0; + } + + rt_memcpy(psSHACtx->pu8SHATempBuf, pu8SrcAddr, u32DataLen); + psSHACtx->u32SHATempBufLen += u32DataLen; + } + + result = rt_mutex_release(&s_SHA_mutex); + RT_ASSERT(result == RT_EOK); + + return RT_EOK; +} + +static rt_err_t nu_sha_update(struct hwcrypto_hash *hash_ctx, const rt_uint8_t *in, rt_size_t length) +{ + uint32_t u32SHAOpMode; + unsigned char *nu_in; + unsigned char in_align_flag = 0; + RT_ASSERT(hash_ctx != RT_NULL); + RT_ASSERT(in != RT_NULL); + + //Select SHA operation mode + switch (hash_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK)) + { + case HWCRYPTO_TYPE_SHA1: + u32SHAOpMode = SHA_MODE_SHA1; + break; + case HWCRYPTO_TYPE_SHA224: + u32SHAOpMode = SHA_MODE_SHA224; + break; + case HWCRYPTO_TYPE_SHA256: + u32SHAOpMode = SHA_MODE_SHA256; + break; + case HWCRYPTO_TYPE_SHA384: + u32SHAOpMode = SHA_MODE_SHA384; + break; + case HWCRYPTO_TYPE_SHA512: + u32SHAOpMode = SHA_MODE_SHA512; + break; + default : + return -RT_ERROR; + } + + nu_in = (unsigned char *)in; + + //Checking in data buffer address not alignment + if (((rt_uint32_t)nu_in % CACHE_LINE_SIZE) != 0) + { + nu_in = rt_malloc_align(length, CACHE_LINE_SIZE); + if (nu_in == RT_NULL) + { + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, length); + return -RT_ENOMEM; + } + + rt_memcpy(nu_in, in, length); + in_align_flag = 1; + } + + nu_sha_hash_run(hash_ctx->parent.contex, u32SHAOpMode, nu_in, length); + + if (in_align_flag) + { + rt_free_align(nu_in); + } + + return RT_EOK; +} + +static rt_err_t nu_sha_finish(struct hwcrypto_hash *hash_ctx, rt_uint8_t *out, rt_size_t length) +{ + unsigned char *nu_out; + unsigned char out_align_flag = 0; + uint32_t u32SHAOpMode; + S_SHA_CONTEXT *psSHACtx = RT_NULL; + RT_ASSERT(hash_ctx != RT_NULL); + RT_ASSERT(out != RT_NULL); + + psSHACtx = hash_ctx->parent.contex; + + //Check SHA Hash value buffer length + switch (hash_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK)) + { + case HWCRYPTO_TYPE_SHA1: + u32SHAOpMode = SHA_MODE_SHA1; + if (length < 5UL) + { + return -RT_EINVAL; + } + break; + case HWCRYPTO_TYPE_SHA224: + u32SHAOpMode = SHA_MODE_SHA224; + if (length < 7UL) + { + return -RT_EINVAL; + } + break; + case HWCRYPTO_TYPE_SHA256: + u32SHAOpMode = SHA_MODE_SHA256; + if (length < 8UL) + { + return -RT_EINVAL; + } + break; + case HWCRYPTO_TYPE_SHA384: + u32SHAOpMode = SHA_MODE_SHA384; + if (length < 12UL) + { + return -RT_EINVAL; + } + break; + case HWCRYPTO_TYPE_SHA512: + u32SHAOpMode = SHA_MODE_SHA512; + if (length < 16UL) + { + return -RT_EINVAL; + } + break; + default : + return -RT_ERROR; + } + + nu_out = (unsigned char *)out; + + //Checking out data buffer address alignment or not + if (((rt_uint32_t)nu_out % CACHE_LINE_SIZE) != 0) + { + nu_out = rt_malloc_align(length, CACHE_LINE_SIZE); + if (nu_out == RT_NULL) + { + LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, length); + return -RT_ENOMEM; + } + + out_align_flag = 1; + } + + if (psSHACtx->pu8SHATempBuf) + { + if (psSHACtx->u32DMAMode == CRYPTO_DMA_FIRST) + SHABlockUpdate(u32SHAOpMode, (uint32_t)psSHACtx->pu8SHATempBuf, psSHACtx->u32SHATempBufLen, CRYPTO_DMA_ONE_SHOT); + else + SHABlockUpdate(u32SHAOpMode, (uint32_t)psSHACtx->pu8SHATempBuf, psSHACtx->u32SHATempBufLen, CRYPTO_DMA_LAST); + + //free SHATempBuf + rt_free_align(psSHACtx->pu8SHATempBuf); + psSHACtx->pu8SHATempBuf = RT_NULL; + psSHACtx->u32SHATempBufLen = 0; + } + else + { + SHABlockUpdate(u32SHAOpMode, (uint32_t)NULL, 0, CRYPTO_DMA_LAST); + } + + SHA_Read((uint32_t *)nu_out); + + if (out_align_flag) + { + rt_memcpy(out, nu_out, length); + rt_free_align(nu_out); + } + + return RT_EOK; +} + +static rt_uint32_t nu_prng_rand(struct hwcrypto_rng *ctx) +{ + return nu_prng_run(); +} + +static const struct hwcrypto_symmetric_ops nu_aes_ops = +{ + .crypt = nu_aes_crypt, +}; + +static const struct hwcrypto_symmetric_ops nu_des_ops = +{ + .crypt = nu_des_crypt, +}; + +static const struct hwcrypto_hash_ops nu_sha_ops = +{ + .update = nu_sha_update, + .finish = nu_sha_finish, +}; + +static const struct hwcrypto_rng_ops nu_rng_ops = +{ + .update = nu_prng_rand, +}; + +/* Register crypto interface ----------------------------------------------------------*/ +static rt_err_t nu_hwcrypto_create(struct rt_hwcrypto_ctx *ctx) +{ + rt_err_t res = RT_EOK; + RT_ASSERT(ctx != RT_NULL); + + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + + case HWCRYPTO_TYPE_AES: + { + ctx->contex = RT_NULL; + //Setup AES operation + ((struct hwcrypto_symmetric *)ctx)->ops = &nu_aes_ops; + break; + } + + case HWCRYPTO_TYPE_DES: + { + ctx->contex = RT_NULL; + //Setup DES operation + ((struct hwcrypto_symmetric *)ctx)->ops = &nu_des_ops; + break; + } + + case HWCRYPTO_TYPE_3DES: + { + ctx->contex = RT_NULL; + //Setup 3DES operation + ((struct hwcrypto_symmetric *)ctx)->ops = &nu_des_ops; + break; + } + + + case HWCRYPTO_TYPE_SHA1: + { + ctx->contex = rt_malloc(sizeof(S_SHA_CONTEXT)); + + if (ctx->contex == RT_NULL) + return -RT_ERROR; + + rt_memset(ctx->contex, 0, sizeof(S_SHA_CONTEXT)); + //Setup SHA1 operation + ((struct hwcrypto_hash *)ctx)->ops = &nu_sha_ops; + break; + } + + case HWCRYPTO_TYPE_SHA2: + { + ctx->contex = rt_malloc(sizeof(S_SHA_CONTEXT)); + + if (ctx->contex == RT_NULL) + return -RT_ERROR; + + rt_memset(ctx->contex, 0, sizeof(S_SHA_CONTEXT)); + //Setup SHA2 operation + ((struct hwcrypto_hash *)ctx)->ops = &nu_sha_ops; + break; + } + + case HWCRYPTO_TYPE_RNG: + { + ctx->contex = RT_NULL; + ((struct hwcrypto_rng *)ctx)->ops = &nu_rng_ops; +#if defined(NU_PRNG_USE_SEED) + nu_prng_open(NU_PRNG_SEED_VALUE); +#endif + break; + } + + default: + res = -RT_ERROR; + break; + } + + return res; +} + +static void nu_hwcrypto_destroy(struct rt_hwcrypto_ctx *ctx) +{ + RT_ASSERT(ctx != RT_NULL); + + if (ctx->contex) + rt_free(ctx->contex); +} + +static rt_err_t nu_hwcrypto_clone(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src) +{ + rt_err_t res = RT_EOK; + RT_ASSERT(des != RT_NULL); + RT_ASSERT(src != RT_NULL); + + if (des->contex && src->contex) + { + rt_memcpy(des->contex, src->contex, sizeof(struct rt_hwcrypto_ctx)); + } + else + return -RT_EINVAL; + return res; +} + +static void nu_hwcrypto_reset(struct rt_hwcrypto_ctx *ctx) +{ + switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK) + { + case HWCRYPTO_TYPE_RNG: + { +#if defined(NU_PRNG_USE_SEED) + nu_prng_open(NU_PRNG_SEED_VALUE); +#else + nu_prng_open(rt_tick_get()); +#endif + break; + } + case HWCRYPTO_TYPE_SHA1: + case HWCRYPTO_TYPE_SHA2: + { + S_SHA_CONTEXT *psSHACtx = (S_SHA_CONTEXT *)ctx->contex; + + if (psSHACtx->pu8SHATempBuf) + { + rt_free_align(psSHACtx->pu8SHATempBuf); + } + + psSHACtx->pu8SHATempBuf = RT_NULL; + psSHACtx->u32SHATempBufLen = 0; + psSHACtx->u32DMAMode = CRYPTO_DMA_FIRST; + + if ((ctx->type == HWCRYPTO_TYPE_SHA384) || (ctx->type == HWCRYPTO_TYPE_SHA512)) + { + psSHACtx->u32BlockSize = 128; + } + else + { + psSHACtx->u32BlockSize = 64; + } + break; + } + + default: + break; + } +} + +/* Init and register nu_hwcrypto_dev */ + +int nu_hwcrypto_device_init(void) +{ + rt_err_t result; + static struct rt_hwcrypto_device nu_hwcrypto_dev; + + nu_hwcrypto_dev.ops = &nu_hwcrypto_ops; + nu_hwcrypto_dev.id = 0; + nu_hwcrypto_dev.user_data = &nu_hwcrypto_dev; + + nu_sys_ipclk_enable(CRYPTOCKEN); + nu_sys_ip_reset(CRYPTORST); + + /* init cipher mutex */ +#if defined(RT_HWCRYPTO_USING_AES) + result = rt_mutex_init(&s_AES_mutex, NU_HWCRYPTO_AES_NAME, RT_IPC_FLAG_PRIO); + RT_ASSERT(result == RT_EOK); + AES_ENABLE_INT(); +#endif + +#if defined(RT_HWCRYPTO_USING_SHA1) || defined(RT_HWCRYPTO_USING_SHA2) + result = rt_mutex_init(&s_SHA_mutex, NU_HWCRYPTO_SHA_NAME, RT_IPC_FLAG_PRIO); + RT_ASSERT(result == RT_EOK); + SHA_ENABLE_INT(); +#endif + +#if defined(RT_HWCRYPTO_USING_RNG) + result = rt_mutex_init(&s_PRNG_mutex, NU_HWCRYPTO_PRNG_NAME, RT_IPC_FLAG_PRIO); + RT_ASSERT(result == RT_EOK); + PRNG_ENABLE_INT(); +#endif + + /* register hwcrypto operation */ + result = rt_hwcrypto_register(&nu_hwcrypto_dev, RT_HWCRYPTO_DEFAULT_NAME); + RT_ASSERT(result == RT_EOK); + + /* Enable Crypto engine interrupt */ + rt_hw_interrupt_install(IRQ_CRPT, nu_crypto_isr, RT_NULL, "crypto"); + + return 0; +} +INIT_DEVICE_EXPORT(nu_hwcrypto_device_init); + +#endif //#if (defined(BSP_USING_CRYPTO) && defined(RT_USING_HWCRYPTO)) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_emac.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_emac.c new file mode 100644 index 0000000000000000000000000000000000000000..0ff6857fd03b17a794e4519b572e2031d87b2f46 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_emac.c @@ -0,0 +1,621 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_EMAC) + +#if defined(RT_USING_LWIP) + +#include +#include "NuMicro.h" +#include +#include +#include +#include "lwipopts.h" + +#include "drv_sys.h" + +/* Private define ---------------------------------------------------------------*/ +// RT_DEV_NAME_PREFIX e + +#define NU_EMAC_DEBUG +#if defined(NU_EMAC_DEBUG) + //#define NU_EMAC_RX_DUMP + //#define NU_EMAC_TX_DUMP + #define NU_EMAC_TRACE rt_kprintf +#else + #define NU_EMAC_TRACE(...) +#endif + +#define NU_EMAC_TID_STACK_SIZE 1024 + +/* Private typedef --------------------------------------------------------------*/ +struct nu_emac +{ + struct eth_device eth; + char *name; + EMAC_MEMMGR_T memmgr; + IRQn_Type irqn_tx; + IRQn_Type irqn_rx; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + rt_thread_t link_monitor; + rt_uint8_t mac_addr[6]; + struct rt_semaphore eth_sem; +}; +typedef struct nu_emac *nu_emac_t; + +enum +{ + EMAC_START = -1, +#if defined(BSP_USING_EMAC0) + EMAC0_IDX, +#endif +#if defined(BSP_USING_EMAC1) + EMAC1_IDX, +#endif + EMAC_CNT +}; + +/* Private functions ------------------------------------------------------------*/ +#if defined(NU_EMAC_RX_DUMP) || defined(NU_EMAC_TX_DUMP) + static void nu_emac_pkt_dump(const char *msg, const struct pbuf *p); +#endif +#if LWIP_IPV4 && LWIP_IGMP + static err_t nu_igmp_mac_filter(struct netif *netif, const ip4_addr_t *ip4_addr, enum netif_mac_filter_action action); +#endif +static void nu_emac_halt(nu_emac_t); +static void nu_emac_reinit(nu_emac_t); +static void link_monitor(void *param); +static rt_err_t nu_emac_init(rt_device_t dev); + +static rt_err_t nu_emac_open(rt_device_t dev, rt_uint16_t oflag); +static rt_err_t nu_emac_close(rt_device_t dev); +static rt_size_t nu_emac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); +static rt_size_t nu_emac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); +static rt_err_t nu_emac_control(rt_device_t dev, int cmd, void *args); +static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p); +static struct pbuf *nu_emac_rx(rt_device_t dev); +static void rt_hw_nu_emac_assign_macaddr(nu_emac_t psNuEMAC); +static int rt_hw_nu_emac_init(void); +static void *nu_emac_memcpy(void *dest, void *src, unsigned int count); +static void nu_emac_tx_isr(int vector, void *param); +static void nu_emac_rx_isr(int vector, void *param); + +/* Public functions -------------------------------------------------------------*/ + +/* Private variables ------------------------------------------------------------*/ +static struct nu_emac nu_emac_arr[] = +{ +#if defined(BSP_USING_EMAC0) + { + .name = "e0", + .memmgr.psEmac = (EMAC_T *)EMC0_BA, + .irqn_tx = IRQ_EMC0_TX, + .irqn_rx = IRQ_EMC0_RX, + .rstidx = EMAC0RST, + .clkidx = EMAC0CKEN, + }, +#endif +#if defined(BSP_USING_EMAC1) + { + .name = "e1", + .memmgr.psEmac = (EMAC_T *)EMC1_BA, + .irqn_tx = IRQ_EMC1_TX, + .irqn_rx = IRQ_EMC1_RX, + .rstidx = EMAC1RST, + .clkidx = EMAC1CKEN, + }, +#endif +}; + +#if defined(NU_EMAC_RX_DUMP) || defined(NU_EMAC_TX_DUMP) +static void nu_emac_pkt_dump(const char *msg, const struct pbuf *p) +{ + rt_uint32_t i; + rt_uint8_t *ptr = p->payload; + + NU_EMAC_TRACE("%s %d byte\n", msg, p->tot_len); + + for (i = 0; i < p->tot_len; i++) + { + if ((i % 8) == 0) + { + NU_EMAC_TRACE(" "); + } + if ((i % 16) == 0) + { + NU_EMAC_TRACE("\r\n"); + } + NU_EMAC_TRACE("%02x ", *ptr); + ptr++; + } + NU_EMAC_TRACE("\n\n"); +} +#endif /* dump */ + +static void nu_emac_halt(nu_emac_t psNuEmac) +{ + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + EMAC_DISABLE_RX(EMAC); + EMAC_DISABLE_TX(EMAC); +} + +static void *nu_emac_memcpy(void *dest, void *src, unsigned int count) +{ + return memcpy(dest, src, count); +} + +static void nu_emac_reinit(nu_emac_t psNuEmac) +{ + rt_uint32_t EMAC_CAMxM[EMAC_CAMENTRY_NB]; + rt_uint32_t EMAC_CAMxL[EMAC_CAMENTRY_NB]; + rt_uint32_t EMAC_CAMEN; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + + // Backup MAC address. + EMAC_CAMEN = EMAC->CAMEN; + for (rt_uint8_t index = 0 ; index < EMAC_CAMENTRY_NB; index ++) + { + rt_uint32_t *CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8)); + rt_uint32_t *CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8)); + + EMAC_CAMxM[index] = *CAMxM; + EMAC_CAMxL[index] = *CAMxL; + } + + nu_emac_halt(psNuEmac); + EMAC_Close(EMAC); + EMAC_Open(&psNuEmac->memmgr, (uint8_t *)&psNuEmac->mac_addr[0]); + EMAC_ENABLE_TX(EMAC); + EMAC_ENABLE_RX(EMAC); + + // Restore MAC address. + for (rt_uint8_t index = 0 ; index < EMAC_CAMENTRY_NB; index ++) + { + rt_uint32_t *CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8)); + rt_uint32_t *CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8)); + + *CAMxM = EMAC_CAMxM[index]; + *CAMxL = EMAC_CAMxL[index]; + } + EMAC->CAMEN = EMAC_CAMEN; +} + +#if LWIP_IPV4 && LWIP_IGMP +static err_t nu_igmp_mac_filter(struct netif *netif, const ip4_addr_t *ip4_addr, enum netif_mac_filter_action action) +{ + nu_emac_t psNuEmac = (nu_emac_t)netif->state; + rt_uint8_t mac[6]; + int32_t ret = 0; + const uint8_t *p = (const uint8_t *)ip4_addr; + + mac[0] = 0x01; + mac[1] = 0x00; + mac[2] = 0x5E; + mac[3] = *(p + 1) & 0x7F; + mac[4] = *(p + 2); + mac[5] = *(p + 3); + + ret = EMAC_FillCamEntry(psNuEmac->memmgr.psEmac, (uint8_t *)&mac[0]); + if (ret >= 0) + { + NU_EMAC_TRACE("%s %s %s ", __FUNCTION__, (action == NETIF_ADD_MAC_FILTER) ? "add" : "del", ip4addr_ntoa(ip4_addr)); + NU_EMAC_TRACE("%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + return (ret >= 0) ? RT_EOK : -(RT_ERROR); +} +#endif /* LWIP_IPV4 && LWIP_IGMP */ + +static void link_monitor(void *param) +{ + nu_emac_t psNuEmac = (nu_emac_t)param; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + uint32_t LinkStatus_Last = EMAC_LINK_DOWN; + + EMAC_PhyInit(EMAC); + + while (1) + { + uint32_t LinkStatus_Current = EMAC_CheckLinkStatus(EMAC); + /* linkchange */ + if (LinkStatus_Last != LinkStatus_Current) + { + + switch (LinkStatus_Current) + { + case EMAC_LINK_DOWN: + NU_EMAC_TRACE("[%s] Link status: Down\n", psNuEmac->name); + break; + + case EMAC_LINK_100F: + NU_EMAC_TRACE("[%s] Link status: 100F\n", psNuEmac->name); + break; + + case EMAC_LINK_100H: + NU_EMAC_TRACE("[%s] Link status: 100H\n", psNuEmac->name); + break; + + case EMAC_LINK_10F: + NU_EMAC_TRACE("[%s] Link status: 10F\n", psNuEmac->name); + break; + + case EMAC_LINK_10H: + NU_EMAC_TRACE("[%s] Link status: 10H\n", psNuEmac->name); + break; + } /* switch( LinkStatus_Current ) */ + + /* Send link status to upper layer. */ + if (LinkStatus_Current == EMAC_LINK_DOWN) + { + eth_device_linkchange(&psNuEmac->eth, RT_FALSE); + } + else + { + eth_device_linkchange(&psNuEmac->eth, RT_TRUE); + } + LinkStatus_Last = LinkStatus_Current; + + } /* if ( LinkStatus_Last != LinkStatus_Current ) */ + + rt_thread_delay(RT_TICK_PER_SECOND); + + } /* while(1) */ + +} + +static void nu_memmgr_init(EMAC_MEMMGR_T *psMemMgr) +{ + psMemMgr->u32TxDescSize = EMAC_TX_DESC_SIZE; + psMemMgr->u32RxDescSize = EMAC_RX_DESC_SIZE; + + psMemMgr->psTXDescs = (EMAC_DESCRIPTOR_T *) rt_malloc_align(sizeof(EMAC_DESCRIPTOR_T) * psMemMgr->u32TxDescSize, 32); + RT_ASSERT(psMemMgr->psTXDescs != RT_NULL); + + psMemMgr->psRXDescs = (EMAC_DESCRIPTOR_T *) rt_malloc_align(sizeof(EMAC_DESCRIPTOR_T) * psMemMgr->u32RxDescSize, 32); + RT_ASSERT(psMemMgr->psRXDescs != RT_NULL); + + psMemMgr->psTXFrames = (EMAC_FRAME_T *) rt_malloc_align(sizeof(EMAC_FRAME_T) * psMemMgr->u32TxDescSize, 32); + RT_ASSERT(psMemMgr->psTXFrames != RT_NULL); + + psMemMgr->psRXFrames = (EMAC_FRAME_T *) rt_malloc_align(sizeof(EMAC_FRAME_T) * psMemMgr->u32RxDescSize, 32); + RT_ASSERT(psMemMgr->psRXFrames != RT_NULL); +} + +static rt_err_t nu_emac_init(rt_device_t dev) +{ + nu_emac_t psNuEmac = (nu_emac_t)dev; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + char szTmp[16]; + rt_err_t ret = RT_EOK; + + nu_memmgr_init(&psNuEmac->memmgr); + + snprintf(szTmp, sizeof(szTmp), "%sphy", psNuEmac->name); + + ret = rt_sem_init(&psNuEmac->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO); + RT_ASSERT(ret == RT_EOK); + + EMAC_Reset(EMAC); + + EMAC_Close(EMAC); + EMAC_Open(&psNuEmac->memmgr, (uint8_t *)&psNuEmac->mac_addr[0]); + +#if defined(BSP_USING_MMU) + mmu_clean_invalidated_dcache((uint32_t)psNuEmac->memmgr.psTXDescs, sizeof(EMAC_DESCRIPTOR_T)*psNuEmac->memmgr.u32TxDescSize); + mmu_clean_invalidated_dcache((uint32_t)psNuEmac->memmgr.psRXDescs, sizeof(EMAC_DESCRIPTOR_T)*psNuEmac->memmgr.u32RxDescSize); +#endif + + EMAC_ENABLE_RX(EMAC); + EMAC_ENABLE_TX(EMAC); + + EMAC_TRIGGER_RX(EMAC); + +#if defined(LWIP_IPV4) && defined(LWIP_IGMP) + netif_set_igmp_mac_filter(psNuEmac->eth.netif, nu_igmp_mac_filter); +#endif /* LWIP_IPV4 && LWIP_IGMP */ + + psNuEmac->link_monitor = rt_thread_create((const char *)szTmp, + link_monitor, + (void *)psNuEmac, + NU_EMAC_TID_STACK_SIZE, + RT_THREAD_PRIORITY_MAX - 2, + 10); + RT_ASSERT(psNuEmac->link_monitor != RT_NULL); + + ret = rt_thread_startup(psNuEmac->link_monitor); + RT_ASSERT(ret == RT_EOK); + + return RT_EOK; +} + +static rt_err_t nu_emac_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t nu_emac_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_size_t nu_emac_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_size_t nu_emac_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_err_t nu_emac_control(rt_device_t dev, int cmd, void *args) +{ + nu_emac_t psNuEMAC = (nu_emac_t)dev; + switch (cmd) + { + case NIOCTL_GADDR: + /* Get MAC address */ + if (args) + rt_memcpy(args, &psNuEMAC->mac_addr[0], 6); + else + return -RT_ERROR; + + break; + default : + break; + } + + return RT_EOK; +} + +static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p) +{ + nu_emac_t psNuEmac = (nu_emac_t)dev; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + struct pbuf *q; + rt_uint32_t offset = 0; + rt_uint8_t *buf; + + buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf(&psNuEmac->memmgr); + /* Get free TX buffer */ + if (buf == RT_NULL) + { + rt_err_t result; + + result = rt_sem_control(&psNuEmac->eth_sem, RT_IPC_CMD_RESET, 0); + RT_ASSERT(result != RT_EOK); + + EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk); + EMAC_ENABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk); + + do + { + result = rt_sem_take(&psNuEmac->eth_sem, 10); + buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf(&psNuEmac->memmgr); + } + while (buf == RT_NULL); + } + + for (q = p; q != NULL; q = q->next) + { + rt_uint8_t *ptr; + rt_uint32_t len; + + len = q->len; + ptr = q->payload; + + nu_emac_memcpy(&buf[offset], ptr, len); + + offset += len; + } + +#if defined(NU_EMAC_TX_DUMP) + nu_emac_pkt_dump("TX dump", p); +#endif + + /* Return SUCCESS? */ +#if defined(BSP_USING_MMU) + mmu_clean_invalidated_dcache((uint32_t)psNuEmac->memmgr.psCurrentTxDesc, sizeof(EMAC_DESCRIPTOR_T)); +#endif + return (EMAC_SendPktWoCopy(&psNuEmac->memmgr, offset) == 1) ? RT_EOK : RT_ERROR; +} + +static struct pbuf *nu_emac_rx(rt_device_t dev) +{ + nu_emac_t psNuEmac = (nu_emac_t)dev; + struct pbuf *p = RT_NULL; + uint8_t *pu8DataBuf = NULL; + unsigned int avaialbe_size; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + + /* Check available data. */ +#if defined(BSP_USING_MMU) + mmu_clean_invalidated_dcache((uint32_t)psNuEmac->memmgr.psCurrentRxDesc, sizeof(EMAC_DESCRIPTOR_T)); +#endif + if ((avaialbe_size = EMAC_GetAvailRXBufSize(&psNuEmac->memmgr, &pu8DataBuf)) > 0) + { + /* Allocate RX packet buffer. */ + p = pbuf_alloc(PBUF_RAW, avaialbe_size, PBUF_RAM); + if (p != RT_NULL) + { + RT_ASSERT(p->next == RT_NULL); + + nu_emac_memcpy((void *)p->payload, (void *)pu8DataBuf, avaialbe_size); + +#if defined(NU_EMAC_RX_DUMP) + nu_emac_pkt_dump("RX dump", p); +#endif + } + else + { + NU_EMAC_TRACE("Can't allocate memory for RX packet.(%d)\n", avaialbe_size); + } + + /* Update RX descriptor */ + EMAC_RecvPktDoneWoRxTrigger(&psNuEmac->memmgr); + } + else /* If it hasn't RX packet, it will enable interrupt. */ + { + /* No available RX packet, we enable RXGD/RDUIEN interrupts. */ + if (!(EMAC->INTEN & EMAC_INTEN_RDUIEN_Msk)) + { + EMAC_CLEAR_INT_FLAG(EMAC, (EMAC_INTSTS_RDUIF_Msk | EMAC_INTSTS_RXGDIF_Msk)); + EMAC_ENABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk)); + } + else + { + EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_RXGDIF_Msk); + EMAC_ENABLE_INT(EMAC, EMAC_INTEN_RXGDIEN_Msk); + } + EMAC_TRIGGER_RX(EMAC); + } + + return p; +} + +static void nu_emac_rx_isr(int vector, void *param) +{ + nu_emac_t psNuEmac = (nu_emac_t)param; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + + unsigned int status = EMAC->INTSTS & 0xFFFF; + + /* No RX descriptor available, we need to get data from RX pool */ + if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_RDUIF_Msk)) + { + EMAC_DISABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk)); + eth_device_ready(&psNuEmac->eth); + } + /* A good packet ready. */ + else if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_RXGDIF_Msk)) + { + EMAC_DISABLE_INT(EMAC, EMAC_INTEN_RXGDIEN_Msk); + eth_device_ready(&psNuEmac->eth); + } + + /* Receive Bus Error Interrupt */ + if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_RXBEIF_Msk)) + { + NU_EMAC_TRACE("Reinit Rx EMAC\n"); + EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_RXBEIF_Msk); + nu_emac_reinit(psNuEmac); + } + + EMAC->INTSTS = status; +} + +static void nu_emac_tx_isr(int vector, void *param) +{ + nu_emac_t psNuEmac = (nu_emac_t)param; + EMAC_T *EMAC = psNuEmac->memmgr.psEmac; + rt_err_t result = RT_EOK; + + unsigned int status = EMAC->INTSTS & 0xFFFF0000; + + /* Wake-up suspended process to send */ + if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk)) + { + EMAC_DISABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk); + + result = rt_sem_release(&psNuEmac->eth_sem); + RT_ASSERT(result == RT_EOK); + } + + if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXBEIF_Msk)) + { + NU_EMAC_TRACE("Reinit Tx EMAC\n"); + nu_emac_reinit(psNuEmac); + } + else + EMAC_SendPktDone(&psNuEmac->memmgr); + + EMAC->INTSTS = status; +} + +static void rt_hw_nu_emac_assign_macaddr(nu_emac_t psNuEMAC) +{ + static rt_uint32_t value = 0x94539453; + + /* Assign MAC address */ + psNuEMAC->mac_addr[0] = 0x82; + psNuEMAC->mac_addr[1] = 0x06; + psNuEMAC->mac_addr[2] = 0x21; + psNuEMAC->mac_addr[3] = (value >> 16) & 0xff; + psNuEMAC->mac_addr[4] = (value >> 8) & 0xff; + psNuEMAC->mac_addr[5] = (value) & 0xff; + + NU_EMAC_TRACE("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", \ + psNuEMAC->mac_addr[0], \ + psNuEMAC->mac_addr[1], \ + psNuEMAC->mac_addr[2], \ + psNuEMAC->mac_addr[3], \ + psNuEMAC->mac_addr[4], \ + psNuEMAC->mac_addr[5]); + value++; +} + +static int rt_hw_nu_emac_init(void) +{ + int i; + rt_err_t ret = RT_EOK; + char szTmp[32]; + + /* MDC CLK divider */ + outpw(REG_CLK_DIVCTL8, (inpw(REG_CLK_DIVCTL8) & ~0xFF) | 0xA0); + + for (i = (EMAC_START + 1); i < EMAC_CNT; i++) + { + nu_emac_t psNuEMAC = (nu_emac_t)&nu_emac_arr[i]; + + nu_sys_ipclk_enable(psNuEMAC->clkidx); + + nu_sys_ip_reset(psNuEMAC->rstidx); + + rt_hw_nu_emac_assign_macaddr(psNuEMAC); + + /* Register member functions */ + psNuEMAC->eth.parent.init = nu_emac_init; + psNuEMAC->eth.parent.open = nu_emac_open; + psNuEMAC->eth.parent.close = nu_emac_close; + psNuEMAC->eth.parent.read = nu_emac_read; + psNuEMAC->eth.parent.write = nu_emac_write; + psNuEMAC->eth.parent.control = nu_emac_control; + psNuEMAC->eth.parent.user_data = psNuEMAC; + psNuEMAC->eth.eth_rx = nu_emac_rx; + psNuEMAC->eth.eth_tx = nu_emac_tx; + + snprintf(szTmp, sizeof(szTmp), "%s_tx", psNuEMAC->name); + rt_hw_interrupt_install(psNuEMAC->irqn_tx, nu_emac_tx_isr, (void *)psNuEMAC, szTmp); + rt_hw_interrupt_umask(psNuEMAC->irqn_tx); + + snprintf(szTmp, sizeof(szTmp), "%s_rx", psNuEMAC->name); + rt_hw_interrupt_install(psNuEMAC->irqn_rx, nu_emac_rx_isr, (void *)psNuEMAC, szTmp); + rt_hw_interrupt_umask(psNuEMAC->irqn_rx); + + /* Register eth device */ + ret = eth_device_init(&psNuEMAC->eth, psNuEMAC->name); + RT_ASSERT(ret == RT_EOK); + } + + return 0; +} + +INIT_APP_EXPORT(rt_hw_nu_emac_init); + +#endif /* #if defined( RT_USING_LWIP ) */ + +#endif /* #if defined( BSP_USING_EMAC ) */ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer.c new file mode 100644 index 0000000000000000000000000000000000000000..7c3b1578e4b4f75c90915a74fc72ee13ae759a2d --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer.c @@ -0,0 +1,283 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-3 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_ETIMER) && defined(RT_USING_HWTIMER) + +#include +#include "NuMicro.h" +#include + +/* Private define ---------------------------------------------------------------*/ +#define NU_TIMER_DEVICE(etimer) (nu_etimer_t)(etimer) + +enum +{ + ETIMER_START = -1, +#if defined(BSP_USING_ETIMER0) + ETIMER0_IDX, +#endif +#if defined(BSP_USING_ETIMER1) + ETIMER1_IDX, +#endif +#if defined(BSP_USING_ETIMER2) + ETIMER2_IDX, +#endif +#if defined(BSP_USING_ETIMER3) + ETIMER3_IDX, +#endif + ETIMER_CNT +}; + +/* Private typedef --------------------------------------------------------------*/ +struct nu_etimer +{ + rt_hwtimer_t parent; + char *name; + uint32_t idx; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; +}; +typedef struct nu_etimer *nu_etimer_t; + +/* Private functions ------------------------------------------------------------*/ +static void nu_etimer_init(rt_hwtimer_t *timer, rt_uint32_t state); +static rt_err_t nu_etimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode); +static void nu_etimer_stop(rt_hwtimer_t *timer); +static rt_uint32_t nu_etimer_count_get(rt_hwtimer_t *timer); +static rt_err_t nu_etimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args); + +/* Public functions -------------------------------------------------------------*/ + + +/* Private variables ------------------------------------------------------------*/ +static struct nu_etimer nu_etimer_arr [] = +{ +#if defined(BSP_USING_ETIMER0) + { + .name = "etmr0", + .idx = 0, + .irqn = IRQ_ETMR0, + .rstidx = ETIMER0RST, + .clkidx = ETIMER0CKEN, + }, +#endif +#if defined(BSP_USING_ETIMER1) + { + .name = "etmr1", + .idx = 1, + .irqn = IRQ_ETMR1, + .rstidx = ETIMER1RST, + .clkidx = ETIMER1CKEN, + }, +#endif +#if defined(BSP_USING_ETIMER2) + { + .name = "etmr2", + .idx = 2, + .irqn = IRQ_ETMR2, + .rstidx = ETIMER2RST, + .clkidx = ETIMER2CKEN, + }, +#endif +#if defined(BSP_USING_ETIMER3) + { + .name = "etmr3", + .idx = 3, + .irqn = IRQ_ETMR3, + .rstidx = ETIMER3RST, + .clkidx = ETIMER3CKEN, + }, +#endif +}; + +static struct rt_hwtimer_info nu_etimer_info = +{ + 12000000, /* maximum count frequency */ + 46875, /* minimum count frequency */ + 0xFFFFFF, /* the maximum counter value */ + HWTIMER_CNTMODE_UP, /* Increment or Decreasing count mode */ +}; + +static struct rt_hwtimer_ops nu_etimer_ops = +{ + nu_etimer_init, + nu_etimer_start, + nu_etimer_stop, + nu_etimer_count_get, + nu_etimer_control +}; + +/* Functions define ------------------------------------------------------------*/ +static void nu_etimer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuETmr != RT_NULL); + + if (1 == state) + { + uint32_t timer_clk; + struct rt_hwtimer_info *info = &nu_etimer_info; + + timer_clk = ETIMER_GetModuleClock(psNuETmr->idx); + info->maxfreq = timer_clk; + info->minfreq = timer_clk / 256; + ETIMER_Open(psNuETmr->idx, ETIMER_ONESHOT_MODE, 1); + ETIMER_EnableInt(psNuETmr->idx); + rt_hw_interrupt_umask(psNuETmr->irqn); + } + else + { + rt_hw_interrupt_mask(psNuETmr->irqn); + ETIMER_DisableInt(psNuETmr->idx); + ETIMER_Close(psNuETmr->idx); + } +} + +static rt_err_t nu_etimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode) +{ + rt_err_t ret = RT_EINVAL; + rt_uint32_t u32OpMode; + + nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuETmr != RT_NULL); + + if (cnt <= 1 || cnt > 0xFFFFFF) + { + goto exit_nu_etimer_start; + } + + switch (opmode) + { + case HWTIMER_MODE_PERIOD: + u32OpMode = ETIMER_PERIODIC_MODE; + break; + + case HWTIMER_MODE_ONESHOT: + u32OpMode = ETIMER_ONESHOT_MODE; + break; + + default: + goto exit_nu_etimer_start; + } + + ETIMER_SET_CMP_VALUE(psNuETmr->idx, cnt); + ETIMER_SET_OPMODE(psNuETmr->idx, u32OpMode); + ETIMER_EnableInt(psNuETmr->idx); + rt_hw_interrupt_umask(psNuETmr->irqn); + + ETIMER_Start(psNuETmr->idx); + + ret = RT_EOK; + +exit_nu_etimer_start: + + return -(ret); +} + +static void nu_etimer_stop(rt_hwtimer_t *timer) +{ + nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuETmr != RT_NULL); + + rt_hw_interrupt_mask(psNuETmr->irqn); + ETIMER_DisableInt(psNuETmr->idx); + ETIMER_Stop(psNuETmr->idx); + ETIMER_ClearCounter(psNuETmr->idx); +} + +static rt_uint32_t nu_etimer_count_get(rt_hwtimer_t *timer) +{ + nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuETmr != RT_NULL); + + return ETIMER_GetCounter(psNuETmr->idx); +} + +static rt_err_t nu_etimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t ret = RT_EOK; + nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuETmr != RT_NULL); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + { + uint32_t clk; + uint32_t pre; + + clk = ETIMER_GetModuleClock(psNuETmr->idx); + pre = clk / *((uint32_t *)args) - 1; + ETIMER_SET_PRESCALE_VALUE(psNuETmr->idx, pre); + *((uint32_t *)args) = clk / (pre + 1) ; + } + break; + + case HWTIMER_CTRL_STOP: + ETIMER_Stop(psNuETmr->idx); + break; + + default: + ret = RT_EINVAL; + break; + } + + return -(ret); +} + +/** + * All UART interrupt service routine + */ +static void nu_etimer_isr(int vector, void *param) +{ + nu_etimer_t psNuETmr = NU_TIMER_DEVICE(param); + RT_ASSERT(psNuETmr != RT_NULL); + + if (ETIMER_GetIntFlag(psNuETmr->idx)) + { + ETIMER_ClearIntFlag(psNuETmr->idx); + rt_device_hwtimer_isr(&psNuETmr->parent); + } +} + +int rt_hw_etimer_init(void) +{ + int i; + rt_err_t ret = RT_EOK; + for (i = (ETIMER_START + 1); i < ETIMER_CNT; i++) + { + nu_sys_ipclk_enable(nu_etimer_arr[i].clkidx); + + nu_sys_ip_reset(nu_etimer_arr[i].rstidx); + + /* Register Etimer information. */ + nu_etimer_arr[i].parent.info = &nu_etimer_info; + + /* Register Etimer operation. */ + nu_etimer_arr[i].parent.ops = &nu_etimer_ops; + + /* Register Etimer interrupt service routine. */ + rt_hw_interrupt_install(nu_etimer_arr[i].irqn, nu_etimer_isr, &nu_etimer_arr[i], nu_etimer_arr[i].name); + + /* Register RT hwtimer device. */ + ret = rt_device_hwtimer_register(&nu_etimer_arr[i].parent, nu_etimer_arr[i].name, &nu_etimer_arr[i]); + RT_ASSERT(ret == RT_EOK); + } + return 0; +} + +INIT_BOARD_EXPORT(rt_hw_etimer_init); + +#endif //#if defined(BSP_USING_ETIMER) && defined(RT_USING_HWTIMER) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer_capture.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer_capture.c new file mode 100644 index 0000000000000000000000000000000000000000..93184c689f22cb9a68958b6d35fed100645e85df --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer_capture.c @@ -0,0 +1,226 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-1-28 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_TIMER_CAPTURE) + +#include +#include "NuMicro.h" +#include + +/* Private define ---------------------------------------------------------------*/ + +/* Timer prescale setting. Since it will affect the pulse width of measure, it is recommended to set to 2. */ +#define PSC_DIV (2) + +#define NU_TCAP_DEVICE(etimer) (nu_capture_t*)(etimer) +enum +{ + TCAP_START = -1, +#if defined(BSP_USING_ETIMER0_CAPTURE) + TCAP0_IDX, +#endif +#if defined(BSP_USING_ETIMER1_CAPTURE) + TCAP1_IDX, +#endif +#if defined(BSP_USING_ETIMER2_CAPTURE) + TCAP2_IDX, +#endif +#if defined(BSP_USING_ETIMER3_CAPTURE) + TCAP3_IDX, +#endif + TCAP_CNT +}; + +/* Private typedef --------------------------------------------------------------*/ +typedef struct _timer +{ + struct rt_inputcapture_device parent; + char *name; + uint32_t idx; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + + uint32_t u32CurrentCnt; +} nu_capture_t; + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture); +static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture); +static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture); +static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us); + +/* Public functions -------------------------------------------------------------*/ + +/* Private variables ------------------------------------------------------------*/ +static nu_capture_t nu_etcap_arr [] = +{ +#if defined(BSP_USING_ETIMER0_CAPTURE) + { + .name = "etmr0i0", + .idx = 0, + .irqn = IRQ_ETMR0, + .rstidx = ETIMER0RST, + .clkidx = ETIMER0CKEN, + }, +#endif +#if defined(BSP_USING_ETIMER1_CAPTURE) + { + .name = "etmr1i0", + .idx = 1, + .irqn = IRQ_ETMR1, + .rstidx = ETIMER1RST, + .clkidx = ETIMER1CKEN, + }, +#endif +#if defined(BSP_USING_ETIMER2_CAPTURE) + { + .name = "etmr2i0", + .idx = 2, + .irqn = IRQ_ETMR2, + .rstidx = ETIMER2RST, + .clkidx = ETIMER2CKEN, + }, +#endif +#if defined(BSP_USING_ETIMER3_CAPTURE) + { + .name = "etmr3i0", + .idx = 3, + .irqn = IRQ_ETMR3, + .rstidx = ETIMER3RST, + .clkidx = ETIMER3CKEN, + }, +#endif +}; + +static struct rt_inputcapture_ops nu_capture_ops = +{ + .init = nu_capture_init, + .open = nu_capture_open, + .close = nu_capture_close, + .get_pulsewidth = nu_capture_get_pulsewidth, +}; + +/* Functions define ------------------------------------------------------------*/ +static void nu_tcap_isr(int vector, void *param) +{ + nu_capture_t *psNuTCap = NU_TCAP_DEVICE(param); + + RT_ASSERT(psNuTCap != RT_NULL); + + ETIMER_ClearCaptureIntFlag(psNuTCap->idx); + + /* Report caputring data and level. */ + psNuTCap->u32CurrentCnt = ETIMER_GetCaptureData(psNuTCap->idx); + rt_hw_inputcapture_isr(&psNuTCap->parent, ETIMER_GetCaptureFallingEdgeFlag(psNuTCap->idx)); +} + +static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us) +{ + nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture); + + RT_ASSERT(inputcapture != RT_NULL); + RT_ASSERT(pulsewidth_us != RT_NULL); + + *pulsewidth_us = psNuTCap->u32CurrentCnt / PSC_DIV; + + return RT_EOK; +} + +static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture) +{ + nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture); + + RT_ASSERT(inputcapture != RT_NULL); + + nu_sys_ipclk_enable(psNuTCap->clkidx); + nu_sys_ip_reset(psNuTCap->rstidx); + + return RT_EOK; +} + +static uint8_t cal_time_prescale(nu_capture_t *psNuTCap) +{ + uint32_t u32Clk = ETIMER_GetModuleClock(psNuTCap->idx); + + /* 1 tick = 1/PSC_DIV us */ + return (u32Clk / 1000000 / PSC_DIV) - 1; +} + +static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture) +{ + nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture); + + RT_ASSERT(inputcapture != RT_NULL); + + /* Enable Timer Interrupt */ + rt_hw_interrupt_umask(psNuTCap->irqn); + + /* Clear counter before openning. */ + ETIMER_ClearCounter(psNuTCap->idx); + + ETIMER_Open(psNuTCap->idx, ETIMER_CONTINUOUS_MODE, 1); + + ETIMER_SET_PRESCALE_VALUE(psNuTCap->idx, cal_time_prescale(psNuTCap)); + + ETIMER_SET_CMP_VALUE(psNuTCap->idx, 0xFFFFFF); + + ETIMER_EnableCapture(psNuTCap->idx, ETIMER_CAPTURE_COUNTER_RESET_MODE, ETIMER_CAPTURE_RISING_THEN_FALLING_EDGE); + + ETIMER_EnableCaptureInt(psNuTCap->idx); + + ETIMER_Start(psNuTCap->idx); + + return RT_EOK; +} + +static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture) +{ + nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture); + + RT_ASSERT(inputcapture != RT_NULL); + + ETIMER_Stop(psNuTCap->idx); + + ETIMER_DisableCaptureInt(psNuTCap->idx); + + ETIMER_Close(psNuTCap->idx); + + rt_hw_interrupt_mask(psNuTCap->irqn); + + return RT_EOK; +} + +/* Init and register timer capture */ +static int nu_etimer_capture_device_init(void) +{ + int i; + + for (i = (TCAP_START + 1); i < TCAP_CNT; i++) + { + /* Register operations */ + nu_etcap_arr[i].parent.ops = &nu_capture_ops; + + /* Install ISR */ + rt_hw_interrupt_install(nu_etcap_arr[i].irqn, nu_tcap_isr, &nu_etcap_arr[i], nu_etcap_arr[i].name); + + /* Register inputcapture device */ + rt_device_inputcapture_register(&nu_etcap_arr[i].parent, nu_etcap_arr[i].name, &nu_etcap_arr[i]); + } + + return 0; +} +INIT_DEVICE_EXPORT(nu_etimer_capture_device_init); + +#endif //#if defined(BSP_USING_ETIMER_CAPTURE) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_ge2d.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_ge2d.c new file mode 100644 index 0000000000000000000000000000000000000000..1b1522fcbfdac7173e1c7114b92a8569522f914c --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_ge2d.c @@ -0,0 +1,3470 @@ +/**************************************************************************//** +* @file 2d.c +* @brief N9H30 GE2D driver source file +* +* @note +* SPDX-License-Identifier: Apache-2.0 +* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved. +*****************************************************************************/ +#include "rtthread.h" + +#include "NuMicro.h" +#include + +//#define DEBUG +//#define DEF_COND_WAIT 1 + +static unsigned int GFX_BPP; +static unsigned int GFX_WIDTH; +static unsigned int GFX_HEIGHT; + +#if defined ( __GNUC__ ) && !(__CC_ARM) + __attribute__((aligned(32))) static void *GFX_START_ADDR = NULL; + __attribute__((aligned(32))) static void *GFX_PAT_ADDR = NULL; +#else + static __align(32) void *GFX_START_ADDR = NULL; + static __align(32) void *GFX_PAT_ADDR = NULL; +#endif + +#define PN 1 // Quadrant 1 +#define NN 2 // Quadrant 2 +#define NP 3 // Quadrant 3 +#define PP 4 // Quadrant 4 + +#define ABS(x) (((x)>0)?(x):-(x)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +/* octant code of line drawing */ + +#define XpYpXl (0<<1) // XY octant position is 1~3 in Control register +#define XpYpYl (1<<1) +#define XpYmXl (2<<1) +#define XpYmYl (3<<1) +#define XmYpXl (4<<1) +#define XmYpYl (5<<1) +#define XmYmXl (6<<1) +#define XmYmYl (7<<1) + +static MONOPATTERN MonoPatternData[6] = +{ + {0x00000000, 0xff000000}, // HS_HORIZONTAL + {0x08080808, 0x08080808}, // HS_VERTICAL + {0x80402010, 0x08040201}, // HS_FDIAGONAL + {0x01020408, 0x10204080}, // HS_BDIAGONAL + {0x08080808, 0xff080808}, // HS_CROSS + {0x81422418, 0x18244281} // HS_DIAGCROSS +}; + +static char _DrawMode = MODE_OPAQUE; +static UINT32 _ColorKey = COLOR_KEY; +static UINT32 _ColorKeyMask = 0xFFFFFF; + +static BOOL _EnableAlpha = FALSE; +static int _AlphaKs, _AlphaKd; +static BOOL _ClipEnable = FALSE; +static BOOL _OutsideClip = FALSE; +static UINT32 _ClipTL, _ClipBR; +static int _PatternType; + +static unsigned char FontData8[256][8] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //0 + {0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E}, //1 + {0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E}, //2 + {0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00}, //3 + {0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00}, //4 + {0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x92, 0x10, 0x7C}, //5 + {0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C}, //6 + {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00}, //7 + {0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF}, //8 + {0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00}, //9 + {0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF}, //10 + {0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78}, //11 + {0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18}, //12 + {0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0}, //13 + {0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0}, //14 + {0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99}, //15 + {0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00}, //16 + {0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00}, //17 + {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18}, //18 + {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, //19 + {0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00}, //20 + {0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0x86, 0xFC}, //21 + {0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00}, //22 + {0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF}, //23 + {0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00}, //24 + {0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00}, //25 + {0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00}, //26 + {0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00}, //27 + {0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00}, //28 + {0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00}, //29 + {0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00}, //30 + {0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00}, //31 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //32 + {0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, //33 + {0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00}, //34 + {0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00}, //35 + {0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00}, //36 + {0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00}, //37 + {0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00}, //38 + {0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, //39 + {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00}, //40 + {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00}, //41 + {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, //42 + {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, //43 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30}, //44 + {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, //45 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, //46 + {0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00}, //47 + {0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0x7C, 0x00}, //48 + {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00}, //49 + {0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00}, //50 + {0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00}, //51 + {0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00}, //52 + {0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00}, //53 + {0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00}, //54 + {0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00}, //55 + {0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //56 + {0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00}, //57 + {0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00}, //58 + {0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30}, //59 + {0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00}, //60 + {0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, //61 + {0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00}, //62 + {0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00}, //63 + {0x7C, 0xC6, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00}, //64 + {0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00}, //65 + {0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00}, //66 + {0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00}, //67 + {0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00}, //68 + {0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00}, //69 + {0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00}, //70 + {0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00}, //71 + {0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00}, //72 + {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, //73 + {0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00}, //74 + {0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00}, //75 + {0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00}, //76 + {0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00}, //77 + {0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00}, //78 + {0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00}, //79 + {0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00}, //80 + {0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0x7C, 0x0E, 0x00}, //81 + {0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00}, //82 + {0x7C, 0xC6, 0xE0, 0x78, 0x0E, 0xC6, 0x7C, 0x00}, //83 + {0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, //84 + {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00}, //85 + {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00}, //86 + {0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00}, //87 + {0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00}, //88 + {0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00}, //89 + {0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00}, //90 + {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00}, //91 + {0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00}, //92 + {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00}, //93 + {0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, //94 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, //95 + {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, //96 + {0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //97 + {0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00}, //98 + {0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00}, //99 + {0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00}, //100 + {0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //101 + {0x38, 0x6C, 0x64, 0xF0, 0x60, 0x60, 0xF0, 0x00}, //102 + {0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, //103 + {0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00}, //104 + {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //105 + {0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78}, //106 + {0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00}, //107 + {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, //108 + {0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xD6, 0x00}, //109 + {0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00}, //110 + {0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00}, //111 + {0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0}, //112 + {0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E}, //113 + {0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00}, //114 + {0x00, 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00}, //115 + {0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00}, //116 + {0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //117 + {0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00}, //118 + {0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00}, //119 + {0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00}, //120 + {0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, //121 + {0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00}, //122 + {0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00}, //123 + {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, //124 + {0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00}, //125 + {0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //126 + {0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00}, //127 + {0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x0C, 0x06, 0x7C}, //128 + {0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //129 + {0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //130 + {0x7E, 0x81, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0x00}, //131 + {0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //132 + {0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //133 + {0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //134 + {0x00, 0x00, 0x7C, 0xC6, 0xC0, 0x78, 0x0C, 0x38}, //135 + {0x7E, 0x81, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00}, //136 + {0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //137 + {0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00}, //138 + {0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //139 + {0x7C, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00}, //140 + {0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //141 + {0xC6, 0x10, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00}, //142 + {0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00}, //143 + {0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00}, //144 + {0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00}, //145 + {0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00}, //146 + {0x78, 0x84, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //147 + {0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //148 + {0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //149 + {0x78, 0x84, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //150 + {0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //151 + {0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8}, //152 + {0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, //153 + {0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00}, //154 + {0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18}, //155 + {0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00}, //156 + {0xCC, 0xCC, 0x78, 0x30, 0xFC, 0x30, 0xFC, 0x30}, //157 + {0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC3}, //158 + {0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70}, //159 + {0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00}, //160 + {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00}, //161 + {0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00}, //162 + {0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00}, //163 + {0x00, 0xF8, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0x00}, //164 + {0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00}, //165 + {0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00}, //166 + {0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00}, //167 + {0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3C, 0x00}, //168 + {0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00}, //169 + {0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00}, //170 + {0xC6, 0xCC, 0xD8, 0x36, 0x6B, 0xC2, 0x84, 0x0F}, //171 + {0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6D, 0xCF, 0x03}, //172 + {0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x18, 0x00}, //173 + {0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, //174 + {0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, //175 + {0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88}, //176 + {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, //177 + {0xDB, 0xF6, 0xDB, 0x6F, 0xDB, 0x7E, 0xD7, 0xED}, //178 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //179 + {0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18}, //180 + {0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18}, //181 + {0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36}, //182 + {0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36}, //183 + {0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18}, //184 + {0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36}, //185 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //186 + {0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36}, //187 + {0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00}, //188 + {0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00}, //189 + {0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00}, //190 + {0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18}, //191 + {0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00}, //192 + {0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00}, //193 + {0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18}, //194 + {0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18}, //195 + {0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, //196 + {0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18}, //197 + {0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18}, //198 + {0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36}, //199 + {0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00}, //200 + {0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36}, //201 + {0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00}, //202 + {0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36}, //203 + {0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36}, //204 + {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00}, //205 + {0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36}, //206 + {0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00}, //207 + {0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00}, //208 + {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18}, //209 + {0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36}, //210 + {0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00}, //211 + {0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00}, //212 + {0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18}, //213 + {0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36}, //214 + {0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36}, //215 + {0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18}, //216 + {0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00}, //217 + {0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18}, //218 + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //219 + {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}, //220 + {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, //221 + {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, //222 + {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, //223 + {0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00}, //224 + {0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0}, //225 + {0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00}, //226 + {0x00, 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x00}, //227 + {0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00}, //228 + {0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00}, //229 + {0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0}, //230 + {0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00}, //231 + {0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC}, //232 + {0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00}, //233 + {0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00}, //234 + {0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00}, //235 + {0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00}, //236 + {0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0}, //237 + {0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00}, //238 + {0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00}, //239 + {0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00}, //240 + {0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00}, //241 + {0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00}, //242 + {0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00}, //243 + {0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18}, //244 + {0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70}, //245 + {0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00}, //246 + {0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00}, //247 + {0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //248 + {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, //249 + {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00}, //250 + {0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C}, //251 + {0x58, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00}, //252 + {0x70, 0x98, 0x30, 0x60, 0xF8, 0x00, 0x00, 0x00}, //253 + {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, //254 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //255 +}; + +static unsigned char FontData16[256][16] = +{ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //0 + {0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00}, //1 + {0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00}, //2 + {0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00}, //3 + {0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, //4 + {0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x99, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //5 + {0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //6 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //7 + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //8 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00}, //9 + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //10 + {0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00}, //11 + {0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //12 + {0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00}, //13 + {0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00}, //14 + {0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //15 + {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00}, //16 + {0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, //17 + {0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //18 + {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00}, //19 + {0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00}, //20 + {0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00}, //21 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00}, //22 + {0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00}, //23 + {0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //24 + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //25 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //26 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //27 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //28 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //29 + {0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, //30 + {0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, //31 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //32 + {0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //33 + {0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //34 + {0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, //35 + {0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00}, //36 + {0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00}, //37 + {0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //38 + {0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //39 + {0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00}, //40 + {0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00}, //41 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //42 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //43 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00}, //44 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //45 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //46 + {0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00}, //47 + {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xCE, 0xD6, 0xD6, 0xE6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //48 + {0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00}, //49 + {0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //50 + {0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //51 + {0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00}, //52 + {0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x0E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //53 + {0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //54 + {0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00}, //55 + {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //56 + {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00}, //57 + {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, //58 + {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00}, //59 + {0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00}, //60 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //61 + {0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00}, //62 + {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //63 + {0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00}, //64 + {0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //65 + {0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00}, //66 + {0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00}, //67 + {0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00}, //68 + {0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00}, //69 + {0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //70 + {0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00}, //71 + {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //72 + {0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //73 + {0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00}, //74 + {0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //75 + {0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00}, //76 + {0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //77 + {0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //78 + {0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //79 + {0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //80 + {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00}, //81 + {0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //82 + {0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //83 + {0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //84 + {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //85 + {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00}, //86 + {0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, //87 + {0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x6C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //88 + {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //89 + {0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //90 + {0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00}, //91 + {0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00}, //92 + {0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00}, //93 + {0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //94 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00}, //95 + {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //96 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //97 + {0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x00}, //98 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //99 + {0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //100 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //101 + {0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //102 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00}, //103 + {0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //104 + {0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //105 + {0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00}, //106 + {0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00}, //107 + {0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //108 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00}, //109 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00}, //110 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //111 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00}, //112 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00}, //113 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00}, //114 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //115 + {0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, //116 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //117 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //118 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00}, //119 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, //120 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00}, //121 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //122 + {0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00}, //123 + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //124 + {0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00}, //125 + {0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //126 + {0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, //127 + {0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00}, //128 + {0x00, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //129 + {0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //130 + {0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //131 + {0x00, 0x00, 0xCC, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //132 + {0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //133 + {0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //134 + {0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00}, //135 + {0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //136 + {0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //137 + {0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //138 + {0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //139 + {0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //140 + {0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //141 + {0x00, 0xC6, 0xC6, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //142 + {0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //143 + {0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00}, //144 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00}, //145 + {0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00}, //146 + {0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //147 + {0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //148 + {0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //149 + {0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //150 + {0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //151 + {0x00, 0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00}, //152 + {0x00, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //153 + {0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //154 + {0x00, 0x18, 0x18, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //155 + {0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00}, //156 + {0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //157 + {0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00}, //158 + {0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0x70, 0x00, 0x00}, //159 + {0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //160 + {0x00, 0x0C, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00}, //161 + {0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //162 + {0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00}, //163 + {0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00}, //164 + {0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //165 + {0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //166 + {0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //167 + {0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00}, //168 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}, //169 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, //170 + {0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x93, 0x06, 0x0C, 0x1F, 0x00, 0x00}, //171 + {0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xCE, 0x9A, 0x3F, 0x06, 0x0F, 0x00, 0x00}, //172 + {0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00}, //173 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //174 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //175 + {0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44}, //176 + {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, //177 + {0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77}, //178 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //179 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //180 + {0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //181 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //182 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //183 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //184 + {0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //185 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //186 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //187 + {0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //188 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //189 + {0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //190 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //191 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //192 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //193 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //194 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //195 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //196 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //197 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //198 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //199 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //200 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //201 + {0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //202 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //203 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //204 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //205 + {0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //206 + {0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //207 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //208 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //209 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //210 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //211 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //212 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //213 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //214 + {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}, //215 + {0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //216 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //217 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //218 + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //219 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //220 + {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, //221 + {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, //222 + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //223 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00}, //224 + {0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0xC0, 0xC0, 0xC0, 0x00, 0x00}, //225 + {0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00}, //226 + {0x00, 0x00, 0x00, 0x00, 0x80, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, //227 + {0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00}, //228 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00}, //229 + {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00}, //230 + {0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, //231 + {0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00}, //232 + {0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00}, //233 + {0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, 0x00, 0x00, 0x00, 0x00}, //234 + {0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00}, //235 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //236 + {0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xCF, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00}, //237 + {0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00}, //238 + {0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00}, //239 + {0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00}, //240 + {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, //241 + {0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, //242 + {0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, //243 + {0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //244 + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00}, //245 + {0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, //246 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //247 + {0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //248 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //249 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //250 + {0x00, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00}, //251 + {0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //252 + {0x00, 0x70, 0x98, 0x30, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //253 + {0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00}, //254 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //255 +}; + +struct nu_ge2d +{ + char *name; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + + rt_mutex_t lock; +#if defined(DEF_COND_WAIT) + rt_sem_t signal; +#endif +}; +typedef struct nu_ge2d *nu_ge2d_t; + +static struct nu_ge2d g_sNuGe2d = +{ + .name = "GE2D", + .irqn = IRQ_GE2D, + .rstidx = GE2DRST, + .clkidx = GE2DCKEN +}; + +#define NU_GE2D_LOCK() { \ + rt_err_t result = rt_mutex_take(g_sNuGe2d.lock, RT_WAITING_FOREVER); \ + RT_ASSERT(result == RT_EOK); \ + } + +#define NU_GE2D_UNLOCK() { \ + rt_err_t result = rt_mutex_release(g_sNuGe2d.lock); \ + RT_ASSERT(result == RT_EOK); \ + } + +#if defined(DEF_COND_WAIT) +#define NU_GE2D_COND_WAIT() { \ + rt_err_t result = rt_sem_take(g_sNuGe2d.signal, RT_WAITING_FOREVER); \ + RT_ASSERT(result == RT_EOK); \ + } + +#define NU_GE2D_SIGNAL() { \ + rt_err_t result = rt_sem_release(g_sNuGe2d.signal); \ + RT_ASSERT(result == RT_EOK); \ + } +/* Interrupt Service Routine for GE2D */ +static void nu_ge2d_isr(int vector, void *param) +{ + /* Clear interrupt status. */ + outpw(REG_GE2D_INTSTS, 1); + + /* Signal condition-waiting to resume caller. */ + NU_GE2D_SIGNAL(); +} +#else +#define NU_GE2D_COND_WAIT() { \ + while ((inpw(REG_GE2D_INTSTS) & 0x01) == 0); \ + outpw(REG_GE2D_INTSTS, 1); \ + } +#define NU_GE2D_SIGNAL() +#endif + + +static unsigned long make_color(int color) +{ + UINT32 r, g, b; + + if (GFX_BPP == 8) + { + r = (color & 0x00e00000) >> 16; // 3 bits + g = (color & 0x0000e000) >> 11; // 3 bits + b = (color & 0x000000c0) >> 6; // 2 bits + return (r | g | b); + } + else if (GFX_BPP == 16) + { + r = (color & 0x00f80000) >> 8; // 5 bits + g = (color & 0x0000fc00) >> 5; // 6 bits + b = (color & 0x000000f8) >> 3; // 5 bits + return (r | g | b); + } + else return (UINT32)color; +} +/// @endcond /* HIDDEN_SYMBOLS */ + +/** + * @brief Clear the on screen buffer with a specified color. + * @param[in] color clear with this color. + * @return none + */ +void ge2dClearScreen(int color) +{ + UINT32 cmd32; + UINT32 color32, dest_pitch, dest_dimension; + + color32 = make_color(color); + + cmd32 = 0xcc430040; + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_BGCOLR, color32); // fill with background color + + dest_pitch = GFX_WIDTH << 16; // pitch in pixels + outpw(REG_GE2D_SDPITCH, dest_pitch); + + outpw(REG_GE2D_DSTSPA, 0); // starts from (0,0) + + dest_dimension = GFX_HEIGHT << 16 | GFX_WIDTH; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Set output data mask. + * @param[in] mask is mask value + * @return none + */ +void ge2dSetWriteMask(int mask) +{ + outpw(REG_GE2D_WRPLNMSK, make_color(mask)); +} + +/** + * @brief Set source origin starting address. + * @param[in] ptr pointer of start address + * @return none + */ +void ge2dSetSourceOriginStarting(void *ptr) +{ + outpw(REG_GE2D_XYSORG, (int)ptr); +} + +/** + * @brief Set destination origin starting address. + * @param[in] ptr pointer of start address + * @return none + */ +void ge2dSetDestinationOriginStarting(void *ptr) +{ + outpw(REG_GE2D_XYDORG, (int)ptr); +} + + +/** + * @brief Reset graphics engine. + * @param none + * @return none + */ +void ge2dReset(void) +{ + outpw(REG_GE2D_MISCTL, 0x40); // FIFO reset + outpw(REG_GE2D_MISCTL, 0x00); + + outpw(REG_GE2D_MISCTL, 0x80); // Engine reset + outpw(REG_GE2D_MISCTL, 0x00); +} + +/** + * @brief Graphics engine initialization. + * @param[in] bpp bit per pixel + * @param[in] width is width of display memory + * @param[in] height is height of display memory + * @param[in] destination is pointer of destination buffer address + * @return none + */ +void ge2dInit(int bpp, int width, int height, void *destination) +{ + UINT32 data32; + + if (destination == NULL) + return; + + NU_GE2D_LOCK(); + + ge2dReset(); + + GFX_WIDTH = width; + GFX_HEIGHT = height; + + _DrawMode = MODE_TRANSPARENT; + _ColorKey = COLOR_KEY; + _ColorKeyMask = 0xFFFFFF; + + GFX_START_ADDR = (void *)destination; + + if (GFX_BPP != bpp) + { + GFX_BPP = bpp; + if (GFX_PAT_ADDR != NULL) + { + rt_free_align(GFX_PAT_ADDR); + GFX_PAT_ADDR = RT_NULL; + } + if (GFX_PAT_ADDR == NULL) + { + uint32_t u32Size = (8 * 8 * (GFX_BPP / 8)) * 2; + GFX_PAT_ADDR = (void *)rt_malloc_align(u32Size, u32Size); + RT_ASSERT(GFX_PAT_ADDR != RT_NULL); + sysprintf("[%s] Allocated %d@0x%08x.\n", __func__, u32Size, GFX_PAT_ADDR); + } + } + + +#ifdef DEBUG + sysprintf("[%s]\n", __func__); + sysprintf("screen width = %d\n", GFX_WIDTH); + sysprintf("screen height = %d\n", GFX_HEIGHT); + sysprintf("screen bpp = %d\n", GFX_BPP); + sysprintf("destination = 0x%x\n", destination); +#endif + + outpw(REG_GE2D_INTSTS, 1); // clear interrupt + outpw(REG_GE2D_PATSA, (unsigned int)GFX_PAT_ADDR); + outpw(REG_GE2D_CTL, 0); // disable interrupt + outpw(REG_GE2D_XYDORG, (unsigned int)GFX_START_ADDR); + outpw(REG_GE2D_XYSORG, (unsigned int)GFX_START_ADDR); + + outpw(REG_GE2D_WRPLNMSK, 0x00ffffff); // write plane mask + + data32 = GE_BPP_8; // default is 8 bpp + + if (GFX_BPP == 16) + { + data32 |= GE_BPP_16; + } + else if (GFX_BPP == 32) + { + data32 |= GE_BPP_32; + } + + outpw(REG_GE2D_MISCTL, data32); +} + +/** + * @brief Reset FIFO of graphics engine. + * @param none + * @return none + */ +void ge2dResetFIFO(void) +{ + UINT32 temp32; + + temp32 = inpw(REG_GE2D_MISCTL); + temp32 |= 0x00000040; + outpw(REG_GE2D_MISCTL, temp32); + temp32 &= 0xffffffbf; + outpw(REG_GE2D_MISCTL, temp32); +} + +/** + * @brief Set BitBlt drawing mode. + * @param[in] opt is drawing mode + * @param[in] ckey is value of color key + * @param[in] mask is value of color mask + * @return none + */ +void ge2dBitblt_SetDrawMode(int opt, int ckey, int mask) +{ + if (opt == MODE_TRANSPARENT) + { + _DrawMode = MODE_TRANSPARENT; + + _ColorKey = make_color(ckey); + _ColorKeyMask = make_color(mask); + + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (opt == MODE_DEST_TRANSPARENT) + { + _DrawMode = MODE_DEST_TRANSPARENT; + + _ColorKey = make_color(ckey); + _ColorKeyMask = make_color(mask); + + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else + { + _DrawMode = MODE_OPAQUE; // default is OPAQUE + } +} + +/** + * @brief Set alpha blending programming. + * @param[in] opt is selection for enable or disable + * @param[in] ks is value of alpha blending factor Ks + * @param[in] kd is value of alpha blending factor Kd + * @return none + */ +int ge2dBitblt_SetAlphaMode(int opt, int ks, int kd) +{ + if (ks + kd > 255) + return -1; + + if (opt == 1) + { + _EnableAlpha = TRUE; + _AlphaKs = ks; + _AlphaKd = kd; + } + else + { + _EnableAlpha = FALSE; + } + + return 0; +} + +/** + * @brief Screen-to-Screen BitBlt with SRCCOPY ROP operation. + * @param[in] srcx is source x position + * @param[in] srcy is source y position + * @param[in] destx is destination x position + * @param[in] desty is destination y position + * @param[in] width is display width + * @param[in] height is display width + * @return none + */ +void ge2dBitblt_ScreenToScreen(int srcx, int srcy, int destx, int desty, int width, int height) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("screen_to_screen_blt():\n"); + sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty); + sysprintf("width=%d height=%d\n", width, height); +#endif + + cmd32 = 0xcc430000; + + outpw(REG_GE2D_CTL, cmd32); + + if (srcx > destx) //+X + { + if (srcy > desty) //+Y + { + } + else //-Y + { + cmd32 |= 0x08; + srcy = srcy + height - 1; + desty = desty + height - 1; + } + } + else //-X + { + if (srcy > desty) //+Y + { + cmd32 |= 0x04; // 010 + srcx = srcx + width - 1; + destx = destx + width - 1; + } + else //-Y + { + cmd32 |= 0xc; // 110 + srcx = srcx + width - 1; + destx = destx + width - 1; + srcy = srcy + height - 1; + desty = desty + height - 1; + } + } + +#ifdef DEBUG + sysprintf("new srcx=%d srcy=%d\n", srcx, srcy); + sysprintf("new destx=%d desty=%d\n", destx, desty); +#endif + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | GFX_WIDTH; + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = srcy << 16 | srcx; + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = desty << 16 | destx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + // + // force to use the same starting address + // + outpw(REG_GE2D_XYSORG, (int)GFX_START_ADDR); + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); //smf + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; // destination pixels control transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Screen-to-Screen BitBlt with ROP option. + * @param[in] srcx is source x position + * @param[in] srcy is source y position + * @param[in] destx is destination x position + * @param[in] desty is destination y position + * @param[in] width is display width + * @param[in] height is display width + * @param[in] rop is rop option + * @return none + */ +void ge2dBitblt_ScreenToScreenRop(int srcx, int srcy, int destx, int desty, int width, int height, int rop) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("screen_to_screen_rop_blt():\n"); + sysprintf("ROP=0x%x\n", rop); + sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty); + sysprintf("width=%d height=%d\n", width, height); +#endif + + cmd32 = 0x00430000 | (rop << 24); + + if (_PatternType == TYPE_MONO) + { + cmd32 |= 0x00000010; // default is TYPE_COLOR + } + + outpw(REG_GE2D_CTL, cmd32); + + if (srcx > destx) //+X + { + if (srcy > desty) //+Y + { + } + else //-Y + { + cmd32 |= 0x08; + srcy = srcy + height - 1; + desty = desty + height - 1; + } + } + else //-X + { + if (srcy > desty) //+Y + { + cmd32 |= 0x04; // 010 + srcx = srcx + width - 1; + destx = destx + width - 1; + } + else //-Y + { + cmd32 |= 0xc; // 110 + srcx = srcx + width - 1; + destx = destx + width - 1; + srcy = srcy + height - 1; + desty = desty + height - 1; + } + } + +#ifdef DEBUG + sysprintf("new srcx=%d srcy=%d\n", srcx, srcy); + sysprintf("new destx=%d desty=%d\n", destx, desty); +#endif + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | GFX_WIDTH; // pitch in pixel + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = srcy << 16 | srcx; + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = desty << 16 | destx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + // + // force to use the same starting address + // + outpw(REG_GE2D_XYSORG, (int)GFX_START_ADDR); + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); //smf + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + if ((rop == 0x00) || (rop == 0xff)) + { + cmd32 = (cmd32 & 0xffff0fff) | 0x00009000; + outpw(REG_GE2D_CTL, cmd32); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Source to destination BitBlt with SRCCOPY ROP operation. + * @param[in] srcx is source x position + * @param[in] srcy is source y position + * @param[in] destx is destination x position + * @param[in] desty is destination y position + * @param[in] width is display width + * @param[in] height is display width + * @param[in] srcpitch is source pixel pitch + * @param[in] destpitch is destination pixel pitch + * @return none + * @note before calling this function, it would set the source and destination origin starting place + */ +void ge2dBitblt_SourceToDestination(int srcx, int srcy, int destx, int desty, int width, int height, int srcpitch, int destpitch) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("source_to_destination_blt():\n"); + sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty); + sysprintf("width=%d height=%d\n", width, height); +#endif + + cmd32 = 0xcc430000; + + outpw(REG_GE2D_CTL, cmd32); + + if (srcx > destx) //+X + { + if (srcy > desty) //+Y + { + } + else //-Y + { + cmd32 |= 0x08; + srcy = srcy + height - 1; + desty = desty + height - 1; + } + } + else //-X + { + if (srcy > desty) //+Y + { + cmd32 |= 0x04; // 010 + srcx = srcx + width - 1; + destx = destx + width - 1; + } + else //-Y + { + cmd32 |= 0xc; // 110 + srcx = srcx + width - 1; + destx = destx + width - 1; + srcy = srcy + height - 1; + desty = desty + height - 1; + } + } + +#ifdef DEBUG + sysprintf("new srcx=%d srcy=%d\n", srcx, srcy); + sysprintf("new destx=%d desty=%d\n", destx, desty); +#endif + + outpw(REG_GE2D_CTL, cmd32); + + pitch = destpitch << 16 | srcpitch; // pitch in pixel, back | GFX_WIDTH ?? + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = srcy << 16 | srcx; + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = desty << 16 | destx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; // destination pixels control transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Set the clip rectangle. (top-left to down-right). + * @param[in] x1 is top-left x position + * @param[in] y1 is top-left y position + * @param[in] x2 is down-right x position + * @param[in] y2 is down-right y position + * @return none + */ +void ge2dClip_SetClip(int x1, int y1, int x2, int y2) +{ + +#ifdef DEBUG + sysprintf("set_clip(): (%d,%d)-(%d,%d)\n", x1, y1, x2, y2); +#endif + + if ((x1 >= 0) && (y1 >= 0) && (x2 >= 0) && (y2 >= 0)) + { + if ((x2 > x1) && (y2 > y1)) + { + _ClipEnable = TRUE; + /* hardware clipper not includes last pixel */ + x2++; + y2++; + _ClipTL = (UINT32)((y1 << 16) | x1); + _ClipBR = (UINT32)((y2 << 16) | x2); + } + else + { + _ClipEnable = FALSE; + } + } + else + { + _ClipEnable = FALSE; + } +} + +/** + * @brief Set the clip to inside clip or outside clip. + * @param[in] opt is option for setting clip inside or outside, value could be + * - \ref MODE_INSIDE_CLIP + * - \ref MODE_OUTSIDE_CLIP + * @return none + */ +void ge2dClip_SetClipMode(int opt) +{ + _OutsideClip = (opt == 0) ? FALSE : TRUE; + + if (_OutsideClip) + { +#ifdef DEBUG + sysprintf("set_clip_mode(): OUTSIDE\n"); +#endif + } + else + { +#ifdef DEBUG + sysprintf("set_clip_mode(): INSIDE\n"); +#endif + } +} + +/** + * @brief Draw an one-pixel rectangle frame. + * @param[in] x1 is top-left x position + * @param[in] y1 is top-left y position + * @param[in] x2 is down-right x position + * @param[in] y2 is down-right y position + * @param[in] color is color of this rectangle + * @param[in] opt is draw option, value could be + * - 0: rectangle + * - 1: diagonal + * @return none + */ +void ge2dDrawFrame(int x1, int y1, int x2, int y2, int color, int opt) +{ + UINT32 dest_pitch, dest_start, dest_dimension; + UINT32 color32; + +#ifdef DEBUG + sysprintf("draw_frame():\n"); + sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2); + sysprintf("color=0x%x opt=%d\n", color, opt); +#endif + + /* + ** The opt==1 case must be specially handled. + */ + + if (opt == 0) + { + outpw(REG_GE2D_CTL, 0xcccb0000); // rectangle + } + else + { + outpw(REG_GE2D_CTL, 0xcccf0000); // diagonal + } + +#ifdef DEBUG + sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2); +#endif + + color32 = make_color(color); + outpw(REG_GE2D_FGCOLR, color32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = y1 << 16 | x1; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = (y2 - y1) << 16 | (x2 - x1); + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + outpw(REG_GE2D_MISCTL, inpw(REG_GE2D_MISCTL)); // address caculation + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Draw an solid rectangle line. + * @param[in] x1 is top-left x position + * @param[in] y1 is top-left y position + * @param[in] x2 is down-right x position + * @param[in] y2 is down-right y position + * @param[in] color is color of this line + * @return none + */ +void ge2dLine_DrawSolidLine(int x1, int y1, int x2, int y2, int color) +{ + int abs_X, abs_Y, min, max; + UINT32 step_constant, initial_error, direction_code; + UINT32 cmd32, dest_pitch, dest_start; + +#ifdef DEBUG + sysprintf("draw_solid_line():\n"); + sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2); + sysprintf("color=0x%x\n", color); +#endif + + abs_X = ABS(x2 - x1); //absolute value + abs_Y = ABS(y2 - y1); //absolute value + if (abs_X > abs_Y) // X major + { + max = abs_X; + min = abs_Y; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpXl; + else // -Y direction + direction_code = XpYmXl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpXl; + else // -Y direction + direction_code = XmYmXl; + } + } + else // Y major + { + max = abs_Y; + min = abs_X; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpYl; + else // -Y direction + direction_code = XpYmYl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpYl; + else // -Y direction + direction_code = XmYmYl; + } + } + + outpw(REG_GE2D_BETSC, step_constant); + outpw(REG_GE2D_BIEPC, initial_error); + + cmd32 = 0x008b0000 | direction_code; + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_BGCOLR, make_color(color)); + outpw(REG_GE2D_FGCOLR, make_color(color)); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); + + dest_start = y1 << 16 | x1; + outpw(REG_GE2D_DSTSPA, dest_start); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Draw an solid rectangle line with assigned RGB565 color + * @param[in] x1 is top-left x position + * @param[in] y1 is top-left y position + * @param[in] x2 is down-right x position + * @param[in] y2 is down-right y position + * @param[in] color is color of this line + * @return none + */ +void ge2dLine_DrawSolidLine_RGB565(int x1, int y1, int x2, int y2, int color) +{ + int abs_X, abs_Y, min, max; + UINT32 step_constant, initial_error, direction_code; + UINT32 cmd32, dest_pitch, dest_start; + +#ifdef DEBUG + sysprintf("draw_solid_line():\n"); + sysprintf("(%d,%d)-(%d,%d)\n", x1, y1, x2, y2); + sysprintf("color=0x%x\n", color); +#endif + + abs_X = ABS(x2 - x1); //absolute value + abs_Y = ABS(y2 - y1); //absolute value + if (abs_X > abs_Y) // X major + { + max = abs_X; + min = abs_Y; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpXl; + else // -Y direction + direction_code = XpYmXl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpXl; + else // -Y direction + direction_code = XmYmXl; + } + } + else // Y major + { + max = abs_Y; + min = abs_X; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * (min) - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpYl; + else // -Y direction + direction_code = XpYmYl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpYl; + else // -Y direction + direction_code = XmYmYl; + } + } + + outpw(REG_GE2D_BETSC, step_constant); + outpw(REG_GE2D_BIEPC, initial_error); + + cmd32 = 0x008b0000 | direction_code; + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_BGCOLR, color); + outpw(REG_GE2D_FGCOLR, color); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); + + dest_start = y1 << 16 | x1; + outpw(REG_GE2D_DSTSPA, dest_start); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + + +/** + * @brief Draw a styled line. + * @param[in] x1 is top-left x position + * @param[in] y1 is top-left y position + * @param[in] x2 is down-right x position + * @param[in] y2 is down-right y position + * @param[in] style is style of line pattern + * @param[in] fgcolor is color of foreground + * @param[in] bkcolor is color of background + * @param[in] draw_mode is transparent is enable or not + * @return none + */ +void ge2dLine_DrawStyledLine(int x1, int y1, int x2, int y2, int style, int fgcolor, int bkcolor, int draw_mode) +{ + int abs_X, abs_Y, min, max; + UINT32 step_constant, initial_error, direction_code; + UINT32 cmd32, dest_pitch, dest_start; + UINT32 temp32, line_control_code; + + abs_X = ABS(x2 - x1); + abs_Y = ABS(y2 - y1); + if (abs_X > abs_Y) // X major + { + max = abs_X; + min = abs_Y; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpXl; + else // -Y direction + direction_code = XpYmXl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpXl; + else // -Y direction + direction_code = XmYmXl; + } + } + else // Y major + { + max = abs_Y; + min = abs_X; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpYl; + else // -Y direction + direction_code = XpYmYl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpYl; + else // -Y direction + direction_code = XmYmYl; + } + } + + outpw(REG_GE2D_BETSC, step_constant); + outpw(REG_GE2D_BIEPC, initial_error); + + cmd32 = 0x009b0000 | direction_code; // styled line + if (draw_mode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // default is MODE_OPAQUE + } + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_BGCOLR, make_color(bkcolor)); + outpw(REG_GE2D_FGCOLR, make_color(fgcolor)); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); + + dest_start = y1 << 16 | x1; + outpw(REG_GE2D_DSTSPA, dest_start); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + line_control_code = style; + temp32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + temp32 = (line_control_code << 16) | temp32; + + outpw(REG_GE2D_MISCTL, temp32); // address caculation + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Draw a styled line using RGB565 color + * @param[in] x1 is top-left x position + * @param[in] y1 is top-left y position + * @param[in] x2 is down-right x position + * @param[in] y2 is down-right y position + * @param[in] style is style of line pattern + * @param[in] fgcolor is color of foreground + * @param[in] bkcolor is color of background + * @param[in] draw_mode is transparent is enable or not + * @return none + */ +void ge2dLine_DrawStyledLine_RGB565(int x1, int y1, int x2, int y2, int style, int fgcolor, int bkcolor, int draw_mode) +{ + int abs_X, abs_Y, min, max; + UINT32 step_constant, initial_error, direction_code; + UINT32 cmd32, dest_pitch, dest_start; + UINT32 temp32, line_control_code; + + abs_X = ABS(x2 - x1); + abs_Y = ABS(y2 - y1); + if (abs_X > abs_Y) // X major + { + max = abs_X; + min = abs_Y; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpXl; + else // -Y direction + direction_code = XpYmXl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpXl; + else // -Y direction + direction_code = XmYmXl; + } + } + else // Y major + { + max = abs_Y; + min = abs_X; + + step_constant = (((UINT32)(2 * (min - max))) << 16) | (UINT32)(2 * min); + initial_error = (((UINT32)(2 * min - max)) << 16) | (UINT32)(max); + + if (x2 > x1) // +X direction + { + if (y2 > y1) // +Y direction + direction_code = XpYpYl; + else // -Y direction + direction_code = XpYmYl; + } + else // -X direction + { + if (y2 > y1) // +Y direction + direction_code = XmYpYl; + else // -Y direction + direction_code = XmYmYl; + } + } + + outpw(REG_GE2D_BETSC, step_constant); + outpw(REG_GE2D_BIEPC, initial_error); + + cmd32 = 0x009b0000 | direction_code; // styled line + if (draw_mode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // default is MODE_OPAQUE + } + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_BGCOLR, bkcolor); + outpw(REG_GE2D_FGCOLR, fgcolor); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); + + dest_start = y1 << 16 | x1; + outpw(REG_GE2D_DSTSPA, dest_start); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + line_control_code = style; + temp32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + temp32 = (line_control_code << 16) | temp32; + + outpw(REG_GE2D_MISCTL, temp32); // address caculation + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle solid color fill with foreground color. + * @param[in] dx x position + * @param[in] dy y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] color is color of foreground + * @return none + */ +void ge2dFill_Solid(int dx, int dy, int width, int height, int color) +{ + UINT32 cmd32, color32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("solid_fill() begin\n"); + sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1); + sysprintf("color=0x%x\n", color); +#endif + + color32 = make_color(color); + cmd32 = 0xcc430060; + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_FGCOLR, color32); // fill with foreground color + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = dy << 16 | dx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle solid color fill with RGB565 color. + * @param[in] dx x position + * @param[in] dy y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] color is RGB565 color of foreground + * @return none + */ +void ge2dFill_Solid_RGB565(int dx, int dy, int width, int height, int color) +{ + UINT32 cmd32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("solid_fill()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1); + sysprintf("color=0x%x\n", color); +#endif + + cmd32 = 0xcc430060; + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_FGCOLR, color); // fill with foreground color + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = dy << 16 | dx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle solid color fill with background color. + * @param[in] dx x position + * @param[in] dy y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] color is color of background + * @return none + */ +void ge2dFill_SolidBackground(int dx, int dy, int width, int height, int color) +{ + UINT32 cmd32, color32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("solid_fill_back()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1); + sysprintf("color=0x%x\n", color); +#endif + + color32 = make_color(color); + + cmd32 = 0xcc430040; + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_BGCOLR, color32); // fill with foreground color + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = dy << 16 | dx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle fill with 8x8 color pattern. + * @param[in] dx x position + * @param[in] dy y position + * @param[in] width is display width + * @param[in] height is display height + * @return none + * @note The color pattern data is stored in the off-screen buffer. + */ +void ge2dFill_ColorPattern(int dx, int dy, int width, int height) +{ + UINT32 cmd32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("color_pattern_fill()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1); + sysprintf("pattern offset (%d,%d)\n", dx % 8, dy % 8); +#endif + + cmd32 = 0xf0430000; + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = dy << 16 | dx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle fill with 8x8 mono pattern. + * @param[in] dx x position + * @param[in] dy y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] opt is transparent is enable or not + * @return none + */ +void ge2dFill_MonoPattern(int dx, int dy, int width, int height, int opt) +{ + UINT32 cmd32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("mono_pattern_fill()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", dx, dy, dx + width - 1, dy + height - 1); +#endif + + cmd32 = 0xf0430010; + if (opt == MODE_TRANSPARENT) + { + cmd32 |= 0x00006000; + } + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = dy << 16 | dx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle fill with 8x8 color pattern. + * @param[in] sx x position + * @param[in] sy y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] rop is ROP operation code + * @return none + */ +void ge2dFill_ColorPatternROP(int sx, int sy, int width, int height, int rop) +{ + UINT32 cmd32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("color_pattern_fill()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", sx, sy, sx + width - 1, sy + height - 1); + sysprintf("pattern offset (%d,%d)\n", sx % 8, sy % 8); +#endif + + cmd32 = 0x00430000 | (rop << 24); + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = sy << 16 | sx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Rectangle fill with 8x8 mono pattern. + * @param[in] sx x position + * @param[in] sy y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] opt is transparent is enable or not + * @param[in] rop is ROP operation code + * @return none + */ +void ge2dFill_MonoPatternROP(int sx, int sy, int width, int height, int rop, int opt) +{ + UINT32 cmd32; + UINT32 dest_start, dest_pitch, dest_dimension; + +#ifdef DEBUG + sysprintf("mono_pattern_fill()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", sx, sy, sx + width - 1, sy + height - 1); +#endif + + cmd32 = 0x00430010 | (rop << 24); + if (opt == MODE_TRANSPARENT) + { + cmd32 |= 0x00006000; + } + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = sy << 16 | sx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief TileBLT function. + * @param[in] srcx source x position + * @param[in] srcy source y position + * @param[in] destx destination x position + * @param[in] desty destination y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] x_count is tile count for x-axis + * @param[in] y_count is tile count for y-axis + * @return none + */ +void ge2dFill_TileBlt(int srcx, int srcy, int destx, int desty, int width, int height, int x_count, int y_count) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 tile_ctl; + +#ifdef DEBUG + sysprintf("tile_blt_image()\n"); + sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty); + sysprintf("width=%d height=%d\n", width, height); + sysprintf("%dx%d grids\n", x_count, y_count); +#endif + + if (x_count > 0) x_count--; + if (y_count > 0) y_count--; + + cmd32 = 0xcc430400; // b10 is the tile control + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | GFX_WIDTH; // pitch in pixel + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = srcy << 16 | srcx; // redundancy ?? + outpw(REG_GE2D_SRCSPA, src_start); // redundancy ?? + + dest_start = desty << 16 | destx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + tile_ctl = (y_count << 8) | (x_count); + outpw(REG_GE2D_TCNTVHSF, tile_ctl); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Host-to-Screen BitBlt with SRCCOPY (through data port) + * @param[in] x x position + * @param[in] y y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] buf is pointer of HostBLT data + * @return none + */ +void ge2dHostBlt_Write(int x, int y, int width, int height, void *buf) +{ + UINT32 cmd32, dest_pitch, dest_start, dest_dimension; + int transfer_count, i, j; + UINT32 *ptr32, data32; + +#ifdef DEBUG + sysprintf("host_write_blt()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", x, y, x + width - 1, y + height - 1); + sysprintf("width=%d height=%d\n", width, height); +#endif + + cmd32 = 0xcc430020; + + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + outpw(REG_GE2D_TRG, 1); + + ptr32 = (UINT32 *)buf; + for (i = 0; i < height; i++) // 120 + { + transfer_count = (width * (GFX_BPP / 8) + 3) / 4; // 4-byte count + + while (transfer_count >= 8) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty + for (j = 0; j < 8; j++) + { + data32 = *ptr32++; + outpw(REG_GE2D_GEHBDW0, data32); + } + transfer_count -= 8; + } + + if (transfer_count > 0) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty + for (j = 0; j < transfer_count; j++) + { + data32 = *ptr32++; + outpw(REG_GE2D_GEHBDW0, data32); + } + } + } + + while ((inpw(REG_GE2D_INTSTS) & 0x01) == 0); // wait for command complete + outpw(REG_GE2D_INTSTS, 1); // clear interrupt status +} + +/** + * @brief Screen-to-Host BitBlt with SRCCOPY (through data port). + * @param[in] x x position + * @param[in] y y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] buf is pointer of HostBLT data + * @return none + */ +void ge2dHostBlt_Read(int x, int y, int width, int height, void *buf) +{ + UINT32 cmd32, dest_pitch, dest_start, dest_dimension; + int transfer_count, i, j; + UINT32 *ptr32; + +#ifdef DEBUG + sysprintf("host_read_blt()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", x, y, x + width - 1, y + height - 1); + sysprintf("width=%d height=%d\n", width, height); +#endif + + cmd32 = 0xcc430001; + + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + outpw(REG_GE2D_TRG, 1); + + ptr32 = (UINT32 *)buf; + for (i = 0; i < height; i++) + { + transfer_count = (width * (GFX_BPP / 8) + 3) / 4; // 4-byte count + + while (transfer_count >= 8) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000400) == 0); + for (j = 0; j < 8; j++) + { + *ptr32++ = inpw(REG_GE2D_GEHBDW0); + } + transfer_count -= 8; + } + + if (transfer_count > 0) + { + while (((inpw(REG_GE2D_MISCTL) & 0x0000f000) >> 12) != transfer_count); + for (j = 0; j < transfer_count; j++) + { + *ptr32++ = inpw(REG_GE2D_GEHBDW0); + } + } + } + + while ((inpw(REG_GE2D_INTSTS) & 0x01) == 0); // wait for command complete + + outpw(REG_GE2D_INTSTS, 1); // clear interrupt status +} + +/** + * @brief Host-to-Screen SpriteBlt with SRCCOPY. + * @param[in] x x position + * @param[in] y y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] buf is pointer of HostBLT data + * @return none + */ +void ge2dHostBlt_Sprite(int x, int y, int width, int height, void *buf) +{ + UINT32 cmd32, dest_pitch, dest_start, dest_dimension; + int transfer_count, i, j; + UINT32 *ptr32, data32, alpha; + +#ifdef DEBUG + sysprintf("host_sprite_blt()\n"); + sysprintf("(%d,%d)-(%d,%d)\n", x, y, x + width - 1, y + height - 1); +#endif + + cmd32 = 0xcc430020; + + outpw(REG_GE2D_CTL, cmd32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + outpw(REG_GE2D_TRG, 1); + + ptr32 = (UINT32 *)buf; + for (i = 0; i < height; i++) + { + transfer_count = width * (GFX_BPP / 8) / 4; // 4-byte count + + while (transfer_count > 8) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty + for (j = 0; j < 8; j++) + { + data32 = *ptr32++; + outpw(REG_GE2D_GEHBDW0, data32); + } + transfer_count -= 8; + } + + if (transfer_count > 0) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty + for (j = 0; j < transfer_count; j++) + { + data32 = *ptr32++; + outpw(REG_GE2D_GEHBDW0, data32); + } + } + } + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Captured the specified photo data from display memory, then displayed on display memory by rotation angle + * @param[in] srcx source x position + * @param[in] srcy source y position + * @param[in] destx destination x position + * @param[in] desty destination y position + * @param[in] width is display width + * @param[in] height is display height + * @param[in] ctl is drawing direction + * @return none + */ +void ge2dRotation(int srcx, int srcy, int destx, int desty, int width, int height, int ctl) +{ + UINT32 cmd32, dest_start, src_start, dimension, pitch; + void *tmpscreen, *orig_dest_start00; + + tmpscreen = (void *)rt_malloc(width * height * GFX_BPP / 8); + +#ifdef DEBUG + sysprintf("rotation_image()\n"); + sysprintf("(%d,%d)=>(%d,%d)\n", srcx, srcy, destx, desty); + sysprintf("width=%d height=%d\n", width, height); +#endif + + rt_memset(tmpscreen, 0, width * height * GFX_BPP / 8); + + orig_dest_start00 = (void *)inpw(REG_GE2D_XYDORG); + outpw(REG_GE2D_XYDORG, (int)tmpscreen); //captured photo to another position + outpw(REG_GE2D_XYSORG, (int)GFX_START_ADDR); + + ge2dBitblt_SourceToDestination(srcx, srcy, 0, 0, width, height, GFX_WIDTH, width); + + src_start = dest_start = dimension = cmd32 = pitch = 0; + + outpw(REG_GE2D_XYDORG, (int)orig_dest_start00); + outpw(REG_GE2D_XYSORG, (int)tmpscreen); + + pitch = GFX_WIDTH << 16 | width; + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = 0 << 16 | 0; // captured photo at (0,0) position + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = desty << 16 | destx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + cmd32 = 0xcc030000 | (ctl << 1); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + /* set rotation reference point xy register, then nothing happened */ + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + rt_free(tmpscreen); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief OffScreen-to-OnScreen SpriteBlt with SRCCOPY. + * @param[in] destx destination x position + * @param[in] desty destination y position + * @param[in] sprite_width is sprite width + * @param[in] sprite_height is sprite height + * @param[in] buf is pointer of origin data + * @return none + */ +void ge2dSpriteBlt_Screen(int destx, int desty, int sprite_width, int sprite_height, void *buf) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("screen_sprite_blt():\n"); + sysprintf("buf=%08x, x=%d y=%d width=%d height=%d\n", buf, destx, desty, sprite_width, sprite_height); +#endif + + cmd32 = 0xcc430000; + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = 0; // start from (0,0) of sprite + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = desty << 16 | destx; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = sprite_height << 16 | sprite_width; + outpw(REG_GE2D_RTGLSZ, dimension); + + outpw(REG_GE2D_XYSORG, (UINT32)buf); + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; // destination pixels control transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief OffScreen-to-OnScreen SpriteBlt with SRCCOPY. + * @param[in] x x position + * @param[in] y y position + * @param[in] sprite_sx sprite x position + * @param[in] sprite_sy sprite y position + * @param[in] width is width + * @param[in] height is height + * @param[in] sprite_width is sprite width + * @param[in] sprite_height is sprite height + * @param[in] buf is pointer of origin data + * @return none + * @note The sprite starting address can be programmed. + */ +void ge2dSpriteBltx_Screen(int x, int y, int sprite_sx, int sprite_sy, int width, int height, int sprite_width, int sprite_height, void *buf) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("screen_sprite_bltx(): (%d,%d)\n", x, y); + sysprintf("sprite width=%d height=%d\n", sprite_width, sprite_height); + sysprintf("x=%d y=%d width=%d height=%d\n", sprite_sx, sprite_sy, width, height); +#endif + + cmd32 = 0xcc430000; + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel + outpw(REG_GE2D_SDPITCH, pitch); + + outpw(REG_GE2D_XYSORG, (UINT32)buf); + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); + + src_start = sprite_sy << 16 | sprite_sx; + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; // destination pixels control transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief OffScreen-to-OnScreen SpriteBlt with ROP. + * @param[in] x x position + * @param[in] y y position + * @param[in] sprite_width is sprite width + * @param[in] sprite_height is sprite height + * @param[in] buf is pointer of origin data + * @param[in] rop is ROP operation code + * @return none + * @note The sprite always starts from (0,0) for the BLT. + */ +void ge2dSpriteBlt_ScreenRop(int x, int y, int sprite_width, int sprite_height, void *buf, int rop) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("screen_sprite_rop_blt():\n"); + sysprintf("x=%d y=%d width=%d height=%d\n", x, y, sprite_width, sprite_height); + sysprintf("rop=0x%x\n", rop); +#endif + + cmd32 = 0x00430000 | (rop << 24); + + if (_PatternType == TYPE_MONO) + { + cmd32 |= 0x00000010; // default is TYPE_COLOR + } + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = 0; // start from (0,0) of sprite + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = sprite_height << 16 | sprite_width; + outpw(REG_GE2D_RTGLSZ, dimension); + + outpw(REG_GE2D_XYSORG, (UINT32)buf); + outpw(REG_GE2D_XYDORG, (int) GFX_START_ADDR); //smf + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; // destination pixels control transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + if ((rop == 0x00) || (rop == 0xff)) + { + cmd32 = (cmd32 & 0xffff0fff) | 0x00009000; + outpw(REG_GE2D_CTL, cmd32); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief OffScreen-to-OnScreen SpriteBlt with ROP. + * @param[in] x x position + * @param[in] y y position + * @param[in] sprite_sx sprite x position + * @param[in] sprite_sy sprite y position + * @param[in] width is width + * @param[in] height is height + * @param[in] sprite_width is sprite width + * @param[in] sprite_height is sprite height + * @param[in] buf is pointer of origin data + * @param[in] rop is ROP operation code + * @return none + * @note The sprite always starts from (0,0) for the BLT. + */ +void ge2dSpriteBltx_ScreenRop(int x, int y, int sprite_sx, int sprite_sy, int width, int height, int sprite_width, int sprite_height, void *buf, int rop) +{ + UINT32 cmd32, pitch, dest_start, src_start, dimension; + UINT32 data32, alpha; + +#ifdef DEBUG + sysprintf("screen_sprite_rop_bltx():\n"); + sysprintf("x=%d y=%d width=%d height=%d\n", x, y, sprite_width, sprite_height); + sysprintf("rop=0x%x\n", rop); +#endif + + cmd32 = 0x00430000 | (rop << 24); + + if (_PatternType == TYPE_MONO) + { + cmd32 |= 0x00000010; // default is TYPE_COLOR + } + + outpw(REG_GE2D_CTL, cmd32); + + pitch = GFX_WIDTH << 16 | sprite_width; // pitch in pixel + outpw(REG_GE2D_SDPITCH, pitch); + + src_start = sprite_sy << 16 | sprite_sx; + outpw(REG_GE2D_SRCSPA, src_start); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dimension); + + outpw(REG_GE2D_XYSORG, (UINT32)buf); + outpw(REG_GE2D_XYDORG, (int)GFX_START_ADDR); //smf + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + if (_DrawMode == MODE_TRANSPARENT) + { + cmd32 |= 0x00008000; // color transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + else if (_DrawMode == MODE_DEST_TRANSPARENT) + { + cmd32 |= 0x00009000; // destination pixels control transparency + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_TRNSCOLR, _ColorKey); + outpw(REG_GE2D_TCMSK, _ColorKeyMask); + } + + if (_EnableAlpha) + { + cmd32 |= 0x00200000; + outpw(REG_GE2D_CTL, cmd32); + + data32 = inpw(REG_GE2D_MISCTL) & 0x0000ffff; + alpha = (UINT32)((_AlphaKs << 8) | _AlphaKd); + data32 |= (alpha << 16); + + outpw(REG_GE2D_MISCTL, data32); + } + + if ((rop == 0x00) || (rop == 0xff)) + { + cmd32 = (cmd32 & 0xffff0fff) | 0x00009000; + outpw(REG_GE2D_CTL, cmd32); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief OffScreen-to-OnScreen TextBLT. + * @param[in] x x position + * @param[in] y y position + * @param[in] width is width + * @param[in] height is height + * @param[in] fore_color is color of foreground + * @param[in] back_color is color of background + * @param[in] opt is transparent is enable or not + * @param[in] buf is pointer of origin data + * @return none + * @note Fetch the monochrome source data from off-screen memory to the desired destination area + */ +void ge2dColorExpansionBlt(int x, int y, int width, int height, int fore_color, int back_color, int opt, void *buf) +{ + UINT32 cmd32, dest_pitch, src_pitch, pitch, dest_start, dest_dimension; + UINT32 fore_color32, back_color32; + + fore_color32 = make_color(fore_color); + back_color32 = make_color(back_color); + + cmd32 = 0xcc430080; + if (opt == MODE_TRANSPARENT) + { + cmd32 |= 0x00004000; // mono transparency + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_FGCOLR, fore_color32); + outpw(REG_GE2D_BGCOLR, back_color32); + + dest_pitch = GFX_WIDTH; // pitch in pixels + src_pitch = width; // pitch in pixels + + pitch = (dest_pitch << 16) | src_pitch; + outpw(REG_GE2D_SDPITCH, pitch); + + outpw(REG_GE2D_XYSORG, (int)buf); + outpw(REG_GE2D_SRCSPA, 0); // always start from (0,0) + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + if (_ClipEnable) + { + cmd32 |= 0x00000200; + if (_OutsideClip) + { + cmd32 |= 0x00000100; + } + outpw(REG_GE2D_CTL, cmd32); + outpw(REG_GE2D_CLPBTL, _ClipTL); + outpw(REG_GE2D_CLPBBR, _ClipBR); + } + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Host-to-Screen TextBLT through data port. + * @param[in] x x position + * @param[in] y y position + * @param[in] width is width + * @param[in] height is height + * @param[in] fore_color is color of foreground + * @param[in] back_color is color of background + * @param[in] opt is transparent is enable or not + * @param[in] buf is pointer of origin data + * @return none + */ +void ge2dHostColorExpansionBlt(int x, int y, int width, int height, int fore_color, int back_color, int opt, void *buf) +{ + UINT32 cmd32, dest_pitch, dest_start, dest_dimension; + UINT32 fore_color32, back_color32; + UINT32 *ptr32, data32; + int transfer_count, i, j; + + fore_color32 = make_color(fore_color); + back_color32 = make_color(back_color); + + cmd32 = 0xcc4300a0; + if (opt == MODE_TRANSPARENT) + { + cmd32 |= 0x00004000; // mono transparency + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_FGCOLR, fore_color32); + outpw(REG_GE2D_BGCOLR, back_color32); + + dest_pitch = GFX_WIDTH << 16; // pitch in pixel + outpw(REG_GE2D_SDPITCH, dest_pitch); + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + outpw(REG_GE2D_SRCSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + outpw(REG_GE2D_TRG, 1); + + ptr32 = (UINT32 *)buf; + for (i = 0; i < height; i++) + { + transfer_count = (width + 31) / 32; // 32 pixels unit + + while (transfer_count > 8) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty + for (j = 0; j < 8; j++) + { + data32 = *ptr32++; + outpw(REG_GE2D_GEHBDW0, data32); + } + transfer_count -= 8; + } + + if (transfer_count > 0) + { + while ((inpw(REG_GE2D_MISCTL) & 0x00000800) == 0); // check empty + for (j = 0; j < transfer_count; j++) + { + data32 = *ptr32++; + outpw(REG_GE2D_GEHBDW0, data32); + } + } + } + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Set the 8x8 mono pattern for following BitBLT functions. + * @param[in] opt is index for build-in pattern + * @param[in] fore_color is color of foreground + * @param[in] back_color is color of background + * @return none + */ +void ge2dInitMonoPattern(int opt, int fore_color, int back_color) +{ + UINT32 color32; + + /* + ** If hardware pattern definition is a little different from software. + ** Need to do the BYTE swap before programming the pattern registers. + */ + + outpw(REG_GE2D_PTNA, MonoPatternData[opt].PatternA); + outpw(REG_GE2D_PTNB, MonoPatternData[opt].PatternB); + + color32 = make_color(fore_color); + outpw(REG_GE2D_FGCOLR, color32); + + color32 = make_color(back_color); + outpw(REG_GE2D_BGCOLR, color32); + + _PatternType = TYPE_MONO; +} + +/** + * @brief Set the 8x8 mono pattern for following BitBLT functions. + * @param[in] PatternA is pattern A + * @param[in] PatternB is pattern B + * @param[in] fore_color is color of foreground + * @param[in] back_color is color of background + * @return none + */ +void ge2dInitMonoInputPattern(UINT32 PatternA, UINT32 PatternB, int fore_color, int back_color) +{ + UINT32 color32; + + /* + ** If hardware pattern definition is a little different from software. + ** Need to do the BYTE swap before programming the pattern registers. + */ + + outpw(REG_GE2D_PTNA, PatternA); + outpw(REG_GE2D_PTNB, PatternB); + + color32 = make_color(fore_color); + outpw(REG_GE2D_FGCOLR, color32); + + color32 = make_color(back_color); + outpw(REG_GE2D_BGCOLR, color32); + + _PatternType = TYPE_MONO; +} + +/** + * @brief Set the 8x8 color pattern for following BitBLT functions. + * @param[in] patformat is format of pattern, value could be + * - \ref RGB888 + * - \ref RGB565 + * - \ref RGB332 + * @param[in] patdata is pointer of input pattern image + * @return none + * @note This function transfers those forms: + * RGB888 to RGB565 or RGB332 + * RGB565 to RGB332 or RGB888 + * RGB332 to RGB565 or RGB888 + */ +void ge2dInitColorPattern(int patformat, void *patdata) +{ + UINT8 *ptr_pat; + UINT8 *ptr8, r8, g8, b8; + UINT16 *ptr16, r16, g16, b16, g16_1, g16_2; + UINT32 *ptr32, r32, g32, b32, g32_1, g32_2; + int idx; + + ptr_pat = (UINT8 *)patdata; + if (patformat == RGB888) + { + if (GFX_BPP == 8) + { + ptr8 = (UINT8 *)GFX_PAT_ADDR; + for (idx = 0; idx < 64; idx++) + { + b8 = (UINT8)(*ptr_pat++) & 0xc0; // 2 bits + g8 = (UINT8)(*ptr_pat++) & 0xe0; // 3 bits + r8 = (UINT8)(*ptr_pat++) & 0xe0; // 3 bits + ptr_pat++; + *ptr8++ = r8 | (g8 >> 3) | (b8 >> 6); + } + } + else if (GFX_BPP == 16) + { + ptr16 = (UINT16 *)GFX_PAT_ADDR; + for (idx = 0; idx < 64; idx++) + { + b16 = (UINT16)(*ptr_pat++) & 0x000f8; // 5 bits + g16 = (UINT16)(*ptr_pat++) & 0x000fc; // 6 bits + r16 = (UINT16)(*ptr_pat++) & 0x000f8; // 5 bits + ptr_pat++; + *ptr16++ = (r16 << 8) | (g16 << 3) | (b16 >> 3); + } + } + else if (GFX_BPP == 32) + { + ptr32 = (UINT32 *)GFX_PAT_ADDR; + for (idx = 0; idx < 64; idx++) + { + b32 = (UINT32)(*ptr_pat++); + g32 = (UINT32)(*ptr_pat++); + r32 = (UINT32)(*ptr_pat++); + ptr_pat++; + *ptr32++ = (r32 << 16) | (g32 << 8) | b32; + } + } + } + else if (patformat == RGB565) + { + if (GFX_BPP == 8) + { + ptr8 = (UINT8 *)GFX_PAT_ADDR; + + for (idx = 0; idx < 64; idx++) + { + b8 = (UINT8)(*ptr_pat++) & 0x00018; // 2 bits + g8 = (UINT8)(*ptr_pat) & 0x00007; // 3 bits + r8 = (UINT8)(*ptr_pat++) & 0x000e0; // 3bits + *ptr8++ = r8 | (g8 << 2) | (b8 >> 3); + } + } + else if (GFX_BPP == 16) + { + ptr16 = (UINT16 *)GFX_PAT_ADDR; + + for (idx = 0; idx < 64; idx++) + { + *ptr16++ = (*ptr_pat) | (*(ptr_pat + 1)) << 8; + ptr_pat += 2; + } + } + else if (GFX_BPP == 32) + { + ptr32 = (UINT32 *)GFX_PAT_ADDR; + + for (idx = 0; idx < 64; idx++) + { + b32 = (UINT8)(*ptr_pat) & 0x1f; // 5 bits + g32_1 = (UINT8)(*ptr_pat++) & 0xe0; // front 3 bits + g32_2 = (UINT8)(*ptr_pat) & 0x07; // back 3 bits + g32 = ((g32_1 >> 5) | (g32_2 << 3)) << 2; + r32 = (UINT8)(*ptr_pat++) & 0xf8; // 5 bits + *ptr32++ = 0 << 24 | (r32 << 16) | (g32 << 8) | (b32 << 3); + } + } + } + else if (patformat == RGB332) + { + if (GFX_BPP == 8) + { + ptr8 = (UINT8 *)GFX_PAT_ADDR; + + for (idx = 0; idx < 64; idx++) + { + *ptr8++ = *ptr_pat; + ptr_pat++; + } + } + else if (GFX_BPP == 16) + { + ptr16 = (UINT16 *)GFX_PAT_ADDR; + + for (idx = 0; idx < 64; idx++) + { + r16 = (UINT8)(*ptr_pat) & 0xe0; // 3 bits + g16_1 = (UINT8)(*ptr_pat) & 0x10; + g16_2 = (UINT8)(*ptr_pat) & 0x0c; + g16 = (g16_1 >> 2) | (g16_2 >> 2); + b16 = (UINT8)(*ptr_pat++) & 0x3; // 2 bits + *ptr16++ = (r16 << 8) | (g16 << 8) | (b16 << 3); + } + } + else if (GFX_BPP == 32) + { + ptr32 = (UINT32 *)GFX_PAT_ADDR; + + for (idx = 0; idx < 64; idx++) + { + r32 = (UINT8)(*ptr_pat) & 0xe0; // 3 bits + g32 = (UINT8)(*ptr_pat) & 0x1c; // 3 bits + b32 = (UINT8)(*ptr_pat++) & 0x3; // 2 bits + *ptr32++ = 0 << 24 | (r32 << 15) | (g32 << 11) | (b32 << 6); + } + } + } + + _PatternType = TYPE_COLOR; +} + +/** + * @brief Display font character. + * @param[in] x x position + * @param[in] y y position + * @param[in] asc_code is ascii code + * @param[in] fore_color is color of foreground + * @param[in] back_color is color of background + * @param[in] draw_mode is transparent is enable or not + * @param[in] font_id is selection of 8x8 or 8x16 font + * @return none + */ +void ge2dFont_PutChar(int x, int y, char asc_code, int fore_color, int back_color, int draw_mode, int font_id) +{ + int cmd32, dest_pitch, src_pitch, pitch, dest_start, dest_dimension; + UINT32 width, height; + UINT32 fore_color32, back_color32; + UINT8 *fptr; + UINT8 *temp_buf[32 * 32], *ptr8; + int idx; + + fore_color32 = make_color(fore_color); + back_color32 = make_color(back_color); + + cmd32 = 0xcc430080; + + if (draw_mode == MODE_TRANSPARENT) + { + cmd32 |= 0x00004000; // mono transparency + } + + outpw(REG_GE2D_CTL, cmd32); + + outpw(REG_GE2D_FGCOLR, fore_color32); + outpw(REG_GE2D_BGCOLR, back_color32); + + if (font_id == F8x16) + { + fptr = (UINT8 *)&FontData16[asc_code][0]; + src_pitch = 32; + width = 32; + height = 16; + + ptr8 = (UINT8 *)&temp_buf[0]; + for (idx = 0; idx < 16; idx++) + { + *ptr8++ = *fptr++; + *ptr8++ = 0; + *ptr8++ = 0; + *ptr8++ = 0; + } + fptr = (UINT8 *)&temp_buf[0]; + } + else /* F8x8 */ + { + fptr = (UINT8 *)&FontData8[asc_code][0]; + src_pitch = 32; + width = 32; + height = 8; + ptr8 = (UINT8 *)&temp_buf[0]; + for (idx = 0; idx < 8; idx++) + { + *ptr8++ = *fptr++; + *ptr8++ = 0; + *ptr8++ = 0; + *ptr8++ = 0; + } + fptr = (UINT8 *)&temp_buf[0]; + } + + dest_pitch = GFX_WIDTH; // pitch in pixels + + pitch = (dest_pitch << 16) | src_pitch; + outpw(REG_GE2D_SDPITCH, pitch); + + outpw(REG_GE2D_XYSORG, (int)fptr); + outpw(REG_GE2D_SRCSPA, 0); // always start from (0,0) + + dest_start = y << 16 | x; + outpw(REG_GE2D_DSTSPA, dest_start); + + dest_dimension = height << 16 | width; + outpw(REG_GE2D_RTGLSZ, dest_dimension); + + outpw(REG_GE2D_TRG, 1); + + NU_GE2D_COND_WAIT(); + + NU_GE2D_UNLOCK(); +} + +/** + * @brief Display font string. + * @param[in] x x position + * @param[in] y y position + * @param[in] str is pointer of display string + * @param[in] fore_color is color of foreground + * @param[in] back_color is color of background + * @param[in] draw_mode is transparent is enable or not + * @param[in] font_id is selection of 8x8 or 8x16 font + * @return none + */ +void ge2dFont_PutString(int x, int y, char *str, int fore_color, int back_color, int draw_mode, int font_id) +{ + char *ptr; + int idx, sx; + + ptr = str; + sx = x; + for (idx = 0; idx < rt_strlen(str); idx++) + { + ge2dFont_PutChar(sx, y, *ptr++, fore_color, back_color, draw_mode, font_id); + sx += 8; //char width + } +} + +/** + * Hardware GE2D Initialization + */ +int rt_hw_ge2d_init(void) +{ + g_sNuGe2d.lock = rt_mutex_create("ge2d_lock", RT_IPC_FLAG_PRIO); + RT_ASSERT(g_sNuGe2d.lock != RT_NULL); + +#if defined(DEF_COND_WAIT) + rt_kprintf("with_cond_wait\n"); + g_sNuGe2d.signal = rt_sem_create("ge2d_wait", 0, RT_IPC_FLAG_FIFO); + RT_ASSERT(g_sNuGe2d.signal != RT_NULL); + + /* Install ISR & Respond the IRQ */ + rt_hw_interrupt_install(g_sNuGe2d.irqn, nu_ge2d_isr, &g_sNuGe2d, g_sNuGe2d.name); + rt_hw_interrupt_umask(g_sNuGe2d.irqn); +#endif + + /* Enable GE2D engine clock */ + nu_sys_ipclk_enable(GE2DCKEN); + + return 0; +} + +INIT_DEVICE_EXPORT(rt_hw_ge2d_init); diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_gpio.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..a6623653c694b69a1d360ff19afb0fd4d6528fc4 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_gpio.c @@ -0,0 +1,388 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if (defined(BSP_USING_GPIO) && defined(RT_USING_PIN)) + +#include +#include +#include "NuMicro.h" +#include +#include +#include +#include + +#define LOG_TAG "drv.gpio" +#define DBG_ENABLE +#define DBG_SECTION_NAME LOG_TAG +#define DBG_LEVEL DBG_INFO +#define DBG_COLOR +#include + +/* Private define ---------------------------------------------------------------*/ + +#define PORT_OFFSET 0x40 +#define IRQ_MAX_NUM 16 //Max support 32 +#define GPIO_PIN_MAX 16 + +/* Private functions ------------------------------------------------------------*/ + +static void nu_gpio_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode); +static void nu_gpio_write(struct rt_device *device, rt_base_t pin, rt_base_t value); +static int nu_gpio_read(struct rt_device *device, rt_base_t pin); +static rt_err_t nu_gpio_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args); +static rt_err_t nu_gpio_detach_irq(struct rt_device *device, rt_int32_t pin); +static rt_err_t nu_gpio_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled); +static rt_base_t nu_gpio_pin_get(const char *name); + +/* Private variables ------------------------------------------------------------*/ +static struct rt_pin_irq_hdr pin_irq_hdr_tab[IRQ_MAX_NUM]; +static struct rt_pin_ops nu_gpio_ops = +{ + nu_gpio_mode, + nu_gpio_write, + nu_gpio_read, + nu_gpio_attach_irq, + nu_gpio_detach_irq, + nu_gpio_irq_enable, + nu_gpio_pin_get, +}; + +static rt_uint32_t g_u32PinIrqMask = 0x0; + +static uint32_t au32PinMaskTbl[] = {GPIOA_MASK, GPIOB_MASK, GPIOC_MASK, GPIOD_MASK, GPIOE_MASK, GPIOF_MASK, GPIOG_MASK, GPIOH_MASK, GPIOI_MASK, GPIOJ_MASK}; + +/* Functions define ------------------------------------------------------------*/ + +static rt_err_t nu_port_check(rt_int32_t pin) +{ + if (NU_GET_PORT(pin) >= NU_PORT_CNT) + { + LOG_E("Over port group. %04x", pin); + return -(RT_ERROR); + } + + if (!(au32PinMaskTbl[NU_GET_PORT(pin)] & NU_GET_PIN_MASK(NU_GET_PINS(pin)))) + { + LOG_E("Over port-pin group. %04x", pin); + return -(RT_ERROR); + } + + return RT_EOK; +} + +static rt_int32_t nu_find_irqindex(rt_uint32_t pin_index) +{ + rt_int32_t irqindex; + rt_int32_t u32PinIrqStatus = g_u32PinIrqMask; + + // Find index of pin is attached in pool. + while ((irqindex = nu_ctz(u32PinIrqStatus)) < IRQ_MAX_NUM) // Count Trailing Zeros ==> Find First One + { + if (pin_irq_hdr_tab[irqindex].pin == pin_index) + return irqindex; + + u32PinIrqStatus &= ~(1 << irqindex); + } + + return -(RT_ERROR); +} + +static void pin_irq_hdr(rt_uint32_t irq_status, rt_uint32_t port_index) +{ + rt_int32_t irqindex, i; + rt_int32_t pinindex = port_index * GPIO_PIN_MAX ; + + while ((i = nu_ctz(irq_status)) < GPIO_PIN_MAX)// Count Trailing Zeros ==> Find First One + { + int pin_mask = (1 << i); + irqindex = nu_find_irqindex(pinindex + i); + if (irqindex != -(RT_ERROR)) + { + if (pin_irq_hdr_tab[irqindex].hdr) + { + pin_irq_hdr_tab[irqindex].hdr(pin_irq_hdr_tab[irqindex].args); + } + } + // Clear the served bit. + irq_status &= ~pin_mask; + } +} + +static rt_base_t nu_gpio_pin_get(const char *name) +{ + /* Get pin number by name,such as PA.0, PF12 */ + if ((name[2] == '\0') || ((name[2] == '.') && (name[3] == '\0'))) + return -(RT_EINVAL); + + long number; + + if ((name[2] == '.')) + number = atol(&name[3]); + else + number = atol(&name[2]); + + if (number > 15) + return -(RT_EINVAL); + + if (name[1] >= 'A' && name[1] <= 'J') + return ((name[1] - 'A') * 0x10) + number; + + if (name[1] >= 'a' && name[1] <= 'i') + return ((name[1] - 'a') * 0x10) + number; + + return -(RT_EINVAL); +} + +static void nu_gpio_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode) +{ + GPIO_PORT PORT; + + if (nu_port_check(pin)) + return; + + PORT = (GPIO_PORT)(GPIOA + (NU_GET_PORT(pin) * PORT_OFFSET)); + + switch (mode) + { + case PIN_MODE_INPUT_PULLUP: + GPIO_OpenBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin)), DIR_INPUT, PULL_UP); + break; + + case PIN_MODE_INPUT_PULLDOWN: + GPIO_OpenBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin)), DIR_INPUT, PULL_DOWN); + break; + + case PIN_MODE_OUTPUT: + GPIO_OpenBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin)), DIR_OUTPUT, NO_PULL_UP); + break; + + case PIN_MODE_INPUT: + GPIO_OpenBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin)), DIR_INPUT, NO_PULL_UP); + break; + + case PIN_MODE_OUTPUT_OD: + default: + LOG_E("Open-drian is not supportted."); + break; + } +} + +static void nu_gpio_write(struct rt_device *device, rt_base_t pin, rt_base_t value) +{ + GPIO_PORT PORT; + + if (nu_port_check(pin)) + return; + + PORT = (GPIO_PORT)(GPIOA + (NU_GET_PORT(pin) * PORT_OFFSET)); + + if (value) + GPIO_SetBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin))); + else + GPIO_ClrBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin))); +} + +static int nu_gpio_read(struct rt_device *device, rt_base_t pin) +{ + GPIO_PORT PORT; + + if (nu_port_check(pin)) + return PIN_LOW; + + PORT = (GPIO_PORT)(GPIOA + (NU_GET_PORT(pin) * PORT_OFFSET)); + + return GPIO_ReadBit(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin))); +} + +static rt_err_t nu_gpio_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args) +{ + rt_base_t level; + rt_int32_t irqindex; + + if (nu_port_check(pin)) + return -(RT_ERROR); + + level = rt_hw_interrupt_disable(); + + /* Find index of pin is attached in pool. */ + if ((irqindex = nu_find_irqindex(pin)) >= 0) + goto exit_nu_gpio_attach_irq; + + /* Find available index of pin in pool. */ + if ((irqindex = nu_cto(g_u32PinIrqMask)) < IRQ_MAX_NUM) // Count Trailing Ones ==> Find First Zero + goto exit_nu_gpio_attach_irq; + + rt_hw_interrupt_enable(level); + + return -(RT_EBUSY); + +exit_nu_gpio_attach_irq: + + pin_irq_hdr_tab[irqindex].pin = pin; + pin_irq_hdr_tab[irqindex].hdr = hdr; + pin_irq_hdr_tab[irqindex].mode = mode; + pin_irq_hdr_tab[irqindex].args = args; + + g_u32PinIrqMask |= (1 << irqindex); + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +static rt_err_t nu_gpio_detach_irq(struct rt_device *device, rt_int32_t pin) +{ + rt_base_t level; + rt_int32_t irqindex; + rt_int32_t u32PinIrqStatus; + + if (nu_port_check(pin)) + return -(RT_ERROR); + + level = rt_hw_interrupt_disable(); + + u32PinIrqStatus = g_u32PinIrqMask; + + // Find index of pin is attached in pool. + while ((irqindex = nu_ctz(u32PinIrqStatus)) < IRQ_MAX_NUM)// Count Trailing Zeros ==> Find First One + { + if (pin_irq_hdr_tab[irqindex].pin == pin) + { + pin_irq_hdr_tab[irqindex].pin = PIN_IRQ_PIN_NONE; + pin_irq_hdr_tab[irqindex].hdr = RT_NULL; + pin_irq_hdr_tab[irqindex].mode = PIN_IRQ_MODE_RISING; + pin_irq_hdr_tab[irqindex].args = RT_NULL; + g_u32PinIrqMask &= ~(1 << irqindex); + break; + } + u32PinIrqStatus &= ~(1 << irqindex); + } + + rt_hw_interrupt_enable(level); + return RT_EOK; +} + +static void nu_gpio_isr(int vector, void *param) +{ + int i; + rt_uint32_t u32IntStatus_Port; + + u32IntStatus_Port = inpw(REG_GPIO_ISR) | ~((1 << MAX_PORT) - 1); + while ((i = nu_ctz(u32IntStatus_Port)) < MAX_PORT)// Count Trailing Zeros ==> Find First One + { + int port_mask = (1 << i); + rt_uint32_t u32IntStatus_Pins = inpw(REG_GPIOA_ISR + PORT_OFFSET * i); + + /* Invoke pins status and port number */ + pin_irq_hdr(u32IntStatus_Pins, i); + + /* Clear Interrupt flag. */ + outpw(REG_GPIOA_ISR + PORT_OFFSET * i, u32IntStatus_Pins); + + /* Clear the served bit. */ + u32IntStatus_Port &= ~port_mask; + } + + /* Clear interrupt */ + outpw(REG_AIC_SCCRH, IRQ_GPIO - 1); +} + +static rt_err_t nu_gpio_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled) +{ + GPIO_PORT PORT; + GPIO_TRIGGER_TYPE triggerType; + + rt_base_t level; + rt_int32_t irqindex; + rt_err_t ret = RT_EOK; + + if (nu_port_check(pin)) + return -(RT_ERROR); + + level = rt_hw_interrupt_disable(); + + irqindex = nu_find_irqindex(pin); + if (irqindex == -(RT_ERROR)) + { + ret = RT_ERROR; + goto exit_nu_gpio_irq_enable; + } + + PORT = (GPIO_PORT)(GPIOA + (NU_GET_PORT(pin) * PORT_OFFSET)); + + if (enabled == PIN_IRQ_ENABLE) + { + switch (pin_irq_hdr_tab[irqindex].mode) + { + case PIN_IRQ_MODE_RISING: + triggerType = RISING; + break; + + case PIN_IRQ_MODE_FALLING: + triggerType = FALLING; + break; + + case PIN_IRQ_MODE_RISING_FALLING: + triggerType = BOTH_EDGE; + break; + + case PIN_IRQ_MODE_HIGH_LEVEL: + triggerType = HIGH; + break; + + case PIN_IRQ_MODE_LOW_LEVEL: + triggerType = LOW; + break; + + default: + goto exit_nu_gpio_irq_enable; + } + GPIO_EnableTriggerType(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin)), triggerType); + } + else + { + GPIO_DisableTriggerType(PORT, NU_GET_PIN_MASK(NU_GET_PINS(pin))); + } + +exit_nu_gpio_irq_enable: + + rt_hw_interrupt_enable(level); + return -(ret); +} + +int rt_hw_gpio_init(void) +{ + char szTmp[16]; + rt_int32_t irqindex; + + for (irqindex = 0; irqindex < IRQ_MAX_NUM ; irqindex++) + { + pin_irq_hdr_tab[irqindex].pin = PIN_IRQ_PIN_NONE; + pin_irq_hdr_tab[irqindex].hdr = RT_NULL; + pin_irq_hdr_tab[irqindex].mode = PIN_IRQ_MODE_RISING; + pin_irq_hdr_tab[irqindex].args = RT_NULL; + } + + nu_sys_ipclk_enable(GPIOCKEN); + + snprintf(szTmp, sizeof(szTmp), "gpio"); + rt_hw_interrupt_install(IRQ_GPIO, nu_gpio_isr, RT_NULL, szTmp); + rt_hw_interrupt_set_type(IRQ_GPIO, HIGH_LEVEL_SENSITIVE); + rt_hw_interrupt_umask(IRQ_GPIO); + + return rt_device_pin_register("gpio", &nu_gpio_ops, RT_NULL); +} + +INIT_BOARD_EXPORT(rt_hw_gpio_init); + +#endif //#if (defined(BSP_USING_GPIO) && defined(RT_USING_PIN)) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_gpio.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..c8f232e49117967051086e0fcccbea854ec712f9 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_gpio.h @@ -0,0 +1,36 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-2-7 YCHuang12 First version +* +******************************************************************************/ + +#ifndef __DRV_GPIO_H__ +#define __DRV_GPIO_H__ + +typedef enum +{ + NU_PA, + NU_PB, + NU_PC, + NU_PD, + NU_PE, + NU_PF, + NU_PG, + NU_PH, + NU_PI, + NU_PJ, + NU_PORT_CNT, +} nu_gpio_port; + +#define NU_GET_PININDEX(port, pin) ((port)*16+(pin)) +#define NU_GET_PINS(rt_pin_index) ((rt_pin_index) & 0x0000000F) +#define NU_GET_PORT(rt_pin_index) (((rt_pin_index)>>4) & 0x0000000F) +#define NU_GET_PIN_MASK(nu_gpio_pin) (1 << (nu_gpio_pin)) + +#endif //__DRV_GPIO_H__ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2c.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..0b4fbaabf18d073e7d8582afae39f42bbb8457d7 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2c.c @@ -0,0 +1,520 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-04-20 Wayne First version +******************************************************************************/ + + +#include + +#if defined( BSP_USING_I2C) + +#include +#include "NuMicro.h" +//#include +#include + +/* Private define ---------------------------------------------------------------*/ +#define LOG_TAG "drv.i2c" +#define DBG_ENABLE +#define DBG_SECTION_NAME LOG_TAG +#define DBG_LEVEL DBG_ERROR +#define DBG_COLOR +#include + +#define I2C_REG_WRITE(dev, addr, byte) outpw(dev->base + addr, byte) +#define I2C_REG_READ(dev, addr) inpw(dev->base + addr) + +#define I2C_DISABLE(dev) I2C_REG_WRITE(dev, I2C_CSR, 0x00) /* Disable i2c core and interrupt */ +#define I2C_ENABLE(dev) I2C_REG_WRITE(dev, I2C_CSR, 0x3) /* Enable i2c core and interrupt */ +#define I2C_ISBUSFREE(dev) (((I2C_REG_READ(dev, I2C_SWR) & 0x18) == 0x18 && (I2C_REG_READ(dev, I2C_CSR) & 0x0400) == 0) ? 1 : 0) + +enum +{ + I2C_START = -1, +#if defined(BSP_USING_I2C0) + I2C0_IDX, +#endif +#if defined(BSP_USING_I2C1) + I2C1_IDX, +#endif + I2C_CNT +}; + +/* Private typedef --------------------------------------------------------------*/ +typedef struct +{ + int32_t base; /* i2c bus number */ + int32_t state; + int32_t addr; + uint32_t last_error; + int32_t bNackValid; + + uint32_t subaddr; + int32_t subaddr_len; + + uint8_t buffer[I2C_MAX_BUF_LEN]; + uint32_t pos, len; + +} nu_i2c_dev; +typedef nu_i2c_dev *nu_i2c_dev_t; + +typedef struct +{ + struct rt_i2c_bus_device parent; + char *name; + + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + + struct rt_i2c_msg *cur_i2c_msg; + + nu_i2c_dev dev; +} nu_i2c_bus ; +typedef nu_i2c_bus *nu_i2c_bus_t; +/* Private variables ------------------------------------------------------------*/ + +static nu_i2c_bus nu_i2c_arr [ ] = +{ +#if defined(BSP_USING_I2C0) + { + .dev = + { + .base = I2C0_BA, + }, + .name = "i2c0", + .irqn = IRQ_I2C0, + .rstidx = I2C0RST, + .clkidx = I2C0CKEN, + }, +#endif +#if defined(BSP_USING_I2C1) + { + .dev = + { + .base = I2C1_BA, + }, + .name = "i2c1", + .irqn = IRQ_I2C1, + .rstidx = I2C1RST, + .clkidx = I2C1CKEN, + }, +#endif +}; + +/* Private functions ------------------------------------------------------------*/ +/** + * @brief Set i2c interface speed + * @param[in] dev i2c device structure pointer + * @param[in] sp i2c speed + * @return always 0 + */ +static int32_t nu_i2c_set_speed(nu_i2c_dev_t psNuI2cDev, int32_t sp) +{ + uint32_t d; + + if (sp != 100 && sp != 400) + return (I2C_ERR_NOTTY); + + d = (sysGetClock(SYS_PCLK) * 1000) / (sp * 5) - 1; + + I2C_REG_WRITE(psNuI2cDev, I2C_DIVIDER, d & 0xffff); + + return 0; +} + +/** + * @brief Configure i2c command + * @param[in] dev i2c device structure pointer + * @param[in] cmd command + * @return None + */ +static void nu_i2c_command(nu_i2c_dev_t psNuI2cDev, int32_t cmd) +{ + psNuI2cDev->bNackValid = (cmd & I2C_CMD_WRITE) ? 1 : 0; + I2C_REG_WRITE(psNuI2cDev, I2C_CMDR, cmd); +} + +/** + * @brief Configure slave address data + * @param[in] dev i2c device structure pointer + * @param[in] mode could be write or read + * @return None + */ +static void nu_i2c_calculate_address(nu_i2c_dev_t psNuI2cDev, int32_t mode) +{ + int32_t i; + uint32_t subaddr = psNuI2cDev->subaddr; + + psNuI2cDev->buffer[0] = (((psNuI2cDev->addr << 1) & 0xfe) | I2C_WRITE) & 0xff; + + for (i = psNuI2cDev->subaddr_len; i > 0; i--) + { + psNuI2cDev->buffer[i] = subaddr & 0xff; + subaddr >>= 8; + } + + if (mode == I2C_STATE_READ) + { + i = psNuI2cDev->subaddr_len + 1; + psNuI2cDev->buffer[i] = (((psNuI2cDev->addr << 1) & 0xfe)) | I2C_READ; + } +} + +/** + * @brief Reset some variables + * @param[in] dev i2c device structure pointer + * @return None + */ +static void nu_i2c_reset(nu_i2c_dev_t psNuI2cDev) +{ + psNuI2cDev->addr = -1; + psNuI2cDev->last_error = 0; + psNuI2cDev->subaddr = 0; + psNuI2cDev->subaddr_len = 0; +} + +static void nu_i2c_isr(int vector, void *param) +{ + nu_i2c_bus_t psNuI2CBus = (nu_i2c_bus_t)param; + nu_i2c_dev_t psNuI2CDev = (nu_i2c_dev_t)&psNuI2CBus->dev; + struct rt_i2c_msg *pmsg = psNuI2CBus->cur_i2c_msg; + uint32_t msg_flag = pmsg->flags; + + uint32_t csr, val; + + csr = I2C_REG_READ(psNuI2CDev, I2C_CSR); + csr |= 0x04; + + /* Clear interrupt flag */ + I2C_REG_WRITE(psNuI2CDev, I2C_CSR, csr); + + if (psNuI2CDev->state == I2C_STATE_NOP) + return; + + /* NACK only valid in WRITE */ + if ((csr & 0x800) && psNuI2CDev->bNackValid && !(msg_flag & RT_I2C_IGNORE_NACK)) + { + rt_kprintf("I2C W/ NACK\n"); + psNuI2CDev->last_error = I2C_ERR_NACK; + nu_i2c_command(psNuI2CDev, I2C_CMD_STOP); + psNuI2CDev->state = I2C_STATE_NOP; + } + /* Arbitration lost */ + else if (csr & 0x200) + { + rt_kprintf("Arbitration lost\n"); + psNuI2CDev->last_error = I2C_ERR_LOSTARBITRATION; + psNuI2CDev->state = I2C_STATE_NOP; + } + /* Transmit complete */ + else if (!(csr & 0x100)) + { + /* Send address state */ + if (psNuI2CDev->pos < psNuI2CDev->subaddr_len + 1) + { + val = psNuI2CDev->buffer[psNuI2CDev->pos++] & 0xff; + I2C_REG_WRITE(psNuI2CDev, I2C_TxR, val); + nu_i2c_command(psNuI2CDev, I2C_CMD_WRITE); + } + else if (psNuI2CDev->state == I2C_STATE_READ) + { + /* Sub-address send over, begin restart a read command */ + if (psNuI2CDev->pos == psNuI2CDev->subaddr_len + 1) + { + val = psNuI2CDev->buffer[psNuI2CDev->pos++]; + I2C_REG_WRITE(psNuI2CDev, I2C_TxR, val); + nu_i2c_command(psNuI2CDev, I2C_CMD_START | I2C_CMD_WRITE); + } + else + { + psNuI2CDev->buffer[psNuI2CDev->pos++] = I2C_REG_READ(psNuI2CDev, I2C_RxR) & 0xff; + if (psNuI2CDev->pos < psNuI2CDev->len) + { + /* Last character */ + if (psNuI2CDev->pos == psNuI2CDev->len - 1) + nu_i2c_command(psNuI2CDev, I2C_CMD_READ | I2C_CMD_STOP | I2C_CMD_NACK); + else + nu_i2c_command(psNuI2CDev, I2C_CMD_READ); + } + else + { + psNuI2CDev->state = I2C_STATE_NOP; + } + } + } + /* Write data */ + else if (psNuI2CDev->state == I2C_STATE_WRITE) + { + + if (psNuI2CDev->pos < psNuI2CDev->len) + { + val = psNuI2CDev->buffer[psNuI2CDev->pos]; + + I2C_REG_WRITE(psNuI2CDev, I2C_TxR, val); + + /* Last character */ + if (psNuI2CDev->pos == psNuI2CDev->len - 1) + nu_i2c_command(psNuI2CDev, I2C_CMD_WRITE | I2C_CMD_STOP); + else + nu_i2c_command(psNuI2CDev, I2C_CMD_WRITE); + + psNuI2CDev->pos ++; + } + else + { + psNuI2CDev->state = I2C_STATE_NOP; + } + } + } +} + + + +/** + * @brief Read data from I2C slave. + * @param[in] psNuI2cDev is interface structure pointer. + * @param[in] pmsg is pointer of rt i2c message structure. + * @return read status. + * @retval >0 length when success. + * @retval I2C_ERR_BUSY Interface busy. + * @retval I2C_ERR_IO Interface not opened. + * @retval I2C_ERR_NODEV No such device. + * @retval I2C_ERR_NACK Slave returns an erroneous ACK. + * @retval I2C_ERR_LOSTARBITRATION arbitration lost happen. + */ +static int32_t nu_i2c_read(nu_i2c_dev_t psNuI2cDev, struct rt_i2c_msg *pmsg) +{ + uint8_t *buf = pmsg->buf; + uint32_t len = pmsg->len; + + if (len > I2C_MAX_BUF_LEN - 10) + len = I2C_MAX_BUF_LEN - 10; + + psNuI2cDev->state = I2C_STATE_READ; + psNuI2cDev->pos = 1; + + /* Current ISR design will get one garbage byte */ + /* plus 1 unused char */ + psNuI2cDev->len = psNuI2cDev->subaddr_len + 1 + len + 2; + psNuI2cDev->last_error = 0; + + /* Get slave address */ + nu_i2c_calculate_address(psNuI2cDev, I2C_STATE_READ); + + /* Enable I2C-EN */ + I2C_ENABLE(psNuI2cDev); + + /* Send first byte to transfer the message. */ + I2C_REG_WRITE(psNuI2cDev, I2C_TxR, psNuI2cDev->buffer[0] & 0xff); + + if (!I2C_ISBUSFREE(psNuI2cDev)) + return (I2C_ERR_BUSY); + + nu_i2c_command(psNuI2cDev, I2C_CMD_START | I2C_CMD_WRITE); + + while (psNuI2cDev->state != I2C_STATE_NOP); + + /* Disable I2C-EN */ + I2C_DISABLE(psNuI2cDev); + + if (psNuI2cDev->last_error) + return (psNuI2cDev->last_error); + + rt_memcpy(buf, psNuI2cDev->buffer + psNuI2cDev->subaddr_len + 3, len); + + psNuI2cDev->subaddr += len; + + return len; +} + +/** + * @brief Write data from I2C slave. + * @param[in] psNuI2cDev is interface structure pointer. + * @param[in] pmsg is pointer of rt i2c message structure. + * @return write status. + * @retval >0 length when success. + * @retval I2C_ERR_BUSY Interface busy. + * @retval I2C_ERR_IO Interface not opened. + * @retval I2C_ERR_NODEV No such device. + * @retval I2C_ERR_NACK Slave returns an erroneous ACK. + * @retval I2C_ERR_LOSTARBITRATION arbitration lost happen. + */ +static int32_t nu_i2c_write(nu_i2c_dev_t psNuI2cDev, struct rt_i2c_msg *pmsg) +{ + uint8_t *buf = pmsg->buf; + uint32_t len = pmsg->len; + + if (len > I2C_MAX_BUF_LEN - 10) + len = I2C_MAX_BUF_LEN - 10; + + rt_memcpy(psNuI2cDev->buffer + psNuI2cDev->subaddr_len + 1, buf, len); + + psNuI2cDev->state = I2C_STATE_WRITE; + psNuI2cDev->pos = 1; + psNuI2cDev->len = psNuI2cDev->subaddr_len + 1 + len; + psNuI2cDev->last_error = 0; + + /* Get slave address */ + nu_i2c_calculate_address(psNuI2cDev, I2C_STATE_WRITE); + + /* Enable I2C-EN */ + I2C_ENABLE(psNuI2cDev); + + /* Send first byte to transfer the message. */ + I2C_REG_WRITE(psNuI2cDev, I2C_TxR, psNuI2cDev->buffer[0] & 0xff); + + if (!I2C_ISBUSFREE(psNuI2cDev)) + return (I2C_ERR_BUSY); + + nu_i2c_command(psNuI2cDev, I2C_CMD_START | I2C_CMD_WRITE); + + while (psNuI2cDev->state != I2C_STATE_NOP); + + /* Disable I2C-EN */ + I2C_DISABLE(psNuI2cDev); + + if (psNuI2cDev->last_error) + return (psNuI2cDev->last_error); + + psNuI2cDev->subaddr += len; + + return len; +} + +/** + * @brief Support some I2C driver commands for application. + * @param[in] psNuI2cDev is interface structure pointer. + * @param[in] cmd is command. + * @param[in] arg0 is the first argument of command. + * @param[in] arg1 is the second argument of command. + * @return command status. + * @retval 0 Success. + * @retval I2C_ERR_IO Interface not opened. + * @retval I2C_ERR_NODEV No such device. + * @retval I2C_ERR_NOTTY Command not support, or parameter error. + */ +static int32_t nu_i2c_ioctl(nu_i2c_dev_t psNuI2cDev, uint32_t cmd, uint32_t arg0, uint32_t arg1) +{ + switch (cmd) + { + case I2C_IOC_SET_DEV_ADDRESS: + + psNuI2cDev->addr = arg0; + break; + + case I2C_IOC_SET_SPEED: + + return (nu_i2c_set_speed(psNuI2cDev, (int32_t)arg0)); + + case I2C_IOC_SET_SUB_ADDRESS: + + if (arg1 > 4) + { + return (I2C_ERR_NOTTY); + } + + psNuI2cDev->subaddr = arg0; + psNuI2cDev->subaddr_len = arg1; + break; + + default: + return (I2C_ERR_NOTTY); + } + + return (0); +} + +static rt_size_t nu_i2c_mst_xfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num) +{ + nu_i2c_bus_t psNuI2cBus; + nu_i2c_dev_t psNuI2cDev; + rt_size_t i; + rt_err_t ret; + struct rt_i2c_msg *pmsg; + + RT_ASSERT(bus != RT_NULL); + psNuI2cBus = (nu_i2c_bus_t) bus; + psNuI2cDev = &psNuI2cBus->dev; + + for (i = 0; i < num; i++) + { + if (!I2C_ISBUSFREE(psNuI2cDev)) + break; + + pmsg = psNuI2cBus->cur_i2c_msg = &msgs[i]; + + /* Not support 10bit. */ + if ((pmsg->flags & RT_I2C_ADDR_10BIT) + || (pmsg->len == 0)) + break; + + /* Set device address */ + nu_i2c_reset(psNuI2cDev); + nu_i2c_ioctl(psNuI2cDev, I2C_IOC_SET_DEV_ADDRESS, pmsg->addr, 0); + + if (pmsg->flags & RT_I2C_RD) + { + ret = nu_i2c_read(psNuI2cDev, pmsg); + } + else + { + ret = nu_i2c_write(psNuI2cDev, pmsg); + } + + + if (ret != pmsg->len) break; + } + + return i; +} + +static const struct rt_i2c_bus_device_ops nu_i2c_ops = +{ + .master_xfer = nu_i2c_mst_xfer, + .slave_xfer = NULL, + .i2c_bus_control = NULL, +}; + + +/* Public functions -------------------------------------------------------------*/ +int rt_hw_i2c_init(void) +{ + int i; + rt_err_t ret = RT_EOK; + + for (i = (I2C_START + 1); i < I2C_CNT; i++) + { + nu_i2c_dev_t psNuI2cDev = &nu_i2c_arr[i].dev; + + ret = rt_i2c_bus_device_register(&nu_i2c_arr[i].parent, nu_i2c_arr[i].name); + RT_ASSERT(RT_EOK == ret); + + nu_i2c_arr[i].parent.ops = &nu_i2c_ops; + + /* Enable I2C engine clock and reset. */ + nu_sys_ipclk_enable(nu_i2c_arr[i].clkidx); + nu_sys_ip_reset(nu_i2c_arr[i].rstidx); + + nu_i2c_ioctl(psNuI2cDev, I2C_IOC_SET_SPEED, 100, 0); + + /* Register ISR and Respond IRQ. */ + rt_hw_interrupt_install(nu_i2c_arr[i].irqn, nu_i2c_isr, &nu_i2c_arr[i], nu_i2c_arr[i].name); + rt_hw_interrupt_umask(nu_i2c_arr[i].irqn); + } + + return 0; +} + +INIT_DEVICE_EXPORT(rt_hw_i2c_init); + +#endif /* BSP_USING_I2C */ + diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2s.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2s.c new file mode 100644 index 0000000000000000000000000000000000000000..f11ea2e25f85d8682420dc0f4b17e2c54300be1f --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2s.c @@ -0,0 +1,630 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne Lin First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_I2S) + +#include +#include +#include "NuMicro.h" + +/* Private define ---------------------------------------------------------------*/ +#define DBG_ENABLE +#define DBG_LEVEL DBG_LOG +#define DBG_SECTION_NAME "i2s" +#define DBG_COLOR +#include + +#define I2S_RSR_R_DMA_RIA_IRQ_Pos (0) +#define I2S_RSR_R_DMA_RIA_IRQ_Msk (1<audio); + } + } + + if (u32RegAudCtl & I2S_GLBCON_R_DMA_IRQ_Msk) + { + volatile uint32_t u32RegRecordStatus = inpw(REG_ACTL_RSR); + + outpw(REG_ACTL_CON, u32RegAudCtl | I2S_GLBCON_R_DMA_IRQ_Msk); //Clear RX INT + + /* Record DMA Reach Indicative Address Interrupt Request Bit */ + /* 0 = Record DMA address does not reach the indicative address by R_DMA_IRQ_SEL */ + /* 1 = Record DMA address does reach the indicative address by R_DMA_IRQ_SEL */ + /* Note: This bit is readable, and can only be cleared by writing '1' to it. */ + if (u32RegRecordStatus & I2S_RSR_R_DMA_RIA_IRQ_Msk) + { + nu_i2s_dai_t psNuI2sDai = &psNuI2s->i2s_dais[NU_I2S_DAI_CAPTURE]; + + /* + Record DMA Reach Indicative Address Section Number Bit (Read Only) + R_DMA_IRQ_SEL (I2S_GLBCON[15:14]) = 01, R_DMA_RIA_SN[2:0]= 1, 0. + R_DMA_IRQ_SEL (I2S_GLBCON[15:14]) = 10, R_DMA_RIA_SN[2:0]= 1, 2, 3, 0. + R_DMA_IRQ_SEL (I2S_GLBCON[15:14]) = 11, R_DMA_RIA_SN[2:0]= 1, 2, 3, 4, 5, 6, 7, 0. + */ + uint8_t u8FifoBlockIdx = (u32RegRecordStatus & I2S_RSR_R_DMA_RIA_SN_Msk) >> I2S_RSR_R_DMA_RIA_SN_Pos; + + rt_uint8_t *pbuf = (uint8_t *)((uint32_t)&psNuI2sDai->fifo[u8FifoBlockIdx * NU_I2S_DMA_BUF_BLOCK_SIZE] | NONCACHEABLE); + + /* Clear Record status of DMA reach indicate address interrupt. */ + outpw(REG_ACTL_RSR, I2S_RSR_R_DMA_RIA_IRQ_Msk); + + /* Report upper layer. */ + rt_audio_rx_done(&psNuI2s->audio, pbuf, NU_I2S_DMA_BUF_BLOCK_SIZE); + } + } + +} + +static rt_bool_t nu_i2s_capacity_check(struct rt_audio_configure *pconfig) +{ + switch (pconfig->samplebits) + { + case 8: + case 16: + case 24: + break; + default: + goto exit_nu_i2s_capacity_check; + } + + switch (pconfig->channels) + { + case 1: + case 2: + break; + default: + goto exit_nu_i2s_capacity_check; + } + + return RT_TRUE; + +exit_nu_i2s_capacity_check: + + return RT_FALSE; +} + +static rt_err_t nu_i2s_dai_setup(nu_i2s_t psNuI2s, struct rt_audio_configure *pconfig) +{ + rt_err_t result = RT_EOK; + nu_acodec_ops_t pNuACodecOps = RT_NULL; + RT_ASSERT(psNuI2s->AcodecOps != RT_NULL); + pNuACodecOps = psNuI2s->AcodecOps; + + /* Open I2S */ + if (nu_i2s_capacity_check(pconfig) == RT_TRUE) + { + /* Reset audio codec */ + if (pNuACodecOps->nu_acodec_reset) + result = pNuACodecOps->nu_acodec_reset(); + + if (result != RT_EOK) + goto exit_nu_i2s_dai_setup; + + /* Setup audio codec */ + if (pNuACodecOps->nu_acodec_init) + result = pNuACodecOps->nu_acodec_init(); + + if (!pNuACodecOps->nu_acodec_init || result != RT_EOK) + goto exit_nu_i2s_dai_setup; + + /* Setup acodec samplerate/samplebit/channel */ + if (pNuACodecOps->nu_acodec_dsp_control) + result = pNuACodecOps->nu_acodec_dsp_control(pconfig); + + if (!pNuACodecOps->nu_acodec_dsp_control || result != RT_EOK) + goto exit_nu_i2s_dai_setup; + + /* Open I2S */ + if (i2sOpen() != 0) + goto exit_nu_i2s_dai_setup; + + /* Select I2S function */ + i2sIoctl(I2S_SELECT_BLOCK, I2S_BLOCK_I2S, 0); + + /* Select Data width */ + i2sIoctl(I2S_SELECT_BIT, ((pconfig->samplebits / 8) - 1), 0); + + if (pconfig->channels > 1) + { + /* Set to stereo */ + i2sIoctl(I2S_SET_CHANNEL, I2S_PLAY, I2S_CHANNEL_P_I2S_TWO); + i2sIoctl(I2S_SET_CHANNEL, I2S_REC, I2S_CHANNEL_R_I2S_TWO); + } + else + { + /* Set to mono */ + i2sIoctl(I2S_SET_CHANNEL, I2S_PLAY, I2S_CHANNEL_P_I2S_ONE); + i2sIoctl(I2S_SET_CHANNEL, I2S_REC, I2S_CHANNEL_R_I2S_LEFT_PCM_SLOT0); + } + + /* Set DMA interrupt selection to half of DMA buffer */ + switch (NU_I2S_DMA_BUF_BLOCK_NUMBER) + { + case 2: + i2sIoctl(I2S_SET_PLAY_DMA_INT_SEL, I2S_DMA_INT_HALF, 0); + i2sIoctl(I2S_SET_REC_DMA_INT_SEL, I2S_DMA_INT_HALF, 0); + break; + case 4: + i2sIoctl(I2S_SET_PLAY_DMA_INT_SEL, I2S_DMA_INT_QUARTER, 0); + i2sIoctl(I2S_SET_REC_DMA_INT_SEL, I2S_DMA_INT_QUARTER, 0); + break; + case 8: + i2sIoctl(I2S_SET_PLAY_DMA_INT_SEL, I2S_DMA_INT_EIGHTH, 0); + i2sIoctl(I2S_SET_REC_DMA_INT_SEL, I2S_DMA_INT_EIGHTH, 0); + break; + default: + RT_ASSERT(0); + break; + } + + /* Set DMA buffer address */ + i2sIoctl(I2S_SET_DMA_ADDRESS, I2S_PLAY, (uint32_t)&psNuI2s->i2s_dais[NU_I2S_DAI_PLAYBACK].fifo[0]); + i2sIoctl(I2S_SET_DMA_ADDRESS, I2S_REC, (uint32_t)&psNuI2s->i2s_dais[NU_I2S_DAI_CAPTURE].fifo[0]); + + /* Set DMA buffer length */ + i2sIoctl(I2S_SET_DMA_LENGTH, I2S_PLAY, NU_I2S_DMA_FIFO_SIZE); + i2sIoctl(I2S_SET_DMA_LENGTH, I2S_REC, NU_I2S_DMA_FIFO_SIZE); + + /* Select I2S format */ + i2sIoctl(I2S_SET_I2S_FORMAT, I2S_FORMAT_I2S, 0); + + if (psNuI2s->AcodecOps->role == NU_ACODEC_ROLE_MASTER) + { + if (pconfig->samplerate % 11025) + { + // 12.288MHz ==> APLL=98.4MHz / 8 = 12.3MHz + // APLL is 98.4MHz + /* + FB_DV = 0x28 -> N=FB_DV+1 -> N=41 + IN_DV = 0 -> M=IN_DV+1 -> M=1 + OUT_DV = 4 -> P=4+1 -> P=5 + Fpllout = 12MHz * N / (M*P) -> Fpllout = 12MHz * 41 / (5*1) = 98.4 MHz + */ + outpw(REG_CLK_APLLCON, 0xC0008028); + + // Select APLL as I2S source and divider is (7+1) + outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0x001f0000) | (0x2 << 19) | (0x7 << 24)); + + // Set sampleing rate, data width, channel + i2sSetSampleRate(12300000, pconfig->samplerate, pconfig->samplebits, pconfig->channels); + } + else + { + // 11.2896MHz ==> APLL=90MHz / 8 = 11.25MHz + // APLL is 90MHz + /* + FB_DV = 0x2D -> N=FB_DV+1 -> N=45 + IN_DV = 0 -> M=IN_DV+1 -> M=1 + OUT_DV = 5 -> P=5+1 -> P=6 + Fpllout = 12MHz * N / (M*P) -> Fpllout = 12MHz * 45 / (6*1) = 90 MHz + */ + outpw(REG_CLK_APLLCON, 0xC000A02D); + + // Select APLL as I2S source and divider is (7+1) + outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0x001f0000) | (0x2 << 19) | (0x7 << 24)); + + // Set sampleing rate, data width, channel + i2sSetSampleRate(11250000, pconfig->samplerate, pconfig->samplebits, pconfig->channels); + } + // Set as master + i2sIoctl(I2S_SET_MODE, I2S_MODE_MASTER, 0); + } + else + { + // Set as slave, source clock is XIN (12MHz) + i2sIoctl(I2S_SET_MODE, I2S_MODE_SLAVE, 0); + } + + LOG_I("Open I2S."); + + /* Set unmute */ + if (pNuACodecOps->nu_acodec_mixer_control) + pNuACodecOps->nu_acodec_mixer_control(AUDIO_MIXER_MUTE, RT_FALSE); + } + else + result = -RT_EINVAL; + +exit_nu_i2s_dai_setup: + + return result; +} + +static rt_err_t nu_i2s_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps) +{ + rt_err_t result = RT_EOK; + nu_i2s_t psNuI2s; + nu_acodec_ops_t pNuACodecOps = RT_NULL; + + RT_ASSERT(audio != RT_NULL); + RT_ASSERT(caps != RT_NULL); + + psNuI2s = (nu_i2s_t)audio; + + RT_ASSERT(psNuI2s->AcodecOps != RT_NULL); + + pNuACodecOps = psNuI2s->AcodecOps; + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: + switch (caps->sub_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_INPUT | AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; + break; + default: + result = -RT_ERROR; + break; + } // switch (caps->sub_type) + break; + + case AUDIO_TYPE_MIXER: + + if (pNuACodecOps->nu_acodec_mixer_query) + { + switch (caps->sub_type) + { + case AUDIO_MIXER_QUERY: + return pNuACodecOps->nu_acodec_mixer_query(AUDIO_MIXER_QUERY, &caps->udata.mask); + + default: + return pNuACodecOps->nu_acodec_mixer_query(caps->sub_type, (rt_uint32_t *)&caps->udata.value); + } // switch (caps->sub_type) + + } // if (pNuACodecOps->nu_acodec_mixer_query) + + result = -RT_ERROR; + break; + + case AUDIO_TYPE_INPUT: + case AUDIO_TYPE_OUTPUT: + + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + caps->udata.config.channels = psNuI2s->config.channels; + caps->udata.config.samplebits = psNuI2s->config.samplebits; + caps->udata.config.samplerate = psNuI2s->config.samplerate; + break; + case AUDIO_DSP_SAMPLERATE: + caps->udata.config.samplerate = psNuI2s->config.samplerate; + break; + case AUDIO_DSP_CHANNELS: + caps->udata.config.channels = psNuI2s->config.channels; + break; + case AUDIO_DSP_SAMPLEBITS: + caps->udata.config.samplebits = psNuI2s->config.samplebits; + break; + default: + result = -RT_ERROR; + break; + } // switch (caps->sub_type) + break; + + default: + result = -RT_ERROR; + break; + + } // switch (caps->main_type) + + return result; +} + +static rt_err_t nu_i2s_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps) +{ + rt_err_t result = RT_EOK; + nu_i2s_t psNuI2s; + nu_acodec_ops_t pNuACodecOps = RT_NULL; + int stream = -1; + + RT_ASSERT(audio != RT_NULL); + RT_ASSERT(caps != RT_NULL); + + psNuI2s = (nu_i2s_t)audio; + + RT_ASSERT(psNuI2s->AcodecOps != RT_NULL); + pNuACodecOps = psNuI2s->AcodecOps; + + switch (caps->main_type) + { + case AUDIO_TYPE_MIXER: + if (psNuI2s->AcodecOps->nu_acodec_mixer_control) + psNuI2s->AcodecOps->nu_acodec_mixer_control(caps->sub_type, caps->udata.value); + break; + + + case AUDIO_TYPE_INPUT: + stream = AUDIO_STREAM_RECORD; + case AUDIO_TYPE_OUTPUT: + { + rt_bool_t bNeedReset = RT_FALSE; + + if (stream < 0) + stream = AUDIO_STREAM_REPLAY; + + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + if (rt_memcmp(&psNuI2s->config, &caps->udata.config, sizeof(struct rt_audio_configure)) != 0) + { + rt_memcpy(&psNuI2s->config, &caps->udata.config, sizeof(struct rt_audio_configure)); + bNeedReset = RT_TRUE; + } + break; + case AUDIO_DSP_SAMPLEBITS: + if (psNuI2s->config.samplerate != caps->udata.config.samplebits) + { + psNuI2s->config.samplerate = caps->udata.config.samplebits; + bNeedReset = RT_TRUE; + } + break; + case AUDIO_DSP_CHANNELS: + if (psNuI2s->config.channels != caps->udata.config.channels) + { + pNuACodecOps->config.channels = caps->udata.config.channels; + bNeedReset = RT_TRUE; + } + break; + case AUDIO_DSP_SAMPLERATE: + if (psNuI2s->config.samplerate != caps->udata.config.samplerate) + { + psNuI2s->config.samplerate = caps->udata.config.samplerate; + bNeedReset = RT_TRUE; + } + break; + default: + result = -RT_ERROR; + break; + } // switch (caps->sub_type) + + if (bNeedReset) + { + return nu_i2s_start(audio, stream); + } + } + break; + default: + result = -RT_ERROR; + break; + } // switch (caps->main_type) + + return result; +} + +static rt_err_t nu_i2s_init(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + nu_i2s_t psNuI2s; + + RT_ASSERT(audio != RT_NULL); + + psNuI2s = (nu_i2s_t)audio; + + /* Enable IP engine clock */ + nu_sys_ipclk_enable(psNuI2s->clkidx); + + /* Reset IP engine */ + nu_sys_ip_reset(psNuI2s->rstidx); + + /* Enable interrupt */ + rt_hw_interrupt_umask(psNuI2s->irqn); + + return -(result); +} + +static rt_err_t nu_i2s_start(struct rt_audio_device *audio, int stream) +{ + nu_i2s_t psNuI2s; + + RT_ASSERT(audio != RT_NULL); + + psNuI2s = (nu_i2s_t)audio; + + /* Restart all: I2S and codec. */ + nu_i2s_stop(audio, stream); + if (nu_i2s_dai_setup(psNuI2s, &psNuI2s->config) != RT_EOK) + return -RT_ERROR; + + switch (stream) + { + case AUDIO_STREAM_REPLAY: + { + i2sIoctl(I2S_SET_PLAY, I2S_START_PLAY, 0); + + LOG_I("Start replay."); + } + break; + + case AUDIO_STREAM_RECORD: + { + i2sIoctl(I2S_SET_RECORD, I2S_START_REC, 0); + + LOG_I("Start record."); + } + break; + + default: + return -RT_ERROR; + } + + return RT_EOK; +} + +static rt_err_t nu_i2s_stop(struct rt_audio_device *audio, int stream) +{ + nu_i2s_t psNuI2s; + nu_i2s_dai_t psNuI2sDai = RT_NULL; + + RT_ASSERT(audio != RT_NULL); + + psNuI2s = (nu_i2s_t)audio; + + switch (stream) + { + case AUDIO_STREAM_REPLAY: + psNuI2sDai = &psNuI2s->i2s_dais[NU_I2S_DAI_PLAYBACK]; + + i2sIoctl(I2S_SET_PLAY, I2S_STOP_PLAY, 0); + + LOG_I("Stop replay."); + break; + + case AUDIO_STREAM_RECORD: + psNuI2sDai = &psNuI2s->i2s_dais[NU_I2S_DAI_CAPTURE]; + + i2sIoctl(I2S_SET_RECORD, I2S_STOP_REC, 0); + + LOG_I("Stop record."); + break; + + default: + return -RT_EINVAL; + } + + /* Close I2S if record and playback path. */ + if (!((inpw(REG_ACTL_RESET)&I2S_RESET_PLAY_Msk) || (inpw(REG_ACTL_RESET)&I2S_RESET_RECORD_Msk))) + { + i2sClose(); + LOG_I("Close I2S."); + } + + /* Silence */ + rt_memset((void *)psNuI2sDai->fifo, 0, NU_I2S_DMA_FIFO_SIZE); + + return RT_EOK; +} + +static void nu_i2s_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info) +{ + nu_i2s_t psNuI2s; + + RT_ASSERT(audio != RT_NULL); + RT_ASSERT(info != RT_NULL); + + psNuI2s = (nu_i2s_t)audio; + + /* Define it a NONCACHEABLE address. */ + info->buffer = (rt_uint8_t *)((uint32_t)psNuI2s->i2s_dais[NU_I2S_DAI_PLAYBACK].fifo | NONCACHEABLE) ; + info->total_size = NU_I2S_DMA_FIFO_SIZE; + info->block_size = NU_I2S_DMA_BUF_BLOCK_SIZE; + info->block_count = NU_I2S_DMA_BUF_BLOCK_NUMBER; + + return; +} + +static struct rt_audio_ops nu_i2s_audio_ops = +{ + .getcaps = nu_i2s_getcaps, + .configure = nu_i2s_configure, + + .init = nu_i2s_init, + .start = nu_i2s_start, + .stop = nu_i2s_stop, + .transmit = RT_NULL, + .buffer_info = nu_i2s_buffer_info +}; + +int rt_hw_i2s_init(void) +{ + int i = 0; + nu_i2s_dai_t psNuI2sDai; + + for (i = 0; i < NU_I2S_DAI_CNT; i++) + { + psNuI2sDai = &g_nu_i2s_dev.i2s_dais[i]; + + /* Allocate playback and record FIFO buffer. */ + psNuI2sDai->fifo = (uint8_t *)rt_malloc_align(NU_I2S_DMA_FIFO_SIZE, 32); + RT_ASSERT(psNuI2sDai->fifo != RT_NULL); + + rt_memset(psNuI2sDai->fifo, 0, NU_I2S_DMA_FIFO_SIZE); + } + + /* Register ops of audio device */ + g_nu_i2s_dev.audio.ops = &nu_i2s_audio_ops; + + /* Register device, RW: it is with replay and record functions. */ + rt_audio_register(&g_nu_i2s_dev.audio, g_nu_i2s_dev.name, RT_DEVICE_FLAG_RDWR, &g_nu_i2s_dev); + + /* Register I2S ISR */ + rt_hw_interrupt_install(g_nu_i2s_dev.irqn, nu_i2s_isr, &g_nu_i2s_dev, g_nu_i2s_dev.name); + + return RT_EOK; +} +INIT_DEVICE_EXPORT(rt_hw_i2s_init); +#endif //#if defined(BSP_USING_I2S) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2s.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2s.h new file mode 100644 index 0000000000000000000000000000000000000000..2b4c877acbf02ac6c245b4bcfeebe26528434aaf --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_i2s.h @@ -0,0 +1,98 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#ifndef __DRV_I2S_H__ +#define __DRV_I2S_H__ + +#include +#include +#include "NuMicro.h" + +#if !defined(NU_I2S_DMA_FIFO_SIZE) + #define NU_I2S_DMA_FIFO_SIZE (2048) +#endif + +#if !defined(NU_I2S_DMA_BUF_BLOCK_NUMBER) + #define NU_I2S_DMA_BUF_BLOCK_NUMBER (2) +#endif + +#if ( (NU_I2S_DMA_FIFO_SIZE % NU_I2S_DMA_BUF_BLOCK_NUMBER) != 0 ) + #error "Please give an aligned definition" +#endif +#if ( NU_I2S_DMA_FIFO_SIZE < 2048 ) + #warning "DMA FIFO too small, miss voice?" +#endif + +#define NU_I2S_DMA_BUF_BLOCK_SIZE (NU_I2S_DMA_FIFO_SIZE/NU_I2S_DMA_BUF_BLOCK_NUMBER) + +#if ( NU_I2S_DMA_BUF_BLOCK_SIZE > RT_AUDIO_RECORD_PIPE_SIZE ) + #error "Specified I2S DMA buffer size is small than PIPE size in RT driver." + #error "You should enlarge RT_AUDIO_RECORD_PIPE_SIZE. " +#endif + +typedef enum +{ + NU_I2S_DAI_PLAYBACK, + NU_I2S_DAI_CAPTURE, + NU_I2S_DAI_CNT +} E_NU_I2S_DAI; + +typedef enum +{ + NU_ACODEC_ROLE_MASTER, + NU_ACODEC_ROLE_SLAVE, +} E_NU_ACODEC_ROLE; + +typedef struct +{ + char *name; + + E_NU_ACODEC_ROLE role; + + struct rt_audio_configure config; + + rt_err_t (*nu_acodec_init)(void); + + rt_err_t (*nu_acodec_reset)(void); + + rt_err_t (*nu_acodec_dsp_control)(struct rt_audio_configure *config); + + rt_err_t (*nu_acodec_mixer_control)(rt_uint32_t ui32Item, rt_uint32_t ui32Value); + + rt_err_t (*nu_acodec_mixer_query)(rt_uint32_t ui32Item, rt_uint32_t *ui32Value); + +} nu_acodec_ops; + +typedef nu_acodec_ops *nu_acodec_ops_t; + +struct nu_i2s_dai +{ + rt_uint8_t *fifo; +}; +typedef struct nu_i2s_dai *nu_i2s_dai_t; + +struct nu_i2s +{ + struct rt_audio_device audio; + struct rt_audio_configure config; + + char *name; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + + struct nu_i2s_dai i2s_dais[NU_I2S_DAI_CNT]; + nu_acodec_ops_t AcodecOps; +}; +typedef struct nu_i2s *nu_i2s_t; + +#endif // __DRV_I2S_H___ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_jpegcodec.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_jpegcodec.c new file mode 100644 index 0000000000000000000000000000000000000000..16ae07f5d1eaf3d3695eec5cf46c7728a699d472 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_jpegcodec.c @@ -0,0 +1,1412 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-4-16 Wayne First version +* +******************************************************************************/ + +#include "rtthread.h" + +#include "NuMicro.h" +#include "nu_jpeg.h" +#include "drv_sys.h" + +struct nu_jpeg +{ + struct rt_device dev; + char *name; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + + struct rt_mutex lock; +}; +typedef struct nu_jpeg *nu_jpeg_t; + +static BOOL volatile g_bWait = FALSE, g_jpegError = FALSE, g_bScale = FALSE, g_OutputWait = FALSE, g_InputWait = FALSE, g_u32WindowDec = FALSE, g_bEncThumbnailDownScale = FALSE, g_bEncPrimaryDownScale = FALSE; +static UINT32 volatile g_u32Stride, g_u32ScaleWidth, g_u32ScaleHeight, g_u32OpMode, g_u32EncRotate = 0; +static UINT32 volatile g_u32BufferCount, g_u32DecInputWaitAddr; +static UINT16 volatile g_u16BufferSize, g_u16ReserveSize; +static UINT32 volatile g_u32OutputFormat, g_u32windowSizeX, g_u32windowSizeY; + + +static PFN_JPEG_CALLBACK pfnJpegDecodeComplete = NULL; +static PFN_JPEG_CALLBACK pfnJpegDecodeError = NULL; +static PFN_JPEG_CALLBACK pfnJpegEncodeComplete = NULL; +static PFN_JPEG_HEADERDECODE_CALLBACK pfnJpegHeaderDecode = NULL; +static PFN_JPEG_DECWAIT_CALLBACK pfnJpegDecInputWait = NULL; +static PFN_JPEG_DECWAIT_CALLBACK pfnJpegDecOutputWait = NULL; + +static JPEG_INFO_T jpegInfo; + +/* Default Quantization-Table 0 ~ 2 */ +static UINT8 g_au8QTable0[64] = { 0x06, 0x04, 0x04, 0x05, 0x04, 0x04, 0x06, 0x05, + 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x08, 0x0E, + 0x09, 0x08, 0x08, 0x08, 0x08, 0x11, 0x0C, 0x0D, + 0x0A, 0x0E, 0x14, 0x11, 0x15, 0x14, 0x13, 0x11, + 0x13, 0x13, 0x16, 0x18, 0x1F, 0x1A, 0x16, 0x17, + 0x1D, 0x17, 0x13, 0x13, 0x1B, 0x25, 0x1B, 0x1D, + 0x20, 0x21, 0x23, 0x23, 0x23, 0x15, 0x1A, 0x26, + 0x29, 0x26, 0x22, 0x28, 0x1F, 0x22, 0x23, 0x21 + }, + g_au8QTable1[64] = { 0x06, 0x06, 0x06, 0x08, 0x07, 0x08, 0x10, 0x09, + 0x09, 0x10, 0x21, 0x16, 0x13, 0x16, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21 + }; + + +static struct nu_jpeg g_sNuJpeg = +{ + .name = "jpegcodec", + .irqn = JPEG_IRQn, + .rstidx = JPEGRST, + .clkidx = JPEGCKEN +}; + +/* Interrupt Service Routine for H/W JPEG CODEC */ +static void nu_jpeg_isr(int vector, void *param) +{ + UINT32 u32interruptStatus; + + /* Get the interrupt status */ + u32interruptStatus = JPEG_GET_INT_STATUS(); + + /* It's Header Decode Complete Interrupt */ + if (u32interruptStatus & DHE_INTS) + { + UINT32 u32YuvFormat; + UINT16 u16Height, u16Width, UVHeight, UVWidth; + UINT16 u16WidthTmp, u16HeightTmp; + /* Get the JPEG format */ + u32YuvFormat = JPEG_DEC_GET_DECODED_IMAGE_FORMAT(); + + /* Get the decoded image dimension */ + jpegGetDecodedDimension(&u16Height, &u16Width); + + jpegInfo.jpeg_width = u16Width; + jpegInfo.jpeg_height = u16Height; + jpegInfo.yuvformat = u32YuvFormat; + + if (pfnJpegHeaderDecode != NULL) + { + if (!pfnJpegHeaderDecode()) + { + jpegInit(); + g_bWait = FALSE; + return; + } + } + + if (g_bScale) + { + UINT16 u16RatioH, u16RatioW; + + if (jpegCalScalingFactor( + g_u32OpMode, //Up / Down Scaling + u16Height, //Original Height + u16Width, //Original Width + g_u32ScaleHeight, //Scaled Height + g_u32ScaleWidth, //Scaled Width + &u16RatioH, //Horizontal Ratio + &u16RatioW //Vertical Ratio + ) != E_SUCCESS) + { + g_bWait = FALSE; + g_jpegError = TRUE; + } + else + { + jpegSetScalingFactor(g_u32OpMode, u16RatioH, u16RatioW); + u16Width = g_u32ScaleWidth; + u16Height = g_u32ScaleHeight; + } + } + else + { + + if (u32YuvFormat == JPEG_DEC_YUV411) + { + /* 32-pixel alignment for YUV411 raw data */ + if (u16Width % 32) + u16Width = (u16Width & 0xFFFFFFE0) + 32; + } + else if ((u32YuvFormat == JPEG_DEC_YUV444) || (u32YuvFormat == JPEG_DEC_YUV422T)) + { + /* 8-pixel alignment for YUV444 raw data */ + if (u16Width % 8) + u16Width = (u16Width & 0xFFFFFFF8) + 8; + } + else + { + /* 16-pixel alignment for YUV422 or YUV420 raw data */ + if (u16Width % 16) + u16Width = (u16Width & 0xFFFFFFF0) + 16; + } + } + + if (g_u32Stride >= u16Width) + { + jpegInfo.stride = g_u32Stride; + g_u32Stride = g_u32Stride - u16Width; + JPEG_SET_YSTRIDE(g_u32Stride); + u16Width = jpegInfo.stride; + } + else + { + g_u32Stride = 0; + JPEG_SET_YSTRIDE(0); + jpegInfo.stride = 0; + } + + if (g_u32OutputFormat == JPEG_DEC_PRIMARY_PLANAR_YUV || g_u32OutputFormat == JPEG_DEC_THUMBNAIL_PLANAR_YUV) + { + if (g_u32WindowDec) + { + u16WidthTmp = u16Width; + u16HeightTmp = u16Height; + + u16Width = g_u32windowSizeX; + u16Height = g_u32windowSizeY; + } + + if (u32YuvFormat == JPEG_DEC_YUV411) + { + /* For YUV411 raw data */ + UVWidth = u16Width / 4; + } + else if ((u32YuvFormat == JPEG_DEC_YUV444) || (u32YuvFormat == JPEG_DEC_YUV422T)) + { + /* For YUV444 raw data */ + UVWidth = u16Width; + } + /* Set the U-component and V-componente width for YUV422 or YUV420 raw data */ + else if (u16Width % 2) + UVWidth = u16Width / 2 + 1; + else + UVWidth = u16Width / 2; + + + /* Sets the height of U and V for YUV420 image */ + if (u32YuvFormat == JPEG_DEC_YUV420) + { + /* 16-pixel alignment for YUV422 or YUV420 raw data */ + if (u16Height % 16) + u16Height = (u16Height & 0xFFFFFFF0) + 16; + UVHeight = u16Height / 2; + } + else if (u32YuvFormat == JPEG_DEC_YUV422) + { + /* 8-pixel alignment for YUV444 raw data */ + if (u16Height % 8) + u16Height = (u16Height & 0xFFFFFFF8) + 8; + UVHeight = u16Height; + } + else if (u32YuvFormat == JPEG_DEC_YUV444) + { + /* 8-pixel alignment for YUV444 raw data */ + if (u16Height % 8) + u16Height = (u16Height & 0xFFFFFFF8) + 8; + UVHeight = u16Height; + } + else if (u32YuvFormat == JPEG_DEC_YUV411) + { + /* 8-pixel alignment for YUV411 raw data */ + if (u16Height % 8) + u16Height = (u16Height & 0xFFFFFFF8) + 8; + UVHeight = u16Height; + } + else if (u32YuvFormat == JPEG_DEC_YUV422T) + { + /* 16-pixel alignment for YUV422 or YUV420 raw data */ + if (u16Height % 16) + u16Height = (u16Height & 0xFFFFFFF0) + 16; + UVHeight = u16Height / 2; + } + else + { + /* 8-pixel alignment for raw data */ + if (u16Height % 8) + u16Height = (u16Height & 0xFFFFFFF8) + 8; + UVHeight = u16Height; + } + + JPEG_SET_UADDR(JPEG_GET_YADDR() + u16Width * u16Height); + JPEG_SET_VADDR(JPEG_GET_UADDR() + UVWidth * UVHeight); + + if (u32YuvFormat == JPEG_DEC_GRAY) + jpegInfo.image_size[0] = u16Width * u16Height; + else + jpegInfo.image_size[0] = u16Width * u16Height + 2 * UVWidth * UVHeight; + + if (g_u32WindowDec) + { + u16Width = u16WidthTmp; + u16Height = u16HeightTmp; + } + } + else + { + if (g_u32WindowDec) + { + u16WidthTmp = u16Width; + u16HeightTmp = u16Height; + + u16Width = g_u32windowSizeX; + u16Height = g_u32windowSizeY; + } + + if (jpegInfo.stride) + jpegInfo.image_size[0] = jpegInfo.stride * u16Height; + else + jpegInfo.image_size[0] = u16Width * u16Height; + + if (g_u32OutputFormat == JPEG_DEC_PRIMARY_PACKET_RGB888) + jpegInfo.image_size[0] = 4 * jpegInfo.image_size[0]; + else + jpegInfo.image_size[0] = 2 * jpegInfo.image_size[0]; + + if (g_u32WindowDec) + { + u16Width = u16WidthTmp; + u16Height = u16HeightTmp; + } + + } + + /* Set the image dimension */ + jpegSetDimension(u16Height, u16Width); + + + outp32(JITCR, inp32(JITCR) | Dec_Scatter_Gather); + + /* Clear interrupt status */ + JPEG_CLEAR_INT(DHE_INTS); + } + /* It's Decode Output Wait Interrupt */ + else if (u32interruptStatus & JPG_DOW_INTS) + { + if (pfnJpegDecOutputWait != NULL) + { + pfnJpegDecOutputWait(inp32(JYADDR0), inp32(JDOWFBS)); + } + JPEG_CLEAR_INT(JPG_DOW_INTS); + + outp32(JITCR, inp32(JITCR) | Dec_Scatter_Gather); + + } + /* It's Encode Complete Interrupt */ + else if (u32interruptStatus & ENC_INTS) + { + /* Get the Encode Bit stream length */ + jpegInfo.image_size[0] = JPEG_GET_ENC_PRIMARY_BITSTREAM_SIZE(); + jpegInfo.image_size[1] = JPEG_GET_ENC_THUMBNAIL_BITSTREAM_SIZE(); + /* Clear interrupt status */ + JPEG_CLEAR_INT(ENC_INTS); + + g_bWait = FALSE; + + if (pfnJpegEncodeComplete != NULL) + pfnJpegEncodeComplete(); + } + /* It's Decode Complete Interrupt */ + else if (u32interruptStatus & DEC_INTS) + { + UINT16 imageWidth, imageHeight; + + /* Get the image dimension */ + jpegGetDimension(&imageHeight, &imageWidth); + + if (g_u32Stride != 0) + { + imageWidth = imageWidth - g_u32Stride; + } + + jpegInfo.width = imageWidth; + jpegInfo.height = imageHeight; + + /* Clear interrupt status */ + JPEG_CLEAR_INT(DEC_INTS); + JPEG_CLEAR_INT(JPG_DOW_INTS); + + g_bWait = FALSE; + + if (pfnJpegDecodeComplete != NULL) + pfnJpegDecodeComplete(); + } + /* It's Decode Error Interrupt */ + else if (u32interruptStatus & DER_INTS) + { + /* Clear interrupt status */ + JPEG_CLEAR_INT(DER_INTS); + + g_bWait = FALSE; + g_jpegError = TRUE; + + if (pfnJpegDecodeError != NULL) + pfnJpegDecodeError(); + } + else if (u32interruptStatus & IPW_INTS) + { + /* Clear interrupt status */ + JPEG_CLEAR_INT(IPW_INTS); + + JPEG_DEC_RESUME_INPUT_WAIT(); + + if (pfnJpegDecInputWait != NULL) + { + if (!pfnJpegDecInputWait((g_u32DecInputWaitAddr + (g_u32BufferCount % 2) * g_u16BufferSize), g_u16BufferSize)) + { + jpegInit(); + g_bWait = FALSE; + return; + } + g_u32BufferCount++; + } + else + while (1); + + } + +} + +static INT jpegAdjustQTAB(UINT8 u8Mode, UINT8 u8Qadjust, UINT8 u8Qscaling) +{ + UINT32 u32Addr; + if (u8Mode == JPEG_ENC_PRIMARY) + u32Addr = REG_JPRIQC; + else if (u8Mode == JPEG_ENC_THUMBNAIL) + u32Addr = REG_JTHBQC; + else + return E_JPEG_INVALID_PARAM; + + outp32(u32Addr, ((u8Qadjust & 0xF) << 4) | (u8Qscaling & 0xF)); + return E_SUCCESS; +} + + +#if 0 +//Poll the interrupt status and get if the interrupt is generated +static BOOL jpegPollInt(UINT32 u32Intflag) +{ + if (JPEG_GET_INT_STATUS() & u32Intflag) + return 1; + else + return 0; +} + + +static UINT32 jpegPower(UINT32 u32Index, UINT32 u32Exp) +{ + if (u32Exp == 0) + return 1; + else + { + UINT32 u32Idx; + for (u32Idx = 1; u32Idx < u32Exp; u32Idx = u32Idx + 1) + { + u32Index = 2 * u32Index; + } + } + return u32Index; +} + +static VOID jpegGetScalingFactor( + UINT8 u8Mode, //Up / Down Scaling + PUINT16 pu16FactorH, //Vertical Scaling Factor + PUINT16 pu16FactorW //Horizontal Scaling Factor +) +{ + if (u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE) + { + *pu16FactorH = inp32(REG_JPSCALD) & 0x3F; + *pu16FactorW = (inp32(REG_JPSCALD) >> 8) & 0x1F; + } + else + { + *pu16FactorH = (inp32(REG_JUPRAT) >> 16) & 0x3FFF; + *pu16FactorW = inp32(REG_JUPRAT) & 0x3FFF; + } +} +#endif + +static INT jpegSetEncodeMode(UINT8 u8SourceFormat, UINT16 u16JpegFormat) +{ + UINT8 u8Gray = 0; + switch (u16JpegFormat) + { + case JPEG_ENC_PRIMARY_YUV420: + case JPEG_ENC_PRIMARY_YUV422: + case JPEG_ENC_THUMBNAIL_YUV420: + case JPEG_ENC_THUMBNAIL_YUV422: + case (JPEG_ENC_PRIMARY_YUV420 | JPEG_ENC_THUMBNAIL_YUV420): + case (JPEG_ENC_PRIMARY_YUV422 | JPEG_ENC_THUMBNAIL_YUV422): + outp32(REG_JMCR, (inp32(REG_JMCR) & WIN_DEC) | u16JpegFormat); + u8Gray = 0; + break; + case JPEG_ENC_PRIMARY_GRAY: + case JPEG_ENC_THUMBNAIL_GRAY: + case (JPEG_ENC_PRIMARY_GRAY | JPEG_ENC_THUMBNAIL_GRAY): + if (u8SourceFormat == JPEG_ENC_SOURCE_PACKET) + return E_JPEG_INVALID_PARAM; + else + { + if (u16JpegFormat == (JPEG_ENC_PRIMARY_GRAY | JPEG_ENC_THUMBNAIL_GRAY)) + outp32(REG_JMCR, 0xB0); + else + outp32(REG_JMCR, 0xA0); + } + u8Gray = EY_ONLY; + break; + default: + return E_JPEG_INVALID_PARAM; + } + g_u32OpMode = JPEG_ENC_UPSCALE_MODE; + + if (g_bEncPrimaryDownScale) + g_u32OpMode = JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE; + + if (g_bEncThumbnailDownScale) + g_u32OpMode = JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE; + + if (u8SourceFormat == JPEG_ENC_SOURCE_PLANAR) + outp32(REG_JITCR, (inp32(REG_JITCR) & (0x8 | ROTATE)) | PLANAR_ON | u8Gray); + else if (u8SourceFormat == JPEG_ENC_SOURCE_PACKET) + outp32(REG_JITCR, inp32(REG_JITCR) & ~(PLANAR_ON | ROTATE)); + else + return E_JPEG_INVALID_PARAM; + + return E_SUCCESS; +} + +static INT jpegSetDecodeMode(UINT32 u32OutputFormat) +{ + switch (u32OutputFormat) + { + case JPEG_DEC_PRIMARY_PLANAR_YUV: + case JPEG_DEC_PRIMARY_PACKET_YUV422: + case JPEG_DEC_PRIMARY_PACKET_RGB555: + case JPEG_DEC_PRIMARY_PACKET_RGB555R1: + case JPEG_DEC_PRIMARY_PACKET_RGB555R2: + case JPEG_DEC_THUMBNAIL_PLANAR_YUV: + case JPEG_DEC_THUMBNAIL_PACKET_YUV422: + case JPEG_DEC_THUMBNAIL_PACKET_RGB555: + case JPEG_DEC_PRIMARY_PACKET_RGB565: + case JPEG_DEC_PRIMARY_PACKET_RGB565R1: + case JPEG_DEC_PRIMARY_PACKET_RGB565R2: + case JPEG_DEC_PRIMARY_PACKET_RGB888: + outp32(REG_JITCR, u32OutputFormat); + outp32(REG_JMCR, inp32(REG_JMCR) & ~ENC_DEC); + g_u32OpMode = JPEG_DEC_PACKET_DOWNSCALE_MODE; + g_u32OutputFormat = u32OutputFormat; + if (u32OutputFormat == JPEG_DEC_PRIMARY_PLANAR_YUV || u32OutputFormat == JPEG_DEC_THUMBNAIL_PLANAR_YUV) + g_u32OpMode = JPEG_DEC_PLANAR_DOWNSCALE_MODE; + break; + default: + return E_JPEG_INVALID_PARAM; + } + return E_SUCCESS; +} + +static VOID jpegDecodeTrigger(void) +{ + g_bWait = TRUE; + g_jpegError = FALSE; + + rt_memset(&jpegInfo, 0, sizeof(jpegInfo)); + + /* Decode Complete /Decode Header End/Decode Error Interrupt Enable and clear the Decode Complete /Decode Header End/Decode Error Interrupt */ + if (g_InputWait) + { + g_u32BufferCount = 0; + g_u32DecInputWaitAddr = JPEG_GET_BITSTREAM_ADDR(); + if (g_OutputWait) + JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE | IPW_INTE | JPG_DOW_INTE); + else + JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE | IPW_INTE); + } + else if (g_OutputWait) + { + JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE | JPG_DOW_INTE); + } + else + JPEG_INT_ENABLE(DEC_INTE | DER_INTE | DHE_INTE); + + + + JPEG_CLEAR_INT(DEC_INTS | JPEG_DER_INTS | JPEG_DHE_INTS | JPEG_IPW_INTS | JPG_DOW_INTS); + + outp32(REG_JMCR, JPG_EN | inp32(REG_JMCR)); + outp32(REG_JMCR, ~JPG_EN & inp32(REG_JMCR)); +} + +static VOID jpegEncodeTrigger(void) +{ + g_bWait = TRUE; + g_jpegError = FALSE; + + g_u32OpMode = JPEG_ENC_UPSCALE_MODE; + + if (g_bEncPrimaryDownScale) + g_u32OpMode = JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE; + + if (g_bEncThumbnailDownScale) + g_u32OpMode = JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE; + + rt_memset(&jpegInfo, 0, sizeof(jpegInfo)); + + if (g_u32EncRotate != 0) + { + UINT16 u16Height, u16Width; + + if (((inp32(REG_JITCR) & (PLANAR_ON | EY_ONLY)) != (PLANAR_ON)) && ((inp32(REG_JMCR) & EY422) != 0)) + { + g_jpegError = TRUE; + g_bWait = FALSE; + return; + } + jpegGetDimension(&u16Width, &u16Height); + + if (g_u32EncRotate == JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT) + { + JPEG_SET_YADDR((JPEG_GET_YADDR() + (u16Width - 1))); + JPEG_SET_UADDR((JPEG_GET_UADDR() + (u16Width / 2 - 1))); + JPEG_SET_VADDR((JPEG_GET_VADDR() + (u16Width / 2 - 1))); + } + else + { + JPEG_SET_YADDR((JPEG_GET_YADDR() + ((u16Height - 1) * u16Width))); + u16Width = JPEG_GET_USTRIDE(); + JPEG_SET_UADDR((JPEG_GET_UADDR() + ((u16Height - 2) * u16Width / 2))); + JPEG_SET_VADDR((JPEG_GET_VADDR() + ((u16Height - 2) * u16Width / 2))); + + } + } + + if (g_bScale) + { + UINT16 u16Height, u16Width, u16ratioH, u16ratioW; + + if (g_u32EncRotate != 0) + jpegGetDimension(&u16Width, &u16Height); + else + jpegGetDimension(&u16Height, &u16Width); + + if (jpegCalScalingFactor( + g_u32OpMode, //Up / Down Scaling + u16Height, //Original Height + u16Width, //Original Width + g_u32ScaleHeight, //Scaled Height + g_u32ScaleWidth, //Scaled Width + &u16ratioH, //Horizontal Ratio + &u16ratioW //Vertical Ratio + ) != E_SUCCESS) + { + g_jpegError = TRUE; + g_bWait = FALSE; + return; + } + else + { + jpegSetScalingFactor(g_u32OpMode, u16ratioH, u16ratioW); + if (g_bEncThumbnailDownScale) + outp32(REG_JTHBWH, ((g_u32ScaleHeight & 0x1FFF) << 16) | (g_u32ScaleWidth & 0x1FFF)); + else + { + if (g_u32EncRotate != 0) + jpegSetDimension(g_u32ScaleWidth, g_u32ScaleHeight); + else + jpegSetDimension(g_u32ScaleHeight, g_u32ScaleWidth); + } + } + } + + /* Encode Complete Interrupt Enable and clear the Encode Complete Interrupt */ + JPEG_INT_ENABLE(ENC_INTE); + JPEG_CLEAR_INT(ENC_INTS); + + outp32(REG_JMCR, JPG_EN | inp32(REG_JMCR)); + outp32(REG_JMCR, ~JPG_EN & inp32(REG_JMCR)); +} + +static INT jpegCalScalingFactor( + UINT8 u8Mode, //Up / Down Scaling + UINT16 u16Height, //Original Height + UINT16 u16Width, //Original Width + UINT16 u16ScalingHeight, //Scaled Height + UINT16 u16ScalingWidth, //Scaled Width + PUINT16 pu16RatioH, //Horizontal Ratio + PUINT16 pu16RatioW //Vertical Ratio +) +{ + if (u8Mode == JPEG_ENC_UPSCALE_MODE) + { + if (u16ScalingHeight < u16Height || u16ScalingWidth < u16Width) + return E_JPEG_INVALID_PARAM; + + *pu16RatioW = (UINT32)((float)(u16ScalingWidth - 1) / (float)(u16Width - 2) * 1024); + *pu16RatioH = (UINT32)((float)(u16ScalingHeight - 1) / (float)(u16Height - 2) * 1024); + + } + else if (u8Mode == JPEG_DEC_PACKET_DOWNSCALE_MODE) + { + if (u16ScalingHeight > u16Height || u16ScalingWidth > u16Width) + return E_JPEG_INVALID_PARAM; + + *pu16RatioW = (UINT32)(((float)(u16ScalingWidth) / (u16Width - 1) * 8192)); + + if (*pu16RatioW > 8192) + *pu16RatioW = 8192; + + *pu16RatioH = (UINT32)((float)(u16ScalingHeight) / (u16Height - 1) * 8192); + + if (*pu16RatioH > 8192) + *pu16RatioH = 8192; + + } + else if (u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE) + { + UINT16 u16RatioW, u16RatioH; + if (u16ScalingHeight > u16Height || u16ScalingWidth > u16Width) + return E_JPEG_INVALID_PARAM; + if (u16Height % u16ScalingHeight) + return E_JPEG_INVALID_PARAM; + if (u16Width % u16ScalingWidth) + return E_JPEG_INVALID_PARAM; + + u16RatioW = u16Width / u16ScalingWidth; + + u16RatioW = u16RatioW / 2 - 1; + + if ((u16RatioW != 0) && (u16RatioW != 1) && (u16RatioW != 3)) + return E_JPEG_INVALID_PARAM; + + u16RatioH = u16Height / u16ScalingHeight - 1; + + if ((u16RatioH != 0) && (u16RatioH != 1) && (u16RatioH != 3) && (u16RatioH != 7)) + return E_JPEG_INVALID_PARAM; + + *pu16RatioW = u16RatioW; + *pu16RatioH = u16RatioH; + } + else + return E_JPEG_INVALID_PARAM; + + return E_SUCCESS; + +} + +static INT jpegSetScalingFactor( + UINT8 u8Mode, //Up / Down Scaling + UINT16 u16FactorH, //Vertical Scaling Factor + UINT16 u16FactorW //Horizontal Scaling Factor +) +{ + if (u8Mode == JPEG_ENC_UPSCALE_MODE) + { + JPEG_DEC_DISABLE_DOWNSCALING(); + JPEG_ENC_ENABLE_UPSCALING(); + } + else if (u8Mode == JPEG_DEC_PACKET_DOWNSCALE_MODE || u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE) + { + JPEG_DEC_ENABLE_DOWNSCALING(); + JPEG_ENC_DISABLE_UPSCALING(); + } + else if (u8Mode == JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE) + { + outp32(REG_JTSCALD, TSX_ON); + } + + if (u8Mode == JPEG_DEC_PLANAR_DOWNSCALE_MODE || u8Mode == JPEG_ENC_PLANAR_PRIMARY_DOWNSCALE_MODE) + outp32(REG_JPSCALD, (inp32(REG_JPSCALD) & ~(PSCALX_F | PSCALY_F)) | ((u16FactorW & 0x1F) << 8) | (u16FactorH & 0x1F)); + + else if (u8Mode == JPEG_ENC_PLANAR_THUMBNAIL_DOWNSCALE_MODE) + outp32(REG_JTSCALD, (inp32(REG_JTSCALD) & ~(TSCALX_F | TSCALY_F)) | ((u16FactorW & 0x1F) << 8) | (u16FactorH & 0x1F)); + else + { + outp32(REG_JPSCALD, inp32(REG_JPSCALD) & ~(PSCALX_F | PSCALY_F)); + outp32(REG_JUPRAT, ((u16FactorH & 0x3FFF) << 16) | (u16FactorW & 0x3FFF)); + } + return E_SUCCESS; +} + +static VOID jpegGetDecodedDimension( + PUINT16 pu16Height, //Decode/Encode Height + PUINT16 pu16Width //Decode/Encode Width +) +{ + *pu16Width = inp32(REG_JDECWH) & 0x0000FFFF; + *pu16Height = inp32(REG_JDECWH) >> 16; +} + + +static VOID jpegSetDimension( + UINT16 u16Height, //Decode/Encode Height + UINT16 u16Width //Decode/Encode Width +) +{ + outp32(REG_JPRIWH, ((u16Height & 0x1FFF) << 16) | (u16Width & 0x1FFF)); +} + +static VOID jpegGetDimension( + PUINT16 pu16Height, //Decoded Height from bit stream + PUINT16 pu16Width //Decoded Width from bit stream +) +{ + *pu16Height = inp32(REG_JPRIWH) >> 16; + *pu16Width = inp32(REG_JPRIWH) & 0x1FFF; +} + +static INT jpegSetWindowDecode( + UINT16 u16StartMCUX, //Start X MCU + UINT16 u16StartMCUY, //Horizontal Scaling Factor + UINT16 u16EndMCUX, //Vertical Scaling Factor + UINT16 u16EndMCUY, //Horizontal Scaling Factor + UINT32 u32Stride //Decode Output Stride +) +{ + if (u16StartMCUX >= u16EndMCUX || u16StartMCUY >= u16EndMCUY) + return E_JPEG_INVALID_PARAM; + + outp32(REG_JWINDEC0, u16StartMCUY << 16 | u16StartMCUX); + outp32(REG_JWINDEC1, u16EndMCUY << 16 | u16EndMCUX); + outp32(REG_JWINDEC2, u32Stride); + outp32(REG_JMCR, WIN_DEC); + //sysprintf("\tJWINDEC0 0x%X\n", inp32(REG_JWINDEC0)); + //sysprintf("\tJWINDEC1 0x%X\n", inp32(REG_JWINDEC1)); + //sysprintf("\tJWINDEC2 0x%X\n", inp32(REG_JWINDEC2)); + return E_SUCCESS; +} + +/** + * @brief The function is used to set JPEG Q Table. + * + * @param[in] puQTable0: Q Table 0 + * @param[in] puQTable1: Q Table 1 + * @param[in] puQTable2: Q Table 2 + * @param[in] u8num: Q Table number + * + * @return E_JPEG_TIMEOUT: Time-out \n + * E_SUCCESS: success + */ +static INT _jpegSetQTAB(PUINT8 puQTable0, PUINT8 puQTable1, PUINT8 puQTable2, UINT8 u8num) +{ + UINT32 u32value; + UINT32 u32TimeOut; + int i; + + u32TimeOut = 0xFFFFFF; + for (i = 0; i < 64; i = i + 4) + { + while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut) + u32TimeOut--; + + if (!u32TimeOut) + return E_JPEG_TIMEOUT; + + u32value = puQTable0[i] | (puQTable0[i + 1] << 8) | (puQTable0[i + 2] << 16) | (puQTable0[i + 3] << 24); + outp32((REG_JQTAB0 + i), u32value); + } + + u32TimeOut = 0xFFFFFF; + for (i = 0; i < 64; i = i + 4) + { + while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut) + u32TimeOut--; + + if (!u32TimeOut) + return E_JPEG_TIMEOUT; + + u32value = puQTable1[i] | (puQTable1[i + 1] << 8) | (puQTable1[i + 2] << 16) | (puQTable1[i + 3] << 24); + outp32((REG_JQTAB1 + i), u32value); + } + + if (u8num < 3) + return E_SUCCESS; + + outp32(JITCR, inp32(JITCR) | 0x8); + + u32TimeOut = 0xFFFFFF; + + for (i = 0; i < 64; i = i + 4) + { + while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut) + u32TimeOut--; + + if (!u32TimeOut) + return E_JPEG_TIMEOUT; + + u32value = puQTable2[i] | (puQTable2[i + 1] << 8) | (puQTable2[i + 2] << 16) | (puQTable2[i + 3] << 24); + outp32((REG_JQTAB2 + i), u32value); + } + + u32TimeOut = 0xFFFFFF; + while ((inp32(REG_JMCR) & QT_BUSY) & u32TimeOut) + u32TimeOut--; + + if (!u32TimeOut) + return E_JPEG_TIMEOUT; + else + return E_SUCCESS; + +} + +INT jpegSetQTAB(PUINT8 puQTable0, PUINT8 puQTable1, PUINT8 puQTable2, UINT8 u8num) +{ + INT ret = 0; + struct nu_jpeg_ioctl sNuJpegIoctl = {0}; + struct nu_jpeg_qtab sNuJpegQTab = {0}; + + sNuJpegQTab.puQTable0 = puQTable0; + sNuJpegQTab.puQTable1 = puQTable1; + sNuJpegQTab.puQTable2 = puQTable2; + sNuJpegQTab.u8num = u8num; + + sNuJpegIoctl.arg0 = (UINT32)&sNuJpegQTab; + sNuJpegIoctl.arg1 = (UINT32)&ret; + + rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_SET_QTAB, (void *)&sNuJpegIoctl); + + return ret; +} + +/// @endcond HIDDEN_SYMBOLS + + +/** @addtogroup N9H30_JPEG_EXPORTED_FUNCTIONS JPEG Exported Functions + @{ +*/ + +/** + * @brief The function is used to initial device parameters and register. + * + * @return 0 + */ +static VOID _jpegInit(void) +{ + /* Set the default values of the JPEG registers */ + g_bScale = FALSE; + g_u32Stride = 0; + g_u32BufferCount = 0; + g_u16ReserveSize = 0; + g_u32WindowDec = FALSE; + g_u32windowSizeX = 0; + g_u32windowSizeY = 0; + g_InputWait = FALSE; + g_bEncThumbnailDownScale = FALSE; + g_bEncPrimaryDownScale = FALSE; + g_OutputWait = FALSE; + g_u32EncRotate = 0; + pfnJpegHeaderDecode = NULL; + pfnJpegDecInputWait = NULL; + pfnJpegDecOutputWait = NULL; + outp32(REG_JPRIQC, 0x000000F4); + outp32(REG_JTHBQC, 0x000000F4); + outp32(REG_JPRST, 0x00000004); + outp32(REG_JTRST, 0x00000004); + outp32(REG_JITCR, 0x00000000); + outp32(REG_JINTCR, 0x00000000); + outp32(JDOWFBS, 0xFFFFFFFF); + + // Disable the Primary Up-scaling & Scaling-down + outp32(REG_JPSCALU, 0x00000000); + outp32(REG_JPSCALD, 0x00000000); + + // Reset JUPRAT and JSRCH + outp32(REG_JUPRAT, 0x00000000); + outp32(REG_JSRCH, 0x00000FFF); + //------------------------------------------- + + /* Reset JPEG (JMCR [1]) */ + outp32(REG_JMCR, 0x00000002); + outp32(REG_JMCR, 0x00000000); + outp32(REG_JMACR, 0x00400000); //Can't use single buffer +} + +VOID jpegInit(void) +{ + rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_INITIAL_CODEC, (void *)RT_NULL); +} + +/** + * @brief The function is used to check JPEG engine not busy. + * + * @return TRUE: JPEG engine busy \n + * FALSE: JPEG engine not busy + */ +static BOOL _jpegIsReady(void) +{ + if (g_bWait == FALSE) + return TRUE; + else + return FALSE; +} + +BOOL jpegIsReady(void) +{ + UINT32 u32IsReady = 0; + struct nu_jpeg_ioctl sNuJpegIoctl = {0}; + + sNuJpegIoctl.arg0 = (UINT32)&u32IsReady; + + rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_IS_READY, (void *)&sNuJpegIoctl); + + return (BOOL)u32IsReady; +} +/** + * @brief The function is used to get JPEG information. + * + * @param[out] *info: JPEG encode/decode information. + * + * @return 0 + */ +static VOID _jpegGetInfo(JPEG_INFO_T *info) +{ + rt_memcpy(info, &jpegInfo, sizeof(JPEG_INFO_T)); +} + +VOID jpegGetInfo(JPEG_INFO_T *info) +{ + struct nu_jpeg_ioctl sNuJpegIoctl = {0}; + + sNuJpegIoctl.arg0 = (UINT32)info; + + rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_GET_INFO, (void *)&sNuJpegIoctl); +} + +/** + * @brief The function is used to wait JPEG engine, until JPEG engine not busy. + * + * @return E_SUCCESS: JPEG engine encode/decode complete \n + * FALSE: JPEG engine error + */ +static INT _jpegWait(void) +{ + while (1) + { + if (g_bWait == FALSE) + break; + } + + if (g_jpegError) + return E_FAIL; + + return E_SUCCESS; +} + +INT jpegWait(void) +{ + INT ret = 0; + struct nu_jpeg_ioctl sNuJpegIoctl; + + sNuJpegIoctl.arg0 = (UINT32)&ret; + sNuJpegIoctl.arg1 = 0; + + rt_device_control(&g_sNuJpeg.dev, JPEG_IOCTL_WAITDONE, (void *)&sNuJpegIoctl); + + return ret; +} + +/** + * @brief The function is used to config and reset JPEG IP. + * + * @return E_SUCCESS: success + */ +INT jpegOpen(void) +{ + return (rt_device_open(&g_sNuJpeg.dev, RT_DEVICE_FLAG_RDWR) == RT_EOK) ? E_SUCCESS : E_FAIL; +} + +/** + * @brief Support some JPEG driver commands for application. + * + * @param[in] cmd: Command. + * + * @param[in] arg0: Arguments for the command. + * + * @param[in] arg1: Arguments for the command. + * + * @return 0 + * + */ +VOID jpegIoctl(UINT32 cmd, UINT32 arg0, UINT32 arg1) +{ + struct nu_jpeg_ioctl sNuJpegIoctl; + + sNuJpegIoctl.arg0 = arg0; + sNuJpegIoctl.arg1 = arg1; + + rt_device_control(&g_sNuJpeg.dev, cmd, (void *)&sNuJpegIoctl); +} + +/** + * @brief JPEG function close. + * + * @return 0 + * + */ +VOID jpegClose(void) +{ + rt_device_close(&g_sNuJpeg.dev); +} + +static rt_err_t nu_jpeg_init(rt_device_t dev) +{ + UINT32 u32JPGDiv = 0; + UINT32 u32JPGSource; + UINT32 u32HclkHz; + nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev; + + RT_ASSERT(dev != RT_NULL); + + /* Set JPEG engine clock */ + u32HclkHz = sysGetClock(SYS_HCLK234) * 1000000; + u32JPGSource = u32HclkHz / (((inp32(REG_CLK_DIVCTL3) & 0xf0000000) >> 28) + 1); + + if (u32JPGSource > 75000000) + { + if (u32JPGSource % 75000000) + { + u32JPGDiv = (u32JPGSource / 75000000); + } + else + u32JPGDiv = (u32JPGSource / 75000000) - 1; + } + outp32(REG_CLK_DIVCTL3, (inp32(REG_CLK_DIVCTL3) & ~(0xf0000000)) | ((u32JPGDiv & 0xf) << 28)); + + rt_kprintf("JPEG Engine clock frequency is %d MHz\n", u32JPGSource / (u32JPGDiv + 1) / 1000000); + + /* Register ISR and Response JPEG Interrupt. */ + rt_hw_interrupt_install(psNuJpeg->irqn, nu_jpeg_isr, (void *)psNuJpeg, psNuJpeg->name); + rt_hw_interrupt_umask(psNuJpeg->irqn); + + return RT_EOK; +} + +static rt_err_t nu_jpeg_open(rt_device_t dev, rt_uint16_t oflag) +{ + rt_err_t result; + nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev; + + result = rt_mutex_take(&psNuJpeg->lock, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + /* Enable JPEG engine clock */ + nu_sys_ipclk_enable(psNuJpeg->clkidx); + + /* Reset JPEG codec and internal variables. */ + nu_sys_ip_reset(psNuJpeg->rstidx); + jpegInit(); + + result = rt_mutex_release(&psNuJpeg->lock); + RT_ASSERT(result == RT_EOK); + + return RT_EOK; +} + +static rt_err_t nu_jpeg_close(rt_device_t dev) +{ + rt_err_t result; + nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev; + + RT_ASSERT(dev != RT_NULL); + + result = rt_mutex_take(&psNuJpeg->lock, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + /* Reset JPEG (JMCR [1]) */ + outp32(REG_JMCR, 0x00000002); + outp32(REG_JMCR, 0x00000000); + + /* Disable JPEG engine clock */ + nu_sys_ipclk_disable(psNuJpeg->clkidx); + + result = rt_mutex_release(&psNuJpeg->lock); + RT_ASSERT(result == RT_EOK); + + return RT_EOK; +} + +static rt_err_t nu_jpeg_control(rt_device_t dev, int cmd, void *args) +{ + JPEG_WINDOW_DECODE_T *winDecode; + PUINT32 pu32Tmp; + UINT32 arg0 = 0, arg1 = 0; + rt_err_t result; + nu_jpeg_t psNuJpeg = (nu_jpeg_t)dev; + + nu_jpeg_ioctl_t psNuJpegIoctl = (nu_jpeg_ioctl_t)args; + + RT_ASSERT(dev != RT_NULL); + + result = rt_mutex_take(&psNuJpeg->lock, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + if (psNuJpegIoctl != RT_NULL) + { + arg0 = psNuJpegIoctl->arg0; + arg1 = psNuJpegIoctl->arg1; + } + + switch (cmd) + { + case JPEG_IOCTL_SET_YADDR: + JPEG_SET_YADDR(arg0); + break; + case JPEG_IOCTL_SET_UADDR: + JPEG_SET_UADDR(arg0); + break; + case JPEG_IOCTL_SET_VADDR: + JPEG_SET_VADDR(arg0); + break; + case JPEG_IOCTL_SET_YSTRIDE: + JPEG_SET_YSTRIDE(arg0); + break; + case JPEG_IOCTL_SET_USTRIDE: + JPEG_SET_USTRIDE(arg0); + break; + case JPEG_IOCTL_SET_VSTRIDE: + JPEG_SET_VSTRIDE(arg0); + break; + case JPEG_IOCTL_SET_BITSTREAM_ADDR: + JPEG_SET_BITSTREAM_ADDR(arg0); + break; + case JPEG_IOCTL_SET_SOURCE_IMAGE_HEIGHT: + JPEG_SET_SOURCE_IMAGE_HEIGHT(arg0); + break; + case JPEG_IOCTL_ENC_SET_HEADER_CONTROL: + JPEG_ENC_SET_HEADER_CONTROL(arg0); + break; + case JPEG_IOCTL_SET_DEFAULT_QTAB: + jpegSetQTAB(g_au8QTable0, g_au8QTable1, 0, 2); + break; + case JPEG_IOCTL_SET_DECODE_MODE: + jpegSetDecodeMode(arg0); + break; + case JPEG_IOCTL_SET_ENCODE_MODE: + jpegSetEncodeMode(arg0, arg1); + break; + case JPEG_IOCTL_SET_DIMENSION: + jpegSetDimension(arg0, arg1); + break; + case JPEG_IOCTL_ENCODE_TRIGGER: + jpegEncodeTrigger(); + if (g_u16ReserveSize != 0) + { + UINT32 u32Addr = JPEG_GET_BITSTREAM_ADDR(); + outp8(u32Addr + 2, 0xFF); + outp8(u32Addr + 3, 0xE0); + outp8(u32Addr + 4, ((g_u16ReserveSize - 4) & 0xFF00) >> 8); + outp8(u32Addr + 5, (g_u16ReserveSize - 4) & 0xFF); + } + break; + case JPEG_IOCTL_DECODE_TRIGGER: + jpegDecodeTrigger(); + break; + case JPEG_IOCTL_WINDOW_DECODE: + winDecode = (JPEG_WINDOW_DECODE_T *)arg0; + jpegSetWindowDecode(winDecode->u16StartMCUX, winDecode->u16StartMCUY, + winDecode->u16EndMCUX, winDecode->u16EndMCUY, winDecode->u32Stride); + g_u32WindowDec = TRUE; + g_u32windowSizeX = winDecode->u32Stride; + g_u32windowSizeY = 16 * (winDecode->u16EndMCUY - winDecode->u16StartMCUY + 1); + + break; + case JPEG_IOCTL_SET_DECODE_STRIDE: + g_u32Stride = arg0; + break; + case JPEG_IOCTL_SET_DECODE_DOWNSCALE: + g_bScale = TRUE; + g_u32ScaleWidth = arg1; + g_u32ScaleHeight = arg0; + break; + case JPEG_IOCTL_SET_ENCODE_UPSCALE: + g_bScale = TRUE; + g_u32ScaleWidth = arg1; + g_u32ScaleHeight = arg0; + break; + case JPEG_IOCTL_SET_HEADERDECODE_CALBACKFUN: + pfnJpegHeaderDecode = (PFN_JPEG_HEADERDECODE_CALLBACK) arg0; + break; + case JPEG_IOCTL_SET_DECINPUTWAIT_CALBACKFUN: + g_InputWait = TRUE; + pfnJpegDecInputWait = (PFN_JPEG_DECWAIT_CALLBACK) arg0; + JPEG_DEC_SET_INPUT_WAIT(((UINT16) arg1 / 2048)); + g_u16BufferSize = arg1 / 2; + break; + case JPEG_IOCTL_ADJUST_QTAB: + jpegAdjustQTAB(arg0, ((arg1 & 0xFF00) >> 4), (arg1 & 0xFF)); + break; + case JPEG_IOCTL_ENC_RESERVED_FOR_SOFTWARE: + if (arg0 > 0) + { + UINT32 u32Tmp; + + u32Tmp = arg0 + 4; + if (u32Tmp % 2) + u32Tmp++; + if ((u32Tmp % 4) == 0) + u32Tmp += 2; + if (u32Tmp >= 0xFFFF) + u32Tmp = 65534; + + outp32(REG_JPSCALU, inp32(REG_JPSCALU) | A_JUMP); + outp32(JRESERVE, u32Tmp); + g_u16ReserveSize = u32Tmp; + } + break; + case JPEG_IOCTL_SET_ENCODE_PRIMARY_RESTART_INTERVAL: + outp32(REG_JPRST, arg0); + break; + case JPEG_IOCTL_SET_ENCODE_THUMBNAIL_RESTART_INTERVAL: + outp32(REG_JTRST, arg0); + break; + case JPEG_IOCTL_GET_ENCODE_PRIMARY_RESTART_INTERVAL: + pu32Tmp = (PUINT32) arg0; + *pu32Tmp = inp32(REG_JPRST); + break; + case JPEG_IOCTL_GET_ENCODE_THUMBNAIL_RESTART_INTERVAL: + pu32Tmp = (PUINT32) arg0; + *pu32Tmp = inp32(REG_JTRST); + break; + + case JPEG_IOCTL_SET_THUMBNAIL_DIMENSION: + outp32(REG_JTHBWH, ((arg0 & 0x1FFF) << 16) | (arg1 & 0x1FFF)); + break; + case JPEG_IOCTL_SET_ENCODE_SW_OFFSET: + outp32(REG_JOFFSET, arg0); + break; + case JPEG_IOCTL_GET_THUMBNAIL_DIMENSION: + pu32Tmp = (PUINT32) arg0; + *pu32Tmp = inp32(REG_JTHBWH) >> 16; + pu32Tmp = (PUINT32) arg1; + *pu32Tmp = inp32(REG_JTHBWH) & 0x1FFF; + break; + case JPEG_IOCTL_GET_ENCODE_SW_OFFSET: + pu32Tmp = (PUINT32) arg0; + *pu32Tmp = inp32(REG_JOFFSET); + break; + case JPEG_IOCTL_SET_ENCODE_PRIMARY_DOWNSCALE: + g_bScale = TRUE; + g_bEncPrimaryDownScale = TRUE; + g_u32ScaleWidth = arg1; + g_u32ScaleHeight = arg0; + break; + case JPEG_IOCTL_SET_ENCODE_THUMBNAIL_DOWNSCALE: + g_bScale = TRUE; + g_bEncThumbnailDownScale = TRUE; + g_u32ScaleWidth = arg1; + g_u32ScaleHeight = arg0; + break; + case JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_RIGHT: + g_u32EncRotate = JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_RIGHT; + outp32(REG_JITCR, (inp32(REG_JITCR) & ~ROTATE) | ROTATE); + break; + case JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT: + g_u32EncRotate = JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_LEFT; + outp32(REG_JITCR, (inp32(REG_JITCR) & ~ROTATE) | 0x1000); + break; + case JPEG_IOCTL_SET_ENCODE_PRIMARY_ROTATE_NORMAL: + g_u32EncRotate = 0; + outp32(REG_JITCR, (inp32(REG_JITCR) & ~ROTATE)); + break; + case JPEG_IOCTL_SET_DECOUTPUTWAIT_CALBACKFUN: + pfnJpegDecOutputWait = (PFN_JPEG_DECWAIT_CALLBACK) arg0; + break; + case JPEG_IOCTL_SET_DECOUTPUTWAIT: + outp32(JYADDR0, arg0); + outp32(JDOWFBS, arg1); + g_OutputWait = TRUE; + break; + case JPEG_IOCTL_GET_DECOUTPUTWAIT_ADDR: + pu32Tmp = (PUINT32) arg0; + *pu32Tmp = inp32(JYADDR0); + break; + case JPEG_IOCTL_GET_DECOUTPUTWAIT_SIZE: + pu32Tmp = (PUINT32) arg0; + *pu32Tmp = inp32(JDOWFBS); + break; + case JPEG_IOCTL_SET_DECODE_COMPLETE_CALBACKFUN: + pfnJpegDecodeComplete = (PFN_JPEG_CALLBACK) arg0; + break; + case JPEG_IOCTL_SET_ENCODE_COMPLETE_CALBACKFUN: + pfnJpegEncodeComplete = (PFN_JPEG_CALLBACK) arg0; + break; + case JPEG_IOCTL_SET_DECODE_ERROR_CALBACKFUN: + pfnJpegDecodeError = (PFN_JPEG_CALLBACK) arg0; + break; + + /* Extended IOCTL command */ + case JPEG_IOCTL_SET_QTAB: + { + nu_jpeg_qtab_t psJpegQtab = (nu_jpeg_qtab_t)arg0; + INT *pi32ret = (INT *)arg1; + *pi32ret = _jpegSetQTAB(psJpegQtab->puQTable0, psJpegQtab->puQTable1, psJpegQtab->puQTable2, psJpegQtab->u8num); + } + break; + case JPEG_IOCTL_INITIAL_CODEC: + _jpegInit(); + break; + case JPEG_IOCTL_GET_INFO: + _jpegGetInfo((JPEG_INFO_T *)arg0); + break; + case JPEG_IOCTL_IS_READY: + { + UINT32 *pu32ret = (UINT32 *)arg0; + *pu32ret = _jpegIsReady(); + + } + break; + case JPEG_IOCTL_WAITDONE: + { + INT *pi32ret = (INT *)arg0; + *pi32ret = _jpegWait(); + } + break; + + default: + break; + } + + result = rt_mutex_release(&psNuJpeg->lock); + RT_ASSERT(result == RT_EOK); + + return RT_EOK; +} + +/* Hardward JPEG codec init */ +static int rt_hw_jpeg_init(void) +{ + rt_err_t ret = RT_EOK; + + /* Register sdcard device */ + g_sNuJpeg.dev.type = RT_Device_Class_Miscellaneous; + g_sNuJpeg.dev.init = nu_jpeg_init; + g_sNuJpeg.dev.open = nu_jpeg_open; + g_sNuJpeg.dev.close = nu_jpeg_close; + g_sNuJpeg.dev.read = RT_NULL; + g_sNuJpeg.dev.write = RT_NULL; + g_sNuJpeg.dev.control = nu_jpeg_control; + + /* Private */ + g_sNuJpeg.dev.user_data = (void *)&g_sNuJpeg; + + ret = rt_mutex_init(&g_sNuJpeg.lock, "jpeg_lock", RT_IPC_FLAG_PRIO); + RT_ASSERT(ret == RT_EOK); + + /* Only support single opening. */ + ret = rt_device_register(&g_sNuJpeg.dev, g_sNuJpeg.name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); + RT_ASSERT(ret == RT_EOK); + + return (int)ret; +} +INIT_DEVICE_EXPORT(rt_hw_jpeg_init); diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_pwm.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_pwm.c new file mode 100644 index 0000000000000000000000000000000000000000..ce77b21aa8bdbc826cfeaec10195b149edbaff07 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_pwm.c @@ -0,0 +1,293 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-1 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_PWM) + +#define LOG_TAG "drv.pwm" +#define DBG_ENABLE +#define DBG_SECTION_NAME "drv.pwm" +#define DBG_LEVEL DBG_INFO +#define DBG_COLOR +#include + +#include +#include +#include +#include "NuMicro.h" +#include "drv_sys.h" + +enum +{ + PWM_START = -1, +#if defined(BSP_USING_PWM0) + PWM0_IDX, +#endif + PWM_CNT +}; + +#define NU_PWM_BA_DISTANCE 0 +#define NU_PWM_CHANNEL_NUM 4 + +struct nu_pwm +{ + struct rt_device_pwm dev; + char *name; + uint32_t base_addr; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; +}; + +typedef struct nu_pwm *nu_pwm_t; + +static struct nu_pwm nu_pwm_arr [] = +{ +#if defined(BSP_USING_PWM0) + { + .name = "pwm0", + .base_addr = PWM_BA, + .rstidx = PWMRST, + .clkidx = PWMCKEN, + }, +#endif + +}; /* pwm nu_pwm */ + +static rt_err_t nu_pwm_control(struct rt_device_pwm *device, int cmd, void *arg); + +static struct rt_pwm_ops nu_pwm_ops = +{ + .control = nu_pwm_control +}; + +static rt_err_t nu_pwm_enable(struct rt_device_pwm *device, struct rt_pwm_configuration *config, rt_bool_t enable) +{ + nu_pwm_t psNuPWM = (nu_pwm_t)device; + + rt_err_t result = RT_EOK; + rt_uint32_t ch = config->channel; + + if (enable == RT_TRUE) + { + uint32_t u32RegAdrrPCR = psNuPWM->base_addr + 0x8; + uint32_t u32PCRChAlign = (!ch) ? 0x9 : (0x9 << (4 + ch * 4)); + + /* Period and enable channel. */ + outpw(u32RegAdrrPCR, inpw(u32RegAdrrPCR) | u32PCRChAlign); + } + else + { + uint32_t u32RegAdrrPCR = psNuPWM->base_addr + 0x8; + uint32_t u32PCRChAlign = (!ch) ? 0x1 : (0x1 << (4 + ch * 4)); + + outpw(u32RegAdrrPCR, inpw(u32RegAdrrPCR) & ~u32PCRChAlign); + } + + return result; +} + +static rt_err_t nu_pwm_get(struct rt_device_pwm *device, struct rt_pwm_configuration *config) +{ + nu_pwm_t psNuPWM = (nu_pwm_t)device; + uint32_t u32RegAdrrPPR = psNuPWM->base_addr; + uint32_t u32RegAdrrCSR = psNuPWM->base_addr + 0x04; + uint32_t u32RegAdrrCNR = psNuPWM->base_addr + 0xC + (config->channel * 0xC); + uint32_t u32RegAdrrCMR = psNuPWM->base_addr + 0x10 + (config->channel * 0xC); + uint32_t u32PWMSrcClk = sysGetClock(SYS_PCLK) * 1000000; + uint32_t u32CMR, u32CNR; + double douDutyCycle; /* unit:% */ + uint32_t u32PWMOutClk; /* unit:Hz */ + uint32_t u32Prescale, u32Divider; + + u32CNR = inpw(u32RegAdrrCNR) + 1; + u32CMR = inpw(u32RegAdrrCMR) + 1; + u32Prescale = ((inpw(u32RegAdrrPPR) & (0xff << ((config->channel >> 1) * 8))) >> ((config->channel >> 1) * 8)) + 1; + u32Divider = (inpw(u32RegAdrrCSR) & (0x7 << (4 * config->channel))) >> (4 * config->channel); + + /* Re-convert register to real value */ + if (u32Divider == 4) + u32Divider = 1; + else if (u32Divider == 0) + u32Divider = 2; + else if (u32Divider == 1) + u32Divider = 4; + else if (u32Divider == 2) + u32Divider = 8; + else // 3 + u32Divider = 16; + + douDutyCycle = (double)u32CMR / u32CNR; + + u32PWMOutClk = u32PWMSrcClk / (u32Prescale * u32Divider * u32CNR); + + config->period = 1000000000 / u32PWMOutClk; /* In ns. */ + config->pulse = douDutyCycle * config->period; + + LOG_I("%s %d %d %d\n", ((nu_pwm_t)device)->name, config->channel, config->period, config->pulse); + + return RT_EOK; +} + +uint32_t nu_pwm_config(uint32_t u32PwmBaseAddr, uint32_t u32ChannelNum, uint32_t u32Frequency, uint32_t u32PulseInHz) +{ + uint32_t i; + uint8_t u8Divider = 1, u8Prescale = 0xFF; + uint16_t u16CNR = 0xFFFF; + uint16_t u16CMR = 0xFFFF; + uint32_t u32RegAdrrPPR = u32PwmBaseAddr; + uint32_t u32RegAdrrCSR = u32PwmBaseAddr + 0x04; + uint32_t u32RegAdrrCNR = u32PwmBaseAddr + 0xC + (u32ChannelNum * 0xC); + uint32_t u32RegAdrrCMR = u32PwmBaseAddr + 0x10 + (u32ChannelNum * 0xC); + uint32_t u32PWMSrcClk = sysGetClock(SYS_PCLK) * 1000000; + uint32_t u32PWMOutClk = 0; + + if (u32Frequency > u32PWMSrcClk) + return 0; + + /* + PWM_Freq = PCLK2 / (Prescale+1) / (Clock Divider) / (CNR+1) + PCLK / PWM_Freq = (Prescale+1) * (Clock Divider) * (CNR+1) + PCLK / PWM_Freq / (Clock Divider) = (Prescale+1) * (CNR+1) + */ + + /* clk divider could only be 1, 2, 4, 8, 16 */ + for (; u8Divider < 17; u8Divider <<= 1) + { + i = (u32PWMSrcClk / u32Frequency) / u8Divider; + + /* If target value is larger than CNR * prescale, need to use a larger divider */ + if (i > (0x10000 * 0x100)) + continue; + + /* CNR = 0xFFFF + 1, get a prescaler that CNR value is below 0xFFFF */ + u8Prescale = (i + 0xFFFF) / 0x10000; + + /* u8Prescale must at least be 2, otherwise the output stop */ + if (u8Prescale < 2) + u8Prescale = 2; + + i /= u8Prescale; + if (i < 0x10000) + { + if (i == 1) + u16CNR = 1; // Too fast, and PWM cannot generate expected frequency... + else + u16CNR = i; + + break; + } + } + + u32PWMOutClk = u32PWMSrcClk / (u8Prescale * u8Divider * u16CNR); + + /* For fill into registers. */ + u8Prescale -= 1; + u16CNR -= 1; + + /* Convert to real register value */ + if (u8Divider == 1) + u8Divider = 4; + else if (u8Divider == 2) + u8Divider = 0; + else if (u8Divider == 4) + u8Divider = 1; + else if (u8Divider == 8) + u8Divider = 2; + else // 16 + u8Divider = 3; + + /* Every two channels share a prescaler */ + outpw(u32RegAdrrPPR, (inpw(u32RegAdrrPPR) & ~(0xff << ((u32ChannelNum >> 1) * 8))) | (u8Prescale << ((u32ChannelNum >> 1) * 8))); + + /* Update CLKSEL in specified channel in CSR field. */ + outpw(u32RegAdrrCSR, inpw(u32RegAdrrCSR) & ~(0x7 << (4 * u32ChannelNum)) | (u8Divider << (4 * u32ChannelNum))); + + u16CMR = u32Frequency * (u16CNR + 1) / u32PulseInHz; + + outpw(u32RegAdrrCMR, (u16CMR == 0) ? 0 : u16CMR - 1); + outpw(u32RegAdrrCNR, u16CNR); + + return (u32PWMOutClk); +} + +static rt_err_t nu_pwm_set(struct rt_device_pwm *device, struct rt_pwm_configuration *config) +{ + nu_pwm_t psNuPWM = (nu_pwm_t)device; + rt_err_t result = RT_EINVAL; + rt_uint32_t u32FreqInHz; /* unit:Hz */ + rt_uint32_t u32PulseInHz; /* unit:% */ + + if (config->period < 1000 || !config->period || !config->pulse) + goto exit_nu_pwm_set; + + /* Calculate frequency, Unit is in us. */ + u32FreqInHz = (1000000000) / config->period; + u32PulseInHz = (1000000000) / config->pulse; + + nu_pwm_config(psNuPWM->base_addr, config->channel, u32FreqInHz, u32PulseInHz); + + result = RT_EOK; + +exit_nu_pwm_set: + + return -(result); +} + +static rt_err_t nu_pwm_control(struct rt_device_pwm *device, int cmd, void *arg) +{ + struct rt_pwm_configuration *config = (struct rt_pwm_configuration *)arg; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(config != RT_NULL); + + if (config->channel > NU_PWM_CHANNEL_NUM) + return -(RT_EINVAL); + + switch (cmd) + { + case PWM_CMD_ENABLE: + return nu_pwm_enable(device, config, RT_TRUE); + case PWM_CMD_DISABLE: + return nu_pwm_enable(device, config, RT_FALSE); + case PWM_CMD_SET: + return nu_pwm_set(device, config); + case PWM_CMD_GET: + return nu_pwm_get(device, config); + default: + break; + } + + return -(RT_ERROR); +} + +int rt_hw_pwm_init(void) +{ + rt_err_t ret; + int i; + + for (i = (PWM_START + 1); i < PWM_CNT; i++) + { + nu_sys_ipclk_enable(nu_pwm_arr[i].clkidx); + + nu_sys_ip_reset(nu_pwm_arr[i].rstidx); + + ret = rt_device_pwm_register(&nu_pwm_arr[i].dev, nu_pwm_arr[i].name, &nu_pwm_ops, RT_NULL); + RT_ASSERT(ret == RT_EOK); + } + + return 0; +} + +INIT_DEVICE_EXPORT(rt_hw_pwm_init); + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_qspi.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_qspi.c new file mode 100644 index 0000000000000000000000000000000000000000..1cbcbc58a1d11f2f0f4e76585e606d0651bc2726 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_qspi.c @@ -0,0 +1,557 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-2-11 Wayne First version +* +******************************************************************************/ +#include + +#if defined(BSP_USING_QSPI) + +#include +#include "NuMicro.h" +#include +#include +#include + +#define LOG_TAG "drv.qspi" +#define DBG_ENABLE +#define DBG_SECTION_NAME LOG_TAG +#define DBG_LEVEL DBG_INFO +#define DBG_COLOR +#include + +#include +#include +#include + +/* Private define ---------------------------------------------------------------*/ + +/* fsclk = fpclk / ((div+1)*2), but div=1 is suggested. */ +#define DEF_SPI_MAX_SPEED (SPI_INPUT_CLOCK/((1)*2)) + +enum +{ + QSPI_START = -1, +#if defined(BSP_USING_QSPI0) + QSPI0_IDX, +#endif +#if defined(BSP_USING_QSPI1) + QSPI1_IDX, +#endif + QSPI_CNT +}; + +/* Private typedef --------------------------------------------------------------*/ +struct nu_qspi +{ + struct rt_spi_bus dev; + char *name; + uint32_t idx; + + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + uint32_t dummy; + + struct rt_qspi_configuration configuration; +}; +typedef struct nu_qspi *nu_qspi_t; + +/* Private functions ------------------------------------------------------------*/ +static void nu_qspi_transmission_with_poll(struct nu_qspi *spi_bus, + uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word); +static int nu_qspi_register_bus(struct nu_qspi *spi_bus, const char *name); +static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message); +static rt_err_t nu_qspi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration); + +/* Public functions -------------------------------------------------------------*/ + +/* Private variables ------------------------------------------------------------*/ +static struct rt_spi_ops nu_qspi_poll_ops = +{ + .configure = nu_qspi_bus_configure, + .xfer = nu_qspi_bus_xfer, +}; + +static struct nu_qspi nu_qspi_arr [] = +{ +#if defined(BSP_USING_QSPI0) + { + .name = "qspi0", + .idx = 0, + .rstidx = SPI0RST, + .clkidx = SPI0CKEN, + }, +#endif +#if defined(BSP_USING_QSPI1) + { + .name = "qspi1", + .idx = 1, + .rstidx = SPI1RST, + .clkidx = SPI1CKEN, + }, +#endif +}; /* nu_qspi */ + +static rt_err_t nu_qspi_bus_configure(struct rt_spi_device *device, + struct rt_spi_configuration *configuration) +{ + struct nu_qspi *qspi_bus; + uint32_t u32SPIMode; + uint32_t u32SPISpeed; + rt_err_t ret = RT_EOK; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(configuration != RT_NULL); + + qspi_bus = (struct nu_qspi *) device->bus; + + /* Check mode */ + switch (configuration->mode & RT_SPI_MODE_3) + { + case RT_SPI_MODE_0: + u32SPIMode = SPI_MODE_0; + break; + case RT_SPI_MODE_1: + u32SPIMode = SPI_MODE_1; + break; + case RT_SPI_MODE_2: + u32SPIMode = SPI_MODE_2; + break; + case RT_SPI_MODE_3: + u32SPIMode = SPI_MODE_3; + break; + default: + ret = RT_EIO; + goto exit_nu_qspi_bus_configure; + } + + /* Check data width */ + if (!(configuration->data_width == 8 || + configuration->data_width == 16 || + configuration->data_width == 24 || + configuration->data_width == 32)) + { + ret = RT_EINVAL; + goto exit_nu_qspi_bus_configure; + } + + /* Need to initialize new configuration? */ + if (rt_memcmp(configuration, &qspi_bus->configuration, sizeof(*configuration)) != 0) + { + rt_memcpy(&qspi_bus->configuration, configuration, sizeof(*configuration)); + + /* Set mode */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_MODE, (uint32_t)u32SPIMode, 0); + + /* Set data width */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_TX_BITLEN, (uint32_t)configuration->data_width, 0); + + /* Set speed */ + u32SPISpeed = configuration->max_hz; + if (u32SPISpeed > DEF_SPI_MAX_SPEED) + u32SPISpeed = DEF_SPI_MAX_SPEED; + + u32SPISpeed = spiIoctl(qspi_bus->idx, SPI_IOC_SET_SPEED, u32SPISpeed, 0); + LOG_I("Actual=%dHz, Prefer=%dHz", u32SPISpeed, configuration->max_hz); + + /* Disable auto-select */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_AUTOSS, SPI_DISABLE_AUTOSS, 0); + + if (configuration->mode & RT_SPI_CS_HIGH) + { + /* Set CS pin to LOW */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_SS_ACTIVE_LEVEL, SPI_SS_ACTIVE_HIGH, 0); + } + else + { + /* Set CS pin to HIGH */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_SS_ACTIVE_LEVEL, SPI_SS_ACTIVE_LOW, 0); + } + + if (configuration->mode & RT_SPI_MSB) + { + /* Set sequence to MSB first */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_LSB_MSB, SPI_MSB, 0); + } + else + { + /* Set sequence to LSB first */ + spiIoctl(qspi_bus->idx, SPI_IOC_SET_LSB_MSB, SPI_LSB, 0); + } + } + +exit_nu_qspi_bus_configure: + + return -(ret); +} + +static int nu_qspi_read(uint32_t idx, uint32_t buf_id, uint8_t *recv_addr, uint8_t bytes_per_word) +{ + uint32_t val; + + // Read data from SPI RX FIFO + switch (bytes_per_word) + { + case 4: + val = spiRead(idx, buf_id); + nu_set32_le(recv_addr, val); + break; + case 3: + val = spiRead(idx, buf_id); + nu_set24_le(recv_addr, val); + break; + case 2: + val = spiRead(idx, buf_id); + nu_set16_le(recv_addr, val); + break; + case 1: + *recv_addr = spiRead(idx, buf_id); + break; + default: + LOG_E("Data length is not supported.\n"); + return 0; + } + return bytes_per_word; +} + +static int nu_qspi_write(uint32_t idx, uint32_t buf_id, const uint8_t *send_addr, uint8_t bytes_per_word) +{ + // Input data to SPI TX + switch (bytes_per_word) + { + case 4: + spiWrite(idx, buf_id, nu_get32_le(send_addr)); + break; + case 3: + spiWrite(idx, buf_id, nu_get24_le(send_addr)); + break; + case 2: + spiWrite(idx, buf_id, nu_get16_le(send_addr)); + break; + case 1: + spiWrite(idx, buf_id, *((uint8_t *)send_addr)); + break; + default: + LOG_E("Data length is not supported.\n"); + return 0; + } + return bytes_per_word; +} + +/** + * @brief SPI bus polling + * @param dev : The pointer of the specified SPI module. + * @param send_addr : Source address + * @param recv_addr : Destination address + * @param length : Data length + */ +static void nu_qspi_transmission_with_poll(struct nu_qspi *spi_bus, + uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word) +{ + uint32_t idx = spi_bus->idx; + int trans_num = length / bytes_per_word; + + while (trans_num > 0) + { + int i; + + uint32_t u32TxNum = (trans_num > 4) ? 4 : trans_num; + + for (i = 0; i < u32TxNum; i++) + { + /* Write TX data into TX-buffer */ + if ((send_addr != RT_NULL)) + { + send_addr += nu_qspi_write(idx, i, (const uint8_t *)send_addr, bytes_per_word); + } + else /* read-only */ + { + spi_bus->dummy = 0; + nu_qspi_write(idx, i, (const uint8_t *)&spi_bus->dummy, bytes_per_word); + } + } + + /* Set TX transacation number */ + spiIoctl(idx, SPI_IOC_SET_TX_NUM, u32TxNum - 1, 0); + + /* Trigger SPI communication. */ + spiIoctl(idx, SPI_IOC_TRIGGER, 0, 0); + + /* Wait it done. */ + while (spiGetBusyStatus(idx)) {}; + + /* Read data from RX-buffer */ + if ((recv_addr != RT_NULL)) + { + for (i = 0; i < u32TxNum; i++) + { + recv_addr += nu_qspi_read(idx, i, recv_addr, bytes_per_word); + } + } + + trans_num -= u32TxNum; + } +} + +void nu_qspi_transfer(struct nu_qspi *spi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word) +{ + RT_ASSERT(spi_bus != RT_NULL); + nu_qspi_transmission_with_poll(spi_bus, tx, rx, length, bytes_per_word); +} + +static int nu_qspi_mode_config(struct nu_qspi *spi_bus, rt_uint8_t *tx, rt_uint8_t *rx, int qspi_lines) +{ + uint32_t idx = spi_bus->idx; + if (qspi_lines > 1) + { + if (tx) + { + switch (qspi_lines) + { + case 2: + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_MODE, SPI_DUAL_MODE, 0); + break; + case 4: + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_MODE, SPI_QUAD_MODE, 0); + break; + default: + LOG_E("Data line is not supported.\n"); + return -1; + } + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_DIR, SPI_DUAL_QUAD_OUTPUT, 0); + } + else if (rx) + { + switch (qspi_lines) + { + case 2: + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_MODE, SPI_DUAL_MODE, 0); + break; + case 4: + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_MODE, SPI_QUAD_MODE, 0); + break; + default: + LOG_E("Data line is not supported.\n"); + return -1; + } + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_DIR, SPI_DUAL_QUAD_INPUT, 0); + } + } + else + { + spiIoctl(idx, SPI_IOC_SET_DUAL_QUAD_MODE, SPI_DISABLE_DUAL_QUAD, 0); + } + return qspi_lines; +} + +static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message) +{ + struct nu_qspi *spi_bus; + struct rt_qspi_configuration *qspi_configuration; + struct rt_qspi_message *qspi_message; + rt_uint8_t u8last = 1; + rt_uint8_t bytes_per_word; + uint32_t idx; + rt_uint32_t u32len = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(message != RT_NULL); + + spi_bus = (struct nu_qspi *) device->bus; + idx = spi_bus->idx; + qspi_configuration = &spi_bus->configuration; + + bytes_per_word = qspi_configuration->parent.data_width / 8; + + if (message->cs_take && !(qspi_configuration->parent.mode & RT_SPI_NO_CS)) + { + /* /CS: active */ + /* We just use CS0 only. if you need CS1, please use pin controlling before sending message. */ + spiIoctl(idx, SPI_IOC_ENABLE_SS, SPI_SS_SS0, 0); + } + + qspi_message = (struct rt_qspi_message *)message; + + /* Command + Address + Dummy + Data */ + /* Command stage */ + if (qspi_message->instruction.content != 0) + { + u8last = nu_qspi_mode_config(spi_bus, (rt_uint8_t *) &qspi_message->instruction.content, RT_NULL, qspi_message->instruction.qspi_lines); + nu_qspi_transfer((struct nu_qspi *)spi_bus, + (rt_uint8_t *) &qspi_message->instruction.content, + RT_NULL, + 1, + 1); + } + + /* Address stage */ + if (qspi_message->address.size > 0) + { + rt_uint32_t u32ReversedAddr = 0; + rt_uint32_t u32AddrNumOfByte = qspi_message->address.size / 8; + switch (u32AddrNumOfByte) + { + case 1: + u32ReversedAddr = (qspi_message->address.content & 0xff); + break; + case 2: + nu_set16_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content); + break; + case 3: + nu_set24_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content); + break; + case 4: + nu_set32_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content); + break; + default: + RT_ASSERT(0); + break; + } + u8last = nu_qspi_mode_config(spi_bus, (rt_uint8_t *)&u32ReversedAddr, RT_NULL, qspi_message->address.qspi_lines); + nu_qspi_transfer((struct nu_qspi *)spi_bus, + (rt_uint8_t *) &u32ReversedAddr, + RT_NULL, + u32AddrNumOfByte, + 1); + } + + /* alternate_bytes stage */ + if ((qspi_message->alternate_bytes.size > 0) && (qspi_message->alternate_bytes.size <= 4)) + { + rt_uint32_t u32AlternateByte = 0; + rt_uint32_t u32NumOfByte = qspi_message->alternate_bytes.size / 8; + switch (u32NumOfByte) + { + case 1: + u32AlternateByte = (qspi_message->alternate_bytes.content & 0xff); + break; + case 2: + nu_set16_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content); + break; + case 3: + nu_set24_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content); + break; + case 4: + nu_set32_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content); + break; + default: + RT_ASSERT(0); + break; + } + u8last = nu_qspi_mode_config(spi_bus, (rt_uint8_t *)&u32AlternateByte, RT_NULL, qspi_message->alternate_bytes.qspi_lines); + nu_qspi_transfer((struct nu_qspi *)spi_bus, + (rt_uint8_t *) &u32AlternateByte, + RT_NULL, + u32NumOfByte, + 1); + } + + /* Dummy_cycles stage */ + if (qspi_message->dummy_cycles > 0) + { + spi_bus->dummy = 0x00; + + u8last = nu_qspi_mode_config(spi_bus, (rt_uint8_t *) &spi_bus->dummy, RT_NULL, u8last); + nu_qspi_transfer((struct nu_qspi *)spi_bus, + (rt_uint8_t *) &spi_bus->dummy, + RT_NULL, + qspi_message->dummy_cycles / (8 / u8last), + 1); + } + + if (message->length > 0) + { + /* Data stage */ + nu_qspi_mode_config(spi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines); + nu_qspi_transfer((struct nu_qspi *)spi_bus, + (rt_uint8_t *) message->send_buf, + (rt_uint8_t *) message->recv_buf, + message->length, + bytes_per_word); + u32len = message->length; + } + else + { + u32len = 1; + } + + if (message->cs_release && !(qspi_configuration->parent.mode & RT_SPI_NO_CS)) + { + /* /CS: deactive */ + /* We just use CS0 only. if you need CS1, please use pin controlling before sending message. */ + spiIoctl(idx, SPI_IOC_DISABLE_SS, SPI_SS_SS0, 0); + } + + return u32len; +} + +static int nu_qspi_register_bus(struct nu_qspi *spi_bus, const char *name) +{ + return rt_qspi_bus_register(&spi_bus->dev, name, &nu_qspi_poll_ops); +} + +/** + * Hardware SPI Initial + */ +static int rt_hw_qspi_init(void) +{ + int i; + + for (i = (QSPI_START + 1); i < QSPI_CNT; i++) + { + nu_sys_ipclk_enable(nu_qspi_arr[i].clkidx); + + nu_sys_ip_reset(nu_qspi_arr[i].rstidx); + + spiOpen(nu_qspi_arr[i].idx); + + nu_qspi_register_bus(&nu_qspi_arr[i], nu_qspi_arr[i].name); + } + + return 0; +} + +INIT_DEVICE_EXPORT(rt_hw_qspi_init); + +rt_err_t nu_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)()) +{ + struct rt_qspi_device *qspi_device = RT_NULL; + rt_err_t result = RT_EOK; + + RT_ASSERT(bus_name != RT_NULL); + RT_ASSERT(device_name != RT_NULL); + RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4); + + qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device)); + if (qspi_device == RT_NULL) + { + LOG_E("no memory, qspi bus attach device failed!\n"); + result = -RT_ENOMEM; + goto __exit; + } + + qspi_device->enter_qspi_mode = enter_qspi_mode; + qspi_device->exit_qspi_mode = exit_qspi_mode; + qspi_device->config.qspi_dl_width = data_line_width; + + result = rt_spi_bus_attach_device(&qspi_device->parent, device_name, bus_name, RT_NULL); + +__exit: + if (result != RT_EOK) + { + if (qspi_device) + { + rt_free(qspi_device); + } + } + + return result; +} + +#endif //#if defined(BSP_USING_SPI) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_qspi.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_qspi.h new file mode 100644 index 0000000000000000000000000000000000000000..c6b13d7db0ba89843db762c072dbdfe4b8fd8dd0 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_qspi.h @@ -0,0 +1,20 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-2-7 Wayne First version +* +******************************************************************************/ + +#ifndef __DRV_QSPI_H__ +#define __DRV_QSPI_H__ + +#include + +rt_err_t nu_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)()); + +#endif // __DRV_QSPI_H___ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_rtc.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_rtc.c new file mode 100644 index 0000000000000000000000000000000000000000..917cb64b501eb13a1e1bbec06f1abf1aea298df1 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_rtc.c @@ -0,0 +1,386 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-04-12 Wayne First version +* +******************************************************************************/ +#include + +#if defined (BSP_USING_RTC) + +#include +#include +#include "NuMicro.h" +#include + +/* Private define ---------------------------------------------------------------*/ + +/* convert the real year and month value to the format of struct tm. */ +#define CONV_TO_TM_YEAR(year) ((year) - 1900) +#define CONV_TO_TM_MON(mon) ((mon) - 1) + +/* convert the tm_year and tm_mon from struct tm to the real value. */ +#define CONV_FROM_TM_YEAR(tm_year) ((tm_year) + 1900) +#define CONV_FROM_TM_MON(tm_mon) ((tm_mon) + 1) + +/* rtc date upper bound reaches the year of 2099. */ +#define RTC_TM_UPPER_BOUND \ +{ .tm_year = CONV_TO_TM_YEAR(2099), \ + .tm_mon = CONV_TO_TM_MON(12), \ + .tm_mday = 31, \ + .tm_hour = 23, \ + .tm_min = 59, \ + .tm_sec = 59, \ +} + +/* rtc date lower bound reaches the year of 2000. */ +#define RTC_TM_LOWER_BOUND \ +{ .tm_year = CONV_TO_TM_YEAR(2000), \ + .tm_mon = CONV_TO_TM_MON(1), \ + .tm_mday = 1, \ + .tm_hour = 0, \ + .tm_min = 0, \ + .tm_sec = 0, \ +} + +/* Private typedef --------------------------------------------------------------*/ + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_rtc_control(rt_device_t dev, int cmd, void *args); + +#if defined (NU_RTC_SUPPORT_IO_RW) + static rt_size_t nu_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); + static rt_size_t nu_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); +#endif + +static rt_err_t nu_rtc_is_date_valid(const time_t *const t); +static void nu_rtc_init(void); + +#if defined(RT_USING_ALARM) + static void nu_rtc_alarm_reset(void); + static void nu_rtc_isr(int vector, void *param); +#endif + +/* Public functions -------------------------------------------------------------*/ +#if defined (NU_RTC_SUPPORT_MSH_CMD) + extern rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day); + extern rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second); +#endif + +/* Private variables ------------------------------------------------------------*/ +static struct rt_device device_rtc; + + +static void nu_rtc_init(void) +{ + S_RTC_TIME_DATA_T sInitTime = {0}; + + nu_sys_ipclk_enable(RTCCKEN); + + /* Time Setting */ + sInitTime.u32Year = 2015; + sInitTime.u32cMonth = 5; + sInitTime.u32cDay = 25; + sInitTime.u32cHour = 13; + sInitTime.u32cMinute = 30; + sInitTime.u32cSecond = 0; + sInitTime.u32cDayOfWeek = RTC_TUESDAY; + sInitTime.u8cClockDisplay = RTC_CLOCK_24; + + /* hw rtc initialise */ + if (RTC_Init() != E_RTC_SUCCESS) + rt_kprintf("[%s] failure!!\n", __func__); + + /* Initialization the RTC timer */ + if (RTC_Open(&sInitTime) != E_RTC_SUCCESS) + rt_kprintf("Open Fail!!\n"); + + /* Do RTC Calibration */ + RTC_Ioctl(0, RTC_IOC_SET_FREQUENCY, 0, 0); + + RTC_DisableInt(RTC_TICK_INT); + RTC_DisableInt(RTC_ALARM_INT); + +#if defined(RT_USING_ALARM) + + nu_rtc_alarm_reset(); + + rt_hw_interrupt_install(IRQ_RTC, nu_rtc_isr, &device_rtc, "rtc"); + rt_hw_interrupt_umask(IRQ_RTC); + +#endif +} + + +#if defined(RT_USING_ALARM) +/* Reset alarm settings to avoid the unwanted values remain in rtc registers. */ +static void nu_rtc_alarm_reset(void) +{ + S_RTC_TIME_DATA_T alarm = {0}; + + /* Reset alarm time and calendar. */ + alarm.u32Year = RTC_YEAR2000; + alarm.u32cMonth = 1; + alarm.u32cDay = 1; + alarm.u8cClockDisplay = RTC_CLOCK_24; + + RTC_Write(RTC_ALARM_TIME, &alarm); + + /* Clear alarm flag for safe */ + RTC_CLEAR_ALARM_INT_FLAG(); +} +#endif + + +/* rtc device driver initialise. */ +int rt_hw_rtc_init(void) +{ + rt_err_t ret; + + nu_rtc_init(); + + /* register rtc device IO operations */ + device_rtc.type = RT_Device_Class_RTC; + device_rtc.init = NULL; + device_rtc.open = NULL; + device_rtc.close = NULL; + device_rtc.control = nu_rtc_control; + +#if defined (NU_RTC_SUPPORT_IO_RW) + device_rtc.read = nu_rtc_read; + device_rtc.write = nu_rtc_write; +#else + device_rtc.read = NULL; + device_rtc.write = NULL; +#endif + + device_rtc.user_data = RT_NULL; + device_rtc.rx_indicate = RT_NULL; + device_rtc.tx_complete = RT_NULL; + + ret = rt_device_register(&device_rtc, "rtc", RT_DEVICE_FLAG_RDWR); + + return (int)ret; +} +INIT_BOARD_EXPORT(rt_hw_rtc_init); + + +#if defined (NU_RTC_SUPPORT_IO_RW) +/* Register rt-thread device.read() entry. */ +static rt_size_t nu_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + (void) pos; + nu_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer); + + return size; +} +#endif + + +#if defined (NU_RTC_SUPPORT_IO_RW) +/* Register rt-thread device.write() entry. */ +static rt_size_t nu_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + (void) pos; + nu_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer); + + return size; +} +#endif + + +static rt_err_t nu_rtc_is_date_valid(const time_t *const t) +{ + static struct tm tm_upper = RTC_TM_UPPER_BOUND; + static struct tm tm_lower = RTC_TM_LOWER_BOUND; + static time_t t_upper, t_lower; + static rt_bool_t initialised = RT_FALSE; + + if (!initialised) + { + t_upper = timegm((struct tm *)&tm_upper); + t_lower = timegm((struct tm *)&tm_lower); + initialised = RT_TRUE; + } + + /* check the date is supported by rtc. */ + if ((*t > t_upper) || (*t < t_lower)) + return -(RT_EINVAL); + + return RT_EOK; +} + + +/* Register rt-thread device.control() entry. */ +static rt_err_t nu_rtc_control(rt_device_t dev, int cmd, void *args) +{ + struct tm tm_out, *tm_in; + time_t *time; + S_RTC_TIME_DATA_T hw_time = {0}; + +#if defined(RT_USING_ALARM) + + struct rt_rtc_wkalarm *wkalarm; + S_RTC_TIME_DATA_T hw_alarm = {0}; +#endif + + if ((dev == NULL) || (args == NULL)) + return -(RT_EINVAL); + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + + time = (time_t *)args; + + if (RTC_Read(RTC_CURRENT_TIME, &hw_time) != E_RTC_SUCCESS) + return -(RT_ERROR); + + tm_out.tm_year = CONV_TO_TM_YEAR(hw_time.u32Year); + tm_out.tm_mon = CONV_TO_TM_MON(hw_time.u32cMonth); + tm_out.tm_mday = hw_time.u32cDay; + tm_out.tm_hour = hw_time.u32cHour; + tm_out.tm_min = hw_time.u32cMinute; + tm_out.tm_sec = hw_time.u32cSecond; + tm_out.tm_wday = hw_time.u32cDayOfWeek; + *time = timegm(&tm_out); + + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + + time = (time_t *) args; + tm_in = gmtime(time); + + if (nu_rtc_is_date_valid(time) != RT_EOK) + return -(RT_ERROR); + + hw_time.u32Year = CONV_FROM_TM_YEAR(tm_in->tm_year); + hw_time.u32cMonth = CONV_FROM_TM_MON(tm_in->tm_mon); + hw_time.u32cDay = tm_in->tm_mday; + hw_time.u32cHour = tm_in->tm_hour; + hw_time.u32cMinute = tm_in->tm_min; + hw_time.u32cSecond = tm_in->tm_sec; + hw_time.u32cDayOfWeek = tm_in->tm_wday; + hw_time.u8cClockDisplay = RTC_CLOCK_24; + hw_time.u8cAmPm = 0; + + if (RTC_Write(RTC_CURRENT_TIME, &hw_time) != E_RTC_SUCCESS) + return -(RT_ERROR); + + break; + +#if defined(RT_USING_ALARM) + case RT_DEVICE_CTRL_RTC_GET_ALARM: + + wkalarm = (struct rt_rtc_wkalarm *) args; + if (RTC_Read(RTC_ALARM_TIME, &hw_alarm) != E_RTC_SUCCESS) + return -(RT_ERROR); + + wkalarm->tm_hour = hw_alarm.u32cHour; + wkalarm->tm_min = hw_alarm.u32cMinute; + wkalarm->tm_sec = hw_alarm.u32cSecond; + break; + + case RT_DEVICE_CTRL_RTC_SET_ALARM: + + wkalarm = (struct rt_rtc_wkalarm *) args; + + /* Readback current ALARM time from RTC register for avoiding wrong parameter when next RTC_Write. */ + if (RTC_Read(RTC_CURRENT_TIME, &hw_alarm) != E_RTC_SUCCESS) + return -(RT_ERROR); + + hw_alarm.u32AlarmMaskHour = 0; + hw_alarm.u32AlarmMaskMinute = 0; + hw_alarm.u32AlarmMaskSecond = 0; + + hw_alarm.u32cHour = wkalarm->tm_hour; + hw_alarm.u32cMinute = wkalarm->tm_min; + hw_alarm.u32cSecond = wkalarm->tm_sec; + + if (RTC_Write(RTC_ALARM_TIME, &hw_alarm) != E_RTC_SUCCESS) + return -(RT_ERROR); + + break; + + default: + return -(RT_EINVAL); +#endif + } + + return RT_EOK; +} + + +#if defined (NU_RTC_SUPPORT_MSH_CMD) + +/* Support "rtc_det_date" command line in msh mode */ +static rt_err_t msh_rtc_set_date(int argc, char **argv) +{ + rt_uint32_t index, len, arg[3]; + + rt_memset(arg, 0, sizeof(arg)); + len = (argc >= 4) ? 4 : argc; + + /* The date information stored in argv is represented by the following order : + argv[0,1,2,3] = [cmd, year, month, day] */ + for (index = 0; index < (len - 1); index ++) + { + arg[index] = atol(argv[index + 1]); + } + + return set_date(arg[0], arg[1], arg[2]); +} +MSH_CMD_EXPORT_ALIAS(msh_rtc_set_date, rtc_set_date, e.g: rtc_set_date 2020 1 20); +#endif + + +#if defined (NU_RTC_SUPPORT_MSH_CMD) + +/* Support "rtc_det_time" command line in msh mode */ +static rt_err_t msh_rtc_set_time(int argc, char **argv) +{ + rt_uint32_t index, len, arg[3]; + + rt_memset(arg, 0, sizeof(arg)); + len = (argc >= 4) ? 4 : argc; + + /* The time information stored in argv is represented by the following order : + argv[0,1,2,3] = [cmd, hour, minute, second] */ + for (index = 0; index < (len - 1); index ++) + { + arg[index] = atol(argv[index + 1]); + } + + return set_time(arg[0], arg[1], arg[2]); +} +MSH_CMD_EXPORT_ALIAS(msh_rtc_set_time, rtc_set_time, e.g: rtc_set_time 18 30 00); +#endif + +#if defined(RT_USING_ALARM) +/* rtc interrupt entry */ +static void nu_rtc_isr(int vector, void *param) +{ + if (RTC_GET_TICK_INT_FLAG()) + { + RTC_CLEAR_TICK_INT_FLAG(); + } + + if (RTC_GET_ALARM_INT_FLAG()) + { + RTC_CLEAR_ALARM_INT_FLAG(); + + /* Send an alarm event to notify rt-thread alarm service. */ + rt_alarm_update(&device_rtc, (rt_uint32_t)NULL); + } + +} +#endif + +#endif /* BSP_USING_RTC */ + diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_scuart.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_scuart.c new file mode 100644 index 0000000000000000000000000000000000000000..ddf9f5f0459dcbd46b89adea589cd03d7d8e25d7 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_scuart.c @@ -0,0 +1,333 @@ +/**************************************************************************//** + * + * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2020-12-1 Wayne First version + * + ******************************************************************************/ + +#include + +#if defined(BSP_USING_SCUART) + +#include "NuMicro.h" +#include +#include +#include + +/* Private definition + * ---------------------------------------------------------------*/ +#define LOG_TAG "drv.scuart" +#define DBG_ENABLE +#define DBG_SECTION_NAME "drv.scuart" +#define DBG_LEVEL DBG_ERROR +#define DBG_COLOR +#include + +enum +{ + SCUART_START = -1, +#if defined(BSP_USING_SCUART0) + SCUART0_IDX, +#endif +#if defined(BSP_USING_SCUART1) + SCUART1_IDX, +#endif + SCUART_CNT +}; + +/* Private typedef + * --------------------------------------------------------------*/ +struct nu_scuart +{ + rt_serial_t dev; + char *name; + uint32_t idx; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; +}; +typedef struct nu_scuart *nu_scuart_t; + +/* Private functions + * ------------------------------------------------------------*/ +static rt_err_t nu_scuart_configure(struct rt_serial_device *serial, + struct serial_configure *cfg); +static rt_err_t nu_scuart_control(struct rt_serial_device *serial, int cmd, + void *arg); +static int nu_scuart_send(struct rt_serial_device *serial, char c); +static int nu_scuart_receive(struct rt_serial_device *serial); +static void nu_scuart_isr(int vector, void *param); + +static const struct rt_uart_ops nu_scuart_ops = +{ + .configure = nu_scuart_configure, + .control = nu_scuart_control, + .putc = nu_scuart_send, + .getc = nu_scuart_receive, + .dma_transmit = RT_NULL /* not support DMA mode */ +}; + +static const struct serial_configure nu_scuart_default_config = + RT_SERIAL_CONFIG_DEFAULT; + +static struct nu_scuart nu_scuart_arr[] = +{ +#if defined(BSP_USING_SCUART0) + { + .name = "scuart0", + .idx = 0, + .irqn = IRQ_SC0, + .rstidx = SMC0RST, + .clkidx = SMC0CKEN, + }, +#endif + +#if defined(BSP_USING_SCUART1) + { + .name = "scuart1", + .idx = 1, + .irqn = IRQ_SC1, + .rstidx = SMC1RST, + .clkidx = SMC1CKEN, + }, +#endif +}; /* scuart nu_scuart */ + +/** + * All SCUART interrupt service routine + */ +static void nu_scuart_isr(int vector, void *param) +{ + nu_scuart_t psNuSCUart = (nu_scuart_t)param; + + /* Handle RX event */ + if (SCUART_GET_INT_FLAG(psNuSCUart->idx, SC_INTSTS_RBTOIF_Msk) || + SCUART_GET_INT_FLAG(psNuSCUart->idx, SC_INTSTS_RDAIF_Msk)) + { + rt_hw_serial_isr(&psNuSCUart->dev, RT_SERIAL_EVENT_RX_IND); + + // RDA is the only interrupt enabled in this driver, this status bit + // automatically cleared after Rx FIFO empty. So no need to clear interrupt + // status here. + SCUART_CLR_INT_FLAG(psNuSCUart->idx, SC_INTSTS_RBTOIF_Msk); + } +} + +/** + * Configure scuart port + */ +static rt_err_t nu_scuart_configure(struct rt_serial_device *serial, + struct serial_configure *cfg) +{ + rt_err_t ret = RT_EOK; + uint32_t scuart_word_len = 0; + uint32_t scuart_stop_bit = 0; + uint32_t scuart_parity = 0; + nu_scuart_t psNuSCUart = (nu_scuart_t)serial; + RT_ASSERT(psNuSCUart != RT_NULL); + + /* Check baud rate */ RT_ASSERT(cfg->baud_rate != 0); + + RT_ASSERT(cfg->baud_rate != 0); + + /* Check word len */ + switch (cfg->data_bits) + { + case DATA_BITS_5: + scuart_word_len = SCUART_CHAR_LEN_5; + break; + + case DATA_BITS_6: + scuart_word_len = SCUART_CHAR_LEN_6; + break; + + case DATA_BITS_7: + scuart_word_len = SCUART_CHAR_LEN_7; + break; + + case DATA_BITS_8: + scuart_word_len = SCUART_CHAR_LEN_8; + break; + + default: + LOG_E("Unsupported data length"); + ret = RT_EINVAL; + goto exit_nu_scuart_configure; + } + + /* Check stop bit */ + switch (cfg->stop_bits) + { + case STOP_BITS_1: + scuart_stop_bit = SCUART_STOP_BIT_1; + break; + + case STOP_BITS_2: + scuart_stop_bit = SCUART_STOP_BIT_2; + break; + + default: + LOG_E("Unsupported stop bit"); + ret = RT_EINVAL; + goto exit_nu_scuart_configure; + } + + /* Check parity */ + switch (cfg->parity) + { + case PARITY_NONE: + scuart_parity = SCUART_PARITY_NONE; + break; + + case PARITY_ODD: + scuart_parity = SCUART_PARITY_ODD; + break; + + case PARITY_EVEN: + scuart_parity = SCUART_PARITY_EVEN; + break; + + default: + LOG_E("Unsupported parity"); + ret = RT_EINVAL; + goto exit_nu_scuart_configure; + } + + nu_sys_ip_reset(psNuSCUart->rstidx); + + /* Open SCUART and set SCUART baud rate */ + SCUART_Open(psNuSCUart->idx, cfg->baud_rate); + + /* Set line configuration. */ + SCUART_SetLineConfig(psNuSCUart->idx, 0, scuart_word_len, scuart_parity, + scuart_stop_bit); + + /* Enable interrupt. */ + rt_hw_interrupt_umask(psNuSCUart->irqn); + +exit_nu_scuart_configure: + + if (ret != RT_EOK) + SCUART_Close(psNuSCUart->idx); + + return -(ret); +} + +/** + * SCUART interrupt control + */ +static rt_err_t nu_scuart_control(struct rt_serial_device *serial, int cmd, + void *arg) +{ + rt_err_t result = RT_EOK; + rt_uint32_t flag; + rt_ubase_t ctrl_arg = (rt_ubase_t)arg; + nu_scuart_t psNuSCUart = (nu_scuart_t)serial; + RT_ASSERT(psNuSCUart != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + + if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) /* Disable INT-RX */ + { + flag = SC_INTEN_RDAIEN_Msk | SC_INTEN_RXTOIEN_Msk; + SCUART_DISABLE_INT(psNuSCUart->idx, flag); + } + break; + + case RT_DEVICE_CTRL_SET_INT: + + if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) /* Enable INT-RX */ + { + flag = SC_INTEN_RDAIEN_Msk | SC_INTEN_RXTOIEN_Msk; + SCUART_ENABLE_INT(psNuSCUart->idx, flag); + } + break; + + case RT_DEVICE_CTRL_CLOSE: + + /* Disable interrupt. */ + rt_hw_interrupt_mask(psNuSCUart->irqn); + + /* Close SCUART port */ + SCUART_Close(psNuSCUart->idx); + + break; + + default: + + result = -RT_EINVAL; + break; + } + return result; +} + +/** + * SCUART put char + */ +static int nu_scuart_send(struct rt_serial_device *serial, char c) +{ + nu_scuart_t psNuSCUart = (nu_scuart_t)serial; + RT_ASSERT(psNuSCUart != RT_NULL); + + /* Waiting if TX-FIFO is full. */ + while (SCUART_IS_TX_FULL(psNuSCUart->idx)) ; + + /* Put char into TX-FIFO */ + SCUART_WRITE(psNuSCUart->idx, c); + + return 1; +} + +/** + * SCUART get char + */ +static int nu_scuart_receive(struct rt_serial_device *serial) +{ + nu_scuart_t psNuSCUart = (nu_scuart_t)serial; + RT_ASSERT(psNuSCUart != RT_NULL); + + /* Return failure if RX-FIFO is empty. */ + if (SCUART_GET_RX_EMPTY(psNuSCUart->idx)) + { + return -1; + } + + /* Get char from RX-FIFO */ + return SCUART_READ(psNuSCUart->idx); +} + +/** + * Hardware SCUART Initialization + */ +static int rt_hw_scuart_init(void) +{ + int i; + rt_uint32_t flag; + rt_err_t ret = RT_EOK; + + for (i = (SCUART_START + 1); i < SCUART_CNT; i++) + { + flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX; + + nu_scuart_arr[i].dev.ops = &nu_scuart_ops; + nu_scuart_arr[i].dev.config = nu_scuart_default_config; + + rt_hw_interrupt_install(nu_scuart_arr[i].irqn, nu_scuart_isr, &nu_scuart_arr[i], nu_scuart_arr[i].name); + + nu_sys_ipclk_enable(nu_scuart_arr[i].clkidx); + + ret = rt_hw_serial_register(&nu_scuart_arr[i].dev, nu_scuart_arr[i].name, flag, NULL); + RT_ASSERT(ret == RT_EOK); + } + + return (int)ret; +} +INIT_DEVICE_EXPORT(rt_hw_scuart_init); +#endif //#if defined(BSP_USING_SCUART) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sdh.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sdh.c new file mode 100644 index 0000000000000000000000000000000000000000..1f44e5d6c189bc6bea6d6c8fa1ed6e08331c9843 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sdh.c @@ -0,0 +1,642 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_SDH) + +#include +#include +#include "NuMicro.h" +#include + +#if defined(RT_USING_DFS) + #include + #include +#endif + +/* Private define ---------------------------------------------------------------*/ + +#if defined(NU_SDH_MOUNT_ON_ROOT) + + #if !defined(NU_SDH_MOUNTPOINT_SDH0) + #define NU_SDH_MOUNTPOINT_SDH0 "/" + #endif + + #if !defined(NU_SDH_MOUNTPOINT_SDH1) + #define NU_SDH_MOUNTPOINT_SDH1 NU_SDH_MOUNTPOINT_SDH0"/sd1" + #endif + +#else + + #if !defined(NU_SDH_MOUNTPOINT_ROOT) + #define NU_SDH_MOUNTPOINT_ROOT "/mnt" + #endif + +#endif + +#if !defined(NU_SDH_MOUNTPOINT_SDH0) + #define NU_SDH_MOUNTPOINT_SDH0 NU_SDH_MOUNTPOINT_ROOT"/sd0" +#endif + +#if !defined(NU_SDH_MOUNTPOINT_SDH1) + #define NU_SDH_MOUNTPOINT_SDH1 NU_SDH_MOUNTPOINT_ROOT"/sd1" +#endif + +enum +{ + SDH_START = -1, +#if defined(BSP_USING_SDH0) + SDH0_IDX, +#endif +#if defined(BSP_USING_SDH1) + SDH1_IDX, +#endif + SDH_CNT +}; + +#define SDH_BLOCK_SIZE 512ul + +#if defined(NU_SDH_HOTPLUG) + #define NU_SDH_TID_STACK_SIZE 1024 +#endif + +#if defined(NU_SDH_HOTPLUG) +enum +{ + NU_SDH_CARD_DETECTED_SD0 = (1 << 0), + NU_SDH_CARD_DETECTED_SD1 = (1 << 1), + NU_SDH_CARD_EVENT_ALL = (NU_SDH_CARD_DETECTED_SD0 | NU_SDH_CARD_DETECTED_SD1) +}; +#endif + +/* Private typedef --------------------------------------------------------------*/ +struct nu_sdh +{ + struct rt_device dev; + char *name; +#if defined(NU_SDH_HOTPLUG) + char *mounted_point; +#endif + SDH_T *base; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + + uint32_t is_card_inserted; + SDH_INFO_T *info; + struct rt_semaphore lock; + uint8_t *pbuf; +}; +typedef struct nu_sdh *nu_sdh_t; + +#if defined(NU_SDH_HOTPLUG) + static struct rt_thread sdh_tid; + static rt_uint8_t sdh_stack[NU_SDH_TID_STACK_SIZE]; +#endif + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_sdh_init(rt_device_t dev); +static rt_err_t nu_sdh_open(rt_device_t dev, rt_uint16_t oflag); +static rt_err_t nu_sdh_close(rt_device_t dev); +static rt_size_t nu_sdh_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t blk_nb); +static rt_err_t nu_sdh_control(rt_device_t dev, int cmd, void *args); +static int rt_hw_sdh_init(void); + +#if defined(NU_SDH_HOTPLUG) + static rt_bool_t nu_sdh_hotplug_is_mounted(const char *mounting_path); + static void sdh_hotplugger(void *param); + static rt_err_t nu_sdh_hotplug_mount(nu_sdh_t sdh); + static rt_err_t nu_sdh_hotplug_unmount(nu_sdh_t sdh); +#endif + +/* Public functions -------------------------------------------------------------*/ + + +/* Private variables ------------------------------------------------------------*/ +static struct nu_sdh nu_sdh_arr [] = +{ +#if defined(BSP_USING_SDH0) + { + .name = "sdh0", +#if defined(NU_SDH_HOTPLUG) + .mounted_point = NU_SDH_MOUNTPOINT_SDH0, +#endif + .irqn = IRQ_FMI, + .base = SDH0, + .rstidx = FMIRST, + .clkidx = EMMCCKEN, + .info = &SD0, + }, +#endif +#if defined(BSP_USING_SDH1) + { + .name = "sdh1", +#if defined(NU_SDH_HOTPLUG) + .mounted_point = NU_SDH_MOUNTPOINT_SDH1, +#endif + .irqn = IRQ_SDH, + .base = SDH1, + .rstidx = SDIORST, + .clkidx = SDHCKEN, + .info = &SD1, + }, +#endif +}; /* struct nu_sdh nu_sdh_arr [] */ +static struct rt_event sdh_event; + +static void SDH_IRQHandler(int vector, void *param) +{ + nu_sdh_t sdh = (nu_sdh_t)param; + SDH_T *sdh_base = sdh->base; + unsigned int volatile isr; + SDH_INFO_T *pSD = sdh->info; + + // FMI data abort interrupt + if (sdh_base->GINTSTS & SDH_GINTSTS_DTAIF_Msk) + { + /* ResetAllEngine() */ + sdh_base->GCTL |= SDH_GCTL_GCTLRST_Msk; + } + + //----- SD interrupt status + isr = sdh_base->INTSTS; + if (isr & SDH_INTSTS_BLKDIF_Msk) + { + // block down + pSD->DataReadyFlag = TRUE; + SDH_CLR_INT_FLAG(sdh_base, SDH_INTSTS_BLKDIF_Msk); + } + + if (isr & SDH_INTSTS_CDIF_Msk) // card detect + { +#if defined(NU_SDH_HOTPLUG) + if (sdh->base == SDH0) + rt_event_send(&sdh_event, NU_SDH_CARD_DETECTED_SD0); + else if (sdh->base == SDH1) + rt_event_send(&sdh_event, NU_SDH_CARD_DETECTED_SD1); +#endif + /* Clear CDIF interrupt flag */ + SDH_CLR_INT_FLAG(sdh_base, SDH_INTSTS_CDIF_Msk); + } + + // CRC error interrupt + if (isr & SDH_INTSTS_CRCIF_Msk) + { + if (!(isr & SDH_INTSTS_CRC16_Msk)) + { + /* CRC_16 error */ + // TODO: handle CRC 16 error + } + else if (!(isr & SDH_INTSTS_CRC7_Msk)) + { + if (!pSD->R3Flag) + { + /* CRC_7 error */ + // TODO: handle CRC 7 error + } + } + /* Clear CRCIF interrupt flag */ + SDH_CLR_INT_FLAG(sdh_base, SDH_INTSTS_CRCIF_Msk); + } + + /* Data-in timeout */ + if (isr & SDH_INTSTS_DITOIF_Msk) + { + sdh_base->INTSTS |= SDH_INTSTS_DITOIF_Msk; + } + + /* Response-in timeout interrupt */ + if (isr & SDH_INTSTS_RTOIF_Msk) + { + sdh_base->INTSTS |= SDH_INTSTS_RTOIF_Msk; + } +} + +/* RT-Thread Device Driver Interface */ +static rt_err_t nu_sdh_init(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_err_t nu_sdh_open(rt_device_t dev, rt_uint16_t oflag) +{ + nu_sdh_t sdh = (nu_sdh_t)dev; + + RT_ASSERT(dev != RT_NULL); + + return (SDH_Probe(sdh->base) == 0) ? RT_EOK : -(RT_ERROR); +} + +static rt_err_t nu_sdh_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_size_t nu_sdh_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t blk_nb) +{ + rt_err_t result = RT_ERROR; + rt_uint32_t ret = 0; + nu_sdh_t sdh = (nu_sdh_t)dev; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + + result = rt_sem_take(&sdh->lock, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + /* Check alignment. */ + if (((uint32_t)buffer & 0x03) != 0) + { + /* Non-aligned. */ + uint32_t i; + uint8_t *copy_buffer = (uint8_t *)buffer; + + sdh->pbuf = rt_malloc(SDH_BLOCK_SIZE); + if (sdh->pbuf == RT_NULL) + goto exit_nu_sdh_read; + + for (i = 0; i < blk_nb; i++) + { + /* Read to temp buffer from specified sector. */ + ret = SDH_Read(sdh->base, (uint8_t *)((uint32_t)&sdh->pbuf[0] | NONCACHEABLE), pos, 1); + if (ret != Successful) + goto exit_nu_sdh_read; + + /* Move to user's buffer */ + memcpy((void *)copy_buffer, (void *)&sdh->pbuf[0], SDH_BLOCK_SIZE); + + pos ++; + copy_buffer += SDH_BLOCK_SIZE; + } + } + else + { +#if defined(BSP_USING_MMU) + mmu_clean_invalidated_dcache((rt_uint32_t)buffer, SDH_BLOCK_SIZE * blk_nb); +#endif + + /* Read to user's buffer from specified sector. */ + ret = SDH_Read(sdh->base, (uint8_t *)((uint32_t)buffer | NONCACHEABLE), pos, blk_nb); + } + +exit_nu_sdh_read: + + if (sdh->pbuf) + { + rt_free(sdh->pbuf); + sdh->pbuf = RT_NULL; + } + + result = rt_sem_release(&sdh->lock); + RT_ASSERT(result == RT_EOK); + + if (ret == Successful) + return blk_nb; + + rt_kprintf("Read failed: %d, buffer 0x%08x\n", ret, buffer); + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_size_t nu_sdh_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t blk_nb) +{ + rt_err_t result = RT_ERROR; + rt_uint32_t ret = 0; + nu_sdh_t sdh = (nu_sdh_t)dev; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + + result = rt_sem_take(&sdh->lock, RT_WAITING_FOREVER); + RT_ASSERT(result == RT_EOK); + + /* Check alignment. */ + if (((uint32_t)buffer & 0x03) != 0) + { + /* Non-aligned. */ + uint32_t i; + uint8_t *copy_buffer = (uint8_t *)buffer; + + sdh->pbuf = rt_malloc(SDH_BLOCK_SIZE); + if (sdh->pbuf == RT_NULL) + goto exit_nu_sdh_write; + + for (i = 0; i < blk_nb; i++) + { +#if defined(BSP_USING_MMU) + mmu_clean_invalidated_dcache((rt_uint32_t)copy_buffer, SDH_BLOCK_SIZE); +#endif + + memcpy((void *)&sdh->pbuf[0], copy_buffer, SDH_BLOCK_SIZE); + + ret = SDH_Write(sdh->base, (uint8_t *)((uint32_t)&sdh->pbuf[0] | NONCACHEABLE), pos, 1); + if (ret != Successful) + goto exit_nu_sdh_write; + + pos++; + copy_buffer += SDH_BLOCK_SIZE; + } + } + else + { +#if defined(BSP_USING_MMU) + mmu_clean_invalidated_dcache((rt_uint32_t)buffer, SDH_BLOCK_SIZE * blk_nb); +#endif + + /* Write to device directly. */ + ret = SDH_Write(sdh->base, (uint8_t *)((uint32_t)buffer | NONCACHEABLE), pos, blk_nb); + } + +exit_nu_sdh_write: + + if (sdh->pbuf) + { + rt_free(sdh->pbuf); + sdh->pbuf = RT_NULL; + } + + result = rt_sem_release(&sdh->lock); + RT_ASSERT(result == RT_EOK); + + if (ret == Successful) return blk_nb; + + rt_kprintf("write failed: %d, buffer 0x%08x\n", ret, buffer); + rt_set_errno(-RT_ENOSYS); + return 0; +} + +static rt_err_t nu_sdh_control(rt_device_t dev, int cmd, void *args) +{ + nu_sdh_t sdh = (nu_sdh_t)dev; + + RT_ASSERT(dev != RT_NULL); + + if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) + { + SDH_INFO_T *sdh_info = sdh->info; + + struct rt_device_blk_geometry *geometry; + + geometry = (struct rt_device_blk_geometry *)args; + if (geometry == RT_NULL) return -RT_ERROR; + + geometry->bytes_per_sector = sdh_info->sectorSize; + geometry->block_size = sdh_info->sectorSize; + geometry->sector_count = sdh_info->totalSectorN; + } + + return RT_EOK; +} + + +static int rt_hw_sdh_init(void) +{ + int i; + rt_err_t ret = RT_EOK; + rt_uint32_t flags = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE; + + ret = rt_event_init(&sdh_event, "sdh_event", RT_IPC_FLAG_FIFO); + RT_ASSERT(ret == RT_EOK); + + for (i = (SDH_START + 1); i < SDH_CNT; i++) + { + /* Register sdcard device */ + nu_sdh_arr[i].dev.type = RT_Device_Class_Block; + nu_sdh_arr[i].dev.init = nu_sdh_init; + nu_sdh_arr[i].dev.open = nu_sdh_open; + nu_sdh_arr[i].dev.close = nu_sdh_close; + nu_sdh_arr[i].dev.read = nu_sdh_read; + nu_sdh_arr[i].dev.write = nu_sdh_write; + nu_sdh_arr[i].dev.control = nu_sdh_control; + + /* Private */ + nu_sdh_arr[i].dev.user_data = (void *)&nu_sdh_arr[i]; + + ret = rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO); + RT_ASSERT(ret == RT_EOK); + + rt_hw_interrupt_install(nu_sdh_arr[i].irqn, SDH_IRQHandler, (void *)&nu_sdh_arr[i], nu_sdh_arr[i].name); + rt_hw_interrupt_umask(nu_sdh_arr[i].irqn); + + nu_sys_ipclk_enable(nu_sdh_arr[i].clkidx); + + nu_sys_ip_reset(nu_sdh_arr[i].rstidx); + + nu_sdh_arr[i].pbuf = RT_NULL; + + ret = rt_device_register(&nu_sdh_arr[i].dev, nu_sdh_arr[i].name, flags); + RT_ASSERT(ret == RT_EOK); + } + + return (int)ret; +} +INIT_BOARD_EXPORT(rt_hw_sdh_init); + +#if defined(NU_SDH_HOTPLUG) +static rt_bool_t nu_sdh_hotplug_is_mounted(const char *mounting_path) +{ + rt_bool_t ret = RT_FALSE; + +#if defined(RT_USING_DFS) + + struct dfs_filesystem *psFS = dfs_filesystem_lookup(mounting_path); + if (psFS == RT_NULL) + { + goto exit_nu_sdh_hotplug_is_mounted; + } + else if (!rt_memcmp(psFS->path, mounting_path, rt_strlen(mounting_path))) + { + ret = RT_TRUE; + } + else + { + ret = RT_FALSE; + } + +exit_nu_sdh_hotplug_is_mounted: + +#endif + + return ret; +} +static rt_err_t nu_sdh_hotplug_mount(nu_sdh_t sdh) +{ + rt_err_t ret = RT_ERROR; + +#if defined(RT_USING_DFS) + DIR *t; + + if (nu_sdh_hotplug_is_mounted(sdh->mounted_point) == RT_TRUE) + { + ret = RT_EOK; + goto exit_nu_sdh_hotplug_mount; + } + + /* Check the SD folder path is valid. */ + if ((t = opendir(sdh->mounted_point)) != RT_NULL) + { + closedir(t); + } +#if !defined(NU_SDH_MOUNT_ON_ROOT) + else + { + + /* Check the ROOT path is valid. */ + if ((t = opendir(NU_SDH_MOUNTPOINT_ROOT)) != RT_NULL) + { + closedir(t); + } + else if ((ret = mkdir(NU_SDH_MOUNTPOINT_ROOT, 0)) != RT_EOK) + { + rt_kprintf("Failed to mkdir %s\n", NU_SDH_MOUNTPOINT_ROOT); + goto exit_nu_sdh_hotplug_mount; + } + + if ((ret = mkdir(sdh->mounted_point, 0)) != RT_EOK) + { + rt_kprintf("Failed to mkdir %s\n", sdh->mounted_point); + goto exit_nu_sdh_hotplug_mount; + } + + } //else +#endif + + if ((ret = dfs_mount(sdh->name, sdh->mounted_point, "elm", 0, 0)) == 0) + { + rt_kprintf("Mounted %s on %s\n", sdh->name, sdh->mounted_point); + } + else + { + rt_kprintf("Failed to mount %s on %s\n", sdh->name, sdh->mounted_point); + ret = RT_ERROR; + } + +exit_nu_sdh_hotplug_mount: + +#endif + return -(ret); +} + +static rt_err_t nu_sdh_hotplug_unmount(nu_sdh_t sdh) +{ + rt_err_t ret = RT_ERROR; + +#if defined(RT_USING_DFS) + if (nu_sdh_hotplug_is_mounted(sdh->mounted_point) == RT_FALSE) + { + ret = RT_EOK; + goto exit_nu_sdh_hotplug_unmount; + } + + ret = dfs_unmount(sdh->mounted_point); + if (ret != RT_EOK) + { + rt_kprintf("Failed to unmount %s.\n", sdh->mounted_point); + } + else + { + rt_kprintf("Succeed to unmount %s.\n", sdh->mounted_point); + ret = RT_EOK; + } + +exit_nu_sdh_hotplug_unmount: + +#endif + + return -(ret); +} + +static void nu_card_detector(nu_sdh_t sdh) +{ + SDH_T *sdh_base = sdh->base; + unsigned int volatile isr = sdh_base->INTSTS; + if (isr & SDH_INTSTS_CDSTS_Msk) + { + /* Card removed */ + sdh->info->IsCardInsert = FALSE; // SDISR_CD_Card = 1 means card remove for GPIO mode + rt_memset((void *)sdh->info, 0, sizeof(SDH_INFO_T)); + nu_sdh_hotplug_unmount(sdh); + } + else + { + SDH_Open(sdh_base, CardDetect_From_GPIO); + if (!SDH_Probe(sdh_base)) + { + /* Card inserted */ + nu_sdh_hotplug_mount(sdh); + } + } +} + +static void sdh_hotplugger(void *param) +{ + rt_uint32_t e; + int i; + + for (i = (SDH_START + 1); i < SDH_CNT; i++) + { + /* Try to detect SD card on selected port. */ + SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO); + if (!SDH_Probe(nu_sdh_arr[i].base) && + SDH_IS_CARD_PRESENT(nu_sdh_arr[i].base)) + { + nu_sdh_hotplug_mount(&nu_sdh_arr[i]); + } + } + + while (1) + { + if (rt_event_recv(&sdh_event, (NU_SDH_CARD_EVENT_ALL), + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, + RT_WAITING_FOREVER, &e) == RT_EOK) + { + /* Debounce */ + rt_thread_mdelay(200); + switch (e) + { +#if defined(BSP_USING_SDH0) + case NU_SDH_CARD_DETECTED_SD0: + nu_card_detector(&nu_sdh_arr[SDH0_IDX]); + break; +#endif +#if defined(BSP_USING_SDH1) + case NU_SDH_CARD_DETECTED_SD1: + nu_card_detector(&nu_sdh_arr[SDH1_IDX]); + break; +#endif + default: + break; + + } //switch(e) + + } //if + + } /* while(1) */ +} + +int mnt_init_sdcard_hotplug(void) +{ + rt_err_t ret = RT_EOK; + + ret = rt_thread_init(&sdh_tid, "hotplug", sdh_hotplugger, NULL, sdh_stack, sizeof(sdh_stack), RT_THREAD_PRIORITY_MAX - 2, 10); + RT_ASSERT(ret == RT_EOK); + + ret = rt_thread_startup(&sdh_tid); + RT_ASSERT(ret == RT_EOK); + + return 0; +} +INIT_ENV_EXPORT(mnt_init_sdcard_hotplug); +#endif + +#endif //#if defined(BSP_USING_SDH) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_softi2c.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_softi2c.c new file mode 100644 index 0000000000000000000000000000000000000000..8defbe38ebbc8d91a7a5e5cd3e3a0b59637981d8 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_softi2c.c @@ -0,0 +1,238 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if (defined(BSP_USING_SOFT_I2C) && defined(RT_USING_I2C_BITOPS) && defined(RT_USING_I2C) && defined(RT_USING_PIN)) + +#include +#include +#include +#include "NuMicro.h" +#include "drv_sys.h" + +/* Private define ---------------------------------------------------------------*/ +#define LOG_TAG "drv.softi2c" +#define DBG_ENABLE +#define DBG_SECTION_NAME LOG_TAG +#define DBG_LEVEL DBG_INFO +#include + +#ifdef BSP_USING_SOFT_I2C0 +#define NU_SOFT_I2C0_BUS_CONFIG \ + { \ + .scl = BSP_SOFT_I2C0_SCL_PIN, \ + .sda = BSP_SOFT_I2C0_SDA_PIN, \ + .bus_name = "softi2c0", \ + } +#endif + +#ifdef BSP_USING_SOFT_I2C1 +#define NU_SOFT_I2C1_BUS_CONFIG \ + { \ + .scl = BSP_SOFT_I2C1_SCL_PIN, \ + .sda = BSP_SOFT_I2C1_SDA_PIN, \ + .bus_name = "softi2c1", \ + } +#endif + +#if (!defined(BSP_USING_SOFT_I2C0) && !defined(BSP_USING_SOFT_I2C1)) + #error "Please define at least one BSP_USING_SOFT_I2Cx" + /* this driver can be disabled at menuconfig ? RT-Thread Components ? Device Drivers */ +#endif + +/* Private typedef --------------------------------------------------------------*/ +/* soft i2c config class */ +struct nu_soft_i2c_config +{ + rt_uint8_t scl; + rt_uint8_t sda; + const char *bus_name; +}; +/* soft i2c driver class */ +struct nu_soft_i2c +{ + struct rt_i2c_bit_ops ops; + struct rt_i2c_bus_device soft_i2c_bus; +}; + +/* Private functions ------------------------------------------------------------*/ +static void nu_soft_i2c_udelay(rt_uint32_t us); +static void nu_soft_i2c_set_sda(void *data, rt_int32_t state); +static void nu_soft_i2c_set_scl(void *data, rt_int32_t state); +static rt_int32_t nu_soft_i2c_get_sda(void *data); +static rt_int32_t nu_soft_i2c_get_scl(void *data); + +/* Private variables ------------------------------------------------------------*/ +static const struct nu_soft_i2c_config nu_soft_i2c_cfg[] = +{ +#ifdef BSP_USING_SOFT_I2C0 + NU_SOFT_I2C0_BUS_CONFIG, +#endif +#ifdef BSP_USING_SOFT_I2C1 + NU_SOFT_I2C1_BUS_CONFIG, +#endif +}; + +static struct nu_soft_i2c nu_soft_i2c_obj[sizeof(nu_soft_i2c_cfg) / sizeof(nu_soft_i2c_cfg[0])]; + +static const struct rt_i2c_bit_ops nu_soft_i2c_bit_ops = +{ + .data = RT_NULL, + .set_sda = nu_soft_i2c_set_sda, + .set_scl = nu_soft_i2c_set_scl, + .get_sda = nu_soft_i2c_get_sda, + .get_scl = nu_soft_i2c_get_scl, + .udelay = nu_soft_i2c_udelay, + .delay_us = 1, + .timeout = 100 +}; + +/* Functions define ------------------------------------------------------------*/ + +/** + * The time delay function. + * + * @param microseconds. + */ +static void nu_soft_i2c_udelay(rt_uint32_t us) +{ + rt_hw_us_delay(us); +} + +/** + * This function initializes the soft i2c pin. + * + * @param soft i2c config class. + */ +static void nu_soft_i2c_gpio_init(const struct nu_soft_i2c_config *cfg) +{ + rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT); + rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT); + + rt_pin_write(cfg->scl, PIN_HIGH); + rt_pin_write(cfg->sda, PIN_HIGH); +} + +/** + * if i2c is locked, this function will unlock it + * + * @param soft i2c config class + * + * @return RT_EOK indicates successful unlock. + */ +static rt_err_t nu_soft_i2c_bus_unlock(const struct nu_soft_i2c_config *cfg) +{ + rt_int32_t i = 0; + + rt_pin_mode(cfg->sda, PIN_MODE_INPUT); + rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT); + + if (PIN_LOW == rt_pin_read(cfg->sda)) + { + while (i++ < 9) + { + rt_pin_write(cfg->scl, PIN_HIGH); + nu_soft_i2c_udelay(100); + rt_pin_write(cfg->scl, PIN_LOW); + nu_soft_i2c_udelay(100); + } + } + if (PIN_LOW == rt_pin_read(cfg->sda)) + { + return -RT_ERROR; + } + + return RT_EOK; +} + +/** + * This function sets the sda pin. + * + * @param soft i2c config class. + * @param The sda pin state. + */ +static void nu_soft_i2c_set_sda(void *data, rt_int32_t state) +{ + struct nu_soft_i2c_config *cfg = (struct nu_soft_i2c_config *)data; + + rt_pin_mode(cfg->sda, PIN_MODE_OUTPUT); + rt_pin_write(cfg->sda, state ? PIN_HIGH : PIN_LOW); +} + +/** + * This function sets the scl pin. + * + * @param soft i2c config class. + * @param The scl pin state. + */ +static void nu_soft_i2c_set_scl(void *data, rt_int32_t state) +{ + struct nu_soft_i2c_config *cfg = (struct nu_soft_i2c_config *)data; + + rt_pin_mode(cfg->scl, PIN_MODE_OUTPUT); + rt_pin_write(cfg->scl, state ? PIN_HIGH : PIN_LOW); +} + +/** + * This function gets the sda pin state. + * + * @param The sda pin state. + */ +static rt_int32_t nu_soft_i2c_get_sda(void *data) +{ + struct nu_soft_i2c_config *cfg = (struct nu_soft_i2c_config *)data; + + rt_pin_mode(cfg->sda, PIN_MODE_INPUT); + return rt_pin_read(cfg->sda); +} + +/** + * This function gets the scl pin state. + * + * @param The scl pin state. + */ +static rt_int32_t nu_soft_i2c_get_scl(void *data) +{ + struct nu_soft_i2c_config *cfg = (struct nu_soft_i2c_config *)data; + + rt_pin_mode(cfg->scl, PIN_MODE_INPUT); + return rt_pin_read(cfg->scl); +} + +/* Soft I2C initialization function */ +int rt_soft_i2c_init(void) +{ + rt_size_t obj_num = sizeof(nu_soft_i2c_obj) / sizeof(struct nu_soft_i2c); + rt_err_t result; + + for (int i = 0; i < obj_num; i++) + { + nu_soft_i2c_obj[i].ops = nu_soft_i2c_bit_ops; + nu_soft_i2c_obj[i].ops.data = (void *)&nu_soft_i2c_cfg[i]; + nu_soft_i2c_obj[i].soft_i2c_bus.priv = &nu_soft_i2c_obj[i].ops; + nu_soft_i2c_gpio_init(&nu_soft_i2c_cfg[i]); + result = rt_i2c_bit_add_bus(&nu_soft_i2c_obj[i].soft_i2c_bus, nu_soft_i2c_cfg[i].bus_name); + RT_ASSERT(result == RT_EOK); + nu_soft_i2c_bus_unlock(&nu_soft_i2c_cfg[i]); + + LOG_I("software simulation %s init done, pin scl: %d, pin sda %d", + nu_soft_i2c_cfg[i].bus_name, + nu_soft_i2c_cfg[i].scl, + nu_soft_i2c_cfg[i].sda); + } + + return 0; +} +INIT_DEVICE_EXPORT(rt_soft_i2c_init); + +#endif //#if (defined(BSP_USING_SOFT_I2C) && defined(RT_USING_I2C_BITOPS) && defined(RT_USING_I2C) && defined(RT_USING_PIN)) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.c new file mode 100644 index 0000000000000000000000000000000000000000..43b0c2cfb859aebb5914d84922fda706f313b733 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.c @@ -0,0 +1,330 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-11-11 Wayne First version +* +******************************************************************************/ + +#include +#include +#include "NuMicro.h" +#include "drv_sys.h" + +#define SYS_MIN_INT_SOURCE 1 +#define SYS_MAX_INT_SOURCE 62 +#define SYS_NUM_OF_AICREG 16 +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +extern rt_uint32_t rt_interrupt_nest; + +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +struct rt_irq_desc irq_desc[SYS_MAX_INT_SOURCE + 1]; + +void rt_hw_interrupt_dummy_handler(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occurred!!!\n", vector); + RT_ASSERT(0); +} + +void rt_hw_interrupt_set_priority(int vector, int IntTypeLevel) +{ + sysSetInterruptPriorityLevel((IRQn_Type)vector, (UINT32)IntTypeLevel); +} + +void rt_interrupt_dispatch(rt_uint32_t fiq_irq) +{ + rt_isr_handler_t isr_func; + rt_uint32_t volatile _mIPER, _mISNR; + void *param; + + /* Get irq number */ + _mIPER = (inpw(REG_AIC_IPER) >> 2) & 0x3f; + _mISNR = inpw(REG_AIC_ISNR) & 0x3f; + if ((_mIPER != _mISNR) || _mISNR == 0) + return; + + /* Get interrupt service routine */ + isr_func = irq_desc[_mISNR].handler; + param = irq_desc[_mISNR].param; + +#ifdef RT_USING_INTERRUPT_INFO + irq_desc[_mISNR].counter ++; +#endif + + /* Turn to interrupt service routine */ + isr_func(_mISNR, param); + + /* Handled the ISR. */ + outpw(REG_AIC_EOSCR, 1); +} + +void rt_hw_interrupt_init(void) +{ + int i; + + *((volatile unsigned int *)REG_AIC_ISR) = 0xFFFFFFFF; // disable all interrupt channel + *((volatile unsigned int *)REG_AIC_ISRH) = 0xFFFFFFFF; // disable all interrupt channel + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; + + for (i = SYS_MIN_INT_SOURCE; i <= SYS_MAX_INT_SOURCE; i++) + { + rt_hw_interrupt_install(i, rt_hw_interrupt_dummy_handler, RT_NULL, (char *)"dummy"); + rt_hw_interrupt_mask(i); + } +} + +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector > SYS_MAX_INT_SOURCE) + return RT_NULL; + + /* Set default priority IRQ_LEVEL_7 */ + rt_hw_interrupt_set_priority(vector, IRQ_LEVEL_7); + + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = (rt_isr_handler_t)handler; + irq_desc[vector].param = param; +#ifdef RT_USING_INTERRUPT_INFO + rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name); + irq_desc[vector].counter = 0; +#endif + } + + return old_handler; +} + +/* Disable interrupt */ +void rt_hw_interrupt_mask(int vector) +{ + sysDisableInterrupt((IRQn_Type)vector); +} + +void rt_hw_interrupt_umask(int vector) +{ + sysEnableInterrupt((IRQn_Type)vector); +} + +/* TYPE + * #define LOW_LEVEL_SENSITIVE 0x00 + * #define HIGH_LEVEL_SENSITIVE 0x40 + * #define NEGATIVE_EDGE_TRIGGER 0x80 + * #define POSITIVE_EDGE_TRIGGER 0xC0 + */ +void rt_hw_interrupt_set_type(int vector, int type) +{ + sysSetInterruptType((IRQn_Type)vector, (UINT32) type); +} + +void rt_low_level_init(void) +{ + /* Unlock write-protect */ + SYS_UnlockReg(); + + /* Close WDT first, to avoid WDT timer is enabled IBR timeout reset. */ + WDT_Close(); + + /* Lock write-protect */ + SYS_LockReg(); +} + +void nu_clock_base_init(void) +{ + nu_sys_ipclk_enable(CPUCKEN); + nu_sys_ipclk_enable(HCLKCKEN); + nu_sys_ipclk_enable(HCLK1CKEN); + nu_sys_ipclk_enable(HCLK3CKEN); + nu_sys_ipclk_enable(HCLK4CKEN); + nu_sys_ipclk_enable(PCLKCKEN); + nu_sys_ipclk_enable(SRAMCKEN); + nu_sys_ipclk_enable(DDRCKEN); +} + +void machine_reset(void) +{ + rt_kprintf("machine_reset...\n"); + rt_hw_interrupt_disable(); + + /* Unlock */ + SYS_UnlockReg(); + + nu_sys_ip_reset(CHIPRST); + + while (1); +} + +void machine_shutdown(void) +{ + rt_kprintf("machine_shutdown...\n"); + rt_hw_interrupt_disable(); + + /* Unlock */ + SYS_UnlockReg(); + + while (1); +} + + +void nu_sys_ip_reset(E_SYS_IPRST eIPRstIdx) +{ + uint32_t volatile u32IPRSTRegAddr; + uint32_t u32IPRSTRegBit; + rt_uint32_t level; + + if (eIPRstIdx >= SYS_IPRST_CNT) + return; + + u32IPRSTRegAddr = REG_SYS_AHBIPRST + (4ul * (eIPRstIdx / 32)); + u32IPRSTRegBit = eIPRstIdx % 32; + + /* Enter critical section */ + level = rt_hw_interrupt_disable(); + + /* Unlock write-protect */ + SYS_UnlockReg(); + + /* Enable IP reset */ + outpw(u32IPRSTRegAddr, inpw(u32IPRSTRegAddr) | (1 << u32IPRSTRegBit)); + + /* Disable IP reset */ + outpw(u32IPRSTRegAddr, inpw(u32IPRSTRegAddr) & ~(1 << u32IPRSTRegBit)); + + /* Wait it done. */ + while (inpw(u32IPRSTRegAddr) & (1 << u32IPRSTRegBit)) {} + + /* Lock write protect */ + SYS_LockReg(); + + /* Leave critical section */ + rt_hw_interrupt_enable(level); +} + +static void _nu_sys_ipclk(E_SYS_IPCLK eIPClkIdx, uint32_t bEnable) +{ + uint32_t volatile u32IPCLKRegAddr; + uint32_t u32IPCLKRegBit; + rt_uint32_t level; + + if (eIPClkIdx >= SYS_IPCLK_CNT) + return; + + u32IPCLKRegAddr = REG_CLK_HCLKEN + (4ul * (eIPClkIdx / 32)); + u32IPCLKRegBit = eIPClkIdx % 32; + + /* Enter critical section */ + level = rt_hw_interrupt_disable(); + + if (bEnable) + { + /* Enable IP CLK */ + outpw(u32IPCLKRegAddr, inpw(u32IPCLKRegAddr) | (1 << u32IPCLKRegBit)); + } + else + { + /* Disable IP CLK */ + outpw(u32IPCLKRegAddr, inpw(u32IPCLKRegAddr) & ~(1 << u32IPCLKRegBit)); + } + + /* Leave critical section */ + rt_hw_interrupt_enable(level); +} + + +void nu_sys_ipclk_enable(E_SYS_IPCLK eIPClkIdx) +{ + _nu_sys_ipclk(eIPClkIdx, 1); +} + +void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx) +{ + _nu_sys_ipclk(eIPClkIdx, 0); +} + +E_SYS_USB0_ID nu_sys_usb0_role(void) +{ + /* Check Role on USB0 dual-role port. */ + /* + [17] USB0_IDS + USB0_ID Status + 0 = USB port 0 used as a USB device port. + 1 = USB port 0 used as a USB host port. + */ + return ((inpw(REG_SYS_MISCISR) & (1 << 17)) > 0) ? USB0_ID_HOST : USB0_ID_DEVICE; +} + +#ifdef RT_USING_FINSH + +#include +FINSH_FUNCTION_EXPORT_ALIAS(rt_hw_cpu_reset, reset, restart the system); + +#ifdef FINSH_USING_MSH +int cmd_reset(int argc, char **argv) +{ + rt_hw_cpu_reset(); + return 0; +} + +int cmd_shutdown(int argc, char **argv) +{ + rt_hw_cpu_shutdown(); + return 0; +} + +FINSH_FUNCTION_EXPORT_ALIAS(cmd_reset, __cmd_reset, restart the system.); +FINSH_FUNCTION_EXPORT_ALIAS(cmd_shutdown, __cmd_shutdown, shutdown the system.); + +int nu_clocks(int argc, char **argv) +{ + rt_kprintf("SYS_UPLL = %d MHz\n", sysGetClock(SYS_UPLL)); + rt_kprintf("SYS_APLL = %d MHz\n", sysGetClock(SYS_APLL)); + rt_kprintf("SYS_SYSTEM = %d MHz\n", sysGetClock(SYS_SYSTEM)); + rt_kprintf("SYS_HCLK1 = %d MHz\n", sysGetClock(SYS_HCLK1)); + rt_kprintf("SYS_HCLK234 = %d MHz\n", sysGetClock(SYS_HCLK234)); + rt_kprintf("SYS_PCLK = %d MHz\n", sysGetClock(SYS_PCLK)); + rt_kprintf("SYS_CPU = %d MHz\n", sysGetClock(SYS_CPU)); + + rt_kprintf("CLK_HCLKEN = %08X\n", inpw(REG_CLK_HCLKEN)); + rt_kprintf("CLK_PCLKEN0 = %08X\n", inpw(REG_CLK_PCLKEN0)); + rt_kprintf("CLK_PCLKEN1 = %08X\n", inpw(REG_CLK_PCLKEN1)); + + return 0; +} +MSH_CMD_EXPORT(nu_clocks, Get all system clocks); + +#ifdef RT_USING_INTERRUPT_INFO +int list_interrupt(int argc, char **argv) +{ + int i; + + for (i = SYS_MIN_INT_SOURCE; i <= SYS_MAX_INT_SOURCE; i++) + { + if (irq_desc[i].handler != rt_hw_interrupt_dummy_handler) + { + rt_kprintf("[%d] %s: %d\n", i, irq_desc[i].name, irq_desc[i].counter); + } + } + + return 0; +} +MSH_CMD_EXPORT(list_interrupt, list registered interrupts); +#endif + +#endif + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.h new file mode 100644 index 0000000000000000000000000000000000000000..621a476e6dae0a05150d1b535758a5e59b7ba4d4 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.h @@ -0,0 +1,281 @@ +#ifndef __PLAT_INTERRUPT_H__ +#define __PLAT_INTERRUPT_H__ + +#include "rthw.h" +#include + +#if defined(BSP_USING_MMU) + #include "mmu.h" + #define NONCACHEABLE BIT31 +#else + #define NONCACHEABLE 0 +#endif + +#define sysprintf rt_kprintf + +typedef enum +{ + SYS_IPRST_NA = -1, + + /* SYS_AHBIPRST, SYS_BA + 0x060 */ + CHIPRST, + AHBIPRST_Reserved_1, + CPURST, + GDMARST, + AHBIPRST_Reserved_4, + AHBIPRST_Reserved_5, + AHBIPRST_Reserved_6, + AHBIPRST_Reserved_7, + + I2SRST, + LCDRST, + CAPRST, + AHBIPRST_Reserved_11, + AHBIPRST_Reserved_12, + AHBIPRST_Reserved_13, + AHBIPRST_Reserved_14, + AHBIPRST_Reserved_15, + + EMAC0RST, + EMAC1RST, + USBHRST, + USBDRST, + FMIRST, + GE2DRST, + JPEGRST, + CRYPTORST, + + SDIORST, + AHBIPRST_Reserved_25, + AHBIPRST_Reserved_26, + AHBIPRST_Reserved_27, + AHBIPRST_Reserved_28, + AHBIPRST_Reserved_29, + AHBIPRST_Reserved_30, + AHBIPRST_Reserved_31, + + /* SYS_APBIPRST0, SYS_BA + 0x064 */ + APBIPRST0_Reserved_0, + APBIPRST0_Reserved_1, + APBIPRST0_Reserved_2, + GPIORST, + ETIMER0RST, + ETIMER1RST, + ETIMER2RST, + ETIMER3RST, + + TIMER0RST, + TIMER1RST, + TIMER2RST, + TIMER3RST, + TIMER4RST, + APBIPRST0_Reserved_13, + APBIPRST0_Reserved_14, + APBIPRST0_Reserved_15, + + UART0RST, + UART1RST, + UART2RST, + UART3RST, + UART4RST, + UART5RST, + UART6RST, + UART7RST, + + UART8RST, + UART9RST, + UART10RST, + APBIPRST0_Reserved_27, + APBIPRST0_Reserved_28, + APBIPRST0_Reserved_29, + APBIPRST0_Reserved_30, + APBIPRST0_Reserved_31, + + /* SYS_APBIPRST1, SYS_BA + 0x068 */ + I2C0RST, + I2C1RST, + APBIPRST1_Reserved_2, + APBIPRST1_Reserved_3, + SPI0RST, + SPI1RST, + APBIPRST1_Reserved_6, + APBIPRST1_Reserved_7, + + CAN0RST, + CAN1RST, + APBIPRST1_Reserved_10, + APBIPRST1_Reserved_11, + SMC0RST, + SMC1RST, + APBIPRST1_Reserved_14, + APBIPRST1_Reserved_15, + + APBIPRST1_Reserved_16, + APBIPRST1_Reserved_17, + APBIPRST1_Reserved_18, + APBIPRST1_Reserved_19, + APBIPRST1_Reserved_20, + APBIPRST1_Reserved_21, + APBIPRST1_Reserved_22, + APBIPRST1_Reserved_23, + + ADCRST, + APBIPRST1_Reserved_25, + MTPCRST, + PWMRST, + APBIPRST1_Reserved_28, + APBIPRST1_Reserved_29, + APBIPRST1_Reserved_30, + APBIPRST1_Reserved_31, + + SYS_IPRST_CNT + +} E_SYS_IPRST; + +typedef enum +{ + SYS_IPCLK_NA = -1, + + /* CLK_HCLKEN, CLK_BA + 0x010 */ + CPUCKEN, + HCLKCKEN, + HCLK1CKEN, + HCLK3CKEN, + HCLK4CKEN, + PCLKCKEN, + HCLKEN_Reserved_6, + TICCKEN, + + SRAMCKEN, + EBICKEN, + DDRCKEN, + HCLKEN_Reserved_11, + GDMACKEN, + HCLKEN_Reserved_13, + HCLKEN_Reserved_14, + CKOCKEN, + + EMAC0CKEN, + EMAC1CKEN, + USBHCKEN, + USBDCKEN, + FMICKEN, + NANDCKEN, + EMMCCKEN, + CRYPTOCKEN, + + I2SCKEN, + LCDCKEN, + CAPCKEN, + SENSORCKEN, + GE2DCKEN, + JPEGCKEN, + SDHCKEN, + HCLKEN_Reserved_31, + + CLK_HCLKEN_END, + + /* CLK_BA+0x014 */ + + /* CLK_PCLKEN0 CLK_BA+0x018 */ + CLK_PCLKEN0_BEGIN = CLK_HCLKEN_END + 32, + + WDTCKEN = CLK_PCLKEN0_BEGIN, + WWDTCKEN, + RTCCKEN, + GPIOCKEN, + ETIMER0CKEN, + ETIMER1CKEN, + ETIMER2CKEN, + ETIMER3CKEN, + + TIMER0CKEN, + TIMER1CKEN, + TIMER2CKEN, + TIMER3CKEN, + TIMER4CKEN, + PCLKEN0_Reserved_14, + PCLKEN0_Reserved_15, + PCLKEN0_Reserved_16, + + UART0CKEN, + UART1CKEN, + UART2CKEN, + UART3CKEN, + UART4CKEN, + UART5CKEN, + UART6CKEN, + UART7CKEN, + + UART8CKEN, + UART9CKEN, + UART10CKEN, + PCLKEN0_Reserved_27, + PCLKEN0_Reserved_28, + PCLKEN0_Reserved_29, + PCLKEN0_Reserved_30, + PCLKEN0_Reserved_31, + + /* CLK_PCLKEN1, CLK_BA + 0x01C */ + I2C0CKEN, + I2C1CKEN, + PCLKEN1_Reserved_2, + PCLKEN1_Reserved_3, + SPI0CKEN, + SPI1CKEN, + PCLKEN1_Reserved_6, + PCLKEN1_Reserved_7, + + CAN0CKEN, + CAN1CKEN, + PCLKEN1_Reserved_10, + PCLKEN1_Reserved_11, + SMC0CKEN, + SMC1CKEN, + PCLKEN1_Reserved_14, + PCLKEN1_Reserved_15, + + PCLKEN1_Reserved_16, + PCLKEN1_Reserved_17, + PCLKEN1_Reserved_18, + PCLKEN1_Reserved_19, + PCLKEN1_Reserved_20, + PCLKEN1_Reserved_21, + PCLKEN1_Reserved_22, + PCLKEN1_Reserved_23, + + ADCCKEN, + PCLKEN1_Reserved_25, + MTPCCKEN, + PWMCKEN, + PCLKEN1_Reserved_28, + PCLKEN1_Reserved_29, + PCLKEN1_Reserved_30, + PCLKEN1_Reserved_31, + + SYS_IPCLK_CNT + +} E_SYS_IPCLK; + +typedef enum +{ + USB0_ID_DEVICE, + USB0_ID_HOST, + USB0_ID_CNT +} E_SYS_USB0_ID; + +void rt_hw_interrupt_init(void); +void rt_hw_interrupt_set_priority(int vector, int priority); +void rt_hw_interrupt_set_type(int vector, int type); +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name); + +void rt_hw_systick_init(void); +void nu_clock_base_init(void); + +void nu_systick_udelay(uint32_t delay_us); +void nu_sys_ip_reset(E_SYS_IPRST eIPRstIdx); +void nu_sys_ipclk_enable(E_SYS_IPCLK eIPClkIdx); +void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx); +E_SYS_USB0_ID nu_sys_usb0_role(void); + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_systick.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_systick.c new file mode 100644 index 0000000000000000000000000000000000000000..8587be6ba345467b339b6bff0cf565cd463b2c34 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_systick.c @@ -0,0 +1,92 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-11-11 Wayne First version +* +******************************************************************************/ + +#include "rtthread.h" +#include "NuMicro.h" +#include "drv_sys.h" +#include "nu_timer.h" + +#define USE_TIMER 4 + +/* Concatenate */ +#define _CONCAT2_(x, y) x##y +#define _CONCAT3_(x, y, z) x##y##z +#define CONCAT2(x, y) _CONCAT2_(x, y) +#define CONCAT3(x, y, z) _CONCAT3_(x,y,z) + +/* Concatenate the macros of timer instance for driver usage. */ +#define SYSTICK_IRQ CONCAT2(IRQ_TMR, USE_TIMER ) + +#define SYSTICK_CLKEN CONCAT3(TIMER, USE_TIMER, CKEN) + +#define SYSTICK_RST CONCAT3(TIMER, USE_TIMER, RST) + +static void nu_systick_isr(int vector, void *param) +{ + rt_tick_increase(); + TIMER_ClearIntFlag(USE_TIMER); +} + +void rt_hw_systick_init(void) +{ + nu_sys_ipclk_enable(SYSTICK_CLKEN); + + nu_sys_ip_reset(SYSTICK_RST); + + // Set timer frequency + TIMER_Open(USE_TIMER, TIMER_PERIODIC_MODE, RT_TICK_PER_SECOND); + + // Enable timer interrupt + TIMER_EnableInt(USE_TIMER); + + rt_hw_interrupt_install(SYSTICK_IRQ, nu_systick_isr, RT_NULL, "systick"); + rt_hw_interrupt_set_priority(SYSTICK_IRQ, IRQ_LEVEL_1); + rt_hw_interrupt_umask(SYSTICK_IRQ); + + TIMER_Start(USE_TIMER); +} /* rt_hw_systick_init */ + +void rt_hw_us_delay(rt_uint32_t us) +{ + rt_uint32_t ticks; + rt_uint32_t told, tnow, tcnt = 0; + rt_uint32_t cmp = TIMER_GetCompareData(USE_TIMER); + + ticks = us * cmp / (1000000 / RT_TICK_PER_SECOND); + told = TIMER_GetCounter(USE_TIMER); + while (1) + { + /* Timer counter is increment. */ + tnow = TIMER_GetCounter(USE_TIMER); + if (tnow != told) + { + /* 0 -- old === now -------- cmp */ + if (tnow > told) + { + tcnt += tnow - told; + } + else + { + /* 0 == now --- old ======== cmp */ + tcnt += cmp - told + tnow; + } + told = tnow; + + /* Timeout */ + if (tcnt >= ticks) + { + break; + } + } + } + +} /* rt_hw_us_delay */ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_timer.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..946da8a6f15223380399e0d8c34968aa7f043c81 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_timer.c @@ -0,0 +1,285 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-3 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_TIMER) && defined(RT_USING_HWTIMER) + +#include +#include "NuMicro.h" +#include +#include "nu_timer.h" + +/* Private define ---------------------------------------------------------------*/ +#define NU_TIMER_DEVICE(timer) (nu_timer_t)(timer) + +enum +{ + TIMER_START = -1, +#if defined(BSP_USING_TIMER0) + TIMER0_IDX, +#endif +#if defined(BSP_USING_TIMER1) + TIMER1_IDX, +#endif +#if defined(BSP_USING_TIMER2) + TIMER2_IDX, +#endif +#if defined(BSP_USING_TIMER3) + TIMER3_IDX, +#endif + /* BSP_USING_TIMER4 is reserved for Systick usage. */ + TIMER_CNT +}; + +/* Private typedef --------------------------------------------------------------*/ +struct nu_timer +{ + rt_hwtimer_t parent; + char *name; + uint32_t idx; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; +}; +typedef struct nu_timer *nu_timer_t; + +/* Private functions ------------------------------------------------------------*/ +static void nu_timer_init(rt_hwtimer_t *timer, rt_uint32_t state); +static rt_err_t nu_timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode); +static void nu_timer_stop(rt_hwtimer_t *timer); +static rt_uint32_t nu_timer_count_get(rt_hwtimer_t *timer); +static rt_err_t nu_timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args); + +/* Public functions -------------------------------------------------------------*/ + + +/* Private variables ------------------------------------------------------------*/ +static struct nu_timer nu_timer_arr [] = +{ +#if defined(BSP_USING_TIMER0) + { + .name = "timer0", + .idx = 0, + .irqn = IRQ_TMR0, + .rstidx = TIMER0RST, + .clkidx = TIMER0CKEN, + }, +#endif +#if defined(BSP_USING_TIMER1) + { + .name = "timer1", + .idx = 1, + .irqn = IRQ_TMR1, + .rstidx = TIMER1RST, + .clkidx = TIMER1CKEN, + }, +#endif +#if defined(BSP_USING_TIMER2) + { + .name = "timer2", + .idx = 2, + .irqn = IRQ_TMR2, + .rstidx = TIMER2RST, + .clkidx = TIMER2CKEN, + }, +#endif +#if defined(BSP_USING_TIMER3) + { + .name = "timer3", + .idx = 3, + .irqn = IRQ_TMR3, + .rstidx = TIMER3RST, + .clkidx = TIMER3CKEN, + }, +#endif + /* BSP_USING_TIMER4 is reserved for Systick usage. */ +}; + +static struct rt_hwtimer_info nu_timer_info = +{ + 12000000, /* maximum count frequency */ + 46875, /* minimum count frequency */ + 0xFFFFFF, /* the maximum counter value */ + HWTIMER_CNTMODE_UP, /* Increment or Decreasing count mode */ +}; + +static struct rt_hwtimer_ops nu_timer_ops = +{ + nu_timer_init, + nu_timer_start, + nu_timer_stop, + nu_timer_count_get, + nu_timer_control +}; + +/* Functions define ------------------------------------------------------------*/ +static void nu_timer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuTmr != RT_NULL); + + if (1 == state) + { + uint32_t timer_clk; + struct rt_hwtimer_info *info = &nu_timer_info; + + timer_clk = TIMER_GetModuleClock(psNuTmr->idx); + info->maxfreq = timer_clk; + info->minfreq = timer_clk / 256; + TIMER_Open(psNuTmr->idx, TIMER_ONESHOT_MODE, 1); + TIMER_EnableInt(psNuTmr->idx); + rt_hw_interrupt_umask(psNuTmr->irqn); + } + else + { + rt_hw_interrupt_mask(psNuTmr->irqn); + TIMER_DisableInt(psNuTmr->idx); + TIMER_Close(psNuTmr->idx); + } +} + +static rt_err_t nu_timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode) +{ + rt_err_t ret = RT_EINVAL; + rt_uint32_t u32OpMode; + + nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuTmr != RT_NULL); + + if (cnt <= 1 || cnt > 0xFFFFFF) + { + goto exit_nu_timer_start; + } + + switch (opmode) + { + case HWTIMER_MODE_PERIOD: + u32OpMode = TIMER_PERIODIC_MODE; + break; + + case HWTIMER_MODE_ONESHOT: + u32OpMode = TIMER_ONESHOT_MODE; + break; + + default: + goto exit_nu_timer_start; + } + + TIMER_SET_CMP_VALUE(psNuTmr->idx, cnt); + TIMER_SET_OPMODE(psNuTmr->idx, u32OpMode); + TIMER_EnableInt(psNuTmr->idx); + rt_hw_interrupt_umask(psNuTmr->irqn); + + TIMER_Start(psNuTmr->idx); + + ret = RT_EOK; + +exit_nu_timer_start: + + return -(ret); +} + +static void nu_timer_stop(rt_hwtimer_t *timer) +{ + nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuTmr != RT_NULL); + + rt_hw_interrupt_mask(psNuTmr->irqn); + TIMER_DisableInt(psNuTmr->idx); + TIMER_Stop(psNuTmr->idx); + TIMER_ClearCounter(psNuTmr->idx); +} + +static rt_uint32_t nu_timer_count_get(rt_hwtimer_t *timer) +{ + nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuTmr != RT_NULL); + + return TIMER_GetCounter(psNuTmr->idx); +} + +static rt_err_t nu_timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t ret = RT_EOK; + nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer); + RT_ASSERT(psNuTmr != RT_NULL); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + { + uint32_t clk; + uint32_t pre; + + clk = TIMER_GetModuleClock(psNuTmr->idx); + pre = clk / *((uint32_t *)args) - 1; + TIMER_SET_PRESCALE_VALUE(psNuTmr->idx, pre); + *((uint32_t *)args) = clk / (pre + 1) ; + } + break; + + case HWTIMER_CTRL_STOP: + TIMER_Stop(psNuTmr->idx); + break; + + default: + ret = RT_EINVAL; + break; + } + + return -(ret); +} + +/** + * All UART interrupt service routine + */ +static void nu_timer_isr(int vector, void *param) +{ + nu_timer_t psNuTmr = NU_TIMER_DEVICE(param); + RT_ASSERT(psNuTmr != RT_NULL); + + if (TIMER_GetIntFlag(psNuTmr->idx)) + { + TIMER_ClearIntFlag(psNuTmr->idx); + rt_device_hwtimer_isr(&psNuTmr->parent); + } +} + +int rt_hw_timer_init(void) +{ + int i; + rt_err_t ret = RT_EOK; + for (i = (TIMER_START + 1); i < TIMER_CNT; i++) + { + nu_sys_ipclk_enable(nu_timer_arr[i].clkidx); + + nu_sys_ip_reset(nu_timer_arr[i].rstidx); + + /* Register Etimer information. */ + nu_timer_arr[i].parent.info = &nu_timer_info; + + /* Register Etimer operation. */ + nu_timer_arr[i].parent.ops = &nu_timer_ops; + + /* Register Etimer interrupt service routine. */ + rt_hw_interrupt_install(nu_timer_arr[i].irqn, nu_timer_isr, &nu_timer_arr[i], nu_timer_arr[i].name); + + /* Register RT hwtimer device. */ + ret = rt_device_hwtimer_register(&nu_timer_arr[i].parent, nu_timer_arr[i].name, &nu_timer_arr[i]); + RT_ASSERT(ret == RT_EOK); + } + return 0; +} +INIT_BOARD_EXPORT(rt_hw_timer_init); + +#endif //#if defined(BSP_USING_TIMER) && defined(RT_USING_HWTIMER) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_uart.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_uart.c new file mode 100644 index 0000000000000000000000000000000000000000..ca7a03e8e308dbe608e0342ff56a53541cbc74c1 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_uart.c @@ -0,0 +1,482 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-1-11 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_UART) + +#include +#include +#include "NuMicro.h" +#include +#include + + +/* Private define ---------------------------------------------------------------*/ +enum +{ + UART_START = -1, +#if defined(BSP_USING_UART0) + UART0_IDX, +#endif +#if defined(BSP_USING_UART1) + UART1_IDX, +#endif +#if defined(BSP_USING_UART2) + UART2_IDX, +#endif +#if defined(BSP_USING_UART3) + UART3_IDX, +#endif +#if defined(BSP_USING_UART4) + UART4_IDX, +#endif +#if defined(BSP_USING_UART5) + UART5_IDX, +#endif +#if defined(BSP_USING_UART6) + UART6_IDX, +#endif +#if defined(BSP_USING_UART7) + UART7_IDX, +#endif +#if defined(BSP_USING_UART8) + UART8_IDX, +#endif +#if defined(BSP_USING_UART9) + UART9_IDX, +#endif +#if defined(BSP_USING_UART10) + UART10_IDX, +#endif + UART_CNT +}; + +/* Private typedef --------------------------------------------------------------*/ +struct nu_uart +{ + rt_serial_t dev; + char *name; + UART_T *uart_base; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; +}; +typedef struct nu_uart *nu_uart_t; + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t nu_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg); +static rt_err_t nu_uart_control(struct rt_serial_device *serial, int cmd, void *arg); +static int nu_uart_send(struct rt_serial_device *serial, char c); +static int nu_uart_receive(struct rt_serial_device *serial); + +/* Public functions ------------------------------------------------------------*/ + +/* Private variables ------------------------------------------------------------*/ + +static const struct rt_uart_ops nu_uart_ops = +{ + .configure = nu_uart_configure, + .control = nu_uart_control, + .putc = nu_uart_send, + .getc = nu_uart_receive, + .dma_transmit = RT_NULL +}; + +static const struct serial_configure nu_uart_default_config = + RT_SERIAL_CONFIG_DEFAULT; + +static struct nu_uart nu_uart_arr [] = +{ +#if defined(BSP_USING_UART0) + { + .name = "uart0", + .uart_base = UART0, + .irqn = IRQ_UART0, + .rstidx = UART0RST, + .clkidx = UART0CKEN, + }, +#endif + +#if defined(BSP_USING_UART1) + { + .name = "uart1", + .uart_base = UART1, + .irqn = IRQ_UART1, + .rstidx = UART1RST, + .clkidx = UART1CKEN, + }, +#endif + +#if defined(BSP_USING_UART2) + { + .name = "uart2", + .uart_base = UART2, + .irqn = IRQ_UART2, + .rstidx = UART2RST, + .clkidx = UART2CKEN, + }, +#endif + +#if defined(BSP_USING_UART3) + { + .name = "uart3", + .uart_base = UART3, + .irqn = IRQ_UART3, + .rstidx = UART3RST, + .clkidx = UART3CKEN, + }, +#endif + +#if defined(BSP_USING_UART4) + { + .name = "uart4", + .uart_base = UART4, + .irqn = IRQ_UART4, + .rstidx = UART4RST, + .clkidx = UART4CKEN, + }, +#endif + +#if defined(BSP_USING_UART5) + { + .name = "uart5", + .uart_base = UART5, + .irqn = IRQ_UART5, + .rstidx = UART5RST, + .clkidx = UART5CKEN, + }, +#endif + +#if defined(BSP_USING_UART6) + { + .name = "uart6", + .uart_base = UART6, + .irqn = IRQ_UART6, + .rstidx = UART6RST, + .clkidx = UART6CKEN, + }, +#endif + +#if defined(BSP_USING_UART7) + { + .name = "uart7", + .uart_base = UART7, + .irqn = IRQ_UART7, + .rstidx = UART7RST, + .clkidx = UART7CKEN, + }, +#endif + +#if defined(BSP_USING_UART8) + { + .name = "uart8", + .uart_base = UART8, + .irqn = IRQ_UART8, + .rstidx = UART8RST, + .clkidx = UART8CKEN, + }, +#endif + +#if defined(BSP_USING_UART9) + { + .name = "uart9", + .uart_base = UART9, + .irqn = IRQ_UART9, + .rstidx = UART9RST, + .clkidx = UART9CKEN, + }, +#endif + +#if defined(BSP_USING_UART10) + { + .name = "uart10", + .uart_base = UARTA, + .irqn = IRQ_UART10, + .rstidx = UART10RST, + .clkidx = UART10CKEN, + }, +#endif + +}; /* uart nu_uart */ + +/** + * All UART interrupt service routine + */ +static void nu_uart_isr(int vector, void *param) +{ + /* Get base address of uart register */ + nu_uart_t serial = (nu_uart_t)param; + UART_T *uart_base = ((nu_uart_t)serial)->uart_base; + + /* Get interrupt event */ + uint32_t u32IntSts = uart_base->INTSTS; + uint32_t u32FIFOSts = uart_base->FIFOSTS; + + /* Handle RX event */ + if (u32IntSts & (UART_ISR_RDA_INT_Msk | UART_ISR_TOUT_INT_Msk)) + { + rt_hw_serial_isr(&serial->dev, RT_SERIAL_EVENT_RX_IND); + } + uart_base->INTSTS = u32IntSts; + uart_base->FIFOSTS = u32FIFOSts; +} + +/** + * Set RS-485 AUD mode + */ +void nu_uart_set_rs485aud(struct rt_serial_device *serial, rt_bool_t bRTSActiveLowLevel) +{ + UART_T *uart_base; + RT_ASSERT(serial != RT_NULL); + + /* Get base address of uart register */ + uart_base = ((nu_uart_t)serial)->uart_base; + + /* Set RTS as RS-485 phy direction controlling ping. */ + uart_base->FUNCSEL = UART_FUNCSEL_RS485; + + /* Set RS585 configuration */ + uart_base->ALTCTL &= ~(UART_ALT_CSR_RS485_NMM_Msk | UART_ALT_CSR_RS485_AAD_Msk | UART_ALT_CSR_RS485_AUD_Msk | UART_ALT_CSR_RS485_ADD_EN_Msk); + uart_base->ALTCTL |= UART_ALT_CSR_RS485_AUD_Msk; + + if (bRTSActiveLowLevel) + { + /* Set direction pin as active-high. */ + uart_base->MODEM &= ~UART_MCR_LEV_RTS_Msk; + } + else + { + /* Set direction pin as active-low. */ + uart_base->MODEM |= UART_MCR_LEV_RTS_Msk; + } + + rt_kprintf("Set %s to RS-485 AUD function mode. ActiveLowLevel-%s\n", ((nu_uart_t)serial)->name, bRTSActiveLowLevel ? "YES" : "NO"); +} + +/** + * Configure uart port + */ +static rt_err_t nu_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg) +{ + rt_err_t ret = RT_EOK; + uint32_t uart_word_len = 0; + uint32_t uart_stop_bit = 0; + uint32_t uart_parity = 0; + + /* Get base address of uart register */ + UART_T *uart_base = ((nu_uart_t)serial)->uart_base; + + /* Check baudrate */ + RT_ASSERT(cfg->baud_rate != 0); + + /* Check word len */ + switch (cfg->data_bits) + { + case DATA_BITS_5: + uart_word_len = UART_WORD_LEN_5; + break; + + case DATA_BITS_6: + uart_word_len = UART_WORD_LEN_6; + break; + + case DATA_BITS_7: + uart_word_len = UART_WORD_LEN_7; + break; + + case DATA_BITS_8: + uart_word_len = UART_WORD_LEN_8; + break; + + default: + rt_kprintf("Unsupported data length"); + ret = RT_EINVAL; + goto exit_nu_uart_configure; + } + + /* Check stop bit */ + switch (cfg->stop_bits) + { + case STOP_BITS_1: + uart_stop_bit = UART_STOP_BIT_1; + break; + + case STOP_BITS_2: + uart_stop_bit = UART_STOP_BIT_2; + break; + + default: + rt_kprintf("Unsupported stop bit"); + ret = RT_EINVAL; + goto exit_nu_uart_configure; + } + + /* Check parity */ + switch (cfg->parity) + { + case PARITY_NONE: + uart_parity = UART_PARITY_NONE; + break; + + case PARITY_ODD: + uart_parity = UART_PARITY_ODD; + break; + + case PARITY_EVEN: + uart_parity = UART_PARITY_EVEN; + break; + + default: + rt_kprintf("Unsupported parity"); + ret = RT_EINVAL; + goto exit_nu_uart_configure; + } + + nu_sys_ip_reset(((nu_uart_t)serial)->rstidx); + + /* Open Uart and set UART Baudrate */ + UART_Open(uart_base, cfg->baud_rate); + + /* Set line configuration. */ + UART_SetLineConfig(uart_base, 0, uart_word_len, uart_parity, uart_stop_bit); + + /* Enable interrupt. */ + rt_hw_interrupt_umask(((nu_uart_t)serial)->irqn); + +exit_nu_uart_configure: + + if (ret != RT_EOK) + UART_Close(uart_base); + + return -(ret); +} + +/** + * Uart interrupt control + */ +static rt_err_t nu_uart_control(struct rt_serial_device *serial, int cmd, void *arg) +{ + nu_uart_t psNuUart = (nu_uart_t)serial; + rt_err_t result = RT_EOK; + rt_uint32_t flag; + rt_ubase_t ctrl_arg = (rt_ubase_t)arg; + + RT_ASSERT(serial != RT_NULL); + + /* Get base address of uart register */ + UART_T *uart_base = psNuUart->uart_base; + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) /* Disable INT-RX */ + { + flag = UART_IER_RDA_IEN_Msk | UART_IER_RTO_IEN_Msk | UART_IER_TIME_OUT_EN_Msk; + UART_DISABLE_INT(uart_base, flag); + } + else if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) /* Disable DMA-RX */ + { + /* Disable Receive Line interrupt & Stop DMA RX transfer. */ + } + break; + + case RT_DEVICE_CTRL_SET_INT: + if (ctrl_arg == RT_DEVICE_FLAG_INT_RX) /* Enable INT-RX */ + { + flag = UART_IER_RDA_IEN_Msk | UART_IER_RTO_IEN_Msk | UART_IER_TIME_OUT_EN_Msk; + UART_ENABLE_INT(uart_base, flag); + } + break; + + case RT_DEVICE_CTRL_CLOSE: + /* Disable interrupt. */ + rt_hw_interrupt_mask(psNuUart->irqn); + + /* Close UART port */ + UART_Close(uart_base); + + break; + + default: + result = -RT_EINVAL; + break; + + } + return result; +} + +/** + * Uart put char + */ +static int nu_uart_send(struct rt_serial_device *serial, char c) +{ + RT_ASSERT(serial != RT_NULL); + + /* Get base address of uart register */ + UART_T *uart_base = ((nu_uart_t)serial)->uart_base; + + /* Waiting if TX-FIFO is full. */ + while (UART_IS_TX_FULL(uart_base)); + + /* Put char into TX-FIFO */ + UART_WRITE(uart_base, c); + + return 1; +} + +/** + * Uart get char + */ +static int nu_uart_receive(struct rt_serial_device *serial) +{ + RT_ASSERT(serial != RT_NULL); + + /* Get base address of uart register */ + UART_T *uart_base = ((nu_uart_t)serial)->uart_base; + + /* Return failure if RX-FIFO is empty. */ + if (UART_GET_RX_EMPTY(uart_base)) + { + return -1; + } + + /* Get char from RX-FIFO */ + return UART_READ(uart_base); +} + +/** + * Hardware UART Initialization + */ +rt_err_t rt_hw_uart_init(void) +{ + int i; + rt_uint32_t flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX; + rt_err_t ret = RT_EOK; + + for (i = (UART_START + 1); i < UART_CNT; i++) + { + nu_uart_arr[i].dev.ops = &nu_uart_ops; + nu_uart_arr[i].dev.config = nu_uart_default_config; + + rt_hw_interrupt_install(nu_uart_arr[i].irqn, nu_uart_isr, &nu_uart_arr[i], nu_uart_arr[i].name); + + nu_sys_ipclk_enable(nu_uart_arr[i].clkidx); + + ret = rt_hw_serial_register(&nu_uart_arr[i].dev, nu_uart_arr[i].name, flag, NULL); + RT_ASSERT(ret == RT_EOK); + } + + return ret; +} + +#endif //#if defined(BSP_USING_UART) diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_uart.h b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_uart.h new file mode 100644 index 0000000000000000000000000000000000000000..cda8e7fb8593a824e81e55f149b0794f31015371 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_uart.h @@ -0,0 +1,21 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-2-7 Wayne First version +* +******************************************************************************/ + +#ifndef __DRV_UART_H__ +#define __DRV_UART_H__ + +#include + +rt_err_t rt_hw_uart_init(void); +void nu_uart_set_rs485aud(struct rt_serial_device *serial, rt_bool_t bRTSActiveLowLevel); + +#endif /* __DRV_UART_H__ */ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_usbd.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_usbd.c new file mode 100644 index 0000000000000000000000000000000000000000..876c6d96c2bd9573ae9930d35ab454ed6a188471 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_usbd.c @@ -0,0 +1,932 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-03-16 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_USBD) + +#include +#include +#include +#include "NuMicro.h" +#include +#include "drv_sys.h" + +#define LOG_TAG "drv.usbd" +//#define DBG_ENABLE +#define DBG_SECTION_NAME "drv.usbd" +//#define DBG_LEVEL DBG_ERROR +#define DBG_COLOR +#include + +/* Private define ---------------------------------------------------------------*/ +#define ENABLE_FULL_SPEED_MODE_ONLY 0 /* 0: default hi-speed mode; 1: full-speed mode only */ + +/* Define EP maximum packet size */ + +#define CEP_MAX_PKT_SIZE 64 +#define CEP_OTHER_MAX_PKT_SIZE 64 + +#define EPA_MAX_PKT_SIZE 512 +#define EPA_OTHER_MAX_PKT_SIZE 64 + +#define EPB_MAX_PKT_SIZE 512 +#define EPB_OTHER_MAX_PKT_SIZE 64 + +#define EPC_MAX_PKT_SIZE 64 +#define EPC_OTHER_MAX_PKT_SIZE 64 + +#define EPD_MAX_PKT_SIZE 64 +#define EPD_OTHER_MAX_PKT_SIZE 64 + +#define EPE_MAX_PKT_SIZE 512 +#define EPE_OTHER_MAX_PKT_SIZE 64 + +#define EPF_MAX_PKT_SIZE 512 +#define EPF_OTHER_MAX_PKT_SIZE 64 + +#define EPG_MAX_PKT_SIZE 64 +#define EPG_OTHER_MAX_PKT_SIZE 64 + +#define EPH_MAX_PKT_SIZE 64 +#define EPH_OTHER_MAX_PKT_SIZE 64 + +#define EPI_MAX_PKT_SIZE 512 +#define EPI_OTHER_MAX_PKT_SIZE 64 + +#define EPJ_MAX_PKT_SIZE 512 +#define EPJ_OTHER_MAX_PKT_SIZE 64 + +#define EPK_MAX_PKT_SIZE 64 +#define EPK_OTHER_MAX_PKT_SIZE 64 + +#define EPL_MAX_PKT_SIZE 64 +#define EPL_OTHER_MAX_PKT_SIZE 64 + +#define CEP_BUF_BASE 0 +#define CEP_BUF_LEN CEP_MAX_PKT_SIZE + +#define EPA_BUF_BASE (CEP_BUF_BASE + CEP_BUF_LEN) +#define EPA_BUF_LEN EPA_MAX_PKT_SIZE + +#define EPB_BUF_BASE (EPA_BUF_BASE + EPA_BUF_LEN) +#define EPB_BUF_LEN EPB_MAX_PKT_SIZE + +#define EPC_BUF_BASE (EPB_BUF_BASE + EPB_BUF_LEN) +#define EPC_BUF_LEN EPC_MAX_PKT_SIZE + +#define EPD_BUF_BASE (EPC_BUF_BASE + EPC_BUF_LEN) +#define EPD_BUF_LEN EPD_MAX_PKT_SIZE + +#define EPE_BUF_BASE (EPD_BUF_BASE + EPD_BUF_LEN) +#define EPE_BUF_LEN EPE_MAX_PKT_SIZE + +#define EPF_BUF_BASE (EPE_BUF_BASE + EPE_BUF_LEN) +#define EPF_BUF_LEN EPF_MAX_PKT_SIZE + +#define EPG_BUF_BASE (EPF_BUF_BASE + EPF_BUF_LEN) +#define EPG_BUF_LEN EPG_MAX_PKT_SIZE + +#define EPH_BUF_BASE (EPG_BUF_BASE + EPG_BUF_LEN) +#define EPH_BUF_LEN EPH_MAX_PKT_SIZE + +#define EPI_BUF_BASE (EPH_BUF_BASE + EPH_BUF_LEN) +#define EPI_BUF_LEN EPI_MAX_PKT_SIZE + +#define EPJ_BUF_BASE (EPI_BUF_BASE + EPI_BUF_LEN) +#define EPJ_BUF_LEN EPJ_MAX_PKT_SIZE + +#define EPK_BUF_BASE (EPJ_BUF_BASE + EPJ_BUF_LEN) +#define EPK_BUF_LEN EPK_MAX_PKT_SIZE + +#define EPL_BUF_BASE (EPK_BUF_BASE + EPK_BUF_LEN) +#define EPL_BUF_LEN EPL_MAX_PKT_SIZE + + +#define EPADR_SW2HW(address) ((address & USB_EPNO_MASK) - 1) /* for non-control endpoint */ +#define EPADR_HW2SW(address) ((address & USB_EPNO_MASK) + 1) /* for non-control endpoint */ + +/* Private typedef --------------------------------------------------------------*/ +typedef struct _nu_usbd_t +{ + USBD_T *base; /* REG base */ + char *name; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + uint8_t address_tmp; /* Keep assigned address for flow control */ + uint8_t plugging_status; /* For debounce, 0: Unplug, 1: plug-in */ +} nu_usbd_t; + + +typedef struct +{ + + uint32_t u32BufferBase; + uint32_t u32BufferLength; + + uint32_t u32OtherMaxPktSize; + +} S_EP_CXT; + + +/* Private variables ------------------------------------------------------------*/ + +static nu_usbd_t nu_usbd = +{ + .base = USBD, + .name = "usbd", + .irqn = IRQ_USBD, + .rstidx = USBDRST, + .clkidx = USBDCKEN, + .address_tmp = 0, + .plugging_status = 0, +}; + +static struct udcd _rt_obj_udc; + +static S_EP_CXT _ep_cxt_pool[] = +{ + { EPA_BUF_BASE, EPA_BUF_LEN, EPA_OTHER_MAX_PKT_SIZE}, //EPA + { EPB_BUF_BASE, EPB_BUF_LEN, EPB_OTHER_MAX_PKT_SIZE}, //EPB + { EPC_BUF_BASE, EPC_BUF_LEN, EPC_OTHER_MAX_PKT_SIZE}, //EPC + { EPD_BUF_BASE, EPD_BUF_LEN, EPD_OTHER_MAX_PKT_SIZE}, //EPD + { EPE_BUF_BASE, EPE_BUF_LEN, EPE_OTHER_MAX_PKT_SIZE}, //EPE + { EPF_BUF_BASE, EPF_BUF_LEN, EPF_OTHER_MAX_PKT_SIZE}, //EPF + { EPG_BUF_BASE, EPG_BUF_LEN, EPG_OTHER_MAX_PKT_SIZE}, //EPG + { EPH_BUF_BASE, EPH_BUF_LEN, EPH_OTHER_MAX_PKT_SIZE}, //EPH + { EPI_BUF_BASE, EPI_BUF_LEN, EPI_OTHER_MAX_PKT_SIZE}, //EPI + { EPJ_BUF_BASE, EPJ_BUF_LEN, EPJ_OTHER_MAX_PKT_SIZE}, //EPJ + { EPK_BUF_BASE, EPK_BUF_LEN, EPK_OTHER_MAX_PKT_SIZE}, //EPK + { EPL_BUF_BASE, EPL_BUF_LEN, EPL_OTHER_MAX_PKT_SIZE} //EPL +}; + +static struct ep_id _ep_pool[] = +{ + {0x0, USB_EP_ATTR_CONTROL, USB_DIR_INOUT, CEP_MAX_PKT_SIZE, ID_ASSIGNED }, + + {EPADR_HW2SW(EPA), USB_EP_ATTR_BULK, USB_DIR_IN, EPA_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPB), USB_EP_ATTR_BULK, USB_DIR_OUT, EPB_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPC), USB_EP_ATTR_INT, USB_DIR_IN, EPC_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPD), USB_EP_ATTR_INT, USB_DIR_OUT, EPD_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPE), USB_EP_ATTR_BULK, USB_DIR_IN, EPE_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPF), USB_EP_ATTR_BULK, USB_DIR_OUT, EPF_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPG), USB_EP_ATTR_INT, USB_DIR_IN, EPG_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPH), USB_EP_ATTR_INT, USB_DIR_OUT, EPH_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPI), USB_EP_ATTR_BULK, USB_DIR_IN, EPE_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPJ), USB_EP_ATTR_BULK, USB_DIR_OUT, EPF_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPK), USB_EP_ATTR_INT, USB_DIR_IN, EPG_MAX_PKT_SIZE, ID_UNASSIGNED}, + {EPADR_HW2SW(EPL), USB_EP_ATTR_INT, USB_DIR_OUT, EPH_MAX_PKT_SIZE, ID_UNASSIGNED}, + + {0xFF, USB_EP_ATTR_TYPE_MASK, USB_DIR_MASK, 0, ID_ASSIGNED }, +}; + + +static void _nu_ep_partition_set(int isHighSpeed) +{ + int i; + + for (i = 0; i < USBD_MAX_EP; i++) + { + uint32_t u32NuEPTypeDef = 0x0; + uint32_t u32NuEPDirDef = 0x0; + + if (_ep_pool[i + 1].type == USB_EP_ATTR_BULK) + u32NuEPTypeDef = USB_EP_CFG_TYPE_BULK; + else if (_ep_pool[i + 1].type == USB_EP_ATTR_INT) + u32NuEPTypeDef = USB_EP_CFG_TYPE_INT; + else + continue; + + if (_ep_pool[i + 1].dir == USB_DIR_IN) + u32NuEPDirDef = USB_EP_CFG_DIR_IN; + else if (_ep_pool[i + 1].dir == USB_DIR_OUT) + u32NuEPDirDef = USB_EP_CFG_DIR_OUT; + else + continue; + + USBD_SetEpBufAddr(i, _ep_cxt_pool[i].u32BufferBase, _ep_cxt_pool[i].u32BufferLength); + if (isHighSpeed) + USBD_SET_MAX_PAYLOAD(i, _ep_cxt_pool[i].u32BufferLength); + else + USBD_SET_MAX_PAYLOAD(i, _ep_cxt_pool[i].u32OtherMaxPktSize); + + USBD_ConfigEp(i, EPADR_HW2SW(i), u32NuEPTypeDef, u32NuEPDirDef); + + if (u32NuEPDirDef == USB_EP_CFG_DIR_OUT) + USBD_ENABLE_EP_INT(i, USBD_EPINTEN_RXPKIEN_Msk); + + } //for + +} + +static void _nu_ep_partition(void) +{ + /* Configure USB controller */ + /* Enable USB BUS, CEP and EPA ~ EPH global interrupt */ + USBD_ENABLE_USB_INT(USBD_GINTEN_USBIE_Msk + | USBD_GINTEN_CEPIE_Msk + | USBD_GINTEN_EPAIE_Msk + | USBD_GINTEN_EPBIE_Msk + | USBD_GINTEN_EPCIE_Msk + | USBD_GINTEN_EPDIE_Msk + | USBD_GINTEN_EPEIE_Msk + | USBD_GINTEN_EPFIE_Msk + | USBD_GINTEN_EPGIE_Msk + | USBD_GINTEN_EPHIE_Msk + | USBD_GINTEN_EPIIE_Msk + | USBD_GINTEN_EPJIE_Msk + | USBD_GINTEN_EPKIE_Msk + | USBD_GINTEN_EPLIE_Msk); + + /* Enable BUS interrupt */ + USBD_ENABLE_BUS_INT(USBD_BUSINTEN_DMADONEIEN_Msk + | USBD_BUSINTEN_RESUMEIEN_Msk + | USBD_BUSINTEN_RSTIEN_Msk + | USBD_BUSINTEN_VBUSDETIEN_Msk); + /* Reset Address to 0 */ + USBD_SET_ADDR(0); + + /*****************************************************/ + /* Control endpoint */ + USBD_SetEpBufAddr(CEP, CEP_BUF_BASE, CEP_BUF_LEN); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk + | USBD_CEPINTEN_STSDONEIEN_Msk); + + _nu_ep_partition_set(1); +} + +static void NU_SetupStageCallback(nu_usbd_t *nu_udc) +{ + struct urequest setup_packet; + + /* Setup packet process */ + setup_packet.request_type = (uint8_t)(nu_udc->base->SETUP1_0 & 0xfful); + setup_packet.bRequest = (uint8_t)((nu_udc->base->SETUP1_0 >> 8) & 0xfful); + setup_packet.wValue = (uint16_t) nu_udc->base->SETUP3_2; + setup_packet.wIndex = (uint16_t) nu_udc->base->SETUP5_4; + setup_packet.wLength = (uint16_t) nu_udc->base->SETUP7_6; + + rt_usbd_ep0_setup_handler(&_rt_obj_udc, (struct urequest *)&setup_packet); +} + +__STATIC_INLINE void nu_udc_enable(void) +{ + USBD_ENABLE_USB(); +} + +__STATIC_INLINE void nu_udc_disable(void) +{ + int i; + + USBD_ENABLE_CEP_INT(0); + USBD_CLR_CEP_INT_FLAG(0xffff); + + USBD_SET_CEP_STATE(inpw(REG_USBD_CEPCTL) | USB_CEPCTL_FLUSH); + + for (i = 0; i < USBD_MAX_EP; i++) + USBD->EP[i].EPRSPCTL = USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_TOGGLE; + + USBD_DISABLE_USB(); +} + + +static rt_err_t _ep_set_stall(rt_uint8_t address) +{ + + if (address & USB_EPNO_MASK) + { + USBD_SetEpStall(EPADR_SW2HW(address)); + } + else + { + /* Not support. Reply STALL. */ + USBD_SET_CEP_STATE(USBD_CEPCTL_STALLEN_Msk); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPPKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk); + } + return RT_EOK; +} + +static rt_err_t _ep_clear_stall(rt_uint8_t address) +{ + if (address & USB_EPNO_MASK) + { + USBD_ClearEpStall(EPADR_SW2HW(address)); + } + + return RT_EOK; +} + + +static rt_err_t _set_address(rt_uint8_t address) +{ + if (0 != address) + { + nu_usbd.address_tmp = address; + } + + return RT_EOK; +} + +static rt_err_t _set_config(rt_uint8_t address) +{ + return RT_EOK; +} + +static rt_err_t _ep_enable(uep_t ep) +{ + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + USBD->EP[EPADR_SW2HW(ep->ep_desc->bEndpointAddress)].EPRSPCTL = USB_EP_RSPCTL_TOGGLE; + USBD->EP[EPADR_SW2HW(ep->ep_desc->bEndpointAddress)].EPCFG |= USB_EP_CFG_VALID; + + return RT_EOK; +} + +static rt_err_t _ep_disable(uep_t ep) +{ + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + USBD->EP[EPADR_SW2HW(ep->ep_desc->bEndpointAddress)].EPCFG &= ~USB_EP_CFG_VALID; + + return RT_EOK; +} + +static rt_err_t _ep0_send_status(void) +{ + /* Status Stage */ + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk + | USBD_CEPINTSTS_SETUPPKIF_Msk); + + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_STSDONEIEN_Msk); + + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + + return RT_EOK; +} + +__STATIC_INLINE void nu_buffer_cpy(rt_uint8_t address, void *buffer, rt_size_t size) +{ + rt_uint32_t i, cnt; + rt_uint32_t *_buf_word; + rt_uint8_t *_buf_byte; + + _buf_word = (rt_uint32_t *)buffer; + cnt = size >> 2; + _buf_byte = (rt_uint8_t *)((rt_uint8_t *)buffer + (cnt * 4)); + + if ((address & USB_EPNO_MASK)) //EPs + { + if (address & USB_DIR_IN) //IN + { + /* Non-control endpoint IN*/ + for (i = 0; i < cnt; i++) + { + USBD->EP[EPADR_SW2HW(address)].ep.EPDAT = _buf_word[i]; + } + + for (i = 0ul; i < (size % 4ul); i++) + USBD->EP[EPADR_SW2HW(address)].ep.EPDAT_BYTE = _buf_byte[i]; + } + else //OUT + { + for (i = 0; i < cnt; i++) + { + _buf_word[i] = USBD->EP[EPADR_SW2HW(address)].ep.EPDAT; + } + + for (i = 0ul; i < (size % 4ul); i++) + _buf_byte[i] = USBD->EP[EPADR_SW2HW(address)].ep.EPDAT_BYTE; + } + } + else //Control + { + if (address & USB_DIR_IN) //IN + { + for (i = 0; i < cnt; i++) + { + USBD->cep.CEPDAT = _buf_word[i]; + } + + for (i = 0ul; i < (size % 4ul); i++) + USBD->cep.CEPDAT_BYTE = _buf_byte[i]; + + } + else //OUT + { + for (i = 0; i < cnt; i++) + { + _buf_word[i] = USBD->cep.CEPDAT; + } + + for (i = 0ul; i < (size % 4ul); i++) + _buf_byte[i] = USBD->cep.CEPDAT_BYTE; + } + } +} + +static rt_size_t _ep_read(rt_uint8_t address, void *buffer) +{ + rt_size_t size = 0; + + RT_ASSERT(!(address & USB_DIR_IN)); + + if ((address & USB_EPNO_MASK)) + { + RT_ASSERT(buffer != RT_NULL); + size = USBD->EP[EPADR_SW2HW(address)].EPDATCNT & 0xffff; + nu_buffer_cpy(address, buffer, size); + } + else //control transfer + { + + size = USBD->CEPRXCNT & 0xffff; + if (size) + { + RT_ASSERT(_rt_obj_udc.stage == STAGE_DOUT); + nu_buffer_cpy(address, buffer, size); + } + + _ep0_send_status(); + } + + return size; +} + +static rt_size_t _ep_read_prepare(rt_uint8_t address, void *buffer, rt_size_t size) +{ + RT_ASSERT(!(address & USB_DIR_IN)); + + if ((address & USB_EPNO_MASK)) + { + USBD_ENABLE_EP_INT(EPADR_SW2HW(address), + USBD_EPINTEN_RXPKIEN_Msk); + } + else //control transfer + { + if (size) + { + RT_ASSERT(_rt_obj_udc.stage == STAGE_DOUT); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_OUTTKIEN_Msk); + } + else + { + + RT_ASSERT(_rt_obj_udc.stage == STAGE_STATUS_OUT); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPPKIF_Msk + | USBD_CEPINTSTS_STSDONEIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk + | USBD_CEPINTEN_STSDONEIEN_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + } + + } + + return size; +} + +static rt_size_t _ep_write(rt_uint8_t address, void *buffer, rt_size_t size) +{ + + RT_ASSERT((address & USB_DIR_IN)); + + if (!(address & USB_EPNO_MASK)) //control transfer + { + if (size) + { + nu_buffer_cpy(address, buffer, size); + USBD_START_CEP_IN(size); + } + else//zero length + { + USBD_SET_CEP_STATE(USB_CEPCTL_ZEROLEN); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk + | USBD_CEPINTSTS_SETUPPKIF_Msk); + + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk + | USBD_CEPINTEN_STSDONEIEN_Msk); + } + + if (_rt_obj_udc.stage == STAGE_DIN) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_TXPKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_TXPKIEN_Msk); + } + else if (_rt_obj_udc.stage == STAGE_DOUT) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_RXPKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_RXPKIEN_Msk); + } + } + else + { + /* Non-control endpoint IN*/ + nu_buffer_cpy(address, buffer, size); + USBD->EP[EPADR_SW2HW(address)].EPRSPCTL = USB_EP_RSPCTL_SHORTTXEN; // packet end + USBD->EP[EPADR_SW2HW(address)].EPTXCNT = size; + + if ((USBD->EP[EPADR_SW2HW(address)].EPCFG & USBD_EPCFG_EPTYPE_Msk) == USB_EP_CFG_TYPE_INT) + { + USBD_ENABLE_EP_INT(EPADR_SW2HW(address), USBD_EPINTEN_INTKIEN_Msk); //for interrupt transfer timing + } + else + { + USBD_ENABLE_EP_INT(EPADR_SW2HW(address), USBD_EPINTEN_TXPKIEN_Msk); //for bulk transfer timing + } + } + + return size; +} + +static rt_err_t _suspend(void) +{ + return RT_EOK; +} + +static rt_err_t _wakeup(void) +{ + return RT_EOK; +} + +static void nu_usbd_isr(int vector, void *param) +{ + __IO rt_uint32_t IrqStL, IrqSt; + int i; + int IrqStAllEP; + + /* Igrone event if role is USBH*/ + if (nu_sys_usb0_role() != USB0_ID_DEVICE) return; + + IrqStL = USBD->GINTSTS & USBD->GINTEN; /* get interrupt status */ + + if (!IrqStL) return; + + /* USB interrupt */ + if (IrqStL & USBD_GINTSTS_USBIF_Msk) + { + IrqSt = USBD->BUSINTSTS & USBD->BUSINTEN; + + if (IrqSt & USBD_BUSINTSTS_SOFIF_Msk) + { + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_SOFIF_Msk); + rt_usbd_sof_handler(&_rt_obj_udc); + } + if (IrqSt & USBD_BUSINTSTS_RSTIF_Msk) + { + /* Reset USB device address */ + USBD_SET_ADDR(0ul); + + USBD_ResetDMA(); + for (i = 0; i < USBD_MAX_EP; i++) + USBD->EP[i].EPRSPCTL = USBD_EPRSPCTL_FLUSH_Msk; + + if (USBD->OPER & 0x04) /* high speed */ + { + LOG_I("-High Speed-"); + _nu_ep_partition_set(1); + } + else /* full speed */ + { + LOG_I("-Full Speed-"); + _nu_ep_partition_set(0); + } + + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk); + USBD_ENABLE_BUS_INT(USBD_BUSINTEN_RSTIEN_Msk + | USBD_BUSINTEN_RESUMEIEN_Msk + | USBD_BUSINTEN_SUSPENDIEN_Msk + | USBD_BUSINTEN_VBUSDETIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_RSTIF_Msk); + USBD_CLR_CEP_INT_FLAG(0x1ffc); + + for (i = 0ul; i < USBD_MAX_EP; i++) + { + if ((USBD->EP[i].EPCFG & 0x1ul) == 0x1ul) + { + USBD->EP[i].EPRSPCTL = USB_EP_RSPCTL_TOGGLE; + } + } + rt_usbd_reset_handler(&_rt_obj_udc); + USBD_ENABLE_USB(); + } + + if (IrqSt & USBD_BUSINTSTS_RESUMEIF_Msk) + { + LOG_I("-Resume-"); + USBD_ENABLE_BUS_INT(USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_SUSPENDIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_RESUMEIF_Msk); + } + + if (IrqSt & USBD_BUSINTSTS_SUSPENDIF_Msk) + { + LOG_I("-Suspend-"); + USBD_ENABLE_BUS_INT(USBD_BUSINTEN_RSTIEN_Msk | USBD_BUSINTEN_RESUMEIEN_Msk | USBD_BUSINTEN_VBUSDETIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_SUSPENDIF_Msk); + } + + if (IrqSt & USBD_BUSINTSTS_HISPDIF_Msk) + { + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk); + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_HISPDIF_Msk); + } + + if (IrqSt & USBD_BUSINTSTS_DMADONEIF_Msk) + { + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_DMADONEIF_Msk); + + if (!(USBD->DMACTL & USBD_DMACTL_DMARD_Msk)) + { + USBD_ENABLE_EP_INT(EPD, USBD_EPINTEN_RXPKIEN_Msk); + } + } + + if (IrqSt & USBD_BUSINTSTS_PHYCLKVLDIF_Msk) + { + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_PHYCLKVLDIF_Msk); + } + + if (IrqSt & USBD_BUSINTSTS_VBUSDETIF_Msk) + { + if (USBD_IS_ATTACHED()) + { + if (!nu_usbd.plugging_status) + { + LOG_I("PLUG IN"); + /* USB Plug In */ + nu_udc_enable(); + rt_usbd_connect_handler(&_rt_obj_udc); + nu_usbd.plugging_status = 1; + } + } + else + { + if (nu_usbd.plugging_status) + { + LOG_I("Un-Plug"); + /* USB Un-plug */ + nu_udc_disable(); + rt_usbd_disconnect_handler(&_rt_obj_udc); + nu_usbd.plugging_status = 0; + } + } + USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_VBUSDETIF_Msk); + } + } //if (IrqStL & USBD_GINTSTS_USBIF_Msk) + + /* Control Transfer */ + if (IrqStL & USBD_GINTSTS_CEPIF_Msk) + { + IrqSt = USBD->CEPINTSTS & USBD->CEPINTEN; + + if (IrqSt & USBD_CEPINTSTS_SETUPTKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPTKIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_SETUPPKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPPKIF_Msk); + NU_SetupStageCallback(&nu_usbd); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk + | USBD_CEPINTSTS_RXPKIF_Msk + | USBD_CEPINTSTS_STSDONEIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_OUTTKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_OUTTKIF_Msk); + rt_usbd_ep0_out_handler(&_rt_obj_udc, 0); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_RXPKIEN_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_INTKIF_Msk) + { + USBD_ENABLE_CEP_INT(0); + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_INTKIF_Msk); + rt_usbd_ep0_in_handler(&_rt_obj_udc); + return; + } + + if (IrqSt & USBD_CEPINTSTS_PINGIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_PINGIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_TXPKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_TXPKIF_Msk + | USBD_CEPINTSTS_SETUPPKIF_Msk + | USBD_CEPINTSTS_STSDONEIF_Msk); + + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_INTKIEN_Msk + | USBD_CEPINTEN_SETUPPKIEN_Msk + | USBD_CEPINTEN_STSDONEIEN_Msk); + + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + return; + } + + if (IrqSt & USBD_CEPINTSTS_RXPKIF_Msk) + { + + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_SETUPPKIF_Msk + | USBD_CEPINTSTS_STSDONEIF_Msk + | USBD_CEPINTSTS_RXPKIF_Msk); + USBD_SET_CEP_STATE(USB_CEPCTL_NAKCLR); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk + | USBD_CEPINTEN_STSDONEIEN_Msk + | USBD_CEPINTEN_RXPKIEN_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_NAKIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_NAKIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_STALLIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STALLIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_ERRIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_ERRIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_STSDONEIF_Msk) + { + + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_STSDONEIF_Msk | USBD_CEPINTSTS_SETUPPKIF_Msk); + USBD_ENABLE_CEP_INT(USBD_CEPINTEN_SETUPPKIEN_Msk); + + if ((USBD_GET_ADDR() == 0) + && ((uint8_t)((nu_usbd.base->SETUP1_0 >> 8) & 0xfful) == SET_ADDRESS)) + { + USBD_SET_ADDR(nu_usbd.address_tmp); + LOG_I("SET ADDR: 0x%02x", nu_usbd.address_tmp); + nu_usbd.address_tmp = 0; + + } + return; + } + + if (IrqSt & USBD_CEPINTSTS_BUFFULLIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_BUFFULLIF_Msk); + return; + } + + if (IrqSt & USBD_CEPINTSTS_BUFEMPTYIF_Msk) + { + USBD_CLR_CEP_INT_FLAG(USBD_CEPINTSTS_BUFEMPTYIF_Msk); + return; + } + + } //if (IrqStL & USBD_GINTSTS_CEPIF_Msk) + + // For End-points + IrqStAllEP = (IrqStL >> USBD_GINTSTS_EPAIF_Pos) & ((1 << USBD_MAX_EP) - 1); + + // Find the position of first '1' in allch_sts. + while ((i = nu_ctz(IrqStAllEP)) != 32) + { + IrqSt = USBD->EP[i].EPINTSTS & USBD->EP[i].EPINTEN; + + if (_ep_pool[i + 1].dir == USB_DIR_IN) + USBD_ENABLE_EP_INT(i, 0); + + USBD_CLR_EP_INT_FLAG(i, IrqSt); + + rt_usbd_ep_in_handler(&_rt_obj_udc, _ep_pool[i + 1].dir | EPADR_HW2SW(i), 0); + + IrqStAllEP &= ~(1 << i); + } +} + +static rt_err_t _init(rt_device_t device) +{ + nu_sys_ipclk_enable(nu_usbd.clkidx); + + nu_sys_ip_reset(nu_usbd.rstidx); + + rt_hw_us_delay(1000); + + /* USBD Open */ + USBD_ENABLE_USB(); + + while (1) + { + USBD->EP[EPA].EPMPS = 0x20ul; + if (USBD->EP[EPA].EPMPS == 0x20ul) + { + break; + } + } + + /* Force SE0 */ + USBD_SET_SE0(); + + _nu_ep_partition(); + +#if ENABLE_FULL_SPEED_MODE_ONLY + USBD->OPER &= ~USBD_OPER_HISPDEN_Msk; +#else + USBD->OPER |= USBD_OPER_HISPDEN_Msk; +#endif + + /* Install USBD interrupt */ + rt_hw_interrupt_install(nu_usbd.irqn, nu_usbd_isr, &nu_usbd, nu_usbd.name); + rt_hw_interrupt_set_priority(nu_usbd.irqn, IRQ_LEVEL_1); + + /* Enable USBD interrupt */ + rt_hw_interrupt_umask(nu_usbd.irqn); + + /* Start transaction */ + USBD_CLR_SE0(); + + /* Get currect cable status */ + nu_usbd.plugging_status = USBD_IS_ATTACHED() >> USBD_PHYCTL_VBUSDET_Pos; + + return RT_EOK; +} + +const static struct udcd_ops _udc_ops = +{ + _set_address, + _set_config, + _ep_set_stall, + _ep_clear_stall, + _ep_enable, + _ep_disable, + _ep_read_prepare, + _ep_read, + _ep_write, + _ep0_send_status, + _suspend, + _wakeup, +}; + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops _ops = +{ + _init, + RT_NULL, + RT_NULL, + RT_NULL, + RT_NULL, + RT_NULL, +}; +#endif + +int nu_usbd_register(void) +{ + rt_err_t result = RT_EOK; + + rt_memset((void *)&_rt_obj_udc, 0, sizeof(struct udcd)); + _rt_obj_udc.parent.type = RT_Device_Class_USBDevice; + +#ifdef RT_USING_DEVICE_OPS + _rt_obj_udc.parent.ops = &_ops; +#else + _rt_obj_udc.parent.init = _init; +#endif + + _rt_obj_udc.parent.user_data = &nu_usbd; + _rt_obj_udc.ops = &_udc_ops; + + /* Register endpoint information */ + _rt_obj_udc.ep_pool = _ep_pool; + _rt_obj_udc.ep0.id = &_ep_pool[0]; + +#if ENABLE_FULL_SPEED_MODE_ONLY + _rt_obj_udc.device_is_hs = RT_FALSE; /* Enable Full-speed only */ +#else + _rt_obj_udc.device_is_hs = RT_TRUE; /* Support Hi-Speed */ +#endif + + result = rt_device_register((rt_device_t)&_rt_obj_udc, nu_usbd.name, 0); + RT_ASSERT(result == RT_EOK); + + return rt_usb_device_init(); +} +INIT_DEVICE_EXPORT(nu_usbd_register); +#endif diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_usbhost.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_usbhost.c new file mode 100644 index 0000000000000000000000000000000000000000..cd6f837c88838f5be3641d39233646e8e930b41e --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_usbhost.c @@ -0,0 +1,893 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-30 Wayne First version +* +******************************************************************************/ +#include + +#if defined(BSP_USING_USBH) + +#include +#include +#include "NuMicro.h" + +#include "usb.h" +#include "usbh_lib.h" + +#if !defined(NU_USBHOST_HUB_POLLING_INTERVAL) + #define NU_USBHOST_HUB_POLLING_INTERVAL (100) +#endif + +#define NU_MAX_USBH_PORT 2 //2* USB2.0 port +#define NU_MAX_USBH_PIPE 16 +#define NU_USBH_THREAD_STACK_SIZE 2048 + +#define NU_MAX_USBH_HUB_PORT_DEV USB_HUB_PORT_NUM + +/* Private typedef --------------------------------------------------------------*/ +typedef struct nu_port_dev +{ + rt_bool_t bRHParent; + UDEV_T *pUDev; + EP_INFO_T *apsEPInfo[NU_MAX_USBH_PIPE]; + struct urequest asSetupReq[NU_MAX_USBH_PIPE]; + struct rt_completion utr_completion; + int port_num; + rt_bool_t bEnumDone; +#if defined(BSP_USING_MMU) + void *asPipePktBuf[NU_MAX_USBH_PIPE]; +#endif +} S_NU_PORT_DEV; + + +typedef struct nu_port_ctrl +{ + S_NU_PORT_DEV sRHPortDev; + S_NU_PORT_DEV asHubPortDev[NU_MAX_USBH_HUB_PORT_DEV]; +} S_NU_RH_PORT_CTRL; + + +struct nu_usbh_dev +{ + struct uhcd uhcd; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + rt_thread_t polling_thread; + S_NU_RH_PORT_CTRL asPortCtrl[NU_MAX_USBH_PORT]; +}; + +/* Private variables ------------------------------------------------------------*/ +static struct nu_usbh_dev s_sUSBHDev = +{ + .rstidx = USBHRST, + .clkidx = USBHCKEN, +}; + +static S_NU_RH_PORT_CTRL * +GetRHPortControlFromPipe( + upipe_t pipe) +{ + uinst_t inst; + int port; + if (pipe->inst->parent_hub->is_roothub) + { + //case: device ---> root hub + inst = pipe->inst; + port = inst->port; + } + else + { + //case: device ---> hub ---> root hub + inst = pipe->inst->parent_hub->self; + port = inst->port; + } + + if (port > NU_MAX_USBH_PORT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: port index over NU_MAX_USBH_PORT\n")); + return RT_NULL; + } + + return &s_sUSBHDev.asPortCtrl[port - 1];; +} + +static S_NU_PORT_DEV * +GetPortDevFromPipe( + upipe_t pipe) +{ + S_NU_RH_PORT_CTRL *psRHPortCtrl = GetRHPortControlFromPipe(pipe); + int i; + + if (psRHPortCtrl == RT_NULL) + return RT_NULL; + + if (pipe->inst->parent_hub->is_roothub) + { + //case: device ---> root hub + return &psRHPortCtrl->sRHPortDev; + } + + //case: device ---> hub ---> root hub + for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++) + { + if (psRHPortCtrl->asHubPortDev[i].port_num == pipe->inst->port) + break; + } + + if (i >= NU_MAX_USBH_HUB_PORT_DEV) + return RT_NULL; + + return &psRHPortCtrl->asHubPortDev[i]; +} + +static rt_err_t nu_reset_port(rt_uint8_t port) +{ + S_NU_RH_PORT_CTRL *psPortCtrl; + + if (port > NU_MAX_USBH_PORT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: port index over NU_MAX_USBH_PORT\n", __func__)); + return RT_EIO; + } + + psPortCtrl = &s_sUSBHDev.asPortCtrl[port - 1]; + if (psPortCtrl->sRHPortDev.pUDev == NULL) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__)); + return RT_EIO; + } + + usbh_reset_port(psPortCtrl->sRHPortDev.pUDev); + + return RT_EOK; +} + +static EP_INFO_T *GetFreePipe( + S_NU_RH_PORT_CTRL *psPortCtrl, + S_NU_PORT_DEV *psPortDev, + rt_uint8_t *pu8PipeIndex) +{ + if (psPortCtrl != NULL) + { + int i; + /* Find free Pipe */ + for (i = 0; i < NU_MAX_USBH_PIPE; i ++) + { + if (psPortDev->apsEPInfo[i] == NULL) + break; + } + + if (i < NU_MAX_USBH_PIPE) + { + EP_INFO_T *psEPInfo = rt_malloc(sizeof(EP_INFO_T)); + if (psEPInfo != RT_NULL) + { + psPortDev->apsEPInfo[i] = psEPInfo; + *pu8PipeIndex = i; + return psEPInfo; + } + } + } + return RT_NULL; +} + +static void FreePipe( + S_NU_RH_PORT_CTRL *psPortCtrl, + S_NU_PORT_DEV *psPortDev, + rt_uint8_t u8PipeIndex) +{ + if ((psPortCtrl != RT_NULL) && + (u8PipeIndex < NU_MAX_USBH_PIPE) && + (psPortDev->apsEPInfo[u8PipeIndex] != RT_NULL)) + { + rt_free(psPortDev->apsEPInfo[u8PipeIndex]); + psPortDev->apsEPInfo[u8PipeIndex] = RT_NULL; + } +} + +static S_NU_PORT_DEV * +AllocateNewUDev( + S_NU_RH_PORT_CTRL *psRHPortCtrl) +{ + if (psRHPortCtrl != RT_NULL) + { + int i; + /* Find free Dev */ + for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++) + { + if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL) + break; + } + + if (i < NU_MAX_USBH_HUB_PORT_DEV) + { + psRHPortCtrl->asHubPortDev[i].pUDev = alloc_device(); + if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL) + { + return RT_NULL; + } + else + { + return &psRHPortCtrl->asHubPortDev[i]; + } + } + } + return RT_NULL; +} + +static rt_err_t nu_open_pipe(upipe_t pipe) +{ + S_NU_RH_PORT_CTRL *psPortCtrl; + S_NU_PORT_DEV *psPortDev; + + psPortCtrl = GetRHPortControlFromPipe(pipe); + if (psPortCtrl == RT_NULL) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: RHPort not found\n", __func__)); + goto exit_nu_open_pipe; + } + + if (psPortCtrl->sRHPortDev.pUDev == NULL) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__)); + goto exit_nu_open_pipe; + } + + psPortDev = GetPortDevFromPipe(pipe); + + if ((psPortDev == NULL) || (psPortDev->pUDev == NULL)) + { + //allocate new dev for hub device + psPortDev = AllocateNewUDev(psPortCtrl); + + if (psPortDev == RT_NULL) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev allocate failed\n")); + goto exit_nu_open_pipe; + } + + if (pipe->inst->speed) + { + psPortDev->pUDev->speed = SPEED_FULL; + } + else + { + psPortDev->pUDev->speed = SPEED_HIGH; + } + + psPortDev->pUDev->parent = NULL; + psPortDev->pUDev->hc_driver = psPortCtrl->sRHPortDev.pUDev->hc_driver; + psPortDev->port_num = pipe->inst->port; + psPortDev->pUDev->port_num = pipe->inst->port; + psPortDev->bEnumDone = FALSE; + } + + //For ep0 control transfer + if ((pipe->ep.bEndpointAddress & 0x7F) == 0) + { + pipe->pipe_index = 0; + } + else + { + int pksz; + EP_INFO_T *psEPInfo = GetFreePipe(psPortCtrl, psPortDev, &pipe->pipe_index); + if (psEPInfo == RT_NULL) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: get free pipe failed\n", __func__)); + goto exit_nu_open_pipe; + } + + psEPInfo->bEndpointAddress = pipe->ep.bEndpointAddress; + psEPInfo->bmAttributes = pipe->ep.bmAttributes; + + pksz = pipe->ep.wMaxPacketSize; + pksz = (pksz & 0x07ff) * (1 + ((pksz >> 11) & 3)); + psEPInfo->wMaxPacketSize = pksz; + + psEPInfo->bInterval = pipe->ep.bInterval; + psEPInfo->hw_pipe = NULL; + psEPInfo->bToggle = 0; + } + +#if defined(BSP_USING_MMU) + if (!psPortDev->asPipePktBuf[pipe->pipe_index]) + { + psPortDev->asPipePktBuf[pipe->pipe_index] = rt_malloc_align(512ul, CACHE_LINE_SIZE); + RT_ASSERT(psPortDev->asPipePktBuf[pipe->pipe_index] != RT_NULL); + } +#endif + + return RT_EOK; + +exit_nu_open_pipe: + + return -RT_ERROR; +} + +static rt_err_t nu_close_pipe(upipe_t pipe) +{ + S_NU_RH_PORT_CTRL *psPortCtrl; + S_NU_PORT_DEV *psPortDev; + + psPortCtrl = GetRHPortControlFromPipe(pipe); + if (psPortCtrl == RT_NULL) + { + return RT_EIO; + } + + psPortDev = GetPortDevFromPipe(pipe); + + //For ep0 control transfer + if ((pipe->ep.bEndpointAddress & 0x7F) == 0) + { + if ((psPortDev) && (psPortDev->bRHParent == FALSE) && (psPortDev->bEnumDone == TRUE)) + { + if (psPortDev->pUDev) + { + int i; + for (i = 0; i < NU_MAX_USBH_PIPE; i++) + { + if (psPortDev->apsEPInfo[i] != NULL) + { + usbh_quit_xfer(psPortDev->pUDev, psPortDev->apsEPInfo[i]); + } + } + + free_device(psPortDev->pUDev); + psPortDev->pUDev = NULL; + } + } + } + + if (psPortDev != NULL) + { +#if defined(BSP_USING_MMU) + if (psPortDev->asPipePktBuf[pipe->pipe_index]) + { + rt_free_align(psPortDev->asPipePktBuf[pipe->pipe_index]); + psPortDev->asPipePktBuf[pipe->pipe_index] = RT_NULL; + } +#endif + + FreePipe(psPortCtrl, psPortDev, pipe->pipe_index); + } + return RT_EOK; +} + +static int nu_ctrl_xfer( + S_NU_PORT_DEV *psPortDev, + struct urequest *psSetup, + void *buffer, + int timeouts) +{ + uint32_t xfer_len = 0; + int ret; + + ret = usbh_ctrl_xfer(psPortDev->pUDev, psSetup->request_type, psSetup->bRequest, psSetup->wValue, psSetup->wIndex, psSetup->wLength, buffer, &xfer_len, timeouts * 10); + if (ret < 0) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer failed %d\n", ret)); + return ret; + } + + if (xfer_len != psSetup->wLength) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer length %d %d\n", psSetup->wLength, xfer_len)); + } + + if ((psSetup->bRequest == USB_REQ_SET_ADDRESS) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV)) + psPortDev->pUDev->dev_num = psSetup->wValue; + + if ((psSetup->bRequest == USB_REQ_SET_CONFIGURATION) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV)) + { + psPortDev->pUDev->cur_conf = psSetup->wValue; + psPortDev->bEnumDone = TRUE; + } + + return xfer_len; +} + +static int nu_bulk_xfer( + S_NU_PORT_DEV *psPortDev, + UTR_T *psUTR, + int timeouts) +{ + int ret; + + ret = usbh_bulk_xfer(psUTR); + + if (ret < 0) + return ret; + + //wait transfer done + rt_completion_wait(&(psPortDev->utr_completion), timeouts); + return 0; +} + +static int nu_int_xfer( + upipe_t pipe, + S_NU_PORT_DEV *psPortDev, + UTR_T *psUTR, + int timeouts) +{ + int ret; + int retry = 3; + + while (retry > 0) + { + ret = usbh_int_xfer(psUTR); + if (ret == 0) + break; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_int_xfer ERROR: failed to submit interrupt request\n")); + rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1); + retry --; + } + + if (ret < 0) + return ret; + + return 0; +} + +static void xfer_done_cb(UTR_T *psUTR) +{ + S_NU_PORT_DEV *psPortDev = (S_NU_PORT_DEV *)psUTR->context; + + //transfer done, signal utr_completion + rt_completion_done(&(psPortDev->utr_completion)); +} + +static void int_xfer_done_cb(UTR_T *psUTR) +{ + upipe_t pipe = (upipe_t)psUTR->context; + + if (psUTR->status != 0) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("Interrupt xfer failed %d\n", psUTR->status)); + goto exit_int_xfer_done_cb; + } + + if (pipe->callback != RT_NULL) + { + struct uhost_msg msg; + msg.type = USB_MSG_CALLBACK; + msg.content.cb.function = pipe->callback; + msg.content.cb.context = pipe; + rt_usbh_event_signal(&msg); + } + +exit_int_xfer_done_cb: + + free_utr(psUTR); +} + +static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts) +{ + S_NU_RH_PORT_CTRL *psPortCtrl; + S_NU_PORT_DEV *psPortDev; + UTR_T *psUTR = NULL; + int i32XferLen = -1; + + void *buffer_nonch = buffer; + + psPortCtrl = GetRHPortControlFromPipe(pipe); + if (psPortCtrl == RT_NULL) + { + goto exit_nu_pipe_xfer; + } + + psPortDev = GetPortDevFromPipe(pipe); + if (psPortDev->pUDev == NULL) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: udev not found\n")); + goto exit_nu_pipe_xfer; + } + +#if defined(BSP_USING_MMU) + if (buffer_nonch && nbytes) + { + buffer_nonch = psPortDev->asPipePktBuf[pipe->pipe_index]; + rt_memcpy(buffer_nonch, buffer, nbytes); + mmu_clean_invalidated_dcache((uint32_t)buffer_nonch, nbytes); + } +#endif + + //ctrl xfer + if (pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL) + { + int ret; + if (token == USBH_PID_SETUP) + { + struct urequest *psSetup = (struct urequest *)buffer_nonch; + RT_ASSERT(buffer_nonch != RT_NULL); + + /* Read data from USB device. */ + if (psSetup->request_type & USB_REQ_TYPE_DIR_IN) + { + //Store setup request + rt_memcpy(&psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], psSetup, sizeof(struct urequest)); + } + else + { + /* Write data to USB device. */ + //Trigger USBHostLib Ctril_Xfer + ret = nu_ctrl_xfer(psPortDev, psSetup, NULL, timeouts); + if (ret != psSetup->wLength) + goto exit_nu_pipe_xfer; + } + } + else + { + //token == USBH_PID_DATA + if (buffer_nonch && ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)) + { + /* Read data from USB device. */ + //Trigger USBHostLib Ctril_Xfer + ret = nu_ctrl_xfer(psPortDev, &psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], buffer_nonch, timeouts); + if (ret != nbytes) + goto exit_nu_pipe_xfer; + } + else + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("%d == USBH_PID_DATA, nil buf-%d \n", token, nbytes)); + } + + } //else + i32XferLen = nbytes; + goto exit_nu_pipe_xfer; + } // if ( pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL ) + else + { + + psUTR = alloc_utr(psPortDev->pUDev); + + if (!psUTR) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: unable alloc UTR\n")); + goto exit_nu_pipe_xfer; + } + + psUTR->ep = psPortDev->apsEPInfo[pipe->pipe_index]; + psUTR->buff = buffer_nonch; + psUTR->data_len = nbytes; + psUTR->xfer_len = 0; + psUTR->func = xfer_done_cb; + psUTR->context = psPortDev; + psUTR->bIsTransferDone = 0; + psUTR->status = 0; + + //others xfer + rt_completion_init(&(psPortDev->utr_completion)); + + if (pipe->ep.bmAttributes == USB_EP_ATTR_BULK) + { + if (nu_bulk_xfer(psPortDev, psUTR, timeouts) < 0) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: bulk transfer failed\n")); + goto exit_nu_pipe_xfer; + } + } + else if (pipe->ep.bmAttributes == USB_EP_ATTR_INT) + { + psUTR->func = int_xfer_done_cb; + psUTR->context = pipe; + + if (nu_int_xfer(pipe, psPortDev, psUTR, timeouts) < 0) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: int transfer failed\n")); + //goto exit_nu_pipe_xfer; + } + else + { + i32XferLen = nbytes; + } + return i32XferLen; + } + else if (pipe->ep.bmAttributes == USB_EP_ATTR_ISOC) + { + //TODO: ISO transfer + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: isoc transfer not support\n")); + goto exit_nu_pipe_xfer; + } + + } //else + + if (psUTR->bIsTransferDone == 0) + { + //Timeout + RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: timeout\n")); + pipe->status = UPIPE_STATUS_ERROR; + usbh_quit_utr(psUTR); + } + else + { + // Transfer Done. Get status + if (psUTR->status == 0) + { + pipe->status = UPIPE_STATUS_OK; + } + else if (psUTR->status == USBH_ERR_STALL) + { + pipe->status = UPIPE_STATUS_STALL; + } + else + { + pipe->status = UPIPE_STATUS_ERROR; + } + } + + i32XferLen = psUTR->xfer_len; + + //Call callback + if (pipe->callback != RT_NULL) + { + struct uhost_msg msg; + msg.type = USB_MSG_CALLBACK; + msg.content.cb.function = pipe->callback; + msg.content.cb.context = pipe->user_data; + rt_usbh_event_signal(&msg); + } + + if (pipe->status != UPIPE_STATUS_OK) + goto exit_nu_pipe_xfer; + +exit_nu_pipe_xfer: + +#if defined(BSP_USING_MMU) + if ((nbytes) && + (buffer_nonch != buffer)) + { + mmu_invalidate_dcache((uint32_t)buffer_nonch, nbytes); + rt_memcpy(buffer, buffer_nonch, nbytes); + } +#endif + + if (psUTR) + free_utr(psUTR); + + return i32XferLen; +} + +/* Polling USB root hub status task */ +static void nu_usbh_rh_thread_entry(void *parameter) +{ + while (1) + { + usbh_polling_root_hubs(); + rt_thread_mdelay(NU_USBHOST_HUB_POLLING_INTERVAL); + } +} + +static void nu_hcd_connect_callback( + struct udev_t *udev, + int param) +{ + int i; + int port_index; + S_NU_RH_PORT_CTRL *psPortCtrl; + + /* Igrone event if role is USBD*/ + if (nu_sys_usb0_role() == USB0_ID_HOST) + { + SYS_UnlockReg(); + outpw(REG_SYS_MISCFCR, (inpw(REG_SYS_MISCFCR) | (1 << 11))); /* Set USRHDSEN as 1; USB host/device role selection decided by USBID (SYS_PWRON[16]) */ + outpw(REG_SYS_PWRON, (inpw(REG_SYS_PWRON) | (1 << 16))); /* Set USB port 0 used for Host */ + SYS_LockReg(); + } + + for (i = 0; i < NU_MAX_USBH_PORT; i++) + { + psPortCtrl = &s_sUSBHDev.asPortCtrl[i]; + if (psPortCtrl->sRHPortDev.pUDev == NULL) + break; + } + + if (i >= NU_MAX_USBH_PORT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: port connect slot is full\n")); + return; + } + + port_index = i + 1; + psPortCtrl->sRHPortDev.pUDev = udev; + psPortCtrl->sRHPortDev.bRHParent = TRUE; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("usb connected\n")); + + if (udev->speed == SPEED_HIGH) + rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_TRUE); + else + rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_FALSE); +} + +static void nu_hcd_disconnect_callback( + struct udev_t *udev, + int param) +{ + int i; + int port_index; + S_NU_RH_PORT_CTRL *psPortCtrl; + + for (i = 0; i < NU_MAX_USBH_PORT; i++) + { + psPortCtrl = &s_sUSBHDev.asPortCtrl[i]; + if (psPortCtrl->sRHPortDev.pUDev == udev) + break; + } + + if (i >= NU_MAX_USBH_PORT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: udev not found\n")); + return; + } + + port_index = i + 1; + + for (i = 0; i < NU_MAX_USBH_PIPE; i++) + { + if (psPortCtrl->sRHPortDev.apsEPInfo[i] != NULL) + { + usbh_quit_xfer(psPortCtrl->sRHPortDev.pUDev, psPortCtrl->sRHPortDev.apsEPInfo[i]); + } + } + + psPortCtrl->sRHPortDev.pUDev = NULL; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n")); + + rt_usbh_root_hub_disconnect_handler(&s_sUSBHDev.uhcd, port_index); + + if (nu_sys_usb0_role() != USB0_ID_HOST) + { + SYS_UnlockReg(); + outpw(REG_SYS_MISCFCR, (inpw(REG_SYS_MISCFCR) & (~(1 << 11)))); + outpw(REG_SYS_PWRON, (inpw(REG_SYS_PWRON) & (~(1 << 16)))); + SYS_LockReg(); + } + +} + + +/* USB host operations -----------------------------------------------------------*/ +static struct uhcd_ops nu_uhcd_ops = +{ + nu_reset_port, + nu_pipe_xfer, + nu_open_pipe, + nu_close_pipe, +}; + +static rt_err_t nu_hcd_init(rt_device_t device) +{ + struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device; + usbh_core_init(); + + //install connect/disconnect callback + usbh_install_conn_callback(nu_hcd_connect_callback, nu_hcd_disconnect_callback); + usbh_polling_root_hubs(); + + //create thread for polling usbh port status + /* create usb hub thread */ + pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL, + NU_USBH_THREAD_STACK_SIZE, 8, 20); + RT_ASSERT(pNuUSBHDev->polling_thread != RT_NULL); + + /* startup usb host thread */ + rt_thread_startup(pNuUSBHDev->polling_thread); + + return RT_EOK; +} + +/* global function for USB host library -----------------------------*/ +uint32_t usbh_get_ticks(void) +{ + return rt_tick_get(); +} + +void usbh_delay_ms(int msec) +{ + rt_thread_mdelay(msec); +} + +uint32_t usbh_tick_from_millisecond(uint32_t msec) +{ + return rt_tick_from_millisecond(msec); +} + +#if defined(RT_USING_PM) + +/* device pm suspend() entry. */ +static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode) +{ + rt_err_t result; + + struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device; + + RT_ASSERT(pNuUSBHDev != RT_NULL); + switch (mode) + { + case PM_SLEEP_MODE_LIGHT: + case PM_SLEEP_MODE_DEEP: + + pNuUSBHDev->polling_thread->stat = RT_THREAD_READY; + result = rt_thread_suspend(pNuUSBHDev->polling_thread); + RT_ASSERT(result == RT_EOK); + + break; + + default: + break; + } + + return (int)RT_EOK; +} + +/* device pm resume() entry. */ +static void usbhost_pm_resume(const struct rt_device *device, rt_uint8_t mode) +{ + rt_err_t result; + struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device; + RT_ASSERT(pNuUSBHDev != RT_NULL); + + switch (mode) + { + case PM_SLEEP_MODE_LIGHT: + case PM_SLEEP_MODE_DEEP: + result = rt_thread_resume(pNuUSBHDev->polling_thread); + RT_ASSERT(result == RT_EOK); + break; + + default: + break; + } +} + +static struct rt_device_pm_ops device_pm_ops = +{ + .suspend = usbhost_pm_suspend, + .resume = usbhost_pm_resume, + .frequency_change = RT_NULL +}; +#endif + +int nu_usbh_register(void) +{ + rt_err_t res; + uhcd_t psUHCD; + + psUHCD = (uhcd_t)&s_sUSBHDev.uhcd; + + psUHCD->parent.type = RT_Device_Class_USBHost; + psUHCD->parent.init = nu_hcd_init; + psUHCD->parent.user_data = &s_sUSBHDev; + + psUHCD->ops = &nu_uhcd_ops; + psUHCD->num_ports = NU_MAX_USBH_PORT; + + res = rt_device_register(&psUHCD->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE); + RT_ASSERT(res == RT_EOK); + + nu_sys_ipclk_enable(s_sUSBHDev.clkidx); + nu_sys_ip_reset(s_sUSBHDev.rstidx); + + + /*initialize the usb host function */ + res = rt_usb_host_init(); + RT_ASSERT(res == RT_EOK); + +#if defined(RT_USING_PM) + rt_pm_device_register(&psUHCD->parent, &device_pm_ops); +#endif + + return 0; +} +INIT_DEVICE_EXPORT(nu_usbh_register); + +#endif diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_vpost.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_vpost.c new file mode 100644 index 0000000000000000000000000000000000000000..50c45ee915fd749271aa5484e86b03a6db386cb0 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_vpost.c @@ -0,0 +1,352 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2021-4-13 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_VPOST) + +#include +#include +#include +#include "NuMicro.h" +#include + +/* Private typedef --------------------------------------------------------------*/ + +typedef enum +{ + eVpost_LCD, +#if defined(BSP_USING_VPOST_OSD) + eVpost_OSD, +#endif + eVpost_Cnt +} E_VPOST_LAYER; + +struct nu_vpost +{ + struct rt_device dev; + char *name; + E_VPOST_LAYER layer; + IRQn_Type irqn; + E_SYS_IPRST rstidx; + E_SYS_IPCLK clkidx; + struct rt_device_graphic_info info; +}; +typedef struct nu_vpost *nu_vpost_t; + +static struct nu_vpost nu_fbdev[eVpost_Cnt] = +{ + { + .name = "lcd", + .layer = eVpost_LCD, + .irqn = IRQ_LCD, + .rstidx = LCDRST, + .clkidx = LCDCKEN, + } +#if defined(BSP_USING_VPOST_OSD) + , { + .name = "osd", + .layer = eVpost_OSD, + .irqn = (IRQn_Type) - 1, + .rstidx = SYS_IPRST_NA, + .clkidx = SYS_IPCLK_NA, + } +#endif +}; + +static rt_err_t vpost_layer_open(rt_device_t dev, rt_uint16_t oflag) +{ + nu_vpost_t psVpost = (nu_vpost_t)dev; + RT_ASSERT(psVpost != RT_NULL); + + switch (psVpost->layer) + { + case eVpost_LCD: + vpostVAStartTrigger(); + break; + +#if defined(BSP_USING_VPOST_OSD) + case eVpost_OSD: + vpostVAStartTrigger(); + + /* Set scale to 1:1 */ + vpostOSDScalingCtrl(1, 0, 0); + +#if (LCM_USING_BPP==4) + vpostOSDSetColMask(0xff, 0xff, 0xff); +#else + vpostOSDSetColMask(0x1f, 0x3f, 0x1f); +#endif + + /* Enable color key function */ + vpostOSDSetColKey(0, 0, 0); + + /* Configure overlay function of OSD to display OSD image */ + vpostOSDSetOverlay(DISPLAY_OSD, DISPLAY_OSD, 0); + + vpostOSDEnable(); + break; +#endif + + default: + return -RT_ERROR; + } + + return RT_EOK; +} + +static rt_err_t vpost_layer_close(rt_device_t dev) +{ + nu_vpost_t psVpost = (nu_vpost_t)dev; + RT_ASSERT(psVpost != RT_NULL); + + switch (psVpost->layer) + { + case eVpost_LCD: +#if defined(BSP_USING_VPOST_OSD) + if (nu_fbdev[eVpost_OSD].dev.ref_count == 0) +#endif + vpostVAStopTrigger(); + break; + +#if defined(BSP_USING_VPOST_OSD) + case eVpost_OSD: + vpostOSDDisable(); + if (nu_fbdev[eVpost_LCD].dev.ref_count == 0) + { + /* Also stop displaying */ + vpostVAStopTrigger(); + } + break; +#endif + + default: + return -RT_ERROR; + } + + return RT_EOK; +} + +static rt_err_t vpost_layer_control(rt_device_t dev, int cmd, void *args) +{ + nu_vpost_t psVpost = (nu_vpost_t)dev; + RT_ASSERT(psVpost != RT_NULL); + + switch (cmd) + { + case RTGRAPHIC_CTRL_GET_INFO: + { + struct rt_device_graphic_info *info = (struct rt_device_graphic_info *) args; + RT_ASSERT(info != RT_NULL); + rt_memcpy(args, (void *)&psVpost->info, sizeof(struct rt_device_graphic_info)); + } + break; + + default: + break; + } + + return RT_EOK; +} + +static rt_err_t vpost_layer_init(rt_device_t dev) +{ + nu_vpost_t psVpost = (nu_vpost_t)dev; + RT_ASSERT(psVpost != RT_NULL); + + /* Enable VPOST engine clock. */ + nu_sys_ipclk_enable(LCDCKEN); + + return RT_EOK; +} + +int rt_hw_vpost_init(void) +{ + int i = -1; + rt_err_t ret; + + VPOST_T *psVpostLcmInst = vpostLCMGetInstance(VPOST_USING_LCD_IDX); + RT_ASSERT(psVpostLcmInst != RT_NULL); + +#if (LCM_USING_BPP==4 ) + /* LCD clock is selected from UPLL and divide to 30MHz */ + outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0x918); +#else + /* LCD clock is selected from UPLL and divide to 20MHz */ + outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0xE18); +#endif + + /* Initial LCM */ + vpostLCMInit(VPOST_USING_LCD_IDX); + + /* Set scale to 1:1 */ + vpostVAScalingCtrl(1, 0, 1, 0, VA_SCALE_INTERPOLATION); + + for (i = eVpost_LCD; i < eVpost_Cnt; i++) + { + nu_vpost_t psVpost = &nu_fbdev[i]; + rt_memset((void *)&psVpost->info, 0, sizeof(struct rt_device_graphic_info)); + + /* Register VPOST information */ + psVpost->info.bits_per_pixel = LCM_USING_BPP * 8; + psVpost->info.pixel_format = (LCM_USING_BPP == 4) ? RTGRAPHIC_PIXEL_FORMAT_ARGB888 : RTGRAPHIC_PIXEL_FORMAT_RGB565; + psVpost->info.pitch = psVpostLcmInst->u32DevWidth * LCM_USING_BPP; + psVpost->info.width = psVpostLcmInst->u32DevWidth; + psVpost->info.height = psVpostLcmInst->u32DevHeight; + + /* Get pointer of video frame buffer */ + /* Set display color depth */ + /* Note: before get pointer of frame buffer, must set display color depth first */ + if (psVpost->layer == eVpost_LCD) + { +#if (LCM_USING_BPP==4) + vpostSetVASrc(VA_SRC_RGB888); +#else + vpostSetVASrc(VA_SRC_RGB565); +#endif + psVpost->info.framebuffer = (rt_uint8_t *)vpostGetFrameBuffer(); + } +#if defined(BSP_USING_VPOST_OSD) + else if (psVpost->layer == eVpost_OSD) + { + vpostOSDSetWindow(0, 0, psVpost->info.width, psVpost->info.height); + +#if (LCM_USING_BPP==4) + vpostSetOSDSrc(OSD_SRC_RGB888); +#else + vpostSetOSDSrc(OSD_SRC_RGB565); +#endif + psVpost->info.framebuffer = (rt_uint8_t *)vpostGetOSDBuffer(); + } +#endif + + if (psVpost->info.framebuffer == NULL) + { + rt_kprintf("Fail to get VRAM buffer.\n"); + RT_ASSERT(0); + } + + /* Register member functions of lcd device */ + psVpost->dev.type = RT_Device_Class_Graphic; + psVpost->dev.init = vpost_layer_init; + psVpost->dev.open = vpost_layer_open; + psVpost->dev.close = vpost_layer_close; + psVpost->dev.control = vpost_layer_control; + + /* register graphic device driver */ + ret = rt_device_register(&psVpost->dev, psVpost->name, RT_DEVICE_FLAG_RDWR); + RT_ASSERT(ret == RT_EOK); + + rt_kprintf("%s's fbmem at 0x%08x.\n", psVpost->name, psVpost->info.framebuffer); + } + + /* For saving memory bandwidth. */ + vpostLCMDeinit(); + + return (int)ret; +} +INIT_DEVICE_EXPORT(rt_hw_vpost_init); + + +/* Support "vpost_set_osd_colkey" command line in msh mode */ +static rt_err_t vpost_set_osd_colkey(int argc, char **argv) +{ + rt_uint32_t index, len, arg[4]; + + rt_memset(arg, 0, sizeof(arg)); + len = (argc >= 4) ? 4 : argc; + + for (index = 0; index < (len - 1); index ++) + { + arg[index] = atol(argv[index + 1]); + } + + /* Enable color key function */ + vpostOSDSetColKey(arg[0], arg[1], arg[2]); + + /* Configure overlay function of OSD to display VIDEO image */ + vpostOSDSetOverlay(DISPLAY_VIDEO, DISPLAY_OSD, 0); + + return 0; +} +MSH_CMD_EXPORT(vpost_set_osd_colkey, e.g: vpost_set_osd_colkey R G B); + +/* Support "vpost_show_layer" command line in msh mode */ +static rt_err_t vpost_show_layer(int argc, char **argv) +{ + rt_uint32_t index, len, arg[2]; + nu_vpost_t psVpostLayer; + + rt_memset(arg, 0, sizeof(arg)); + len = (argc >= 2) ? 2 : argc; + + for (index = 0; index < (len - 1); index ++) + { + arg[index] = atol(argv[index + 1]); + } + psVpostLayer = &nu_fbdev[arg[0]]; + + return rt_device_open(&psVpostLayer->dev, RT_DEVICE_FLAG_RDWR); +} +MSH_CMD_EXPORT(vpost_show_layer, e.g: vpost_show_layer layer); + +/* Support "vpost_hide_layer" command line in msh mode */ +static rt_err_t vpost_hide_layer(int argc, char **argv) +{ + rt_uint32_t index, len, arg[2]; + nu_vpost_t psVpostLayer; + + rt_memset(arg, 0, sizeof(arg)); + len = (argc >= 2) ? 2 : argc; + + for (index = 0; index < (len - 1); index ++) + { + arg[index] = atol(argv[index + 1]); + } + psVpostLayer = &nu_fbdev[arg[0]]; + + return rt_device_close(&psVpostLayer->dev); +} +MSH_CMD_EXPORT(vpost_hide_layer, e.g: vpost_hide_layer layer); + +/* Support "vpost_fill_color" command line in msh mode */ +static rt_err_t vpost_fill_color(int argc, char **argv) +{ + rt_uint32_t index, len, arg[5]; + nu_vpost_t psVpostLayer; + + rt_memset(arg, 0, sizeof(arg)); + len = (argc >= 5) ? 5 : argc; + + for (index = 0; index < (len - 1); index ++) + { + arg[index] = atol(argv[index + 1]); + } + + psVpostLayer = &nu_fbdev[arg[0]]; + + if (psVpostLayer->info.framebuffer != RT_NULL) + { + int i; + uint32_t fill_num = psVpostLayer->info.height * psVpostLayer->info.width; + uint32_t *fbmem_start = (uint32_t *)psVpostLayer->info.framebuffer; + uint32_t color = (arg[1] << 16) | (arg[2] << 8) | arg[3] ; + for (i = 0; i < fill_num; i++) + { + rt_memcpy((void *)&fbmem_start[i], &color, (psVpostLayer->info.bits_per_pixel / 8)); + } + } + return 0; +} +MSH_CMD_EXPORT(vpost_fill_color, e.g: vpost_fill_color layer R G B); + +#endif /* if defined(BSP_USING_VPOST) */ diff --git a/bsp/nuvoton/libraries/n9h30/rtt_port/drv_wdt.c b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_wdt.c new file mode 100644 index 0000000000000000000000000000000000000000..cc77bd2b308ee74cd4cd5f5e7bb7364866cec849 --- /dev/null +++ b/bsp/nuvoton/libraries/n9h30/rtt_port/drv_wdt.c @@ -0,0 +1,283 @@ +/**************************************************************************//** +* +* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2020-12-12 Wayne First version +* +******************************************************************************/ + +#include + +#if defined(BSP_USING_WDT) + +#include +#include +#include +#include "NuMicro.h" +#include + +/* Private define ---------------------------------------------------------------*/ + +/* Pick a suitable wdt timeout interval, it is a trade-off between the + consideration of timeout accuracy and the system performance. The MIN_CYCLES + parameter is a numerical value of the toutsel setting, and it must be set to + a correct one which matches to the literal meaning of MIN_TOUTSEL. */ +#define MIN_TOUTSEL (WDT_TIMEOUT_2POW10) +#define MIN_CYCLES (1024) + + +/* Macros to convert the value between the timeout interval and the soft time iterations. */ +#define ROUND_TO_INTEGER(value) ((int)(((value) * 10 + 5) / 10)) +#define CONV_SEC_TO_IT(hz, secs) (ROUND_TO_INTEGER((float)((secs) * (hz)) / (float)(MIN_CYCLES))) +#define CONV_IT_TO_SEC(hz, iterations) (ROUND_TO_INTEGER((float)((iterations) * (MIN_CYCLES)) / (float)(hz))) + + +/* Private typedef --------------------------------------------------------------*/ +struct soft_time_handle +{ + int clock_hz; + int wanted_sec; + int report_sec; + int left_iterations; + int full_iterations; + rt_bool_t expired; + rt_bool_t feed_dog; +}; + +typedef volatile struct soft_time_handle soft_time_handle_t; + +/* Private functions ------------------------------------------------------------*/ +static rt_err_t wdt_init(rt_watchdog_t *dev); +static rt_err_t wdt_control(rt_watchdog_t *dev, int cmd, void *args); +static uint32_t wdt_get_working_hz(void); +static void soft_time_init(soft_time_handle_t *const soft_time); +static void soft_time_setup(uint32_t wanted_sec, uint32_t hz, soft_time_handle_t *const soft_time); +static void soft_time_feed_dog(soft_time_handle_t *const soft_time); +static void nu_wdt_isr(int vector, void *param); + +/* Public functions -------------------------------------------------------------*/ + +/* Private variables ------------------------------------------------------------*/ +static struct soft_time_handle soft_time; +static struct rt_watchdog_device device_wdt; +static struct rt_watchdog_ops ops_wdt = +{ + .init = wdt_init, + .control = wdt_control, +}; + +static void hw_wdt_init(void) +{ + nu_sys_ipclk_enable(WDTCKEN); + + rt_hw_interrupt_install(IRQ_WDT, nu_wdt_isr, &device_wdt, "wdt"); + rt_hw_interrupt_umask(IRQ_WDT); +} + + +/* wdt device driver initialize. */ +int rt_hw_wdt_init(void) +{ + rt_err_t ret; + + hw_wdt_init(); + + device_wdt.ops = &ops_wdt; + ret = rt_hw_watchdog_register(&device_wdt, "wdt", RT_DEVICE_FLAG_RDWR, RT_NULL); + + return (int)ret; +} +INIT_BOARD_EXPORT(rt_hw_wdt_init); + + +/* Register rt-thread device.init() entry. */ +static rt_err_t wdt_init(rt_watchdog_t *dev) +{ + soft_time_init(&soft_time); + + return RT_EOK; +} + + +static uint32_t wdt_get_working_hz(void) +{ + static uint32_t u32ClkTbl[4] = {12000000, 12000000 / 128, 0, 32768}; + uint32_t u32WDT_S = (inpw(REG_CLK_DIVCTL8) & (0x3 << 8)) >> 8; + uint32_t clk = 0; + + switch (u32WDT_S) + { + case 0: // XIN Hz + case 1: // XIN/128 Hz + case 3: // 32.768 Hz + clk = u32ClkTbl[u32WDT_S]; + break; + + case 2: // PCLK/4096 Hz + clk = sysGetClock(SYS_PCLK) * 1000000 / 4096; + break; + + default: + break; + } + + return clk; +} + + + +static void soft_time_init(soft_time_handle_t *const soft_time) +{ + rt_memset((void *)soft_time, 0, sizeof(struct soft_time_handle)); + +} + + +static void soft_time_setup(uint32_t wanted_sec, uint32_t hz, soft_time_handle_t *const soft_time) +{ + rt_base_t level = rt_hw_interrupt_disable(); + + soft_time->expired = RT_FALSE; + soft_time->feed_dog = RT_FALSE; + soft_time->wanted_sec = wanted_sec; + soft_time->full_iterations = CONV_SEC_TO_IT(hz, wanted_sec); + soft_time->left_iterations = soft_time->full_iterations; + soft_time->report_sec = CONV_IT_TO_SEC(hz, soft_time->full_iterations); + soft_time->clock_hz = hz; + + rt_hw_interrupt_enable(level); +} + + +static void soft_time_feed_dog(soft_time_handle_t *const soft_time) +{ + soft_time->feed_dog = RT_TRUE; +} + + +/* Register rt-thread device.control() entry. */ +static rt_err_t wdt_control(rt_watchdog_t *dev, int cmd, void *args) +{ + uint32_t wanted_sec, hz; + uint32_t *buf; + rt_err_t ret = RT_EOK; + + if (dev == NULL) + return -(RT_EINVAL); + + hz = wdt_get_working_hz(); + + SYS_UnlockReg(); + + switch (cmd) + { + case RT_DEVICE_CTRL_WDT_GET_TIMEOUT: + + if (args == RT_NULL) + { + ret = RT_EINVAL; + break; + } + + buf = (uint32_t *)args; + *buf = soft_time.report_sec; + break; + + case RT_DEVICE_CTRL_WDT_SET_TIMEOUT: + + wanted_sec = *((uint32_t *)args); + + if (wanted_sec == 0) + { + ret = RT_EINVAL; + break; + } + + soft_time_setup(wanted_sec, hz, &soft_time); + break; + + case RT_DEVICE_CTRL_WDT_GET_TIMELEFT: + + if (args == RT_NULL) + { + ret = RT_EINVAL; + break; + } + + buf = (uint32_t *)args; + *buf = CONV_IT_TO_SEC(hz, soft_time.left_iterations); + break; + + case RT_DEVICE_CTRL_WDT_KEEPALIVE: + + /* Make a mark that the application has fed the watchdog. */ + soft_time_feed_dog(&soft_time); + break; + + case RT_DEVICE_CTRL_WDT_START: + + WDT_RESET_COUNTER(); + WDT_Open(MIN_TOUTSEL, WDT_RESET_DELAY_1026CLK, TRUE, TRUE); + WDT_EnableInt(); + break; + + case RT_DEVICE_CTRL_WDT_STOP: + + WDT_Close(); + break; + + default: + ret = RT_ERROR; + } + + SYS_LockReg(); + + return -(ret); +} + + +/* wdt interrupt entry */ +static void nu_wdt_isr(int vector, void *param) +{ + /* Clear wdt interrupt flag */ + if (WDT_GET_TIMEOUT_INT_FLAG()) + { + WDT_CLEAR_TIMEOUT_INT_FLAG(); + } + + SYS_UnlockReg(); + + /* The soft time has not reached the configured timeout yet. Clear the wdt counter + any way to prevent the system from hardware wdt reset. */ + if (soft_time.left_iterations-- > 0) + { + WDT_RESET_COUNTER(); + } + + /* The soft time reaches the configured timeout boundary. Clear the wdt + counter if he application has fed the dog at least once until now. */ + else + { + if ((soft_time.feed_dog) && (!soft_time.expired)) + { + WDT_RESET_COUNTER(); + soft_time.feed_dog = RT_FALSE; + soft_time.left_iterations = soft_time.full_iterations; + } + else + { + /* Application does not feed the dog in time. */ + soft_time.expired = RT_TRUE; + } + } + + SYS_LockReg(); +} + +#endif /* BSP_USING_WDT */ + +