diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0b44c79f2b2..2ba434667da 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -227,6 +227,7 @@ config ARCH_CHIP_MOXART bool "MoxART" select ARCH_ARM7TDMI select ARCH_HAVE_RESET + select ARCH_HAVE_SERIAL_TERMIOS ---help--- MoxART family diff --git a/arch/arm/include/moxart/irq.h b/arch/arm/include/moxart/irq.h index 31c92ed5d3b..238d47761ef 100644 --- a/arch/arm/include/moxart/irq.h +++ b/arch/arm/include/moxart/irq.h @@ -81,7 +81,8 @@ extern "C" #define IRQ_SYSTIMER 19 -#define NR_IRQS 32 +#define VIRQ_START 32 + +#define NR_IRQS (VIRQ_START+2) #endif /* __ARCH_ARM_INCLUDE_MOXART_IRQ_H */ - diff --git a/arch/arm/include/samv7/chip.h b/arch/arm/include/samv7/chip.h index 29ed62afa36..eff9fe1ea4f 100644 --- a/arch/arm/include/samv7/chip.h +++ b/arch/arm/include/samv7/chip.h @@ -86,7 +86,7 @@ # define SAMV7_NTCCHIO 36 /* 12 Timer/counter channels I/O */ # define SAMV7_NUSART 3 /* 3 USARTs */ # define SAMV7_NUART 5 /* 5 UARTs */ -# define SAMV7_NQSPI 5 /* 1 Quad SPI */ +# define SAMV7_NQSPI 1 /* 1 Quad SPI */ # define SAMV7_NSPI 2 /* 2 SPI, SPI0-1 */ # define SAMV7_NTWIHS 3 /* 3 TWIHS */ # define SAMV7_NHSMCI4 1 /* 1 4-bit HSMCI port */ @@ -142,7 +142,7 @@ # define SAMV7_NTCCHIO 9 /* 12 Timer/counter channels I/O */ # define SAMV7_NUSART 3 /* 3 USARTs */ # define SAMV7_NUART 5 /* 5 UARTs */ -# define SAMV7_NQSPI 5 /* 1 Quad SPI */ +# define SAMV7_NQSPI 1 /* 1 Quad SPI */ # define SAMV7_NSPI 1 /* 1 SPI, SPI0 */ # define SAMV7_NTWIHS 3 /* 3 TWIHS */ # define SAMV7_NHSMCI4 1 /* 1 4-bit HSMCI port */ diff --git a/arch/arm/include/stm32/chip.h b/arch/arm/include/stm32/chip.h index d52a9aec29c..8635da36dc9 100644 --- a/arch/arm/include/stm32/chip.h +++ b/arch/arm/include/stm32/chip.h @@ -1212,6 +1212,86 @@ # define STM32_NRNG 0 /* (0) No random number generator (RNG) */ # define STM32_NDCMI 0 /* (0) No digital camera interface (DCMI) */ +#elif defined(CONFIG_ARCH_CHIP_STM32F303K6) || defined(CONFIG_ARCH_CHIP_STM32F303K8) +# undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */ +# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */ +# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */ +# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */ +# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */ +# undef CONFIG_STM32_MEDIUMPLUSDENSITY /* STM32L15xxC w/ 32/256 Kbytes */ +# undef CONFIG_STM32_HIGHDENSITY /* STM32F100x, STM32F101x, and STM32F103x w/ 256/512 Kbytes */ +# undef CONFIG_STM32_VALUELINE /* STM32F100x */ +# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */ +# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */ +# define CONFIG_STM32_STM32F30XX 1 /* STM32F30xxx family */ +# undef CONFIG_STM32_STM32F37XX /* STM32F37xxx family */ +# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx */ +# define STM32_NFSMC 0 /* No FSMC */ + +# define STM32_NATIM 1 /* (1) Advanced 16-bit timers with DMA: TIM1 */ +# define STM32_NGTIM 5 /* (1) 16-bit general timers with DMA: TIM3 + * (1) 32-bit general timers with DMA: TIM2 + * (3) 16-bit general timers count-up timers with DMA: TIM15-17 */ +# define STM32_NGTIMNDMA 0 /* All timers have DMA */ +# define STM32_NBTIM 2 /* (2) Basic timers: TIM6 and TIM7 */ +# define STM32_NDMA 1 /* (1) DMA1 (7 channels) */ +# define STM32_NSPI 1 /* (1) SPI1 */ +# define STM32_NI2S 0 /* (0) No I2S */ +# define STM32_NUSART 2 /* (2) USART1-2, no UARTs */ +# define STM32_NI2C 1 /* (1) I2C1 */ +# define STM32_NCAN 1 /* (1) CAN1 */ +# define STM32_NSDIO 0 /* (0) No SDIO */ +# define STM32_NLCD 0 /* (0) No LCD */ +# define STM32_NUSBOTG 0 /* No USB OTG FS/HS */ +# define STM32_NGPIO 25 /* GPIOA-F */ +# define STM32_NADC 2 /* (2) 12-bit ADC1-2 */ +# define STM32_NDAC 3 /* (2) 12-bit DAC1-3 */ +# define STM32_NCAPSENSE 0 /* (0) No capacitive sensing channels */ +# define STM32_NCRC 1 /* (1) CRC calculation unit */ +# define STM32_NETHERNET 0 /* (0) No Ethernet MAC */ +# define STM32_NRNG 0 /* (0) No random number generator (RNG) */ +# define STM32_NDCMI 0 /* (0) No digital camera interface (DCMI) */ + +#elif defined(CONFIG_ARCH_CHIP_STM32F303C6) || defined(CONFIG_ARCH_CHIP_STM32F303C8) +# undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */ +# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */ +# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */ +# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */ +# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */ +# undef CONFIG_STM32_MEDIUMPLUSDENSITY /* STM32L15xxC w/ 32/256 Kbytes */ +# undef CONFIG_STM32_HIGHDENSITY /* STM32F100x, STM32F101x, and STM32F103x w/ 256/512 Kbytes */ +# undef CONFIG_STM32_VALUELINE /* STM32F100x */ +# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */ +# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */ +# define CONFIG_STM32_STM32F30XX 1 /* STM32F30xxx family */ +# undef CONFIG_STM32_STM32F37XX /* STM32F37xxx family */ +# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx */ +# define STM32_NFSMC 0 /* No FSMC */ + +# define STM32_NATIM 1 /* (1) Advanced 16-bit timers with DMA: TIM1 */ +# define STM32_NGTIM 5 /* (1) 16-bit general timers with DMA: TIM3 + * (1) 32-bit general timers with DMA: TIM2 + * (3) 16-bit general timers count-up timers with DMA: TIM15-17 */ +# define STM32_NGTIMNDMA 0 /* All timers have DMA */ +# define STM32_NBTIM 2 /* (2) Basic timers: TIM6 and TIM7 */ +# define STM32_NDMA 1 /* (1) DMA1 (7 channels) */ +# define STM32_NSPI 1 /* (1) SPI1 */ +# define STM32_NI2S 0 /* (0) No I2S */ +# define STM32_NUSART 3 /* (3) USART1-3, no UARTs */ +# define STM32_NI2C 1 /* (1) I2C1 */ +# define STM32_NCAN 1 /* (1) CAN1 */ +# define STM32_NSDIO 0 /* (0) No SDIO */ +# define STM32_NLCD 0 /* (0) No LCD */ +# define STM32_NUSBOTG 0 /* No USB OTG FS/HS */ +# define STM32_NGPIO 37 /* GPIOA-F */ +# define STM32_NADC 2 /* (2) 12-bit ADC1-2 */ +# define STM32_NDAC 3 /* (2) 12-bit DAC1-3 */ +# define STM32_NCAPSENSE 0 /* (0) No capacitive sensing channels */ +# define STM32_NCRC 1 /* (1) CRC calculation unit */ +# define STM32_NETHERNET 0 /* (0) No Ethernet MAC */ +# define STM32_NRNG 0 /* (0) No random number generator (RNG) */ +# define STM32_NDCMI 0 /* (0) No digital camera interface (DCMI) */ + #elif defined(CONFIG_ARCH_CHIP_STM32F303CB) || defined(CONFIG_ARCH_CHIP_STM32F303CC) # undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */ # undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */ @@ -1292,6 +1372,46 @@ # define STM32_NRNG 0 /* (0) No random number generator (RNG) */ # define STM32_NDCMI 0 /* (0) No digital camera interface (DCMI) */ +#elif defined(CONFIG_ARCH_CHIP_STM32F303RD) || defined(CONFIG_ARCH_CHIP_STM32F303RE) +# undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */ +# undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */ +# undef CONFIG_STM32_STM32F10XX /* STM32F10xxx family */ +# undef CONFIG_STM32_LOWDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 16/32 Kbytes */ +# undef CONFIG_STM32_MEDIUMDENSITY /* STM32F100x, STM32F101x, STM32F102x and STM32F103x w/ 64/128 Kbytes */ +# undef CONFIG_STM32_MEDIUMPLUSDENSITY /* STM32L15xxC w/ 32/256 Kbytes */ +# undef CONFIG_STM32_HIGHDENSITY /* STM32F100x, STM32F101x, and STM32F103x w/ 256/512 Kbytes */ +# undef CONFIG_STM32_VALUELINE /* STM32F100x */ +# undef CONFIG_STM32_CONNECTIVITYLINE /* STM32F105x and STM32F107x */ +# undef CONFIG_STM32_STM32F20XX /* STM32F205x and STM32F207x */ +# define CONFIG_STM32_STM32F30XX 1 /* STM32F30xxx family */ +# undef CONFIG_STM32_STM32F37XX /* STM32F37xxx family */ +# undef CONFIG_STM32_STM32F40XX /* STM32F405xx and STM32407xx */ +# define STM32_NFSMC 0 /* No FSMC */ + +# define STM32_NATIM 2 /* (2) Advanced 16-bit timers with DMA: TIM1 and TIM8 */ +# define STM32_NGTIM 6 /* (2) 16-bit general timers with DMA: TIM3 and TIM4 + * (1) 32-bit general timers with DMA: TIM2 + * (3) 16-bit general timers count-up timers with DMA: TIM15-17 */ +# define STM32_NGTIMNDMA 0 /* All timers have DMA */ +# define STM32_NBTIM 2 /* (2) Basic timers: TIM6 and TIM7 */ +# define STM32_NDMA 2 /* (2) DMA1 (7 channels) and DMA2 (5 channels) */ +# define STM32_NSPI 4 /* (4) SPI1-4 */ +# define STM32_NI2S 2 /* (2) I2S1-2 (multiplexed with SPI2-3) */ +# define STM32_NUSART 5 /* (5) USART1-3, UART4-5 */ +# define STM32_NI2C 3 /* (2) I2C1-3 */ +# define STM32_NCAN 1 /* (1) CAN1 */ +# define STM32_NSDIO 0 /* (0) No SDIO */ +# define STM32_NLCD 0 /* (0) No LCD */ +# define STM32_NUSBOTG 0 /* USB FS device, but no USB OTG FS/HS */ +# define STM32_NGPIO 51 /* GPIOA-F */ +# define STM32_NADC 4 /* (4) 12-bit ADC1-4 */ +# define STM32_NDAC 2 /* (2) 12-bit DAC1-2 */ +# define STM32_NCAPSENSE 0 /* (0) No capacitive sensing channels */ +# define STM32_NCRC 1 /* (1) CRC calculation unit */ +# define STM32_NETHERNET 0 /* (0) No Ethernet MAC */ +# define STM32_NRNG 0 /* (0) No random number generator (RNG) */ +# define STM32_NDCMI 0 /* (0) No digital camera interface (DCMI) */ + #elif defined(CONFIG_ARCH_CHIP_STM32F303VB) || defined(CONFIG_ARCH_CHIP_STM32F303VC) # undef CONFIG_STM32_STM32L15XX /* STM32L151xx and STM32L152xx family */ # undef CONFIG_STM32_ENERGYLITE /* STM32L EnergyLite family */ diff --git a/arch/arm/src/armv7-m/up_ramvec_initialize.c b/arch/arm/src/armv7-m/up_ramvec_initialize.c index b8bf2057214..37332776850 100644 --- a/arch/arm/src/armv7-m/up_ramvec_initialize.c +++ b/arch/arm/src/armv7-m/up_ramvec_initialize.c @@ -56,6 +56,21 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Alignment ****************************************************************/ +/* Per the ARMv7M Architecture reference manual, the NVIC vector table + * requires 7-bit address alignment (i.e, bits 0-6 of the address of the + * vector table must be zero). In this case alignment to a 128 byte address + * boundary is sufficient. + * + * Some parts, such as the LPC17xx family, require alignment to a 256 byte + * address boundary. Any other unusual alignment requirements for the vector + * can be specified for a given architecture be redefining + * NVIC_VECTAB_TBLOFF_MASK in the chip-specific chip.h header file for the + * appropriate mask. + */ + +#define RAMVEC_ALIGN ((~NVIC_VECTAB_TBLOFF_MASK & 0xffff) + 1) + /* Debug ********************************************************************/ /* Non-standard debug that may be enabled just for testing the interrupt * config. NOTE: that only lldbg types are used so that the output is @@ -91,7 +106,7 @@ */ up_vector_t g_ram_vectors[ARMV7M_VECTAB_SIZE] - __attribute__ ((section (".ram_vectors"), aligned (128))); + __attribute__ ((section (".ram_vectors"), aligned (RAMVEC_ALIGN))); /**************************************************************************** * Private Variables diff --git a/arch/arm/src/efm32/efm32_irq.c b/arch/arm/src/efm32/efm32_irq.c index 3b7c386ef65..9923bcdf259 100644 --- a/arch/arm/src/efm32/efm32_irq.c +++ b/arch/arm/src/efm32/efm32_irq.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/efm32/efm32_irq.c * - * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -79,8 +79,18 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; +/* This is the address of the exception vector table (determined by the + * linker script). + */ + +extern uint32_t _vectors[]; + /**************************************************************************** * Private Data ****************************************************************************/ @@ -363,6 +373,15 @@ void up_irqinitialize(void) } #endif + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + #ifdef CONFIG_ARCH_RAMVECTORS /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. diff --git a/arch/arm/src/efm32/efm32_usbdev.c b/arch/arm/src/efm32/efm32_usbdev.c index 6816d50b708..9ce5b6a1387 100644 --- a/arch/arm/src/efm32/efm32_usbdev.c +++ b/arch/arm/src/efm32/efm32_usbdev.c @@ -683,7 +683,7 @@ static const struct usbdev_ops_s g_devops = .pullup = efm32_pullup, }; -/* Device error strings that may be enabled for more desciptive USB trace +/* Device error strings that may be enabled for more descriptive USB trace * output. */ @@ -725,7 +725,7 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] = }; #endif -/* Interrupt event strings that may be enabled for more desciptive USB trace +/* Interrupt event strings that may be enabled for more descriptive USB trace * output. */ diff --git a/arch/arm/src/efm32/efm32_usbhost.c b/arch/arm/src/efm32/efm32_usbhost.c index 97b75f75d5d..35c0bc65b91 100644 --- a/arch/arm/src/efm32/efm32_usbhost.c +++ b/arch/arm/src/efm32/efm32_usbhost.c @@ -1171,7 +1171,7 @@ static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv, /* Loop, testing for an end of transfer condition. The channel 'result' * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' * will be set to false and 'result' will be set appropriately when the - * tranfer is completed. + * transfer is completed. */ do diff --git a/arch/arm/src/kinetis/kinetis_enet.c b/arch/arm/src/kinetis/kinetis_enet.c index 8cf87932da2..6edc71fcd24 100644 --- a/arch/arm/src/kinetis/kinetis_enet.c +++ b/arch/arm/src/kinetis/kinetis_enet.c @@ -191,14 +191,14 @@ struct kinetis_driver_s #endif /* The DMA descriptors. A unaligned uint8_t is used to allocate the - * memory; 16 is added to assure that we can meet the desciptor alignment + * memory; 16 is added to assure that we can meet the descriptor alignment * requirements. */ uint8_t desc[NENET_NBUFFERS * sizeof(struct enet_desc_s) + 16]; /* The DMA buffers. Again, A unaligned uint8_t is used to allocate the - * memory; 16 is added to assure that we can meet the desciptor alignment + * memory; 16 is added to assure that we can meet the descriptor alignment * requirements. */ diff --git a/arch/arm/src/kinetis/kinetis_irq.c b/arch/arm/src/kinetis/kinetis_irq.c index 452c4b45b6a..cded69a62a7 100644 --- a/arch/arm/src/kinetis/kinetis_irq.c +++ b/arch/arm/src/kinetis/kinetis_irq.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc17/kinetis_irq.c * - * Copyright (C) 2011, 2013-14 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -75,8 +75,18 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; +/* This is the address of the exception vector table (determined by the + * linker script). + */ + +extern uint32_t _vectors[]; + /**************************************************************************** * Private Data ****************************************************************************/ @@ -341,11 +351,20 @@ void up_irqinitialize(void) putreg32(0, regaddr); } + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#ifdef CONFIG_ARCH_RAMVECTORS up_ramvec_initialize(); #endif diff --git a/arch/arm/src/lpc17xx/lpc17_allocateheap.c b/arch/arm/src/lpc17xx/lpc17_allocateheap.c index 577de74053f..491a3445af5 100644 --- a/arch/arm/src/lpc17xx/lpc17_allocateheap.c +++ b/arch/arm/src/lpc17xx/lpc17_allocateheap.c @@ -155,15 +155,23 @@ /* Sanity checking */ +#if !defined(CONFIG_LPC17_EXTDRAMHEAP) && !defined(CONFIG_LPC17_EXTSRAM0HEAP) +# define LPC17_EXT_MM_REGIONS 0 +#elif defined(CONFIG_LPC17_EXTDRAMHEAP) && defined(CONFIG_LPC17_EXTSRAM0HEAP) +# define LPC17_EXT_MM_REGIONS 2 +#else +# define LPC17_EXT_MM_REGIONS 1 +#endif + #ifdef LPC17_AHB_HEAPBASE -# if CONFIG_MM_REGIONS < 2 +# if CONFIG_MM_REGIONS < 2 + LPC17_EXT_MM_REGIONS # warning "CONFIG_MM_REGIONS < 2: Available AHB SRAM Bank(s) not included in HEAP" # endif -# if CONFIG_MM_REGIONS > 2 +# if (CONFIG_MM_REGIONS > 2 + LPC17_EXT_MM_REGIONS) # warning "CONFIG_MM_REGIONS > 2: Are additional regions handled by application?" # endif #else -# if CONFIG_MM_REGIONS > 1 +# if CONFIG_MM_REGIONS > 1 + LPC17_EXT_MM_REGIONS # warning "CONFIG_MM_REGIONS > 1: This configuration has no available AHB SRAM Bank0/1" # warning "CONFIG_MM_REGIONS > 1: Are additional regions handled by application?" # endif @@ -340,5 +348,16 @@ void up_addregion(void) kumm_addregion((FAR void*)LPC17_AHB_HEAPBASE, LPC17_AHB_HEAPSIZE); #endif + +#if CONFIG_MM_REGIONS >= 3 +#if defined(CONFIG_LPC17_EXTDRAM) && defined(CONFIG_LPC17_EXTDRAMHEAP) + kmm_addregion((FAR void*)LPC17_EXTDRAM_CS0, CONFIG_LPC17_EXTDRAMSIZE); +#endif +#if !defined(CONFIG_LPC17_EXTDRAMHEAP) || (CONFIG_MM_REGIONS >= 4) +#if defined(CONFIG_LPC17_EXTSRAM0) && defined(CONFIG_LPC17_EXTSRAM0HEAP) + kmm_addregion((FAR void*)LPC17_EXTSRAM_CS0, CONFIG_LPC17_EXTSRAM0SIZE); +#endif +#endif +#endif } #endif diff --git a/arch/arm/src/lpc17xx/lpc17_can.c b/arch/arm/src/lpc17xx/lpc17_can.c index 8334e01ab1f..310330dc4ed 100644 --- a/arch/arm/src/lpc17xx/lpc17_can.c +++ b/arch/arm/src/lpc17xx/lpc17_can.c @@ -750,7 +750,8 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) irqstate_t flags; int ret = OK; - canvdbg("CAN%d ID: %d DLC: %d\n", priv->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); + canvdbg("CAN%d ID: %d DLC: %d\n", + priv->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); if (msg->cm_hdr.ch_rtr) { @@ -971,12 +972,15 @@ static void can_interrupt(FAR struct can_dev_s *dev) /* Construct the CAN header */ - hdr.ch_id = rid; - hdr.ch_rtr = ((rfs & CAN_RFS_RTR) != 0); - hdr.ch_dlc = (rfs & CAN_RFS_DLC_MASK) >> CAN_RFS_DLC_SHIFT; + hdr.ch_id = rid; + hdr.ch_rtr = ((rfs & CAN_RFS_RTR) != 0); + hdr.ch_dlc = (rfs & CAN_RFS_DLC_MASK) >> CAN_RFS_DLC_SHIFT; + hdr.ch_error = 0; #ifdef CONFIG_CAN_EXTID - hdr.ch_extid = ((rfs & CAN_RFS_FF) != 0); + hdr.ch_extid = ((rfs & CAN_RFS_FF) != 0); #else + hdr.ch_unused = 0; + if ((rfs & CAN_RFS_FF) != 0) { canlldbg("ERROR: Received message with extended identifier. Dropped\n"); diff --git a/arch/arm/src/lpc17xx/lpc17_gpdma.h b/arch/arm/src/lpc17xx/lpc17_gpdma.h index 0136ac105f8..4e1e499eb1c 100644 --- a/arch/arm/src/lpc17xx/lpc17_gpdma.h +++ b/arch/arm/src/lpc17xx/lpc17_gpdma.h @@ -60,7 +60,7 @@ typedef FAR void *DMA_HANDLE; * function is called at the completion of the DMA transfer. 'arg' is the * same 'arg' value that was provided when lpc17_dmastart() was called and * result indicates the result of the transfer: Zero indicates a successful - * tranfers. On failure, a negated errno is returned indicating the general + * transfers. On failure, a negated errno is returned indicating the general * nature of the DMA faiure. */ diff --git a/arch/arm/src/lpc17xx/lpc17_irq.c b/arch/arm/src/lpc17xx/lpc17_irq.c index 29f398c8e3e..7a6005c71fb 100644 --- a/arch/arm/src/lpc17xx/lpc17_irq.c +++ b/arch/arm/src/lpc17xx/lpc17_irq.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc17/lpc17_irq.c * - * Copyright (C) 2010-2011, 2013-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2010-2011, 2013-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -76,11 +76,17 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; -/**************************************************************************** - * Private Data - ****************************************************************************/ +/* This is the address of the exception vector table (determined by the + * linker script). + */ + +extern uint32_t _vectors[]; /**************************************************************************** * Private Functions @@ -313,8 +319,21 @@ void up_irqinitialize(void) putreg32(0, regaddr); } + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. + * + * But even in this case NVIC_VECTAB has to point to the initial table + * because up_ramvec_initialize() initializes RAM table from table + * pointed by NVIC_VECTAB register. */ #ifdef CONFIG_ARCH_RAMVECTORS diff --git a/arch/arm/src/lpc17xx/lpc17_usbdev.c b/arch/arm/src/lpc17xx/lpc17_usbdev.c index 876584ba337..1ab475edc07 100644 --- a/arch/arm/src/lpc17xx/lpc17_usbdev.c +++ b/arch/arm/src/lpc17xx/lpc17_usbdev.c @@ -2457,7 +2457,7 @@ static int lpc17_dmasetup(struct lpc17_usbdev_s *priv, uint8_t epphy, dmadesc->size = (uint32_t)packet; #endif - /* Enable DMA tranfer for this endpoint */ + /* Enable DMA transfer for this endpoint */ putreq32(1 << epphy, LPC17_USBDEV_EPDMAEN); diff --git a/arch/arm/src/lpc214x/lpc214x_usbdev.c b/arch/arm/src/lpc214x/lpc214x_usbdev.c index f1d21bab434..b3caf5ea3b9 100644 --- a/arch/arm/src/lpc214x/lpc214x_usbdev.c +++ b/arch/arm/src/lpc214x/lpc214x_usbdev.c @@ -212,7 +212,7 @@ /* USB RAM ******************************************************************** * - * UBS_UDCA is is list of 32 pointers to DMA desciptors located at the + * UBS_UDCA is is list of 32 pointers to DMA descriptors located at the * beginning of USB RAM. Each pointer points to a DMA descriptor with * assocated DMA buffer. */ @@ -2422,7 +2422,7 @@ static int lpc214x_dmasetup(struct lpc214x_usbdev_s *priv, uint8_t epphy, dmadesc->size = (uint32_t)packet; #endif - /* Enable DMA tranfer for this endpoint */ + /* Enable DMA transfer for this endpoint */ putreq32(1 << epphy, LPC214X_USBDEV_EPDMAEN); diff --git a/arch/arm/src/lpc43xx/lpc43_irq.c b/arch/arm/src/lpc43xx/lpc43_irq.c index e9e57e5ef63..ee82f24fb3a 100644 --- a/arch/arm/src/lpc43xx/lpc43_irq.c +++ b/arch/arm/src/lpc43xx/lpc43_irq.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/lpc43/lpc43_irq.c * - * Copyright (C) 2012-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2012-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -77,11 +77,17 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; -/* This is the address of the vector table */ +/* This is the address of the exception vector table (determined by the + * linker script). + */ -extern unsigned _vectors[]; +extern uint32_t _vectors[]; /**************************************************************************** * Private Data @@ -316,15 +322,16 @@ void up_irqinitialize(void) * positioned in SRAM or in external FLASH, then we may need to reset * the interrupt vector so that it refers to the table in SRAM or in * external FLASH. - * - * If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#ifdef CONFIG_ARCH_RAMVECTORS up_ramvec_initialize(); -#else - putreg32((uint32_t)_vectors, NVIC_VECTAB); #endif /* Set all interrupts (and exceptions) to the default priority */ diff --git a/arch/arm/src/moxart/Kconfig b/arch/arm/src/moxart/Kconfig index 3c8166499ff..d7487ee8a02 100644 --- a/arch/arm/src/moxart/Kconfig +++ b/arch/arm/src/moxart/Kconfig @@ -7,3 +7,12 @@ comment "MoxART Configuration Options" config UART_MOXA_MODE_REG hex "16550 UART mode register address" + default 0x982000E0 + +config UART_MOXA_IRQ_STATUS_REG + hex "16550 UART shared IRQ status register address" + default 0x982000C0 + +config UART_MOXA_SHARED_IRQ + int "16550 UART shared IRQ number" + default 31 diff --git a/arch/arm/src/moxart/moxart_16550.c b/arch/arm/src/moxart/moxart_16550.c index a1dbed0bb30..8152c28a800 100644 --- a/arch/arm/src/moxart/moxart_16550.c +++ b/arch/arm/src/moxart/moxart_16550.c @@ -67,6 +67,30 @@ void uart_putreg(uart_addrwidth_t base, unsigned int offset, uart_datawidth_t va *((volatile uart_addrwidth_t *)base + offset) = value; } +void uart_decodeirq(int irq, FAR void *context) +{ + int i; + uint32_t status; + static int os = 0; + + status = *((volatile uart_addrwidth_t *)CONFIG_UART_MOXA_IRQ_STATUS_REG); + + if ((status & 0x3f) == 0x3f) + { + return; + } + + i = 0; + do + { + if (!(status & 0x1)) { + irq_dispatch(VIRQ_START + i, context); + } + status >>= 1; + } + while (++i <= 4); +} + #ifdef CONFIG_SERIAL_UART_ARCH_IOCTL int uart_ioctl(struct file *filep, int cmd, unsigned long arg) { @@ -109,9 +133,12 @@ int uart_ioctl(struct file *filep, int cmd, unsigned long arg) /* Update mode register with requested mode */ vmode = getreg32(CONFIG_UART_MOXA_MODE_REG); - putreg32(CONFIG_UART_MOXA_MODE_REG, (vmode & ~(OP_MODE_MASK << 2 * bitm_off)) | ((opmode << 2 * bitm_off) & 0xffff)); + putreg32(vmode & ~(OP_MODE_MASK << 2 * bitm_off), CONFIG_UART_MOXA_MODE_REG); + vmode = opmode << 2 * bitm_off; + putreg32(getreg32(CONFIG_UART_MOXA_MODE_REG) | vmode, CONFIG_UART_MOXA_MODE_REG); irqrestore(flags); + ret = OK; break; } @@ -126,6 +153,7 @@ int uart_ioctl(struct file *filep, int cmd, unsigned long arg) irqrestore(flags); *(unsigned long *)arg = opmode; + ret = OK; break; } } diff --git a/arch/arm/src/moxart/moxart_irq.c b/arch/arm/src/moxart/moxart_irq.c index a29f5b2c4a8..4e8747b45c0 100644 --- a/arch/arm/src/moxart/moxart_irq.c +++ b/arch/arm/src/moxart/moxart_irq.c @@ -81,6 +81,8 @@ volatile uint32_t *current_regs; * Public Functions ****************************************************************************/ +extern void uart_decodeirq(int irq, uint32_t *regs); + /**************************************************************************** * Name: up_irqinitialize * @@ -93,6 +95,10 @@ void up_irqinitialize(void) { /* Prepare hardware */ + *(volatile int *)0x98700000 |= 0x3f; + + /* PMU setup */ + (*(volatile uint32_t *)0x98100008) &= ~0x9; while (!((*(volatile uint32_t *)0x98100008) & 0x2)) { ; } @@ -101,6 +107,8 @@ void up_irqinitialize(void) (*(volatile uint32_t *)0x98800100) = 0xDFF8003F; + /* Check board type */ + /* Mask all interrupts off */ putreg32(0, IRQ_REG(IRQ__MASK)); @@ -119,6 +127,11 @@ void up_irqinitialize(void) current_regs = NULL; + /* Setup UART shared interrupt */ + + irq_attach(CONFIG_UART_MOXA_SHARED_IRQ, uart_decodeirq); + up_enable_irq(CONFIG_UART_MOXA_SHARED_IRQ); + /* And finally, enable interrupts */ #if 1 diff --git a/arch/arm/src/moxart/moxart_timer.c b/arch/arm/src/moxart/moxart_timer.c index b085e631151..e2c115bee8a 100644 --- a/arch/arm/src/moxart/moxart_timer.c +++ b/arch/arm/src/moxart/moxart_timer.c @@ -132,9 +132,6 @@ void up_timer_initialize(void) uint32_t tmp; // up_disable_irq(IRQ_SYSTIMER); - - *(volatile int *)0x98700000 = 0x3f; - putreg32(0, TM1_ADDR + CNTL_TIMER); putreg32(0, TM1_ADDR + INTR_STATE_TIMER); putreg32(0x1ff, TM1_ADDR + INTR_MASK_TIMER); diff --git a/arch/arm/src/nuc1xx/chip/nuc_gcr.h b/arch/arm/src/nuc1xx/chip/nuc_gcr.h index c9ad2df98ad..065c3defbb2 100644 --- a/arch/arm/src/nuc1xx/chip/nuc_gcr.h +++ b/arch/arm/src/nuc1xx/chip/nuc_gcr.h @@ -356,7 +356,7 @@ # define GCR_REGWRPROT_2 (0x16) # define GCR_REGWRPROT_3 (0x88) /* Read: */ -#define GCR_REGWRPROT_DIS (1 << 0) /* Bit 0: Register write protectino disable index */ +#define GCR_REGWRPROT_DIS (1 << 0) /* Bit 0: Register write protection disable index */ /******************************************************************************************** * Public Types diff --git a/arch/arm/src/sam34/sam_dmac.c b/arch/arm/src/sam34/sam_dmac.c index 63b46ada61d..d9f31eb52db 100644 --- a/arch/arm/src/sam34/sam_dmac.c +++ b/arch/arm/src/sam34/sam_dmac.c @@ -1225,7 +1225,7 @@ static inline int sam_multiple(struct sam_dma_s *dmach) * Additionally, the CTRLA DONE bit is asserted when the buffer transfer has completed. * * The DMAC transfer continues until the CTRLB register disables the descriptor - * (DSCR bits) registers at the final buffer tranfer. + * (DSCR bits) registers at the final buffer transfer. * * Enable error, buffer complete and transfer complete interrupts. We * don't really need the buffer complete interrupts, but we will take them diff --git a/arch/arm/src/sam34/sam_irq.c b/arch/arm/src/sam34/sam_irq.c index 80f7b5af785..0c33e75f13b 100644 --- a/arch/arm/src/sam34/sam_irq.c +++ b/arch/arm/src/sam34/sam_irq.c @@ -78,7 +78,16 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; + +/* This is the address of the exception vector table (determined by the + * linker script). + */ + extern uint32_t _vectors[]; /**************************************************************************** @@ -378,16 +387,21 @@ void up_irqinitialize(void) } #endif - /* Set up the vector table address. - * - * If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#if defined(CONFIG_ARCH_RAMVECTORS) up_ramvec_initialize(); -#elif defined(CONFIG_SAM_BOOTLOADER) - putreg32((uint32_t)_vectors, NVIC_VECTAB); #endif /* Set all interrupts (and exceptions) to the default priority */ diff --git a/arch/arm/src/sam34/sam_udp.c b/arch/arm/src/sam34/sam_udp.c index b933a310d5a..a79c7502740 100644 --- a/arch/arm/src/sam34/sam_udp.c +++ b/arch/arm/src/sam34/sam_udp.c @@ -500,7 +500,7 @@ static const struct usb_epdesc_s g_ep0desc = .interval = 0 }; -/* Device error strings that may be enabled for more desciptive USB trace +/* Device error strings that may be enabled for more descriptive USB trace * output. */ @@ -540,7 +540,7 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] = }; #endif -/* Interrupt event strings that may be enabled for more desciptive USB trace +/* Interrupt event strings that may be enabled for more descriptive USB trace * output. */ diff --git a/arch/arm/src/sama5/sam_can.c b/arch/arm/src/sama5/sam_can.c index aa4a3255de7..b201d88a559 100644 --- a/arch/arm/src/sama5/sam_can.c +++ b/arch/arm/src/sama5/sam_can.c @@ -733,7 +733,10 @@ static int can_recvsetup(FAR struct sam_can_s *priv) canvdbg("CAN%d Mailbox %d: Index=%d rxmbset=%02x\n", config->port, mbno, mbndx, priv->rxmbset); - /* Set up the message ID and filter mask */ + /* Set up the message ID and filter mask + * REVISIT: This logic should be capable of setting up standard + * filters when CONFIG_CAN_EXTID is selected. + */ #ifdef CONFIG_CAN_EXTID can_putreg(priv, SAM_CAN_MnID_OFFSET(mbndx), @@ -1125,14 +1128,16 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) canvdbg("Mailbox Index=%d txmbset=%02x\n", mbndx, priv->txmbset); - /* Set up the ID and mask, standard 11-bit or extended 29-bit. */ + /* Set up the ID and mask, standard 11-bit or extended 29-bit. + * REVISIT: This logic should be capable of sending standard messages + * when CONFIG_CAN_EXTID is selected. + */ #ifdef CONFIG_CAN_EXTID DEBUGASSERT(msg->cm_hdr.ch_extid); DEBUGASSERT(msg->cm_hdr.ch_id < (1 << 29)); can_putreg(priv, SAM_CAN_MnID_OFFSET(mbndx), CAN_MID_EXTID(msg->cm_hdr.ch_id)); #else - DEBUGASSERT(!msg->cm_hdr.ch_extid); DEBUGASSERT(msg->cm_hdr.ch_id < (1 << 11)); can_putreg(priv, SAM_CAN_MnID_OFFSET(mbndx), CAN_MID_STDID(msg->cm_hdr.ch_id)); #endif @@ -1309,24 +1314,27 @@ static inline void can_rxinterrupt(FAR struct can_dev_s *dev, int mbndx, mid = can_getreg(priv, SAM_CAN_MnID_OFFSET(mbndx)); - /* Format the CAN header */ + /* Format the CAN header. + * REVISIT: This logic should be capable of receiving standard messages + * when CONFIG_CAN_EXTID is selected. + */ #ifdef CONFIG_CAN_EXTID /* Save the extended ID of the newly received message */ hdr.ch_id = (mid & CAN_MAM_EXTID_MASK) >> CAN_MAM_EXTID_SHIFT; - hdr.ch_dlc = (msr & CAN_MSR_MDLC_MASK) >> CAN_MSR_MDLC_SHIFT; - hdr.ch_rtr = 0; hdr.ch_extid = true; - hdr.ch_unused = 0; #else /* Save the standard ID of the newly received message */ - hdr.ch_dlc = (msr & CAN_MSR_MDLC_MASK) >> CAN_MSR_MDLC_SHIFT; - hdr.ch_rtr = 0; hdr.ch_id = (mid & CAN_MAM_STDID_MASK) >> CAN_MAM_STDID_SHIFT; #endif + hdr.ch_dlc = (msr & CAN_MSR_MDLC_MASK) >> CAN_MSR_MDLC_SHIFT; + hdr.ch_rtr = 0; + hdr.ch_error = 0; + hdr.ch_unused = 0; + /* And provide the CAN message to the upper half logic */ ret = can_receive(dev, &hdr, (FAR uint8_t *)md); diff --git a/arch/arm/src/sama5/sam_dmac.c b/arch/arm/src/sama5/sam_dmac.c index f248d58937c..300c4e11f4f 100644 --- a/arch/arm/src/sama5/sam_dmac.c +++ b/arch/arm/src/sama5/sam_dmac.c @@ -1721,7 +1721,7 @@ static inline int sam_multiple(struct sam_dmach_s *dmach) * buffer transfer has completed. * * The DMAC transfer continues until the CTRLB register disables the - * descriptor (DSCR bits) registers at the final buffer tranfer. + * descriptor (DSCR bits) registers at the final buffer transfer. * * Enable error, buffer complete and transfer complete interrupts. We * don't really need the buffer complete interrupts, but we will take them @@ -2309,7 +2309,7 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) dmach->callback = callback; dmach->arg = arg; - /* Is this a single block transfer? Or a multiple block tranfer? */ + /* Is this a single block transfer? Or a multiple block transfer? */ if (dmach->llhead == dmach->lltail) { diff --git a/arch/arm/src/sama5/sam_udphs.c b/arch/arm/src/sama5/sam_udphs.c index 7d4d700cd97..e5791f4af91 100644 --- a/arch/arm/src/sama5/sam_udphs.c +++ b/arch/arm/src/sama5/sam_udphs.c @@ -555,7 +555,7 @@ static const struct usb_epdesc_s g_ep0desc = #ifdef CONFIG_SAMA5_UDPHS_SCATTERGATHER #ifdef CONFIG_SAMA5_UDPHS_PREALLOCATE -/* This is a properly aligned pool of preallocated DMA transfer desciptors */ +/* This is a properly aligned pool of preallocated DMA transfer descriptors */ static struct sam_dtd_s g_dtdpool[CONFIG_SAMA5_UDPHS_NDTDS] __attribute__ ((aligned(16))); @@ -563,7 +563,7 @@ static struct sam_dtd_s g_dtdpool[CONFIG_SAMA5_UDPHS_NDTDS] #endif -/* Device error strings that may be enabled for more desciptive USB trace +/* Device error strings that may be enabled for more descriptive USB trace * output. */ @@ -604,7 +604,7 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] = }; #endif -/* Interrupt event strings that may be enabled for more desciptive USB trace +/* Interrupt event strings that may be enabled for more descriptive USB trace * output. */ @@ -1280,7 +1280,7 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, * When a request is queued, the request 'len' is the number of bytes * to transfer and 'xfrd' and 'inflight' must be zero. * - * When this function starts a tranfer it will update the request + * When this function starts a transfer it will update the request * 'inflight' field to indicate the size of the transfer. * * When the transfer completes, the the 'inflight' field must hold the @@ -1547,7 +1547,7 @@ static void sam_req_rddisable(uint8_t epno) * - When receiving data via DMA, then data has already been transferred * and this function is called on the terminating event. The transfer * is complete and we just need to check for end of request events and - * if we need to setup the tranfer for the next request. + * if we need to setup the transfer for the next request. * - When receiving via the FIFO, the transfer is not complete. The * data is in the FIFO and must be transferred from the FIFO to the * request buffer. No setup is needed for the next transfer other than diff --git a/arch/arm/src/sama5/sam_xdmac.c b/arch/arm/src/sama5/sam_xdmac.c index ba3af1b2675..2936dec8d95 100644 --- a/arch/arm/src/sama5/sam_xdmac.c +++ b/arch/arm/src/sama5/sam_xdmac.c @@ -2355,7 +2355,7 @@ int sam_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg) xdmach->callback = callback; xdmach->arg = arg; - /* Is this a single block transfer? Or a multiple block tranfer? */ + /* Is this a single block transfer? Or a multiple block transfer? */ if (xdmach->llhead == xdmach->lltail) { diff --git a/arch/arm/src/samdl/chip/saml_eic.h b/arch/arm/src/samdl/chip/saml_eic.h index fca13fe45fc..e6bb167e2eb 100644 --- a/arch/arm/src/samdl/chip/saml_eic.h +++ b/arch/arm/src/samdl/chip/saml_eic.h @@ -106,7 +106,7 @@ # define EIC_NVMICTRL_NMISENSE_HIGH (4 << EIC_NVMICTRL_NMISENSE_SHIFT) /* High level detection */ # define EIC_NVMICTRL_NMISENSE_LOW (5 << EIC_NVMICTRL_NMISENSE_SHIFT) /* Low level detection */ #define EIC_NVMICTRL_NMIFLTEN (1 << 3) /* Bit 3: Non-maskable interrupt filter enable */ -#define EIC_NVMICTRL_ASYNC (1 << 4) /* Bit 4: Asynchronous edge detectino mode */ +#define EIC_NVMICTRL_ASYNC (1 << 4) /* Bit 4: Asynchronous edge detection mode */ /* Non-maskable interrupt flas status and clear register */ diff --git a/arch/arm/src/samdl/sam_lowputc.c b/arch/arm/src/samdl/sam_lowputc.c index a8b4d117623..fcc512279d7 100644 --- a/arch/arm/src/samdl/sam_lowputc.c +++ b/arch/arm/src/samdl/sam_lowputc.c @@ -296,6 +296,9 @@ sam_pad_configure(const struct sam_usart_config_s * const config) #ifdef SAMDL_HAVE_USART int sam_usart_internal(const struct sam_usart_config_s * const config) { +#ifdef CONFIG_ARCH_FAMILY_SAML21 + int channel; +#endif int ret; /* Enable clocking to the SERCOM module */ @@ -306,10 +309,20 @@ int sam_usart_internal(const struct sam_usart_config_s * const config) #if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) sercom_coreclk_configure(config->sercom, config->gclkgen, false); + #elif defined(CONFIG_ARCH_FAMILY_SAML21) - sam_gclk_chan_enable(config->sercom + GCLK_CHAN_SERCOM0_CORE, - config->gclkgen); + if (config->sercom == 5) + { + channel = GCLK_CHAN_SERCOM5_CORE; + } + else + { + channel = config->sercom + GCLK_CHAN_SERCOM0_CORE; + } + + sam_gclk_chan_enable(channel, config->gclkgen); #endif + sercom_slowclk_configure(config->sercom, config->slowgen); /* Set USART configuration according to the board configuration */ diff --git a/arch/arm/src/samdl/sam_port.c b/arch/arm/src/samdl/sam_port.c index dddc7a1ae9e..b8445c7f1af 100644 --- a/arch/arm/src/samdl/sam_port.c +++ b/arch/arm/src/samdl/sam_port.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/samdl/sam_port.c * - * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: @@ -94,7 +94,7 @@ static inline uintptr_t sam_portbase(port_pinset_t pinset) * Name: sam_portpin * * Description: - * Returun the base address of the PORT register set + * Return the bit associated with the pin * ****************************************************************************/ @@ -330,7 +330,7 @@ static inline void sam_configperiph(uintptr_t base, port_pinset_t pinset) regval |= PORT_WRCONFIG_INEN; } - if (pin > 16) + if (pin >= 16) { /* Select the upper half word and adjust the bit setting */ @@ -538,15 +538,15 @@ int sam_dumpport(uint32_t pinset, const char *msg) /* Get the base address associated with the PIO port */ - pin = sam_portpin(pinset); + pin = (pinset & PORT_PIN_MASK) >> PORT_PIN_SHIFT; port = (pinset & PORT_MASK) >> PORT_SHIFT; base = SAM_PORTN_BASE(port); /* The following requires exclusive access to the PORT registers */ flags = irqsave(); - lldbg("PORT%c pinset: %08x base: %08x -- %s\n", - g_portchar[port], pinset, base, msg); + lldbg("PORT%c pin: %d pinset: %08x base: %08x -- %s\n", + g_portchar[port], pin, pinset, base, msg); lldbg(" DIR: %08x OUT: %08x IN: %08x\n", getreg32(base + SAM_PORT_DIR_OFFSET), getreg32(base + SAM_PORT_OUT_OFFSET), diff --git a/arch/arm/src/samdl/sam_port.h b/arch/arm/src/samdl/sam_port.h index d40c9246a41..26ba8bcb5d3 100644 --- a/arch/arm/src/samdl/sam_port.h +++ b/arch/arm/src/samdl/sam_port.h @@ -380,7 +380,7 @@ bool sam_portread(port_pinset_t pinset); ****************************************************************************/ #ifdef CONFIG_DEBUG -void sam_dumpport(port_pinset_t pinset, const char *msg); +int sam_dumpport(port_pinset_t pinset, const char *msg); #else # define sam_dumpport(p,m) #endif diff --git a/arch/arm/src/samdl/sam_spi.c b/arch/arm/src/samdl/sam_spi.c index a90737debac..bbbfb55101b 100644 --- a/arch/arm/src/samdl/sam_spi.c +++ b/arch/arm/src/samdl/sam_spi.c @@ -1467,6 +1467,9 @@ struct spi_dev_s *up_spiinitialize(int port) struct sam_spidev_s *priv; irqstate_t flags; uint32_t regval; +#ifdef CONFIG_ARCH_FAMILY_SAML21 + int channel; +#endif #if 0 /* Not used */ int ret; #endif @@ -1534,7 +1537,22 @@ struct spi_dev_s *up_spiinitialize(int port) /* Configure the GCLKs for the SERCOM module */ +#if defined(CONFIG_ARCH_FAMILY_SAMD20) || defined(CONFIG_ARCH_FAMILY_SAMD21) sercom_coreclk_configure(priv->sercom, priv->gclkgen, false); + +#elif defined(CONFIG_ARCH_FAMILY_SAML21) + if (priv->sercom == 5) + { + channel = GCLK_CHAN_SERCOM5_CORE; + } + else + { + channel = priv->sercom + GCLK_CHAN_SERCOM0_CORE; + } + + sam_gclk_chan_enable(channel, config->gclkgen); +#endif + sercom_slowclk_configure(priv->sercom, priv->slowgen); /* Set the SERCOM in SPI master mode (no address) */ diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 75540fe2230..086a8a31a73 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -65,7 +65,7 @@ config ARCH_CHIP_SAMV71Q bool default n select ARCH_CHIP_SAMV71 - select SAMV7_HAVE_CAN1 + select SAMV7_HAVE_MCAN1 select SAMV7_HAVE_DAC1 select SAMV7_HAVE_EBI select SAMV7_HAVE_HSMCI0 @@ -82,7 +82,7 @@ config ARCH_CHIP_SAMV71N bool default n select ARCH_CHIP_SAMV71 - select SAMV7_HAVE_CAN1 + select SAMV7_HAVE_MCAN1 select SAMV7_HAVE_DAC1 select SAMV7_HAVE_HSMCI0 select SAMV7_HAVE_SPI0 @@ -102,7 +102,11 @@ config ARCH_CHIP_SAMV71J # Chip Capabilities -config SAMV7_HAVE_CAN1 +config SAMV7_MCAN + bool + default n + +config SAMV7_HAVE_MCAN1 bool default n @@ -143,10 +147,6 @@ config SAMV7_HAVE_SDRAMC bool default n -config SAMV7_HAVE_SPI - bool - default n - config SAMV7_HAVE_SPI0 bool default n @@ -187,6 +187,18 @@ config SAMV7_HAVE_USART2 bool default n +config SAMV7_SPI + bool + default n + +config SAMV7_SPI_MASTER + bool + default n + +config SAMV7_SPI_SLAVE + bool + default n + # Peripheral Selection menu "SAMV7 Peripheral Selection" @@ -207,14 +219,18 @@ config SAMV7_AFEC1 bool "Analog Front End 1 (AFEC1)" default n -config SAMV7_CAN0 - bool "CAN0" +config SAMV7_MCAN0 + bool "CAN controller 0 (MCAN0)" default n + select CAN + select SAMV7_MCAN -config SAMV7_CAN1 - bool "CAN1" +config SAMV7_MCAN1 + bool "CAN controller 1 (MCAN1)" default n - depends on SAMV7_HAVE_CAN1 + depends on SAMV7_HAVE_MCAN1 + select CAN + select SAMV7_MCAN config SAMV7_DAC0 bool "Digital To Analog Converter 0 (DAC0)" @@ -291,14 +307,14 @@ config SAMV7_SPI0 bool "Serial Peripheral Interface 0 (SPI0)" default n depends on SAMV7_HAVE_SPI0 - select SAMV7_HAVE_SPI + select SAMV7_SPI select SPI config SAMV7_SPI1 bool "Serial Peripheral Interface 1 (SPI1)" default n depends on SAMV7_HAVE_SPI1 - select SAMV7_HAVE_SPI + select SAMV7_SPI select SPI config SAMV7_SSC0 @@ -518,8 +534,51 @@ config SAMV7_SDRAMHEAP endmenu # SDRAM Configuration -menu "SAMV7 SPI device driver options" - depends on AMV7_SPI0 || SAMV7_SPI1 +menu "SPI Device Driver Configuration" + depends on SAMV7_SPI + +choice + prompt "SPI0 Configuration" + default SAMV7_SPI0_MASTER + depends on SAMV7_SPI0 + +config SAMV7_SPI0_MASTER + bool "Master" + select SAMV7_SPI_MASTER + ---help--- + Configure SPI0 as an SPI master driver. Default: Master + +config SAMV7_SPI0_SLAVE + bool "Slave" + depends on EXPERIMENTAL + select SAMV7_SPI_SLAVE + ---help--- + Configure SPI0 as an SPI slave driver. Default: Master + +endchoice # SPI0 Configuration + +choice + prompt "SPI1 Configuration" + default SAMV7_SPI1_MASTER + depends on SAMV7_SPI1 + +config SAMV7_SPI1_MASTER + bool "Master" + select SAMV7_SPI_MASTER + ---help--- + Configure SPI1 as an SPI master driver. Default: Master + +config SAMV7_SPI1_SLAVE + bool "Slave" + depends on EXPERIMENTAL + select SAMV7_SPI_SLAVE + ---help--- + Configure SPI1 as an SPI slave driver. Default: Master + +endchoice # SPI1 Configuration + +if SAMV7_SPI_MASTER +comment "SPI Master Configuration" config SAMV7_SPI_DMA bool "SPI DMA" @@ -547,6 +606,20 @@ config SAMV7_SPI_DMADEBUG registers at key points in the data transfer and then dumps all of the registers at the end of the transfer. +endif # SAMV7_SPI_MASTER + +if SAMV7_SPI_SLAVE +comment "SPI Slave Configuration" + +config SAMV7_SPI_SLAVE_QSIZE + int "Output queue size" + default 8 + ---help--- + The number of words that an be retained in the controller driver's + output queue. + +endif # SAMV7_SPI_SLAVE + config SAMV7_SPI_REGDEBUG bool "SPI Register level debug" depends on DEBUG @@ -729,7 +802,7 @@ config SAMV7_SSC0_TX_FSLEN default 1 range 0 255 ---help--- - This setting define the length of the Transmit Frame Sync signal in + This setting defines the length of the Transmit Frame Sync signal in units of transmit clock periods. A value of zero disables this feature. In that case the TD line is driven with the default value during the Transmit Frame Sync signal. @@ -901,7 +974,7 @@ config SAMV7_SSC1_TX_FSLEN default 1 range 0 255 ---help--- - This setting define the length of the Transmit Frame Sync signal in + This setting defines the length of the Transmit Frame Sync signal in units of transmit clock periods. A value of zero disables this feature. In that case the TD line is driven with the default value during the Transmit Frame Sync signal. @@ -1256,7 +1329,6 @@ menu "USB High Speed Device Controller driver (DCD) options" config SAMV7_USBDEVHS_LOWPOWER bool "Low-power mode" default n - depends on EXPERIMENTAL ---help--- The USBHS can work in two modes: @@ -1264,7 +1336,9 @@ config SAMV7_USBDEVHS_LOWPOWER available. - Low-power mode where only Full speed and Low speed are available. - This options selects the low-power mode. + This options selects the low-power mode. In order to use high speed + mode, this option must be disabled and USBDEV_DUALSPEED must be + enabled. config SAMV7_USBHS_SCATTERGATHER bool @@ -1296,3 +1370,679 @@ config SAMV7_USBHS_REGDEBUG depends on DEBUG endmenu # USB High Speed Device Controller driver (DCD) options + +if SAMV7_MCAN + +menu "MCAN device driver options" + +choice + prompt "MCAN clock source (PCK5)" + default SAMV7_MCAN_CLKSRC_MCK + +config SAMV7_MCAN_CLKSRC_SLOW + bool "Slow clock" + +config SAMV7_MCAN_CLKSRC_MAIN + bool "Main clock" + +config SAMV7_MCAN_CLKSRC_PLLA + bool "PLLA clock" + +config SAMV7_MCAN_CLKSRC_UPLL + bool "UPLL clock" + +config SAMV7_MCAN_CLKSRC_MCK + bool "Master clock" + +endchoice # MCAN clock source + +config SAMV7_MCAN_CLKSRC_PRESCALER + int "MCAN clock prescaler" + default 1 + range 1 1024 + ---help--- + The frequency associated with time quanta is derived by dividing + down the input frequency. This setting provides prescaler/divider + must lie the range of 1 to 1024. + +menu "MCAN0 device driver options" + depends on SAMV7_MCAN0 + +choice + prompt "MCAN0 mode" + default SAMV7_MCAN0_ISO11899_1 + +config SAMV7_MCAN0_ISO11899_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 mode + +config SAMV7_MCAN0_FD + bool "FD" + depends on CAN_FD + ---help--- + Enable FD mode + +config SAMV7_MCAN0_FD_BSW + bool "FD with fast bit rate switching" + depends on CAN_FD + ---help--- + Enable FD mode with fast bit rate switching mode. + +endchoice # MCAN0 mode + +config SAMV7_MCAN0_LOOPBACK + bool "Enable MCAN0 loopback mode" + default n + ---help--- + Enable the MCAN0 local loopback mode for testing purposes. + +config SAMV7_MCAN0_BITRATE + int "MCAN0 bitrate" + default 500000 + ---help--- + MCAN0 bitrate in bits per second. Required if SAMV7_MCAN0 is defined. + +config SAMV7_MCAN0_PROPSEG + int "MCAN0 PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN0_PHASESEG1 + int "MCAN0 PhaseSeg1" + default 11 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN0_PHASESEG2 + int "MCAN0 PhaseSeg2" + default 11 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN0_FSJW + int "MCAN0 synchronization jump width" + default 4 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMV7_MCAN0_FBITRATE + int "MCAN0 fast bitrate" + default 2000000 + ---help--- + MCAN0 bitrate in bits per second. Required if SAMV7_MCAN0 is + defined. + +config SAMV7_MCAN0_FPROPSEG + int "MCAN0 fast PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN0_FPHASESEG1 + int "MCAN0 fast PhaseSeg1" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN0_FPHASESEG2 + int "MCAN0 fast PhaseSeg2" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN0_FFSJW + int "MCAN0 fast synchronization jump width" + default 2 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMV7_MCAN0_NSTDFILTERS + int "MCAN0 number of standard filters" + default 8 + range 0 128 + ---help--- + Number of standard message ID filters. + +config SAMV7_MCAN0_NEXTFILTERS + int "MCAN0 number of extended filters" + default 8 + range 0 64 + depends on CAN_EXTID + ---help--- + Number of extended message ID filters. + +choice + prompt "MCAN0 RX FIFO0 element size" + default SAMV7_MCAN0_RXFIFO0_8BYTES + +config SAMV7_MCAN0_RXFIFO0_8BYTES + bool "8 bytes" + +config SAMV7_MCAN0_RXFIFO0_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO0_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO0_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO0_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO0_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO0_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO0_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN0_FD + +endchoice # MCAN0 RX buffer element size + +config SAMV7_MCAN0_RXFIFO0_SIZE + int "MCAN0 RX FIFO0 size" + default 8 + range 1 64 + ---help--- + Number of receive FIFO 0 elements. Zero disables FIFO 0. + +choice + prompt "MCAN0 RX FIFO1 element size" + default SAMV7_MCAN0_RXFIFO1_8BYTES + +config SAMV7_MCAN0_RXFIFO1_8BYTES + bool "8 bytes" + +config SAMV7_MCAN0_RXFIFO1_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO1_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO1_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO1_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO1_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO1_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXFIFO1_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN0_FD + +endchoice # MCAN0 RX buffer element size + +config SAMV7_MCAN0_RXFIFO1_SIZE + int "MCAN0 RX FIFO1 size" + default 4 + range 1 64 + ---help--- + Number of receive FIFO 1 elements for MCAN0. Zero disables FIFO 1. + +choice + prompt "MCAN0 RX buffer element size" + default SAMV7_MCAN0_RXBUFFER_8BYTES + +config SAMV7_MCAN0_RXBUFFER_8BYTES + bool "8 bytes" + +config SAMV7_MCAN0_RXBUFFER_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXBUFFER_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXBUFFER_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXBUFFER_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXBUFFER_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXBUFFER_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_RXBUFFER_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN0_FD + +endchoice # MCAN0 RX buffer element size + +config SAMV7_MCAN0_DEDICATED_RXBUFFER_SIZE + int "MCAN0 dedicated RX buffer size" + default 0 + range 0 64 + depends on EXPERIMENTAL + ---help--- + Number of dedicated RX buffer elements for MCAN0. + + NOTE: Dedicated RX buffers are not used in the current MCAN design. + +choice + prompt "MCAN0 TX buffer element size" + default SAMV7_MCAN0_TXBUFFER_8BYTES + +config SAMV7_MCAN0_TXBUFFER_8BYTES + bool "8 bytes" + +config SAMV7_MCAN0_TXBUFFER_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_TXBUFFER_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_TXBUFFER_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_TXBUFFER_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_TXBUFFER_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_TXBUFFER_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN0_FD + +config SAMV7_MCAN0_TXBUFFER_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN0_FD + +endchoice # MCAN0 TX buffer element size + +config SAMV7_MCAN0_DEDICATED_TXBUFFER_SIZE + int "MCAN0 dedicated TX buffer size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of dedicated TX buffer elements for MCAN0. + + NOTE: Dedicated TX buffers are not used in the current MCAN design. + +config SAMV7_MCAN0_TXFIFOQ_SIZE + int "MCAN0 TX FIFO queue size" + default 4 + range 1 32 + ---help--- + Number of dedicated TX buffer elements for MCAN0. + +config SAMV7_MCAN0_TXEVENTFIFO_SIZE + int "MCAN0 TX event FIFO size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of TX event FIFO elements for MCAN0. Zero disables TX event FIFO. + +endmenu # MCAN0 device driver options + +menu "MCAN1 device driver options" + depends on SAMV7_MCAN1 + +choice + prompt "MCAN1 mode" + default SAMV7_MCAN1_ISO11899_1 + +config SAMV7_MCAN1_ISO11899_1 + bool "ISO11898-1" + ---help--- + Enable ISO11898-1 mode + +config SAMV7_MCAN1_FD + bool "FD" + depends on CAN_FD + ---help--- + Enable FD mode + +config SAMV7_MCAN1_FD_BSW + bool "FD with fast bit rate switching" + depends on CAN_FD + ---help--- + Enable FD mode with fast bit rate switching mode. + +endchoice # MCAN0 mode + +config SAMV7_MCAN1_LOOPBACK + bool "Enable MCAN1 loopback mode" + default n + ---help--- + Enable the MCAN1 local loopback mode for testing purposes. + +config SAMV7_MCAN1_BITRATE + int "MCAN1 bitrate" + default 500000 + ---help--- + MCAN1 bitrate in bits per second. Required if SAMV7_MCAN1 is + defined. + +config SAMV7_MCAN1_PROPSEG + int "MCAN1 PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN1_PHASESEG1 + int "MCAN1 PhaseSeg1" + default 11 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN1_PHASESEG2 + int "MCAN1 PhaseSeg2" + default 11 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN1_FSJW + int "MCAN1 synchronization jump width" + default 4 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMV7_MCAN1_FBITRATE + int "MCAN1 fast bitrate" + default 2000000 + ---help--- + MCAN1 bitrate in bits per second. Required if SAMV7_MCAN1 is + defined. + +config SAMV7_MCAN1_FPROPSEG + int "MCAN1 fast PropSeg" + default 2 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN1_FPHASESEG1 + int "MCAN1 fast PhaseSeg1" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN1_FPHASESEG2 + int "MCAN1 fast PhaseSeg2" + default 4 + range 1 63 + ---help--- + The length of the bit time is Tquanta * (SyncSeg + PropSeg + PhaseSeg1 + PhaseSeg2). + +config SAMV7_MCAN1_FFSJW + int "MCAN1 fast synchronization jump width" + default 2 + range 1 5 + ---help--- + The duration of a synchronization jump is Tcan_clk x FSJW. + +config SAMV7_MCAN1_NSTDFILTERS + int "MCAN1 number of standard filters" + default 8 + range 0 128 + ---help--- + Number of standard message ID filters. + +config SAMV7_MCAN1_NEXTFILTERS + int "MCAN1 number of extended filters" + default 8 + range 0 64 + depends on CAN_EXTID + ---help--- + Number of extended message ID filters. + +choice + prompt "MCAN1 RX FIFO0 element size" + default SAMV7_MCAN1_RXFIFO0_8BYTES + +config SAMV7_MCAN1_RXFIFO0_8BYTES + bool "8 bytes" + +config SAMV7_MCAN1_RXFIFO0_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO0_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO0_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO0_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO0_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO0_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO0_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN1_FD + +endchoice # MCAN1 RX buffer element size + +config SAMV7_MCAN1_RXFIFO0_SIZE + int "MCAN1 RX FIFO0 size" + default 8 + range 1 64 + ---help--- + Number of receive FIFO 0 elements. Zero disables FIFO 0. + +choice + prompt "MCAN1 RX FIFO1 element size" + default SAMV7_MCAN1_RXFIFO1_8BYTES + +config SAMV7_MCAN1_RXFIFO1_8BYTES + bool "8 bytes" + +config SAMV7_MCAN1_RXFIFO1_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO1_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO1_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO1_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO1_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO1_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXFIFO1_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN1_FD + +endchoice # MCAN1 RX buffer element size + +config SAMV7_MCAN1_RXFIFO1_SIZE + int "MCAN1 RX FIFO1 size" + default 4 + range 1 64 + ---help--- + Number of receive FIFO 1 elements for MCAN1. Zero disables FIFO 1. + +choice + prompt "MCAN1 RX buffer element size" + default SAMV7_MCAN1_RXBUFFER_8BYTES + +config SAMV7_MCAN1_RXBUFFER_8BYTES + bool "8 bytes" + +config SAMV7_MCAN1_RXBUFFER_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXBUFFER_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXBUFFER_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXBUFFER_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXBUFFER_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXBUFFER_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_RXBUFFER_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN1_FD + +endchoice # MCAN1 RX buffer element size + +config SAMV7_MCAN1_DEDICATED_RXBUFFER_SIZE + int "MCAN1 dedicated RX buffer size" + default 0 + range 0 64 + depends on EXPERIMENTAL + ---help--- + Number of dedicated RX buffer elements for MCAN1. + + NOTE: Dedicated RX buffers are not used in the current MCAN design. + +choice + prompt "MCAN1 TX buffer element size" + default SAMV7_MCAN1_TXBUFFER_8BYTES + +config SAMV7_MCAN1_TXBUFFER_8BYTES + bool "8 bytes" + +config SAMV7_MCAN1_TXBUFFER_12BYTES + bool "12 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_TXBUFFER_16BYTES + bool "16 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_TXBUFFER_20BYTES + bool "20 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_TXBUFFER_24BYTES + bool "24 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_TXBUFFER_32BYTES + bool "32 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_TXBUFFER_48BYTES + bool "48 bytes" + depends on SAMV7_MCAN1_FD + +config SAMV7_MCAN1_TXBUFFER_64BYTES + bool "64 bytes" + depends on SAMV7_MCAN1_FD + +endchoice # MCAN1 TX buffer element size + +config SAMV7_MCAN1_TXEVENTFIFO_SIZE + int "MCAN1 TX event FIFO size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of TX event FIFO elements for MCAN1. Zero disables TX event FIFO. + +config SAMV7_MCAN1_DEDICATED_TXBUFFER_SIZE + int "MCAN1 dedicated TX buffer size" + default 0 + range 0 32 + depends on EXPERIMENTAL + ---help--- + Number of dedicated TX buffer elements for MCAN1. + + NOTE: Dedicated TX buffers are not used in the current MCAN design. + +config SAMV7_MCAN1_TXFIFOQ_SIZE + int "MCAN1 TX FIFO queue" + default 4 + range 1 32 + ---help--- + Number of dedicated TX buffer elements for MCAN1. + +endmenu # MCAN1 device driver options + +config SAMV7_MCAN_REGDEBUG + bool "CAN Register level debug" + depends on DEBUG + default n + ---help--- + Output detailed register-level CAN device debug information. + Requires also DEBUG. + +endmenu # CAN device driver options +endif # SAMV7_MCAN diff --git a/arch/arm/src/samv7/Make.defs b/arch/arm/src/samv7/Make.defs index 24ca0488207..a6c7a6a9595 100644 --- a/arch/arm/src/samv7/Make.defs +++ b/arch/arm/src/samv7/Make.defs @@ -124,12 +124,18 @@ ifeq ($(CONFIG_SAMV7_XDMAC),y) CHIP_CSRCS += sam_xdmac.c endif -ifeq ($(CONFIG_SAMV7_SPI0),y) -CHIP_CSRCS += sam_spi.c -else ifeq ($(CONFIG_SAMV7_SPI1),y) +ifeq ($(CONFIG_SAMV7_SPI_MASTER),y) CHIP_CSRCS += sam_spi.c endif +ifeq ($(CONFIG_SAMV7_SPI_SLAVE),y) +CHIP_CSRCS += sam_spi_slave.c +endif + +ifeq ($(CONFIG_SAMV7_QSPI),y) +CHIP_CSRCS += sam_qspi.c +endif + ifeq ($(CONFIG_SAMV7_TWIHS0),y) CHIP_CSRCS += sam_twihs.c else ifeq ($(CONFIG_SAMV7_TWIHS1),y) @@ -150,6 +156,10 @@ ifeq ($(CONFIG_SAMV7_EMAC),y) CHIP_CSRCS += sam_emac.c sam_ethernet.c endif +ifeq ($(CONFIG_SAMV7_MCAN),y) +CHIP_CSRCS += sam_mcan.c +endif + ifeq ($(CONFIG_SAMV7_USBDEVHS),y) CHIP_CSRCS += sam_usbdevhs.c endif diff --git a/arch/arm/src/samv7/chip/sam_matrix.h b/arch/arm/src/samv7/chip/sam_matrix.h index 567e900a4dd..e399ef3cc12 100644 --- a/arch/arm/src/samv7/chip/sam_matrix.h +++ b/arch/arm/src/samv7/chip/sam_matrix.h @@ -258,6 +258,7 @@ /* CAN0 Configuration Register */ +#define MATRIX_CAN0_RESERVED 0x000001ff /* Bits 0-9: Reserved */ #define MATRIX_CAN0_CAN0DMABA_MASK 0xffff0000 /* Bits 16-31: CAN0 DMA Base Address */ /* System I/O and CAN1 Configuration Register */ @@ -268,7 +269,7 @@ # define MATRIX_CCFG_SYSIO_SYSIO6 (1 << 6) /* Bit 6: PB6 or TMS/SWDIO Assignment */ # define MATRIX_CCFG_SYSIO_SYSIO7 (1 << 7) /* Bit 7: PB7 or TCK/SWCLK Assignment */ # define MATRIX_CCFG_SYSIO_SYSIO12 (1 << 12) /* Bit 12: PB12 or ERASE Assignment */ -#define MATRIX_CAN0_CAN1DMABA_MASK 0xffff0000 /* Bits 16-31: CAN1 DMA Base Address */ +#define MATRIX_CCFG_CAN1DMABA_MASK 0xffff0000 /* Bits 16-31: CAN1 DMA Base Address */ /* SMC Chip Select NAND Flash Assignment Register */ diff --git a/arch/arm/src/samv7/chip/sam_mcan.h b/arch/arm/src/samv7/chip/sam_mcan.h index 64ccf23c9c9..b3951aef703 100644 --- a/arch/arm/src/samv7/chip/sam_mcan.h +++ b/arch/arm/src/samv7/chip/sam_mcan.h @@ -67,7 +67,7 @@ #define SAM_MCAN_ECR_OFFSET 0x0040 /* Error Counter Register */ #define SAM_MCAN_PSR_OFFSET 0x0044 /* Protocol Status Register */ /* 0x0048-0x004c Reserved */ -#define SAM_MCAN_IR_OFFSET 0x0050 /* Interrupt Register*/ +#define SAM_MCAN_IR_OFFSET 0x0050 /* Interrupt Register*/ #define SAM_MCAN_IE_OFFSET 0x0054 /* Interrupt Enable Register */ #define SAM_MCAN_ILS_OFFSET 0x0058 /* Interrupt Line Select Register */ #define SAM_MCAN_ILE_OFFSET 0x005c /* Interrupt Line Enable Register */ @@ -214,7 +214,7 @@ #define MCAN_FBTP_FBRP_SHIFT (16) /* Bits 16-20: Fast Baud Rate Prescaler */ #define MCAN_FBTP_FBRP_MASK (31 << MCAN_FBTP_FBRP_SHIFT) # define MCAN_FBTP_FBRP(n) ((uint32_t)(n) << MCAN_FBTP_FBRP_SHIFT) -#define MCAN_FBTP_TDCO (1 << 23) /* Bit: 23: Transceiver Delay Compensation */ +#define MCAN_FBTP_TDC (1 << 23) /* Bit: 23: Transceiver Delay Compensation */ #define MCAN_FBTP_TDCO_SHIFT (24) /* Bits 24-28: Transceiver Delay Compensation Offset */ #define MCAN_FBTP_TDCO_MASK (31 << MCAN_FBTP_TDC_SHIFT) # define MCAN_FBTP_TDCO(n) ((uint32_t)(n) << MCAN_FBTP_TDC_SHIFT) @@ -360,7 +360,7 @@ /* Common bit definitions for Interrupt Register, Interrupt Enable Register, Interrupt * Line Select Register - */ + */ #define MCAN_INT_RF0N (1 << 0) /* Bit 0: Receive FIFO 0 New Message */ #define MCAN_INT_RF0W (1 << 1) /* Bit 1: Receive FIFO 0 Watermark Reached */ @@ -370,7 +370,7 @@ #define MCAN_INT_RF1W (1 << 5) /* Bit 5: Receive FIFO 1 Watermark Reached */ #define MCAN_INT_RF1F (1 << 6) /* Bit 6: Receive FIFO 1 Full */ #define MCAN_INT_RF1L (1 << 7) /* Bit 7: Receive FIFO 1 Message Lost */ -#define MCAN_INT_HPM (1 << 8) /* Bit 8: High Priority Message */ +#define MCAN_INT_HPM (1 << 8) /* Bit 8: High Priority Message Received */ #define MCAN_INT_TC (1 << 9) /* Bit 9: Transmission Completed */ #define MCAN_INT_TCF (1 << 10) /* Bit 10: Transmission Cancellation Finished */ #define MCAN_INT_TFE (1 << 11) /* Bit 11: Tx FIFO Empty */ @@ -387,12 +387,14 @@ #define MCAN_INT_EW (1 << 24) /* Bit 24: Warning Status */ #define MCAN_INT_BO (1 << 25) /* Bit 25: Bus_Off Status */ #define MCAN_INT_WDI (1 << 26) /* Bit 26: Watchdog Interrupt */ -#define MCAN_INT_CRCE (1 << 27) /* Bit 27: CRC Error */ +#define MCAN_INT_CRCE (1 << 27) /* Bit 27: Receive CRC Error */ #define MCAN_INT_BE (1 << 28) /* Bit 28: Bit Error */ #define MCAN_INT_ACKE (1 << 29) /* Bit 29: Acknowledge Error */ #define MCAN_INT_FOE (1 << 30) /* Bit 30: Format Error */ #define MCAN_INT_STE (1 << 31) /* Bit 31: Stuff Error */ +#define MCAN_INT_ALL (0xffcfffff) + /* Interrupt Line Enable Register */ #define MCAN_ILE_EINT0 (1 << 0) /* Bit 0: Enable Interrupt Line 0 */ @@ -442,10 +444,10 @@ # define MCAN_HPMS_BIDX(n) ((uint32_t)(n) << MCAN_HPMS_BIDX_SHIFT) #define MCAN_HPMS_MSI_SHIFT (6) /* Bits 6-7: Message Storage Indicator */ #define MCAN_HPMS_MSI_MASK (3 << MCAN_HPMS_MSI_SHIFT) -# define MCAN_HPMS_MSI_ NOFIFO (0 << MCAN_HPMS_MSI_SHIFT) /* No FIFO selected. */ -# define MCAN_HPMS_MSI_ LOST (1 << MCAN_HPMS_MSI_SHIFT) /* FIFO message. */ -# define MCAN_HPMS_MSI_ FIFO0 (2 << MCAN_HPMS_MSI_SHIFT) /* Message stored in FIFO 0. */ -# define MCAN_HPMS_MSI_ FIFO1 (3 << MCAN_HPMS_MSI_SHIFT) /* Message stored in FIFO 1. */ +# define MCAN_HPMS_MSI_NOFIFO (0 << MCAN_HPMS_MSI_SHIFT) /* No FIFO selected. */ +# define MCAN_HPMS_MSI_LOST (1 << MCAN_HPMS_MSI_SHIFT) /* FIFO message. */ +# define MCAN_HPMS_MSI_FIFO0 (2 << MCAN_HPMS_MSI_SHIFT) /* Message stored in FIFO 0. */ +# define MCAN_HPMS_MSI_FIFO1 (3 << MCAN_HPMS_MSI_SHIFT) /* Message stored in FIFO 1. */ #define MCAN_HPMS_FIDX_SHIFT (8) /* Bits 8-14: Filter Index */ #define MCAN_HPMS_FIDX_MASK (0x7f << MCAN_HPMS_FIDX_SHIFT) # define MCAN_HPMS_FIDX(n) ((uint32_t)(n) << MCAN_HPMS_FIDX_SHIFT) @@ -535,6 +537,7 @@ #define MCAN_RXESC_F0DS_SHIFT (0) /* Bits 0-2: Receive FIFO 0 Data Field Size */ #define MCAN_RXESC_F0DS_MASK (7 << MCAN_RXESC_F0DS_SHIFT) +# define MCAN_RXESC_F0DS(n) ((uint32_t)(n) << MCAN_RXESC_F0DS_SHIFT) # define MCAN_RXESC_F0DS_8B (0 << MCAN_RXESC_F0DS_SHIFT) /* 8-byte data field */ # define MCAN_RXESC_F0DS_12B (1 << MCAN_RXESC_F0DS_SHIFT) /* 12-byte data field */ # define MCAN_RXESC_F0DS_16B (2 << MCAN_RXESC_F0DS_SHIFT) /* 16-byte data field */ @@ -545,6 +548,7 @@ # define MCAN_RXESC_F0DS_64B (7 << MCAN_RXESC_F0DS_SHIFT) /* 64-byte data field */ #define MCAN_RXESC_F1DS_SHIFT (4) /* Bits 4-6: Receive FIFO 1 Data Field Size */ #define MCAN_RXESC_F1DS_MASK (7 << MCAN_RXESC_F1DS_SHIFT) +# define MCAN_RXESC_F1DS(n) ((uint32_t)(n) << MCAN_RXESC_F1DS_SHIFT) # define MCAN_RXESC_F1DS_8B (0 << MCAN_RXESC_F1DS_SHIFT) /* 8-byte data field */ # define MCAN_RXESC_F1DS_12B (1 << MCAN_RXESC_F1DS_SHIFT) /* 12-byte data field */ # define MCAN_RXESC_F1DS_16B (2 << MCAN_RXESC_F1DS_SHIFT) /* 16-byte data field */ @@ -555,6 +559,7 @@ # define MCAN_RXESC_F1DS_64B (7 << MCAN_RXESC_F1DS_SHIFT) /* 64-byte data field */ #define MCAN_RXESC_RBDS_SHIFT (8) /* Bits 8-10: Receive Buffer Data Field Size */ #define MCAN_RXESC_RBDS_MASK (7 << MCAN_RXESC_RBDS_SHIFT) +# define MCAN_RXESC_RBDS(n) ((uint32_t)(n) << MCAN_RXESC_RBDS_SHIFT) # define MCAN_RXESC_RBDS_8B (0 << MCAN_RXESC_RBDS_SHIFT) /* 8-byte data field */ # define MCAN_RXESC_RBDS_12B (1 << MCAN_RXESC_RBDS_SHIFT) /* 12-byte data field */ # define MCAN_RXESC_RBDS_16B (2 << MCAN_RXESC_RBDS_SHIFT) /* 16-byte data field */ @@ -594,6 +599,7 @@ #define MCAN_TXESC_TBDS_SHIFT (0) /* Bits 0-2: Tx Buffer Data Field Size */ #define MCAN_TXESC_TBDS_MASK (7 << MCAN_TXESC_TBDS_SHIFT) +# define MCAN_TXESC_TBDS(n) ((uint32_t)(n) << MCAN_TXESC_TBDS_SHIFT) # define MCAN_TXESC_TBDS_8B (0 << MCAN_TXESC_TBDS_SHIFT) /* 8-byte data field */ # define MCAN_TXESC_TBDS_12B (1 << MCAN_TXESC_TBDS_SHIFT) /* 12-byte data field */ # define MCAN_TXESC_TBDS_16B (2 << MCAN_TXESC_TBDS_SHIFT) /* 16-byte data field */ @@ -661,6 +667,137 @@ #define MCAN_TXEFA_MASK 0x0000001f /* Event fifo acknowledge index mask */ +/* Message RAM Definitions **************************************************************/ +/* Common Buffer and FIFO element bit definitions: + * + * --------------- ------------------- -------------------------------- + * RESOURCE R0 R1 + * --------------- ------------------- -------------------------------- + * RX Buffer: ESI, XTD, RTR, ID, ANMF, FIDX, EDL, BRS, DLC, RXTS + * RX FIFO: ESI, XTD, RTR, ID, ANMF, FIDX, EDL, BRS, DLC, RXTS + * TX buffer: XTD, RTR, ID, MM, EFC, DLC + * TX Event FIFO: ESI, XTD, RTR, ID, MM, ET, EDL, BRS, DLC, TXTS + * --------------- ------------------- -------------------------------- + */ + +/* Common */ + +#define BUFFER_R0_EXTID_SHIFT (0) /* Bits 0-28: Extended identifer */ +#define BUFFER_R0_EXTID_MASK (0x1fffffff << BUFFER_R0_EXTID_SHIFT) +# define BUFFER_R0_EXTID(n) ((uint32_t)(n) << BUFFER_R0_EXTID_SHIFT) +#define BUFFER_R0_STDID_SHIFT (18) /* Bits 18-28: Standard idendifier */ +#define BUFFER_R0_STDID_MASK (0x7ff << BUFFER_R0_STDID_SHIFT) +# define BUFFER_R0_STDID(n) ((uint32_t)(n) << BUFFER_R0_STDID_SHIFT) +#define BUFFER_R0_RTR (1 << 29) /* Bit 29: Remote Transmission Request */ +#define BUFFER_R0_XTD (1 << 30) /* Bit 30: Extended Identifier */ +#define BUFFER_R0_ESI (1 << 31) /* Bit 31: Error State Indicator */ + +/* Common */ + +#define BUFFER_R1_DLC_SHIFT (16) /* Bits 16-19: Date length code */ +#define BUFFER_R1_DLC_MASK (15 << BUFFER_R1_DLC_SHIFT) +# define BUFFER_R1_DLC(n) ((uint32_t)(n) << BUFFER_R1_DLC_SHIFT) +#define BUFFER_R1_BRS (1 << 20) /* Bit 20: Bit Rate Switch */ +#define BUFFER_R1_EDL (1 << 21) /* Bit 21: Extended Data Length */ + +/* RX buffer/RX FIFOs */ + +#define BUFFER_R1_RXTS_SHIFT (0) /* Bits 0-15: RX Timestamp */ +#define BUFFER_R1_RXTS_MASK (0xffff << BUFFER_R1_RXTS_SHIFT) +# define BUFFER_R1_RXTS(n) ((uint32_t)(n) << BUFFER_R1_RXTS_SHIFT) +#define BUFFER_R1_FIDX_SHIFT (24) /* Bits 24-30: Filter index */ +#define BUFFER_R1_FIDX_MASK (0x7f << BUFFER_R1_FIDX_SHIFT) +# define BUFFER_R1_FIDX(n) ((uint32_t)(n) << BUFFER_R1_FIDX_SHIFT) +#define BUFFER_R1_ANMF (1 << 31) /* Bit 31: Accepted Non-matching Frame */ + +/* TX buffer/TX Event FIFO */ + +#define BUFFER_R1_MM_SHIFT (24) /* Bits 24-31: Message Marker */ +#define BUFFER_R1_MM_MASK (0xffff << BUFFER_R1_MM_SHIFT) +# define BUFFER_R1_MM(n) ((uint32_t)(n) << BUFFER_R1_MM_SHIFT) + +/* TX buffer */ + +#define BUFFER_R1_EFC (1 << 23) /* Bit 23: Event FIFO Control */ + +/* TX Event FIFO */ + +#define BUFFER_R1_TXTS_SHIFT (0) /* Bits 0-15: TX Timestamp */ +#define BUFFER_R1_TXTS_MASK (0xffff << BUFFER_R1_TXTS_SHIFT) +# define BUFFER_R1_TXTS(n) ((uint32_t)(n) << BUFFER_R1_TXTS_SHIFT) +#define BUFFER_R1_ET_SHIFT (22) /* Bits 22-23: Event Type */ +#define BUFFER_R1_ET_MASK (15 << BUFFER_R1_ET_SHIFT) +# define BUFFER_R1_ET_TXEVENT (1 << BUFFER_R1_ET_SHIFT) /* Tx event */ +# define BUFFER_R1_ET_TXCANCEL (2 << BUFFER_R1_ET_SHIFT) /* Transmission despite cancellation */ + +/* Standard Message ID Filter Element */ + +#define STDFILTER_S0_SFID2_SHIFT (0) /* Bits 0-10: Standard Filter ID 2 */ +#define STDFILTER_S0_SFID2_MASK (0x3ff << STDFILTER_S0_SFID2_SHIFT) +# define STDFILTER_S0_SFID2(n) ((uint32_t)(n) << STDFILTER_S0_SFID2_SHIFT) +#define STDFILTER_S0_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define STDFILTER_S0_BUFFER_MASK (0x3f << STDFILTER_S0_BUFFER_SHIFT) +# define STDFILTER_S0_BUFFER(n) ((uint32_t)(n) << STDFILTER_S0_BUFFER_SHIFT) +#define STDFILTER_S0_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define STDFILTER_S0_ACTION_MASK (3 << STDFILTER_S0_ACTION_SHIFT) +# define STDFILTER_S0_RXBUFFER (0 << STDFILTER_S0_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define STDFILTER_S0_DEBUGA (1 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message A */ +# define STDFILTER_S0_DEBUGB (2 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message B */ +# define STDFILTER_S0_DEBUGC (3 << STDFILTER_S0_ACTION_SHIFT) /* Debug Message C */ +#define STDFILTER_S0_SFID1_SHIFT (16) /* Bits 16-26: Standard Filter ID 2 */ +#define STDFILTER_S0_SFID1_MASK (0x3ff << STDFILTER_S0_SFID1_SHIFT) +# define STDFILTER_S0_SFID1(n) ((uint32_t)(n) << STDFILTER_S0_SFID1_SHIFT) +#define STDFILTER_S0_SFEC_SHIFT (17) /* Bits 27-29: Standard Filter Element Configuration */ +#define STDFILTER_S0_SFEC_MASK (7 << STDFILTER_S0_SFEC_SHIFT) +# define STDFILTER_S0_SFEC_DISABLE (0 << STDFILTER_S0_SFEC_SHIFT) /* Disable filter element */ +# define STDFILTER_S0_SFEC_FIFO0 (1 << STDFILTER_S0_SFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define STDFILTER_S0_SFEC_FIFO1 (2 << STDFILTER_S0_SFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define STDFILTER_S0_SFEC_REJECT (3 << STDFILTER_S0_SFEC_SHIFT) /* Reject ID on match */ +# define STDFILTER_S0_SFEC_PRIORITY (4 << STDFILTER_S0_SFEC_SHIFT) /* Set priority ion match */ +# define STDFILTER_S0_SFEC_PRIOFIFO0 (5 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define STDFILTER_S0_SFEC_PRIOFIFO1 (6 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define STDFILTER_S0_SFEC_BUFFER (7 << STDFILTER_S0_SFEC_SHIFT) /* Store into Rx Buffer or as debug message */ +#define STDFILTER_S0_SFT_SHIFT (30) /* Bits 30-31: Standard Filter Type */ +#define STDFILTER_S0_SFT_MASK (3 << STDFILTER_S0_SFT_SHIFT) +# define STDFILTER_S0_SFT_RANGE (0 << STDFILTER_S0_SFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define STDFILTER_S0_SFT_DUAL (1 << STDFILTER_S0_SFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define STDFILTER_S0_SFT_CLASSIC (2 << STDFILTER_S0_SFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ + +/* Extended Message ID Filter Element */ + +#define EXTFILTER_F0_EFID1_SHIFT (0) /* Bits 0-28: Extended Filter ID 1 */ +#define EXTFILTER_F0_EFID1_MASK (0x1fffffff << EXTFILTER_F0_EFID1_SHIFT) +# define EXTFILTER_F0_EFID1(n) ((uint32_t)(n) << EXTFILTER_F0_EFID1_SHIFT) +#define EXTFILTER_F0_EFEC_SHIFT (29) /* Bits 29-31: Extended Filter Element Configuration */ +#define EXTFILTER_F0_EFEC_MASK (7 << EXTFILTER_F0_EFEC_SHIFT) +# define EXTFILTER_F0_EFEC_DISABLE (0 << EXTFILTER_F0_EFEC_SHIFT) /* Disable filter element */ +# define EXTFILTER_F0_EFEC_FIFO0 (1 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_FIFO1 (2 << EXTFILTER_F0_EFEC_SHIFT) /* Store in Rx FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_REJECT (3 << EXTFILTER_F0_EFEC_SHIFT) /* Reject ID on match */ +# define EXTFILTER_F0_EFEC_PRIORITY (4 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO0 (5 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 0 on match */ +# define EXTFILTER_F0_EFEC_PRIOFIFO1 (6 << EXTFILTER_F0_EFEC_SHIFT) /* Set priority and store in FIFO 1 on match */ +# define EXTFILTER_F0_EFEC_BUFFER (7 << EXTFILTER_F0_EFEC_SHIFT) /* Store into Rx Buffer or as debug message */ + +#define EXTFILTER_F1_EFID2_SHIFT (0) /* Bits 0-28: Extended Filter ID 2 */ +#define EXTFILTER_F1_EFID2_MASK (0x1fffffff << EXTFILTER_F1_EFID2_SHIFT) +# define EXTFILTER_F1_EFID2(n) ((uint32_t)(n) << EXTFILTER_F1_EFID2_SHIFT) +#define EXTFILTER_F1_BUFFER_SHIFT (0) /* Bits 0-5: RX buffer start address */ +#define EXTFILTER_F1_BUFFER_MASK (0x3f << EXTFILTER_F1_BUFFER_SHIFT) +# define EXTFILTER_F1_BUFFER(n) ((uint32_t)(n) << EXTFILTER_F1_BUFFER_SHIFT) +#define EXTFILTER_F1_ACTION_SHIFT (9) /* Bits 9-10: Action taken */ +#define EXTFILTER_F1_ACTION_MASK (3 << EXTFILTER_F1_ACTION_SHIFT) +# define EXTFILTER_F1_RXBUFFER (0 << EXTFILTER_F1_ACTION_SHIFT) /* Store message in a Rx buffer */ +# define EXTFILTER_F1_DEBUGA (1 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message A */ +# define EXTFILTER_F1_DEBUGB (2 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message B */ +# define EXTFILTER_F1_DEBUGC (3 << EXTFILTER_F1_ACTION_SHIFT) /* Debug Message C */ +#define EXTFILTER_F1_EFT_SHIFT (30) /* Bits 30-31: Extended Filter Type */ +#define EXTFILTER_F1_EFT_MASK (3 << EXTFILTER_F1_EFT_SHIFT) +# define EXTFILTER_F1_EFT_RANGE (0 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from SF1ID to SF2ID */ +# define EXTFILTER_F1_EFT_DUAL (1 << EXTFILTER_F1_EFT_SHIFT) /* Dual ID filter for SF1ID or SF2ID */ +# define EXTFILTER_F1_EFT_CLASSIC (2 << EXTFILTER_F1_EFT_SHIFT) /* Classic filter: SF1ID=filter SF2ID=mask */ +# define EXTFILTER_F1_EFT_NOXIDAM (2 << EXTFILTER_F1_EFT_SHIFT) /* Range filter from EF1ID to EF2ID, no XIDAM */ + /**************************************************************************************** * Public Types ****************************************************************************************/ diff --git a/arch/arm/src/samv7/chip/sam_qspi.h b/arch/arm/src/samv7/chip/sam_qspi.h new file mode 100644 index 00000000000..29d785704e3 --- /dev/null +++ b/arch/arm/src/samv7/chip/sam_qspi.h @@ -0,0 +1,272 @@ +/**************************************************************************************** + * arch/arm/src/samv7/chip/sam_qspi.h + * Quad SPI (QSPI) definitions for the SAMV71 + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_CHIP_SAM_QSPI_H +#define __ARCH_ARM_SRC_SAMV7_CHIP_SAM_QSPI_H + +/**************************************************************************************** + * Included Files + ****************************************************************************************/ + +#include +#include + +#include "chip/sam_memorymap.h" + +#if SAMV7_NQSPI > 0 + +/**************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************/ +/* General Characteristics **************************************************************/ + +#define SAM_QSPI_MINBITS 8 /* Minimum word width */ +#define SAM_QSPI_MAXBITS 16 /* Maximum word width */ + +/* QSPI register offsets ****************************************************************/ + +#define SAM_QSPI_CR_OFFSET 0x0000 /* Control Register */ +#define SAM_QSPI_MR_OFFSET 0x0004 /* Mode Register */ +#define SAM_QSPI_RDR_OFFSET 0x0008 /* Receive Data Register */ +#define SAM_QSPI_TDR_OFFSET 0x000c /* Transmit Data Register */ +#define SAM_QSPI_SR_OFFSET 0x0010 /* Status Register */ +#define SAM_QSPI_IER_OFFSET 0x0014 /* Interrupt Enable Register */ +#define SAM_QSPI_IDR_OFFSET 0x0018 /* Interrupt Disable Register */ +#define SAM_QSPI_IMR_OFFSET 0x001c /* Interrupt Mask Register */ +#define SAM_QSPI_SCR_OFFSET 0x0020 /* Serial Clock Register */ +#define SAM_QSPI_IAR_OFFSET 0x0030 /* Instruction Address Register */ +#define SAM_QSPI_ICR_OFFSET 0x0034 /* Instruction Code Register */ +#define SAM_QSPI_IFR_OFFSET 0x0038 /* Instruction Frame Register */ + /* 0x003c Reserved */ +#define SAM_QSPI_SMR_OFFSET 0x0040 /* Scrambling Mode Register */ +#define SAM_QSPI_SKR_OFFSET 0x0044 /* Scrambling Key Register */ + /* 0x0048–0x00e0 Reserved */ +#define SAM_QSPI_WPCR_OFFSET 0x00e4 /* Write Protection Control Register */ +#define SAM_QSPI_WPSR_OFFSET 0x00e8 /* Write Protection Status Register */ + /* 0xec-0xfc: Reserved */ + +/* QSPI register addresses **************************************************************/ + +#define SAM_QSPI0_CR (SAM_QSPI0_BASE+SAM_QSPI_CR_OFFSET) /* Control Register */ +#define SAM_QSPI0_MR (SAM_QSPI0_BASE+SAM_QSPI_MR_OFFSET) /* Mode Register */ +#define SAM_QSPI0_RDR (SAM_QSPI0_BASE+SAM_QSPI_RDR_OFFSET) /* Receive Data Register */ +#define SAM_QSPI0_TDR (SAM_QSPI0_BASE+SAM_QSPI_TDR_OFFSET) /* Transmit Data Register */ +#define SAM_QSPI0_SR (SAM_QSPI0_BASE+SAM_QSPI_SR_OFFSET) /* Status Register */ +#define SAM_QSPI0_IER (SAM_QSPI0_BASE+SAM_QSPI_IER_OFFSET) /* Interrupt Enable Register */ +#define SAM_QSPI0_IDR (SAM_QSPI0_BASE+SAM_QSPI_IDR_OFFSET) /* Interrupt Disable Register */ +#define SAM_QSPI0_IMR (SAM_QSPI0_BASE+SAM_QSPI_IMR_OFFSET) /* Interrupt Mask Register */ +#define SAM_QSPI0_SCR (SAM_QSPI0_BASE+SAM_QSPI_SCR_OFFSET) /* Serial Clock Register */ +#define SAM_QSPI0_IAR (SAM_QSPI0_BASE+SAM_QSPI_IAR_OFFSET) /* Instruction Address Register */ +#define SAM_QSPI0_ICR (SAM_QSPI0_BASE+SAM_QSPI_ICR_OFFSET) /* Instruction Code Register */ +#define SAM_QSPI0_IFR (SAM_QSPI0_BASE+SAM_QSPI_IFR_OFFSET) /* Instruction Frame Register */ +#define SAM_QSPI0_SMR (SAM_QSPI0_BASE+SAM_QSPI_SMR_OFFSET) /* Scrambling Mode Register */ +#define SAM_QSPI0_SKR (SAM_QSPI0_BASE+SAM_QSPI_SKR_OFFSET) /* Scrambling Key Register */ +#define SAM_QSPI0_WPCR (SAM_QSPI0_BASE+SAM_QSPI_WPCR_OFFSET) /* Write Protection Control Register */ +#define SAM_QSPI0_WPSR (SAM_QSPI0_BASE+SAM_QSPI_WPSR_OFFSET) /* Write Protection Status Register */ + +#if SAMV7_NQSPI > 1 +# define SAM_QSPI1_CR (SAM_QSPI1_BASE+SAM_QSPI_CR_OFFSET) /* Control Register */ +# define SAM_QSPI1_MR (SAM_QSPI1_BASE+SAM_QSPI_MR_OFFSET) /* Mode Register */ +# define SAM_QSPI1_RDR (SAM_QSPI1_BASE+SAM_QSPI_RDR_OFFSET) /* Receive Data Register */ +# define SAM_QSPI1_TDR (SAM_QSPI1_BASE+SAM_QSPI_TDR_OFFSET) /* Transmit Data Register */ +# define SAM_QSPI1_SR (SAM_QSPI1_BASE+SAM_QSPI_SR_OFFSET) /* Status Register */ +# define SAM_QSPI1_IER (SAM_QSPI1_BASE+SAM_QSPI_IER_OFFSET) /* Interrupt Enable Register */ +# define SAM_QSPI1_IDR (SAM_QSPI1_BASE+SAM_QSPI_IDR_OFFSET) /* Interrupt Disable Register */ +# define SAM_QSPI1_IMR (SAM_QSPI1_BASE+SAM_QSPI_IMR_OFFSET) /* Interrupt Mask Register */ +# define SAM_QSPI1_SCR (SAM_QSPI1_BASE+SAM_QSPI_SCR_OFFSET) /* Serial Clock Register */ +# define SAM_QSPI1_IAR (SAM_QSPI1_BASE+SAM_QSPI_IAR_OFFSET) /* Instruction Address Register */ +# define SAM_QSPI1_ICR (SAM_QSPI1_BASE+SAM_QSPI_ICR_OFFSET) /* Instruction Code Register */ +# define SAM_QSPI1_IFR (SAM_QSPI1_BASE+SAM_QSPI_IFR_OFFSET) /* Instruction Frame Register */ +# define SAM_QSPI1_SMR (SAM_QSPI1_BASE+SAM_QSPI_SMR_OFFSET) /* Scrambling Mode Register */ +# define SAM_QSPI1_SKR (SAM_QSPI1_BASE+SAM_QSPI_SKR_OFFSET) /* Scrambling Key Register */ +# define SAM_QSPI1_WPCR (SAM_QSPI1_BASE+SAM_QSPI_WPCR_OFFSET) /* Write Protection Control Register */ +# define SAM_QSPI1_WPSR (SAM_QSPI1_BASE+SAM_QSPI_WPSR_OFFSET) /* Write Protection Status Register */ +#endif + +/* QSPI register bit definitions ********************************************************/ + +/* QSPI Control Register */ + +#define QSPI_CR_QSPIEN (1 << 0) /* Bit 0: QSPI Enable */ +#define QSPI_CR_QSPIDIS (1 << 1) /* Bit 1: QSPI Disable */ +#define QSPI_CR_SWRST (1 << 7) /* Bit 7: QSPI Software Reset */ +#define QSPI_CR_LASTXFER (1 << 24) /* Bit 24: Last Transfer */ + +/* QSPI Mode Register */ + +#define QSPI_MR_SMM (1 << 0) /* Bit 0: Serial Memory Mode */ +#define QSPI_MR_LLB (1 << 1) /* Bit 1: Local Loopback Enable */ +#define QSPI_MR_WDRBT (1 << 2) /* Bit 2: Wait Data Read Before Transfer */ +#define QSPI_MR_CSMODE_SHIFT (4) /* Bits 4-5: Chip Select Mode */ +#define QSPI_MR_CSMODE_MASK (3 << QSPI_MR_PCS_SHIFT) +# define QSPI_MR_CSMODE_NRELOAD (0 << QSPI_MR_PCS_SHIFT) /* CS deasserted if TD not reloaded */ +# define QSPI_MR_CSMODE_LASTXFER (1 << QSPI_MR_PCS_SHIFT) /* CS deasserted when LASTXFER transferred */ +# define QSPI_MR_CSMODE_SYSTEM (2 << QSPI_MR_PCS_SHIFT) /* CS deasserted after each transfer */ +#define QSPI_MR_NBBITS_SHIFT (8) /* Bits 8-11: Number Of Bits Per Transfer */ +#define QSPI_MR_NBBITS_MASK (15 << QSPI_MR_NBBITS_SHIFT) +# define QSPI_MR_NBBITS(n) ((uint32_t)((n)-SAM_QSPI_MINBITS) << QSPI_MR_NBBITS_SHIFT) +# define QSPI_MR_NBBITS_8BIT (0 << QSPI_MR_NBBITS_SHIFT) /* 8 bits for transfer */ +# define QSPI_MR_NBBITS_9BIT (1 << QSPI_MR_NBBITS_SHIFT) /* 9 bits for transfer */ +# define QSPI_MR_NBBITS_10BIT (2 << QSPI_MR_NBBITS_SHIFT) /* 10 bits for transfer */ +# define QSPI_MR_NBBITS_11BIT (3 << QSPI_MR_NBBITS_SHIFT) /* 11 bits for transfer */ +# define QSPI_MR_NBBITS_12BIT (4 << QSPI_MR_NBBITS_SHIFT) /* 12 bits for transfer */ +# define QSPI_MR_NBBITS_13BIT (5 << QSPI_MR_NBBITS_SHIFT) /* 13 bits for transfer */ +# define QSPI_MR_NBBITS_14BIT (6 << QSPI_MR_NBBITS_SHIFT) /* 14 bits for transfer */ +# define QSPI_MR_NBBITS_15BIT (7 << QSPI_MR_NBBITS_SHIFT) /* 15 bits for transfer */ +# define QSPI_MR_NBBITS_16BIT (8 << QSPI_MR_NBBITS_SHIFT) /* 16 bits for transfer */ +#define QSPI_MR_DLYBCT_SHIFT (16) /* Bits 16-23: Delay Between Consecutive Transfers */ +#define QSPI_MR_DLYBCT_MASK (0xff << QSPI_MR_DLYBCT_SHIFT) +# define QSPI_MR_DLYBCT(n) ((uint32_t)(n) << QSPI_MR_DLYBCT_SHIFT) +#define QSPI_MR_DLYCS_SHIFT (24) /* Bits 24-31: Minimum Inactive QCS Delay */ +#define QSPI_MR_DLYCS_MASK (0xff << QSPI_MR_DLYCS_SHIFT) +# define QSPI_MR_DLYCS(n) ((uint32_t)(n) << QSPI_MR_DLYCS_SHIFT) + +/* QSPI Receive Data Register */ + +#define QSPI_RDR_RD_SHIFT (0) /* Bits 0-15: Receive Data */ +#define QSPI_RDR_RD_MASK (0xffff << QSPI_RDR_RD_SHIFT) + +/* QSPI Transmit Data Register */ + +#define QSPI_TDR_TD_SHIFT (0) /* Bits 0-15: Transmit Data */ +#define QSPI_TDR_TD_MASK (0xffff << QSPI_TDR_TD_SHIFT) + +/* QSPI Status Register, QSPI Interrupt Enable Register, QSPI Interrupt Disable Register, + * and QSPI Interrupt Mask Register (common bit fields) + */ + +#define QSPI_INT_RDRF (1 << 0) /* Bit 0: Receive Data Register Full Interrupt */ +#define QSPI_INT_TDRE (1 << 1) /* Bit 1: Transmit Data Register Empty Interrupt */ +#define QSPI_INT_TXEMPTY (1 << 2) /* Bit 2: Transmission Registers Empty Interrupt */ +#define QSPI_INT_OVRES (1 << 3) /* Bit 3: Overrun Error Interrupt */ +#define QSPI_INT_CSR (1 << 8) /* Bit 8: Chip Select Rise Interrupt */ +#define QSPI_SR_CSS (1 << 9) /* Bit 9: Chip Select Status Interrupt */ +#define QSPI_SR_INTSTRE (1 << 10) /* Bit 10: Instruction End Status Interrupt */ +#define QSPI_SR_QSPIENS (1 << 24) /* Bit 24: QSPI Enable Status (SR only) */ + +#define QSPI_INT_ALL (0x0000070f) + +/* Serial Clock Register */ + +#define QSPI_SCR_CPOL (1 << 0) /* Bit 0: Clock Polarity */ +#define QSPI_SCR_NCPHA (1 << 1) /* Bit 1: Clock Phase */ +#define QSPI_SCR_SCBR_SHIFT (8) /* Bits 8-15: Serial Clock Baud Rate */ +#define QSPI_SCR_SCBR_MASK (0xff << QSPI_SCR_SCBR_SHIFT) +# define QSPI_SCR_SCBR(n) ((uint32_t)(n) << QSPI_SCR_SCBR_SHIFT) +#define QSPI_SCR_DLYBS_SHIFT (16) /* Bits 16-23: Delay Before QSCK */ +#define QSPI_SCR_DLYBS_MASK (0xff << QSPI_SCR_DLYBS_SHIFT) +# define QSPI_SCR_DLYBS(n) ((uint32_t)(n) << QSPI_SCR_DLYBS_SHIFT) + +/* Instruction Address Register (32-bit value) */ + +/* Instruction Code Register */ + +#define QSPI_ICR_INST_SHIFT (0) /* Bits 0-7: Instruction Code */ +#define QSPI_ICR_INST_MASK (0xff << QSPI_ICR_INST_SHIFT) +# define QSPI_ICR_INST(n) ((uint32_t)(n) << QSPI_ICR_INST_SHIFT) +#define QSPI_ICR_OPT_SHIFT (16) /* Bits 16-23: Option Code */ +#define QSPI_ICR_OPT_MASK (0xff << QSPI_ICR_OPT_SHIFT) +# define QSPI_ICR_OPT(n) ((uint32_t)(n) << QSPI_ICR_OPT_SHIFT) + +/* Instruction Frame Register */ + +#define QSPI_IFR_WIDTH_SHIFT (0) /* Bits 0-2: Width of Instruction Code, + * Address, Option Code and Data */ +#define QSPI_IFR_WIDTH_MASK (7 << QSPI_IFR_WIDTH_SHIFT) + /* Instruction Address-Option Data */ +# define QSPI_IFR_WIDTH_SINGLE (0 << QSPI_IFR_WIDTH_SHIFT) /* Single-bit Single-bit Single-bit */ +# define QSPI_IFR_WIDTH_DUALOUT (1 << QSPI_IFR_WIDTH_SHIFT) /* Single-bit Single-bit Dual */ +# define QSPI_IFR_WIDTH_QUADOUT (2 << QSPI_IFR_WIDTH_SHIFT) /* Single-bit Single-bit Quad */ +# define QSPI_IFR_WIDTH_DUALIO (3 << QSPI_IFR_WIDTH_SHIFT) /* Single-bit Dual Dual */ +# define QSPI_IFR_WIDTH_QUADIO (4 << QSPI_IFR_WIDTH_SHIFT) /* Single-bit Quad Quad */ +# define QSPI_IFR_WIDTH_DUALCMD (5 << QSPI_IFR_WIDTH_SHIFT) /* Dual Dual Dual */ +# define QSPI_IFR_WIDTH_QUADCMD (6 << QSPI_IFR_WIDTH_SHIFT) /* Quad Quad Quad */ +#define QSPI_IFR_INSTEN (1 << 4) /* Bit 4: Instruction Enable */ +#define QSPI_IFR_ADDREN (1 << 5) /* Bit 5: Address Enable */ +#define QSPI_IFR_OPTEN (1 << 6) /* Bit 6: Option Enable */ +#define QSPI_IFR_DATAEN (1 << 7) /* Bit 7: Data Enable */ +#define QSPI_IFR_OPTL_SHIFT (8) /* Bits 8-9: Option Code Length */ +#define QSPI_IFR_OPTL_MASK (3 << QSPI_IFR_OPTL_SHIFT) +# define QSPI_IFR_OPTL_1BIT (0 << QSPI_IFR_OPTL_SHIFT) /* Option is 1 bit */ +# define QSPI_IFR_OPTL_2BIT (1 << QSPI_IFR_OPTL_SHIFT) /* Option is 2 bits */ +# define QSPI_IFR_OPTL_4BIT (2 << QSPI_IFR_OPTL_SHIFT) /* Option is 4 bits */ +# define QSPI_IFR_OPTL_8BIT (3 << QSPI_IFR_OPTL_SHIFT) /* Option is 8 bits */ +#define QSPI_IFR_ADDRL (1 << 10) /* Bit 10: Address Length */ +#define QSPI_IFR_TFRTYP_SHIFT (12) /* Bits 12-13: Data Transfer Type */ +#define QSPI_IFR_TFRTYP_MASK (3 << QSPI_IFR_TFRTYP_SHIFT) +# define QSPI_IFR_TFRTYP_READ (0 << QSPI_IFR_TFRTYP_SHIFT) /* Read transfer from serial memory */ +# define QSPI_IFR_TFRTYP_RDMEM (1 << QSPI_IFR_TFRTYP_SHIFT) /* Read data transfer from serial memory */ +# define QSPI_IFR_TFRTYP_WRITE (2 << QSPI_IFR_TFRTYP_SHIFT) /* Write transfer into serial memory */ +# define QSPI_IFR_TFRTYP_WRMEM (3 << QSPI_IFR_TFRTYP_SHIFT) /* Write data transfer the serial memory */ +#define QSPI_IFR_CRM (1 << 14) /* Bit 14: Continuous Read Mode */ +#define QSPI_IFR_NBDUM_SHIFT (16) /* Bits 16-20: Number Of Dummy Cycles */ +#define QSPI_IFR_NBDUM_MASK (31 << QSPI_IFR_NBDUM_SHIFT) +# define QSPI_IFR_NBDUM(n) ((uint32_t)(n) << QSPI_IFR_NBDUM_SHIFT) + +/* Scrambling Mode Register */ + +#define QSPI_SMR_SCREN (1 << 0) /* Bit 0: Scrambling/Unscrambling Enable */ +#define QSPI_SMR_RVDIS (1 << 1) /* Bit 1: Scrambling/Unscrambling Random Value Disable */ + +/* Scrambling Key Register (32-bit value) */ + +/* QSPI Write Protection Control Register */ + +#define QSPI_WPCR_WPEN (1 << 0) /* Bit 0: QSPI Write Protection Enable */ +#define QSPI_WPCR_WPKEY_SHIFT (8) /* Bits 8-31: QSPI Write Protection Key Password */ +#define QSPI_WPCR_WPKEY_MASK (0x00ffffff << QSPI_WPCR_WPKEY_SHIFT) +# define QSPI_WPCR_WPKEY (0x00515350 << QSPI_WPCR_WPKEY_SHIFT) + +/* QSPI Write Protection Status Register */ + +#define QSPI_WPSR_WPVS (1 << 0) /* Bit 0: QSPI Write Protection Violation Status */ +#define QSPI_WPSR_WPVSRC_SHIFT (8) /* Bits 8-15: QSPI Write Protection Violation Source */ +#define QSPI_WPSR_WPVSRC_MASK (0xff << QSPI_WPSR_WPVSRC_SHIFT) + +/**************************************************************************************** + * Public Types + ****************************************************************************************/ + +/**************************************************************************************** + * Public Data + ****************************************************************************************/ + +/**************************************************************************************** + * Public Functions + ****************************************************************************************/ + +#endif /* SAMV7_NQSPI > 0 */ +#endif /* __ARCH_ARM_SRC_SAMV7_CHIP_SAM_QSPI_H */ diff --git a/arch/arm/src/samv7/chip/sam_spi.h b/arch/arm/src/samv7/chip/sam_spi.h index 44ec25e8759..fe738b2e184 100644 --- a/arch/arm/src/samv7/chip/sam_spi.h +++ b/arch/arm/src/samv7/chip/sam_spi.h @@ -120,7 +120,8 @@ /* SPI Mode Register */ -#define SPI_MR_MSTR (1 << 0) /* Bit 0: Master/Slave Mode */ +#define SPI_MR_MSTR (1 << 0) /* Bit 0: 1=Master Mode */ +# define SPI_MR_SLAVE (0) /* 0=Slave Mode */ #define SPI_MR_PS (1 << 1) /* Bit 1: Peripheral Select */ #define SPI_MR_PCSDEC (1 << 2) /* Bit 2: Chip Select Decode */ #define SPI_MR_MODFDIS (1 << 4) /* Bit 4: Mode Fault Detection */ @@ -170,7 +171,9 @@ #define SPI_INT_NSSR (1 << 8) /* Bit 8: NSS Rising Interrupt */ #define SPI_INT_TXEMPTY (1 << 9) /* Bit 9: Transmission Registers Empty Interrupt */ #define SPI_INT_UNDES (1 << 10) /* Bit 10: Underrun Error Status Interrupt (slave) */ -#define SPI_SR_SPIENS (1 << 16) /* Bit 16: SPI Enable Status (SR only) */ +#define SPI_SR_SPIENS (1 << 16) /* Bit 16: SPI Enable Status (SR only) */ + +#define SPI_INT_ALL (0x0000070f) /* SPI Chip Select Registers 0-3 */ diff --git a/arch/arm/src/samv7/chip/sam_usbhs.h b/arch/arm/src/samv7/chip/sam_usbhs.h index b01240fc67f..04c9c4db511 100644 --- a/arch/arm/src/samv7/chip/sam_usbhs.h +++ b/arch/arm/src/samv7/chip/sam_usbhs.h @@ -746,6 +746,9 @@ #define USBHS_CTRL_RDERRE (1 << 4) /* Bit 4: Remote Device Connection Error Interrupt Enable */ #define USBHS_CTRL_FRZCLK (1 << 14) /* Bit 14: Freeze USB Clock */ #define USBHS_CTRL_USBE (1 << 15) /* Bit 15: USBHS Enable */ +#define USBHS_CTRL_UIDE (1 << 24) /* Bit 24: UOTGID Pin Enable */ +# define USBHS_CTRL_UIDE_UIMOD (0 << 24) /* 0=USB mode selected UIMOD bit. */ +# define USBHS_CTRL_UIDE_UOTGID (1 << 24) /* 1=USB mode selected by UOTGID */ #define USBHS_CTRL_UIMOD_MASK (1 << 25) /* Bit 25: USBHS Mode */ # define USBHS_CTRL_UIMOD_HOST (0 << 25) /* 0=Host mode */ # define USBHS_CTRL_UIMOD_DEVICE (1 << 25) /* 1=Device mode */ diff --git a/arch/arm/src/samv7/chip/samv71_memorymap.h b/arch/arm/src/samv7/chip/samv71_memorymap.h index 6e9413d5ef5..917bfd0b5ec 100644 --- a/arch/arm/src/samv7/chip/samv71_memorymap.h +++ b/arch/arm/src/samv7/chip/samv71_memorymap.h @@ -55,7 +55,7 @@ #define SAM_MEMORY_BASE 0x60000000 /* 0x60000000-0x7fffffff: Memories */ #define SAM_QSPIMEM_BASE 0x80000000 /* 0x80000000-0x9fffffff: QSPI memory */ #define SAM_AXIMX_BASE 0xa0000000 /* 0xa0000000-0x9fffffff: AXIMX */ -#define SAM_USBHSRAM_BASE 0xa0010000 /* 0xa0100000-0xa01fffff: USBHS RAM */ +#define SAM_USBHSRAM_BASE 0xa0100000 /* 0xa0100000-0xa01fffff: USBHS RAM */ /* 0xa0200000-0xdfffffff: Reserved */ #define SAM_SYSTEM_BASE 0xe0000000 /* 0xe0000000-0xffffffff: System */ diff --git a/arch/arm/src/samv7/chip/samv71_pinmap.h b/arch/arm/src/samv7/chip/samv71_pinmap.h index 95b7a7c29fe..cb9942f2d2a 100644 --- a/arch/arm/src/samv7/chip/samv71_pinmap.h +++ b/arch/arm/src/samv7/chip/samv71_pinmap.h @@ -152,14 +152,14 @@ #define GPIO_AFE0_ADTRG (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOA | GPIO_PIN8) #define GPIO_AFE1_ADTRG (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN9) -/* CAN */ +/* MCAN */ -#define GPIO_CAN0_RX (GPIO_PERIPHA | GPIO_CFG_DEFAULT | GPIO_PORT_PIOB | GPIO_PIN3) -#define GPIO_CAN0_TX (GPIO_PERIPHA | GPIO_CFG_DEFAULT | GPIO_PORT_PIOB | GPIO_PIN2) -#define GPIO_CAN1_RX_1 (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN28) -#define GPIO_CAN1_RX_2 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN12) -#define GPIO_CAN1_TX_1 (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN12) -#define GPIO_CAN1_TX_2 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN14) +#define GPIO_MCAN0_RX (GPIO_PERIPHA | GPIO_CFG_DEFAULT | GPIO_PORT_PIOB | GPIO_PIN3) +#define GPIO_MCAN0_TX (GPIO_PERIPHA | GPIO_CFG_DEFAULT | GPIO_PORT_PIOB | GPIO_PIN2) +#define GPIO_MCAN1_RX_1 (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN28) +#define GPIO_MCAN1_RX_2 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN12) +#define GPIO_MCAN1_TX_1 (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN12) +#define GPIO_MCAN1_TX_2 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN14) /* Digital-to-Analog Convert (DAC) */ @@ -399,6 +399,7 @@ #define GPIO_SPI0_MOSI (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN21) #define GPIO_SPI0_SPCK (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN22) +#define GPIO_SPI0_NSS (GPIO_PERIPHD | GPIO_CFG_DEFAULT | GPIO_PORT_PIOB | GPIO_PIN2) #define GPIO_SPI0_NPCS0 (GPIO_PERIPHD | GPIO_CFG_DEFAULT | GPIO_PORT_PIOB | GPIO_PIN2) #define GPIO_SPI0_NPCS1_1 (GPIO_PERIPHA | GPIO_CFG_DEFAULT | GPIO_PORT_PIOA | GPIO_PIN31) #define GPIO_SPI0_NPCS1_2 (GPIO_PERIPHB | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN25) @@ -409,6 +410,7 @@ #define GPIO_SPI1_MOSI (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN27) #define GPIO_SPI1_SPCK (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN24) +#define GPIO_SPI1_NSS (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN25) #define GPIO_SPI1_NPCS0 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN25) #define GPIO_SPI1_NPCS1_1 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOC | GPIO_PIN28) #define GPIO_SPI1_NPCS1_2 (GPIO_PERIPHC | GPIO_CFG_DEFAULT | GPIO_PORT_PIOD | GPIO_PIN0) diff --git a/arch/arm/src/samv7/sam_clockconfig.c b/arch/arm/src/samv7/sam_clockconfig.c index 9d68d4d278c..82b834a53d0 100644 --- a/arch/arm/src/samv7/sam_clockconfig.c +++ b/arch/arm/src/samv7/sam_clockconfig.c @@ -224,30 +224,27 @@ static inline void sam_pmcsetup(void) putreg32(BOARD_CKGR_PLLAR, SAM_PMC_CKGR_PLLAR); sam_pmcwait(PMC_INT_LOCKA); -#ifdef CONFIG_USBDEV +#ifdef CONFIG_SAMV7_USBDEVHS /* UTMI configuration: Enable port0, select 12/16 MHz MAINOSC crystal source */ -#if 0 /* REVISIT: Does this apply only to OHCI? */ - putreg32(UTMI_OHCIICR_RES0, SAM_UTMI_OHCIICR); -#endif - #if BOARD_MAINOSC_FREQUENCY == 12000000 putreg32(UTMI_CKTRIM_FREQ_XTAL12, SAM_UTMI_CKTRIM); -#elif BOARD_MAINOSC_FREQUENCY == 12000000 +#elif BOARD_MAINOSC_FREQUENCY == 16000000 putreg32(UTMI_CKTRIM_FREQ_XTAL16, SAM_UTMI_CKTRIM); #else # error ERROR: Unrecognized MAINSOSC frequency #endif +#ifdef CONFIG_SAMV7_USBDEVHS_LOWPOWER /* Enable UTMI Clocking. The USBHS can work in two modes: * * - Normal mode where High speed, Full speed and Low speed are available. * - Low-power mode where only Full speed and Low speed are available. * - * Only the normal mode is supported by this logic. + * Only the Low-power mode is mode is supported by the logic here. Normal + * mode logic is handled in the function sam_usbclock(). */ -#ifdef CONFIG_SAMV7_USBDEVHS_LOWPOWER /* UTMI Low-power mode, Full/Low Speed mode * * Enable the 48MHz FS Clock. @@ -255,15 +252,6 @@ static inline void sam_pmcsetup(void) putreg32(PMC_USBCLK, SAM_PMC_SCER); -#else - /* UTMI normal mode, High/Full/Low Speed - * - * Disable the 48MHz USB FS Clock. It is not used in this configuration - */ - - putreg32(PMC_USBCLK, SAM_PMC_SCDR); -#endif - /* Select the UTMI PLL as the USB PLL clock input (480MHz) with divider * to get to 48MHz. UPLL output frequency is determined only by the * 12/16MHz crystal selection above. @@ -271,7 +259,6 @@ static inline void sam_pmcsetup(void) regval = PMC_USB_USBS_UPLL; -#ifdef CONFIG_SAMV7_USBDEVHS_LOWPOWER if ((getreg32(SAM_PMC_MCKR) & PMC_MCKR_PLLADIV2) != 0) { /* Divider = 480 Mhz / 2 / 48 Mhz = 5 */ @@ -284,7 +271,6 @@ static inline void sam_pmcsetup(void) regval |= PMC_USB_USBDIV(9); } -#endif putreg32(regval, SAM_PMC_USB); @@ -296,7 +282,9 @@ static inline void sam_pmcsetup(void) /* Wait for LOCKU */ sam_pmcwait(PMC_INT_LOCKU); -#endif + +#endif /* CONFIG_SAMV7_USBDEVHS_LOWPOWER */ +#endif /* CONFIG_SAMV7_USBDEVHS */ /* Switch to the fast clock and wait for MCKRDY */ @@ -405,3 +393,51 @@ void sam_clockconfig(void) sam_enabledefaultmaster(); } + +/**************************************************************************** + * Name: sam_usbclock + * + * Description: + * Enable USBHS clocking. + * + ****************************************************************************/ + +#if defined(CONFIG_SAMV7_USBDEVHS) && !defined(CONFIG_SAMV7_USBDEVHS_LOWPOWER) +void sam_usbclock(void) +{ + uint32_t regval; + + /* Enable UTMI Clocking. The USBHS can work in two modes: + * + * - Normal mode where High speed, Full speed and Low speed are available. + * - Low-power mode where only Full speed and Low speed are available. + * + * Only the normal mode is supported by this logic of this function. Low- + * power mode was handled in the sam_clockconfig(). + */ + + /* UTMI normal mode, High/Full/Low Speed + * + * Disable the 48MHz USB FS Clock. It is not used in this configuration + */ + + putreg32(PMC_USBCLK, SAM_PMC_SCDR); + + /* Select the UTMI PLL as the USB PLL clock input (480MHz) with a divider + * of 1. UPLL output frequency is determined only by the 12/16MHz crystal + * selection set in sam_clockconfig(). + */ + + putreg32(PMC_USB_USBS_UPLL, SAM_PMC_USB); + + /* Enable the UTMI PLL with the maximum start-up time */ + + regval = PMC_CKGR_UCKR_UPLLEN | PMC_CKGR_UCKR_UPLLCOUNT_MAX; + putreg32(regval, SAM_PMC_CKGR_UCKR); + + /* Wait for LOCKU */ + + sam_pmcwait(PMC_INT_LOCKU); +} + +#endif /* CONFIG_SAMV7_USBDEVHS && !CONFIG_SAMV7_USBDEVHS_LOWPOWER */ diff --git a/arch/arm/src/samv7/sam_clockconfig.h b/arch/arm/src/samv7/sam_clockconfig.h index 9f264bc84af..f62d7329041 100644 --- a/arch/arm/src/samv7/sam_clockconfig.h +++ b/arch/arm/src/samv7/sam_clockconfig.h @@ -85,6 +85,20 @@ extern "C" void sam_clockconfig(void); +/**************************************************************************** + * Name: sam_usbclock + * + * Description: + * Enable USBHS clocking. + * + ****************************************************************************/ + +#if defined(CONFIG_SAMV7_USBDEVHS) && !defined(CONFIG_SAMV7_USBDEVHS_LOWPOWER) +void sam_usbclock(void); +#else +# define sam_usbclock() +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/arm/src/samv7/sam_config.h b/arch/arm/src/samv7/sam_config.h index 547a6a0bb6b..8aca6fb6fd4 100644 --- a/arch/arm/src/samv7/sam_config.h +++ b/arch/arm/src/samv7/sam_config.h @@ -255,22 +255,60 @@ /* SPI ******************************************************************************/ /* Don't enable SPI peripherals not supported by the chip. */ -#if CHIP_NSPI < 1 +#if SAMV7_NSPI < 1 # undef CONFIG_SAMV7_SPI0 +# undef CONFIG_SAMV7_SPI0_MASTER +# undef CONFIG_SAMV7_SPI0_SLAVE # undef CONFIG_SAMV7_SPI1 -#elif CHIP_NSPI < 2 +# undef CONFIG_SAMV7_SPI1_MASTER +# undef CONFIG_SAMV7_SPI1_SLAVE +#elif SAMV7_NSPI < 2 # undef CONFIG_SAMV7_SPI1 +# undef CONFIG_SAMV7_SPI1_MASTER +# undef CONFIG_SAMV7_SPI1_SLAVE #endif -#ifndef CONFIG_SAMV7_HAVE_SPI +#ifndef CONFIG_SAMV7_SPI # undef CONFIG_SAMV7_SPI0 +# undef CONFIG_SAMV7_SPI0_MASTER +# undef CONFIG_SAMV7_SPI0_SLAVE # undef CONFIG_SAMV7_SPI1 +# undef CONFIG_SAMV7_SPI1_MASTER +# undef CONFIG_SAMV7_SPI1_SLAVE #endif /* Are any SPI peripherals enabled? */ #if !defined(CONFIG_SAMV7_SPI0) && !defined(CONFIG_SAMV7_SPI0) -# undef CONFIG_SAMV7_HAVE_SPI +# undef CONFIG_SAMV7_SPI +# undef CONFIG_SAMV7_SPI_MASTER +# undef CONFIG_SAMV7_SPI_SLAVE +#endif + +/* Each SPI peripheral must be enabled as a MASTER or as a SLAVE */ + +#ifndef CONFIG_SAMV7_SPI_MASTER +# undef CONFIG_SAMV7_SPI0_MASTER +# undef CONFIG_SAMV7_SPI1_MASTER +#endif + +#if !defined(CONFIG_SAMV7_SPI0_MASTER) && !defined(CONFIG_SAMV7_SPI1_MASTER) +# undef CONFIG_SAMV7_SPI_MASTER +#endif + +#ifndef CONFIG_SAMV7_SPI_SLAVE +# undef CONFIG_SAMV7_SPI0_SLAVE +# undef CONFIG_SAMV7_SPI1_SLAVE +#endif + +#if !defined(CONFIG_SAMV7_SPI0_SLAVE) && !defined(CONFIG_SAMV7_SPI1_SLAVE) +# undef CONFIG_SAMV7_SPI_SLAVE +#endif + +#if !defined(CONFIG_SAMV7_SPI_MASTER) && !defined(CONFIG_SAMV7_SPI_SLAVE) +# undef CONFIG_SAMV7_SPI +# undef CONFIG_SAMV7_SPI0 +# undef CONFIG_SAMV7_SPI1 #endif /**************************************************************************** diff --git a/arch/arm/src/samv7/sam_emac.c b/arch/arm/src/samv7/sam_emac.c index 29725cff533..44453b93a92 100644 --- a/arch/arm/src/samv7/sam_emac.c +++ b/arch/arm/src/samv7/sam_emac.c @@ -350,7 +350,7 @@ * the 8-byte (2 word boundaries). However, if the data cache is enabled * the a higher level of alignment is required. That is because the data * will need to be invalidated and that cache invalidation will occur in - * multiples of full change lines. + * multiples of full cache lines. * * In addition, padding may be required at the ends of the descriptors and * buffers to protect data after the end of from invalidation. @@ -2103,7 +2103,7 @@ static void sam_txdone(struct sam_emac_s *priv, int qid) * * Parameters: * priv - Reference to the driver state structure - * quid - Index of the tranfer queue that generated the interrupt + * quid - Index of the transfer queue that generated the interrupt * * Returned Value: * None @@ -2230,7 +2230,7 @@ static void sam_txerr_interrupt(FAR struct sam_emac_s *priv, int qid) * * Parameters: * priv - Reference to the driver state structure - * quid - Index of the tranfer queue that generated the interrupt + * quid - Index of the transfer queue that generated the interrupt * * Returned Value: * None diff --git a/arch/arm/src/samv7/sam_irq.c b/arch/arm/src/samv7/sam_irq.c index 9efaaf5ec46..ec6fcee54e2 100644 --- a/arch/arm/src/samv7/sam_irq.c +++ b/arch/arm/src/samv7/sam_irq.c @@ -78,7 +78,16 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; + +/* This is the address of the exception vector table (determined by the + * linker script). + */ + extern uint32_t _vectors[]; /**************************************************************************** @@ -378,16 +387,21 @@ void up_irqinitialize(void) } #endif - /* Set up the vector table address. - * - * If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#if defined(CONFIG_ARCH_RAMVECTORS) up_ramvec_initialize(); -#elif defined(CONFIG_SAM_BOOTLOADER) - putreg32((uint32_t)_vectors, NVIC_VECTAB); #endif /* Set all interrupts (and exceptions) to the default priority */ diff --git a/arch/arm/src/samv7/sam_mcan.c b/arch/arm/src/samv7/sam_mcan.c new file mode 100755 index 00000000000..45acfe49721 --- /dev/null +++ b/arch/arm/src/samv7/sam_mcan.c @@ -0,0 +1,3788 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_mcan.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * SAMV7D3 Series Data Sheet + * Atmel sample code + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX, Atmel, nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cache.h" +#include "up_internal.h" +#include "up_arch.h" + +#include "chip/sam_matrix.h" +#include "chip/sam_pinmap.h" +#include "sam_periphclks.h" +#include "sam_gpio.h" +#include "sam_mcan.h" + +#if defined(CONFIG_CAN) && defined(CONFIG_SAMV7_MCAN) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Common definitions *******************************************************/ + +#ifndef MIN +# define MIN(a,b) ((a < b) ? a : b) +#endif + +#ifndef MAX +# define MAX(a,b) ((a > b) ? a : b) +#endif + +/* Clock source *************************************************************/ + +/* PCK5 is the programmable clock source, common to all MCAN controllers */ + +#if defined(CONFIG_SAMV7_MCAN_CLKSRC_SLOW) +# define SAMV7_MCAN_CLKSRC PMC_PCK_CSS_SLOW +# define SAMV7_MCAN_CLKSRC_FREQUENCY BOARD_SLOWCLK_FREQUENCY +#elif defined(CONFIG_SAMV7_MCAN_CLKSRC_PLLA) +# define SAMV7_MCAN_CLKSRC PMC_PCK_CSS_PLLA +# define SAMV7_MCAN_CLKSRC_FREQUENCY BOARD_PLLA_FREQUENCY +#elif defined(CONFIG_SAMV7_MCAN_CLKSRC_UPLL) +# define SAMV7_MCAN_CLKSRC PMC_PCK_CSS_UPLL +# define SAMV7_MCAN_CLKSRC_FREQUENCY BOARD_UPLL_FREQUENCY +#elif defined(CONFIG_SAMV7_MCAN_CLKSRC_MCK) +# define SAMV7_MCAN_CLKSRC PMC_PCK_CSS_MCK +# define SAMV7_MCAN_CLKSRC_FREQUENCY BOARD_MCK_FREQUENCY +#else /* if defined(CONFIG_SAMV7_MCAN_CLKSRC_MAIN */ +# define SAMV7_MCAN_CLKSRC PMC_PCK_CSS_MAIN +# define SAMV7_MCAN_CLKSRC_FREQUENCY BOARD_MAINOSC_FREQUENCY +#endif + +#ifndef CONFIG_SAMV7_MCAN_CLKSRC_PRESCALER +# define CONFIG_SAMV7_MCAN_CLKSRC_PRESCALER 1 +#endif + +#define SAMV7_MCANCLK_FREQUENCY \ + (SAMV7_MCAN_CLKSRC_FREQUENCY / CONFIG_SAMV7_MCAN_CLKSRC_PRESCALER) + +/* Buffer Alignment *********************************************************/ +/* Buffer Alignment. + * + * The MCAN peripheral does not require any data be aligned. However, if + * the data cache is enabled then alignment is required. That is because + * the data will need to be invalidated and that cache invalidation will + * occur in multiples of full change lines. + */ + +#ifdef CONFIG_ARMV7M_DCACHE +# define MCAN_ALIGN ARMV7M_DCACHE_LINESIZE +# define MCAN_ALIGN_MASK (MCAN_ALIGN-1) +# define MCAN_ALIGN_UP(n) (((n) + MCAN_ALIGN_MASK) & ~MCAN_ALIGN_MASK) + +# ifndef CONFIG_ARMV7M_DCACHE_WRITETHROUGH +# warning !!! This driver will not work without CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y!!! +# endif +#endif + +/* MCAN0 Configuration ******************************************************/ + +#ifdef CONFIG_SAMV7_MCAN0 + +/* Bit timing */ + +# define MCAN0_TSEG1 (CONFIG_SAMV7_MCAN0_PROPSEG + CONFIG_SAMV7_MCAN0_PHASESEG1) +# define MCAN0_TSEG2 CONFIG_SAMV7_MCAN0_PHASESEG2 +# define MCAN0_BRP ((uint32_t)(((float) SAMV7_MCANCLK_FREQUENCY / \ + ((float)(MCAN0_TSEG1 + MCAN0_TSEG2 + 3) * \ + (float)CONFIG_SAMV7_MCAN0_BITRATE)) - 1)) +# define MCAN0_SJW (CONFIG_SAMV7_MCAN0_FSJW - 1) + +# if MCAN0_TSEG1 > 63 +# error Invalid MCAN0 TSEG1 +# endif +# if MCAN0_TSEG2 > 15 +# error Invalid MCAN0 TSEG2 +# endif +# if MCAN0_SJW > 15 +# error Invalid MCAN0 SJW +# endif + +# define MCAN0_FTSEG1 (CONFIG_SAMV7_MCAN0_FPROPSEG + CONFIG_SAMV7_MCAN0_FPHASESEG1) +# define MCAN0_FTSEG2 (CONFIG_SAMV7_MCAN0_FPHASESEG2) +# define MCAN0_FBRP ((uint32_t)(((float) SAMV7_MCANCLK_FREQUENCY / \ + ((float)(MCAN0_FTSEG1 + MCAN0_FTSEG2 + 3) * \ + (float)CONFIG_SAMV7_MCAN0_FBITRATE)) - 1)) +# define MCAN0_FSJW (CONFIG_SAMV7_MCAN0_FFSJW - 1) + +# if MCAN0_FTSEG1 > 15 +# error Invalid MCAN0 FTSEG1 +# endif +# if MCAN0_FTSEG2 > 7 +# error Invalid MCAN0 FTSEG2 +# endif +# if MCAN0_FSJW > 3 +# error Invalid MCAN0 FSJW +# endif + +/* MCAN0 RX FIFO0 element size */ + +# if defined(CONFIG_SAMV7_MCAN0_RXFIFO0_8BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 8 +# define MCAN0_RXFIFO0_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_12BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 12 +# define MCAN0_RXFIFO0_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_16BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 16 +# define MCAN0_RXFIFO0_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_20BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 20 +# define MCAN0_RXFIFO0_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_24BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 24 +# define MCAN0_RXFIFO0_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_32BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 32 +# define MCAN0_RXFIFO0_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_48BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 48 +# define MCAN0_RXFIFO0_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO0_64BYTES) +# define MCAN0_RXFIFO0_ELEMENT_SIZE 64 +# define MCAN0_RXFIFO0_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 RX FIFO0 element size +# endif + +# ifndef CONFIG_SAMV7_MCAN0_RXFIFO0_SIZE +# define CONFIG_SAMV7_MCAN0_RXFIFO0_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN0_RXFIFO0_SIZE > 64 +# error Invalid MCAN0 number of RX FIFO0 elements +# endif + +# define MCAN0_RXFIFO0_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_RXFIFO0_SIZE * \ + MCAN0_RXFIFO0_ELEMENT_SIZE + 8) +# define MCAN0_RXFIFO0_WORDS (MCAN0_RXFIFO0_BYTES >> 2) + +/* MCAN0 RX FIFO1 element size */ + +# if defined(CONFIG_SAMV7_MCAN0_RXFIFO1_8BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 8 +# define MCAN0_RXFIFO1_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_12BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 12 +# define MCAN0_RXFIFO1_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_16BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 16 +# define MCAN0_RXFIFO1_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_20BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 20 +# define MCAN0_RXFIFO1_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_24BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 24 +# define MCAN0_RXFIFO1_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_32BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 32 +# define MCAN0_RXFIFO1_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_48BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 48 +# define MCAN0_RXFIFO1_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN0_RXFIFO1_64BYTES) +# define MCAN0_RXFIFO1_ELEMENT_SIZE 64 +# define MCAN0_RXFIFO1_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 RX FIFO1 element size +# endif + +# ifndef CONFIG_SAMV7_MCAN0_RXFIFO1_SIZE +# define CONFIG_SAMV7_MCAN0_RXFIFO1_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN0_RXFIFO1_SIZE > 64 +# error Invalid MCAN0 number of RX FIFO1 elements +# endif + +# define MCAN0_RXFIFO1_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_RXFIFO1_SIZE * \ + MCAN1_RXFIFO1_ELEMENT_SIZE + 8) +# define MCAN0_RXFIFO1_WORDS (MCAN0_RXFIFO1_BYTES >> 2) + +/* MCAN0 Filters */ + +# ifndef CONFIG_SAMV7_MCAN0_NSTDFILTERS +# define CONFIG_SAMV7_MCAN0_NSTDFILTERS 0 +# endif + +# if (CONFIG_SAMV7_MCAN0_NSTDFILTERS > 128) +# error Invalid MCAN0 number of Standard Filters +# endif + +# ifndef CONFIG_SAMV7_MCAN0_NEXTFILTERS +# define CONFIG_SAMV7_MCAN0_NEXTFILTERS 0 +# endif + +# if (CONFIG_SAMV7_MCAN0_NEXTFILTERS > 64) +# error Invalid MCAN0 number of Extended Filters +# endif + +# define MCAN0_STDFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_NSTDFILTERS << 2) +# define MCAN0_STDFILTER_WORDS (MCAN0_STDFILTER_BYTES >> 2) + +# define MCAN0_EXTFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_NEXTFILTERS << 3) +# define MCAN0_EXTFILTER_WORDS (MCAN0_EXTFILTER_BYTES >> 2) + +/* MCAN0 RX buffer element size */ + +# if defined(CONFIG_SAMV7_MCAN0_RXBUFFER_8BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 8 +# define MCAN0_RXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_12BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 12 +# define MCAN0_RXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_16BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 16 +# define MCAN0_RXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_20BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 20 +# define MCAN0_RXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_24BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 24 +# define MCAN0_RXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_32BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 32 +# define MCAN0_RXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_48BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 48 +# define MCAN0_RXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN0_RXBUFFER_64BYTES) +# define MCAN0_RXBUFFER_ELEMENT_SIZE 64 +# define MCAN0_RXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 RX buffer element size +# endif + +# ifndef CONFIG_SAMV7_MCAN0_DEDICATED_RXBUFFER_SIZE +# define CONFIG_SAMV7_MCAN0_DEDICATED_RXBUFFER_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN0_DEDICATED_RXBUFFER_SIZE > 64 +# error Invalid MCAN0 number of RX BUFFER elements +# endif + +# define MCAN0_DEDICATED_RXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_DEDICATED_RXBUFFER_SIZE * \ + MCAN0_RXBUFFER_ELEMENT_SIZE + 8) +# define MCAN0_DEDICATED_RXBUFFER_WORDS \ + (MCAN0_DEDICATED_RXBUFFER_BYTES >> 2) + +/* MCAN0 TX buffer element size */ + +# if defined(CONFIG_SAMV7_MCAN0_TXBUFFER_8BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 8 +# define MCAN0_TXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_12BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 12 +# define MCAN0_TXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_16BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 16 +# define MCAN0_TXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_20BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 20 +# define MCAN0_TXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_24BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 24 +# define MCAN0_TXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_32BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 32 +# define MCAN0_TXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_48BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 48 +# define MCAN0_TXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN0_TXBUFFER_64BYTES) +# define MCAN0_TXBUFFER_ELEMENT_SIZE 64 +# define MCAN0_TXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN0 TX buffer element size +# endif + +# ifndef CONFIG_SAMV7_MCAN0_DEDICATED_TXBUFFER_SIZE +# define CONFIG_SAMV7_MCAN0_DEDICATED_TXBUFFER_SIZE 0 +# endif + +# define MCAN0_DEDICATED_TXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_DEDICATED_TXBUFFER_SIZE * \ + MCAN0_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN0_DEDICATED_TXBUFFER_WORDS \ + (MCAN0_DEDICATED_TXBUFFER_BYTES >> 2) + +/* MCAN0 TX FIFOs */ + +# ifndef CONFIG_SAMV7_MCAN0_TXFIFOQ_SIZE +# define CONFIG_SAMV7_MCAN0_TXFIFOQ_SIZE 0 +# endif + +# if (CONFIG_SAMV7_MCAN0_DEDICATED_TXBUFFER_SIZE + \ + CONFIG_SAMV7_MCAN0_TXFIFOQ_SIZE) > 32 +# error Invalid MCAN0 number of TX BUFFER elements +# endif + +# ifndef CONFIG_SAMV7_MCAN0_TXEVENTFIFO_SIZE +# define CONFIG_SAMV7_MCAN0_TXEVENTFIFO_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN0_TXEVENTFIFO_SIZE > 32 +# error Invalid MCAN0 number of TX EVENT FIFO elements +# endif + +# define MCAN0_TXEVENTFIFO_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_TXEVENTFIFO_SIZE << 3) +# define MCAN0_TXEVENTFIFO_WORDS \ + (MCAN0_TXEVENTFIFO_BYTES >> 2) + +# define MCAN0_TXFIFIOQ_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN0_TXFIFOQ_SIZE * \ + MCAN0_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN0_TXFIFIOQ_WORDS (MCAN0_TXFIFIOQ_BYTES >> 2) + +/* MCAN0 Message RAM */ + +# define MCAN0_STDFILTER_INDEX 0 +# define MCAN0_EXTFILTERS_INDEX (MCAN0_STDFILTER_INDEX + MCAN0_STDFILTER_WORDS) +# define MCAN0_RXFIFO0_INDEX (MCAN0_EXTFILTERS_INDEX + MCAN0_EXTFILTER_WORDS) +# define MCAN0_RXFIFO1_INDEX (MCAN0_RXFIFO0_INDEX + MCAN0_RXFIFO0_WORDS) +# define MCAN0_RXDEDICATED_INDEX (MCAN0_RXFIFO1_INDEX + MCAN0_RXFIFO1_WORDS) +# define MCAN0_TXEVENTFIFO_INDEX (MCAN0_RXDEDICATED_INDEX + MCAN0_DEDICATED_RXBUFFER_WORDS) +# define MCAN0_TXDEDICATED_INDEX (MCAN0_TXEVENTFIFO_INDEX + MCAN0_TXEVENTFIFO_WORDS) +# define MCAN0_TXFIFOQ_INDEX (MCAN0_TXDEDICATED_INDEX + MCAN0_DEDICATED_TXBUFFER_WORDS) +# define MCAN0_MSGRAM_WORDS (MCAN0_TXFIFOQ_INDEX + MCAN0_TXFIFIOQ_WORDS) + +#endif /* CONFIG_SAMV7_MCAN0 */ + +/* Loopback mode */ + +#undef SAMV7_MCAN_LOOPBACK +#if defined(CONFIG_SAMV7_MCAN0_LOOPBACK) || defined(CONFIG_SAMV7_MCAN1_LOOPBACK) +# define SAMV7_MCAN_LOOPBACK 1 +#endif + +/* MCAN1 Configuration ******************************************************/ + +#ifdef CONFIG_SAMV7_MCAN1 + /* Bit timing */ + +# define MCAN1_TSEG1 (CONFIG_SAMV7_MCAN1_PROPSEG + CONFIG_SAMV7_MCAN1_PHASESEG1) +# define MCAN1_TSEG2 CONFIG_SAMV7_MCAN1_PHASESEG2 +# define MCAN1_BRP ((uint32_t)(((float) SAMV7_MCANCLK_FREQUENCY / \ + ((float)(MCAN1_TSEG1 + MCAN1_TSEG2 + 3) * \ + (float)CONFIG_SAMV7_MCAN1_BITRATE)) - 1)) +# define MCAN1_SJW (CONFIG_SAMV7_MCAN1_FSJW - 1) + +# if MCAN1_TSEG1 > 63 +# error Invalid MCAN1 TSEG1 +# endif +# if MCAN1_TSEG2 > 15 +# error Invalid MCAN1 TSEG2 +# endif +# if MCAN1_SJW > 15 +# error Invalid MCAN1 SJW +# endif + +# define MCAN1_FTSEG1 (CONFIG_SAMV7_MCAN1_FPROPSEG + CONFIG_SAMV7_MCAN1_FPHASESEG1) +# define MCAN1_FTSEG2 (CONFIG_SAMV7_MCAN1_FPHASESEG2) +# define MCAN1_FBRP ((uint32_t)(((float) SAMV7_MCANCLK_FREQUENCY / \ + ((float)(MCAN1_FTSEG1 + MCAN1_FTSEG2 + 3) * \ + (float)CONFIG_SAMV7_MCAN1_FBITRATE)) - 1)) +# define MCAN1_FSJW (CONFIG_SAMV7_MCAN1_FFSJW - 1) + +#if MCAN1_FTSEG1 > 15 +# error Invalid MCAN1 FTSEG1 +#endif +#if MCAN1_FTSEG2 > 7 +# error Invalid MCAN1 FTSEG2 +#endif +#if MCAN1_FSJW > 3 +# error Invalid MCAN1 FSJW +#endif + +/* MCAN1 RX FIFO0 element size */ + +# if defined(CONFIG_SAMV7_MCAN1_RXFIFO0_8BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 8 +# define MCAN1_RXFIFO0_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_12BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 12 +# define MCAN1_RXFIFO0_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_16BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 16 +# define MCAN1_RXFIFO0_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_20BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 20 +# define MCAN1_RXFIFO0_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_24BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 24 +# define MCAN1_RXFIFO0_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_32BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 32 +# define MCAN1_RXFIFO0_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_48BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 48 +# define MCAN1_RXFIFO0_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO0_64BYTES) +# define MCAN1_RXFIFO0_ELEMENT_SIZE 64 +# define MCAN1_RXFIFO0_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 RX FIFO0 element size +# endif + +# ifndef CONFIG_SAMV7_MCAN1_RXFIFO0_SIZE +# define CONFIG_SAMV7_MCAN1_RXFIFO0_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN1_RXFIFO0_SIZE > 64 +# error Invalid MCAN1 number of RX FIFO 0 elements +# endif + +# define MCAN1_RXFIFO0_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_RXFIFO0_SIZE * \ + MCAN1_RXFIFO0_ELEMENT_SIZE + 8) +# define MCAN1_RXFIFO0_WORDS (MCAN1_RXFIFO0_BYTES >> 2) + +/* MCAN1 RX FIFO1 element size */ + +# if defined(CONFIG_SAMV7_MCAN1_RXFIFO1_8BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 8 +# define MCAN1_RXFIFO1_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_12BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 12 +# define MCAN1_RXFIFO1_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_16BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 16 +# define MCAN1_RXFIFO1_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_20BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 20 +# define MCAN1_RXFIFO1_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_24BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 24 +# define MCAN1_RXFIFO1_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_32BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 32 +# define MCAN1_RXFIFO1_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_48BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 48 +# define MCAN1_RXFIFO1_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN1_RXFIFO1_64BYTES) +# define MCAN1_RXFIFO1_ELEMENT_SIZE 64 +# define MCAN1_RXFIFO1_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 RX FIFO1 element size +# endif + +# ifndef CONFIG_SAMV7_MCAN1_RXFIFO1_SIZE +# define CONFIG_SAMV7_MCAN1_RXFIFO1_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN1_RXFIFO1_SIZE > 64 +# error Invalid MCAN1 number of RX FIFO 0 elements +# endif + +# define MCAN1_RXFIFO1_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_RXFIFO1_SIZE * \ + MCAN1_RXFIFO1_ELEMENT_SIZE + 8) +# define MCAN1_RXFIFO1_WORDS (MCAN1_RXFIFO1_BYTES >> 2) + +/* MCAN1 Filters */ + +# ifndef CONFIG_SAMV7_MCAN1_NSTDFILTERS +# define CONFIG_SAMV7_MCAN1_NSTDFILTERS 0 +# endif + +# if CONFIG_SAMV7_MCAN1_NSTDFILTERS > 128 +# error Invalid MCAN1 number of Standard Filters +# endif + +# ifndef CONFIG_SAMV7_MCAN1_NEXTFILTERS +# define CONFIG_SAMV7_MCAN1_NEXTFILTERS 0 +# endif + +# if CONFIG_SAMV7_MCAN1_NEXTFILTERS > 64 +# error Invalid MCAN1 number of Extended Filters +# endif + +# define MCAN1_STDFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_NSTDFILTERS << 2) +# define MCAN1_STDFILTER_WORDS (MCAN1_STDFILTER_BYTES >> 2) + +# define MCAN1_EXTFILTER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_NEXTFILTERS << 3) +# define MCAN1_EXTFILTER_WORDS (MCAN1_EXTFILTER_BYTES >> 2) + +/* MCAN1 RX buffer element size */ + +# if defined(CONFIG_SAMV7_MCAN1_RXBUFFER_8BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 8 +# define MCAN1_RXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_12BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 12 +# define MCAN1_RXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_16BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 16 +# define MCAN1_RXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_20BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 20 +# define MCAN1_RXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_24BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 24 +# define MCAN1_RXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_32BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 32 +# define MCAN1_RXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_48BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 48 +# define MCAN1_RXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN1_RXBUFFER_64BYTES) +# define MCAN1_RXBUFFER_ELEMENT_SIZE 64 +# define MCAN1_RXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 RX buffer element size +# endif + +# ifndef CONFIG_SAMV7_MCAN1_DEDICATED_RXBUFFER_SIZE +# define CONFIG_SAMV7_MCAN1_DEDICATED_RXBUFFER_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN1_DEDICATED_RXBUFFER_SIZE > 64 +# error Invalid MCAN1 number of RX BUFFER elements +# endif + +# define MCAN1_DEDICATED_RXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_DEDICATED_RXBUFFER_SIZE * \ + MCAN1_RXBUFFER_ELEMENT_SIZE + 8) +# define MCAN1_DEDICATED_RXBUFFER_WORDS \ + (MCAN1_DEDICATED_RXBUFFER_BYTES >> 2) + +/* MCAN1 TX buffer element size */ + +# if defined(CONFIG_SAMV7_MCAN1_TXBUFFER_8BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 8 +# define MCAN1_TXBUFFER_ENCODED_SIZE 0 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_12BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 12 +# define MCAN1_TXBUFFER_ENCODED_SIZE 1 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_16BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 16 +# define MCAN1_TXBUFFER_ENCODED_SIZE 2 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_20BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 20 +# define MCAN1_TXBUFFER_ENCODED_SIZE 3 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_24BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 24 +# define MCAN1_TXBUFFER_ENCODED_SIZE 4 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_32BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 32 +# define MCAN1_TXBUFFER_ENCODED_SIZE 5 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_48BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 48 +# define MCAN1_TXBUFFER_ENCODED_SIZE 6 +# elif defined(CONFIG_SAMV7_MCAN1_TXBUFFER_64BYTES) +# define MCAN1_TXBUFFER_ELEMENT_SIZE 64 +# define MCAN1_TXBUFFER_ENCODED_SIZE 7 +# else +# error Undefined MCAN1 TX buffer element size +# endif + +# ifndef CONFIG_SAMV7_MCAN1_DEDICATED_TXBUFFER_SIZE +# define CONFIG_SAMV7_MCAN1_DEDICATED_TXBUFFER_SIZE 0 +# endif + +# define MCAN1_DEDICATED_TXBUFFER_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_DEDICATED_TXBUFFER_SIZE * \ + MCAN1_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN1_DEDICATED_TXBUFFER_WORDS \ + (MCAN1_DEDICATED_TXBUFFER_BYTES >> 2) + +/* MCAN1 TX FIFOs */ + +# ifndef CONFIG_SAMV7_MCAN1_TXFIFOQ_SIZE +# define CONFIG_SAMV7_MCAN1_TXFIFOQ_SIZE 0 +# endif + +# if (CONFIG_SAMV7_MCAN1_DEDICATED_TXBUFFER_SIZE + \ + CONFIG_SAMV7_MCAN1_TXFIFOQ_SIZE) > 32 +# error Invalid MCAN1 number of TX BUFFER elements +# endif + +# ifndef CONFIG_SAMV7_MCAN1_TXEVENTFIFO_SIZE +# define CONFIG_SAMV7_MCAN1_TXEVENTFIFO_SIZE 0 +# endif + +# if CONFIG_SAMV7_MCAN1_TXEVENTFIFO_SIZE > 32 +# error Invalid MCAN1 number of TX EVENT FIFO elements +# endif + +# define MCAN1_TXEVENTFIFO_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_TXEVENTFIFO_SIZE << 3) +# define MCAN1_TXEVENTFIFO_WORDS \ + (MCAN1_TXEVENTFIFO_BYTES >> 2) + +# define MCAN1_TXFIFIOQ_BYTES \ + MCAN_ALIGN_UP(CONFIG_SAMV7_MCAN1_TXFIFOQ_SIZE * \ + MCAN1_TXBUFFER_ELEMENT_SIZE + 8) +# define MCAN1_TXFIFIOQ_WORDS (MCAN1_TXFIFIOQ_BYTES >> 2) + +/* MCAN1 Message RAM */ + +# define MCAN1_STDFILTER_INDEX 0 +# define MCAN1_EXTFILTERS_INDEX (MCAN1_STDFILTER_INDEX + MCAN1_STDFILTER_WORDS) +# define MCAN1_RXFIFO0_INDEX (MCAN1_EXTFILTERS_INDEX + MCAN1_EXTFILTER_WORDS) +# define MCAN1_RXFIFO1_INDEX (MCAN1_RXFIFO0_INDEX + MCAN1_RXFIFO0_WORDS) +# define MCAN1_RXDEDICATED_INDEX (MCAN1_RXFIFO1_INDEX + MCAN1_RXFIFO1_WORDS) +# define MCAN1_TXEVENTFIFO_INDEX (MCAN1_RXDEDICATED_INDEX + MCAN1_DEDICATED_RXBUFFER_WORDS) +# define MCAN1_TXDEDICATED_INDEX (MCAN1_TXEVENTFIFO_INDEX + MCAN1_TXEVENTFIFO_WORDS) +# define MCAN1_TXFIFOQ_INDEX (MCAN1_TXDEDICATED_INDEX + MCAN1_DEDICATED_TXBUFFER_WORDS) +# define MCAN1_MSGRAM_WORDS (MCAN1_TXFIFOQ_INDEX + MCAN1_TXFIFIOQ_WORDS) + +#endif /* CONFIG_SAMV7_MCAN1 */ + +/* MCAN helpers *************************************************************/ + +#define MAILBOX_ADDRESS(a) ((uint32_t)(a) & 0x0000fffc) + +/* Interrupts ***************************************************************/ +/* Common interrupts + * + * MCAN_INT_TSW - Timestamp Wraparound + * MCAN_INT_MRAF - Message RAM Access Failure + * MCAN_INT_TOO - Timeout Occurred + * MCAN_INT_ELO - Error Logging Overflow + * MCAN_INT_EP - Error Passive + * MCAN_INT_EW - Warning Status + * MCAN_INT_BO - Bus_Off Status + * MCAN_INT_WDI - Watchdog Interrupt + */ + +#define MCAN_CMNERR_INTS (MCAN_INT_MRAF | MCAN_INT_TOO | MCAN_INT_EP | \ + MCAN_INT_BO | MCAN_INT_WDI) +#define MCAN_COMMON_INTS MCAN_CMNERR_INTS + +/* RXFIFO mode interrupts + * + * MCAN_INT_RF0N - Receive FIFO 0 New Message + * MCAN_INT_RF0W - Receive FIFO 0 Watermark Reached + * MCAN_INT_RF0F - Receive FIFO 0 Full + * MCAN_INT_RF0L - Receive FIFO 0 Message Lost + * MCAN_INT_RF1N - Receive FIFO 1 New Message + * MCAN_INT_RF1W - Receive FIFO 1 Watermark Reached + * MCAN_INT_RF1F - Receive FIFO 1 Full + * MCAN_INT_RF1L - Receive FIFO 1 Message Lost + * MCAN_INT_HPM - High Priority Message Received + * + * Dedicated RX Buffer mode interrupts + * + * MCAN_INT_DRX - Message stored to Dedicated Receive Buffer + * + * Mode-independent RX-related interrupts + * + * MCAN_INT_CRCE - Receive CRC Error + * MCAN_INT_FOE - Format Error + * MCAN_INT_STE - Stuff Error + */ + +#define MCAN_RXCOMMON_INTS (MCAN_INT_CRCE | MCAN_INT_FOE | MCAN_INT_STE) +#define MCAN_RXFIFO0_INTS (MCAN_INT_RF0N | MCAN_INT_RF0W | MCAN_INT_RF0L) +#define MCAN_RXFIFO1_INTS (MCAN_INT_RF1N | MCAN_INT_RF1W | MCAN_INT_RF1L) +#define MCAN_RXFIFO_INTS (MCAN_RXFIFO0_INTS | MCAN_RXFIFO1_INTS | \ + MCAN_INT_HPM | MCAN_RXCOMMON_INTS) +#define MCAN_RXDEDBUF_INTS (MCAN_INT_DRX | MCAN_RXCOMMON_INTS) + +#define MCAN_RXERR_INTS (MCAN_INT_RF0L | MCAN_INT_RF1L | MCAN_INT_CRCE | \ + MCAN_INT_FOE | MCAN_INT_STE) + +/* TX FIFOQ mode interrupts + * + * MCAN_INT_TFE - Tx FIFO Empty + * + * TX Event FIFO interrupts + * + * MCAN_INT_TEFN - Tx Event FIFO New Entry + * MCAN_INT_TEFW - Tx Event FIFO Watermark Reached + * MCAN_INT_TEFF - Tx Event FIFO Full + * MCAN_INT_TEFL - Tx Event FIFO Element Lost + * + * Mode-independent TX-related interrupts + * + * MCAN_INT_TC - Transmission Completed + * MCAN_INT_TCF - Transmission Cancellation Finished + * MCAN_INT_BE - Bit Error + * MCAN_INT_ACKE - Acknowledge Error + */ + +#define MCAN_TXCOMMON_INTS (MCAN_INT_TC | MCAN_INT_TCF | MCAN_INT_BE | \ + MCAN_INT_ACKE) +#define MCAN_TXFIFOQ_INTS (MCAN_INT_TFE | MCAN_TXCOMMON_INTS) +#define MCAN_TXEVFIFO_INTS (MCAN_INT_TEFN | MCAN_INT_TEFW | MCAN_INT_TEFF | \ + MCAN_INT_TEFL) +#define MCAN_TXDEDBUF_INTS MCAN_TXCOMMON_INTS + +#define MCAN_TXERR_INTS (MCAN_INT_TEFL | MCAN_INT_BE | MCAN_INT_ACKE) + +/* Debug ********************************************************************/ +/* Debug configurations that may be enabled just for testing MCAN */ + +#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_CAN) +# undef CONFIG_SAMV7_MCAN_REGDEBUG +#endif + +#ifdef CONFIG_DEBUG_CAN +# define candbg dbg +# define canvdbg vdbg +# define canlldbg lldbg +# define canllvdbg llvdbg + +# ifdef CONFIG_SAMV7_MCAN_REGDEBUG +# define canregdbg lldbg +# else +# define canregdbg(x...) +# endif + +#else +# define candbg(x...) +# define canvdbg(x...) +# define canlldbg(x...) +# define canllvdbg(x...) +# define canregdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* CAN mode of operation */ + +enum sam_canmode_e +{ + MCAN_ISO11898_1_MODE = 0, /* CAN operation according to ISO11898-1 */ + MCAN_FD_MODE = 1, /* CAN FD operation */ + MCAN_FD_BSW_MODE = 2 /* CAN FD operation with bit rate switching */ +}; + +/* CAN driver state */ + +enum can_state_s +{ + MCAN_STATE_UNINIT = 0, /* Not yet initialized */ + MCAN_STATE_RESET, /* Initialized, reset state */ + MCAN_STATE_SETUP, /* can_setup() has been called */ +}; + +/* This structure describes the MCAN message RAM layout */ + +struct sam_msgram_s +{ + uint32_t *stdfilters; /* Standard filters */ + uint32_t *extfilters; /* Extended filters */ + uint32_t *rxfifo0; /* RX FIFO0 */ + uint32_t *rxfifo1; /* RX FIFO1 */ + uint32_t *rxdedicated; /* RX dedicated buffers */ + uint32_t *txeventfifo; /* TX event FIFO */ + uint32_t *txdedicated; /* TX dedicated buffers */ + uint32_t *txfifoq; /* TX FIFO queue */ +}; + +/* This structure provides the constant configuration of a MCAN peripheral */ + +struct sam_config_s +{ + gpio_pinset_t rxpinset; /* RX pin configuration */ + gpio_pinset_t txpinset; /* TX pin configuration */ + xcpt_t handler; /* MCAN common interrupt handler */ + uintptr_t base; /* Base address of the MCAN registers */ + uint32_t baud; /* Configured baud */ + uint32_t btp; /* Bit timing/prescaler register setting */ + uint32_t fbtp; /* Fast bit timing/prescaler register setting */ + uint8_t port; /* MCAN port number (1 or 2) */ + uint8_t pid; /* MCAN peripheral ID */ + uint8_t irq0; /* MCAN peripheral IRQ number for interrupt line 0 */ + uint8_t irq1; /* MCAN peripheral IRQ number for interrupt line 1 */ + uint8_t mode; /* See enum sam_canmode_e */ + uint8_t nstdfilters; /* Number of standard filters (up to 128) */ + uint8_t nextfilters; /* Number of extended filters (up to 64) */ + uint8_t nrxfifo0; /* Number of RX FIFO0 elements (up to 64) */ + uint8_t nrxfifo1; /* Number of RX FIFO1 elements (up to 64) */ + uint8_t nrxdedicated; /* Number of dedicated RX buffers (up to 64) */ + uint8_t ntxeventfifo; /* Number of TXevent FIFO elements (up to 32) */ + uint8_t ntxdedicated; /* Number of dedicated TX buffers (up to 64) */ + uint8_t ntxfifoq; /* Number of TX FIFO queue elements (up to 32) */ + uint8_t rxfifo0ecode; /* Encoded RX FIFO0 element size */ + uint8_t rxfifo0esize; /* RX FIFO0 element size (words) */ + uint8_t rxfifo1ecode; /* Encoded RX FIFO1 element size */ + uint8_t rxfifo1esize; /* RX FIFO1 element size (words) */ + uint8_t rxbufferecode; /* Encoded RX buffer element size */ + uint8_t rxbufferesize; /* RX buffer element size (words) */ + uint8_t txbufferecode; /* Encoded TX buffer element size */ + uint8_t txbufferesize; /* TX buffer element size (words) */ +#ifdef SAMV7_MCAN_LOOPBACK + bool loopback; /* True: Loopback mode */ +#endif + + /* MCAN message RAM layout */ + + struct sam_msgram_s msgram; +}; + +/* This structure provides the current state of a MCAN peripheral */ + +struct sam_mcan_s +{ + const struct sam_config_s *config; /* The constant configuration */ + uint8_t state; /* See enum can_state_s */ +#ifdef CONFIG_CAN_EXTID + uint8_t nextalloc; /* Number of allocated extended filters */ +#endif + uint8_t nstdalloc; /* Number of allocated standard filters */ + sem_t locksem; /* Enforces mutually exclusive access */ + sem_t txfsem; /* Used to wait for TX FIFO availability */ + uint32_t btp; /* Current bit timing */ + uint32_t fbtp; /* Current fast bit timing */ + uint32_t rxints; /* Configured RX interrupts */ + uint32_t txints; /* Configured TX interrupts */ + +#ifdef CONFIG_CAN_EXTID + uint32_t extfilters[2]; /* Extended filter bit allocator. 2*32=64 */ +#endif + uint32_t stdfilters[4]; /* Standard filter bit allocator. 4*32=128 */ + +#ifdef CONFIG_SAMV7_MCAN_REGDEBUG + uintptr_t regaddr; /* Last register address read */ + uint32_t regval; /* Last value read from the register */ + unsigned int count; /* Number of times that the value was read */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* MCAN Register access */ + +static uint32_t mcan_getreg(FAR struct sam_mcan_s *priv, int offset); +static void mcan_putreg(FAR struct sam_mcan_s *priv, int offset, + uint32_t regval); +#ifdef CONFIG_SAMV7_MCAN_REGDEBUG +static void mcan_dumpregs(FAR struct sam_mcan_s *priv, FAR const char *msg); +#else +# define mcan_dumpregs(priv,msg) +#endif + +/* Semaphore helpers */ + +static void mcan_dev_lock(FAR struct sam_mcan_s *priv); +#define mcan_dev_unlock(priv) sem_post(&priv->locksem) + +static void mcan_buffer_reserve(FAR struct sam_mcan_s *priv); +static void mcan_buffer_release(FAR struct sam_mcan_s *priv); + +/* MCAN helpers */ + +static uint8_t mcan_dlc2bytes(FAR struct sam_mcan_s *priv, uint8_t dlc); +#if 0 /* Not used */ +static uint8_t mcan_bytes2dlc(FAR struct sam_mcan_s *priv, uint8_t nbytes); +#endif + +#ifdef CONFIG_CAN_EXTID +static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, + FAR struct canioc_extfilter_s *extconfig); +static int mcan_del_extfilter(FAR struct sam_mcan_s *priv, int ndx); +#endif +static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, + FAR struct canioc_stdfilter_s *stdconfig); +static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx); + +/* CAN driver methods */ + +static void mcan_reset(FAR struct can_dev_s *dev); +static int mcan_setup(FAR struct can_dev_s *dev); +static void mcan_shutdown(FAR struct can_dev_s *dev); +static void mcan_rxint(FAR struct can_dev_s *dev, bool enable); +static void mcan_txint(FAR struct can_dev_s *dev, bool enable); +static int mcan_ioctl(FAR struct can_dev_s *dev, int cmd, + unsigned long arg); +static int mcan_remoterequest(FAR struct can_dev_s *dev, uint16_t id); +static int mcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg); +static bool mcan_txready(FAR struct can_dev_s *dev); +static bool mcan_txempty(FAR struct can_dev_s *dev); + +/* MCAN interrupt handling */ + +#if 0 /* Not Used */ +static bool mcan_dedicated_rxbuffer_available(FAR struct sam_mcan_s *priv, + int bufndx); +#endif +static void mcan_error(FAR struct can_dev_s *dev, uint32_t status); +static void mcan_receive(FAR struct can_dev_s *dev, + FAR uint32_t *rxbuffer, unsigned long nwords); +static void mcan_interrupt(FAR struct can_dev_s *dev); +#ifdef CONFIG_SAMV7_MCAN0 +static int mcan0_interrupt(int irq, void *context); +#endif +#ifdef CONFIG_SAMV7_MCAN1 +static int mcan1_interrupt(int irq, void *context); +#endif + +/* Hardware initialization */ + +static int mcan_hw_initialize(FAR struct sam_mcan_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct can_ops_s g_mcanops = +{ + .co_reset = mcan_reset, + .co_setup = mcan_setup, + .co_shutdown = mcan_shutdown, + .co_rxint = mcan_rxint, + .co_txint = mcan_txint, + .co_ioctl = mcan_ioctl, + .co_remoterequest = mcan_remoterequest, + .co_send = mcan_send, + .co_txready = mcan_txready, + .co_txempty = mcan_txempty, +}; + +#ifdef CONFIG_SAMV7_MCAN0 +/* Message RAM allocation */ + +static uint32_t g_mcan0_msgram[MCAN0_MSGRAM_WORDS] +#ifdef CONFIG_ARMV7M_DCACHE + __attribute__((aligned(MCAN_ALIGN))); +#else + ; +#endif + +/* Constant configuration */ + +static const struct sam_config_s g_mcan0const = +{ + .rxpinset = GPIO_MCAN0_RX, + .txpinset = GPIO_MCAN0_TX, + .handler = mcan0_interrupt, + .base = SAM_MCAN0_BASE, + .baud = CONFIG_SAMV7_MCAN0_BITRATE, + .btp = MCAN_BTP_BRP(MCAN0_BRP) | MCAN_BTP_TSEG1(MCAN0_TSEG1) | + MCAN_BTP_TSEG2(MCAN0_TSEG2) | MCAN_BTP_SJW(MCAN0_SJW), + .fbtp = MCAN_FBTP_FBRP(MCAN0_FBRP) | MCAN_FBTP_FTSEG1(MCAN0_FTSEG1) | + MCAN_FBTP_FTSEG2(MCAN0_FTSEG2) | MCAN_FBTP_FSJW(MCAN0_FSJW), + .port = 0, + .pid = SAM_PID_MCAN00, + .irq0 = SAM_IRQ_MCAN00, + .irq1 = SAM_IRQ_MCAN01, +#if defined(CONFIG_SAMV7_MCAN0_ISO11899_1) + .mode = MCAN_ISO11898_1_MODE, +#elif defined(CONFIG_SAMV7_MCAN0_FD) + .mode = MCAN_FD_MODE, +#else /* if defined(CONFIG_SAMV7_MCAN0_FD_BSW) */ + .mode = MCAN_FD_BSW_MODE, +#endif + .nstdfilters = CONFIG_SAMV7_MCAN0_NSTDFILTERS, + .nextfilters = CONFIG_SAMV7_MCAN0_NEXTFILTERS, + .nrxfifo0 = CONFIG_SAMV7_MCAN0_RXFIFO0_SIZE, + .nrxfifo1 = CONFIG_SAMV7_MCAN0_RXFIFO1_SIZE, + .nrxdedicated = CONFIG_SAMV7_MCAN0_DEDICATED_RXBUFFER_SIZE, + .ntxeventfifo = CONFIG_SAMV7_MCAN0_TXEVENTFIFO_SIZE, + .ntxdedicated = CONFIG_SAMV7_MCAN0_DEDICATED_TXBUFFER_SIZE, + .ntxfifoq = CONFIG_SAMV7_MCAN0_TXFIFOQ_SIZE, + .rxfifo0ecode = MCAN0_RXFIFO0_ENCODED_SIZE, + .rxfifo0esize = (MCAN0_RXFIFO0_ELEMENT_SIZE / 4) + 2, + .rxfifo1ecode = MCAN0_RXFIFO1_ENCODED_SIZE, + .rxfifo1esize = (MCAN0_RXFIFO1_ELEMENT_SIZE / 4) + 2, + .rxbufferecode = MCAN0_RXBUFFER_ENCODED_SIZE, + .rxbufferesize = (MCAN0_RXBUFFER_ELEMENT_SIZE / 4) + 2, + .txbufferecode = MCAN0_TXBUFFER_ENCODED_SIZE, + .txbufferesize = (MCAN0_TXBUFFER_ELEMENT_SIZE / 4) + 2, + +#ifdef CONFIG_SAMV7_MCAN0_LOOPBACK + .loopback = true, +#endif + + /* MCAN0 Message RAM */ + + .msgram = + { + &g_mcan0_msgram[MCAN0_STDFILTER_INDEX], + &g_mcan0_msgram[MCAN0_EXTFILTERS_INDEX], + &g_mcan0_msgram[MCAN0_RXFIFO0_INDEX], + &g_mcan0_msgram[MCAN0_RXFIFO1_INDEX], + &g_mcan0_msgram[MCAN0_RXDEDICATED_INDEX], + &g_mcan0_msgram[MCAN0_TXEVENTFIFO_INDEX], + &g_mcan0_msgram[MCAN0_TXDEDICATED_INDEX], + &g_mcan0_msgram[MCAN0_TXFIFOQ_INDEX] + } +}; + +/* MCAN0 variable driver state */ + +static struct sam_mcan_s g_mcan0priv; +static struct can_dev_s g_mcan0dev; + +#endif /* CONFIG_SAMV7_MCAN0 */ + +#ifdef CONFIG_SAMV7_MCAN1 +/* MCAN1 message RAM allocation */ + +static uint32_t g_mcan1_msgram[MCAN1_MSGRAM_WORDS] +#ifdef CONFIG_ARMV7M_DCACHE + __attribute__((aligned(MCAN_ALIGN))); +#else + ; +#endif + +/* MCAN1 constant configuration */ + +static const struct sam_config_s g_mcan1const = +{ + .rxpinset = GPIO_MCAN1_RX, + .txpinset = GPIO_MCAN1_TX, + .handler = mcan1_interrupt, + .base = SAM_MCAN1_BASE, + .baud = CONFIG_SAMV7_MCAN1_BITRATE, + .btp = MCAN_BTP_BRP(MCAN1_BRP) | MCAN_BTP_TSEG1(MCAN1_TSEG1) | + MCAN_BTP_TSEG2(MCAN1_TSEG2) | MCAN_BTP_SJW(MCAN1_SJW), + .fbtp = MCAN_FBTP_FBRP(MCAN1_FBRP) | MCAN_FBTP_FTSEG1(MCAN1_FTSEG1) | + MCAN_FBTP_FTSEG2(MCAN1_FTSEG2) | MCAN_FBTP_FSJW(MCAN1_FSJW), + .port = 1, + .pid = SAM_PID_MCAN10, + .irq0 = SAM_IRQ_MCAN10, + .irq1 = SAM_IRQ_MCAN11, +#if defined(CONFIG_SAMV7_MCAN1_ISO11899_1) + .mode = MCAN_ISO11898_1_MODE, +#elif defined(CONFIG_SAMV7_MCAN1_FD) + .mode = MCAN_FD_MODE, +#else /* if defined(CONFIG_SAMV7_MCAN1_FD_BSW) */ + .mode = MCAN_FD_BSW_MODE, +#endif + .nstdfilters = CONFIG_SAMV7_MCAN1_NSTDFILTERS, + .nextfilters = CONFIG_SAMV7_MCAN1_NEXTFILTERS, + .nrxfifo0 = CONFIG_SAMV7_MCAN1_RXFIFO0_SIZE, + .nrxfifo1 = CONFIG_SAMV7_MCAN1_RXFIFO1_SIZE, + .nrxdedicated = CONFIG_SAMV7_MCAN1_DEDICATED_RXBUFFER_SIZE, + .ntxeventfifo = CONFIG_SAMV7_MCAN1_TXEVENTFIFO_SIZE, + .ntxdedicated = CONFIG_SAMV7_MCAN1_DEDICATED_TXBUFFER_SIZE, + .ntxfifoq = CONFIG_SAMV7_MCAN1_TXFIFOQ_SIZE, + .rxfifo0ecode = MCAN1_RXFIFO0_ENCODED_SIZE, + .rxfifo0esize = (MCAN1_RXFIFO0_ELEMENT_SIZE / 4) + 2, + .rxfifo1ecode = MCAN1_RXFIFO1_ENCODED_SIZE, + .rxfifo1esize = (MCAN1_RXFIFO1_ELEMENT_SIZE / 4) + 2, + .rxbufferecode = MCAN1_RXBUFFER_ENCODED_SIZE, + .rxbufferesize = (MCAN1_RXBUFFER_ELEMENT_SIZE / 4) + 2, + .txbufferecode = MCAN1_TXBUFFER_ENCODED_SIZE, + .txbufferesize = (MCAN1_TXBUFFER_ELEMENT_SIZE / 4) + 2, + +#ifdef CONFIG_SAMV7_MCAN1_LOOPBACK + .loopback = true, +#endif + /* MCAN0 Message RAM */ + + .msgram = + { + &g_mcan1_msgram[MCAN1_STDFILTER_INDEX], + &g_mcan1_msgram[MCAN1_EXTFILTERS_INDEX], + &g_mcan1_msgram[MCAN1_RXFIFO0_INDEX], + &g_mcan1_msgram[MCAN1_RXFIFO1_INDEX], + &g_mcan1_msgram[MCAN1_RXDEDICATED_INDEX], + &g_mcan1_msgram[MCAN1_TXEVENTFIFO_INDEX], + &g_mcan1_msgram[MCAN1_TXDEDICATED_INDEX], + &g_mcan1_msgram[MCAN1_TXFIFOQ_INDEX] + } +}; + +/* MCAN0 variable driver state */ + +static struct sam_mcan_s g_mcan1priv; +static struct can_dev_s g_mcan1dev; + +#endif /* CONFIG_SAMV7_MCAN1 */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mcan_getreg + * + * Description: + * Read the value of a MCAN register. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * offset - The offset to the register to read + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_MCAN_REGDEBUG +static uint32_t mcan_getreg(FAR struct sam_mcan_s *priv, int offset) +{ + FAR const struct sam_config_s *config = priv->config; + uintptr_t regaddr; + uint32_t regval; + + /* Read the value from the register */ + + regaddr = config->base + offset; + regval = getreg32(regaddr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (regaddr == priv->regaddr && regval == priv->regval) + { + if (priv->count == 0xffffffff || ++priv->count > 3) + { + if (priv->count == 4) + { + lldbg("...\n"); + } + + return regval; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (priv->count > 3) + { + /* Yes.. then show how many times the value repeated */ + + lldbg("[repeats %d more times]\n", priv->count - 3); + } + + /* Save the new address, value, and count */ + + priv->regaddr = regaddr; + priv->regval = regval; + priv->count = 1; + } + + /* Show the register value read */ + + lldbg("%08x->%08x\n", regaddr, regval); + return regval; +} + +#else +static uint32_t mcan_getreg(FAR struct sam_mcan_s *priv, int offset) +{ + FAR const struct sam_config_s *config = priv->config; + return getreg32(config->base + offset); +} + +#endif + +/**************************************************************************** + * Name: mcan_putreg + * + * Description: + * Set the value of a MCAN register. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * offset - The offset to the register to write + * regval - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_MCAN_REGDEBUG +static void mcan_putreg(FAR struct sam_mcan_s *priv, int offset, uint32_t regval) +{ + FAR const struct sam_config_s *config = priv->config; + uintptr_t regaddr = config->base + offset; + + /* Show the register value being written */ + + lldbg("%08x<-%08x\n", regaddr, regval); + + /* Write the value */ + + putreg32(regval, regaddr); +} + +#else +static void mcan_putreg(FAR struct sam_mcan_s *priv, int offset, uint32_t regval) +{ + FAR const struct sam_config_s *config = priv->config; + putreg32(regval, config->base + offset); +} + +#endif + +/**************************************************************************** + * Name: mcan_dumpregs + * + * Description: + * Dump the contents of all MCAN control registers + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_MCAN_REGDEBUG +static void mcan_dumpregs(FAR struct sam_mcan_s *priv, FAR const char *msg) +{ + FAR const struct sam_config_s *config = priv->config; + + lldbg("MCAN%d Registers: %s\n", config->port, msg); + lldbg(" Base: %08x\n", config->base); + + lldbg(" CUST: %08x FBTP: %08x TEST: %08x RWD: %08x\n", + getreg32(config->base + SAM_MCAN_CUST_OFFSET), + getreg32(config->base + SAM_MCAN_FBTP_OFFSET), + getreg32(config->base + SAM_MCAN_TEST_OFFSET), + getreg32(config->base + SAM_MCAN_RWD_OFFSET)); + + lldbg(" CCCR: %08x BTP: %08x TSCC: %08x TSCV: %08x\n", + getreg32(config->base + SAM_MCAN_CCCR_OFFSET), + getreg32(config->base + SAM_MCAN_BTP_OFFSET), + getreg32(config->base + SAM_MCAN_TSCC_OFFSET), + getreg32(config->base + SAM_MCAN_TSCV_OFFSET)); + + lldbg(" TOCC: %08x TOCV: %08x ECR: %08x PSR: %08x\n", + getreg32(config->base + SAM_MCAN_TOCC_OFFSET), + getreg32(config->base + SAM_MCAN_TOCV_OFFSET), + getreg32(config->base + SAM_MCAN_ECR_OFFSET), + getreg32(config->base + SAM_MCAN_PSR_OFFSET)); + + lldbg(" IR: %08x IE: %08x ILS: %08x ILE: %08x\n", + getreg32(config->base + SAM_MCAN_IR_OFFSET), + getreg32(config->base + SAM_MCAN_IE_OFFSET), + getreg32(config->base + SAM_MCAN_ILS_OFFSET), + getreg32(config->base + SAM_MCAN_ILE_OFFSET)); + + lldbg(" GFC: %08x SIDFC: %08x XIDFC: %08x XIDAM: %08x\n", + getreg32(config->base + SAM_MCAN_GFC_OFFSET), + getreg32(config->base + SAM_MCAN_SIDFC_OFFSET), + getreg32(config->base + SAM_MCAN_XIDFC_OFFSET), + getreg32(config->base + SAM_MCAN_XIDAM_OFFSET)); + + lldbg(" HPMS: %08x NDAT1: %08x NDAT2: %08x RXF0C: %08x\n", + getreg32(config->base + SAM_MCAN_HPMS_OFFSET), + getreg32(config->base + SAM_MCAN_NDAT1_OFFSET), + getreg32(config->base + SAM_MCAN_NDAT2_OFFSET), + getreg32(config->base + SAM_MCAN_RXF0C_OFFSET)); + + lldbg(" RXF0S: %08x FXF0A: %08x RXBC: %08x RXF1C: %08x\n", + getreg32(config->base + SAM_MCAN_RXF0S_OFFSET), + getreg32(config->base + SAM_MCAN_RXF0A_OFFSET), + getreg32(config->base + SAM_MCAN_RXBC_OFFSET), + getreg32(config->base + SAM_MCAN_RXF1C_OFFSET)); + + lldbg(" RXF1S: %08x FXF1A: %08x RXESC: %08x TXBC: %08x\n", + getreg32(config->base + SAM_MCAN_RXF1S_OFFSET), + getreg32(config->base + SAM_MCAN_RXF1A_OFFSET), + getreg32(config->base + SAM_MCAN_RXESC_OFFSET), + getreg32(config->base + SAM_MCAN_TXBC_OFFSET)); + + lldbg(" TXFQS: %08x TXESC: %08x TXBRP: %08x TXBAR: %08x\n", + getreg32(config->base + SAM_MCAN_TXFQS_OFFSET), + getreg32(config->base + SAM_MCAN_TXESC_OFFSET), + getreg32(config->base + SAM_MCAN_TXBRP_OFFSET), + getreg32(config->base + SAM_MCAN_TXBAR_OFFSET)); + + lldbg(" TXBCR: %08x TXBTO: %08x TXBCF: %08x TXBTIE: %08x\n", + getreg32(config->base + SAM_MCAN_TXBCR_OFFSET), + getreg32(config->base + SAM_MCAN_TXBTO_OFFSET), + getreg32(config->base + SAM_MCAN_TXBCF_OFFSET), + getreg32(config->base + SAM_MCAN_TXBTIE_OFFSET)); + + lldbg("TXBCIE: %08x TXEFC: %08x TXEFS: %08x TXEFA: %08x\n", + getreg32(config->base + SAM_MCAN_TXBCIE_OFFSET), + getreg32(config->base + SAM_MCAN_TXEFC_OFFSET), + getreg32(config->base + SAM_MCAN_TXEFS_OFFSET), + getreg32(config->base + SAM_MCAN_TXEFA_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: mcan_dev_lock + * + * Description: + * Take the semaphore that enforces mutually exclusive access to device + * structures, handling any exceptional conditions + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_dev_lock(FAR struct sam_mcan_s *priv) +{ + int ret; + + /* Wait until we successfully get the semaphore. EINTR is the only + * expected 'failure' (meaning that the wait for the semaphore was + * interrupted by a signal. + */ + + do + { + ret = sem_wait(&priv->locksem); + DEBUGASSERT(ret == 0 || errno == EINTR); + } + while (ret < 0); +} + +/**************************************************************************** + * Name: mcan_buffer_reserve + * + * Description: + * Take the semaphore, decrementing the semaphore count to indicate that + * one fewer TX FIFOQ buffer is available. Handles any exceptional + * conditions. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + * Assumptions: + * Called only non-interrupt logic via mcan_write(). We do not have + * exclusive access to the MCAN hardware and interrupts are not disabled. + * mcan_write() does lock the scheduler for reasons noted below. + * + ****************************************************************************/ + +static void mcan_buffer_reserve(FAR struct sam_mcan_s *priv) +{ + irqstate_t flags; + uint32_t txfqs1; + uint32_t txfqs2; + int sval; + int ret; + + /* Wait until we successfully get the semaphore. EINTR is the only + * expected 'failure' (meaning that the wait for the semaphore was + * interrupted by a signal. + */ + + do + { + /* We take some extra precautions here because it is possible that on + * certain error conditions, the semaphore count could get out of + * phase with the actual count of elements in the TX FIFO (I have + * never seen this happen, however. My paranoia). + * + * An missed TX interrupt could cause the semaphore count to fail to + * be incremented and, hence, to be too low. + */ + + for(;;) + { + /* Get the current queue status and semaphore count. */ + + flags = irqsave(); + txfqs1 = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + (void)sem_getvalue(&priv->txfsem, &sval); + txfqs2 = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + + /* If the semaphore count and the TXFQS samples are in + * sync, then break out of the look with interrupts + * disabled. + */ + + if (txfqs1 == txfqs2) + { + break; + } + + /* Otherwise, re-enable interrupts to interrupts that may + * resynchronize, the semaphore count and try again. + */ + + irqrestore(flags); + } + + /* We only have one useful bit of information in the TXFQS: + * Is the TX FIFOQ full or not? We can only do limited checks + * with that single bit of information. + */ + + if ((txfqs1 & MCAN_TXFQS_TFQF) != 0) + { + /* The TX FIFOQ is full. The semaphore count should then be + * less than or equal to zero. If it is greater than zero, + * then reinitialize it to 0. + */ + + if (sval > 0) + { + candbg("ERROR: TX FIFOQ full but txfsem is %d\n", sval); + sem_init(&priv->txfsem, 0, 0); + } + } + + /* The FIFO is not full so the semaphore count should be greater + * than zero. If it is not, then we have missed a call to + * mcan_buffer_release(0). + * + * NOTE: Since there is no mutual exclusion, it might be possible + * that mcan_write() could be re-entered AFTER taking the semaphore + * and dropping the count to zero, but BEFORE adding the message + * to the TX FIFOQ. That corner case is handled in mcan_write() by + * locking the scheduler. + */ + + else if (sval <= 0) + { + candbg("ERROR: TX FIFOQ not full but txfsem is %d\n", sval); + + /* Less than zero means that another thread is waiting */ + + if (sval < 0) + { + /* Bump up the count by one and try again */ + + sem_post(&priv->txfsem); + irqrestore(flags); + continue; + } + + /* Exactly zero but the FIFO is not full. Just return without + * decrementing the count. + */ + + irqrestore(flags); + return; + } + + /* The semaphore value is reasonable. Wait for the next TC interrupt. */ + + ret = sem_wait(&priv->txfsem); + irqrestore(flags); + DEBUGASSERT(ret == 0 || errno == EINTR); + } + while (ret < 0); +} + +/**************************************************************************** + * Name: mcan_buffer_release + * + * Description: + * Release the semaphore, increment the semaphore count to indicate that + * one more TX FIFOQ buffer is available. + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + * Assumptions: + * This function is called only from the interrupt level in response to the + * complete of a transmission. + * + ****************************************************************************/ + +static void mcan_buffer_release(FAR struct sam_mcan_s *priv) +{ + int sval; + + /* We take some extra precautions here because it is possible that on + * certain error conditions, the semaphore count could get out of phase + * with the actual count of elements in the TX FIFO (I have never seen + * this happen, however. My paranoia). + * + * An extra TC interrupt could cause the count to be incremented too + * many times. + */ + + (void)sem_getvalue(&priv->txfsem, &sval); + if (sval < priv->config->ntxfifoq) + { + sem_post(&priv->txfsem); + } + else + { + candbg("ERROR: txfsem would increment beyond %d\n", + priv->config->ntxfifoq); + } +} + +/**************************************************************************** + * Name: mcan_dlc2bytes + * + * Description: + * In the CAN FD format, the coding of the DLC differs from the standard + * CAN format. The DLC codes 0 to 8 have the same coding as in standard + * CAN. But the codes 9 to 15 all imply a data field of 8 bytes with + * standard CAN. In CAN FD mode, the values 9 to 15 are encoded to values + * in the range 12 to 64. + * + * Input Parameter: + * dlc - the DLC value to convert to a byte count + * + * Returned Value: + * The number of bytes corresponding to the DLC value. + * + ****************************************************************************/ + +static uint8_t mcan_dlc2bytes(FAR struct sam_mcan_s *priv, uint8_t dlc) +{ + if (dlc > 8) + { +#ifdef CONFIG_CAN_FD + if (priv->config->mode == MCAN_ISO11898_1_MODE) + { + return 8; + } + else + { + switch (dlc) + { + case 9: + return 12; + case 10: + return 16; + case 11: + return 20; + case 12: + return 24; + case 13: + return 32; + case 14: + return 48; + default: + case 15: + return 64; + } + } +#else + return 8; +#endif + } + + return dlc; +} + +/**************************************************************************** + * Name: mcan_bytes2dlc + * + * Description: + * In the CAN FD format, the coding of the DLC differs from the standard + * CAN format. The DLC codes 0 to 8 have the same coding as in standard + * CAN. But the codes 9 to 15 all imply a data field of 8 bytes with + * standard CAN. In CAN FD mode, the values 9 to 15 are encoded to values + * in the range 12 to 64. + * + * Input Parameter: + * nbytes - the byte count to convert to a DLC value + * + * Returned Value: + * The encoded DLC value corresponding to at least that number of bytes. + * + ****************************************************************************/ + +#if 0 /* Not used */ +static uint8_t mcan_bytes2dlc(FAR struct sam_mcan_s *priv, uint8_t nbytes) +{ + if (nbytes <= 8) + { + return nbytes; + } +#ifdef CONFIG_CAN_FD + else if (priv->mode == MCAN_ISO11898_1_MODE) + { + return 8; + } + else if (nbytes <= 12) + { + return 9; + } + else if (nbytes <= 16) + { + return 10; + } + else if (nbytes <= 20) + { + return 11; + } + else if (nbytes <= 24) + { + return 12; + } + else if (nbytes <= 32) + { + return 13; + } + else if (nbytes <= 48) + { + return 14; + } + else /* if (nbytes <= 64) */ + { + return 15; + } +#else + else + { + return 8; + } +#endif +} +#endif + +/**************************************************************************** + * Name: mcan_add_extfilter + * + * Description: + * Add an address filter for a extended 29 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * extconfig - The configuration of the extended filter + * + * Returned Value: + * A non-negative filter ID is returned on success. Otherwise a negated + * errno value is returned to indicate the nature of the error. + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_EXTID +static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, + FAR struct canioc_extfilter_s *extconfig) +{ + FAR const struct sam_config_s *config; + FAR uint32_t *extfilter; + uint32_t regval; + int word; + int bit; + int ndx; + + DEBUGASSERT(priv != NULL && priv->config != NULL && extconfig != NULL); + config = priv->config; + + /* Get exclusive excess to the MCAN hardware */ + + mcan_dev_lock(priv); + + /* Find an unused standard filter */ + + for (ndx = 0; ndx < config->nextfilters; ndx++) + { + /* Is this filter assigned? */ + + word = ndx >> 5; + bit = ndx & 0x1f; + + if ((priv->extfilters[word] & (1 << bit)) == 0) + { + /* No, assign the filter */ + + DEBUGASSERT(priv->nextalloc < priv->config->nstdfilters); + priv->extfilters[word] |= (1 << bit); + priv->nextalloc++; + + extfilter = config->msgram.extfilters + (ndx << 1); + + /* Format and write filter word F0 */ + + DEBUGASSERT(extconfig->xf_id1 <= CAN_MAX_EXTMSGID); + regval = EXTFILTER_F0_EFID1(extconfig->xf_id1); + + if (extconfig->xf_prio == 0) + { + regval |= EXTFILTER_F0_EFEC_FIFO0; + } + else + { + regval |= EXTFILTER_F0_EFEC_FIFO0; + } + + extfilter[0] = regval; + + /* Format and write filter word F1 */ + + DEBUGASSERT(extconfig->xf_id2 <= CAN_MAX_EXTMSGID); + regval = EXTFILTER_F1_EFID2(extconfig->xf_id2); + + switch (extconfig->xf_type) + { + default: + case CAN_FILTER_DUAL: + regval |= EXTFILTER_F1_EFT_DUAL; + break; + + case CAN_FILTER_MASK: + regval |= EXTFILTER_F1_EFT_CLASSIC; + break; + case CAN_FILTER_RANGE: + regval |= EXTFILTER_F1_EFT_RANGE; + break; + } + + extfilter[1] = regval; + + /* Flush the filter entry into physical RAM */ + + arch_clean_dcache((uintptr_t)extfilter, (uintptr_t)exfilter + 8); + + /* Is this the first extended filter? */ + + if (priv->nextalloc == 1) + { + /* Update the Global Filter Configuration so that received + * messages are rejected if they do not match the acceptance + * filter. + * + * ANFE=2: Discard all rejected frames + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFE_MASK; + regval |= MCAN_GFC_ANFE_REJECTED; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + + mcan_dev_unlock(priv); + return ndx; + } + } + + DEBUGASSERT(priv->nextalloc == priv->config->nextfilters); + mcan_dev_unlock(priv); + return -EAGAIN; +} +#endif + +/**************************************************************************** + * Name: mcan_del_extfilter + * + * Description: + * Remove an address filter for a standard 29 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * ndx - The filter index previously returned by the mcan_add_extfilter(). + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_EXTID +static int mcan_del_extfilter(FAR struct sam_mcan_s *priv, int ndx) +{ + FAR const struct sam_config_s *config; + FAR uint32_t *extfilter; + uint32_t regval; + int word; + int bit; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + DEBUGASSERT(ndx < config->nextfilters); + + /* Get exclusive excess to the MCAN hardware */ + + mcan_dev_lock(priv); + + /* Release the filter */ + + word = ndx >> 5; + bit = ndx & 0x1f; + priv->extfilters[word] &= ~(1 << bit); + + DEBUGASSERT(priv->nextalloc > 0); + priv->nextalloc--; + + /* Was that the last extended filter? */ + + if (priv->nextalloc == 0) + { + /* If there are no extended filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFE=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFE_MASK; + regval |= MCAN_GFC_ANFE_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + + /* Deactivate the filter last so that no messages are lost. */ + + extfilter = config->msgram.extfilters + (ndx << 1); + *extfilter++ = 0; + *extfilter = 0; + + mcan_dev_unlock(priv); + return OK; +} +#endif + +/**************************************************************************** + * Name: mcan_add_stdfilter + * + * Description: + * Add an address filter for a standard 11 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * stdconfig - The configuration of the standard filter + * + * Returned Value: + * A non-negative filter ID is returned on success. Otherwise a negated + * errno value is returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, + FAR struct canioc_stdfilter_s *stdconfig) +{ + FAR const struct sam_config_s *config; + FAR uint32_t *stdfilter; + uint32_t regval; + int word; + int bit; + int ndx; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + + /* Get exclusive excess to the MCAN hardware */ + + mcan_dev_lock(priv); + + /* Find an unused standard filter */ + + for (ndx = 0; ndx < config->nstdfilters; ndx++) + { + /* Is this filter assigned? */ + + word = ndx >> 5; + bit = ndx & 0x1f; + + if ((priv->stdfilters[word] & (1 << bit)) == 0) + { + /* No, assign the filter */ + + DEBUGASSERT(priv->nstdalloc < priv->config->nstdfilters); + priv->stdfilters[word] |= (1 << bit); + priv->nstdalloc++; + + /* Format and write filter word S0 */ + + stdfilter = config->msgram.stdfilters + ndx; + + DEBUGASSERT(stdconfig->sf_id1 <= CAN_MAX_STDMSGID); + regval = STDFILTER_S0_SFID1(stdconfig->sf_id1); + + DEBUGASSERT(stdconfig->sf_id2 <= CAN_MAX_STDMSGID); + regval |= STDFILTER_S0_SFID2(stdconfig->sf_id2); + + if (stdconfig->sf_prio == 0) + { + regval |= STDFILTER_S0_SFEC_FIFO0; + } + else + { + regval |= STDFILTER_S0_SFEC_FIFO1; + } + + switch (stdconfig->sf_type) + { + default: + case CAN_FILTER_DUAL: + regval |= STDFILTER_S0_SFT_DUAL; + break; + + case CAN_FILTER_MASK: + regval |= STDFILTER_S0_SFT_CLASSIC; + break; + case CAN_FILTER_RANGE: + regval |= STDFILTER_S0_SFT_RANGE; + break; + } + + *stdfilter = regval; + + /* Flush the filter entry into physical RAM */ + + arch_clean_dcache((uintptr_t)stdfilter, (uintptr_t)stdfilter + 4); + + /* Is this the first standard filter? */ + + if (priv->nstdalloc == 1) + { + /* Update the Global Filter Configuration so that received + * messages are rejected if they do not match the acceptance + * filter. + * + * ANFS=2: Discard all rejected frames + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFS_MASK; + regval |= MCAN_GFC_ANFS_REJECTED; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + + mcan_dev_unlock(priv); + return ndx; + } + } + + DEBUGASSERT(priv->nstdalloc == priv->config->nstdfilters); + mcan_dev_unlock(priv); + return -EAGAIN; +} + +/**************************************************************************** + * Name: mcan_del_stdfilter + * + * Description: + * Remove an address filter for a standard 29 bit address. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * ndx - The filter index previously returned by the mcan_add_stdfilter(). + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx) +{ + FAR const struct sam_config_s *config; + FAR uint32_t *stdfilter; + uint32_t regval; + int word; + int bit; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + config = priv->config; + DEBUGASSERT(ndx < config->nstdfilters); + + /* Get exclusive excess to the MCAN hardware */ + + mcan_dev_lock(priv); + + /* Release the filter */ + + word = ndx >> 5; + bit = ndx & 0x1f; + priv->stdfilters[word] &= ~(1 << bit); + + DEBUGASSERT(priv->nstdalloc > 0); + priv->nstdalloc--; + + /* Was that the last standard filter? */ + + if (priv->nstdalloc == 0) + { + /* If there are no standard filters, then modify Global Filter + * Configuration so that all rejected messages are places in RX + * FIFO0. + * + * ANFS=0: Store all rejected extended frame in RX FIFO0 + */ + + regval = mcan_getreg(priv, SAM_MCAN_GFC_OFFSET); + regval &= ~MCAN_GFC_ANFS_MASK; + regval |= MCAN_GFC_ANFS_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + } + + /* Deactivate the filter last so that no messages are lost. */ + + stdfilter = config->msgram.stdfilters + ndx; + *stdfilter = 0; + + mcan_dev_unlock(priv); + return OK; +} + +/**************************************************************************** + * Name: mcan_reset + * + * Description: + * Reset the MCAN device. Called early to initialize the hardware. This + * function is called, before mcan_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_reset(FAR struct can_dev_s *dev) +{ + FAR struct sam_mcan_s *priv; + FAR const struct sam_config_s *config; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + canllvdbg("MCAN%d\n", config->port); + UNUSED(config); + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + + /* Disable all interrupts */ + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, 0); + + /* Make sure that all buffers are released. + * + * REVISIT: What if a thread is waiting for a buffer? The following + * will not wake up any waiting threads. + */ + + sem_destroy(&priv->txfsem); + sem_init(&priv->txfsem, 0, config->ntxfifoq); + + /* Disable peripheral clocking to the MCAN controller */ + + sam_disableperiph1(priv->config->pid); + priv->state = MCAN_STATE_RESET; + mcan_dev_unlock(priv); +} + +/**************************************************************************** + * Name: mcan_setup + * + * Description: + * Configure the MCAN. This method is called the first time that the MCAN + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching MCAN interrupts. + * All MCAN interrupts are disabled upon return. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_setup(FAR struct can_dev_s *dev) +{ + FAR struct sam_mcan_s *priv; + FAR const struct sam_config_s *config; + int ret; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + canllvdbg("MCAN%d pid: %d\n", config->port, config->pid); + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + + /* MCAN hardware initialization */ + + ret = mcan_hw_initialize(priv); + if (ret < 0) + { + canlldbg("MCAN%d H/W initialization failed: %d\n", config->port, ret); + return ret; + } + + mcan_dumpregs(priv, "After hardware initialization"); + + /* Attach the MCAN interrupt handlers */ + + ret = irq_attach(config->irq0, config->handler); + if (ret < 0) + { + canlldbg("Failed to attach MCAN%d line 0 IRQ (%d)", + config->port, config->irq0); + return ret; + } + + ret = irq_attach(config->irq1, config->handler); + if (ret < 0) + { + canlldbg("Failed to attach MCAN%d line 1 IRQ (%d)", + config->port, config->irq1); + return ret; + } + + /* Enable receive interrupts */ + + priv->state = MCAN_STATE_SETUP; + mcan_rxint(dev, true); + + mcan_dumpregs(priv, "After receive setup"); + + /* Enable the interrupts at the NVIC (they are still disabled at the MCAN + * peripheral). */ + + up_enable_irq(config->irq0); + up_enable_irq(config->irq1); + mcan_dev_unlock(priv); + return OK; +} + +/**************************************************************************** + * Name: mcan_shutdown + * + * Description: + * Disable the MCAN. This method is called when the MCAN device is closed. + * This method reverses the operation the setup method. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_shutdown(FAR struct can_dev_s *dev) +{ + FAR struct sam_mcan_s *priv; + FAR const struct sam_config_s *config; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv); + config = priv->config; + DEBUGASSERT(config); + + canllvdbg("MCAN%d\n", config->port); + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + + /* Disable MCAN interrupts at the NVIC */ + + up_disable_irq(config->irq0); + up_disable_irq(config->irq1); + + /* Disable all interrupts from the MCAN peripheral */ + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, 0); + + /* Detach the MCAN interrupt handler */ + + irq_detach(config->irq0); + irq_detach(config->irq1); + + /* Disable peripheral clocking to the MCAN controller */ + + sam_disableperiph1(priv->config->pid); + mcan_dev_unlock(priv); +} + +/**************************************************************************** + * Name: mcan_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_rxint(FAR struct can_dev_s *dev, bool enable) +{ + FAR struct sam_mcan_s *priv = dev->cd_priv; + irqstate_t flags; + uint32_t regval; + + DEBUGASSERT(priv && priv->config); + + canllvdbg("MCAN%d enable: %d\n", priv->config->port, enable); + + /* Enable/disable the receive interrupts */ + + flags = irqsave(); + regval = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + + if (enable) + { + regval |= priv->rxints | MCAN_COMMON_INTS; + } + else + { + regval &= ~priv->rxints; + } + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, regval); + irqrestore(flags); +} + +/**************************************************************************** + * Name: mcan_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_txint(FAR struct can_dev_s *dev, bool enable) +{ + FAR struct sam_mcan_s *priv = dev->cd_priv; + irqstate_t flags; + uint32_t regval; + + DEBUGASSERT(priv && priv->config); + + canllvdbg("MCAN%d enable: %d\n", priv->config->port, enable); + + /* Enable/disable the receive interrupts */ + + flags = irqsave(); + regval = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + + if (enable) + { + regval |= priv->txints | MCAN_COMMON_INTS; + } + else + { + regval &= ~priv->txints; + } + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, regval); + irqrestore(flags); +} + +/**************************************************************************** + * Name: mcan_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg) +{ + FAR struct sam_mcan_s *priv; + int ret = -ENOTTY; + + canvdbg("cmd=%04x arg=%lu\n", cmd, arg); + + DEBUGASSERT(dev && dev->cd_priv); + priv = dev->cd_priv; + + /* Handle the command */ + + switch (cmd) + { + /* CANIOC_GET_BITTIMING: + * Description: Return the current bit timing settings + * Argument: A pointer to a write-able instance of struct + * canioc_bittiming_s in which current bit timing values + * will be returned. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR) + * is returned with the errno variable set to indicate the + * nature of the error. + * Dependencies: None + */ + + case CANIOC_GET_BITTIMING: + { + FAR struct canioc_bittiming_s *bt = + (FAR struct canioc_bittiming_s *)arg; + uint32_t regval; + uint32_t brp; + + DEBUGASSERT(bt != NULL); + + regval = mcan_getreg(priv, SAM_MCAN_BTP_OFFSET); + bt->bt_sjw = ((regval & MCAN_BTP_SJW_MASK) >> MCAN_BTP_SJW_SHIFT) + 1; + bt->bt_tseg1 = ((regval & MCAN_BTP_TSEG1_MASK) >> MCAN_BTP_TSEG1_SHIFT) + 1; + bt->bt_tseg2 = ((regval & MCAN_BTP_TSEG2_MASK) >> MCAN_BTP_TSEG2_SHIFT) + 1; + + brp = ((regval & MCAN_BTP_BRP_MASK) >> MCAN_BTP_BRP_SHIFT) + 1; + bt->bt_baud = SAMV7_MCANCLK_FREQUENCY / brp / + (bt->bt_tseg1 + bt->bt_tseg2 + 1); + ret = OK; + } + break; + + /* CANIOC_SET_BITTIMING: + * Description: Set new current bit timing values + * Argument: A pointer to a read-able instance of struct + * canioc_bittiming_s in which the new bit timing values + * are provided. + * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR) + * is returned with the errno variable set to indicate the + * nature of the error. + * Dependencies: None + * + * REVISIT: There is probably a limitation here: If there are multiple + * threads trying to send CAN packets, when one of these threads reconfigures + * the bitrate, the MCAN hardware will be reset and the context of operation + * will be lost. Hence, this IOCTL can only safely be executed in quiescent + * time periods. + */ + + case CANIOC_SET_BITTIMING: + { + FAR const struct canioc_bittiming_s *bt = + (FAR const struct canioc_bittiming_s *)arg; + irqstate_t flags; + uint32_t brp; + uint32_t tseg1; + uint32_t tseg2; + uint32_t sjw; + uint32_t ie; + uint8_t state; + + DEBUGASSERT(bt != NULL); + DEBUGASSERT(bt->bt_baud < SAMV7_MCANCLK_FREQUENCY); + DEBUGASSERT(bt->bt_sjw > 0 && bt->bt_sjw <= 16); + DEBUGASSERT(bt->bt_tseg1 > 0 && bt->bt_tseg1 <= 16); + DEBUGASSERT(bt->bt_tseg2 > 1 && bt->bt_tseg2 <= 64); + + /* Extract bit timing data */ + + tseg1 = bt->bt_tseg1 - 1; + tseg2 = bt->bt_tseg2 - 1; + sjw = bt->bt_sjw - 1; + + brp = (uint32_t) + (((float) SAMV7_MCANCLK_FREQUENCY / + ((float)(tseg1 + tseg2 + 3) * (float)bt->bt_baud)) - 1); + + /* Save the value of the new bit timing register */ + + flags = irqsave(); + priv->btp = MCAN_BTP_BRP(brp) | MCAN_BTP_TSEG1(tseg1) | + MCAN_BTP_TSEG2(tseg2) | MCAN_BTP_SJW(sjw); + + /* We need to reset to instantiate the new timing. Save + * current state information so that recover to this + * state. + */ + + ie = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + state = priv->state; + + /* Reset the MCAN */ + + mcan_reset(dev); + ret = OK; + + /* If we have previously been setup, then setup again */ + + if (state == MCAN_STATE_SETUP) + { + ret = mcan_setup(dev); + } + + /* We we have successfully re-initialized, then restore the + * interrupt state. + * + * REVISIT: Since the hardware was reset, any pending TX + * activity was lost. Should we disable TX interrupts? + */ + + if (ret == OK) + { + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, ie & ~priv->txints); + } + + irqrestore(flags); + } + break; + +#ifdef CONFIG_CAN_EXTID + /* CANIOC_ADD_EXTFILTER: + * Description: Add an address filter for a extended 29 bit + * address. + * Argument: A reference to struct canioc_extfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_EXTFILTER: + { + DEBUGASSERT(arg != 0); + ret = mcan_add_extfilter(priv, (FAR struct canioc_extfilter_s *)arg); + } + break; + + /* CANIOC_DEL_EXTFILTER: + * Description: Remove an address filter for a standard 29 bit address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_EXTFILTER command + * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR) + * is returned with the errno variable set to indicate the + * nature of the error. + */ + + case CANIOC_DEL_EXTFILTER: + { + DEBUGASSERT(arg <= priv->config->nextfilters); + ret = mcan_del_extfilter(priv, (int)arg); + } + break; +#endif + + /* CANIOC_ADD_STDFILTER: + * Description: Add an address filter for a standard 11 bit + * address. + * Argument: A reference to struct canioc_stdfilter_s + * Returned Value: A non-negative filter ID is returned on success. + * Otherwise -1 (ERROR) is returned with the errno + * variable set to indicate the nature of the error. + */ + + case CANIOC_ADD_STDFILTER: + { + DEBUGASSERT(arg != 0); + ret = mcan_add_stdfilter(priv, (FAR struct canioc_stdfilter_s *)arg); + } + break; + + /* CANIOC_DEL_STDFILTER: + * Description: Remove an address filter for a standard 11 bit address. + * Argument: The filter index previously returned by the + * CANIOC_ADD_STDFILTER command + * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR) + * is returned with the errno variable set to indicate the + * nature of the error. + */ + + case CANIOC_DEL_STDFILTER: + { + DEBUGASSERT(arg <= priv->config->nstdfilters); + ret = mcan_del_stdfilter(priv, (int)arg); + } + break; + + /* Unsupported/unrecognized command */ + + default: + candbg("ERROR: Unrecognized command: %04x\n", cmd); + break; + } + + /* No CAN ioctls are supported */ + + return ret; +} + +/**************************************************************************** + * Name: mcan_remoterequest + * + * Description: + * Send a remote request + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_remoterequest(FAR struct can_dev_s *dev, uint16_t id) +{ + /* REVISIT: Remote request not implemented */ + + return -ENOSYS; +} + +/**************************************************************************** + * Name: mcan_send + * + * Description: + * Send one can message. + * + * One CAN-message consists of a maximum of 10 bytes. A message is + * composed of at least the first 2 bytes (when there are no data bytes). + * + * Byte 0: Bits 0-7: Bits 3-10 of the 11-bit CAN identifier + * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier + * Bit 4: Remote Transmission Request (RTR) + * Bits 0-3: Data Length Code (DLC) + * Bytes 2-10: CAN data + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int mcan_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) +{ + FAR struct sam_mcan_s *priv; + FAR const struct sam_config_s *config; + FAR uint32_t *txbuffer = 0; + FAR const uint8_t *src; + FAR uint8_t *dest; + uint32_t regval; + unsigned int msglen; + unsigned int ndx; + unsigned int nbytes; + unsigned int i; + + DEBUGASSERT(dev); + priv = dev->cd_priv; + DEBUGASSERT(priv && priv->config); + config = priv->config; + + canllvdbg("MCAN%d\n", config->port); + canllvdbg("MCAN%d ID: %d DLC: %d\n", + config->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); + + /* That that FIFO elements were configured. + * + * REVISIT: Dedicated TX buffers are not used by this driver. + */ + + DEBUGASSERT(config->ntxfifoq > 0); + + /* Reserve a buffer for the transmission, waiting if necessary. When + * mcan_buffer_reserve() returns, we are guaranteed the the TX FIFOQ is + * not full and cannot become full at least until we add our packet to + * the FIFO. + * + * We can't get exclusive access to MAN resource here because that + * lock the MCAN while we wait for a free buffer. Instead, the + * scheduler is locked here momentarily. See discussion in + * mcan_buffer_reserve() for an explanation. + * + * REVISIT: This needs to be extended in order to handler case where + * the MCAN device was opened O_NONBLOCK. + */ + + sched_lock(); + mcan_buffer_reserve(priv); + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + sched_unlock(); + + /* Get our reserved Tx FIFO/queue put index */ + + regval = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + DEBUGASSERT((regval & MCAN_TXFQS_TFQF) == 0); + + ndx = (regval & MCAN_TXFQS_TFQPI_MASK) >> MCAN_TXFQS_TFQPI_SHIFT; + + /* And the TX buffer corresponding to this index */ + + txbuffer = config->msgram.txdedicated + ndx * config->txbufferesize; + + /* Format the TX FIFOQ entry + * + * Format word T1: + * Transfer message ID (ID) - Value from message structure + * Remote Transmission Request (RTR) - Value from message structure + * Extended Identifier (XTD) - Depends on configuration. + */ + +#ifdef CONFIG_CAN_EXTID + if (msg->cm_hdr.ch_extid) + { + DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_EXTMSGID); + + regval = BUFFER_R0_EXTID(msg->cm_hdr.ch_id) | BUFFER_R0_XTD; + } + else +#endif + { + DEBUGASSERT(msg->cm_hdr.ch_id <= CAN_MAX_STDMSGID); + + regval = BUFFER_R0_STDID(msg->cm_hdr.ch_id); + } + + if (msg->cm_hdr.ch_rtr) + { + regval |= BUFFER_R0_RTR; + } + + txbuffer[0] = regval; + canregdbg("T0: %08x\n", regval); + + /* Format word T1: + * Data Length Code (DLC) - Value from message structure + * Event FIFO Control (EFC) - Do not store events. + * Message Marker (MM) - Always zero + */ + + txbuffer[1] = BUFFER_R1_DLC(msg->cm_hdr.ch_dlc); + canregdbg("T1: %08x\n", txbuffer[1]); + + /* Followed by the amount of data corresponding to the DLC (T2..) */ + + dest = (FAR uint8_t*)&txbuffer[2]; + src = msg->cm_data; + nbytes = mcan_dlc2bytes(priv, msg->cm_hdr.ch_dlc); + + for (i = 0; i < nbytes; i++) + { + /* Little endian is assumed */ + + *dest++ = *src++; + } + + /* Flush the D-Cache to memory before initiating the transfer */ + + msglen = 2 * sizeof(uint32_t) + nbytes; + arch_clean_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + msglen); + UNUSED(msglen); + + /* Enable transmit interrupts from the TX FIFOQ buffer by setting TC + * interrupt bit in IR (also requires that the TC interrupt is enabled) + */ + + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, (1 << ndx)); + + /* And request to send the packet */ + + mcan_putreg(priv, SAM_MCAN_TXBAR_OFFSET, (1 << ndx)); + + /* Report that the TX transfer is complete to the upper half logic. Of + * course, the transfer is not complete, but this early notification + * allows the upper half logic to free resources sooner. + * + * REVISTI: Should we disable interrupts? can_txdone() was designed to + * be called from and interrupt handler and, hence, may be unsafe when + * called from the tasking level. + */ + + can_txdone(dev); + + mcan_dev_unlock(priv); + return OK; +} + +/**************************************************************************** + * Name: mcan_txready + * + * Description: + * Return true if the MCAN hardware can accept another TX message. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if the MCAN hardware is ready to accept another TX message. + * + ****************************************************************************/ + +static bool mcan_txready(FAR struct can_dev_s *dev) +{ + FAR struct sam_mcan_s *priv = dev->cd_priv; + uint32_t regval; + bool notfull; +#ifdef CONFIG_DEBUG + int sval; +#endif + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * not full. + * + * REVISIT: Dedicated TX buffers are not supported. + */ + + regval = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + notfull = ((regval & MCAN_TXFQS_TFQF) == 0); + +#ifdef CONFIG_DEBUG + /* As a sanity check, the txfsem should also track the number of elements + * the TX FIFO/queue. Make sure that they are consistent. + */ + + (void)sem_getvalue(&priv->txfsem, &sval); + DEBUGASSERT(((notfull && sval > 0) || (!notfull && sval <= 0)) && + (sval <= priv->config->ntxfifoq)); +#endif + + mcan_dev_unlock(priv); + return notfull; +} + +/**************************************************************************** + * Name: mcan_txempty + * + * Description: + * Return true if all message have been sent. If for example, the MCAN + * hardware implements FIFOs, then this would mean the transmit FIFO is + * empty. This method is called when the driver needs to make sure that + * all characters are "drained" from the TX hardware before calling + * co_shutdown(). + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if there are no pending TX transfers in the MCAN hardware. + * + ****************************************************************************/ + +static bool mcan_txempty(FAR struct can_dev_s *dev) +{ + FAR struct sam_mcan_s *priv = dev->cd_priv; + uint32_t regval; + int sval; + bool empty; + + DEBUGASSERT(priv != NULL && priv->config != NULL); + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + + /* Return the state of the TX FIFOQ. Return TRUE if the TX FIFO/Queue is + * empty. We don't have a reliable indication that the FIFO is empty, so + * we have to use some heuristics. + * + * REVISIT: Dedicated TX buffers are not supported. + */ + + regval = mcan_getreg(priv, SAM_MCAN_TXFQS_OFFSET); + if (((regval & MCAN_TXFQS_TFQF) != 0)) + { + return false; + } + + /* The TX FIFO/Queue is not full, but is it empty? The txfsem should + * track the number of elements the TX FIFO/queue in use. + * + * Since the FIFO is not full, the semaphore count should be greater + * than zero. If it is equal to the full count of TX FIFO/Queue + * elements, then there is no transfer in progress. + */ + + (void)sem_getvalue(&priv->txfsem, &sval); + DEBUGASSERT(sval > 0 && sval <= priv->config->ntxfifoq); + + empty = (sval == priv->config->ntxfifoq); + mcan_dev_unlock(priv); + return empty; +} + +/**************************************************************************** + * Name: mcan_dedicated_rxbuffer_available + * + * Description: + * Check if data is available in a dedicated RX buffer. + * + * Input Parameters: + * priv - MCAN-specific private data + * bufndx - Buffer index + * + * None + * Returned Value: + * True: Data is available + * + ***************************************************************************/ + +#if 0 /* Not Used */ +bool mcan_dedicated_rxbuffer_available(FAR struct sam_mcan_s *priv, int bufndx) +{ + if (bufndx < 32) + { + return (bool)(mcan->MCAN_NDAT1 & (1 << bufndx)); + } + else if (bufndx < 64) + { + return (bool)(mcan->MCAN_NDAT1 & (1 << (bufndx - 32))); + } + else + { + return false; + } +} +#endif + +/**************************************************************************** + * Name: mcan_error + * + * Description: + * Report a CAN error + * + * Input Parameters: + * dev - CAN-common state data + * status - Interrupt status with error bits set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_error(FAR struct can_dev_s *dev, uint32_t status) +{ + struct can_hdr_s hdr; + uint16_t errbits; + int ret; + + /* Encode error bits */ + + errbits = 0; + if ((status & (MCAN_INT_ELO | MCAN_INT_EW)) != 0) + { + errbits |= CAN_ERROR_SYSTEM; + } + + if ((status & (MCAN_INT_RF0L | MCAN_INT_RF1L)) != 0) + { + errbits |= CAN_ERROR_RXLOST; + } + + if ((status & MCAN_INT_TEFL) != 0) + { + errbits |= CAN_ERROR_TXLOST; + } + + if ((status & (MCAN_INT_MRAF | MCAN_INT_BO)) != 0) + { + errbits |= CAN_ERROR_ACCESS; + } + + if ((status & MCAN_INT_TOO) != 0) + { + errbits |= CAN_ERROR_TIMEOUT; + } + + if ((status & MCAN_INT_EP) != 0) + { + errbits |= CAN_ERROR_PASSIVE; + } + + if ((status & MCAN_INT_CRCE) != 0) + { + errbits |= CAN_ERROR_CRC; + } + + if ((status & MCAN_INT_BE) != 0) + { + errbits |= CAN_ERROR_BIT; + } + + if ((status & MCAN_INT_ACKE) != 0) + { + errbits |= CAN_ERROR_ACK; + } + + if ((status & MCAN_INT_FOE) != 0) + { + errbits |= CAN_ERROR_FORMAT; + } + + if ((status & MCAN_INT_STE) != 0) + { + errbits |= CAN_ERROR_STUFF; + } + + if (errbits != 0) + { + /* Format the CAN header for the error report. */ + + hdr.ch_id = errbits; + hdr.ch_dlc = 0; + hdr.ch_rtr = 0; + hdr.ch_error = 1; +#ifdef CONFIG_CAN_EXTID + hdr.ch_extid = 0; +#endif + hdr.ch_unused = 0; + + /* And provide the error report to the upper half logic */ + + ret = can_receive(dev, &hdr, NULL); + if (ret < 0) + { + canlldbg("ERROR: can_receive failed: %d\n", ret); + } + } +} + +/**************************************************************************** + * Name: mcan_receive + * + * Description: + * Receive an MCAN messages + * + * Input Parameters: + * dev - CAN-common state data + * rxbuffer - The RX buffer containing the received messages + * nwords - The length of the RX buffer (element size in words). + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_receive(FAR struct can_dev_s *dev, FAR uint32_t *rxbuffer, + unsigned long nwords) +{ + struct can_hdr_s hdr; + uint32_t regval; + unsigned int nbytes; + int ret; + + /* Invalidate the D-Cache so that we reread the RX buffer data from memory. */ + + nbytes = (nwords << 2); + arch_invalidate_dcache((uintptr_t)rxbuffer, (uintptr_t)rxbuffer + nbytes); + + /* Format the CAN header */ + /* Work R0 contains the CAN ID */ + + regval = *rxbuffer++; + canregdbg("R0: %08x\n", regval); + + hdr.ch_rtr = 0; + hdr.ch_error = 0; + hdr.ch_unused = 0; + +#ifdef CONFIG_CAN_EXTID + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Save the extended ID of the newly received message */ + + hdr.ch_id = (regval & BUFFER_R0_EXTID_MASK) >> BUFFER_R0_EXTID_SHIFT; + hdr.ch_extid = true; + } + else + { + hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; + hdr.ch_extid = false; + } + +#else + if ((regval & BUFFER_R0_XTD) != 0) + { + /* Drop any messages with extended IDs */ + + return; + } + + /* Save the standard ID of the newly received message */ + + hdr.ch_id = (regval & BUFFER_R0_STDID_MASK) >> BUFFER_R0_STDID_SHIFT; +#endif + + /* Word R1 contains the DLC and timestamp */ + + regval = *rxbuffer++; + canregdbg("R1: %08x\n", regval); + + hdr.ch_dlc = (regval & BUFFER_R1_DLC_MASK) >> BUFFER_R1_DLC_SHIFT; + + /* And provide the CAN message to the upper half logic */ + + ret = can_receive(dev, &hdr, (FAR uint8_t *)rxbuffer); + if (ret < 0) + { + canlldbg("ERROR: can_receive failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: mcan_interrupt + * + * Description: + * Common MCAN interrupt handler + * + * Input Parameters: + * dev - CAN-common state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mcan_interrupt(FAR struct can_dev_s *dev) +{ + FAR struct sam_mcan_s *priv = dev->cd_priv; + FAR const struct sam_config_s *config; + uint32_t ir; + uint32_t ie; + uint32_t pending; + uint32_t regval; + unsigned int nelem; + unsigned int ndx; + bool handled; + + DEBUGASSERT(priv && priv->config); + config = priv->config; + + /* Loop while there are pending interrupt events */ + + do + { + /* Get the set of pending interrupts. */ + + ir = mcan_getreg(priv, SAM_MCAN_IR_OFFSET); + ie = mcan_getreg(priv, SAM_MCAN_IE_OFFSET); + + pending = (ir & ie); + handled = false; + + /* Check for common errors */ + + if ((pending & MCAN_CMNERR_INTS) != 0) + { + canlldbg("ERROR: Common %08x\n", pending & MCAN_CMNERR_INTS); + + /* Clear the error indications */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_CMNERR_INTS); + + /* Report errors */ + + mcan_error(dev, pending & MCAN_CMNERR_INTS); + handled = true; + } + + /* Check for transmission errors */ + + if ((pending & MCAN_TXERR_INTS) != 0) + { + canlldbg("ERROR: TX %08x\n", pending & MCAN_TXERR_INTS); + + /* Clear the error indications */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_TXERR_INTS); + + /* Report errors */ + + mcan_error(dev, pending & MCAN_TXERR_INTS); + + /* REVISIT: Will MCAN_INT_TC also be set in the event of + * a transmission error? Each write must conclude with a + * call to man_buffer_release(), whether or not the write + * was successful. + * + * Here we force transmit complete processing just in case. + * This could have the side effect of pushing the semaphore + * count up to high. + */ + + pending |= MCAN_INT_TC; + handled = true; + } + + /* Check for successful completion of a transmission */ + + if ((pending & MCAN_INT_TC) != 0) + { + /* Clear the pending TX completion interrupt (and all + * other TX-related interrupts) + */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, priv->txints); + + /* Indicate that there is one more buffer free in the TX FIFOQ by + * "releasing" it. This may have the effect of waking up a thread + * that has been waiting for a free TX FIFOQ buffer. + * + * REVISIT: TX dedicated buffers are not supported. + */ + + mcan_buffer_release(priv); + handled = true; + } + else if ((pending & priv->txints) != 0) + { + /* Clear unhandled TX events */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, priv->txints); + handled = true; + } + +#if 0 /* Not used */ + /* Check if a message has been stored to the dedicated RX buffer (DRX) */ + + if ((pending & MCAN_INT_DRX) != 0)) + { + int i; + + /* Clear the pending DRX interrupt */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_DRX); + + /* Process each dedicated RX buffer */ + + for (i = 0; i < config->nrxdedicated; i++) + { + uint32_t *rxdedicated = &config->rxdedicated[i]; + + /* Check if datat is available in this dedicated RX buffer */ + + if (mcan_dedicated_rxbuffer_available(priv, i)) + { + /* Yes.. Invalidate the D-Cache to that data will be re- + * fetched from RAM. + * + * REVISIT: This will require 32-byte alignment. + */ + + arch_invalidata_dcache(); + mcan_receive(priv, rxdedicated, config->rxbufferesize); + + /* Clear the new data flag for the buffer */ + + if (i < 32) + { + sam_putreg(priv, SAM_MCAN_NDAT1_OFFSET, (1 << i); + } + else + { + sam_putreg(priv, SAM_MCAN_NDAT1_OFFSET, (1 << (i - 32)); + } + } + } + + handled = true; + } +#endif + + /* Check for reception errors */ + + if ((pending & MCAN_RXERR_INTS) != 0) + { + canlldbg("ERROR: RX %08x\n", pending & MCAN_RXERR_INTS); + + /* Clear the error indications */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_RXERR_INTS); + + /* Report errors */ + + mcan_error(dev, pending & MCAN_TXERR_INTS); + handled = true; + } + + /* Clear the RX FIFO1 new message interrupt */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_RF1N); + pending &= ~MCAN_INT_RF1N; + + /* We treat RX FIFO1 as the "high priority" queue: We will process + * all messages in RX FIFO1 before processing any message from RX + * FIFO0. + */ + + for (;;) + { + /* Check if there is anything in RX FIFO1 */ + + regval = mcan_getreg(priv, SAM_MCAN_RXF1S_OFFSET); + nelem = (regval & MCAN_RXF0S_F0FL_MASK) >> MCAN_RXF0S_F0FL_SHIFT; + if (nelem == 0) + { + /* Break out of the loop if RX FIFO1 is empty */ + + break; + } + + /* Clear the RX FIFO1 interrupt (and all other FIFO1-related + * interrupts) + */ + + /* Handle the newly received message in FIFO1 */ + + ndx = (regval & MCAN_RXF1S_F1GI_MASK) >> MCAN_RXF1S_F1GI_SHIFT; + + if ((regval & MCAN_RXF0S_RF0L) != 0) + { + canlldbg("ERROR: Message lost: %08x\n", regval); + } + else + { + mcan_receive(dev, + config->msgram.rxfifo1 + + (ndx * priv->config->rxfifo1esize), + priv->config->rxfifo1esize); + } + + /* Acknowledge reading the FIFO entry */ + + mcan_putreg(priv, SAM_MCAN_RXF1A_OFFSET, ndx); + handled = true; + } + + /* Check for successful reception of a new message in RX FIFO0 */ + /* Clear the RX FIFO0 new message interrupt */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_RF0N); + pending &= ~MCAN_INT_RF0N; + + /* Check if there is anything in RX FIFO0 */ + + regval = mcan_getreg(priv, SAM_MCAN_RXF0S_OFFSET); + nelem = (regval & MCAN_RXF0S_F0FL_MASK) >> MCAN_RXF0S_F0FL_SHIFT; + if (nelem > 0) + { + /* Handle the newly received message in FIFO0 */ + + ndx = (regval & MCAN_RXF0S_F0GI_MASK) >> MCAN_RXF0S_F0GI_SHIFT; + + if ((regval & MCAN_RXF0S_RF0L) != 0) + { + canlldbg("ERROR: Message lost: %08x\n", regval); + } + else + { + mcan_receive(dev, + config->msgram.rxfifo0 + + (ndx * priv->config->rxfifo0esize), + priv->config->rxfifo0esize); + } + + /* Acknowledge reading the FIFO entry */ + + mcan_putreg(priv, SAM_MCAN_RXF0A_OFFSET, ndx); + handled = true; + } + + /* Clear unhandled RX interrupts */ + + if ((pending & priv->rxints) != 0) + { + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, priv->rxints); + } + } + while (handled); +} + +/**************************************************************************** + * Name: mcan0_interrupt + * + * Description: + * MCAN0 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_MCAN0 +static int mcan0_interrupt(int irq, void *context) +{ + mcan_interrupt(&g_mcan0dev); + return OK; +} +#endif + +/**************************************************************************** + * Name: mcan1_interrupt + * + * Description: + * MCAN1 interrupt handler + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_MCAN1 +static int mcan1_interrupt(int irq, void *context) +{ + mcan_interrupt(&g_mcan1dev); + return OK; +} +#endif + +/**************************************************************************** + * Name: mcan_hw_initialize + * + * Description: + * MCAN hardware initialization + * + * Input Parameter: + * priv - A pointer to the private data structure for this MCAN peripheral + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int mcan_hw_initialize(struct sam_mcan_s *priv) +{ + FAR const struct sam_config_s *config = priv->config; + FAR uint32_t *msgram; + uint32_t regval; + uint32_t cntr; + uint32_t cmr; + + canllvdbg("MCAN%d\n", config->port); + + /* Configure MCAN pins */ + + sam_configgpio(config->rxpinset); + sam_configgpio(config->txpinset); + + /* Enable peripheral clocking */ + + sam_enableperiph1(config->pid); + + /* Enable the Initialization state */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Wait for initialization mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & MCAN_CCCR_INIT) == 0); + + /* Enable writing to configuration registers */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_INIT | MCAN_CCCR_CCE); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Global Filter Configuration: + * + * ANFS=0: Store all rejected extended frame in RX FIFO0 + * ANFE=0: Store all rejected extended frame in RX FIFO0 + * FFSE=1: Reject all remote frames with 11-bit standard IDs. + * RRFE=1: Reject all remote frames with 29-bit extended IDs. + */ + + regval = MCAN_GFC_RRFE | MCAN_GFC_RRFS | MCAN_GFC_ANFE_RX_FIFO0 | + MCAN_GFC_ANFS_RX_FIFO0; + mcan_putreg(priv, SAM_MCAN_GFC_OFFSET, regval); + + /* Extended ID Filter AND mask */ + + mcan_putreg(priv, SAM_MCAN_XIDAM_OFFSET, 0x1fffffff); + + /* Disable all interrupts */ + + mcan_putreg(priv, SAM_MCAN_IE_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_TXBTIE_OFFSET, 0); + + /* All interrupts directed to Line 0. But disable both interrupt lines 0 + * and 1 for now. + * + * REVISIT: Only interrupt line 0 is used by this driver. + */ + + mcan_putreg(priv, SAM_MCAN_ILS_OFFSET, 0); + mcan_putreg(priv, SAM_MCAN_ILE_OFFSET, 0); + + /* Clear all pending interrupts. */ + + mcan_putreg(priv, SAM_MCAN_IR_OFFSET, MCAN_INT_ALL); + + /* Configure MCAN bit timing */ + + mcan_putreg(priv, SAM_MCAN_BTP_OFFSET, priv->btp); + mcan_putreg(priv, SAM_MCAN_FBTP_OFFSET, priv->fbtp); + + /* Configure message RAM starting addresses and sizes. */ + + regval = MAILBOX_ADDRESS(config->msgram.stdfilters) | + MCAN_SIDFC_LSS(config->nstdfilters); + mcan_putreg(priv, SAM_MCAN_SIDFC_OFFSET, regval); + + regval = MAILBOX_ADDRESS(config->msgram.extfilters) | + MCAN_XIDFC_LSE(config->nextfilters); + mcan_putreg(priv, SAM_MCAN_XIDFC_OFFSET, regval); + + /* Configure RX FIFOs */ + + regval = MAILBOX_ADDRESS(config->msgram.rxfifo0) | + MCAN_RXF0C_F0S(config->nrxfifo0); + mcan_putreg(priv, SAM_MCAN_RXF0C_OFFSET, regval); + + regval = MAILBOX_ADDRESS(config->msgram.rxfifo1) | + MCAN_RXF1C_F1S(config->nrxfifo1); + mcan_putreg(priv, SAM_MCAN_RXF1C_OFFSET, regval); + + /* Watermark interrupt off, blocking mode */ + + regval = MAILBOX_ADDRESS(config->msgram.rxdedicated); + mcan_putreg(priv, SAM_MCAN_RXBC_OFFSET, regval); + + regval = MAILBOX_ADDRESS(config->msgram.txeventfifo) | + MCAN_TXEFC_EFS(config->ntxeventfifo); + mcan_putreg(priv, SAM_MCAN_TXEFC_OFFSET, regval); + + /* Watermark interrupt off */ + + regval = MAILBOX_ADDRESS(config->msgram.txdedicated) | + MCAN_TXBC_NDTB(config->ntxdedicated) | + MCAN_TXBC_TFQS(config->ntxfifoq); + mcan_putreg(priv, SAM_MCAN_TXBC_OFFSET, regval); + + regval = MCAN_RXESC_RBDS(config->rxbufferecode) | + MCAN_RXESC_F1DS(config->rxfifo1ecode) | + MCAN_RXESC_F0DS(config->rxfifo0ecode); + mcan_putreg(priv, SAM_MCAN_RXESC_OFFSET, regval); + + regval = MCAN_TXESC_TBDS(config->txbufferecode); + mcan_putreg(priv, SAM_MCAN_TXESC_OFFSET, regval); + + /* Configure Message Filters */ + /* Disable all standard filters */ + + msgram = config->msgram.stdfilters; + cntr = config->nstdfilters; + while (cntr > 0) + { + *msgram++ = STDFILTER_S0_SFEC_DISABLE; + cntr--; + } + + /* Disable all extended filters */ + + msgram = config->msgram.extfilters; + cntr = config->nextfilters; + while (cntr > 0) + { + *msgram = EXTFILTER_F0_EFEC_DISABLE; + msgram = msgram + 2; + cntr--; + } + + /* Clear new RX data flags */ + + mcan_putreg(priv, SAM_MCAN_NDAT1_OFFSET, 0xffffffff); + mcan_putreg(priv, SAM_MCAN_NDAT2_OFFSET, 0xffffffff); + + /* Select ISO11898-1 mode or FD mode with or without fast bit rate + * switching + */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~(MCAN_CCCR_CME_MASK | MCAN_CCCR_CMR_MASK); + + switch (config->mode) + { + default: + case MCAN_ISO11898_1_MODE: + regval |= MCAN_CCCR_CME_ISO11898_1; + cmr = MCAN_CCCR_CMR_ISO11898_1; + break; + +#ifdef CONFIG_CAN_FD + case MCAN_FD_MODE: + regval |= MCAN_CCCR_CME_FD; + cmr = MCAN_CCCR_CMR_FD; + break; + + case MCAN_FD_BSW_MODE: + regval |= MCAN_CCCR_CME_FD_BSW; + cmr = MCAN_CCCR_CMR_FD_BSW; + break; +#endif + } + + /* Set the initial CAN mode */ + + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + /* Request the mode change */ + + regval |= cmr; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + +#if 0 /* Not necessary in initialization mode */ + /* Wait for the mode to take effect */ + + while ((mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET) & (MCAN_CCCR_FDBS | MCAN_CCCR_FDO)) != 0); +#endif + + /* Enable FIFO/Queue mode + * + * REVISIT: Dedicated TX buffers are not used. + */ + + regval = mcan_getreg(priv, SAM_MCAN_TXBC_OFFSET); + regval |= MCAN_TXBC_TFQM; + mcan_putreg(priv, SAM_MCAN_TXBC_OFFSET, regval); + +#ifdef SAMV7_MCAN_LOOPBACK + /* Is loopback mode selected for this peripheral? */ + + if (config->loopback) + { + /* MCAN_CCCR_TEST - Test mode enable + * MCAN_CCCR_MON - Bus monitoring mode (for internal loopback) + * MCAN_TEST_LBCK - Loopback mode + */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval |= (MCAN_CCCR_TEST | MCAN_CCCR_MON); + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + regval = mcan_getreg(priv, SAM_MCAN_TEST_OFFSET); + regval |= MCAN_TEST_LBCK; + mcan_putreg(priv, SAM_MCAN_TEST_OFFSET, regval); + } +#endif + + /* Configure interrupt lines */ + /* Select RX-related interrupts */ + +#if 0 /* Dedicated RX buffers are not used by this driver */ + priv->rxints = MCAN_RXDEDBUF_INTS; +#else + priv->rxints = MCAN_RXFIFO_INTS; +#endif + + /* Select TX-related interrupts */ + +#if 0 /* Dedicated TX buffers are not used by this driver */ + priv->txints = MCAN_TXDEDBUF_INTS; +#else + priv->txints = MCAN_TXFIFOQ_INTS; +#endif + + /* Direct all interrupts to Line 0. + * + * Bits in the ILS register correspond to each MCAN interrupt; A bit + * set to '1' is directed to interrupt line 1; a bit cleared to '0' + * is directed interrupt line 0. + * + * REVISIT: Nothing is done here. Only interrupt line 0 is used by + * this driver and ILS was already cleared above. + */ + + /* Enable only interrupt line 0. */ + + mcan_putreg(priv, SAM_MCAN_ILE_OFFSET, MCAN_ILE_EINT0); + + /* Disable initialization mode to enable normal operation */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_mcan_initialize + * + * Description: + * Initialize the selected MCAN port + * + * Input Parameter: + * port - Port number (for hardware that has multiple MCAN interfaces), + * 0=MCAN0, 1=MCAN1 + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct can_dev_s *sam_mcan_initialize(int port) +{ + FAR struct can_dev_s *dev; + FAR struct sam_mcan_s *priv; + FAR const struct sam_config_s *config; + uint32_t regval; + + canvdbg("MCAN%d\n", port); + + /* Select PCK5 clock source and pre-scaler value. Both MCAN controllers + * use PCK5 to derive bit rate. + */ + + regval = PMC_PCK_PRES(CONFIG_SAMV7_MCAN_CLKSRC_PRESCALER) | SAMV7_MCAN_CLKSRC; + putreg32(regval, SAM_PMC_PCK5); + + /* Enable PCK5 */ + + putreg32(PMC_PCK5, SAM_PMC_SCER); + + /* Select MCAN peripheral to be initialized */ + +#ifdef CONFIG_SAMV7_MCAN0 + if (port == MCAN0) + { + /* Select the MCAN0 device structure */ + + dev = &g_mcan0dev; + priv = &g_mcan0priv; + config = &g_mcan0const; + + /* Configure MCAN0 Message RAM Base Address */ + + regval = getreg32(SAM_MATRIX_CAN0); + regval &= MATRIX_CAN0_RESERVED; + regval |= (uint32_t)config->msgram.stdfilters & MATRIX_CAN0_CAN0DMABA_MASK; + putreg32(regval, SAM_MATRIX_CAN0); + } + else +#endif +#ifdef CONFIG_SAMV7_MCAN1 + if (port == MCAN1) + { + /* Select the MCAN1 device structure */ + + dev = &g_mcan1dev; + priv = &g_mcan1priv; + config = &g_mcan1const; + + /* Configure MCAN1 Message RAM Base Address */ + + regval = getreg32(SAM_MATRIX_CCFG_SYSIO); + regval &= ~MATRIX_CCFG_CAN1DMABA_MASK; + regval |= (uint32_t)config->msgram.stdfilters & MATRIX_CCFG_CAN1DMABA_MASK; + putreg32(regval, SAM_MATRIX_CCFG_SYSIO); + } + else +#endif + { + candbg("ERROR: Unsupported port %d\n", port); + return NULL; + } + + /* Is this the first time that we have handed out this device? */ + + if (priv->state == MCAN_STATE_UNINIT) + { + /* Yes, then perform one time data initialization */ + + memset(priv, 0, sizeof(struct sam_mcan_s)); + priv->config = config; + + /* Set the initial bit timing. This might change subsequently + * due to IOCTL command processing. + */ + + priv->btp = config->btp; + priv->fbtp = config->fbtp; + + /* Initialize semaphores */ + + sem_init(&priv->locksem, 0, 1); + sem_init(&priv->txfsem, 0, config->ntxfifoq); + + dev->cd_ops = &g_mcanops; + dev->cd_priv = (FAR void *)priv; + + /* And put the hardware in the initial state */ + + mcan_reset(dev); + } + + return dev; +} + +#endif /* CONFIG_CAN && CONFIG_SAMV7_MCAN */ diff --git a/arch/arm/src/samv7/sam_mcan.h b/arch/arm/src/samv7/sam_mcan.h new file mode 100644 index 00000000000..741c458a784 --- /dev/null +++ b/arch/arm/src/samv7/sam_mcan.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_mcan.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_SAM_MCAN_H +#define __ARCH_ARM_SRC_SAMV7_SAM_MCAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "chip/sam_mcan.h" + +#include + +#if defined(CONFIG_CAN) && (defined(CONFIG_SAMV7_MCAN0) || \ + defined(CONFIG_SAMV7_MCAN1)) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Port numbers for use with sam_mcan_initialize() */ + +#define MCAN0 0 +#define MCAN1 1 + +/*************************************************************************** + * Public Types + ***************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/*************************************************************************** + * Public Functions + ***************************************************************************/ + +/**************************************************************************** + * Name: sam_mcan_initialize + * + * Description: + * Initialize the selected MCAN port + * + * Input Parameter: + * port - Port number (for hardware that has multiple CAN interfaces), + * 0=MCAN0, 1=NCAN1 + * + * Returned Value: + * Valid CAN device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct can_dev_s; +FAR struct can_dev_s *sam_mcan_initialize(int port); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_CAN && (CONFIG_SAMV7_MCAN0 || CONFIG_SAMV7_MCAN1) */ +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_MCAN_H */ diff --git a/arch/arm/src/samv7/sam_qspi.c b/arch/arm/src/samv7/sam_qspi.c new file mode 100644 index 00000000000..01fb96935e8 --- /dev/null +++ b/arch/arm/src/samv7/sam_qspi.c @@ -0,0 +1,1750 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_qspi.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "sam_gpio.h" +#include "sam_xdmac.h" +#include "sam_periphclks.h" +#include "sam_qspi.h" +#include "chip/sam_pmc.h" +#include "chip/sam_xdmac.h" +#include "chip/sam_qspi.h" +#include "chip/sam_pinmap.h" + +#ifdef CONFIG_SAMV7_QSPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* When QSPI DMA is enabled, small DMA transfers will still be performed by + * polling logic. But we need a threshold value to determine what is small. + * That value is provided by CONFIG_SAMV7_QSPI_DMATHRESHOLD. + */ + +#ifndef CONFIG_SAMV7_QSPI_DMATHRESHOLD +# define CONFIG_SAMV7_QSPI_DMATHRESHOLD 4 +#endif + +#ifdef CONFIG_SAMV7_QSPI_DMA +# if defined(CONFIG_SAMV7_QSPI) && defined(CONFIG_SAMV7_DMAC0) +# define SAMV7_QSPI0_DMA true +# else +# define SAMV7_QSPI0_DMA false +# endif +#endif + +#ifndef CONFIG_SAMV7_QSPI_DMA +# undef CONFIG_SAMV7_QSPI_DMADEBUG +#endif + +/* Clocking *****************************************************************/ +/* The QSPI Baud rate clock is generated by dividing the peripheral clock by + * a value between 1 and 255 + */ + +#define SAM_QSPI_CLOCK BOARD_MCK_FREQUENCY /* Frequency of the main clock */ + +/* DMA timeout. The value is not critical; we just don't want the system to + * hang in the event that a DMA does not finish. This is set to + */ + +#define DMA_TIMEOUT_MS (800) +#define DMA_TIMEOUT_TICKS MSEC2TICK(DMA_TIMEOUT_MS) + +/* Debug *******************************************************************/ +/* Check if QSPI debug is enabled (non-standard.. no support in + * include/debug.h + */ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_VERBOSE +# undef CONFIG_DEBUG_SPI +# undef CONFIG_SAMV7_QSPI_DMADEBUG +# undef CONFIG_SAMV7_QSPI_REGDEBUG +#endif + +#ifndef CONFIG_DEBUG_DMA +# undef CONFIG_SAMV7_QSPI_DMADEBUG +#endif + +#ifdef CONFIG_DEBUG_SPI +# define spidbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define spivdbg lldbg +# else +# define spivdbg(x...) +# endif +#else +# define spidbg(x...) +# define spivdbg(x...) +#endif + +#define DMA_INITIAL 0 +#define DMA_AFTER_SETUP 1 +#define DMA_AFTER_START 2 +#define DMA_CALLBACK 3 +#define DMA_TIMEOUT 3 +#define DMA_END_TRANSFER 4 +#define DMA_NSAMPLES 5 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The state of the QSPI controller */ + +struct sam_qspidev_s +{ + struct spi_dev_s spidev; /* Externally visible part of the QSPI interface */ + + uint32_t base; /* QSPI controller register base address */ +#ifndef CONFIG_SPI_OWNBUS + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + uint8_t mode; /* Mode 0,1,2,3 */ +#endif + uint8_t nbits; /* Width of word in bits (8 to 16) */ + uint8_t intf; /* QSPI controller number (0) */ + bool initialized; /* TRUE: Controller has been initialized */ + sem_t spisem; /* Assures mutually exclusive access to QSPI */ + +#ifdef CONFIG_SAMV7_QSPI_DMA + bool candma; /* DMA is supported */ + sem_t dmawait; /* Used to wait for DMA completion */ + WDOG_ID dmadog; /* Watchdog that handles DMA timeouts */ + int result; /* DMA result */ + DMA_HANDLE rxdma; /* QSPI RX DMA handle */ + DMA_HANDLE txdma; /* QSPI TX DMA handle */ +#endif + +#ifdef CONFIG_SAMV7_QSPI_DMA + uint8_t rxintf; /* RX hardware interface number */ + uint8_t txintf; /* TX hardware interface number */ +#endif + + /* Debug stuff */ + +#ifdef CONFIG_SAMV7_QSPI_DMADEBUG + struct sam_dmaregs_s rxdmaregs[DMA_NSAMPLES]; + struct sam_dmaregs_s txdmaregs[DMA_NSAMPLES]; +#endif + +#ifdef CONFIG_SAMV7_QSPI_REGDEBUG + bool wrlast; /* Last was a write */ + uint32_t addresslast; /* Last address */ + uint32_t valuelast; /* Last value */ + int ntimes; /* Number of times */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +#ifdef CONFIG_SAMV7_QSPI_REGDEBUG +static bool qspi_checkreg(struct sam_qspidev_s *priv, bool wr, + uint32_t value, uint32_t address); +#else +# define qspi_checkreg(priv,wr,value,address) (false) +#endif + +static inline uint32_t qspi_getreg(struct sam_qspidev_s *priv, + unsigned int offset); +static inline void qspi_putreg(struct sam_qspidev_s *priv, uint32_t value, + unsigned int offset); + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE) +static void qspi_dumpregs(struct sam_qspidev_s *priv, const char *msg); +#else +# define qspi_dumpregs(priv,msg) +#endif + +static inline void qspi_flush(struct sam_qspidev_s *priv); + +/* DMA support */ + +#ifdef CONFIG_SAMV7_QSPI_DMA + +#ifdef CONFIG_SAMV7_QSPI_DMADEBUG +# define qspi_rxdma_sample(s,i) sam_dmasample((s)->rxdma, &(s)->rxdmaregs[i]) +# define qspi_txdma_sample(s,i) sam_dmasample((s)->txdma, &(s)->txdmaregs[i]) +static void qspi_dma_sampleinit(struct sam_qspidev_s *priv); +static void qspi_dma_sampledone(struct sam_qspidev_s *priv); + +#else +# define qspi_rxdma_sample(s,i) +# define qspi_txdma_sample(s,i) +# define qspi_dma_sampleinit(s) +# define qspi_dma_sampledone(s) + +#endif + +static void qspi_rxcallback(DMA_HANDLE handle, void *arg, int result); +static void qspi_txcallback(DMA_HANDLE handle, void *arg, int result); +static inline uintptr_t qspi_regaddr(struct sam_qspidev_s *priv, + unsigned int offset); +#endif + +/* QSPI master methods */ + +#ifndef CONFIG_SPI_OWNBUS +static int qspi_lock(struct spi_dev_s *dev, bool lock); +#endif +static void qspi_select(struct spi_dev_s *dev, enum spi_dev_e devid, + bool selected); +static uint32_t qspi_setfrequency(struct spi_dev_s *dev, uint32_t frequency); +static void qspi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode); +static void qspi_setbits(struct spi_dev_s *dev, int nbits); +static uint8_t qspi_status(struct spi_dev_s *dev, enum spi_dev_e devid); +static uint16_t qspi_send(struct spi_dev_s *dev, uint16_t ch); +#ifdef CONFIG_SAMV7_QSPI_DMA +static void qspi_exchange_nodma(struct spi_dev_s *dev, + const void *txbuffer, void *rxbuffer, size_t nwords); +#endif +static void qspi_exchange(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords); +#ifndef CONFIG_SPI_EXCHANGE +static void qspi_sndblock(struct spi_dev_s *dev, + const void *buffer, size_t nwords); +static void qspi_recvblock(struct spi_dev_s *dev, void *buffer, + size_t nwords); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI +/* QSPI0 driver operations */ + +static const struct spi_ops_s g_qspi0ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = qspi_lock, +#endif + .select = qspi_select, + .setfrequency = qspi_setfrequency, + .setmode = qspi_setmode, + .setbits = qspi_setbits, + .status = qspi_status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = qspi_cmddata, +#endif + .send = qspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = qspi_exchange, +#else + .sndblock = qspi_sndblock, + .recvblock = qspi_recvblock, +#endif + .registercallback = 0, /* Not implemented */ +}; + +/* This is the overall state of the QSPI0 controller */ + +static struct sam_qspidev_s g_qspi0dev = +{ + .spidev = + { + .ops = &g_qspi0ops, + }, + .base = SAM_QSPI_BASE, + .intf = 0, +#ifdef CONFIG_SAMV7_QSPI_DMA + .candma = SAMV7_QSPI_DMA, + .rxintf = XDMACH_QSPI_RX, + .txintf = XDMACH_QSPI_TX, +#endif +}; +#endif /* CONFIG_SAMV7_QSPI */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: qspi_checkreg + * + * Description: + * Check if the current register access is a duplicate of the preceding. + * + * Input Parameters: + * value - The value to be written + * address - The address of the register to write to + * + * Returned Value: + * true: This is the first register access of this type. + * flase: This is the same as the preceding register access. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_REGDEBUG +static bool qspi_checkreg(struct sam_qspidev_s *priv, bool wr, uint32_t value, + uint32_t address) +{ + if (wr == priv->wrlast && /* Same kind of access? */ + value == priv->valuelast && /* Same value? */ + address == priv->addresslast) /* Same address? */ + { + /* Yes, then just keep a count of the number of times we did this. */ + + priv->ntimes++; + return false; + } + else + { + /* Did we do the previous operation more than once? */ + + if (priv->ntimes > 0) + { + /* Yes... show how many times we did it */ + + lldbg("...[Repeats %d times]...\n", priv->ntimes); + } + + /* Save information about the new access */ + + priv->wrlast = wr; + priv->valuelast = value; + priv->addresslast = address; + priv->ntimes = 0; + } + + /* Return true if this is the first time that we have done this operation */ + + return true; +} +#endif + +/**************************************************************************** + * Name: qspi_getreg + * + * Description: + * Read an QSPI register + * + ****************************************************************************/ + +static inline uint32_t qspi_getreg(struct sam_qspidev_s *priv, + unsigned int offset) +{ + uint32_t address = priv->base + offset; + uint32_t value = getreg32(address); + +#ifdef CONFIG_SAMV7_QSPI_REGDEBUG + if (qspi_checkreg(priv, false, value, address)) + { + lldbg("%08x->%08x\n", address, value); + } +#endif + + return value; +} + +/**************************************************************************** + * Name: qspi_putreg + * + * Description: + * Write a value to an QSPI register + * + ****************************************************************************/ + +static inline void qspi_putreg(struct sam_qspidev_s *priv, uint32_t value, + unsigned int offset) +{ + uint32_t address = priv->base + offset; + +#ifdef CONFIG_SAMV7_QSPI_REGDEBUG + if (qspi_checkreg(priv, true, value, address)) + { + lldbg("%08x<-%08x\n", address, value); + } +#endif + + putreg32(value, address); +} + +/**************************************************************************** + * Name: qspi_dumpregs + * + * Description: + * Dump the contents of all QSPI registers + * + * Input Parameters: + * priv - The QSPI controller to dump + * msg - Message to print before the register data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE) +static void qspi_dumpregs(struct sam_qspidev_s *priv, const char *msg) +{ + spivdbg("%s:\n", msg); + spivdbg(" MR:%08x SR:%08x IMR:%08x\n", + getreg32(priv->base + SAM_QSPI_MR_OFFSET), + getreg32(priv->base + SAM_QSPI_SR_OFFSET), + getreg32(priv->base + SAM_QSPI_IMR_OFFSET)); + spivdbg(" SCR0:%08x SCR1:%08x SCR2:%08x SCR3:%08x\n", + getreg32(priv->base + SAM_QSPI_SCR0_OFFSET), + getreg32(priv->base + SAM_QSPI_SCR1_OFFSET), + getreg32(priv->base + SAM_QSPI_SCR2_OFFSET), + getreg32(priv->base + SAM_QSPI_SCR3_OFFSET)); + spivdbg(" WPCR:%08x WPSR:%08x\n", + getreg32(priv->base + SAM_QSPI_WPCR_OFFSET), + getreg32(priv->base + SAM_QSPI_WPSR_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: qspi_flush + * + * Description: + * Make sure that there are now dangling QSPI transfer in progress + * + * Input Parameters: + * priv - QSPI controller state + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void qspi_flush(struct sam_qspidev_s *priv) +{ + /* Make sure the no TX activity is in progress... waiting if necessary */ + + while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TXEMPTY) == 0); + + /* Then make sure that there is no pending RX data .. reading as + * discarding as necessary. + */ + + while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_RDRF) != 0) + { + (void)qspi_getreg(priv, SAM_QSPI_RDR_OFFSET); + } +} + +/**************************************************************************** + * Name: qspi_dma_sampleinit + * + * Description: + * Initialize sampling of DMA registers (if CONFIG_SAMV7_QSPI_DMADEBUG) + * + * Input Parameters: + * priv - QSPI driver instance + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMADEBUG +static void qspi_dma_sampleinit(struct sam_qspidev_s *priv) +{ + /* Put contents of register samples into a known state */ + + memset(priv->rxdmaregs, 0xff, DMA_NSAMPLES * sizeof(struct sam_dmaregs_s)); + memset(priv->txdmaregs, 0xff, DMA_NSAMPLES * sizeof(struct sam_dmaregs_s)); + + /* Then get the initial samples */ + + sam_dmasample(priv->rxdma, &priv->rxdmaregs[DMA_INITIAL]); + sam_dmasample(priv->txdma, &priv->txdmaregs[DMA_INITIAL]); +} +#endif + +/**************************************************************************** + * Name: qspi_dma_sampledone + * + * Description: + * Dump sampled DMA registers + * + * Input Parameters: + * priv - QSPI driver instance + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMADEBUG +static void qspi_dma_sampledone(struct sam_qspidev_s *priv) +{ + /* Sample the final registers */ + + sam_dmasample(priv->rxdma, &priv->rxdmaregs[DMA_END_TRANSFER]); + sam_dmasample(priv->txdma, &priv->txdmaregs[DMA_END_TRANSFER]); + + /* Then dump the sampled DMA registers */ + /* Initial register values */ + + sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_INITIAL], + "TX: Initial Registers"); + sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_INITIAL], + "RX: Initial Registers"); + + /* Register values after DMA setup */ + + sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_AFTER_SETUP], + "TX: After DMA Setup"); + sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_AFTER_SETUP], + "RX: After DMA Setup"); + + /* Register values after DMA start */ + + sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_AFTER_START], + "TX: After DMA Start"); + sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_AFTER_START], + "RX: After DMA Start"); + + /* Register values at the time of the TX and RX DMA callbacks + * -OR- DMA timeout. + * + * If the DMA timed out, then there will not be any RX DMA + * callback samples. There is probably no TX DMA callback + * samples either, but we don't know for sure. + */ + + sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_CALLBACK], + "TX: At DMA callback"); + + /* Register values at the end of the DMA */ + + if (priv->result == -ETIMEDOUT) + { + sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_TIMEOUT], + "RX: At DMA timeout"); + } + else + { + sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_CALLBACK], + "RX: At DMA callback"); + } + + sam_dmadump(priv->txdma, &priv->txdmaregs[DMA_END_TRANSFER], + "TX: At End-of-Transfer"); + sam_dmadump(priv->rxdma, &priv->rxdmaregs[DMA_END_TRANSFER], + "RX: At End-of-Transfer"); +} +#endif + +/**************************************************************************** + * Name: qspi_dmatimeout + * + * Description: + * The watchdog timeout setup when a has expired without completion of a + * DMA. + * + * Input Parameters: + * argc - The number of arguments (should be 1) + * arg - The argument (state structure reference cast to uint32_t) + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMA +static void qspi_dmatimeout(int argc, uint32_t arg) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)arg; + DEBUGASSERT(priv != NULL); + + /* Sample DMA registers at the time of the timeout */ + + qspi_rxdma_sample(priv, DMA_CALLBACK); + + /* Report timeout result, perhaps overwriting any failure reports from + * the TX callback. + */ + + priv->result = -ETIMEDOUT; + + /* Then wake up the waiting thread */ + + sem_post(&priv->dmawait); +} +#endif + +/**************************************************************************** + * Name: qspi_rxcallback + * + * Description: + * This callback function is invoked at the completion of the QSPI RX DMA. + * + * Input Parameters: + * handle - The DMA handler + * arg - A pointer to the chip select structure + * result - The result of the DMA transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMA +static void qspi_rxcallback(DMA_HANDLE handle, void *arg, int result) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)arg; + DEBUGASSERT(priv != NULL); + + /* Cancel the watchdog timeout */ + + (void)wd_cancel(priv->dmadog); + + /* Sample DMA registers at the time of the callback */ + + qspi_rxdma_sample(priv, DMA_CALLBACK); + + /* Report the result of the transfer only if the TX callback has not already + * reported an error. + */ + + if (priv->result == -EBUSY) + { + /* Save the result of the transfer if no error was previously reported */ + + priv->result = result; + } + + /* Then wake up the waiting thread */ + + sem_post(&priv->dmawait); +} +#endif + +/**************************************************************************** + * Name: qspi_txcallback + * + * Description: + * This callback function is invoked at the completion of the QSPI TX DMA. + * + * Input Parameters: + * handle - The DMA handler + * arg - A pointer to the chip select structure + * result - The result of the DMA transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMA +static void qspi_txcallback(DMA_HANDLE handle, void *arg, int result) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)arg; + DEBUGASSERT(priv != NULL); + + qspi_txdma_sample(priv, DMA_CALLBACK); + + /* Do nothing on the TX callback unless an error is reported. This + * callback is not really important because the QSPI exchange is not + * complete until the RX callback is received. + */ + + if (result != OK && priv->result == -EBUSY) + { + /* Save the result of the transfer if an error is reported */ + + priv->result = result; + } +} +#endif + +/**************************************************************************** + * Name: qspi_regaddr + * + * Description: + * Return the address of an QSPI register + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMA +static inline uintptr_t qspi_regaddr(struct sam_qspidev_s *priv, + unsigned int offset) +{ + return priv->base + offset; +} +#endif + +/**************************************************************************** + * Name: qspi_lock + * + * Description: + * On QSPI buses where there are multiple devices, it will be necessary to + * lock QSPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the QSPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the QSPI is properly + * configured for the device. If the QSPI bus is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock QSPI bus, false: unlock QSPI bus + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_OWNBUS +static int qspi_lock(struct spi_dev_s *dev, bool lock) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + + spivdbg("lock=%d\n", lock); + if (lock) + { + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&priv->spisem) != 0) + { + /* The only case that an error should occur here is if the wait was awakened + * by a signal. + */ + + ASSERT(errno == EINTR); + } + } + else + { + (void)sem_post(&priv->spisem); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: qspi_select + * + * Description: + * This function does not actually set the chip select line. Rather, it + * simply maps the device ID into a chip select number and retains that + * chip select number for later use. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The QSPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + + static void qspi_select(struct spi_dev_s *dev, enum spi_dev_e devid, + bool selected) + { + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + + /* Are we selecting or de-selecting the device? */ + + spivdbg("selected=%d\n", selected); + if (selected) + { +#warning Missing logic + } + else + { +#warning Missing logic + } +} + +/**************************************************************************** + * Name: qspi_setfrequency + * + * Description: + * Set the QSPI frequency. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The QSPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32_t qspi_setfrequency(struct spi_dev_s *dev, uint32_t frequency) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + uint32_t actual; + uint32_t scbr; + uint32_t dlybs; + uint32_t dlybct; + uint32_t regval; + + spivdbg("frequency=%d\n", frequency); + + /* Check if the requested frequency is the same as the frequency selection */ + +#ifndef CONFIG_SPI_OWNBUS + if (priv->frequency == frequency) + { + /* We are already at this frequency. Return the actual. */ + + return priv->actual; + } +#endif + + /* Configure QSPI to a frequency as close as possible to the requested frequency. + * + * SPCK frequency = QSPI_CLK / SCBR, or SCBR = QSPI_CLK / frequency + */ + + scbr = SAM_QSPI_CLOCK / frequency; + + if (scbr < 8) + { + scbr = 8; + } + else if (scbr > 254) + { + scbr = 254; + } + + scbr = (scbr + 1) & ~1; + + /* Save the new scbr value */ + + regval = qspi_getreg(priv, SAM_QSPI_SCR_OFFSET); + regval &= ~(QSPI_SCR_SCBR_MASK | QSPI_SCR_DLYBS_MASK); + regval |= scbr << QSPI_SCR_SCBR_SHIFT; + + /* DLYBS: Delay Before SPCK. This field defines the delay from NPCS valid to the + * first valid SPCK transition. When DLYBS equals zero, the NPCS valid to SPCK + * transition is 1/2 the SPCK clock period. Otherwise, the following equations + * determine the delay: + * + * Delay Before SPCK = DLYBS / QSPI_CLK + * + * For a 2uS delay + * + * DLYBS = QSPI_CLK * 0.000002 = QSPI_CLK / 500000 + */ + + dlybs = SAM_QSPI_CLOCK / 500000; + regval |= dlybs << QSPI_SCR_DLYBS_SHIFT; + qspi_putreg(priv, regval, SAM_QSPI_SCR_OFFSET); + + /* DLYBCT: Delay Between Consecutive Transfers. This field defines the delay + * between two consecutive transfers with the same peripheral without removing + * the chip select. The delay is always inserted after each transfer and + * before removing the chip select if needed. + * + * Delay Between Consecutive Transfers = (32 x DLYBCT) / QSPI_CLK + * + * For a 5uS delay: + * + * DLYBCT = QSPI_CLK * 0.000005 / 32 = QSPI_CLK / 200000 / 32 + */ + + dlybct = SAM_QSPI_CLOCK / 200000 / 32; + + regval = qspi_getreg(priv, SAM_QSPI_MR_OFFSET); + regval &= ~QSPI_MR_DLYBCT_MASK; + regval |= dlybct << QSPI_MR_DLYBCT_SHIFT; + qspi_putreg(priv, regval, SAM_QSPI_MR_OFFSET); + + /* Calculate the new actual frequency */ + + actual = SAM_QSPI_CLOCK / scbr; + spivdbg("SCR=%08x actual=%d\n", regval, actual); + + /* Save the frequency setting */ + +#ifndef CONFIG_SPI_OWNBUS + priv->frequency = frequency; + priv->actual = actual; +#endif + + spidbg("Frequency %d->%d\n", frequency, actual); + return actual; +} + +/**************************************************************************** + * Name: qspi_setmode + * + * Description: + * Set the QSPI mode. Optional. See enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The QSPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void qspi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + uint32_t regval; + + spivdbg("mode=%d\n", mode); + + /* Has the mode changed? */ + +#ifndef CONFIG_SPI_OWNBUS + if (mode != priv->mode) + { +#endif + /* Yes... Set the mode appropriately: + * + * QSPI CPOL NCPHA + * MODE + * 0 0 1 + * 1 0 0 + * 2 1 1 + * 3 1 0 + */ + + regval = qspi_getreg(priv, SAM_QSPI_SCR_OFFSET); + regval &= ~(QSPI_SCR_CPOL | QSPI_SCR_NCPHA); + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0; NCPHA=1 */ + regval |= QSPI_SCR_NCPHA; + break; + + case SPIDEV_MODE1: /* CPOL=0; NCPHA=0 */ + break; + + case SPIDEV_MODE2: /* CPOL=1; NCPHA=1 */ + regval |= (QSPI_SCR_CPOL | QSPI_SCR_NCPHA); + break; + + case SPIDEV_MODE3: /* CPOL=1; NCPHA=0 */ + regval |= QSPI_SCR_CPOL; + break; + + default: + DEBUGASSERT(FALSE); + return; + } + + qspi_putreg(priv, regval, SAM_QSPI_SCR_OFFSET); + spivdbg("SCR=%08x\n", regval); + + /* Save the mode so that subsequent re-configurations will be faster */ + +#ifndef CONFIG_SPI_OWNBUS + priv->mode = mode; + } +#endif +} + +/**************************************************************************** + * Name: qspi_setbits + * + * Description: + * Set the number if bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void qspi_setbits(struct spi_dev_s *dev, int nbits) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + uint32_t regval; + + spivdbg("nbits=%d\n", nbits); + DEBUGASSERT(priv != NULL); + DEBUGASSERT(nbits >= SAM_QSPI_MINBITS && nbits <= SAM_QSPI_MAXBITS); + + /* Has the number of bits changed? */ + +#ifndef CONFIG_SPI_OWNBUS + if (nbits != priv->nbits) +#endif + { + /* Yes... Set number of bits appropriately */ + + regval = qspi_getreg(priv, SAM_QSPI_MR_OFFSET); + regval &= ~QSPI_MR_NBBITS_MASK; + regval |= QSPI_MR_NBBITS(nbits); + qspi_putreg(priv, regval, SAM_QSPI_MR_OFFSET); + + spivdbg("SCR%02x]=%08x\n", regval); + + /* Save the selection so the subsequence re-configurations will be faster */ + + priv->nbits = nbits; + } +} + +/**************************************************************************** + * Name: qspi_status + * + * Description: + * Return status information associated with the QSPI device. + * + * Input Parameters: + * dev - SPI device info + * devid - Identifies the (logical) device + * + * Returned Values: + * Bit-encoded SPI status (see include/nuttx/spi/spi.h. + * + ****************************************************************************/ + +uint8_t qspi_status(struct spi_dev_s *dev, enum spi_dev_e devid) +{ +#warning Missing logic + return 0; +} + +/**************************************************************************** + * Name: qspi_send + * + * Description: + * Exchange one word on QSPI + * + * Input Parameters: + * dev - Device-specific state data + * wd - The word to send. the size of the data is determined by the + * number of bits selected for the QSPI interface. + * + * Returned Value: + * response + * + ****************************************************************************/ + +static uint16_t qspi_send(struct spi_dev_s *dev, uint16_t wd) +{ + uint8_t txbyte; + uint8_t rxbyte; + + /* qspi_exchange can do this. Note: right now, this only deals with 8-bit + * words. If the QSPI interface were configured for words of other sizes, + * this would fail. + */ + + txbyte = (uint8_t)wd; + rxbyte = (uint8_t)0; + qspi_exchange(dev, &txbyte, &rxbyte, 1); + + spivdbg("Sent %02x received %02x\n", txbyte, rxbyte); + return (uint16_t)rxbyte; +} + +/**************************************************************************** + * Name: qspi_exchange (and qspi_exchange_nodma) + * + * Description: + * Exchange a block of data from QSPI. There are two versions of this + * function: (1) One that is enabled only when CONFIG_SAMV7_QSPI_DMA=y + * that performs DMA QSPI transfers, but only when a larger block of + * data is being transferred. And (2) another version that does polled + * QSPI transfers. When CONFIG_SAMV7_QSPI_DMA=n the latter is the only + * version avaialable; when CONFIG_SAMV7_QSPI_DMA=y, this version is only + * used for short QSPI transfers and gets renamed as qspi_exchange_nodma). + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to the buffer in which to receive data + * nwords - the length of data that to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the QSPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_QSPI_DMA +static void qspi_exchange_nodma(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords) +#else +static void qspi_exchange(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords) +#endif +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + uint32_t data; + uint16_t *rxptr16; + uint16_t *txptr16; + uint8_t *rxptr8; + uint8_t *txptr8; + + spivdbg("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords); + + /* Set up working pointers */ + + if (priv->nbits > 8) + { + rxptr16 = (uint16_t*)rxbuffer; + txptr16 = (uint16_t*)txbuffer; + rxptr8 = NULL; + txptr8 = NULL; + } + else + { + rxptr16 = NULL; + txptr16 = NULL; + rxptr8 = (uint8_t*)rxbuffer; + txptr8 = (uint8_t*)txbuffer; + } + + /* Make sure that any previous transfer is flushed from the hardware */ + + qspi_flush(priv); + + /* Loop, sending each word in the user-provided data buffer. + * + * Note 1: Good QSPI performance would require that we implement DMA + * transfers! + * Note 2: This loop might be made more efficient. Would logic + * like the following improve the throughput? Or would it + * just add the risk of overruns? + * + * Get word 1; + * Send word 1; Now word 1 is "in flight" + * nwords--; + * for ( ; nwords > 0; nwords--) + * { + * Get word N. + * Wait for TDRE meaning that word N-1 has moved to the shift + * register. + * Disable interrupts to keep the following atomic + * Send word N. Now both work N-1 and N are "in flight" + * Wait for RDRF meaning that word N-1 is available + * Read word N-1. + * Re-enable interrupts. + * Save word N-1. + * } + * Wait for RDRF meaning that the final word is available + * Read the final word. + * Save the final word. + */ + + for ( ; nwords > 0; nwords--) + { + /* Get the data to send (0xff if there is no data source). */ + + if (txptr8) + { + data = (uint32_t)*txptr8++; + } + else if (txptr16) + { + data = (uint32_t)*txptr16++; + } + else + { + data = 0xffff; + } + + /* Do we need to set the LASTXFER bit in the TDR value too? */ + +#ifdef CONFIG_SPI_VARSELECT + if (nwords == 1) + { + data |= QSPI_TDR_LASTXFER; + } +#endif + + /* Wait for any previous data written to the TDR to be transferred + * to the serializer. + */ + + while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TDRE) == 0); + + /* Write the data to transmitted to the Transmit Data Register (TDR) */ + + qspi_putreg(priv, data, SAM_QSPI_TDR_OFFSET); + + /* Wait for the read data to be available in the RDR. + * TODO: Data transfer rates would be improved using the RX FIFO + * (and also DMA) + */ + + while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_RDRF) == 0); + + /* Read the received data from the QSPI Data Register. */ + + data = qspi_getreg(priv, SAM_QSPI_RDR_OFFSET); + if (rxptr8) + { + *rxptr8++ = (uint8_t)data; + } + else if (rxptr16) + { + *rxptr16++ = (uint16_t)data; + } + } +} + +#ifdef CONFIG_SAMV7_QSPI_DMA +static void qspi_exchange(struct spi_dev_s *dev, const void *txbuffer, + void *rxbuffer, size_t nwords) +{ + struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; + uint32_t rxflags; + uint32_t txflags; + uint32_t txdummy; + uint32_t rxdummy; + uint32_t regaddr; + uint32_t memaddr; + uint32_t width; + size_t nbytes; + int ret; + + /* Convert the number of word to a number of bytes */ + + nbytes = (priv->nbits > 8) ? nwords << 1 : nwords; + + /* If we cannot do DMA -OR- if this is a small QSPI transfer, then let + * qspi_exchange_nodma() do the work. + */ + + if (!priv->candma || nbytes <= CONFIG_SAMV7_QSPI_DMATHRESHOLD) + { + qspi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); + return; + } + + spivdbg("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords); + + priv = (struct sam_qspidev_s *)dev; + DEBUGASSERT(priv); + + /* Make sure that any previous transfer is flushed from the hardware */ + + qspi_flush(priv); + + /* Sample initial DMA registers */ + + qspi_dma_sampleinit(priv); + + /* Select the source and destination width bits */ + + if (priv->nbits > 8) + { + width = (DMACH_FLAG_PERIPHWIDTH_16BITS | DMACH_FLAG_MEMWIDTH_16BITS); + } + else + { + width = (DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_MEMWIDTH_8BITS); + } + + /* Configure the DMA channels. There are four different cases: + * + * 1) A true exchange with the memory address incrementing on both + * RX and TX channels, + * 2) A read operation with the memory address incrementing only on + * the receive channel, + * 3) A write operation where the memory address increments only on + * the receive channel, and + * 4) A corner case where there the memory address does not increment + * on either channel. This case might be used in certain cases + * where you want to assure that certain number of clocks are + * provided on the QSPI bus. + */ + + /* Configure the RX DMA channel */ + + rxflags = DMACH_FLAG_FIFOCFG_LARGEST | + ((uint32_t)priv->rxintf << DMACH_FLAG_PERIPHPID_SHIFT) | + DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | + DMACH_FLAG_PERIPHCHUNKSIZE_1 | + ((uint32_t)(15) << DMACH_FLAG_MEMPID_SHIFT) | + DMACH_FLAG_MEMCHUNKSIZE_1; + + /* Set the source and destination width bits */ + + rxflags |= width; + + /* Handle the case where there is no sink buffer */ + + if (!rxbuffer) + { + /* No sink data buffer. Point to our dummy buffer and leave + * the rxflags so that no address increment is performed. + */ + + rxbuffer = (void *)&rxdummy; + } + else + { + /* A receive buffer is available. + * + * Invalidate the RX buffer memory to force re-fetching from RAM when + * the DMA completes + */ + + sam_cmcc_invalidate((uintptr_t)rxbuffer, (uintptr_t)rxbuffer + nbytes); + + /* Use normal RX memory incrementing. */ + + rxflags |= DMACH_FLAG_MEMINCREMENT; + } + + /* Configure the TX DMA channel */ + + txflags = DMACH_FLAG_FIFOCFG_LARGEST | + ((uint32_t)priv->txintf << DMACH_FLAG_PERIPHPID_SHIFT) | + DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | + DMACH_FLAG_PERIPHCHUNKSIZE_1 | + ((uint32_t)(15) << DMACH_FLAG_MEMPID_SHIFT) | + DMACH_FLAG_MEMCHUNKSIZE_1; + + /* Set the source and destination width bits */ + + txflags |= width; + + /* Handle the case where there is no source buffer */ + + if (!txbuffer) + { + /* No source data buffer. Point to our dummy buffer and leave + * the txflags so that no address increment is performed. + */ + + txdummy = 0xffffffff; + txbuffer = (const void *)&txdummy; + } + else + { + /* Source data is available. Use normal TX memory incrementing. */ + + txflags |= DMACH_FLAG_MEMINCREMENT; + } + + /* Then configure the DMA channels to make it so */ + + sam_dmaconfig(priv->rxdma, rxflags); + sam_dmaconfig(priv->txdma, txflags); + + /* Configure the RX side of the exchange transfer */ + + regaddr = qspi_regaddr(priv, SAM_QSPI_RDR_OFFSET); + memaddr = (uintptr_t)rxbuffer; + + ret = sam_dmarxsetup(priv->rxdma, regaddr, memaddr, nwords); + if (ret < 0) + { + dmadbg("ERROR: sam_dmarxsetup failed: %d\n", ret); + return; + } + + qspi_rxdma_sample(priv, DMA_AFTER_SETUP); + + /* Configure the TX side of the exchange transfer */ + + regaddr = qspi_regaddr(priv, SAM_QSPI_TDR_OFFSET); + memaddr = (uintptr_t)txbuffer; + + ret = sam_dmatxsetup(priv->txdma, regaddr, memaddr, nwords); + if (ret < 0) + { + dmadbg("ERROR: sam_dmatxsetup failed: %d\n", ret); + return; + } + + qspi_txdma_sample(priv, DMA_AFTER_SETUP); + + /* Start the DMA transfer */ + + priv->result = -EBUSY; + ret = sam_dmastart(priv->rxdma, qspi_rxcallback, (void *)priv); + if (ret < 0) + { + dmadbg("ERROR: RX sam_dmastart failed: %d\n", ret); + return; + } + + qspi_rxdma_sample(priv, DMA_AFTER_START); + + ret = sam_dmastart(priv->txdma, qspi_txcallback, (void *)priv); + if (ret < 0) + { + dmadbg("ERROR: RX sam_dmastart failed: %d\n", ret); + sam_dmastop(priv->rxdma); + return; + } + + qspi_txdma_sample(priv, DMA_AFTER_START); + + /* Wait for DMA completion. This is done in a loop because there may be + * false alarm semaphore counts that cause sam_wait() not fail to wait + * or to wake-up prematurely (for example due to the receipt of a signal). + * We know that the DMA has completed when the result is anything other + * that -EBUSY. + */ + + do + { + /* Start (or re-start) the watchdog timeout */ + + ret = wd_start(priv->dmadog, DMA_TIMEOUT_TICKS, + (wdentry_t)qspi_dmatimeout, 1, (uint32_t)priv); + if (ret != OK) + { + spidbg("ERROR: wd_start failed: %d\n", ret); + } + + /* Wait for the DMA complete */ + + ret = sem_wait(&priv->dmawait); + + /* Cancel the watchdog timeout */ + + (void)wd_cancel(priv->dmadog); + + /* Check if we were awakened by an error of some kind */ + + if (ret < 0) + { + /* EINTR is not a failure. That simply means that the wait + * was awakened by a signal. + */ + + int errorcode = errno; + if (errorcode != EINTR) + { + DEBUGPANIC(); + return; + } + } + + /* Not that we might be awakened before the wait is over due to + * residual counts on the semaphore. So, to handle, that case, + * we loop until something changes the DMA result to any value other + * than -EBUSY. + */ + } + while (priv->result == -EBUSY); + + /* Dump the sampled DMA registers */ + + qspi_dma_sampledone(priv); + + /* Make sure that the DMA is stopped (it will be stopped automatically + * on normal transfers, but not necessarily when the transfer terminates + * on an error condition). + */ + + sam_dmastop(priv->rxdma); + sam_dmastop(priv->txdma); + + /* All we can do is complain if the DMA fails */ + + if (priv->result) + { + spidbg("ERROR: DMA failed with result: %d\n", priv->result); + } +} +#endif /* CONFIG_SAMV7_QSPI_DMA */ + +/*************************************************************************** + * Name: qspi_sndblock + * + * Description: + * Send a block of data on QSPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of words. + * The wordsize is determined by the number of bits-per-word + * selected for the QSPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void qspi_sndblock(struct spi_dev_s *dev, const void *buffer, + size_t nwords) +{ + /* qspi_exchange can do this. */ + + qspi_exchange(dev, buffer, NULL, nwords); +} +#endif + +/**************************************************************************** + * Name: qspi_recvblock + * + * Description: + * Revice a block of data from QSPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer in which to receive data + * nwords - the length of data that can be received in the buffer in number + * of words. The wordsize is determined by the number of bits-per-word + * selected for the QSPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void qspi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords) +{ + /* qspi_exchange can do this. */ + + qspi_exchange(dev, NULL, buffer, nwords); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_qspi_initialize + * + * Description: + * Initialize the selected QSPI port in master mode + * + * Input Parameter: + * intf - Interface number(must be zero) + * + * Returned Value: + * Valid QSPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *sam_qspi_initialize(int intf) +{ + FAR struct sam_qspidev_s *priv; + irqstate_t flags; +#ifndef CONFIG_SPI_OWNBUS + uint32_t regval; +#endif + + /* The support SAM parts have only a single QSPI port */ + + spivdbg("intf: %d\n", intf); + DEBUGASSERT(intf >= 0 && intf < SAMV7_NQSPI); + + /* Select the QSPI interface */ + +#ifdef CONFIG_SAMV7_QSPI + if (intf == 0) + { + /* Select QSPI0 */ + + priv = &g_qspi0dev; + + /* Enable clocking to the QSPI peripheral */ + + sam_qspi_enableclk(); + + /* Configure multiplexed pins as connected on the board. */ + + sam_configgpio(GPIO_QSPI_CS); + sam_configgpio(GPIO_QSPI_IO0); + sam_configgpio(GPIO_QSPI_IO1); + sam_configgpio(GPIO_QSPI_IO2); + sam_configgpio(GPIO_QSPI_IO3); + sam_configgpio(GPIO_QSPI_SCK); + } + else +#endif + { + spidbg("ERROR: QSPI%d not supported\n", intf); + return NULL; + } + +#ifdef CONFIG_SAMV7_QSPI_DMA + /* Pre-allocate DMA channels. These allocations exploit that fact that + * QSPI0 is managed by DMAC0 and QSPI1 is managed by DMAC1. Hence, + * the QSPI number (intf) is the same as the DMAC number. + */ + + if (priv->candma) + { + priv->rxdma = sam_dmachannel(0); + if (!priv->rxdma) + { + spidbg("ERROR: Failed to allocate the RX DMA channel\n"); + priv->candma = false; + } + } + + if (priv->candma) + { + priv->txdma = sam_dmachannel(0); + if (!priv->txdma) + { + spidbg("ERROR: Failed to allocate the TX DMA channel\n"); + sam_dmafree(priv->rxdma); + priv->rxdma = NULL; + priv->candma = false; + } + } +#endif + + /* Has the QSPI hardware been initialized? */ + + if (!priv->initialized) + { + /* Enable clocking to the QSPI block */ + + flags = irqsave(); +#if defined(CONFIG_SAMV7_QSPI) && defined(CONFIG_SAMV7_QSPI1_MASTER) + if (intf == 0) +#endif + /* Disable QSPI clocking */ + + qspi_putreg(priv, QSPI_CR_QSPIDIS, SAM_QSPI_CR_OFFSET); + + /* Execute a software reset of the QSPI (twice) */ + + qspi_putreg(priv, QSPI_CR_SWRST, SAM_QSPI_CR_OFFSET); + qspi_putreg(priv, QSPI_CR_SWRST, SAM_QSPI_CR_OFFSET); + irqrestore(flags); + + /* Configure the QSPI mode register */ +#warning Missing Logic + + /* And enable the QSPI */ + + qspi_putreg(priv, QSPI_CR_QSPIEN, SAM_QSPI_CR_OFFSET); + up_mdelay(20); + + /* Flush any pending transfers */ + + (void)qspi_getreg(priv, SAM_QSPI_SR_OFFSET); + (void)qspi_getreg(priv, SAM_QSPI_RDR_OFFSET); + +#ifndef CONFIG_SPI_OWNBUS + /* Initialize the QSPI semaphore that enforces mutually exclusive + * access to the QSPI registers. + */ + + sem_init(&priv->spisem, 0, 1); + priv->initialized = true; +#endif + +#ifdef CONFIG_SAMV7_QSPI_DMA + /* Initialize the QSPI semaphore that is used to wake up the waiting + * thread when the DMA transfer completes. + */ + + sem_init(&priv->dmawait, 0, 0); + + /* Create a watchdog time to catch DMA timeouts */ + + priv->dmadog = wd_create(); + DEBUGASSERT(priv->dmadog); +#endif + + qspi_dumpregs(priv, "After initialization"); + } + +#ifndef CONFIG_SPI_OWNBUS + /* Set to mode=0 and nbits=8 and impossible frequency. It is only + * critical to do this if CONFIG_SPI_OWNBUS is not defined because in + * that case, the QSPI will only be reconfigured if there is a change. + */ + + regval = qspi_getreg(priv, SAM_QSPI_SCR_OFFSET); + regval &= ~QSPI_SCR_CPOL; + regval |= QSPI_SCR_NCPHA; + qspi_putreg(priv, regval, SAM_QSPI_SCR_OFFSET); + + regval = qspi_getreg(priv, SAM_QSPI_MR_OFFSET); + regval &= ~QSPI_MR_NBBITS_MASK; + regval |= QSPI_MR_NBBITS_8BIT; + qspi_putreg(priv, regval, SAM_QSPI_MR_OFFSET); + + priv->nbits = 8; + spivdbg("SCR=%08x\n", regval); +#endif + + return &priv->spidev; +} +#endif /* CONFIG_SAMV7_QSPI */ diff --git a/arch/arm/src/samv7/sam_qspi.h b/arch/arm/src/samv7/sam_qspi.h new file mode 100644 index 00000000000..7888c5dde1b --- /dev/null +++ b/arch/arm/src/samv7/sam_qspi.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_qspi.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_SAM_QSPI_H +#define __ARCH_ARM_SRC_SAMV7_SAM_QSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "chip.h" +#include "sam_config.h" + +#ifdef CONFIG_SAMV7_QSPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_qspi_initialize + * + * Description: + * Initialize the selected QSPI port in master mode + * + * Input Parameter: + * intf - Interface number(must be zero) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *sam_qspi_initialize(int intf); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_SAMV7_QSPI */ +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_QSPI_H */ diff --git a/arch/arm/src/samv7/sam_spi.c b/arch/arm/src/samv7/sam_spi.c index 1fc521d2d24..702e8ad779c 100644 --- a/arch/arm/src/samv7/sam_spi.c +++ b/arch/arm/src/samv7/sam_spi.c @@ -69,7 +69,7 @@ #include "chip/sam_spi.h" #include "chip/sam_pinmap.h" -#if defined(CONFIG_SAMV7_SPI0) || defined(CONFIG_SAMV7_SPI1) +#ifdef CONFIG_SAMV7_SPI_MASTER /**************************************************************************** * Pre-processor Definitions @@ -86,13 +86,13 @@ #ifdef CONFIG_SAMV7_SPI_DMA -# if defined(CONFIG_SAMV7_SPI0) && defined(CONFIG_SAMV7_DMAC0) +# if defined(CONFIG_SAMV7_SPI0_MASTER) && defined(CONFIG_SAMV7_DMAC0) # define SAMV7_SPI0_DMA true # else # define SAMV7_SPI0_DMA false # endif -# if defined(CONFIG_SAMV7_SPI1) && defined(CONFIG_SAMV7_DMAC1) +# if defined(CONFIG_SAMV7_SPI1_MASTER) && defined(CONFIG_SAMV7_DMAC1) # define SAMV7_SPI1_DMA true # else # define SAMV7_SPI1_DMA false @@ -118,7 +118,7 @@ #define DMA_TIMEOUT_TICKS MSEC2TICK(DMA_TIMEOUT_MS) /* Debug *******************************************************************/ -/* Check if SPI debut is enabled (non-standard.. no support in +/* Check if SPI debug is enabled (non-standard.. no support in * include/debug.h */ @@ -170,7 +170,7 @@ struct sam_spics_s #endif uint8_t nbits; /* Width of word in bits (8 to 16) */ -#if defined(CONFIG_SAMV7_SPI0) || defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) || defined(CONFIG_SAMV7_SPI1_MASTER) uint8_t spino; /* SPI controller number (0 or 1) */ #endif uint8_t cs; /* Chip select number */ @@ -196,7 +196,7 @@ struct sam_spics_s typedef void (*select_t)(enum spi_dev_e devid, bool selected); -/* Chip select register offsetrs */ +/* Chip select register offsets */ /* The overall state of one SPI controller */ @@ -273,7 +273,7 @@ static inline uintptr_t spi_regaddr(struct sam_spics_s *spics, unsigned int offset); #endif -/* SPI methods */ +/* SPI master methods */ #ifndef CONFIG_SPI_OWNBUS static int spi_lock(struct spi_dev_s *dev, bool lock); @@ -309,7 +309,7 @@ static const uint8_t g_csroffset[4] = SAM_SPI_CSR2_OFFSET, SAM_SPI_CSR3_OFFSET }; -#ifdef CONFIG_SAMV7_SPI0 +#ifdef CONFIG_SAMV7_SPI0_MASTER /* SPI0 driver operations */ static const struct spi_ops_s g_spi0ops = @@ -348,7 +348,7 @@ static struct sam_spidev_s g_spi0dev = }; #endif -#ifdef CONFIG_SAMV7_SPI1 +#ifdef CONFIG_SAMV7_SPI1_MASTER /* SPI1 driver operations */ static const struct spi_ops_s g_spi1ops = @@ -541,9 +541,9 @@ static void spi_dumpregs(struct sam_spidev_s *spi, const char *msg) static inline struct sam_spidev_s *spi_device(struct sam_spics_s *spics) { -#if defined(CONFIG_SAMV7_SPI0) && defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) && defined(CONFIG_SAMV7_SPI1_MASTER) return spics->spino ? &g_spi1dev : &g_spi0dev; -#elif defined(CONFIG_SAMV7_SPI0) +#elif defined(CONFIG_SAMV7_SPI0_MASTER) return &g_spi0dev; #else return &g_spi1dev; @@ -1726,7 +1726,7 @@ static void spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords) * Name: up_spiinitialize * * Description: - * Initialize the selected SPI port + * Initialize the selected SPI port in master mode * * Input Parameter: * cs - Chip select number (identifying the "logical" SPI port) @@ -1736,10 +1736,10 @@ static void spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords) * ****************************************************************************/ -struct spi_dev_s *up_spiinitialize(int port) +FAR struct spi_dev_s *up_spiinitialize(int port) { - struct sam_spidev_s *spi; - struct sam_spics_s *spics; + FAR struct sam_spidev_s *spi; + FAR struct sam_spics_s *spics; int csno = (port & __SPI_CS_MASK) >> __SPI_CS_SHIFT; int spino = (port & __SPI_SPI_MASK) >> __SPI_SPI_SHIFT; irqstate_t flags; @@ -1753,9 +1753,9 @@ struct spi_dev_s *up_spiinitialize(int port) spivdbg("port: %d csno: %d spino: %d\n", port, csno, spino); DEBUGASSERT(csno >= 0 && csno <= SAM_SPI_NCS); -#if defined(CONFIG_SAMV7_SPI0) && defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) && defined(CONFIG_SAMV7_SPI1_MASTER) DEBUGASSERT(spino >= 0 && spino <= 1); -#elif defined(CONFIG_SAMV7_SPI0) +#elif defined(CONFIG_SAMV7_SPI0_MASTER) DEBUGASSERT(spino == 0); #else DEBUGASSERT(spino == 1); @@ -1812,9 +1812,9 @@ struct spi_dev_s *up_spiinitialize(int port) /* Select the SPI operations */ -#if defined(CONFIG_SAMV7_SPI0) && defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) && defined(CONFIG_SAMV7_SPI1_MASTER) spics->spidev.ops = spino ? &g_spi1ops : &g_spi0ops; -#elif defined(CONFIG_SAMV7_SPI0) +#elif defined(CONFIG_SAMV7_SPI0_MASTER) spics->spidev.ops = &g_spi0ops; #else spics->spidev.ops = &g_spi1ops; @@ -1823,7 +1823,7 @@ struct spi_dev_s *up_spiinitialize(int port) /* Save the chip select and SPI controller numbers */ spics->cs = csno; -#if defined(CONFIG_SAMV7_SPI0) || defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) || defined(CONFIG_SAMV7_SPI1_MASTER) spics->spino = spino; #endif @@ -1838,10 +1838,10 @@ struct spi_dev_s *up_spiinitialize(int port) /* Enable clocking to the SPI block */ flags = irqsave(); -#if defined(CONFIG_SAMV7_SPI0) && defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) && defined(CONFIG_SAMV7_SPI1_MASTER) if (spino == 0) #endif -#if defined(CONFIG_SAMV7_SPI0) +#if defined(CONFIG_SAMV7_SPI0_MASTER) { sam_spi0_enableclk(); @@ -1854,10 +1854,10 @@ struct spi_dev_s *up_spiinitialize(int port) sam_configgpio(GPIO_SPI0_SPCK); } #endif -#if defined(CONFIG_SAMV7_SPI0) && defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI0_MASTER) && defined(CONFIG_SAMV7_SPI1_MASTER) else #endif -#if defined(CONFIG_SAMV7_SPI1) +#if defined(CONFIG_SAMV7_SPI1_MASTER) { sam_spi1_enableclk(); @@ -1938,4 +1938,4 @@ struct spi_dev_s *up_spiinitialize(int port) return &spics->spidev; } -#endif /* CONFIG_SAMV7_SPI0 || CONFIG_SAMV7_SPI1 */ +#endif /* CONFIG_SAMV7_SPI_MASTER */ diff --git a/arch/arm/src/samv7/sam_spi.h b/arch/arm/src/samv7/sam_spi.h index 47afad02fd9..cf8732059f4 100644 --- a/arch/arm/src/samv7/sam_spi.h +++ b/arch/arm/src/samv7/sam_spi.h @@ -46,6 +46,9 @@ #include #include "chip.h" +#include "sam_config.h" + +#ifdef CONFIG_SAMV7_SPI /**************************************************************************** * Pre-processor Definitions @@ -108,6 +111,43 @@ extern "C" * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: up_spiinitialize + * + * Description: + * Initialize the selected SPI port in master mode + * + * Input Parameter: + * cs - Chip select number (identifying the "logical" SPI port) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +#if 0 /* Prototyped in include/nuttx/spi/spi.h */ +FAR struct spi_dev_s *up_spiinitialize(int port) +#endif + +/**************************************************************************** + * Name: up_spi_slave_initialize + * + * Description: + * Initialize the selected SPI port in slave mode. + * + * Input Parameter: + * port - Chip select number identifying the "logical" SPI port. Includes + * encoded port and chip select information. + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +#if 0 /* Prototyped in include/nuttx/spi/slave.h */ +FAR struct spi_sctrlr_s *up_spi_slave_initialize(int port); +#endif + /**************************************************************************** * Name: sam_spi[0|1]select, sam_spi[0|1]status, and sam_spi[0|1]cmddata * @@ -115,7 +155,7 @@ extern "C" * These external functions must be provided by board-specific logic. * They include: * - * o sam_spi[0|1]select is a functions tomanage the board-specific chip + * o sam_spi[0|1]select is a functions to manage the board-specific chip * selects * o sam_spi[0|1]status and sam_spi[0|1]cmddata: Implementations of the * status and cmddata methods of the SPI interface defined by struct @@ -142,9 +182,8 @@ extern "C" * ****************************************************************************/ -#ifdef CONFIG_SAMV7_SPI0 -struct spi_dev_s; -enum spi_dev_e; +struct spi_dev_s; /* Forward reference */ +enum spi_dev_e; /* Forward reference */ /**************************************************************************** * Name: sam_spi[0|1]select @@ -172,10 +211,10 @@ enum spi_dev_e; * ****************************************************************************/ -#ifdef CONFIG_SAMV7_SPI0 +#ifdef CONFIG_SAMV7_SPI0_MASTER void sam_spi0select(enum spi_dev_e devid, bool selected); #endif -#ifdef CONFIG_SAMV7_SPI1 +#ifdef CONFIG_SAMV7_SPI1_MASTER void sam_spi1select(enum spi_dev_e devid, bool selected); #endif @@ -226,14 +265,13 @@ uint8_t sam_spi1status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); ****************************************************************************/ #ifdef CONFIG_SPI_CMDDATA -#ifdef CONFIG_SAMV7_SPI0 +#ifdef CONFIG_SAMV7_SPI0_MASTER int sam_spi0cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool cmd); #endif -#ifdef CONFIG_SAMV7_SPI1 +#ifdef CONFIG_SAMV7_SPI1_MASTER int sam_spi1cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool cmd); #endif -#endif -#endif /* CONFIG_SAMV7_SPI0 */ +#endif /* CONFIG_SPI_CMDDATA */ #undef EXTERN #if defined(__cplusplus) @@ -241,4 +279,5 @@ int sam_spi1cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool cmd); #endif #endif /* __ASSEMBLY__ */ +#endif /* CONFIG_SAMV7_SPI */ #endif /* __ARCH_ARM_SRC_SAMV7_SAM_SPI_H */ diff --git a/arch/arm/src/samv7/sam_spi_slave.c b/arch/arm/src/samv7/sam_spi_slave.c new file mode 100644 index 00000000000..71e54057df1 --- /dev/null +++ b/arch/arm/src/samv7/sam_spi_slave.c @@ -0,0 +1,1286 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_spi_slave.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "up_arch.h" + +#include "sam_config.h" +#include "sam_gpio.h" +#include "sam_periphclks.h" +#include "sam_spi.h" + +#include "chip/sam_spi.h" +#include "chip/sam_pinmap.h" +#include + +#ifdef CONFIG_SAMV7_SPI_SLAVE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_SAMV7_SPI_SLAVE_QSIZE +# define CONFIG_SAMV7_SPI_SLAVE_QSIZE 8 +#endif + +/* Debug *******************************************************************/ +/* Check if SPI debug is enabled (non-standard.. no support in + * include/debug.h + */ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_VERBOSE +# undef CONFIG_DEBUG_SPI +#endif + +#ifdef CONFIG_DEBUG_SPI +# define spidbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define spivdbg lldbg +# else +# define spivdbg(x...) +# endif +#else +# define spidbg(x...) +# define spivdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The overall state of one SPI controller */ + +struct sam_spidev_s +{ + struct spi_sctrlr_s sctrlr; /* Externally visible part of the SPI slave + * controller interface */ + struct spi_sdev_s *sdev; /* Bound SPI slave device interface */ + xcpt_t handler; /* SPI interrupt handler */ + uint32_t base; /* SPI controller register base address */ + sem_t spisem; /* Assures mutually exclusive access to SPI */ + uint16_t outval; /* Default shift-out value */ + uint16_t irq; /* SPI IRQ number */ + uint8_t mode; /* Mode 0,1,2,3 */ + uint8_t nbits; /* Width of word in bits (8 to 16) */ + uint8_t spino; /* SPI controller number (0 or 1) */ + bool initialized; /* True: Controller has been initialized */ + bool nss; /* True: Chip selected */ + + /* Output queue */ + + uint8_t head; /* Location of next value */ + uint8_t tail; /* Index of first value */ + + uint16_t outq[CONFIG_SAMV7_SPI_SLAVE_QSIZE]; + + /* Debug stuff */ + +#ifdef CONFIG_SAMV7_SPI_REGDEBUG + bool wrlast; /* Last was a write */ + uint32_t addresslast; /* Last address */ + uint32_t valuelast; /* Last value */ + int ntimes; /* Number of times */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +#ifdef CONFIG_SAMV7_SPI_REGDEBUG +static bool spi_checkreg(struct sam_spidev_s *priv, bool wr, + uint32_t value, uint32_t address); +#else +# define spi_checkreg(priv,wr,value,address) (false) +#endif + +static uint32_t spi_getreg(struct sam_spidev_s *priv, + unsigned int offset); +static void spi_putreg(struct sam_spidev_s *priv, uint32_t value, + unsigned int offset); + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE) +static void spi_dumpregs(struct sam_spidev_s *priv, const char *msg); +#else +# define spi_dumpregs(priv,msg) +#endif + +static void spi_semtake(struct sam_spidev_s *priv); +#define spi_semgive(priv) (sem_post(&(priv)->spisem)) + +/* Interrupt Handling */ + +static int spi_interrupt(struct sam_spidev_s *priv); +#ifdef CONFIG_SAMV7_SPI0_SLAVE +static int spi0_interrupt(int irq, void *context); +#endif +#ifdef CONFIG_SAMV7_SPI1_SLAVE +static int spi1_interrupt(int irq, void *context); +#endif + +/* SPI Helpers */ + +static uint16_t spi_dequeue(struct sam_spidev_s *priv); +static void spi_setmode(struct sam_spidev_s *priv, + enum spi_smode_e mode); +static void spi_setbits(struct sam_spidev_s *priv, + int nbits); + +/* SPI slave controller methods */ + +static void spi_bind(struct spi_sctrlr_s *sctrlr, + struct spi_sdev_s *sdev, enum spi_smode_e mode, + int nbits); +static void spi_unbind(struct spi_sctrlr_s *sctrlr); +static int spi_enqueue(struct spi_sctrlr_s *sctrlr, uint16_t data); +static bool spi_qfull(struct spi_sctrlr_s *sctrlr); +static void spi_qflush(struct spi_sctrlr_s *sctrlr); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This array maps chip select numbers (0-3) to CSR register offsets */ + +static const uint8_t g_csroffset[4] = +{ + SAM_SPI_CSR0_OFFSET, SAM_SPI_CSR1_OFFSET, + SAM_SPI_CSR2_OFFSET, SAM_SPI_CSR3_OFFSET +}; + +/* SPI slave controller driver operations */ + +static const struct spi_sctrlrops_s g_sctrlr_ops = +{ + .bind = spi_bind, + .unbind = spi_unbind, + .enqueue = spi_enqueue, + .qfull = spi_qfull, + .qflush = spi_qflush, +}; + +#ifdef CONFIG_SAMV7_SPI0_SLAVE +/* This is the overall state of the SPI0 controller */ + +static struct sam_spidev_s g_spi0_sctrlr; +#endif + +#ifdef CONFIG_SAMV7_SPI1_SLAVE +/* This is the overall state of the SPI0 controller */ + +static struct sam_spidev_s g_spi1_sctrlr; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spi_checkreg + * + * Description: + * Check if the current register access is a duplicate of the preceding. + * + * Input Parameters: + * value - The value to be written + * address - The address of the register to write to + * + * Returned Value: + * true: This is the first register access of this type. + * flase: This is the same as the preceding register access. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_SPI_REGDEBUG +static bool spi_checkreg(struct sam_spidev_s *priv, bool wr, uint32_t value, + uint32_t address) +{ + if (wr == priv->wrlast && /* Same kind of access? */ + value == priv->valuelast && /* Same value? */ + address == priv->addresslast) /* Same address? */ + { + /* Yes, then just keep a count of the number of times we did this. */ + + priv->ntimes++; + return false; + } + else + { + /* Did we do the previous operation more than once? */ + + if (priv->ntimes > 0) + { + /* Yes... show how many times we did it */ + + lldbg("...[Repeats %d times]...\n", priv->ntimes); + } + + /* Save information about the new access */ + + priv->wrlast = wr; + priv->valuelast = value; + priv->addresslast = address; + priv->ntimes = 0; + } + + /* Return true if this is the first time that we have done this operation */ + + return true; +} +#endif + +/**************************************************************************** + * Name: spi_getreg + * + * Description: + * Read an SPI register + * + ****************************************************************************/ + +static uint32_t spi_getreg(struct sam_spidev_s *priv, unsigned int offset) +{ + uint32_t address = priv->base + offset; + uint32_t value = getreg32(address); + +#ifdef CONFIG_SAMV7_SPI_REGDEBUG + if (spi_checkreg(priv, false, value, address)) + { + lldbg("%08x->%08x\n", address, value); + } +#endif + + return value; +} + +/**************************************************************************** + * Name: spi_putreg + * + * Description: + * Write a value to an SPI register + * + ****************************************************************************/ + +static void spi_putreg(struct sam_spidev_s *priv, uint32_t value, + unsigned int offset) +{ + uint32_t address = priv->base + offset; + +#ifdef CONFIG_SAMV7_SPI_REGDEBUG + if (spi_checkreg(priv, true, value, address)) + { + lldbg("%08x<-%08x\n", address, value); + } +#endif + + putreg32(value, address); +} + +/**************************************************************************** + * Name: spi_dumpregs + * + * Description: + * Dump the contents of all SPI registers + * + * Input Parameters: + * priv - The SPI controller to dump + * msg - Message to print before the register data + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE) +static void spi_dumpregs(struct sam_spidev_s *priv, const char *msg) +{ + spivdbg("%s:\n", msg); + spivdbg(" MR:%08x SR:%08x IMR:%08x\n", + getreg32(priv->base + SAM_SPI_MR_OFFSET), + getreg32(priv->base + SAM_SPI_SR_OFFSET), + getreg32(priv->base + SAM_SPI_IMR_OFFSET)); + spivdbg(" CSR0:%08x CSR1:%08x CSR2:%08x CSR3:%08x\n", + getreg32(priv->base + SAM_SPI_CSR0_OFFSET), + getreg32(priv->base + SAM_SPI_CSR1_OFFSET), + getreg32(priv->base + SAM_SPI_CSR2_OFFSET), + getreg32(priv->base + SAM_SPI_CSR3_OFFSET)); + spivdbg(" WPCR:%08x WPSR:%08x\n", + getreg32(priv->base + SAM_SPI_WPCR_OFFSET), + getreg32(priv->base + SAM_SPI_WPSR_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: spi_semtake + * + * Description: + * Take the semaphore that enforces mutually exclusive access to SPI + * resources, handling any exceptional conditions + * + * Input Parameters: + * priv - A reference to the MCAN peripheral state + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_semtake(struct sam_spidev_s *priv) +{ + int ret; + + /* Wait until we successfully get the semaphore. EINTR is the only + * expected 'failure' (meaning that the wait for the semaphore was + * interrupted by a signal. + */ + + do + { + ret = sem_wait(&priv->spisem); + DEBUGASSERT(ret == 0 || errno == EINTR); + } + while (ret < 0); +} + +/**************************************************************************** + * Name: spi_interrupt + * + * Description: + * Common SPI interrupt handler + * + * Input Parameters: + * priv - SPI controller CS state + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +static int spi_interrupt(struct sam_spidev_s *priv) +{ + uint32_t sr; + uint32_t imr; + uint32_t pending; + uint32_t regval; + + /* We loop because the TDRE interrupt will probably immediately follow the + * RDRF interrupt and we might be able to catch it in this handler + * execution. + */ + + for (;;) + { + /* Get the current set of pending/enabled interrupts */ + + sr = spi_getreg(priv, SAM_SPI_SR_OFFSET); + imr = spi_getreg(priv, SAM_SPI_IMR_OFFSET); + pending = sr & imr; + + /* Return from the interrupt handler when all pending interrupts have + * been processed. + */ + + if (pending == 0) + { + return OK; + } + + /* TThe SPI waits until NSS goes active before receiving the serial + * clock from an external master. When NSS falls, the clock is + * validated and the data is loaded in the SPI_RDR depending on the + * BITS field configured in the SPI_CSR0. These bits are processed + * following a phase and a polarity defined respectively by the NCPHA + * and CPOL bits in the SPI_CSR0. + * + * When all bits are processed, the received data is transferred in + * the SPI_RDR and the RDRF bit rises. If the SPI_RDR has not been + * read before new data is received, the Overrun Error Status (OVRES) + * bit in the SPI_SR is set. As long as this flag is set, data is + * loaded in the SPI_RDR. The user must read SPI_SR to clear the OVRES + * bit. + */ + +#ifdef CONFIG_DEBUG_SPI + /* Check the RX data overflow condition */ + + if ((pending & SPI_INT_OVRES) != 0) + { + /* If debug is enabled, report any overrun errors */ + + spidbg("Error: Overrun (OVRES): %08x\n", pending); + + /* OVRES was cleared by the status read. */ + } +#endif + + /* Check for the availability of RX data */ + + if ((pending & SPI_INT_RDRF) != 0) + { + uint16_t data; + + /* We get no indication of the falling edge of NSS. But if we are + * here then it must have fallen. + */ + + if (priv->nss) + { + priv->nss = false; + SPI_SDEV_SELECT(priv->sdev, true); + } + + /* Read the RDR to get the data and to clear the pending RDRF + * interrupt. + */ + + regval = spi_getreg(priv, SAM_SPI_RDR_OFFSET); + data = (uint16_t)((regval & SPI_RDR_RD_MASK) >> SPI_RDR_RD_SHIFT); + + /* Enable TXDR/OVRE interrupts */ + + regval = (SPI_INT_TDRE | SPI_INT_UNDES); + spi_putreg(priv, regval, SAM_SPI_IER_OFFSET); + + /* Report the receipt of data to the SPI device driver */ + + SPI_SDEV_RECEIVE(priv->sdev, data); + } + + /* When a transfer starts, the data shifted out is the data present + * in the Shift register. If no data has been written in the SPI_TDR, + * the last data received is transferred. If no data has been received + * since the last reset, all bits are transmitted low, as the Shift + * register resets to 0. + * + * When a first data is written in the SPI_TDR, it is transferred + * immediately in the Shift register and the TDRE flag rises. If new + * data is written, it remains in the SPI_TDR until a transfer occurs, + * i.e., NSS falls and there is a valid clock on the SPCK pin. When + * the transfer occurs, the last data written in the SPI_TDR is + * transferred in the Shift register and the TDRE flag rises. This + * enables frequent updates of critical variables with single transfers. + * + * Then, new data is loaded in the Shift register from the SPI_TDR. If + * no character is ready to be transmitted, i.e., no character has been + * written in the SPI_TDR since the last load from the SPI_TDR to the + * Shift register, the SPI_TDR is retransmitted. In this case the + * Underrun Error Status Flag (UNDES) is set in the SPI_SR. + */ + +#ifdef CONFIG_DEBUG_SPI + /* Check the TX data underflow condition */ + + if ((pending & SPI_INT_UNDES) != 0) + { + /* If debug is enabled, report any overrun errors */ + + spidbg("Error: Underrun (UNDEX): %08x\n", pending); + + /* UNDES was cleared by the status read. */ + } +#endif + + /* Output the next TX data */ + + if ((pending & SPI_INT_TDRE) != 0) + { + /* Get the next output value and write it to the TDR + * The TDRE interrupt is cleared by writing to the from RDR. + */ + + regval = spi_dequeue(priv); + spi_putreg(priv, regval, SAM_SPI_TDR_OFFSET); + } + + /* The SPI slave hardware provides only an event when NSS rises + * which may or many not happen at the end of a transfer. NSSR was + * cleared by the status read. + */ + + if ((pending & SPI_INT_NSSR) != 0) + { + /* Disable further TXDR/OVRE interrupts */ + + regval = (SPI_INT_TDRE | SPI_INT_UNDES); + spi_putreg(priv, regval, SAM_SPI_IDR_OFFSET); + + /* Report the state change to the SPI device driver */ + + priv->nss = true; + SPI_SDEV_SELECT(priv->sdev, false); + } + } + + return OK; +} + +/**************************************************************************** + * Name: spi0_interrupt + * + * Description: + * SPI0 interrupt handler + * + * Input Parameters: + * Standard interrupt input parameters + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_SPI0_SLAVE +static int spi0_interrupt(int irq, void *context) +{ + return spi_interrupt(&g_spi0_sctrlr); +} +#endif + +/**************************************************************************** + * Name: spi1_interrupt + * + * Description: + * SPI1 interrupt handler + * + * Input Parameters: + * Standard interrupt input parameters + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMV7_SPI1_SLAVE +static int spi1_interrupt(int irq, void *context) +{ + return spi_interrupt(&g_spi1_sctrlr); +} +#endif + +/**************************************************************************** + * Name: spi_dequeue + * + * Description: + * Return the next queued output value. If nothing is in the output queue, + * then return the last value obtained from getdata(); + * + * Input Parameters: + * priv - SPI controller CS state + * + * Assumptions: + * Called only from the SPI interrupt handler so all interrupts are + * disabled. + * + ****************************************************************************/ + +static uint16_t spi_dequeue(struct sam_spidev_s *priv) +{ + uint32_t regval; + uint16_t ret; + int next; + + /* Is the queue empty? */ + + if (priv->head != priv->tail) + { + /* No, take the oldest value from the tail of the cicular buffer */ + + ret = priv->outq[priv->tail]; + + /* Update the tail index, handling wraparound */ + + next = priv->tail + 1; + if (next >= CONFIG_SAMV7_SPI_SLAVE_QSIZE) + { + next = 0; + } + + priv->tail = next; + + /* If the queue is empty Disable further TXDR/OVRE interrupts until + * spi_enqueue() is called or until we received another command. We + * do this only for the case where NSS is non-functional (tied to + * ground) and we need to end transfers in some fashion. + */ + + if (priv->head == next) + { + regval = (SPI_INT_TDRE | SPI_INT_UNDES); + spi_putreg(priv, regval, SAM_SPI_IDR_OFFSET); + } + } + else + { + /* Yes, return the last value we got from the getdata() method */ + + ret = priv->outval; + + /* Disable further TXDR/OVRE interrupts until spi_enqueue() is called. */ + + regval = (SPI_INT_TDRE | SPI_INT_UNDES); + spi_putreg(priv, regval, SAM_SPI_IDR_OFFSET); + } + + return ret; +} + +/**************************************************************************** + * Name: spi_setmode + * + * Description: + * Set the SPI mode. See enum spi_smode_e for mode definitions + * + * Input Parameters: + * priv - SPI device data structure + * mode - The SPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setmode(struct sam_spidev_s *priv, enum spi_smode_e mode) +{ + uint32_t regval; + + spivdbg("mode=%d\n", mode); + + /* Has the mode changed? */ + + if (mode != priv->mode) + { + /* Yes... Set the mode appropriately: + * + * SPI CPOL NCPHA + * MODE + * 0 0 1 + * 1 0 0 + * 2 1 1 + * 3 1 0 + */ + + regval = spi_getreg(priv, SAM_SPI_CSR0_OFFSET); + regval &= ~(SPI_CSR_CPOL | SPI_CSR_NCPHA); + + switch (mode) + { + case SPISLAVE_MODE0: /* CPOL=0; NCPHA=1 */ + regval |= SPI_CSR_NCPHA; + break; + + case SPISLAVE_MODE1: /* CPOL=0; NCPHA=0 */ + break; + + case SPISLAVE_MODE2: /* CPOL=1; NCPHA=1 */ + regval |= (SPI_CSR_CPOL | SPI_CSR_NCPHA); + break; + + case SPISLAVE_MODE3: /* CPOL=1; NCPHA=0 */ + regval |= SPI_CSR_CPOL; + break; + + default: + DEBUGASSERT(FALSE); + return; + } + + spi_putreg(priv, regval, SAM_SPI_CSR0_OFFSET); + spivdbg("csr0=%08x\n", regval); + + /* Save the mode so that subsequent re-configurations will be faster */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: spi_setbits + * + * Description: + * Set the number if bits per word. + * + * Input Parameters: + * priv - SPI device data structure + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setbits(struct sam_spidev_s *priv, int nbits) +{ + uint32_t regval; + + spivdbg("nbits=%d\n", nbits); + DEBUGASSERT(priv && nbits > 7 && nbits < 17); + + /* Has the number of bits changed? */ + + if (nbits != priv->nbits) + { + /* Yes... Set number of bits appropriately */ + + regval = spi_getreg(priv, SAM_SPI_CSR0_OFFSET); + regval &= ~SPI_CSR_BITS_MASK; + regval |= SPI_CSR_BITS(nbits); + spi_putreg(priv, regval, SAM_SPI_CSR0_OFFSET); + + spivdbg("csr0=%08x\n", regval); + + /* Save the selection so the subsequence re-configurations will be faster */ + + priv->nbits = nbits; + } +} + +/**************************************************************************** + * Name: spi_bind + * + * Description: + * Bind the SPI slave device interface to the SPI slave controller + * interface and configure the SPI interface. Upon return, the SPI + * slave controller driver is fully operational and ready to perform + * transfers. + * + * Input Parameters: + * sctrlr - SPI slave controller interface instance + * sdev - SPI slave device interface instance + * mode - The SPI mode requested + * nbits - The number of bits requests. + * If value is greater > 0 then it implies MSB first + * If value is below < 0, then it implies LSB first with -nbits + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_bind(struct spi_sctrlr_s *sctrlr, + struct spi_sdev_s *sdev, enum spi_smode_e mode, + int nbits) +{ + struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr; + uint32_t regval; + + spivdbg("sdev=%p mode=%d nbits=%d\n", sdv, mode, nbits); + + DEBUGASSERT(priv != NULL && priv->sdev == NULL && sdev != NULL); + + /* Get exclusive access to the SPI device */ + + spi_semtake(priv); + + /* Bind the SPI slave device interface instance to the SPI slave + * controller interface. + */ + + priv->sdev = sdev; + + /* Call the slaved device's select() and cmddata() methods to indicate + * the initial state of the chip select and command/data discretes. + * + * NOTE: Unless we reconfigure the NSS GPIO pin, it may not be possible + * to read the NSS pin value (I haven't actually tried just reading it). + * And, since the is no interrupt on the falling edge of NSS, we get no + * notification when we are selected... not until the arrival of data. + * + * REVISIT: A board-level interface would be required in order to support + * the Command/Data indication (not yet impklemented). + */ + + SPI_SDEV_SELECT(sdev, false); +#warning Missing logic + SPI_SDEV_CMDDATA(sdev, false); + + /* Discard any queued data */ + + priv->head = 0; + priv->tail = 0; + + /* Call the slave device's getdata() method to get the value that will + * be shifted out the SPI clock is detected. + */ + + priv->outval = SPI_SDEV_GETDATA(sdev); + spi_putreg(priv, priv->outval, SAM_SPI_TDR_OFFSET); + + /* Setup to begin normal SPI operation */ + + spi_setmode(priv, mode); + spi_setbits(priv, nbits); + + /* Clear pending interrupts by reading the SPI Status Register */ + + regval = spi_getreg(priv, SAM_SPI_SR_OFFSET); + UNUSED(regval); + + /* Enable SPI interrupts (already enabled at the NVIC): + * + * Data Transfer: + * SPI_INT_RDRF - Receive Data Register Full Interrupt + * SPI_INT_TDRE - Transmit Data Register Empty Interrupt + * SPI_INT_NSSR - NSS Rising Interrupt + * + * Transfer Errors (for DEBUG purposes only): + * SPI_INT_OVRES - Overrun Error Interrupt + * SPI_INT_UNDES - Underrun Error Status Interrupt (slave) + * + * Not Used: + * SPI_INT_MODF - Mode Fault Error Interrupt + * SPI_INT_TXEMPTY - Transmission Registers Empty Interrupt + * + * TX interrupts (SPI_INT_TDRE and SPI_INT_UNDES) are not enabled until + * the transfer of data actually starts. + */ + + regval = (SPI_INT_RDRF | SPI_INT_NSSR); +#ifdef CONFIG_DEBUG_SPI + regval |= SPI_INT_OVRES; +#endif + + spi_putreg(priv, regval, SAM_SPI_IER_OFFSET); + + spi_semgive(priv); +} + +/**************************************************************************** + * Name: spi_unbind + * + * Description: + * Un-bind the SPI slave device interface from the SPI slave controller + * interface. Reset the SPI interface and restore the SPI slave + * controller driver to its initial state, + * + * Input Parameters: + * sctrlr - SPI slave controller interface instance + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_unbind(struct spi_sctrlr_s *sctrlr) +{ + struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr; + + DEBUGASSERT(priv != NULL); + spivdbg("Unbinding %p\n", priv->sdev); + + DEBUGASSERT(priv->sdev != NULL); + + /* Get exclusive access to the SPI device */ + + spi_semtake(priv); + + /* Disable SPI interrupts (still enabled at the NVIC) */ + + spi_putreg(priv, SPI_INT_ALL, SAM_SPI_IDR_OFFSET); + + /* Unbind the SPI slave interface */ + + priv->sdev = NULL; + + /* Disable the SPI peripheral */ + + spi_putreg(priv, SPI_CR_SPIDIS, SAM_SPI_CR_OFFSET); + + /* Execute a software reset of the SPI (twice) */ + + spi_putreg(priv, SPI_CR_SWRST, SAM_SPI_CR_OFFSET); + spi_putreg(priv, SPI_CR_SWRST, SAM_SPI_CR_OFFSET); + + spi_semgive(priv); +} + +/**************************************************************************** + * Name: spi_enqueue + * + * Description: + * Enqueue the next value to be shifted out from the interface. This adds + * the word the controller driver for a subsequent transfer but has no + * effect on anyin-process or currently "committed" transfers + * + * Input Parameters: + * sctrlr - SPI slave controller interface instance + * data - Command/data mode data value to be shifted out. The width of + * the data must be the same as the nbits parameter previously + * provided to the bind() methods. + * + * Returned Value: + * Zero if the word was successfully queue; A negated errno valid is + * returned on any failure to enqueue the word (such as if the queue is + * full). + * + ****************************************************************************/ + +static int spi_enqueue(struct spi_sctrlr_s *sctrlr, uint16_t data) +{ + struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr; + irqstate_t flags; + uint32_t regval; + int next; + int ret; + + spivdbg("data=%04x\n", data); + DEBUGASSERT(priv != NULL && priv->sdev != NULL); + + /* Get exclusive access to the SPI device */ + + spi_semtake(priv); + + /* Check if this word would overflow the circular buffer + * + * Interrupts are disabled briefly. + */ + + flags = irqsave(); + next = priv->head + 1; + if (next >= CONFIG_SAMV7_SPI_SLAVE_QSIZE) + { + next = 0; + } + + if (next == priv->tail) + { + ret = -ENOSPC; + } + else + { + /* Save this new word as the next word to shifted out. The current + * word written to the TX data registers is "committed" and will not + * be overwritten. + */ + + priv->outq[priv->head] = data; + priv->head = next; + ret = OK; + + /* Enable TX interrupts if we have begun the transfer */ + + if (!priv->nss) + { + /* Enable TXDR/OVRE interrupts */ + + regval = (SPI_INT_TDRE | SPI_INT_UNDES); + spi_putreg(priv, regval, SAM_SPI_IER_OFFSET); + } + } + + irqrestore(flags); + spi_semgive(priv); + return ret; +} + +/**************************************************************************** + * Name: spi_qfull + * + * Description: + * Return true if the queue is full or false if there is space to add an + * additional word to the queue. + * + * Input Parameters: + * sctrlr - SPI slave controller interface instance + * + * Returned Value: + * true if the output wueue is full + * + ****************************************************************************/ + +static bool spi_qfull(struct spi_sctrlr_s *sctrlr) +{ + struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr; + irqstate_t flags; + int next; + bool ret; + + DEBUGASSERT(priv != NULL && priv->sdev != NULL); + + /* Get exclusive access to the SPI device */ + + spi_semtake(priv); + + /* Check if another word would overflow the circular buffer + * + * Interrupts are disabled briefly. + */ + + flags = irqsave(); + next = priv->head + 1; + if (next >= CONFIG_SAMV7_SPI_SLAVE_QSIZE) + { + next = 0; + } + + ret = (next == priv->tail); + irqrestore(flags); + spi_semgive(priv); + return ret; +} + +/**************************************************************************** + * Name: spi_qflush + * + * Description: + * Discard all saved values in the output queue. On return from this + * function the output queue will be empty. Any in-progress or otherwise + * "committed" output values may not be flushed. + * + * Input Parameters: + * sctrlr - SPI slave controller interface instance + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_qflush(struct spi_sctrlr_s *sctrlr) +{ + struct sam_spidev_s *priv = (struct sam_spidev_s *)sctrlr; + irqstate_t flags; + + spivdbg("data=%04x\n", data); + + DEBUGASSERT(priv != NULL && priv->sdev != NULL); + + /* Get exclusive access to the SPI device */ + + spi_semtake(priv); + + /* Mark the buffer empty, momentarily disabling interrupts */ + + flags = irqsave(); + priv->head = 0; + priv->tail = 0; + irqrestore(flags); + spi_semgive(priv); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_spi_slave_initialize + * + * Description: + * Initialize the selected SPI port in slave mode. + * + * Input Parameter: + * port - Chip select number identifying the "logical" SPI port. Includes + * encoded port and chip select information. + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct spi_sctrlr_s *sam_spi_slave_initialize(int port) +{ + struct sam_spidev_s *priv; + int spino = (port & __SPI_SPI_MASK) >> __SPI_SPI_SHIFT; + irqstate_t flags; + uint32_t regval; + + /* The support SAM parts have only a single SPI port */ + + spivdbg("port: %d spino: %d\n", port, spino); + +#if defined(CONFIG_SAMV7_SPI0_SLAVE) && defined(CONFIG_SAMV7_SPI1_SLAVE) + DEBUGASSERT(spino >= 0 && spino <= 1); +#elif defined(CONFIG_SAMV7_SPI0_SLAVE) + DEBUGASSERT(spino == 0); +#else + DEBUGASSERT(spino == 1); +#endif + + /* Allocate a new state structure for this chip select. NOTE that there + * is no protection if the same chip select is used in two different + * chip select structures. + */ + + priv = (struct sam_spidev_s *)zalloc(sizeof(struct sam_spidev_s)); + if (!priv) + { + spidbg("ERROR: Failed to allocate a chip select structure\n"); + return NULL; + } + + /* Set up the initial state for this chip select structure. Other fields + * were zeroed by zalloc(). + */ + + /* Initialize the SPI operations */ + + priv->sctrlr.ops = &g_sctrlr_ops; + + /* Save the SPI controller number */ + + priv->spino = spino; + + /* Has the SPI hardware been initialized? */ + + if (!priv->initialized) + { + /* Enable clocking to the SPI block */ + + flags = irqsave(); +#if defined(CONFIG_SAMV7_SPI0_SLAVE) && defined(CONFIG_SAMV7_SPI1_SLAVE) + if (spino == 0) +#endif +#if defined(CONFIG_SAMV7_SPI0_SLAVE) + { + /* Set the SPI0 register base address and interrupt information */ + + priv->base = SAM_SPI0_BASE, + priv->irq = SAM_IRQ_SPI0; + priv->handler = spi0_interrupt; + + /* Enable peripheral clocking to SPI0 */ + + sam_spi0_enableclk(); + + /* Configure multiplexed pins as connected on the board. */ + + sam_configgpio(GPIO_SPI0_MISO); /* Output */ + sam_configgpio(GPIO_SPI0_MOSI); /* Input */ + sam_configgpio(GPIO_SPI0_SPCK); /* Drives slave */ + sam_configgpio(GPIO_SPI0_NSS); /* aka NPCS0 */ + } +#endif +#if defined(CONFIG_SAMV7_SPI0_SLAVE) && defined(CONFIG_SAMV7_SPI1_SLAVE) + else +#endif +#if defined(CONFIG_SAMV7_SPI1_SLAVE) + { + /* Set the SPI1 register base address and interrupt information */ + + priv->base = SAM_SPI1_BASE, + priv->irq = SAM_IRQ_SPI1; + priv->handler = spi1_interrupt; + + /* Enable peripheral clocking to SPI1 */ + + sam_spi1_enableclk(); + + /* Configure multiplexed pins as connected on the board. */ + + sam_configgpio(GPIO_SPI1_MISO); /* Output */ + sam_configgpio(GPIO_SPI1_MOSI); /* Input */ + sam_configgpio(GPIO_SPI1_SPCK); /* Drives slave */ + sam_configgpio(GPIO_SPI0_NSS); /* aka NPCS0 */ + } +#endif + + /* Disable the SPI peripheral */ + + spi_putreg(priv, SPI_CR_SPIDIS, SAM_SPI_CR_OFFSET); + + /* Execute a software reset of the SPI (twice) */ + + spi_putreg(priv, SPI_CR_SWRST, SAM_SPI_CR_OFFSET); + spi_putreg(priv, SPI_CR_SWRST, SAM_SPI_CR_OFFSET); + irqrestore(flags); + + /* Configure the SPI mode register */ + + spi_putreg(priv, SPI_MR_SLAVE | SPI_MR_MODFDIS, SAM_SPI_MR_OFFSET); + + /* And enable the SPI */ + + spi_putreg(priv, SPI_CR_SPIEN, SAM_SPI_CR_OFFSET); + up_mdelay(20); + + /* Flush any pending interrupts/transfers */ + + (void)spi_getreg(priv, SAM_SPI_SR_OFFSET); + (void)spi_getreg(priv, SAM_SPI_RDR_OFFSET); + + /* Initialize the SPI semaphore that enforces mutually exclusive + * access to the SPI registers. + */ + + sem_init(&priv->spisem, 0, 1); + priv->nss = true; + priv->initialized = true; + + /* Disable all SPI interrupts at the SPI peripheral */ + + spi_putreg(priv, SPI_INT_ALL, SAM_SPI_IDR_OFFSET); + + /* Attach and enable interrupts at the NVIC */ + + DEBUGVERIFY(irq_attach(priv->irq, priv->handler)); + up_enable_irq(priv->irq); + + spi_dumpregs(priv, "After initialization"); + } + + /* Set to mode=0 and nbits=8 */ + + regval = spi_getreg(priv, SAM_SPI_CSR0_OFFSET); + regval &= ~(SPI_CSR_CPOL | SPI_CSR_NCPHA | SPI_CSR_BITS_MASK); + regval |= (SPI_CSR_NCPHA | SPI_CSR_BITS(8)); + spi_putreg(priv, regval, SAM_SPI_CSR0_OFFSET); + + priv->nbits = 8; + spivdbg("csr[offset=%02x]=%08x\n", offset, regval); + + return &priv->sctrlr; +} +#endif /* CONFIG_SAMV7_SPI_SLAVE */ diff --git a/arch/arm/src/samv7/sam_usbdevhs.c b/arch/arm/src/samv7/sam_usbdevhs.c index e6c20e11ea5..d912c400e29 100644 --- a/arch/arm/src/samv7/sam_usbdevhs.c +++ b/arch/arm/src/samv7/sam_usbdevhs.c @@ -72,8 +72,10 @@ #include "up_internal.h" #include "cache.h" +#include "chip.h" #include "sam_periphclks.h" #include "chip/sam_usbhs.h" +#include "sam_clockconfig.h" #include "sam_usbdev.h" #if defined(CONFIG_USBDEV) && defined(CONFIG_SAMV7_USBDEVHS) @@ -105,7 +107,6 @@ /* Not yet supported */ #undef CONFIG_SAMV7_USBDEVHS_SCATTERGATHER -#undef CONFIG_SAMV7_USBDEVHS_LOWPOWER /* Driver Definitions *******************************************************/ /* Initial interrupt mask: Reset + Suspend + Correct Transfer */ @@ -146,6 +147,36 @@ #define sam_rqempty(q) ((q)->head == NULL) #define sam_rqpeek(q) ((q)->head) +/* Buffer Alignment ********************************************************* + * + * DMA buffers be aligned the 8-byte (2 word boundaries). However, if the + * data cache is enabled the a higher level of alignment is required. That + * is because the data will need to be invalidated and that cache + * invalidation will occur in multiples of full cache lines. + */ + +#ifdef CONFIG_ARMV7M_DCACHE +/* Align to the cache line size which we assume is >= 8 */ + +# define USBHS_ALIGN ARMV7M_DCACHE_LINESIZE +# define USBHS_ALIGN_MASK (USBHS_ALIGN-1) +# define USBHS_ALIGN_DOWN(n) ((n) & ~USBHS_ALIGN_MASK) +# define USBHS_ALIGN_UP(n) (((n) + USBHS_ALIGN_MASK) & ~USBHS_ALIGN_MASK) + +# ifndef CONFIG_ARMV7M_DCACHE_WRITETHROUGH +# warning !!! This driver will not work without CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y!!! +# endif + +#else +/* Use the minimum alignment requirement */ + +# define USBHS_ALIGN 8 +# define USBHS_ALIGN_MASK 7 +# define USBHS_ALIGN_DOWN(n) ((n) & ~7) +# define USBHS_ALIGN_UP(n) (((n) + 7) & ~7) + +#endif + /* USB trace ****************************************************************/ /* Trace error codes */ @@ -174,11 +205,10 @@ #define SAM_TRACEERR_EPRESERVE 0x0017 #define SAM_TRACEERR_NCFGOK 0x0018 #define SAM_TRACEERR_INVALIDCTRLREQ 0x0019 -#define SAM_TRACEERR_INVALIDPARMS 0x001a -#define SAM_TRACEERR_IRQREGISTRATION 0x001b -#define SAM_TRACEERR_NOTCONFIGURED 0x001c -#define SAM_TRACEERR_REQABORTED 0x001d -#define SAM_TRACEERR_TXINERR 0x001e +#define SAM_TRACEERR_IRQREGISTRATION 0x001a +#define SAM_TRACEERR_NOTCONFIGURED 0x001b +#define SAM_TRACEERR_REQABORTED 0x001c +#define SAM_TRACEERR_TXINERR 0x001d /* Trace interrupt codes */ @@ -191,32 +221,35 @@ #define SAM_TRACEINTID_DMAEOB 0x0007 #define SAM_TRACEINTID_DMAEOC 0x0008 #define SAM_TRACEINTID_ENDRESET 0x0009 -#define SAM_TRACEINTID_EP 0x0001 +#define SAM_TRACEINTID_EP 0x000a #define SAM_TRACEINTID_EP0SETUPIN 0x000b #define SAM_TRACEINTID_EP0SETUPOUT 0x000c #define SAM_TRACEINTID_EP0SETUPSETADDRESS 0x000d -#define SAM_TRACEINTID_EPGETSTATUS 0x000e -#define SAM_TRACEINTID_EPINQEMPTY 0x000f -#define SAM_TRACEINTID_EPOUTQEMPTY 0x0010 -#define SAM_TRACEINTID_GETCONFIG 0x0011 -#define SAM_TRACEINTID_GETSETDESC 0x0012 -#define SAM_TRACEINTID_GETSETIF 0x0013 -#define SAM_TRACEINTID_GETSTATUS 0x0014 -#define SAM_TRACEINTID_IFGETSTATUS 0x0015 -#define SAM_TRACEINTID_INTERRUPT 0x0016 -#define SAM_TRACEINTID_INTSOF 0x0017 -#define SAM_TRACEINTID_INTMSOF 0x0018 -#define SAM_TRACEINTID_NOSTDREQ 0x0019 -#define SAM_TRACEINTID_PENDING 0x001a -#define SAM_TRACEINTID_RXRDY 0x001b -#define SAM_TRACEINTID_RXSETUP 0x001c -#define SAM_TRACEINTID_SETCONFIG 0x001d -#define SAM_TRACEINTID_SETFEATURE 0x001e -#define SAM_TRACEINTID_STALLSNT 0x001f -#define SAM_TRACEINTID_SYNCHFRAME 0x0020 -#define SAM_TRACEINTID_TXINI 0x0021 -#define SAM_TRACEINTID_UPSTRRES 0x0022 -#define SAM_TRACEINTID_WAKEUP 0x0023 +#define SAM_TRACEINTID_EPDMAINT 0x000e +#define SAM_TRACEINTID_EPGETSTATUS 0x000f +#define SAM_TRACEINTID_EPINQEMPTY 0x0010 +#define SAM_TRACEINTID_EPINT 0x0011 +#define SAM_TRACEINTID_EPOUTQEMPTY 0x0012 +#define SAM_TRACEINTID_GETCONFIG 0x0013 +#define SAM_TRACEINTID_GETSETDESC 0x0014 +#define SAM_TRACEINTID_GETSETIF 0x0015 +#define SAM_TRACEINTID_GETSTATUS 0x0016 +#define SAM_TRACEINTID_IFGETSTATUS 0x0017 +#define SAM_TRACEINTID_INTERRUPT 0x0018 +#define SAM_TRACEINTID_INTSOF 0x0019 +#define SAM_TRACEINTID_INTMSOF 0x001a +#define SAM_TRACEINTID_NOSTDREQ 0x001b +#define SAM_TRACEINTID_PENDING 0x001c +#define SAM_TRACEINTID_RXRDY 0x001d +#define SAM_TRACEINTID_RXSETUP 0x001e +#define SAM_TRACEINTID_SETCONFIG 0x001f +#define SAM_TRACEINTID_SETFEATURE 0x0020 +#define SAM_TRACEINTID_SPEED 0x0021 +#define SAM_TRACEINTID_STALLSNT 0x0022 +#define SAM_TRACEINTID_SYNCHFRAME 0x0023 +#define SAM_TRACEINTID_TXINI 0x0024 +#define SAM_TRACEINTID_UPSTRRES 0x0025 +#define SAM_TRACEINTID_WAKEUP 0x0026 /* Ever-present MIN and MAX macros */ @@ -364,7 +397,6 @@ struct sam_usbdev_s struct usb_ctrlreq_s ctrl; /* Last EP0 request */ uint8_t devstate; /* State of the device (see enum sam_devstate_e) */ uint8_t prevstate; /* Previous state of the device before SUSPEND */ - uint8_t devaddr; /* Assigned device address */ uint8_t selfpowered:1; /* 1: Device is self powered */ uint16_t epavail; /* Bitset of available endpoints */ @@ -438,7 +470,7 @@ static inline void sam_req_abort(struct sam_ep_s *privep, struct sam_req_s *privreq, int16_t result); static void sam_req_complete(struct sam_ep_s *privep, int16_t result); -static void sam_ep_fifcon(unsigned int epno); +static void sam_ep_fifocon(unsigned int epno); static void sam_req_wrsetup(struct sam_usbdev_s *priv, struct sam_ep_s *privep, struct sam_req_s *privreq); static int sam_req_write(struct sam_usbdev_s *priv, @@ -455,9 +487,11 @@ static void sam_req_cancel(struct sam_ep_s *privep, int16_t status); /* Interrupt level processing ***********************************************/ static void sam_ep0_read(uint8_t *buffer, size_t buflen); -static void sam_ep0_wrstatus(const uint8_t *buffer, size_t buflen); +static void sam_ctrlep_write(struct sam_ep_s *privep, const uint8_t *buffer, + size_t buflen); +static void sam_ep_write(struct sam_ep_s *privep, const uint8_t *buffer, + size_t buflen); static void sam_ep0_dispatch(struct sam_usbdev_s *priv); -static void sam_setdevaddr(struct sam_usbdev_s *priv, uint8_t value); static void sam_ep0_setup(struct sam_usbdev_s *priv); #ifdef CONFIG_USBDEV_DMA static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno); @@ -568,14 +602,14 @@ static const struct usb_epdesc_s g_ep0desc = #ifdef CONFIG_SAMV7_USBDEVHS_SCATTERGATHER #ifdef CONFIG_SAMV7_USBDEVHS_PREALLOCATE -/* This is a properly aligned pool of preallocated DMA transfer desciptors */ +/* This is a properly aligned pool of preallocated DMA transfer descriptors */ static struct sam_dtd_s g_dtdpool[CONFIG_SAMV7_USBDEVHS_NDTDS] __attribute__ ((aligned(16))); #endif #endif -/* Device error strings that may be enabled for more desciptive USB trace +/* Device error strings that may be enabled for more descriptive USB trace * output. */ @@ -607,7 +641,6 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] = TRACE_STR(SAM_TRACEERR_EPRESERVE), TRACE_STR(SAM_TRACEERR_NCFGOK), TRACE_STR(SAM_TRACEERR_INVALIDCTRLREQ), - TRACE_STR(SAM_TRACEERR_INVALIDPARMS), TRACE_STR(SAM_TRACEERR_IRQREGISTRATION), TRACE_STR(SAM_TRACEERR_NOTCONFIGURED), TRACE_STR(SAM_TRACEERR_REQABORTED), @@ -616,7 +649,7 @@ const struct trace_msg_t g_usb_trace_strings_deverror[] = }; #endif -/* Interrupt event strings that may be enabled for more desciptive USB trace +/* Interrupt event strings that may be enabled for more descriptive USB trace * output. */ @@ -636,8 +669,10 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] = TRACE_STR(SAM_TRACEINTID_EP0SETUPIN), TRACE_STR(SAM_TRACEINTID_EP0SETUPOUT), TRACE_STR(SAM_TRACEINTID_EP0SETUPSETADDRESS), + TRACE_STR(SAM_TRACEINTID_EPDMAINT), TRACE_STR(SAM_TRACEINTID_EPGETSTATUS), TRACE_STR(SAM_TRACEINTID_EPINQEMPTY), + TRACE_STR(SAM_TRACEINTID_EPINT), TRACE_STR(SAM_TRACEINTID_EPOUTQEMPTY), TRACE_STR(SAM_TRACEINTID_GETCONFIG), TRACE_STR(SAM_TRACEINTID_GETSETDESC), @@ -653,6 +688,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] = TRACE_STR(SAM_TRACEINTID_RXSETUP), TRACE_STR(SAM_TRACEINTID_SETCONFIG), TRACE_STR(SAM_TRACEINTID_SETFEATURE), + TRACE_STR(SAM_TRACEINTID_SPEED), TRACE_STR(SAM_TRACEINTID_STALLSNT), TRACE_STR(SAM_TRACEINTID_SYNCHFRAME), TRACE_STR(SAM_TRACEINTID_TXINI), @@ -817,7 +853,7 @@ static void sam_dumpep(struct sam_usbdev_s *priv, int epno) lldbg("Global Register:\n"); lldbg(" CTRL: %08x\n", sam_getreg(SAM_USBHS_DEVCTRL)); - lldbg(" IISR: %08x\n", sam_getreg(SAM_USBHS_DEVISR)); + lldbg(" ISR: %08x\n", sam_getreg(SAM_USBHS_DEVISR)); lldbg(" IMR: %08x\n", sam_getreg(SAM_USBHS_DEVIMR)); lldbg(" EPT: %08x\n", sam_getreg(SAM_USBHS_DEVEPT)); lldbg(" FNUM: %08x\n", sam_getreg(SAM_USBHS_DEVFNUM)); @@ -1164,7 +1200,7 @@ static void sam_req_complete(struct sam_ep_s *privep, int16_t result) } /**************************************************************************** - * Name: sam_ep_fifcon + * Name: sam_ep_fifocon * * Description: * IN data has been loaded in the endpoint FIFO. Manage the endpoint to @@ -1173,7 +1209,7 @@ static void sam_req_complete(struct sam_ep_s *privep, int16_t result) * ****************************************************************************/ -static void sam_ep_fifcon(unsigned int epno) +static void sam_ep_fifocon(unsigned int epno) { /* Clear FIFOCON to indicate that the packet is ready to send (this works * even for zero length packets). We will get an TXIN interrupt with @@ -1207,21 +1243,16 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, struct sam_ep_s *privep, struct sam_req_s *privreq) { + uint32_t regval; const uint8_t *buf; - uint8_t *fifo; uint8_t epno; + unsigned int eptype; int nbytes; /* Get the unadorned endpoint number */ epno = USB_EPNO(privep->ep.eplog); - /* Write access to the FIFO is not possible if FIFOCON is clear (meaning - * that a write is already in progress. - */ - - DEBUGASSERT((sam_getreg(SAM_USBHS_DEVEPTISR(epno)) & USBHS_DEVEPTINT_FIFOCONI) != 0); - /* Get the number of bytes remaining to be sent. */ DEBUGASSERT(privreq->req.xfrd < privreq->req.len); @@ -1242,35 +1273,25 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, usbtrace(TRACE_WRITE(USB_EPNO(privep->ep.eplog)), nbytes); /* The new buffer pointer is the started of the buffer plus the number - * of bytes successfully transfered plus the number of bytes previously + * of bytes successfully transferred plus the number of bytes previously * "in-flight". */ buf = privreq->req.buf + privreq->req.xfrd; - /* Write packet in the FIFO buffer */ + /* How we send packets differs for control endpoints */ - fifo = (uint8_t *) - ((uint32_t *)SAM_USBHSRAM_BASE + (EPT_FIFO_SIZE * epno)); + regval = sam_getreg(SAM_USBHS_DEVEPTCFG(epno)); + eptype = regval & USBHS_DEVEPTCFG_EPTYPE_MASK; - for (; nbytes; nbytes--) + if (eptype == USBHS_DEVEPTCFG_EPTYPE_CTRL) { - *fifo++ = *buf++; + sam_ctrlep_write(privep, buf, nbytes); + } + else + { + sam_ep_write(privep, buf, nbytes); } - - MEMORY_SYNC(); - - /* Indicate that there is data in the TX packet memory. This will - * be cleared when the next data out interrupt is received. - */ - - privep->epstate = USBHS_EPSTATE_SENDING; - - /* Initiate the transfer and configure to receive the transfer complete - * interrupt. - */ - - sam_ep_fifcon(epno); } /**************************************************************************** @@ -1290,7 +1311,7 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv, * When a request is queued, the request 'len' is the number of bytes * to transfer and 'xfrd' and 'inflight' must be zero. * - * When this function starts a tranfer it will update the request + * When this function starts a transfer it will update the request * 'inflight' field to indicate the size of the transfer. * * When the transfer completes, the the 'inflight' field must hold the @@ -1410,8 +1431,8 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) /* If we get here, then we sent the last of the data on the * previous pass and we need to send the zero length packet now. * - * A Zero Length Packet can be sent by clearing just the FIFOCON flag - * in the USBHS_DEVTEPTIDRx register + * A Zero Length Packet can be sent by clearing just the FIFOCON + * flag in the USBHS_DEVTEPTIDRx register */ privep->epstate = USBHS_EPSTATE_SENDING; @@ -1423,7 +1444,7 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep) * transfer complete interrupt. */ - sam_ep_fifcon(epno); + sam_ep_fifocon(epno); } /* If all of the bytes were sent (including any final zero length @@ -1547,7 +1568,7 @@ static void sam_req_rddisable(uint8_t epno) * - When receiving data via DMA, then data has already been transferred * and this function is called on the terminating event. The transfer * is complete and we just need to check for end of request events and - * if we need to setup the tranfer for the next request. + * if we need to setup the transfer for the next request. * - When receiving via the FIFO, the transfer is not complete. The * data is in the FIFO and must be transferred from the FIFO to the * request buffer. No setup is needed for the next transfer other than @@ -1647,10 +1668,17 @@ static int sam_req_read(struct sam_usbdev_s *priv, struct sam_ep_s *privep, if ((SAM_EPSET_DMA & SAM_EP_BIT(epno)) != 0) { - /* Set up the next DMA */ + /* Set up the next DMA. We will come through this logic path + * again with xrfd != 0 when the DMA completes. + */ sam_dma_rdsetup(priv, privep, privreq); } + + /* No DMA for this endpoint and we have an available, empty read + * request. We need to wait for data to become avaialable. + */ + else { /* Enable endpoint RXRDY_TXTK interrupts */ @@ -1700,6 +1728,7 @@ static int sam_req_read(struct sam_usbdev_s *priv, struct sam_ep_s *privep, static void sam_req_cancel(struct sam_ep_s *privep, int16_t result) { + uint32_t regval; uint8_t epno; /* Disable endpoint interrupts if not endpoint 0 */ @@ -1707,7 +1736,8 @@ static void sam_req_cancel(struct sam_ep_s *privep, int16_t result) epno = USB_EPNO(privep->ep.eplog); if (epno != 0) { - sam_putreg(USBHS_DEVINT_DMA(epno), SAM_USBHS_DEVIDR); + regval = USBHS_DEVINT_DMA(epno) | USBHS_DEVINT_PEP(epno); + sam_putreg(regval, SAM_USBHS_DEVIDR); } /* Then complete every queued request with the specified status */ @@ -1747,21 +1777,28 @@ static void sam_ep0_read(uint8_t *buffer, size_t buflen) } /**************************************************************************** - * Name: sam_ep0_wrstatus + * Name: sam_ctrlep_write * * Description: - * Process the next queued write request for an endpoint that does not - * support DMA. + * Process the next queued write request for a control endpoint. * ****************************************************************************/ -static void sam_ep0_wrstatus(const uint8_t *buffer, size_t buflen) +static void sam_ctrlep_write(struct sam_ep_s *privep, const uint8_t *buffer, + size_t buflen) { volatile uint8_t *fifo; + unsigned int epno; + + /* Get the endpoint number */ + + epno = USB_EPNO(privep->ep.eplog); /* Write packet in the FIFO buffer */ - fifo = (volatile uint8_t *)SAM_USBHSRAM_BASE; + fifo = (uint8_t *) + ((uint32_t *)SAM_USBHSRAM_BASE + (EPT_FIFO_SIZE * epno)); + for (; buflen > 0; buflen--) { *fifo++ = *buffer++; @@ -1769,11 +1806,78 @@ static void sam_ep0_wrstatus(const uint8_t *buffer, size_t buflen) MEMORY_SYNC(); + /* Indicate that there is data in the TX packet memory. This will + * be cleared when the next NAKIN interrupt is received. + */ + + privep->epstate = USBHS_EPSTATE_SENDING; + + /* The FIFO Control (USBHS_DEVEPTIMRx.FIFOCON) bit and the Read/Write + * Allowed (USBHS_DEVEPTISRx.RWALL) bit are irrelevant for control + * endpoints. The user never uses them on these endpoints. + */ + + /* USBHS_DEVEPTISRx.TXINI is cleared by software (by writing a one to + * the Transmitted IN Data Interrupt Clear bit (USBHS_DEVEPTIDRx.TXINIC) + * to acknowledge the interrupt, which has no effect on the endpoint + * FIFO. This acknowledges the interrupt and sends the packet. + */ + + sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIDR(epno)); + + /* Clear the NAKIN bit to stop NAKing IN tokens from the host. We now + * have data ready to go. + */ + + sam_putreg((USBHS_DEVEPTINT_NAKINI | USBHS_DEVEPTINT_TXINI), + SAM_USBHS_DEVEPTICR(epno)); + + /* Enable the TXIN interrupt on the endpoint */ + + sam_putreg(USBHS_DEVEPTINT_TXINI, SAM_USBHS_DEVEPTIER(epno)); +} + +/**************************************************************************** + * Name: sam_ep_write + * + * Description: + * Process the next queued write request for a control endpoint. + * + ****************************************************************************/ + +static void sam_ep_write(struct sam_ep_s *privep, const uint8_t *buffer, + size_t buflen) +{ + volatile uint8_t *fifo; + unsigned int epno; + + /* Get the endpoint number */ + + epno = USB_EPNO(privep->ep.eplog); + + /* Write packet in the FIFO buffer */ + + fifo = (uint8_t *) + ((uint32_t *)SAM_USBHSRAM_BASE + (EPT_FIFO_SIZE * epno)); + + for (; buflen; buflen--) + { + *fifo++ = *buffer++; + } + + MEMORY_SYNC(); + + /* Indicate that there is data in the TX packet memory. This will + * be cleared when the next data out interrupt is received. + */ + + privep->epstate = USBHS_EPSTATE_SENDING; + /* Initiate the transfer and configure to receive the transfer complete * interrupt. */ - sam_ep_fifcon(EP0); + sam_ep_fifocon(epno); } /**************************************************************************** @@ -1820,41 +1924,6 @@ static void sam_ep0_dispatch(struct sam_usbdev_s *priv) } } -/**************************************************************************** - * Name: sam_setdevaddr - ****************************************************************************/ - -static void sam_setdevaddr(struct sam_usbdev_s *priv, uint8_t address) -{ - uint32_t regval; - - if (address) - { - /* Enable the address */ - - regval = sam_getreg(SAM_USBHS_DEVCTRL); - regval &= ~USBHS_DEVCTRL_UADD_MASK; - regval |= USBHS_DEVCTRL_UADD(address) | USBHS_DEVCTRL_ADDEN; - sam_putreg(regval, SAM_USBHS_DEVCTRL); - - /* Go to the addressed state */ - - priv->devstate = USBHS_DEVSTATE_ADDRESSED; - } - else - { - /* Disable address */ - - regval = sam_getreg(SAM_USBHS_DEVCTRL); - regval &= ~USBHS_DEVCTRL_ADDEN; - sam_putreg(regval, SAM_USBHS_DEVCTRL); - - /* Revert to the un-addressed, default state */ - - priv->devstate = USBHS_DEVSTATE_DEFAULT; - } -} - /**************************************************************************** * Name: sam_ep0_setup ****************************************************************************/ @@ -1868,6 +1937,7 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv) union wb_u len; union wb_u response; enum sam_ep0setup_e ep0result; + uint32_t regval; uint8_t epno; int nbytes = 0; /* Assume zero-length packet */ int ret; @@ -2108,8 +2178,21 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv) */ usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP0SETUPSETADDRESS), value.w); - priv->devaddr = value.w; - ep0result = USBHS_EP0SETUP_ADDRESS; + + /* Write this address to the USB Address (USBHS_DEVCTRL.UADD) field + * but do not yet enable (USBHS_DEVCTRL.ADDEN) so the actual address is + * still 0. + * + * USBHS_DEVCTRL.UADD and USBHS_DEVCTRL.ADDEN must not be written all + * at once. + */ + + regval = sam_getreg(SAM_USBHS_DEVCTRL); + regval &= ~(USBHS_DEVCTRL_UADD_MASK | USBHS_DEVCTRL_ADDEN); + regval |= USBHS_DEVCTRL_UADD(value.w); + sam_putreg(regval, SAM_USBHS_DEVCTRL); + + ep0result = USBHS_EP0SETUP_ADDRESS; } } break; @@ -2181,12 +2264,12 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv) if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE && index.w == 0 && len.w == 0) { - /* The request seems valid... let the class implementation handle it. - * If the class implementation accespts it new configuration, it will - * call sam_ep_configure() to configure the endpoints. - */ + /* The request seems valid... let the class implementation handle it. + * If the class implementation accespts it new configuration, it will + * call sam_ep_configure() to configure the endpoints. + */ - sam_ep0_dispatch(priv); + sam_ep0_dispatch(priv); ep0result = USBHS_EP0SETUP_DISPATCHED; } else @@ -2284,8 +2367,8 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv) { /* Send the response (might be a zero-length packet) */ + sam_ctrlep_write(ep0, response.b, nbytes); ep0->epstate = USBHS_EPSTATE_EP0STATUSIN; - sam_ep0_wrstatus(response.b, nbytes); } break; @@ -2293,8 +2376,8 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv) { /* Send the response (might be a zero-length packet) */ + sam_ctrlep_write(ep0, response.b, nbytes); ep0->epstate = USBHS_EPSTATE_EP0ADDRESS; - sam_ep0_wrstatus(response.b, nbytes); } break; @@ -2359,7 +2442,7 @@ static void sam_dma_interrupt(struct sam_usbdev_s *priv, int epno) /* Get the result of the DMA operation */ dmastatus = sam_getreg(SAM_USBHS_DEVDMASTA(epno)); - uvdbg("DMA%d DMASTATUS: %08x\n", epno, dmastatus); + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EPDMAINT), dmastatus); /* Disable DMA interrupt to avoid receiving 2 (B_EN and TR_EN) */ @@ -2530,6 +2613,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno) /* Get the endpoint status */ eptisr = sam_getreg(SAM_USBHS_DEVEPTISR(epno)); + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EPINT), eptisr); /* Get the endpoint type */ @@ -2538,7 +2622,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno) /* IN packet sent */ - if ((eptisr & USBHS_DEVEPTINT_TXINI) == 0 && + if ((eptisr & USBHS_DEVEPTINT_TXINI) != 0 && (sam_getreg(SAM_USBHS_DEVEPTIMR(epno)) & USBHS_DEVEPTINT_TXINI) != 0) { usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_TXINI), (uint16_t)eptisr); @@ -2567,13 +2651,24 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno) else if (privep->epstate == USBHS_EPSTATE_EP0ADDRESS) { - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ADDRESSED), priv->devaddr); DEBUGASSERT(epno == EP0); - /* Set the device address */ + /* Enable the address previously set in the SETUP processing. + * USBHS_DEVCTRL.UADD and USBHS_DEVCTRL.ADDEN must not be written + * all at once. + */ + regval = sam_getreg(SAM_USBHS_DEVCTRL); + regval |= USBHS_DEVCTRL_ADDEN; + sam_putreg(regval, SAM_USBHS_DEVCTRL); + + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ADDRESSED), + (regval & USBHS_DEVCTRL_UADD_MASK) << USBHS_DEVCTRL_UADD_SHIFT); + + /* Go to the addressed state. EP0 is now IDLE. */ + + priv->devstate = USBHS_DEVSTATE_ADDRESSED; privep->epstate = USBHS_EPSTATE_IDLE; - sam_setdevaddr(priv, priv->devaddr); /* Acknowledge then disable the further TXIN interrupts on EP0. */ @@ -2832,14 +2927,14 @@ static int sam_usbhs_interrupt(int irq, void *context) sam_putreg(USBHS_DEVINT_SUSPD | USBHS_DEVINT_WAKEUP, SAM_USBHS_DEVICR); + /* Inform board logic that USB is suspended */ + + sam_suspend(priv); + /* Re-freeze the clock */ regval |= USBHS_CTRL_FRZCLK; sam_putreg(regval, SAM_USBHS_CTRL); - - /* Inform board logic that USB is suspended */ - - sam_suspend(priv); } /* SOF interrupt */ @@ -2901,26 +2996,55 @@ static int sam_usbhs_interrupt(int irq, void *context) * - The data toggle sequence of the default control endpoint is cleared. * - At the end of the reset process, the End of Reset (USBHS_DEVISR.EORST) * bit is set. + * - During a reset, the USBHS automatically switches to High-speed mode + * if the host is High-speed-capable (the reset is called High-speed + * reset). The user should observe the USBHS_SR.SPEED field to know + * the speed running at the end of the reset (USBHS_DEVISR.EORST = 1). */ if ((pending & USBHS_DEVINT_EORST) != 0) { - usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ENDRESET), (uint16_t)pending); + /* Sample the USBHS SR register at the time of the EORST event. */ - /* Acknowledge the interrupt, clear pednding wakeup and suspend + regval = sam_getreg(SAM_USBHS_SR); + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_ENDRESET), regval); + + /* Acknowledge the interrupt, clear pending wakeup and suspend * status as we.. */ - sam_putreg(USBHS_DEVINT_WAKEUP | USBHS_DEVINT_SUSPD | USBHS_DEVINT_EORST, + sam_putreg(USBHS_DEVINT_WAKEUP | USBHS_DEVINT_SUSPD | + USBHS_DEVINT_EORST, SAM_USBHS_DEVICR); /* Enable suspend interrupts */ sam_putreg(USBHS_DEVINT_SUSPD, SAM_USBHS_DEVIER); - /* Handle the reset */ + /* Handle the reset (will select full speed mode) */ sam_reset(priv); + + /* Get the correct speed mode reported by the hardware */ + + switch (regval & USBHS_SR_SPEED_MASK) + { + default: + case USBHS_SR_SPEED_FULL: + priv->usbdev.speed = USB_SPEED_FULL; + break; + + case USBHS_SR_SPEED_HIGH: + priv->usbdev.speed = USB_SPEED_HIGH; + break; + + case USBHS_SR_SPEED_LOW: + priv->usbdev.speed = USB_SPEED_LOW; + break; + } + + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_SPEED), + priv->usbdev.speed); } /* Upstream resume */ @@ -2934,14 +3058,24 @@ static int sam_usbhs_interrupt(int irq, void *context) } #ifdef CONFIG_USBDEV_DMA - /* DMA interrupts */ + /* Endpoint DMA interrupts */ else if ((pending & USBHS_DEVINT_DMA_MASK) != 0) { + /* Each endpoint DMA ineterrupt is cleared when the + * USBHS_DEVDMASTATUSx interrupt source is cleared. + */ + + /* Process each pending endpoint DMA interrupt */ + for (i = 1; i <= SAM_USBHS_NDMACHANNELS; i++) { + /* Is there a DMA interrupt pending for endpoint i? */ + if ((pending & USBHS_DEVINT_DMA(i)) != 0) { + /* Yes.. process the endpoint i DMA interrupt */ + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_DMA), (uint16_t)i); sam_dma_interrupt(priv, i); } @@ -2953,10 +3087,20 @@ static int sam_usbhs_interrupt(int irq, void *context) else if ((pending & USBHS_DEVINT_PEP_MASK) != 0) { + /* Each endpoint interrupt is cleared when the interrupt source + * is serviced. + */ + + /* Process each pending endpoint interrupt */ + for (i = 0; i < SAM_USBHS_NENDPOINTS; i++) { + /* Is there an interrupt pending for endpoint i? */ + if ((pending & USBHS_DEVINT_PEP(i)) != 0) { + /* Yes.. process the endpoint i interrupt */ + usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EP), (uint16_t)i); sam_ep_interrupt(priv, i); } @@ -3080,7 +3224,7 @@ static void sam_ep_reset(struct sam_usbdev_s *priv, uint8_t epno) sam_putreg(USBHS_DEVINT_PEP(epno), SAM_USBHS_DEVIDR); - /* Cancel any queued requests. Since they are canceled with status + /* Cancel any queued requests. Since they are cancelled with status * -ESHUTDOWN, then will not be requeued until the configuration is reset. * NOTE: This should not be necessary... the CLASS_DISCONNECT above * should result in the class implementation calling sam_ep_disable @@ -3325,9 +3469,15 @@ static int sam_ep_configure_internal(struct sam_ep_s *privep, if (eptype == USB_EP_ATTR_XFER_CONTROL) { - sam_putreg(USBHS_DEVINT_PEP(epno), SAM_USBHS_DEVIDR); + sam_putreg(USBHS_DEVINT_PEP(epno), SAM_USBHS_DEVIDR); } + /* Enable the endpoint */ + + regval = sam_getreg(SAM_USBHS_DEVEPT); + regval |= USBHS_DEVEPT_EPEN(epno); + sam_putreg(regval, SAM_USBHS_DEVEPT); + /* Configure the endpoint */ regval = USBHS_DEVEPTCFG_ALLOC | @@ -3410,12 +3560,6 @@ static int sam_ep_configure_internal(struct sam_ep_s *privep, sam_putreg(regval, SAM_USBHS_DEVEPTIER(epno)); } - /* Enable the endpoint */ - - regval = sam_getreg(SAM_USBHS_DEVEPT); - regval |= USBHS_DEVEPT_EPEN(epno); - sam_putreg(regval, SAM_USBHS_DEVEPT); - /* If this is EP0, enable interrupts now */ if (eptype == USB_EP_ATTR_XFER_CONTROL) @@ -3519,14 +3663,7 @@ static int sam_ep_disable(struct usbdev_ep_s *ep) irqstate_t flags; uint8_t epno; -#ifdef CONFIG_DEBUG - if (!ep) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - ulldbg("ERROR: ep=%p\n", ep); - return -EINVAL; - } -#endif + DEBUGASSERT(ep != NULL); epno = USB_EPNO(ep->eplog); usbtrace(TRACE_EPDISABLE, epno); @@ -3556,13 +3693,7 @@ static struct usbdev_req_s *sam_ep_allocreq(struct usbdev_ep_s *ep) { struct sam_req_s *privreq; -#ifdef CONFIG_DEBUG - if (!ep) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return NULL; - } -#endif + DEBUGASSERT(ep != NULL); usbtrace(TRACE_EPALLOCREQ, USB_EPNO(ep->eplog)); privreq = (struct sam_req_s *)kmm_malloc(sizeof(struct sam_req_s)); @@ -3588,13 +3719,7 @@ static void sam_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *req) { struct sam_req_s *privreq = (struct sam_req_s*)req; -#ifdef CONFIG_DEBUG - if (!ep || !req) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return; - } -#endif + DEBUGASSERT(ep != NULL && req != NULL); usbtrace(TRACE_EPFREEREQ, USB_EPNO(ep->eplog)); kmm_free(privreq); @@ -3611,9 +3736,9 @@ static void sam_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *req) #ifdef CONFIG_USBDEV_DMA static void *sam_ep_allocbuffer(struct usbdev_ep_s *ep, uint16_t nbytes) { - /* There is not special buffer allocation requirement */ + /* Allocate properly aligned memory */ - return kumm_malloc(nbytes); + return kmm_memalign(USBHS_ALIGN, USBHS_ALIGN_UP(nbytes)); } #endif @@ -3628,7 +3753,7 @@ static void *sam_ep_allocbuffer(struct usbdev_ep_s *ep, uint16_t nbytes) #ifdef CONFIG_USBDEV_DMA static void sam_ep_freebuffer(struct usbdev_ep_s *ep, void *buf) { - /* There is not special buffer allocation requirement */ + /* There is no special buffer requirement to free aligned DMA buffers */ kumm_free(buf); } @@ -3651,26 +3776,10 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) uint8_t epno; int ret = OK; -#ifdef CONFIG_DEBUG - if (!req || !req->callback || !req->buf || !ep) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - ulldbg("ERROR: req=%p callback=%p buf=%p ep=%p\n", req, req->callback, req->buf, ep); - return -EINVAL; - } -#endif - + DEBUGASSERT(ep != NULL && req != NULL && req->callback != NULL && req->buf != NULL); usbtrace(TRACE_EPSUBMIT, USB_EPNO(ep->eplog)); priv = privep->dev; - -#ifdef CONFIG_DEBUG - if (!priv->driver) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_NOTCONFIGURED), priv->usbdev.speed); - ulldbg("ERROR: driver=%p\n", priv->driver); - return -ESHUTDOWN; - } -#endif + DEBUGASSERT(priv->driver != NULL); /* Handle the request from the class driver */ @@ -3743,13 +3852,7 @@ static int sam_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req) struct sam_ep_s *privep = (struct sam_ep_s *)ep; irqstate_t flags; -#ifdef CONFIG_DEBUG - if (!ep || !req) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif + DEBUGASSERT(ep != NULL && req != NULL); usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog)); flags = irqsave(); @@ -3771,13 +3874,7 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume) uint32_t regval; irqstate_t flags; -#ifdef CONFIG_DEBUG - if (!ep) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif + DEBUGASSERT(ep != NULL); /* Check that endpoint is in Idle state */ @@ -3935,13 +4032,7 @@ static struct usbdev_ep_s *sam_allocep(struct usbdev_s *dev, uint8_t epno, uint16_t epset = SAM_EPSET_NOTEP0; usbtrace(TRACE_DEVALLOCEP, (uint16_t)epno); -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return NULL; - } -#endif + DEBUGASSERT(dev != NULL); /* Ignore any direction bits in the logical address */ @@ -3997,13 +4088,8 @@ static void sam_freeep(struct usbdev_s *dev, struct usbdev_ep_s *ep) struct sam_usbdev_s *priv; struct sam_ep_s *privep; -#ifdef CONFIG_DEBUG - if (!dev || !ep) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return; - } -#endif + DEBUGASSERT(dev != NULL && ep != NULL); + priv = (struct sam_usbdev_s *)dev; privep = (struct sam_ep_s *)ep; usbtrace(TRACE_DEVFREEEP, (uint16_t)USB_EPNO(ep->eplog)); @@ -4029,13 +4115,7 @@ static int sam_getframe(struct usbdev_s *dev) uint32_t regval; uint16_t frameno; -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif + DEBUGASSERT(dev != NULL); /* Return the last frame number detected by the hardware */ @@ -4061,13 +4141,7 @@ static int sam_wakeup(struct usbdev_s *dev) uint32_t regval; usbtrace(TRACE_DEVWAKEUP, 0); -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif + DEBUGASSERT(dev != NULL); /* Resume normal operation */ @@ -4106,14 +4180,7 @@ static int sam_selfpowered(struct usbdev_s *dev, bool selfpowered) struct sam_usbdev_s *priv = (struct sam_usbdev_s *)dev; usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); - -#ifdef CONFIG_DEBUG - if (!dev) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -ENODEV; - } -#endif + DEBUGASSERT(dev != NULL); priv->selfpowered = selfpowered; return OK; @@ -4153,7 +4220,9 @@ static int sam_pullup(FAR struct usbdev_s *dev, bool enable) regval &= ~USBHS_CTRL_FRZCLK; sam_putreg(regval, SAM_USBHS_CTRL); - /* DETACH=0: USBHS is attached. Pulls up the DP line */ + /* DETACH=0: USBHS is attached. ARMs the USBHS to pull up the DP line + * when the USBHS is no longer suspended. + */ regval = sam_getreg(SAM_USBHS_DEVCTRL); regval &= ~USBHS_DEVCTRL_DETACH; @@ -4161,49 +4230,97 @@ static int sam_pullup(FAR struct usbdev_s *dev, bool enable) priv->usbdev.speed = USB_SPEED_FULL; - /* The next event that we expect to see is a reset from the connected - * host. When a USB reset is detected on the USB line, the following - * operations are performed by the controller: + /* There are several possibilities: * - * - All endpoints are disabled, except the default control endpoint. - * - The default control endpoint is reset - * - The data toggle sequence of the default control endpoint is cleared. - * - At the end of the reset process, the End of Reset (USBHS_DEVISR.EORST) - * bit is set. - * - * The class implementation should not call this method with - * enable == true until is is fully initialized and ready to accept - * connections. - * - * If there is no host connected (no bus activity), then we might - * get a SUSPend interrupt instead of a End of Reset. In the case, we - * would like to keep the clock frozen until the host is connected. - * - * The strategy here was taken from the SAMV7 sample code: It will - * force a SUSPend event. Then disable clocking. We will take the - * SUSPend interrupt (because it is already pending), but after the - * clock is frozen, only a WAKEUP interrupt can be received. + * 1. The device may not be plugged into a host. In that case, the + * hardware will be in a suspended state. When an idle USB bus state + * has been detected for 3 ms , the controller sets the Suspend + * (USBHS_DEVISR.SUSP) interrupt bit. + * 2. We may have been suspended but a WAKEUP event has already occurred. + * The USBHS_DEVISR.WAKEUP interrupt bit is set when a non-idle event + * is detected, it can occur whether the controller is in the Suspend + * mode or not. The USBHS_DEVISR.SUSP and USBHS_DEVISR.WAKEUP interrupts + * are thus independent, except that one bit is cleared when the other is set. + * 3. Because we have already enabled the pull-up, that event may have already + * have been reset by the host. */ - /* Enable expected interrupts */ + regval = sam_getreg(SAM_USBHS_DEVISR); + if ((regval & USBHS_DEVINT_SUSPD) == 0) + { + /* If the USBHS detects activity on the BUS, then it will not be + * suspended. In that case, next event that we expect to see is a + * reset from the connected host. When a USB reset is detected on + * the USB line, the following operations are performed by the + * controller: + * + * - All endpoints are disabled, except the default control + * endpoint. + * - The default control endpoint is reset + * - The data toggle sequence of the default control endpoint is + * cleared. + * - At the end of the reset process, the End of Reset + * (USBHS_DEVISR.EORST) bit is set. + * - During a reset, the USBHS automatically switches to High- + * speed mode if the host is High-speed-capable (the reset is + * called High-speed reset). The user should observe the + * USBHS_SR.SPEED field to know the speed running at the end + * of the reset (USBHS_DEVISR.EORST = 1). + * + * The class implementation should not call this method with + * enable == true until is is fully initialized and ready to + * accept connections. + */ - sam_putreg(USBHS_DEVINT_EORST | USBHS_DEVINT_WAKEUP | USBHS_DEVINT_SUSPD, - SAM_USBHS_DEVIER); + /* Enable expected interrupts */ - /* Clear pending interrupt interrupts */ + sam_putreg(USBHS_DEVINT_EORST | USBHS_DEVINT_EORSM | + USBHS_DEVINT_SUSPD, + SAM_USBHS_DEVIER); - sam_putreg(USBHS_DEVINT_EORST | USBHS_DEVINT_SUSPD, SAM_USBHS_DEVICR); + /* Leave the clock unfrozen */ + } + else + { + /* If there is no host connected (no bus activity), then we + * might get a SUSPend interrupt instead of a End of Reset. In + * the case, we would like to keep the clock frozen until the + * host is connected. + * + * The strategy here was taken from the SAMV7 sample code: It + * will force a SUSPend event. Then disable clocking. We will + * take the SUSPend interrupt (because it is already pending), + * but after the clock is frozen, only a WAKEUP interrupt can be + * received. + */ - /* Force the first suspend event */ + /* Enable wakeup interrupts */ - sam_putreg(USBHS_DEVINT_SUSPD, SAM_USBHS_DEVIFR); - sam_putreg(USBHS_DEVINT_WAKEUP, SAM_USBHS_DEVICR); + sam_putreg(USBHS_DEVINT_WAKEUP | USBHS_DEVINT_EORSM, + SAM_USBHS_DEVIER); - /* Refreeze the clock and wait for the wakeup event */ + /* Enable expected interrupts */ - regval = sam_getreg(SAM_USBHS_CTRL); - regval |= USBHS_CTRL_FRZCLK; - sam_putreg(regval, SAM_USBHS_CTRL); + sam_putreg(USBHS_DEVINT_EORST | USBHS_DEVINT_WAKEUP | + USBHS_DEVINT_SUSPD, + SAM_USBHS_DEVIER); + + /* Clear pending interrupts */ + + sam_putreg(USBHS_DEVINT_EORST | USBHS_DEVINT_SUSPD, + SAM_USBHS_DEVICR); + + /* Force the first suspend event */ + + sam_putreg(USBHS_DEVINT_SUSPD, SAM_USBHS_DEVIFR); + sam_putreg(USBHS_DEVINT_WAKEUP, SAM_USBHS_DEVICR); + + /* Refreeze the clock and wait for the wakeup event */ + + regval = sam_getreg(SAM_USBHS_CTRL); + regval |= USBHS_CTRL_FRZCLK; + sam_putreg(regval, SAM_USBHS_CTRL); + } } else { @@ -4262,13 +4379,17 @@ static void sam_reset(struct sam_usbdev_s *priv) CLASS_DISCONNECT(priv->driver, &priv->usbdev); /* The device enters the Default state */ + /* Disable the device address */ - priv->devaddr = 0; - sam_setdevaddr(priv, 0); + regval = sam_getreg(SAM_USBHS_DEVCTRL); + regval &= ~(USBHS_DEVCTRL_UADD_MASK | USBHS_DEVCTRL_ADDEN); + sam_putreg(regval, SAM_USBHS_DEVCTRL); + + /* Revert to the un-addressed, default state */ priv->devstate = USBHS_DEVSTATE_DEFAULT; - /* Reset and disable all endpoints other. Then re-configure EP0 */ + /* Reset and disable all endpoints. Then re-configure EP0 */ sam_epset_reset(priv, SAM_EPSET_ALL); sam_ep0_configure(priv); @@ -4325,6 +4446,10 @@ static void sam_hw_setup(struct sam_usbdev_s *priv) regval &= ~USBHS_CTRL_USBE; sam_putreg(regval, SAM_USBHS_CTRL); + /* Configure USBHS pins. Nothing needs to be done: HDM and HDP are the + * primary pin functions and there are no alternatives. + */ + /* Enable clocking to the USBHS peripheral. * * The clock for the USBHS bus interface is generated by the Power @@ -4346,7 +4471,7 @@ static void sam_hw_setup(struct sam_usbdev_s *priv) * 3. Enable the UPLL 480 MHz. * 4. Wait for the UPLL 480 MHz to be considered as locked by the PMC. * - * Steps 1,3, and 4 were performed in sam_clockconfig.c. + * Steps 3 and 4 are performed in sam_usbclock.c. */ /* Enable the USBHS peripheral clock (PMC_PCER) */ @@ -4363,9 +4488,16 @@ static void sam_hw_setup(struct sam_usbdev_s *priv) regval |= USBHS_CTRL_USBE; sam_putreg(regval, SAM_USBHS_CTRL); + regval &= ~USBHS_CTRL_UIDE; + sam_putreg(regval, SAM_USBHS_CTRL); + regval &= ~USBHS_CTRL_FRZCLK; sam_putreg(regval, SAM_USBHS_CTRL); + /* Enable the UPLL */ + + sam_usbclock(); + /* Select High Speed or force Full Speed */ regval = sam_getreg(SAM_USBHS_DEVCTRL); @@ -4692,21 +4824,12 @@ int usbdev_register(struct usbdevclass_driver_s *driver) int ret; usbtrace(TRACE_DEVREGISTER, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !driver->ops->bind || !driver->ops->unbind || - !driver->ops->disconnect || !driver->ops->setup) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } - - if (priv->driver) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_DRIVER), 0); - return -EBUSY; - } -#endif + DEBUGASSERT(driver != NULL && + driver->ops->bind != NULL && + driver->ops->unbind != NULL && + driver->ops->disconnect != NULL && + driver->ops->setup != NULL); + DEBUGASSERT(priv->driver == NULL); /* First hook up the driver */ @@ -4746,14 +4869,7 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver) irqstate_t flags; usbtrace(TRACE_DEVUNREGISTER, 0); - -#ifdef CONFIG_DEBUG - if (driver != priv->driver) - { - usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0); - return -EINVAL; - } -#endif + DEBUGASSERT(driver == priv->driver); /* Reset the hardware and cancel all requests. All requests must be * canceled while the class driver is still bound. diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 47ed9d1fb63..2d462bebcb9 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -460,6 +460,30 @@ config ARCH_CHIP_STM32F302VC select STM32_STM32F30XX select ARCH_HAVE_FPU +config ARCH_CHIP_STM32F303K6 + bool "STM32F303K6" + select ARCH_CORTEXM4 + select STM32_STM32F30XX + select ARCH_HAVE_FPU + +config ARCH_CHIP_STM32F303K8 + bool "STM32F303K8" + select ARCH_CORTEXM4 + select STM32_STM32F30XX + select ARCH_HAVE_FPU + +config ARCH_CHIP_STM32F303C6 + bool "STM32F303C6" + select ARCH_CORTEXM4 + select STM32_STM32F30XX + select ARCH_HAVE_FPU + +config ARCH_CHIP_STM32F303C8 + bool "STM32F303C8" + select ARCH_CORTEXM4 + select STM32_STM32F30XX + select ARCH_HAVE_FPU + config ARCH_CHIP_STM32F303CB bool "STM32F303CB" select ARCH_CORTEXM4 @@ -484,6 +508,18 @@ config ARCH_CHIP_STM32F303RC select STM32_STM32F30XX select ARCH_HAVE_FPU +config ARCH_CHIP_STM32F303RD + bool "STM32F303RD" + select ARCH_CORTEXM4 + select STM32_STM32F30XX + select ARCH_HAVE_FPU + +config ARCH_CHIP_STM32F303RE + bool "STM32F303RE" + select ARCH_CORTEXM4 + select STM32_STM32F30XX + select ARCH_HAVE_FPU + config ARCH_CHIP_STM32F303VB bool "STM32F303VB" select ARCH_CORTEXM4 diff --git a/arch/arm/src/stm32/chip/stm32f44xxx_otgfs.h b/arch/arm/src/stm32/chip/stm32f44xxx_otgfs.h new file mode 100644 index 00000000000..231c4b352c4 --- /dev/null +++ b/arch/arm/src/stm32/chip/stm32f44xxx_otgfs.h @@ -0,0 +1,1022 @@ +/**************************************************************************************************** + * arch/arm/src/stm32/chip/stm32f44xxx_otgfs.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_CHIP_STM32F44XXX_OTGFS_H +#define __ARCH_ARM_SRC_STM32_CHIP_STM32F44XXX_OTGFS_H + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ +/**************************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************************/ +/* General definitions */ + +#define OTGFS_EPTYPE_CTRL (0) /* Control */ +#define OTGFS_EPTYPE_ISOC (1) /* Isochronous */ +#define OTGFS_EPTYPE_BULK (2) /* Bulk */ +#define OTGFS_EPTYPE_INTR (3) /* Interrupt */ + +#define OTGFS_PID_DATA0 (0) +#define OTGFS_PID_DATA2 (1) +#define OTGFS_PID_DATA1 (2) +#define OTGFS_PID_MDATA (3) /* Non-control */ +#define OTGFS_PID_SETUP (3) /* Control */ + +/* Register Offsets *********************************************************************************/ +/* Core global control and status registers */ + +#define STM32_OTGFS_GOTGCTL_OFFSET 0x0000 /* Control and status register */ +#define STM32_OTGFS_GOTGINT_OFFSET 0x0004 /* Interrupt register */ +#define STM32_OTGFS_GAHBCFG_OFFSET 0x0008 /* AHB configuration register */ +#define STM32_OTGFS_GUSBCFG_OFFSET 0x000c /* USB configuration register */ +#define STM32_OTGFS_GRSTCTL_OFFSET 0x0010 /* Reset register */ +#define STM32_OTGFS_GINTSTS_OFFSET 0x0014 /* Core interrupt register */ +#define STM32_OTGFS_GINTMSK_OFFSET 0x0018 /* Interrupt mask register */ +#define STM32_OTGFS_GRXSTSR_OFFSET 0x001c /* Receive status debug read/OTG status read register */ +#define STM32_OTGFS_GRXSTSP_OFFSET 0x0020 /* Receive status debug read/OTG status pop register */ +#define STM32_OTGFS_GRXFSIZ_OFFSET 0x0024 /* Receive FIFO size register */ +#define STM32_OTGFS_HNPTXFSIZ_OFFSET 0x0028 /* Host non-periodic transmit FIFO size register */ +#define STM32_OTGFS_DIEPTXF0_OFFSET 0x0028 /* Endpoint 0 Transmit FIFO size */ +#define STM32_OTGFS_HNPTXSTS_OFFSET 0x002c /* Non-periodic transmit FIFO/queue status register */ +#define STM32_OTGFS_GCCFG_OFFSET 0x0038 /* General core configuration register */ +#define STM32_OTGFS_CID_OFFSET 0x003c /* Core ID register */ +#define STM32_OTGFS_HPTXFSIZ_OFFSET 0x0100 /* Host periodic transmit FIFO size register */ + +#define STM32_OTGFS_DIEPTXF_OFFSET(n) (104+(((n)-1) << 2)) +#define STM32_OTGFS_DIEPTXF1_OFFSET 0x0104 /* Device IN endpoint transmit FIFO1 size register */ +#define STM32_OTGFS_DIEPTXF2_OFFSET 0x0108 /* Device IN endpoint transmit FIFO2 size register */ +#define STM32_OTGFS_DIEPTXF3_OFFSET 0x010c /* Device IN endpoint transmit FIFO3 size register */ + +/* Host-mode control and status registers */ + +#define STM32_OTGFS_HCFG_OFFSET 0x0400 /* Host configuration register */ +#define STM32_OTGFS_HFIR_OFFSET 0x0404 /* Host frame interval register */ +#define STM32_OTGFS_HFNUM_OFFSET 0x0408 /* Host frame number/frame time remaining register */ +#define STM32_OTGFS_HPTXSTS_OFFSET 0x0410 /* Host periodic transmit FIFO/queue status register */ +#define STM32_OTGFS_HAINT_OFFSET 0x0414 /* Host all channels interrupt register */ +#define STM32_OTGFS_HAINTMSK_OFFSET 0x0418 /* Host all channels interrupt mask register */ +#define STM32_OTGFS_HPRT_OFFSET 0x0440 /* Host port control and status register */ + +#define STM32_OTGFS_CHAN_OFFSET(n) (0x500 + ((n) << 5) +#define STM32_OTGFS_HCCHAR_CHOFFSET 0x0000 /* Host channel characteristics register */ +#define STM32_OTGFS_HCINT_CHOFFSET 0x0008 /* Host channel interrupt register */ +#define STM32_OTGFS_HCINTMSK_CHOFFSET 0x000c /* Host channel interrupt mask register */ +#define STM32_OTGFS_HCTSIZ_CHOFFSET 0x0010 /* Host channel interrupt register */ + +#define STM32_OTGFS_HCCHAR_OFFSET(n) (0x500 + ((n) << 5)) +#define STM32_OTGFS_HCCHAR0_OFFSET 0x0500 /* Host channel-0 characteristics register */ +#define STM32_OTGFS_HCCHAR1_OFFSET 0x0520 /* Host channel-1 characteristics register */ +#define STM32_OTGFS_HCCHAR2_OFFSET 0x0540 /* Host channel-2 characteristics register */ +#define STM32_OTGFS_HCCHAR3_OFFSET 0x0560 /* Host channel-3 characteristics register */ +#define STM32_OTGFS_HCCHAR4_OFFSET 0x0580 /* Host channel-4 characteristics register */ +#define STM32_OTGFS_HCCHAR5_OFFSET 0x05a0 /* Host channel-5 characteristics register */ +#define STM32_OTGFS_HCCHAR6_OFFSET 0x05c0 /* Host channel-6 characteristics register */ +#define STM32_OTGFS_HCCHAR7_OFFSET 0x05e0 /* Host channel-7 characteristics register */ + +#define STM32_OTGFS_HCINT_OFFSET(n) (0x508 + ((n) << 5)) +#define STM32_OTGFS_HCINT0_OFFSET 0x0508 /* Host channel-0 interrupt register */ +#define STM32_OTGFS_HCINT1_OFFSET 0x0528 /* Host channel-1 interrupt register */ +#define STM32_OTGFS_HCINT2_OFFSET 0x0548 /* Host channel-2 interrupt register */ +#define STM32_OTGFS_HCINT3_OFFSET 0x0568 /* Host channel-3 interrupt register */ +#define STM32_OTGFS_HCINT4_OFFSET 0x0588 /* Host channel-4 interrupt register */ +#define STM32_OTGFS_HCINT5_OFFSET 0x05a8 /* Host channel-5 interrupt register */ +#define STM32_OTGFS_HCINT6_OFFSET 0x05c8 /* Host channel-6 interrupt register */ +#define STM32_OTGFS_HCINT7_OFFSET 0x05e8 /* Host channel-7 interrupt register */ + +#define STM32_OTGFS_HCINTMSK_OFFSET(n) (0x50c + ((n) << 5)) +#define STM32_OTGFS_HCINTMSK0_OFFSET 0x050c /* Host channel-0 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK1_OFFSET 0x052c /* Host channel-1 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK2_OFFSET 0x054c /* Host channel-2 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK3_OFFSET 0x056c /* Host channel-3 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK4_OFFSET 0x058c /* Host channel-4 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK5_OFFSET 0x05ac /* Host channel-5 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK6_OFFSET 0x05cc /* Host channel-6 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK7_OFFSET 0x05ec /* Host channel-7 interrupt mask register */ + +#define STM32_OTGFS_HCTSIZ_OFFSET(n) (0x510 + ((n) << 5)) +#define STM32_OTGFS_HCTSIZ0_OFFSET 0x0510 /* Host channel-0 interrupt register */ +#define STM32_OTGFS_HCTSIZ1_OFFSET 0x0530 /* Host channel-1 interrupt register */ +#define STM32_OTGFS_HCTSIZ2_OFFSET 0x0550 /* Host channel-2 interrupt register */ +#define STM32_OTGFS_HCTSIZ3_OFFSET 0x0570 /* Host channel-3 interrupt register */ +#define STM32_OTGFS_HCTSIZ4_OFFSET 0x0590 /* Host channel-4 interrupt register */ +#define STM32_OTGFS_HCTSIZ5_OFFSET 0x05b0 /* Host channel-5 interrupt register */ +#define STM32_OTGFS_HCTSIZ6_OFFSET 0x05d0 /* Host channel-6 interrupt register */ +#define STM32_OTGFS_HCTSIZ7_OFFSET 0x05f0 /* Host channel-7 interrupt register */ + +/* Device-mode control and status registers */ + +#define STM32_OTGFS_DCFG_OFFSET 0x0800 /* Device configuration register */ +#define STM32_OTGFS_DCTL_OFFSET 0x0804 /* Device control register */ +#define STM32_OTGFS_DSTS_OFFSET 0x0808 /* Device status register */ +#define STM32_OTGFS_DIEPMSK_OFFSET 0x0810 /* Device IN endpoint common interrupt mask register */ +#define STM32_OTGFS_DOEPMSK_OFFSET 0x0814 /* Device OUT endpoint common interrupt mask register */ +#define STM32_OTGFS_DAINT_OFFSET 0x0818 /* Device all endpoints interrupt register */ +#define STM32_OTGFS_DAINTMSK_OFFSET 0x081c /* All endpoints interrupt mask register */ +#define STM32_OTGFS_DVBUSDIS_OFFSET 0x0828 /* Device VBUS discharge time register */ +#define STM32_OTGFS_DVBUSPULSE_OFFSET 0x082c /* Device VBUS pulsing time register */ +#define STM32_OTGFS_DIEPEMPMSK_OFFSET 0x0834 /* Device IN endpoint FIFO empty interrupt mask register */ + +#define STM32_OTGFS_DIEP_OFFSET(n) (0x0900 + ((n) << 5)) +#define STM32_OTGFS_DIEPCTL_EPOFFSET 0x0000 /* Device endpoint control register */ +#define STM32_OTGFS_DIEPINT_EPOFFSET 0x0008 /* Device endpoint interrupt register */ +#define STM32_OTGFS_DIEPTSIZ_EPOFFSET 0x0010 /* Device IN endpoint transfer size register */ +#define STM32_OTGFS_DTXFSTS_EPOFFSET 0x0018 /* Device IN endpoint transmit FIFO status register */ + +#define STM32_OTGFS_DIEPCTL_OFFSET(n) (0x0900 + ((n) << 5)) +#define STM32_OTGFS_DIEPCTL0_OFFSET 0x0900 /* Device control IN endpoint 0 control register */ +#define STM32_OTGFS_DIEPCTL1_OFFSET 0x0920 /* Device control IN endpoint 2 control register */ +#define STM32_OTGFS_DIEPCTL2_OFFSET 0x0940 /* Device control IN endpoint 3 control register */ +#define STM32_OTGFS_DIEPCTL3_OFFSET 0x0960 /* Device control IN endpoint 4 control register */ + +#define STM32_OTGFS_DIEPINT_OFFSET(n) (0x0908 + ((n) << 5)) +#define STM32_OTGFS_DIEPINT0_OFFSET 0x0908 /* Device endpoint-0 interrupt register */ +#define STM32_OTGFS_DIEPINT1_OFFSET 0x0928 /* Device endpoint-1 interrupt register */ +#define STM32_OTGFS_DIEPINT2_OFFSET 0x0948 /* Device endpoint-2 interrupt register */ +#define STM32_OTGFS_DIEPINT3_OFFSET 0x0968 /* Device endpoint-3 interrupt register */ + +#define STM32_OTGFS_DIEPTSIZ_OFFSET(n) (0x910 + ((n) << 5)) +#define STM32_OTGFS_DIEPTSIZ0_OFFSET 0x0910 /* Device IN endpoint 0 transfer size register */ +#define STM32_OTGFS_DIEPTSIZ1_OFFSET 0x0930 /* Device IN endpoint 1 transfer size register */ +#define STM32_OTGFS_DIEPTSIZ2_OFFSET 0x0950 /* Device IN endpoint 2 transfer size register */ +#define STM32_OTGFS_DIEPTSIZ3_OFFSET 0x0970 /* Device IN endpoint 3 transfer size register */ + +#define STM32_OTGFS_DTXFSTS_OFFSET(n) (0x0918 + ((n) << 5)) +#define STM32_OTGFS_DTXFSTS0_OFFSET 0x0918 /* Device OUT endpoint-0 TxFIFO status register */ +#define STM32_OTGFS_DTXFSTS1_OFFSET 0x0938 /* Device OUT endpoint-1 TxFIFO status register */ +#define STM32_OTGFS_DTXFSTS2_OFFSET 0x0958 /* Device OUT endpoint-2 TxFIFO status register */ +#define STM32_OTGFS_DTXFSTS3_OFFSET 0x0978 /* Device OUT endpoint-3 TxFIFO status register */ + +#define STM32_OTGFS_DOEP_OFFSET(n) (0x0b00 + ((n) << 5)) +#define STM32_OTGFS_DOEPCTL_EPOFFSET 0x0000 /* Device control OUT endpoint 0 control register */ +#define STM32_OTGFS_DOEPINT_EPOFFSET 0x0008 /* Device endpoint-x interrupt register */ + +#define STM32_OTGFS_DOEPCTL_OFFSET(n) (0x0b00 + ((n) << 5)) +#define STM32_OTGFS_DOEPCTL0_OFFSET 0x00b00 /* Device OUT endpoint 0 control register */ +#define STM32_OTGFS_DOEPCTL1_OFFSET 0x00b20 /* Device OUT endpoint 1 control register */ +#define STM32_OTGFS_DOEPCTL2_OFFSET 0x00b40 /* Device OUT endpoint 2 control register */ +#define STM32_OTGFS_DOEPCTL3_OFFSET 0x00b60 /* Device OUT endpoint 3 control register */ + +#define STM32_OTGFS_DOEPINT_OFFSET(n) (0x0b08 + ((n) << 5)) +#define STM32_OTGFS_DOEPINT0_OFFSET 0x00b08 /* Device endpoint-0 interrupt register */ +#define STM32_OTGFS_DOEPINT1_OFFSET 0x00b28 /* Device endpoint-1 interrupt register */ +#define STM32_OTGFS_DOEPINT2_OFFSET 0x00b48 /* Device endpoint-2 interrupt register */ +#define STM32_OTGFS_DOEPINT3_OFFSET 0x00b68 /* Device endpoint-3 interrupt register */ + +#define STM32_OTGFS_DOEPTSIZ_OFFSET(n) (0x0b10 + ((n) << 5)) +#define STM32_OTGFS_DOEPTSIZ0_OFFSET 0x00b10 /* Device OUT endpoint-0 transfer size register */ +#define STM32_OTGFS_DOEPTSIZ1_OFFSET 0x00b30 /* Device OUT endpoint-1 transfer size register */ +#define STM32_OTGFS_DOEPTSIZ2_OFFSET 0x00b50 /* Device OUT endpoint-2 transfer size register */ +#define STM32_OTGFS_DOEPTSIZ3_OFFSET 0x00b70 /* Device OUT endpoint-3 transfer size register */ + +/* Power and clock gating registers */ + +#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */ + +/* Data FIFO (DFIFO) access registers */ + +#define STM32_OTGFS_DFIFO_DEP_OFFSET(n) (0x1000 + ((n) << 12)) +#define STM32_OTGFS_DFIFO_HCH_OFFSET(n) (0x1000 + ((n) << 12)) + +#define STM32_OTGFS_DFIFO_DEP0_OFFSET 0x1000 /* 0x1000-0x1ffc Device IN/OUT Endpoint 0 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH0_OFFSET 0x1000 /* 0x1000-0x1ffc Host OUT/IN Channel 0 DFIFO Read/Write Access */ + +#define STM32_OTGFS_DFIFO_DEP1_OFFSET 0x2000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH1_OFFSET 0x2000 /* 0x2000-0x2ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */ + +#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 2 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 2 DFIFO Read/Write Access */ + +#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 3 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 3 DFIFO Read/Write Access */ + +/* Register Addresses *******************************************************************************/ + +#define STM32_OTGFS_GOTGCTL (STM32_OTGFS_BASE+STM32_OTGFS_GOTGCTL_OFFSET) +#define STM32_OTGFS_GOTGINT (STM32_OTGFS_BASE+STM32_OTGFS_GOTGINT_OFFSET) +#define STM32_OTGFS_GAHBCFG (STM32_OTGFS_BASE+STM32_OTGFS_GAHBCFG_OFFSET) +#define STM32_OTGFS_GUSBCFG (STM32_OTGFS_BASE+STM32_OTGFS_GUSBCFG_OFFSET) +#define STM32_OTGFS_GRSTCTL (STM32_OTGFS_BASE+STM32_OTGFS_GRSTCTL_OFFSET) +#define STM32_OTGFS_GINTSTS (STM32_OTGFS_BASE+STM32_OTGFS_GINTSTS_OFFSET) +#define STM32_OTGFS_GINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_GINTMSK_OFFSET) +#define STM32_OTGFS_GRXSTSR (STM32_OTGFS_BASE+STM32_OTGFS_GRXSTSR_OFFSET) +#define STM32_OTGFS_GRXSTSP (STM32_OTGFS_BASE+STM32_OTGFS_GRXSTSP_OFFSET) +#define STM32_OTGFS_GRXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_GRXFSIZ_OFFSET) +#define STM32_OTGFS_HNPTXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_HNPTXFSIZ_OFFSET) +#define STM32_OTGFS_DIEPTXF0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF0_OFFSET) +#define STM32_OTGFS_HNPTXSTS (STM32_OTGFS_BASE+STM32_OTGFS_HNPTXSTS_OFFSET) +#define STM32_OTGFS_GCCFG (STM32_OTGFS_BASE+STM32_OTGFS_GCCFG_OFFSET) +#define STM32_OTGFS_CID (STM32_OTGFS_BASE+STM32_OTGFS_CID_OFFSET) +#define STM32_OTGFS_HPTXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_HPTXFSIZ_OFFSET) + +#define STM32_OTGFS_DIEPTXF(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF_OFFSET(n)) +#define STM32_OTGFS_DIEPTXF1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF1_OFFSET) +#define STM32_OTGFS_DIEPTXF2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF2_OFFSET) +#define STM32_OTGFS_DIEPTXF3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF3_OFFSET) + +/* Host-mode control and status registers */ + +#define STM32_OTGFS_HCFG (STM32_OTGFS_BASE+STM32_OTGFS_HCFG_OFFSET) +#define STM32_OTGFS_HFIR (STM32_OTGFS_BASE+STM32_OTGFS_HFIR_OFFSET) +#define STM32_OTGFS_HFNUM (STM32_OTGFS_BASE+STM32_OTGFS_HFNUM_OFFSET) +#define STM32_OTGFS_HPTXSTS (STM32_OTGFS_BASE+STM32_OTGFS_HPTXSTS_OFFSET) +#define STM32_OTGFS_HAINT (STM32_OTGFS_BASE+STM32_OTGFS_HAINT_OFFSET) +#define STM32_OTGFS_HAINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_HAINTMSK_OFFSET) +#define STM32_OTGFS_HPRT (STM32_OTGFS_BASE+STM32_OTGFS_HPRT_OFFSET) + +#define STM32_OTGFS_CHAN(n) (STM32_OTGFS_BASE+STM32_OTGFS_CHAN_OFFSET(n)) + +#define STM32_OTGFS_HCCHAR(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR_OFFSET(n)) +#define STM32_OTGFS_HCCHAR0 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR0_OFFSET) +#define STM32_OTGFS_HCCHAR1 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR1_OFFSET) +#define STM32_OTGFS_HCCHAR2 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR2_OFFSET) +#define STM32_OTGFS_HCCHAR3 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR3_OFFSET) +#define STM32_OTGFS_HCCHAR4 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR4_OFFSET) +#define STM32_OTGFS_HCCHAR5 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR5_OFFSET) +#define STM32_OTGFS_HCCHAR6 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR6_OFFSET) +#define STM32_OTGFS_HCCHAR7 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR7_OFFSET) + +#define STM32_OTGFS_HCINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCINT_OFFSET(n)) +#define STM32_OTGFS_HCINT0 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT0_OFFSET) +#define STM32_OTGFS_HCINT1 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT1_OFFSET) +#define STM32_OTGFS_HCINT2 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT2_OFFSET) +#define STM32_OTGFS_HCINT3 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT3_OFFSET) +#define STM32_OTGFS_HCINT4 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT4_OFFSET) +#define STM32_OTGFS_HCINT5 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT5_OFFSET) +#define STM32_OTGFS_HCINT6 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT6_OFFSET) +#define STM32_OTGFS_HCINT7 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT7_OFFSET) + +#define STM32_OTGFS_HCINTMSK(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK_OFFSET(n)) +#define STM32_OTGFS_HCINTMSK0 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK0_OFFSET) +#define STM32_OTGFS_HCINTMSK1 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK1_OFFSET) +#define STM32_OTGFS_HCINTMSK2 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK2_OFFSET) +#define STM32_OTGFS_HCINTMSK3 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK3_OFFSET) +#define STM32_OTGFS_HCINTMSK4 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK4_OFFSET) +#define STM32_OTGFS_HCINTMSK5 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK5_OFFSET) +#define STM32_OTGFS_HCINTMSK6 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK6_OFFSET) +#define STM32_OTGFS_HCINTMSK7 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK7_OFFSET)_ + +#define STM32_OTGFS_HCTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ_OFFSET(n)) +#define STM32_OTGFS_HCTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ0_OFFSET) +#define STM32_OTGFS_HCTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ1_OFFSET) +#define STM32_OTGFS_HCTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ2_OFFSET) +#define STM32_OTGFS_HCTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ3_OFFSET) +#define STM32_OTGFS_HCTSIZ4 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ4_OFFSET) +#define STM32_OTGFS_HCTSIZ5 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ5_OFFSET) +#define STM32_OTGFS_HCTSIZ6 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ6_OFFSET) +#define STM32_OTGFS_HCTSIZ7 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ7_OFFSET) + +/* Device-mode control and status registers */ + +#define STM32_OTGFS_DCFG (STM32_OTGFS_BASE+STM32_OTGFS_DCFG_OFFSET) +#define STM32_OTGFS_DCTL (STM32_OTGFS_BASE+STM32_OTGFS_DCTL_OFFSET) +#define STM32_OTGFS_DSTS (STM32_OTGFS_BASE+STM32_OTGFS_DSTS_OFFSET) +#define STM32_OTGFS_DIEPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DIEPMSK_OFFSET) +#define STM32_OTGFS_DOEPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DOEPMSK_OFFSET) +#define STM32_OTGFS_DAINT (STM32_OTGFS_BASE+STM32_OTGFS_DAINT_OFFSET) +#define STM32_OTGFS_DAINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_DAINTMSK_OFFSET) +#define STM32_OTGFS_DVBUSDIS (STM32_OTGFS_BASE+STM32_OTGFS_DVBUSDIS_OFFSET) +#define STM32_OTGFS_DVBUSPULSE (STM32_OTGFS_BASE+STM32_OTGFS_DVBUSPULSE_OFFSET) +#define STM32_OTGFS_DIEPEMPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DIEPEMPMSK_OFFSET) + +#define STM32_OTGFS_DIEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEP_OFFSET(n)) + +#define STM32_OTGFS_DIEPCTL(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL_OFFSET(n)) +#define STM32_OTGFS_DIEPCTL0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL0_OFFSET) +#define STM32_OTGFS_DIEPCTL1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL1_OFFSET) +#define STM32_OTGFS_DIEPCTL2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL2_OFFSET) +#define STM32_OTGFS_DIEPCTL3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL3_OFFSET) + +#define STM32_OTGFS_DIEPINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT_OFFSET(n)) +#define STM32_OTGFS_DIEPINT0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT0_OFFSET) +#define STM32_OTGFS_DIEPINT1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT1_OFFSET) +#define STM32_OTGFS_DIEPINT2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT2_OFFSET) +#define STM32_OTGFS_DIEPINT3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT3_OFFSET) + +#define STM32_OTGFS_DIEPTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ_OFFSET(n)) +#define STM32_OTGFS_DIEPTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ0_OFFSET) +#define STM32_OTGFS_DIEPTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ1_OFFSET) +#define STM32_OTGFS_DIEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ2_OFFSET) +#define STM32_OTGFS_DIEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ3_OFFSET) + +#define STM32_OTGFS_DTXFSTS(n) (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS_OFFSET(n)) +#define STM32_OTGFS_DTXFSTS0 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS0_OFFSET) +#define STM32_OTGFS_DTXFSTS1 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS1_OFFSET) +#define STM32_OTGFS_DTXFSTS2 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS2_OFFSET) +#define STM32_OTGFS_DTXFSTS3 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS3_OFFSET) + +#define STM32_OTGFS_DOEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEP_OFFSET(n)) + +#define STM32_OTGFS_DOEPCTL(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL_OFFSET(n)) +#define STM32_OTGFS_DOEPCTL0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL0_OFFSET) +#define STM32_OTGFS_DOEPCTL1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL1_OFFSET) +#define STM32_OTGFS_DOEPCTL2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL2_OFFSET) +#define STM32_OTGFS_DOEPCTL3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL3_OFFSET) + +#define STM32_OTGFS_DOEPINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT_OFFSET(n)) +#define STM32_OTGFS_DOEPINT0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT0_OFFSET) +#define STM32_OTGFS_DOEPINT1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT1_OFFSET) +#define STM32_OTGFS_DOEPINT2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT2_OFFSET) +#define STM32_OTGFS_DOEPINT3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT3_OFFSET) + +#define STM32_OTGFS_DOEPTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ_OFFSET(n)) +#define STM32_OTGFS_DOEPTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ0_OFFSET) +#define STM32_OTGFS_DOEPTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ1_OFFSET) +#define STM32_OTGFS_DOEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ2_OFFSET) +#define STM32_OTGFS_DOEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ3_OFFSET) + +/* Power and clock gating registers */ + +#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET) + +/* Data FIFO (DFIFO) access registers */ + +#define STM32_OTGFS_DFIFO_DEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP_OFFSET(n)) +#define STM32_OTGFS_DFIFO_HCH(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH_OFFSET(n)) + +#define STM32_OTGFS_DFIFO_DEP0 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP0_OFFSET) +#define STM32_OTGFS_DFIFO_HCH0 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH0_OFFSET) + +#define STM32_OTGFS_DFIFO_DEP1 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP1_OFFSET) +#define STM32_OTGFS_DFIFO_HCH1 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH1_OFFSET) + +#define STM32_OTGFS_DFIFO_DEP2 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP2_OFFSET) +#define STM32_OTGFS_DFIFO_HCH2 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH2_OFFSET) + +#define STM32_OTGFS_DFIFO_DEP3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP3_OFFSET) +#define STM32_OTGFS_DFIFO_HCH3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH3_OFFSET) + +/* Register Bitfield Definitions ********************************************************************/ +/* Core global control and status registers */ + +/* Control and status register */ + +#define OTGFS_GOTGCTL_SRQSCS (1 << 0) /* Bit 0: Session request success */ +#define OTGFS_GOTGCTL_SRQ (1 << 1) /* Bit 1: Session request */ +#define OTGFS_GOTGCTL_VBVALOEN (1 << 2) /* Bit 2: VBUS valid override enable */ +#define OTGFS_GOTGCTL_VBVALOVAL (1 << 3) /* Bit 3: VBUS valid override value */ +#define OTGFS_GOTGCTL_AVALOEN (1 << 4) /* Bit 4: A-peripheral session valid override enable */ +#define OTGFS_GOTGCTL_AVALOVAL (1 << 5) /* Bit 5: A-peripheral session valid override value */ +#define OTGFS_GOTGCTL_BVALOEN (1 << 6) /* Bit 6: B-peripheral session valid override enable */ +#define OTGFS_GOTGCTL_BVALOVAL (1 << 7) /* Bit 7: B-peripheral session valid override value */ +#define OTGFS_GOTGCTL_HNGSCS (1 << 8) /* Bit 8: Host set HNP enable */ +#define OTGFS_GOTGCTL_HNPRQ (1 << 9) /* Bit 9: HNP request */ +#define OTGFS_GOTGCTL_HSHNPEN (1 << 10) /* Bit 10: host set HNP enable */ +#define OTGFS_GOTGCTL_DHNPEN (1 << 11) /* Bit 11: Device HNP enabled */ +#define OTGFS_GOTGCTL_EHEN (1 << 12) /* Bit 12: Embedded host enable */ + /* Bits 13-15: Reserved, must be kept at reset value */ +#define OTGFS_GOTGCTL_CIDSTS (1 << 16) /* Bit 16: Connector ID status */ +#define OTGFS_GOTGCTL_DBCT (1 << 17) /* Bit 17: Long/short debounce time */ +#define OTGFS_GOTGCTL_ASVLD (1 << 18) /* Bit 18: A-session valid */ +#define OTGFS_GOTGCTL_BSVLD (1 << 19) /* Bit 19: B-session valid */ +#define OTGFS_GOTGCTL_OTGVER (1 << 20) /* Bit 20: OTG version */ + /* Bits 21-31: Reserved, must be kept at reset value */ + +/* Interrupt register */ + /* Bits 1:0 Reserved, must be kept at reset value */ +#define OTGFS_GOTGINT_SEDET (1 << 2) /* Bit 2: Session end detected */ + /* Bits 3-7: Reserved, must be kept at reset value */ +#define OTGFS_GOTGINT_SRSSCHG (1 << 8) /* Bit 8: Session request success status change */ +#define OTGFS_GOTGINT_HNSSCHG (1 << 9) /* Bit 9: Host negotiation success status change */ + /* Bits 16:10 Reserved, must be kept at reset value */ +#define OTGFS_GOTGINT_HNGDET (1 << 17) /* Bit 17: Host negotiation detected */ +#define OTGFS_GOTGINT_ADTOCHG (1 << 18) /* Bit 18: A-device timeout change */ +#define OTGFS_GOTGINT_DBCDNE (1 << 19) /* Bit 19: Debounce done */ +#define OTGFS_GOTGINT_IDCHNG (1 << 20) /* Bit 20: Change in ID pin input value */ + /* Bits 21-31: Reserved, must be kept at reset value */ + +/* AHB configuration register */ + +#define OTGFS_GAHBCFG_GINTMSK (1 << 0) /* Bit 0: Global interrupt mask */ + /* Bits 1-6: Reserved, must be kept at reset value */ +#define OTGFS_GAHBCFG_TXFELVL (1 << 7) /* Bit 7: TxFIFO empty level */ +#define OTGFS_GAHBCFG_PTXFELVL (1 << 8) /* Bit 8: Periodic TxFIFO empty level */ + /* Bits 20-31: Reserved, must be kept at reset value */ +/* USB configuration register */ + +#define OTGFS_GUSBCFG_TOCAL_SHIFT (0) /* Bits 0-2: FS timeout calibration */ +#define OTGFS_GUSBCFG_TOCAL_MASK (7 << OTGFS_GUSBCFG_TOCAL_SHIFT) + /* Bits 3-5: Reserved, must be kept at reset value */ +#define OTGFS_GUSBCFG_PHYSEL (1 << 6) /* Bit 6: Full Speed serial transceiver select */ + /* Bit 7: Reserved, must be kept at reset value */ +#define OTGFS_GUSBCFG_SRPCAP (1 << 8) /* Bit 8: SRP-capable */ +#define OTGFS_GUSBCFG_HNPCAP (1 << 9) /* Bit 9: HNP-capable */ +#define OTGFS_GUSBCFG_TRDT_SHIFT (10) /* Bits 10-13: USB turnaround time */ +#define OTGFS_GUSBCFG_TRDT_MASK (15 << OTGFS_GUSBCFG_TRDT_SHIFT) +# define OTGFS_GUSBCFG_TRDT(n) ((n) << OTGFS_GUSBCFG_TRDT_SHIFT) + /* Bits 14-28: Reserved, must be kept at reset value */ +#define OTGFS_GUSBCFG_FHMOD (1 << 29) /* Bit 29: Force host mode */ +#define OTGFS_GUSBCFG_FDMOD (1 << 30) /* Bit 30: Force device mode */ +#define OTGFS_GUSBCFG_CTXPKT (1 << 31) /* Bit 31: Corrupt Tx packet */ + /* Bits 20-31: Reserved, must be kept at reset value */ +/* Reset register */ + +#define OTGFS_GRSTCTL_CSRST (1 << 0) /* Bit 0: Core soft reset */ +#define OTGFS_GRSTCTL_HSRST (1 << 1) /* Bit 1: HCLK soft reset */ +#define OTGFS_GRSTCTL_FCRST (1 << 2) /* Bit 2: Host frame counter reset */ + /* Bit 3 Reserved, must be kept at reset value */ +#define OTGFS_GRSTCTL_RXFFLSH (1 << 4) /* Bit 4: RxFIFO flush */ +#define OTGFS_GRSTCTL_TXFFLSH (1 << 5) /* Bit 5: TxFIFO flush */ +#define OTGFS_GRSTCTL_TXFNUM_SHIFT (6) /* Bits 6-10: TxFIFO number */ +#define OTGFS_GRSTCTL_TXFNUM_MASK (31 << OTGFS_GRSTCTL_TXFNUM_SHIFT) +# define OTGFS_GRSTCTL_TXFNUM_HNONPER (0 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Non-periodic TxFIFO flush in host mode */ +# define OTGFS_GRSTCTL_TXFNUM_HPER (1 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Periodic TxFIFO flush in host mode */ +# define OTGFS_GRSTCTL_TXFNUM_HALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in host mode.*/ +# define OTGFS_GRSTCTL_TXFNUM_D(n) ((n) << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* TXFIFO n flush in device mode, n=0-15 */ +# define OTGFS_GRSTCTL_TXFNUM_DALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in device mode.*/ + /* Bits 11-31: Reserved, must be kept at reset value */ +#define OTGFS_GRSTCTL_AHBIDL (1 << 31) /* Bit 31: AHB master idle */ + +/* Core interrupt and Interrupt mask registers */ + +#define OTGFS_GINTSTS_CMOD (1 << 0) /* Bit 0: Current mode of operation */ +# define OTGFS_GINTSTS_DEVMODE (0) +# define OTGFS_GINTSTS_HOSTMODE (OTGFS_GINTSTS_CMOD) +#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: Mode mismatch interrupt */ +#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: OTG interrupt */ +#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: Start of frame */ +#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: RxFIFO non-empty */ +#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: Non-periodic TxFIFO empty */ +#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: Global IN non-periodic NAK effective */ +#define OTGFS_GINT_GONAKEFF (1 << 7) /* Bit 7: Global OUT NAK effective */ + /* Bits 8-9: Reserved, must be kept at reset value */ +#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: Early suspend */ +#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: USB suspend */ +#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: USB reset */ +#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: Enumeration done */ +#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: Isochronous OUT packet dropped interrupt */ +#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: End of periodic frame interrupt */ + /* Bits 16 Reserved, must be kept at reset value */ +#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Endpoint mismatch interrupt mask */ +#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: IN endpoint interrupt */ +#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: OUT endpoint interrupt */ +#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: Incomplete isochronous IN transfer */ +#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: Incomplete isochronous OUT transfer (device) */ +#define OTGFS_GINT_IPXFR (1 << 21) /* Bit 21: Incomplete periodic transfer (host) */ + /* Bit 22: Reserved, must be kept at reset value */ +#define OTGFS_GINT_RSTDET (1 << 23) /* Bit 23: Reset detected interrupt */ +#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: Host port interrupt */ +#define OTGFS_GINT_HC (1 << 25) /* Bit 25: Host channels interrupt */ +#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: Periodic TxFIFO empty */ +#define OTGFS_GINT_LPMINT (1 << 27) /* Bit 27: LPM interrupt */ +#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: Connector ID status change */ +#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: Disconnect detected interrupt */ +#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: Session request/new session detected interrupt */ +#define OTGFS_GINT_WKUP (1 << 31) /* Bit 31: Resume/remote wakeup detected interrupt */ + +/* Receive status debug read/OTG status read and pop registers (host mode) */ + +#define OTGFS_GRXSTSH_CHNUM_SHIFT (0) /* Bits 0-3: Channel number */ +#define OTGFS_GRXSTSH_CHNUM_MASK (15 << OTGFS_GRXSTSH_CHNUM_SHIFT) +#define OTGFS_GRXSTSH_BCNT_SHIFT (4) /* Bits 4-14: Byte count */ +#define OTGFS_GRXSTSH_BCNT_MASK (0x7ff << OTGFS_GRXSTSH_BCNT_SHIFT) +#define OTGFS_GRXSTSH_DPID_SHIFT (15) /* Bits 15-16: Data PID */ +#define OTGFS_GRXSTSH_DPID_MASK (3 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA0 (0 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA2 (1 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA1 (2 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_MDATA (3 << OTGFS_GRXSTSH_DPID_SHIFT) +#define OTGFS_GRXSTSH_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */ +#define OTGFS_GRXSTSH_PKTSTS_MASK (15 << OTGFS_GRXSTSH_PKTSTS_SHIFT) +# define OTGFS_GRXSTSH_PKTSTS_INRECVD (2 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN data packet received */ +# define OTGFS_GRXSTSH_PKTSTS_INDONE (3 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN transfer completed */ +# define OTGFS_GRXSTSH_PKTSTS_DTOGERR (5 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Data toggle error */ +# define OTGFS_GRXSTSH_PKTSTS_HALTED (7 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Channel halted */ + /* Bits 21-31: Reserved, must be kept at reset value */ +/* Receive status debug read/OTG status read and pop registers (device mode) */ + +#define OTGFS_GRXSTSD_EPNUM_SHIFT (0) /* Bits 0-3: Endpoint number */ +#define OTGFS_GRXSTSD_EPNUM_MASK (15 << OTGFS_GRXSTSD_EPNUM_SHIFT) +#define OTGFS_GRXSTSD_BCNT_SHIFT (4) /* Bits 4-14: Byte count */ +#define OTGFS_GRXSTSD_BCNT_MASK (0x7ff << OTGFS_GRXSTSD_BCNT_SHIFT) +#define OTGFS_GRXSTSD_DPID_SHIFT (15) /* Bits 15-16: Data PID */ +#define OTGFS_GRXSTSD_DPID_MASK (3 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA0 (0 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA2 (1 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA1 (2 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_MDATA (3 << OTGFS_GRXSTSD_DPID_SHIFT) +#define OTGFS_GRXSTSD_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */ +#define OTGFS_GRXSTSD_PKTSTS_MASK (15 << OTGFS_GRXSTSD_PKTSTS_SHIFT) +# define OTGFS_GRXSTSD_PKTSTS_OUTNAK (1 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* Global OUT NAK */ +# define OTGFS_GRXSTSD_PKTSTS_OUTRECVD (2 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT data packet received */ +# define OTGFS_GRXSTSD_PKTSTS_OUTDONE (3 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT transfer completed */ +# define OTGFS_GRXSTSD_PKTSTS_SETUPDONE (4 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP transaction completed */ +# define OTGFS_GRXSTSD_PKTSTS_SETUPRECVD (6 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP data packet received */ +#define OTGFS_GRXSTSD_FRMNUM_SHIFT (21) /* Bits 21-24: Frame number */ +#define OTGFS_GRXSTSD_FRMNUM_MASK (15 << OTGFS_GRXSTSD_FRMNUM_SHIFT) + /* Bits 25-31: Reserved, must be kept at reset value */ +/* Receive FIFO size register */ + +#define OTGFS_GRXFSIZ_MASK (0xffff) + +/* Host non-periodic transmit FIFO size register */ + +#define OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT (0) /* Bits 0-15: Non-periodic transmit RAM start address */ +#define OTGFS_HNPTXFSIZ_NPTXFSA_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT) +#define OTGFS_HNPTXFSIZ_NPTXFD_SHIFT (16) /* Bits 16-31: Non-periodic TxFIFO depth */ +#define OTGFS_HNPTXFSIZ_NPTXFD_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) +# define OTGFS_HNPTXFSIZ_NPTXFD_MIN (16 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) +# define OTGFS_HNPTXFSIZ_NPTXFD_MAX (256 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) + +/* Endpoint 0 Transmit FIFO size */ + +#define OTGFS_DIEPTXF0_TX0FD_SHIFT (0) /* Bits 0-15: Endpoint 0 transmit RAM start address */ +#define OTGFS_DIEPTXF0_TX0FD_MASK (0xffff << OTGFS_DIEPTXF0_TX0FD_SHIFT) +#define OTGFS_DIEPTXF0_TX0FSA_SHIFT (16) /* Bits 16-31: Endpoint 0 TxFIFO depth */ +#define OTGFS_DIEPTXF0_TX0FSA_MASK (0xffff << OTGFS_DIEPTXF0_TX0FSA_SHIFT) +# define OTGFS_DIEPTXF0_TX0FSA_MIN (16 << OTGFS_DIEPTXF0_TX0FSA_SHIFT) +# define OTGFS_DIEPTXF0_TX0FSA_MAX (256 << OTGFS_DIEPTXF0_TX0FSA_SHIFT) + +/* Non-periodic transmit FIFO/queue status register */ + +#define OTGFS_HNPTXSTS_NPTXFSAV_SHIFT (0) /* Bits 0-15: Non-periodic TxFIFO space available */ +#define OTGFS_HNPTXSTS_NPTXFSAV_MASK (0xffff << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) +# define OTGFS_HNPTXSTS_NPTXFSAV_FULL (0 << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) +#define OTGFS_HNPTXSTS_NPTQXSAV_SHIFT (16) /* Bits 16-23: Non-periodic transmit request queue space available */ +#define OTGFS_HNPTXSTS_NPTQXSAV_MASK (0xff << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT) +# define OTGFS_HNPTXSTS_NPTQXSAV_FULL (0 << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT) +#define OTGFS_HNPTXSTS_NPTXQTOP_SHIFT (24) /* Bits 24-30: Top of the non-periodic transmit request queue */ +#define OTGFS_HNPTXSTS_NPTXQTOP_MASK (0x7f << OTGFS_HNPTXSTS_NPTXQTOP_SHIFT) +# define OTGFS_HNPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */ +# define OTGFS_HNPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Status */ +# define OTGFS_HNPTXSTS_TYPE_MASK (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) +# define OTGFS_HNPTXSTS_TYPE_INOUT (0 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* IN/OUT token */ +# define OTGFS_HNPTXSTS_TYPE_ZLP (1 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet (device IN/host OUT) */ +# define OTGFS_HNPTXSTS_TYPE_HALT (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Channel halt command */ +# define OTGFS_HNPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */ +# define OTGFS_HNPTXSTS_CHNUM_MASK (15 << OTGFS_HNPTXSTS_CHNUM_SHIFT) +# define OTGFS_HNPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */ +# define OTGFS_HNPTXSTS_EPNUM_MASK (15 << OTGFS_HNPTXSTS_EPNUM_SHIFT) + /* Bit 31 Reserved, must be kept at reset value */ +/* General core configuration register */ + /* Bits 15:0 Reserved, must be kept at reset value */ +#define OTGFS_GCCFG_PWRDWN (1 << 16) /* Bit 16: Power down */ + /* Bit 17 Reserved, must be kept at reset value */ + /* Bits 18:20 Reserved, must be kept at reset value */ +#define OTGFS_GCCFG_VBDEN (1 << 21) /* Bit 21: USB VBUS detection enable */ + /* Bits 22:31 Reserved, must be kept at reset value */ +/* Core ID register (32-bit product ID) */ + +/* Host periodic transmit FIFO size register */ + +#define OTGFS_HPTXFSIZ_PTXSA_SHIFT (0) /* Bits 0-15: Host periodic TxFIFO start address */ +#define OTGFS_HPTXFSIZ_PTXSA_MASK (0xffff << OTGFS_HPTXFSIZ_PTXSA_SHIFT) +#define OTGFS_HPTXFSIZ_PTXFD_SHIFT (16) /* Bits 16-31: Host periodic TxFIFO depth */ +#define OTGFS_HPTXFSIZ_PTXFD_MASK (0xffff << OTGFS_HPTXFSIZ_PTXFD_SHIFT) + +/* Device IN endpoint transmit FIFOn size register */ + +#define OTGFS_DIEPTXF_INEPTXSA_SHIFT (0) /* Bits 0-15: IN endpoint FIFOx transmit RAM start address */ +#define OTGFS_DIEPTXF_INEPTXSA_MASK (0xffff << OTGFS_DIEPTXF_INEPTXSA_SHIFT) +#define OTGFS_DIEPTXF_INEPTXFD_SHIFT (16) /* Bits 16-31: IN endpoint TxFIFO depth */ +#define OTGFS_DIEPTXF_INEPTXFD_MASK (0xffff << OTGFS_DIEPTXF_INEPTXFD_SHIFT) +# define OTGFS_DIEPTXF_INEPTXFD_MIN (16 << OTGFS_DIEPTXF_INEPTXFD_MASK) + +/* Host-mode control and status registers */ + +/* Host configuration register */ + +#define OTGFS_HCFG_FSLSPCS_SHIFT (0) /* Bits 0-1: FS/LS PHY clock select */ +#define OTGFS_HCFG_FSLSPCS_MASK (3 << OTGFS_HCFG_FSLSPCS_SHIFT) +# define OTGFS_HCFG_FSLSPCS_FS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* FS host mode, PHY clock is running at 48 MHz */ +# define OTGFS_HCFG_FSLSPCS_LS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 48 MHz PHY clock frequency */ +# define OTGFS_HCFG_FSLSPCS_LS6MHz (2 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 6 MHz PHY clock frequency */ +#define OTGFS_HCFG_FSLSS (1 << 2) /* Bit 2: FS- and LS-only support */ + /* Bits 31:3 Reserved, must be kept at reset value */ +/* Host frame interval register */ + +#define OTGFS_HFIR_MASK (0xffff) + +/* Host frame number/frame time remaining register */ + +#define OTGFS_HFNUM_FRNUM_SHIFT (0) /* Bits 0-15: Frame number */ +#define OTGFS_HFNUM_FRNUM_MASK (0xffff << OTGFS_HFNUM_FRNUM_SHIFT) +#define OTGFS_HFNUM_FTREM_SHIFT (16) /* Bits 16-31: Frame time remaining */ +#define OTGFS_HFNUM_FTREM_MASK (0xffff << OTGFS_HFNUM_FTREM_SHIFT) + +/* Host periodic transmit FIFO/queue status register */ + +#define OTGFS_HPTXSTS_PTXFSAVL_SHIFT (0) /* Bits 0-15: Periodic transmit data FIFO space available */ +#define OTGFS_HPTXSTS_PTXFSAVL_MASK (0xffff << OTGFS_HPTXSTS_PTXFSAVL_SHIFT) +# define OTGFS_HPTXSTS_PTXFSAVL_FULL (0 << OTGFS_HPTXSTS_PTXFSAVL_SHIFT) +#define OTGFS_HPTXSTS_PTXQSAV_SHIFT (16) /* Bits 16-23: Periodic transmit request queue space available */ +#define OTGFS_HPTXSTS_PTXQSAV_MASK (0xff << OTGFS_HPTXSTS_PTXQSAV_SHIFT) +# define OTGFS_HPTXSTS_PTXQSAV_FULL (0 << OTGFS_HPTXSTS_PTXQSAV_SHIFT) +#define OTGFS_HPTXSTS_PTXQTOP_SHIFT (24) /* Bits 24-31: Top of the periodic transmit request queue */ +#define OTGFS_HPTXSTS_PTXQTOP_MASK (0x7f << OTGFS_HPTXSTS_PTXQTOP_SHIFT) +# define OTGFS_HPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */ +# define OTGFS_HPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Type */ +# define OTGFS_HPTXSTS_TYPE_MASK (3 << OTGFS_HPTXSTS_TYPE_SHIFT) +# define OTGFS_HPTXSTS_TYPE_INOUT (0 << OTGFS_HPTXSTS_TYPE_SHIFT) /* IN/OUT token */ +# define OTGFS_HPTXSTS_TYPE_ZLP (1 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet */ +# define OTGFS_HPTXSTS_TYPE_HALT (3 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Disable channel command */ +# define OTGFS_HPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */ +# define OTGFS_HPTXSTS_EPNUM_MASK (15 << OTGFS_HPTXSTS_EPNUM_SHIFT) +# define OTGFS_HPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */ +# define OTGFS_HPTXSTS_CHNUM_MASK (15 << OTGFS_HPTXSTS_CHNUM_SHIFT) +# define OTGFS_HPTXSTS_ODD (1 << 24) /* Bit 31: Send in odd (vs even) frame */ + +/* Host all channels interrupt and all channels interrupt mask registers */ + +#define OTGFS_HAINT(n) (1 << (n)) /* Bits 15:0 HAINTM: Channel interrupt */ + +/* Host port control and status register */ + +#define OTGFS_HPRT_PCSTS (1 << 0) /* Bit 0: Port connect status */ +#define OTGFS_HPRT_PCDET (1 << 1) /* Bit 1: Port connect detected */ +#define OTGFS_HPRT_PENA (1 << 2) /* Bit 2: Port enable */ +#define OTGFS_HPRT_PENCHNG (1 << 3) /* Bit 3: Port enable/disable change */ +#define OTGFS_HPRT_POCA (1 << 4) /* Bit 4: Port overcurrent active */ +#define OTGFS_HPRT_POCCHNG (1 << 5) /* Bit 5: Port overcurrent change */ +#define OTGFS_HPRT_PRES (1 << 6) /* Bit 6: Port resume */ +#define OTGFS_HPRT_PSUSP (1 << 7) /* Bit 7: Port suspend */ +#define OTGFS_HPRT_PRST (1 << 8) /* Bit 8: Port reset */ + /* Bit 9: Reserved, must be kept at reset value */ +#define OTGFS_HPRT_PLSTS_SHIFT (10) /* Bits 10-11: Port line status */ +#define OTGFS_HPRT_PLSTS_MASK (3 << OTGFS_HPRT_PLSTS_SHIFT) +# define OTGFS_HPRT_PLSTS_DP (1 << 10) /* Bit 10: Logic level of OTG_FS_FS_DP */ +# define OTGFS_HPRT_PLSTS_DM (1 << 11) /* Bit 11: Logic level of OTG_FS_FS_DM */ +#define OTGFS_HPRT_PPWR (1 << 12) /* Bit 12: Port power */ +#define OTGFS_HPRT_PTCTL_SHIFT (13) /* Bits 13-16: Port test control */ +#define OTGFS_HPRT_PTCTL_MASK (15 << OTGFS_HPRT_PTCTL_SHIFT) +# define OTGFS_HPRT_PTCTL_DISABLED (0 << OTGFS_HPRT_PTCTL_SHIFT) /* Test mode disabled */ +# define OTGFS_HPRT_PTCTL_J (1 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_J mode */ +# define OTGFS_HPRT_PTCTL_L (2 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_K mode */ +# define OTGFS_HPRT_PTCTL_SE0_NAK (3 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_SE0_NAK mode */ +# define OTGFS_HPRT_PTCTL_PACKET (4 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Packet mode */ +# define OTGFS_HPRT_PTCTL_FORCE (5 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Force_Enable */ +#define OTGFS_HPRT_PSPD_SHIFT (17) /* Bits 17-18: Port speed */ +#define OTGFS_HPRT_PSPD_MASK (3 << OTGFS_HPRT_PSPD_SHIFT) +# define OTGFS_HPRT_PSPD_FS (1 << OTGFS_HPRT_PSPD_SHIFT) /* Full speed */ +# define OTGFS_HPRT_PSPD_LS (2 << OTGFS_HPRT_PSPD_SHIFT) /* Low speed */ + /* Bits 19-31: Reserved, must be kept at reset value */ + +/* Host channel-n characteristics register */ + +#define OTGFS_HCCHAR_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_HCCHAR_MPSIZ_MASK (0x7ff << OTGFS_HCCHAR_MPSIZ_SHIFT) +#define OTGFS_HCCHAR_EPNUM_SHIFT (11) /* Bits 11-14: Endpoint number */ +#define OTGFS_HCCHAR_EPNUM_MASK (15 << OTGFS_HCCHAR_EPNUM_SHIFT) +#define OTGFS_HCCHAR_EPDIR (1 << 15) /* Bit 15: Endpoint direction */ +# define OTGFS_HCCHAR_EPDIR_OUT (0) +# define OTGFS_HCCHAR_EPDIR_IN OTGFS_HCCHAR_EPDIR + /* Bit 16 Reserved, must be kept at reset value */ +#define OTGFS_HCCHAR_LSDEV (1 << 17) /* Bit 17: Low-speed device */ +#define OTGFS_HCCHAR_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_HCCHAR_EPTYP_MASK (3 << OTGFS_HCCHAR_EPTYP_SHIFT) +# define OTGFS_HCCHAR_EPTYP_CTRL (0 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Control */ +# define OTGFS_HCCHAR_EPTYP_ISOC (1 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_HCCHAR_EPTYP_BULK (2 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_HCCHAR_EPTYP_INTR (3 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Interrupt */ +#define OTGFS_HCCHAR_MCNT_SHIFT (20) /* Bits 20-21: Multicount */ +#define OTGFS_HCCHAR_MCNT_MASK (3 << OTGFS_HCCHAR_MCNT_SHIFT) +#define OTGFS_HCCHAR_DAD_SHIFT (22) /* Bits 22-28: Device address */ +#define OTGFS_HCCHAR_DAD_MASK (0x7f << OTGFS_HCCHAR_DAD_SHIFT) +#define OTGFS_HCCHAR_ODDFRM (1 << 29) /* Bit 29: Odd frame */ +#define OTGFS_HCCHAR_CHDIS (1 << 30) /* Bit 30: Channel disable */ +#define OTGFS_HCCHAR_CHENA (1 << 31) /* Bit 31: Channel enable */ + +/* Host channel-n interrupt and Host channel-0 interrupt mask registers */ + +#define OTGFS_HCINT_XFRC (1 << 0) /* Bit 0: Transfer completed */ +#define OTGFS_HCINT_CHH (1 << 1) /* Bit 1: Channel halted */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_HCINT_STALL (1 << 3) /* Bit 3: STALL response received interrupt */ +#define OTGFS_HCINT_NAK (1 << 4) /* Bit 4: NAK response received interrupt */ +#define OTGFS_HCINT_ACK (1 << 5) /* Bit 5: ACK response received/transmitted interrupt */ +#define OTGFS_HCINT_NYET (1 << 6) /* Bit 6: Response received interrupt */ +#define OTGFS_HCINT_TXERR (1 << 7) /* Bit 7: Transaction error */ +#define OTGFS_HCINT_BBERR (1 << 8) /* Bit 8: Babble error */ +#define OTGFS_HCINT_FRMOR (1 << 9) /* Bit 9: Frame overrun */ +#define OTGFS_HCINT_DTERR (1 << 10) /* Bit 10: Data toggle error */ + /* Bits 11-31 Reserved, must be kept at reset value */ +/* Host channel-n interrupt register */ + +#define OTGFS_HCTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_HCTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_HCTSIZ_XFRSIZ_SHIFT) +#define OTGFS_HCTSIZ_PKTCNT_SHIFT (19) /* Bits 19-28: Packet count */ +#define OTGFS_HCTSIZ_PKTCNT_MASK (0x3ff << OTGFS_HCTSIZ_PKTCNT_SHIFT) +#define OTGFS_HCTSIZ_DPID_SHIFT (29) /* Bits 29-30: Data PID */ +#define OTGFS_HCTSIZ_DPID_MASK (3 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA0 (0 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA2 (1 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA1 (2 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_MDATA (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Non-control */ +# define OTGFS_HCTSIZ_PID_SETUP (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Control */ + /* Bit 31 Reserved, must be kept at reset value */ +/* Device-mode control and status registers */ + +/* Device configuration register */ + +#define OTGFS_DCFG_DSPD_SHIFT (0) /* Bits 0-1: Device speed */ +#define OTGFS_DCFG_DSPD_MASK (3 << OTGFS_DCFG_DSPD_SHIFT) +# define OTGFS_DCFG_DSPD_FS (3 << OTGFS_DCFG_DSPD_SHIFT) /* Full speed */ +#define OTGFS_DCFG_NZLSOHSK (1 << 2) /* Bit 2: Non-zero-length status OUT handshake */ + /* Bit 3: Reserved, must be kept at reset value */ +#define OTGFS_DCFG_DAD_SHIFT (4) /* Bits 4-10: Device address */ +#define OTGFS_DCFG_DAD_MASK (0x7f << OTGFS_DCFG_DAD_SHIFT) +#define OTGFS_DCFG_PFIVL_SHIFT (11) /* Bits 11-12: Periodic frame interval */ +#define OTGFS_DCFG_PFIVL_MASK (3 << OTGFS_DCFG_PFIVL_SHIFT) +# define OTGFS_DCFG_PFIVL_80PCT (0 << OTGFS_DCFG_PFIVL_SHIFT) /* 80% of the frame interval */ +# define OTGFS_DCFG_PFIVL_85PCT (1 << OTGFS_DCFG_PFIVL_SHIFT) /* 85% of the frame interval */ +# define OTGFS_DCFG_PFIVL_90PCT (2 << OTGFS_DCFG_PFIVL_SHIFT) /* 90% of the frame interval */ +# define OTGFS_DCFG_PFIVL_95PCT (3 << OTGFS_DCFG_PFIVL_SHIFT) /* 95% of the frame interval */ + /* Bits 13-31 Reserved, must be kept at reset value */ +/* Device control register */ + +#define OTGFS_TESTMODE_DISABLED (0) /* Test mode disabled */ +#define OTGFS_TESTMODE_J (1) /* Test_J mode */ +#define OTGFS_TESTMODE_K (2) /* Test_K mode */ +#define OTGFS_TESTMODE_SE0_NAK (3) /* Test_SE0_NAK mode */ +#define OTGFS_TESTMODE_PACKET (4) /* Test_Packet mode */ +#define OTGFS_TESTMODE_FORCE (5) /* Test_Force_Enable */ + +#define OTGFS_DCTL_RWUSIG (1 << 0) /* Bit 0: Remote wakeup signaling */ +#define OTGFS_DCTL_SDIS (1 << 1) /* Bit 1: Soft disconnect */ +#define OTGFS_DCTL_GINSTS (1 << 2) /* Bit 2: Global IN NAK status */ +#define OTGFS_DCTL_GONSTS (1 << 3) /* Bit 3: Global OUT NAK status */ +#define OTGFS_DCTL_TCTL_SHIFT (4) /* Bits 4-6: Test control */ +#define OTGFS_DCTL_TCTL_MASK (7 << OTGFS_DCTL_TCTL_SHIFT) +# define OTGFS_DCTL_TCTL_DISABLED (0 << OTGFS_DCTL_TCTL_SHIFT) /* Test mode disabled */ +# define OTGFS_DCTL_TCTL_J (1 << OTGFS_DCTL_TCTL_SHIFT) /* Test_J mode */ +# define OTGFS_DCTL_TCTL_K (2 << OTGFS_DCTL_TCTL_SHIFT) /* Test_K mode */ +# define OTGFS_DCTL_TCTL_SE0_NAK (3 << OTGFS_DCTL_TCTL_SHIFT) /* Test_SE0_NAK mode */ +# define OTGFS_DCTL_TCTL_PACKET (4 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Packet mode */ +# define OTGFS_DCTL_TCTL_FORCE (5 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Force_Enable */ +#define OTGFS_DCTL_SGINAK (1 << 7) /* Bit 7: Set global IN NAK */ +#define OTGFS_DCTL_CGINAK (1 << 8) /* Bit 8: Clear global IN NAK */ +#define OTGFS_DCTL_SGONAK (1 << 9) /* Bit 9: Set global OUT NAK */ +#define OTGFS_DCTL_CGONAK (1 << 10) /* Bit 10: Clear global OUT NAK */ +#define OTGFS_DCTL_POPRGDNE (1 << 11) /* Bit 11: Power-on programming done */ + /* Bits 12-31: Reserved, must be kept at reset value */ +/* Device status register */ + +#define OTGFS_DSTS_SUSPSTS (1 << 0) /* Bit 0: Suspend status */ +#define OTGFS_DSTS_ENUMSPD_SHIFT (1) /* Bits 1-2: Enumerated speed */ +#define OTGFS_DSTS_ENUMSPD_MASK (3 << OTGFS_DSTS_ENUMSPD_SHIFT) +# define OTGFS_DSTS_ENUMSPD_FS (3 << OTGFS_DSTS_ENUMSPD_MASK) /* Full speed */ + /* Bits 4-7: Reserved, must be kept at reset value */ +#define OTGFS_DSTS_EERR (1 << 3) /* Bit 3: Erratic error */ +#define OTGFS_DSTS_SOFFN_SHIFT (8) /* Bits 8-21: Frame number of the received SOF */ +#define OTGFS_DSTS_SOFFN_MASK (0x3fff << OTGFS_DSTS_SOFFN_SHIFT) +#define OTGFS_DSTS_SOFFN0 (1 << 8) /* Bits 8: Frame number even/odd bit */ +#define OTGFS_DSTS_SOFFN_EVEN 0 +#define OTGFS_DSTS_SOFFN_ODD OTGFS_DSTS_SOFFN0 + /* Bits 22-31: Reserved, must be kept at reset value */ +/* Device IN endpoint common interrupt mask register */ + +#define OTGFS_DIEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */ +#define OTGFS_DIEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DIEPMSK_TOM (1 << 3) /* Bit 3: Timeout condition mask (Non-isochronous endpoints) */ +#define OTGFS_DIEPMSK_ITTXFEMSK (1 << 4) /* Bit 4: IN token received when TxFIFO empty mask */ +#define OTGFS_DIEPMSK_INEPNMM (1 << 5) /* Bit 5: IN token received with EP mismatch mask */ +#define OTGFS_DIEPMSK_INEPNEM (1 << 6) /* Bit 6: IN endpoint NAK effective mask */ + /* Bits 7-31: Reserved, must be kept at reset value */ +/* Device OUT endpoint common interrupt mask register */ + +#define OTGFS_DOEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */ +#define OTGFS_DOEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DOEPMSK_STUPM (1 << 3) /* Bit 3: SETUP phase done mask */ +#define OTGFS_DOEPMSK_OTEPDM (1 << 4) /* Bit 4: OUT token received when endpoint disabled mask */ + /* Bits 5-31: Reserved, must be kept at reset value */ +/* Device all endpoints interrupt and All endpoints interrupt mask registers */ + +#define OTGFS_DAINT_IEP_SHIFT (0) /* Bits 0-15: IN endpoint interrupt bits */ +#define OTGFS_DAINT_IEP_MASK (0xffff << OTGFS_DAINT_IEP_SHIFT) +# define OTGFS_DAINT_IEP(n) (1 << (n)) +#define OTGFS_DAINT_OEP_SHIFT (16) /* Bits 16-31: OUT endpoint interrupt bits */ +#define OTGFS_DAINT_OEP_MASK (0xffff << OTGFS_DAINT_OEP_SHIFT) +# define OTGFS_DAINT_OEP(n) (1 << ((n)+16)) + +/* Device VBUS discharge time register */ + +#define OTGFS_DVBUSDIS_MASK (0xffff) + +/* Device VBUS pulsing time register */ + +#define OTGFS_DVBUSPULSE_MASK (0xfff) + +/* Device IN endpoint FIFO empty interrupt mask register */ + +#define OTGFS_DIEPEMPMSK(n) (1 << (n)) + +/* Device control IN endpoint 0 control register */ + +#define OTGFS_DIEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */ +#define OTGFS_DIEPCTL0_MPSIZ_MASK (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) +# define OTGFS_DIEPCTL0_MPSIZ_64 (0 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 64 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_32 (1 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 32 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_16 (2 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 16 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_8 (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 8 bytes */ + /* Bits 2-14: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ + /* Bit 16: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DIEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DIEPCTL0_EPTYP_MASK (3 << OTGFS_DIEPCTL0_EPTYP_SHIFT) +# define OTGFS_DIEPCTL0_EPTYP_CTRL (0 << OTGFS_DIEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */ + /* Bit 20: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */ +#define OTGFS_DIEPCTL0_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */ +#define OTGFS_DIEPCTL0_TXFNUM_MASK (15 << OTGFS_DIEPCTL0_TXFNUM_SHIFT) +#define OTGFS_DIEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DIEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */ + /* Bits 28-29: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DIEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device control IN endpoint n control register */ + +#define OTGFS_DIEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_DIEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DIEPCTL_MPSIZ_SHIFT) + /* Bits 11-14: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ +#define OTGFS_DIEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame */ +# define OTGFS_DIEPCTL_EVEN (0) +# define OTGFS_DIEPCTL_ODD OTGFS_DIEPCTL_EONUM +# define OTGFS_DIEPCTL_DATA0 (0) +# define OTGFS_DIEPCTL_DATA1 OTGFS_DIEPCTL_EONUM +#define OTGFS_DIEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DIEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DIEPCTL_EPTYP_MASK (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) +# define OTGFS_DIEPCTL_EPTYP_CTRL (0 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Control */ +# define OTGFS_DIEPCTL_EPTYP_ISOC (1 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_DIEPCTL_EPTYP_BULK (2 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_DIEPCTL_EPTYP_INTR (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Interrupt */ + /* Bit 20: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */ +#define OTGFS_DIEPCTL_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */ +#define OTGFS_DIEPCTL_TXFNUM_MASK (15 << OTGFS_DIEPCTL_TXFNUM_SHIFT) +#define OTGFS_DIEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DIEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */ +#define OTGFS_DIEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */ +#define OTGFS_DIEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous)) */ +#define OTGFS_DIEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous) */ +#define OTGFS_DIEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DIEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device endpoint-n interrupt register */ + +#define OTGFS_DIEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */ +#define OTGFS_DIEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DIEPINT_TOC (1 << 3) /* Bit 3: Timeout condition */ +#define OTGFS_DIEPINT_ITTXFE (1 << 4) /* Bit 4: IN token received when TxFIFO is empty */ + /* Bit 5: Reserved, must be kept at reset value */ +#define OTGFS_DIEPINT_INEPNE (1 << 6) /* Bit 6: IN endpoint NAK effective */ +#define OTGFS_DIEPINT_TXFE (1 << 7) /* Bit 7: Transmit FIFO empty */ + /* Bits 8-31: Reserved, must be kept at reset value */ +/* Device IN endpoint 0 transfer size register */ + +#define OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */ +#define OTGFS_DIEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT) + /* Bits 7-18: Reserved, must be kept at reset value */ +#define OTGFS_DIEPTSIZ0_PKTCNT_SHIFT (19) /* Bits 19-20: Packet count */ +#define OTGFS_DIEPTSIZ0_PKTCNT_MASK (3 << OTGFS_DIEPTSIZ0_PKTCNT_SHIFT) + /* Bits 21-31: Reserved, must be kept at reset value */ +/* Device IN endpoint n transfer size register */ + +#define OTGFS_DIEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_DIEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DIEPTSIZ_XFRSIZ_SHIFT) +#define OTGFS_DIEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */ +#define OTGFS_DIEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DIEPTSIZ_PKTCNT_SHIFT) +#define OTGFS_DIEPTSIZ_MCNT_SHIFT (29) /* Bits 29-30: Multi count */ +#define OTGFS_DIEPTSIZ_MCNT_MASK (3 << OTGFS_DIEPTSIZ_MCNT_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ +/* Device OUT endpoint TxFIFO status register */ + +#define OTGFS_DTXFSTS_MASK (0xffff) + +/* Device OUT endpoint 0 control register */ + +#define OTGFS_DOEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */ +#define OTGFS_DOEPCTL0_MPSIZ_MASK (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) +# define OTGFS_DOEPCTL0_MPSIZ_64 (0 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 64 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_32 (1 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 32 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_16 (2 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 16 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_8 (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 8 bytes */ + /* Bits 2-14: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ + /* Bit 16: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DOEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DOEPCTL0_EPTYP_MASK (3 << OTGFS_DOEPCTL0_EPTYP_SHIFT) +# define OTGFS_DOEPCTL0_EPTYP_CTRL (0 << OTGFS_DOEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */ +#define OTGFS_DOEPCTL0_SNPM (1 << 20) /* Bit 20: Snoop mode */ +#define OTGFS_DOEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */ + /* Bits 22-25: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DOEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */ + /* Bits 28-29: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DOEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device OUT endpoint n control register */ + +#define OTGFS_DOEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_DOEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DOEPCTL_MPSIZ_SHIFT) + /* Bits 11-14: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ +#define OTGFS_DOEPCTL_DPID (1 << 16) /* Bit 16: Endpoint data PID (interrupt/buld) */ +# define OTGFS_DOEPCTL_DATA0 (0) +# define OTGFS_DOEPCTL_DATA1 OTGFS_DOEPCTL_DPID +#define OTGFS_DOEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame (isochronous) */ +# define OTGFS_DOEPCTL_EVEN (0) +# define OTGFS_DOEPCTL_ODD OTGFS_DOEPCTL_EONUM +#define OTGFS_DOEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DOEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DOEPCTL_EPTYP_MASK (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) +# define OTGFS_DOEPCTL_EPTYP_CTRL (0 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Control */ +# define OTGFS_DOEPCTL_EPTYP_ISOC (1 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_DOEPCTL_EPTYP_BULK (2 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_DOEPCTL_EPTYP_INTR (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Interrupt */ +#define OTGFS_DOEPCTL_SNPM (1 << 20) /* Bit 20: Snoop mode */ +#define OTGFS_DOEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */ + /* Bits 22-25: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DOEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */ +#define OTGFS_DOEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */ +#define OTGFS_DOEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous) */ +#define OTGFS_DOEPCTL_SD1PID (1 << 29) /* Bit 29: Set DATA1 PID (interrupt/bulk) */ +#define OTGFS_DOEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous */ +#define OTGFS_DOEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DOEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device endpoint-n interrupt register */ + +#define OTGFS_DOEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */ +#define OTGFS_DOEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DOEPINT_SETUP (1 << 3) /* Bit 3: SETUP phase done */ +#define OTGFS_DOEPINT_OTEPDIS (1 << 4) /* Bit 4: OUT token received when endpoint disabled */ + /* Bit 5: Reserved, must be kept at reset value */ +#define OTGFS_DOEPINT_B2BSTUP (1 << 6) /* Bit 6: Back-to-back SETUP packets received */ + /* Bits 7-31: Reserved, must be kept at reset value */ +/* Device OUT endpoint-0 transfer size register */ + +#define OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */ +#define OTGFS_DOEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) + /* Bits 7-18: Reserved, must be kept at reset value */ +#define OTGFS_DOEPTSIZ0_PKTCNT (1 << 19) /* Bit 19 PKTCNT: Packet count */ + /* Bits 20-28: Reserved, must be kept at reset value */ +#define OTGFS_DOEPTSIZ0_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */ +#define OTGFS_DOEPTSIZ0_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ +/* Device OUT endpoint-n transfer size register */ + +#define OTGFS_DOEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_DOEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DOEPTSIZ_XFRSIZ_SHIFT) +#define OTGFS_DOEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */ +#define OTGFS_DOEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DOEPTSIZ_PKTCNT_SHIFT) +#define OTGFS_DOEPTSIZ_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */ +#define OTGFS_DOEPTSIZ_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ_STUPCNT_SHIFT) +#define OTGFS_DOEPTSIZ_RXDPID_SHIFT (29) /* Bits 29-30: Received data PID */ +#define OTGFS_DOEPTSIZ_RXDPID_MASK (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA0 (0 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA2 (1 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA1 (2 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_MDATA (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ +/* Power and clock gating control register */ + +#define OTGFS_PCGCCTL_STPPCLK (1 << 0) /* Bit 0: Stop PHY clock */ +#define OTGFS_PCGCCTL_GATEHCLK (1 << 1) /* Bit 1: Gate HCLK */ + /* Bits 2-3: Reserved, must be kept at reset value */ +#define OTGFS_PCGCCTL_PHYSUSP (1 << 4) /* Bit 4: PHY Suspended */ + /* Bits 5-31: Reserved, must be kept at reset value */ + +#endif /* __ARCH_ARM_SRC_STM32_CHIP_STM32F44XXX_OTGFS_H */ diff --git a/arch/arm/src/stm32/chip/stm32f44xxx_rcc.h b/arch/arm/src/stm32/chip/stm32f44xxx_rcc.h index 9328e62dd8f..4ea159e16a6 100644 --- a/arch/arm/src/stm32/chip/stm32f44xxx_rcc.h +++ b/arch/arm/src/stm32/chip/stm32f44xxx_rcc.h @@ -536,10 +536,13 @@ #define RCC_PLLI2SCFGR_PLLI2SN_SHIFT (6) /* Bits 6-14: PLLI2S N multiplication factor for VCO */ #define RCC_PLLI2SCFGR_PLLI2SN_MASK (0x1ff << RCC_PLLI2SCFGR_PLLI2SN_SHIFT) # define RCC_PLLI2SCFGR_PLLI2SN(n) ((n) << RCC_PLLI2SCFGR_PLLI2SN_SHIFT) - #define RCC_PLLI2SCFGR_PLLI2SP_SHIFT (16) /* Bits 16-17: PLLI2S division factor for SPDIF-Rx clock */ #define RCC_PLLI2SCFGR_PLLI2SP_MASK (0x1ff << RCC_PLLI2SCFGR_PLLI2SP_SHIFT) # define RCC_PLLI2SCFGR_PLLI2SP(n) ((n) << RCC_PLLI2SCFGR_PLLI2SP_SHIFT) +# define RCC_PLLI2SCFGR_PLLI2SP_2 RCC_PLLI2SCFGR_PLLI2SP(0) /* 00: PLLI2S = 2 */ +# define RCC_PLLI2SCFGR_PLLI2SP_4 RCC_PLLI2SCFGR_PLLI2SP(1) /* 01: PLLI2S = 4 */ +# define RCC_PLLI2SCFGR_PLLI2SP_6 RCC_PLLI2SCFGR_PLLI2SP(2) /* 10: PLLI2S = 6 */ +# define RCC_PLLI2SCFGR_PLLI2SP_8 RCC_PLLI2SCFGR_PLLI2SP(3) /* 11: PLLI2S = 8 */ #define RCC_PLLI2SCFGR_PLLI2SQ_SHIFT (24) /* Bits 24-27: PLLI2S division factor for SAI1 clock*/ #define RCC_PLLI2SCFGR_PLLI2SQ_MASK (0xf << RCC_PLLI2SCFGR_PLLI2SQ_SHIFT) @@ -563,7 +566,10 @@ #define RCC_PLLSAICFGR_PLLSAIP_SHIFT (16) /* Bits 16-17: PLLSAI division factor for 48 MHz clock */ #define RCC_PLLSAICFGR_PLLSAIP_MASK (3 << RCC_PLLSAICFGR_PLLSAIP_SHIFT) # define RCC_PLLSAICFGR_PLLSAIP(n) ((n) << RCC_PLLSAICFGR_PLLSAIP_SHIFT) - +# define RCC_PLLSAICFGR_PLLSAI_2 RCC_PLLSAICFGR_PLLSAIP(0) /* 00: PLLSAI = 2 */ +# define RCC_PLLSAICFGR_PLLSAI_4 RCC_PLLSAICFGR_PLLSAIP(1) /* 01: PLLSAI = 4 */ +# define RCC_PLLSAICFGR_PLLSAI_6 RCC_PLLSAICFGR_PLLSAIP(2) /* 10: PLLSAI = 6 */ +# define RCC_PLLSAICFGR_PLLSAI_8 RCC_PLLSAICFGR_PLLSAIP(3) /* 11: PLLSAI = 8 */ #define RCC_PLLSAICFGR_PLLSAIQ_SHIFT (24) /* Bits 24-27: PLLSAI division factor for SAI clock */ #define RCC_PLLSAICFGR_PLLSAIQ_MASK (0x0F << RCC_PLLSAICFGR_PLLSAIQ_SHIFT) # define RCC_PLLSAICFGR_PLLSAIQ(n) ((n) << RCC_PLLSAICFGR_PLLSAIQ_SHIFT) diff --git a/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h b/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h new file mode 100644 index 00000000000..d799b98738a --- /dev/null +++ b/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h @@ -0,0 +1,1014 @@ +/**************************************************************************************************** + * arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h + * + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32_CHIP_STM32FXXXXX_OTGFS_H +#define __ARCH_ARM_SRC_STM32_CHIP_STM32FXXXXX_OTGFS_H + +/**************************************************************************************************** + * Included Files + ****************************************************************************************************/ +/**************************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************************/ +/* General definitions */ + +#define OTGFS_EPTYPE_CTRL (0) /* Control */ +#define OTGFS_EPTYPE_ISOC (1) /* Isochronous */ +#define OTGFS_EPTYPE_BULK (2) /* Bulk */ +#define OTGFS_EPTYPE_INTR (3) /* Interrupt */ + +#define OTGFS_PID_DATA0 (0) +#define OTGFS_PID_DATA2 (1) +#define OTGFS_PID_DATA1 (2) +#define OTGFS_PID_MDATA (3) /* Non-control */ +#define OTGFS_PID_SETUP (3) /* Control */ + +/* Register Offsets *********************************************************************************/ +/* Core global control and status registers */ + +#define STM32_OTGFS_GOTGCTL_OFFSET 0x0000 /* Control and status register */ +#define STM32_OTGFS_GOTGINT_OFFSET 0x0004 /* Interrupt register */ +#define STM32_OTGFS_GAHBCFG_OFFSET 0x0008 /* AHB configuration register */ +#define STM32_OTGFS_GUSBCFG_OFFSET 0x000c /* USB configuration register */ +#define STM32_OTGFS_GRSTCTL_OFFSET 0x0010 /* Reset register */ +#define STM32_OTGFS_GINTSTS_OFFSET 0x0014 /* Core interrupt register */ +#define STM32_OTGFS_GINTMSK_OFFSET 0x0018 /* Interrupt mask register */ +#define STM32_OTGFS_GRXSTSR_OFFSET 0x001c /* Receive status debug read/OTG status read register */ +#define STM32_OTGFS_GRXSTSP_OFFSET 0x0020 /* Receive status debug read/OTG status pop register */ +#define STM32_OTGFS_GRXFSIZ_OFFSET 0x0024 /* Receive FIFO size register */ +#define STM32_OTGFS_HNPTXFSIZ_OFFSET 0x0028 /* Host non-periodic transmit FIFO size register */ +#define STM32_OTGFS_DIEPTXF0_OFFSET 0x0028 /* Endpoint 0 Transmit FIFO size */ +#define STM32_OTGFS_HNPTXSTS_OFFSET 0x002c /* Non-periodic transmit FIFO/queue status register */ +#define STM32_OTGFS_GCCFG_OFFSET 0x0038 /* General core configuration register */ +#define STM32_OTGFS_CID_OFFSET 0x003c /* Core ID register */ +#define STM32_OTGFS_HPTXFSIZ_OFFSET 0x0100 /* Host periodic transmit FIFO size register */ + +#define STM32_OTGFS_DIEPTXF_OFFSET(n) (104+(((n)-1) << 2)) +#define STM32_OTGFS_DIEPTXF1_OFFSET 0x0104 /* Device IN endpoint transmit FIFO1 size register */ +#define STM32_OTGFS_DIEPTXF2_OFFSET 0x0108 /* Device IN endpoint transmit FIFO2 size register */ +#define STM32_OTGFS_DIEPTXF3_OFFSET 0x010c /* Device IN endpoint transmit FIFO3 size register */ + +/* Host-mode control and status registers */ + +#define STM32_OTGFS_HCFG_OFFSET 0x0400 /* Host configuration register */ +#define STM32_OTGFS_HFIR_OFFSET 0x0404 /* Host frame interval register */ +#define STM32_OTGFS_HFNUM_OFFSET 0x0408 /* Host frame number/frame time remaining register */ +#define STM32_OTGFS_HPTXSTS_OFFSET 0x0410 /* Host periodic transmit FIFO/queue status register */ +#define STM32_OTGFS_HAINT_OFFSET 0x0414 /* Host all channels interrupt register */ +#define STM32_OTGFS_HAINTMSK_OFFSET 0x0418 /* Host all channels interrupt mask register */ +#define STM32_OTGFS_HPRT_OFFSET 0x0440 /* Host port control and status register */ + +#define STM32_OTGFS_CHAN_OFFSET(n) (0x500 + ((n) << 5) +#define STM32_OTGFS_HCCHAR_CHOFFSET 0x0000 /* Host channel characteristics register */ +#define STM32_OTGFS_HCINT_CHOFFSET 0x0008 /* Host channel interrupt register */ +#define STM32_OTGFS_HCINTMSK_CHOFFSET 0x000c /* Host channel interrupt mask register */ +#define STM32_OTGFS_HCTSIZ_CHOFFSET 0x0010 /* Host channel interrupt register */ + +#define STM32_OTGFS_HCCHAR_OFFSET(n) (0x500 + ((n) << 5)) +#define STM32_OTGFS_HCCHAR0_OFFSET 0x0500 /* Host channel-0 characteristics register */ +#define STM32_OTGFS_HCCHAR1_OFFSET 0x0520 /* Host channel-1 characteristics register */ +#define STM32_OTGFS_HCCHAR2_OFFSET 0x0540 /* Host channel-2 characteristics register */ +#define STM32_OTGFS_HCCHAR3_OFFSET 0x0560 /* Host channel-3 characteristics register */ +#define STM32_OTGFS_HCCHAR4_OFFSET 0x0580 /* Host channel-4 characteristics register */ +#define STM32_OTGFS_HCCHAR5_OFFSET 0x05a0 /* Host channel-5 characteristics register */ +#define STM32_OTGFS_HCCHAR6_OFFSET 0x05c0 /* Host channel-6 characteristics register */ +#define STM32_OTGFS_HCCHAR7_OFFSET 0x05e0 /* Host channel-7 characteristics register */ + +#define STM32_OTGFS_HCINT_OFFSET(n) (0x508 + ((n) << 5)) +#define STM32_OTGFS_HCINT0_OFFSET 0x0508 /* Host channel-0 interrupt register */ +#define STM32_OTGFS_HCINT1_OFFSET 0x0528 /* Host channel-1 interrupt register */ +#define STM32_OTGFS_HCINT2_OFFSET 0x0548 /* Host channel-2 interrupt register */ +#define STM32_OTGFS_HCINT3_OFFSET 0x0568 /* Host channel-3 interrupt register */ +#define STM32_OTGFS_HCINT4_OFFSET 0x0588 /* Host channel-4 interrupt register */ +#define STM32_OTGFS_HCINT5_OFFSET 0x05a8 /* Host channel-5 interrupt register */ +#define STM32_OTGFS_HCINT6_OFFSET 0x05c8 /* Host channel-6 interrupt register */ +#define STM32_OTGFS_HCINT7_OFFSET 0x05e8 /* Host channel-7 interrupt register */ + +#define STM32_OTGFS_HCINTMSK_OFFSET(n) (0x50c + ((n) << 5)) +#define STM32_OTGFS_HCINTMSK0_OFFSET 0x050c /* Host channel-0 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK1_OFFSET 0x052c /* Host channel-1 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK2_OFFSET 0x054c /* Host channel-2 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK3_OFFSET 0x056c /* Host channel-3 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK4_OFFSET 0x058c /* Host channel-4 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK5_OFFSET 0x05ac /* Host channel-5 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK6_OFFSET 0x05cc /* Host channel-6 interrupt mask register */ +#define STM32_OTGFS_HCINTMSK7_OFFSET 0x05ec /* Host channel-7 interrupt mask register */ + +#define STM32_OTGFS_HCTSIZ_OFFSET(n) (0x510 + ((n) << 5)) +#define STM32_OTGFS_HCTSIZ0_OFFSET 0x0510 /* Host channel-0 interrupt register */ +#define STM32_OTGFS_HCTSIZ1_OFFSET 0x0530 /* Host channel-1 interrupt register */ +#define STM32_OTGFS_HCTSIZ2_OFFSET 0x0550 /* Host channel-2 interrupt register */ +#define STM32_OTGFS_HCTSIZ3_OFFSET 0x0570 /* Host channel-3 interrupt register */ +#define STM32_OTGFS_HCTSIZ4_OFFSET 0x0590 /* Host channel-4 interrupt register */ +#define STM32_OTGFS_HCTSIZ5_OFFSET 0x05b0 /* Host channel-5 interrupt register */ +#define STM32_OTGFS_HCTSIZ6_OFFSET 0x05d0 /* Host channel-6 interrupt register */ +#define STM32_OTGFS_HCTSIZ7_OFFSET 0x05f0 /* Host channel-7 interrupt register */ + +/* Device-mode control and status registers */ + +#define STM32_OTGFS_DCFG_OFFSET 0x0800 /* Device configuration register */ +#define STM32_OTGFS_DCTL_OFFSET 0x0804 /* Device control register */ +#define STM32_OTGFS_DSTS_OFFSET 0x0808 /* Device status register */ +#define STM32_OTGFS_DIEPMSK_OFFSET 0x0810 /* Device IN endpoint common interrupt mask register */ +#define STM32_OTGFS_DOEPMSK_OFFSET 0x0814 /* Device OUT endpoint common interrupt mask register */ +#define STM32_OTGFS_DAINT_OFFSET 0x0818 /* Device all endpoints interrupt register */ +#define STM32_OTGFS_DAINTMSK_OFFSET 0x081c /* All endpoints interrupt mask register */ +#define STM32_OTGFS_DVBUSDIS_OFFSET 0x0828 /* Device VBUS discharge time register */ +#define STM32_OTGFS_DVBUSPULSE_OFFSET 0x082c /* Device VBUS pulsing time register */ +#define STM32_OTGFS_DIEPEMPMSK_OFFSET 0x0834 /* Device IN endpoint FIFO empty interrupt mask register */ + +#define STM32_OTGFS_DIEP_OFFSET(n) (0x0900 + ((n) << 5)) +#define STM32_OTGFS_DIEPCTL_EPOFFSET 0x0000 /* Device endpoint control register */ +#define STM32_OTGFS_DIEPINT_EPOFFSET 0x0008 /* Device endpoint interrupt register */ +#define STM32_OTGFS_DIEPTSIZ_EPOFFSET 0x0010 /* Device IN endpoint transfer size register */ +#define STM32_OTGFS_DTXFSTS_EPOFFSET 0x0018 /* Device IN endpoint transmit FIFO status register */ + +#define STM32_OTGFS_DIEPCTL_OFFSET(n) (0x0900 + ((n) << 5)) +#define STM32_OTGFS_DIEPCTL0_OFFSET 0x0900 /* Device control IN endpoint 0 control register */ +#define STM32_OTGFS_DIEPCTL1_OFFSET 0x0920 /* Device control IN endpoint 2 control register */ +#define STM32_OTGFS_DIEPCTL2_OFFSET 0x0940 /* Device control IN endpoint 3 control register */ +#define STM32_OTGFS_DIEPCTL3_OFFSET 0x0960 /* Device control IN endpoint 4 control register */ + +#define STM32_OTGFS_DIEPINT_OFFSET(n) (0x0908 + ((n) << 5)) +#define STM32_OTGFS_DIEPINT0_OFFSET 0x0908 /* Device endpoint-0 interrupt register */ +#define STM32_OTGFS_DIEPINT1_OFFSET 0x0928 /* Device endpoint-1 interrupt register */ +#define STM32_OTGFS_DIEPINT2_OFFSET 0x0948 /* Device endpoint-2 interrupt register */ +#define STM32_OTGFS_DIEPINT3_OFFSET 0x0968 /* Device endpoint-3 interrupt register */ + +#define STM32_OTGFS_DIEPTSIZ_OFFSET(n) (0x910 + ((n) << 5)) +#define STM32_OTGFS_DIEPTSIZ0_OFFSET 0x0910 /* Device IN endpoint 0 transfer size register */ +#define STM32_OTGFS_DIEPTSIZ1_OFFSET 0x0930 /* Device IN endpoint 1 transfer size register */ +#define STM32_OTGFS_DIEPTSIZ2_OFFSET 0x0950 /* Device IN endpoint 2 transfer size register */ +#define STM32_OTGFS_DIEPTSIZ3_OFFSET 0x0970 /* Device IN endpoint 3 transfer size register */ + +#define STM32_OTGFS_DTXFSTS_OFFSET(n) (0x0918 + ((n) << 5)) +#define STM32_OTGFS_DTXFSTS0_OFFSET 0x0918 /* Device OUT endpoint-0 TxFIFO status register */ +#define STM32_OTGFS_DTXFSTS1_OFFSET 0x0938 /* Device OUT endpoint-1 TxFIFO status register */ +#define STM32_OTGFS_DTXFSTS2_OFFSET 0x0958 /* Device OUT endpoint-2 TxFIFO status register */ +#define STM32_OTGFS_DTXFSTS3_OFFSET 0x0978 /* Device OUT endpoint-3 TxFIFO status register */ + +#define STM32_OTGFS_DOEP_OFFSET(n) (0x0b00 + ((n) << 5)) +#define STM32_OTGFS_DOEPCTL_EPOFFSET 0x0000 /* Device control OUT endpoint 0 control register */ +#define STM32_OTGFS_DOEPINT_EPOFFSET 0x0008 /* Device endpoint-x interrupt register */ + +#define STM32_OTGFS_DOEPCTL_OFFSET(n) (0x0b00 + ((n) << 5)) +#define STM32_OTGFS_DOEPCTL0_OFFSET 0x00b00 /* Device OUT endpoint 0 control register */ +#define STM32_OTGFS_DOEPCTL1_OFFSET 0x00b20 /* Device OUT endpoint 1 control register */ +#define STM32_OTGFS_DOEPCTL2_OFFSET 0x00b40 /* Device OUT endpoint 2 control register */ +#define STM32_OTGFS_DOEPCTL3_OFFSET 0x00b60 /* Device OUT endpoint 3 control register */ + +#define STM32_OTGFS_DOEPINT_OFFSET(n) (0x0b08 + ((n) << 5)) +#define STM32_OTGFS_DOEPINT0_OFFSET 0x00b08 /* Device endpoint-0 interrupt register */ +#define STM32_OTGFS_DOEPINT1_OFFSET 0x00b28 /* Device endpoint-1 interrupt register */ +#define STM32_OTGFS_DOEPINT2_OFFSET 0x00b48 /* Device endpoint-2 interrupt register */ +#define STM32_OTGFS_DOEPINT3_OFFSET 0x00b68 /* Device endpoint-3 interrupt register */ + +#define STM32_OTGFS_DOEPTSIZ_OFFSET(n) (0x0b10 + ((n) << 5)) +#define STM32_OTGFS_DOEPTSIZ0_OFFSET 0x00b10 /* Device OUT endpoint-0 transfer size register */ +#define STM32_OTGFS_DOEPTSIZ1_OFFSET 0x00b30 /* Device OUT endpoint-1 transfer size register */ +#define STM32_OTGFS_DOEPTSIZ2_OFFSET 0x00b50 /* Device OUT endpoint-2 transfer size register */ +#define STM32_OTGFS_DOEPTSIZ3_OFFSET 0x00b70 /* Device OUT endpoint-3 transfer size register */ + +/* Power and clock gating registers */ + +#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */ + +/* Data FIFO (DFIFO) access registers */ + +#define STM32_OTGFS_DFIFO_DEP_OFFSET(n) (0x1000 + ((n) << 12)) +#define STM32_OTGFS_DFIFO_HCH_OFFSET(n) (0x1000 + ((n) << 12)) + +#define STM32_OTGFS_DFIFO_DEP0_OFFSET 0x1000 /* 0x1000-0x1ffc Device IN/OUT Endpoint 0 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH0_OFFSET 0x1000 /* 0x1000-0x1ffc Host OUT/IN Channel 0 DFIFO Read/Write Access */ + +#define STM32_OTGFS_DFIFO_DEP1_OFFSET 0x2000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH1_OFFSET 0x2000 /* 0x2000-0x2ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */ + +#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 2 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 2 DFIFO Read/Write Access */ + +#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 3 DFIFO Write/Read Access */ +#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 3 DFIFO Read/Write Access */ + +/* Register Addresses *******************************************************************************/ + +#define STM32_OTGFS_GOTGCTL (STM32_OTGFS_BASE+STM32_OTGFS_GOTGCTL_OFFSET) +#define STM32_OTGFS_GOTGINT (STM32_OTGFS_BASE+STM32_OTGFS_GOTGINT_OFFSET) +#define STM32_OTGFS_GAHBCFG (STM32_OTGFS_BASE+STM32_OTGFS_GAHBCFG_OFFSET) +#define STM32_OTGFS_GUSBCFG (STM32_OTGFS_BASE+STM32_OTGFS_GUSBCFG_OFFSET) +#define STM32_OTGFS_GRSTCTL (STM32_OTGFS_BASE+STM32_OTGFS_GRSTCTL_OFFSET) +#define STM32_OTGFS_GINTSTS (STM32_OTGFS_BASE+STM32_OTGFS_GINTSTS_OFFSET) +#define STM32_OTGFS_GINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_GINTMSK_OFFSET) +#define STM32_OTGFS_GRXSTSR (STM32_OTGFS_BASE+STM32_OTGFS_GRXSTSR_OFFSET) +#define STM32_OTGFS_GRXSTSP (STM32_OTGFS_BASE+STM32_OTGFS_GRXSTSP_OFFSET) +#define STM32_OTGFS_GRXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_GRXFSIZ_OFFSET) +#define STM32_OTGFS_HNPTXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_HNPTXFSIZ_OFFSET) +#define STM32_OTGFS_DIEPTXF0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF0_OFFSET) +#define STM32_OTGFS_HNPTXSTS (STM32_OTGFS_BASE+STM32_OTGFS_HNPTXSTS_OFFSET) +#define STM32_OTGFS_GCCFG (STM32_OTGFS_BASE+STM32_OTGFS_GCCFG_OFFSET) +#define STM32_OTGFS_CID (STM32_OTGFS_BASE+STM32_OTGFS_CID_OFFSET) +#define STM32_OTGFS_HPTXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_HPTXFSIZ_OFFSET) + +#define STM32_OTGFS_DIEPTXF(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF_OFFSET(n)) +#define STM32_OTGFS_DIEPTXF1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF1_OFFSET) +#define STM32_OTGFS_DIEPTXF2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF2_OFFSET) +#define STM32_OTGFS_DIEPTXF3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF3_OFFSET) + +/* Host-mode control and status registers */ + +#define STM32_OTGFS_HCFG (STM32_OTGFS_BASE+STM32_OTGFS_HCFG_OFFSET) +#define STM32_OTGFS_HFIR (STM32_OTGFS_BASE+STM32_OTGFS_HFIR_OFFSET) +#define STM32_OTGFS_HFNUM (STM32_OTGFS_BASE+STM32_OTGFS_HFNUM_OFFSET) +#define STM32_OTGFS_HPTXSTS (STM32_OTGFS_BASE+STM32_OTGFS_HPTXSTS_OFFSET) +#define STM32_OTGFS_HAINT (STM32_OTGFS_BASE+STM32_OTGFS_HAINT_OFFSET) +#define STM32_OTGFS_HAINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_HAINTMSK_OFFSET) +#define STM32_OTGFS_HPRT (STM32_OTGFS_BASE+STM32_OTGFS_HPRT_OFFSET) + +#define STM32_OTGFS_CHAN(n) (STM32_OTGFS_BASE+STM32_OTGFS_CHAN_OFFSET(n)) + +#define STM32_OTGFS_HCCHAR(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR_OFFSET(n)) +#define STM32_OTGFS_HCCHAR0 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR0_OFFSET) +#define STM32_OTGFS_HCCHAR1 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR1_OFFSET) +#define STM32_OTGFS_HCCHAR2 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR2_OFFSET) +#define STM32_OTGFS_HCCHAR3 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR3_OFFSET) +#define STM32_OTGFS_HCCHAR4 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR4_OFFSET) +#define STM32_OTGFS_HCCHAR5 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR5_OFFSET) +#define STM32_OTGFS_HCCHAR6 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR6_OFFSET) +#define STM32_OTGFS_HCCHAR7 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR7_OFFSET) + +#define STM32_OTGFS_HCINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCINT_OFFSET(n)) +#define STM32_OTGFS_HCINT0 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT0_OFFSET) +#define STM32_OTGFS_HCINT1 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT1_OFFSET) +#define STM32_OTGFS_HCINT2 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT2_OFFSET) +#define STM32_OTGFS_HCINT3 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT3_OFFSET) +#define STM32_OTGFS_HCINT4 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT4_OFFSET) +#define STM32_OTGFS_HCINT5 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT5_OFFSET) +#define STM32_OTGFS_HCINT6 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT6_OFFSET) +#define STM32_OTGFS_HCINT7 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT7_OFFSET) + +#define STM32_OTGFS_HCINTMSK(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK_OFFSET(n)) +#define STM32_OTGFS_HCINTMSK0 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK0_OFFSET) +#define STM32_OTGFS_HCINTMSK1 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK1_OFFSET) +#define STM32_OTGFS_HCINTMSK2 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK2_OFFSET) +#define STM32_OTGFS_HCINTMSK3 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK3_OFFSET) +#define STM32_OTGFS_HCINTMSK4 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK4_OFFSET) +#define STM32_OTGFS_HCINTMSK5 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK5_OFFSET) +#define STM32_OTGFS_HCINTMSK6 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK6_OFFSET) +#define STM32_OTGFS_HCINTMSK7 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK7_OFFSET)_ + +#define STM32_OTGFS_HCTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ_OFFSET(n)) +#define STM32_OTGFS_HCTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ0_OFFSET) +#define STM32_OTGFS_HCTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ1_OFFSET) +#define STM32_OTGFS_HCTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ2_OFFSET) +#define STM32_OTGFS_HCTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ3_OFFSET) +#define STM32_OTGFS_HCTSIZ4 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ4_OFFSET) +#define STM32_OTGFS_HCTSIZ5 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ5_OFFSET) +#define STM32_OTGFS_HCTSIZ6 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ6_OFFSET) +#define STM32_OTGFS_HCTSIZ7 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ7_OFFSET) + +/* Device-mode control and status registers */ + +#define STM32_OTGFS_DCFG (STM32_OTGFS_BASE+STM32_OTGFS_DCFG_OFFSET) +#define STM32_OTGFS_DCTL (STM32_OTGFS_BASE+STM32_OTGFS_DCTL_OFFSET) +#define STM32_OTGFS_DSTS (STM32_OTGFS_BASE+STM32_OTGFS_DSTS_OFFSET) +#define STM32_OTGFS_DIEPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DIEPMSK_OFFSET) +#define STM32_OTGFS_DOEPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DOEPMSK_OFFSET) +#define STM32_OTGFS_DAINT (STM32_OTGFS_BASE+STM32_OTGFS_DAINT_OFFSET) +#define STM32_OTGFS_DAINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_DAINTMSK_OFFSET) +#define STM32_OTGFS_DVBUSDIS (STM32_OTGFS_BASE+STM32_OTGFS_DVBUSDIS_OFFSET) +#define STM32_OTGFS_DVBUSPULSE (STM32_OTGFS_BASE+STM32_OTGFS_DVBUSPULSE_OFFSET) +#define STM32_OTGFS_DIEPEMPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DIEPEMPMSK_OFFSET) + +#define STM32_OTGFS_DIEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEP_OFFSET(n)) + +#define STM32_OTGFS_DIEPCTL(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL_OFFSET(n)) +#define STM32_OTGFS_DIEPCTL0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL0_OFFSET) +#define STM32_OTGFS_DIEPCTL1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL1_OFFSET) +#define STM32_OTGFS_DIEPCTL2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL2_OFFSET) +#define STM32_OTGFS_DIEPCTL3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL3_OFFSET) + +#define STM32_OTGFS_DIEPINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT_OFFSET(n)) +#define STM32_OTGFS_DIEPINT0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT0_OFFSET) +#define STM32_OTGFS_DIEPINT1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT1_OFFSET) +#define STM32_OTGFS_DIEPINT2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT2_OFFSET) +#define STM32_OTGFS_DIEPINT3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT3_OFFSET) + +#define STM32_OTGFS_DIEPTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ_OFFSET(n)) +#define STM32_OTGFS_DIEPTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ0_OFFSET) +#define STM32_OTGFS_DIEPTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ1_OFFSET) +#define STM32_OTGFS_DIEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ2_OFFSET) +#define STM32_OTGFS_DIEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ3_OFFSET) + +#define STM32_OTGFS_DTXFSTS(n) (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS_OFFSET(n)) +#define STM32_OTGFS_DTXFSTS0 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS0_OFFSET) +#define STM32_OTGFS_DTXFSTS1 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS1_OFFSET) +#define STM32_OTGFS_DTXFSTS2 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS2_OFFSET) +#define STM32_OTGFS_DTXFSTS3 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS3_OFFSET) + +#define STM32_OTGFS_DOEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEP_OFFSET(n)) + +#define STM32_OTGFS_DOEPCTL(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL_OFFSET(n)) +#define STM32_OTGFS_DOEPCTL0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL0_OFFSET) +#define STM32_OTGFS_DOEPCTL1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL1_OFFSET) +#define STM32_OTGFS_DOEPCTL2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL2_OFFSET) +#define STM32_OTGFS_DOEPCTL3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL3_OFFSET) + +#define STM32_OTGFS_DOEPINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT_OFFSET(n)) +#define STM32_OTGFS_DOEPINT0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT0_OFFSET) +#define STM32_OTGFS_DOEPINT1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT1_OFFSET) +#define STM32_OTGFS_DOEPINT2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT2_OFFSET) +#define STM32_OTGFS_DOEPINT3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT3_OFFSET) + +#define STM32_OTGFS_DOEPTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ_OFFSET(n)) +#define STM32_OTGFS_DOEPTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ0_OFFSET) +#define STM32_OTGFS_DOEPTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ1_OFFSET) +#define STM32_OTGFS_DOEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ2_OFFSET) +#define STM32_OTGFS_DOEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ3_OFFSET) + +/* Power and clock gating registers */ + +#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET) + +/* Data FIFO (DFIFO) access registers */ + +#define STM32_OTGFS_DFIFO_DEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP_OFFSET(n)) +#define STM32_OTGFS_DFIFO_HCH(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH_OFFSET(n)) + +#define STM32_OTGFS_DFIFO_DEP0 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP0_OFFSET) +#define STM32_OTGFS_DFIFO_HCH0 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH0_OFFSET) + +#define STM32_OTGFS_DFIFO_DEP1 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP1_OFFSET) +#define STM32_OTGFS_DFIFO_HCH1 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH1_OFFSET) + +#define STM32_OTGFS_DFIFO_DEP2 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP2_OFFSET) +#define STM32_OTGFS_DFIFO_HCH2 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH2_OFFSET) + +#define STM32_OTGFS_DFIFO_DEP3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP3_OFFSET) +#define STM32_OTGFS_DFIFO_HCH3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH3_OFFSET) + +/* Register Bitfield Definitions ********************************************************************/ +/* Core global control and status registers */ + +/* Control and status register */ + +#define OTGFS_GOTGCTL_SRQSCS (1 << 0) /* Bit 0: Session request success */ +#define OTGFS_GOTGCTL_SRQ (1 << 1) /* Bit 1: Session request */ + /* Bits 2-7 Reserved, must be kept at reset value */ +#define OTGFS_GOTGCTL_HNGSCS (1 << 8) /* Bit 8: Host negotiation success */ +#define OTGFS_GOTGCTL_HNPRQ (1 << 9) /* Bit 9: HNP request */ +#define OTGFS_GOTGCTL_HSHNPEN (1 << 10) /* Bit 10: host set HNP enable */ +#define OTGFS_GOTGCTL_DHNPEN (1 << 11) /* Bit 11: Device HNP enabled */ + /* Bits 12-15: Reserved, must be kept at reset value */ +#define OTGFS_GOTGCTL_CIDSTS (1 << 16) /* Bit 16: Connector ID status */ +#define OTGFS_GOTGCTL_DBCT (1 << 17) /* Bit 17: Long/short debounce time */ +#define OTGFS_GOTGCTL_ASVLD (1 << 18) /* Bit 18: A-session valid */ +#define OTGFS_GOTGCTL_BSVLD (1 << 19) /* Bit 19: B-session valid */ + /* Bits 20-31: Reserved, must be kept at reset value */ +/* Interrupt register */ + /* Bits 1:0 Reserved, must be kept at reset value */ +#define OTGFS_GOTGINT_SEDET (1 << 2) /* Bit 2: Session end detected */ + /* Bits 3-7: Reserved, must be kept at reset value */ +#define OTGFS_GOTGINT_SRSSCHG (1 << 8) /* Bit 8: Session request success status change */ +#define OTGFS_GOTGINT_HNSSCHG (1 << 9) /* Bit 9: Host negotiation success status change */ + /* Bits 16:10 Reserved, must be kept at reset value */ +#define OTGFS_GOTGINT_HNGDET (1 << 17) /* Bit 17: Host negotiation detected */ +#define OTGFS_GOTGINT_ADTOCHG (1 << 18) /* Bit 18: A-device timeout change */ +#define OTGFS_GOTGINT_DBCDNE (1 << 19) /* Bit 19: Debounce done */ + /* Bits 20-31: Reserved, must be kept at reset value */ + +/* AHB configuration register */ + +#define OTGFS_GAHBCFG_GINTMSK (1 << 0) /* Bit 0: Global interrupt mask */ + /* Bits 1-6: Reserved, must be kept at reset value */ +#define OTGFS_GAHBCFG_TXFELVL (1 << 7) /* Bit 7: TxFIFO empty level */ +#define OTGFS_GAHBCFG_PTXFELVL (1 << 8) /* Bit 8: Periodic TxFIFO empty level */ + /* Bits 20-31: Reserved, must be kept at reset value */ +/* USB configuration register */ + +#define OTGFS_GUSBCFG_TOCAL_SHIFT (0) /* Bits 0-2: FS timeout calibration */ +#define OTGFS_GUSBCFG_TOCAL_MASK (7 << OTGFS_GUSBCFG_TOCAL_SHIFT) + /* Bits 3-5: Reserved, must be kept at reset value */ +#define OTGFS_GUSBCFG_PHYSEL (1 << 6) /* Bit 6: Full Speed serial transceiver select */ + /* Bit 7: Reserved, must be kept at reset value */ +#define OTGFS_GUSBCFG_SRPCAP (1 << 8) /* Bit 8: SRP-capable */ +#define OTGFS_GUSBCFG_HNPCAP (1 << 9) /* Bit 9: HNP-capable */ +#define OTGFS_GUSBCFG_TRDT_SHIFT (10) /* Bits 10-13: USB turnaround time */ +#define OTGFS_GUSBCFG_TRDT_MASK (15 << OTGFS_GUSBCFG_TRDT_SHIFT) +# define OTGFS_GUSBCFG_TRDT(n) ((n) << OTGFS_GUSBCFG_TRDT_SHIFT) + /* Bits 14-28: Reserved, must be kept at reset value */ +#define OTGFS_GUSBCFG_FHMOD (1 << 29) /* Bit 29: Force host mode */ +#define OTGFS_GUSBCFG_FDMOD (1 << 30) /* Bit 30: Force device mode */ +#define OTGFS_GUSBCFG_CTXPKT (1 << 31) /* Bit 31: Corrupt Tx packet */ + /* Bits 20-31: Reserved, must be kept at reset value */ +/* Reset register */ + +#define OTGFS_GRSTCTL_CSRST (1 << 0) /* Bit 0: Core soft reset */ +#define OTGFS_GRSTCTL_HSRST (1 << 1) /* Bit 1: HCLK soft reset */ +#define OTGFS_GRSTCTL_FCRST (1 << 2) /* Bit 2: Host frame counter reset */ + /* Bit 3 Reserved, must be kept at reset value */ +#define OTGFS_GRSTCTL_RXFFLSH (1 << 4) /* Bit 4: RxFIFO flush */ +#define OTGFS_GRSTCTL_TXFFLSH (1 << 5) /* Bit 5: TxFIFO flush */ +#define OTGFS_GRSTCTL_TXFNUM_SHIFT (6) /* Bits 6-10: TxFIFO number */ +#define OTGFS_GRSTCTL_TXFNUM_MASK (31 << OTGFS_GRSTCTL_TXFNUM_SHIFT) +# define OTGFS_GRSTCTL_TXFNUM_HNONPER (0 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Non-periodic TxFIFO flush in host mode */ +# define OTGFS_GRSTCTL_TXFNUM_HPER (1 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Periodic TxFIFO flush in host mode */ +# define OTGFS_GRSTCTL_TXFNUM_HALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in host mode.*/ +# define OTGFS_GRSTCTL_TXFNUM_D(n) ((n) << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* TXFIFO n flush in device mode, n=0-15 */ +# define OTGFS_GRSTCTL_TXFNUM_DALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in device mode.*/ + /* Bits 11-31: Reserved, must be kept at reset value */ +#define OTGFS_GRSTCTL_AHBIDL (1 << 31) /* Bit 31: AHB master idle */ + +/* Core interrupt and Interrupt mask registers */ + +#define OTGFS_GINTSTS_CMOD (1 << 0) /* Bit 0: Current mode of operation */ +# define OTGFS_GINTSTS_DEVMODE (0) +# define OTGFS_GINTSTS_HOSTMODE (OTGFS_GINTSTS_CMOD) +#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: Mode mismatch interrupt */ +#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: OTG interrupt */ +#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: Start of frame */ +#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: RxFIFO non-empty */ +#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: Non-periodic TxFIFO empty */ +#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: Global IN non-periodic NAK effective */ +#define OTGFS_GINT_GONAKEFF (1 << 7) /* Bit 7: Global OUT NAK effective */ + /* Bits 8-9: Reserved, must be kept at reset value */ +#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: Early suspend */ +#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: USB suspend */ +#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: USB reset */ +#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: Enumeration done */ +#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: Isochronous OUT packet dropped interrupt */ +#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: End of periodic frame interrupt */ + /* Bits 16 Reserved, must be kept at reset value */ +#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Endpoint mismatch interrupt mask */ +#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: IN endpoint interrupt */ +#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: OUT endpoint interrupt */ +#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: Incomplete isochronous IN transfer */ +#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: Incomplete isochronous OUT transfer (device) */ +#define OTGFS_GINT_IPXFR (1 << 21) /* Bit 21: Incomplete periodic transfer (host) */ + /* Bits 22-23: Reserved, must be kept at reset value */ +#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: Host port interrupt */ +#define OTGFS_GINT_HC (1 << 25) /* Bit 25: Host channels interrupt */ +#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: Periodic TxFIFO empty */ + /* Bit 27 Reserved, must be kept at reset value */ +#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: Connector ID status change */ +#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: Disconnect detected interrupt */ +#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: Session request/new session detected interrupt */ +#define OTGFS_GINT_WKUP (1 << 31) /* Bit 31: Resume/remote wakeup detected interrupt */ + +/* Receive status debug read/OTG status read and pop registers (host mode) */ + +#define OTGFS_GRXSTSH_CHNUM_SHIFT (0) /* Bits 0-3: Channel number */ +#define OTGFS_GRXSTSH_CHNUM_MASK (15 << OTGFS_GRXSTSH_CHNUM_SHIFT) +#define OTGFS_GRXSTSH_BCNT_SHIFT (4) /* Bits 4-14: Byte count */ +#define OTGFS_GRXSTSH_BCNT_MASK (0x7ff << OTGFS_GRXSTSH_BCNT_SHIFT) +#define OTGFS_GRXSTSH_DPID_SHIFT (15) /* Bits 15-16: Data PID */ +#define OTGFS_GRXSTSH_DPID_MASK (3 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA0 (0 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA2 (1 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_DATA1 (2 << OTGFS_GRXSTSH_DPID_SHIFT) +# define OTGFS_GRXSTSH_DPID_MDATA (3 << OTGFS_GRXSTSH_DPID_SHIFT) +#define OTGFS_GRXSTSH_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */ +#define OTGFS_GRXSTSH_PKTSTS_MASK (15 << OTGFS_GRXSTSH_PKTSTS_SHIFT) +# define OTGFS_GRXSTSH_PKTSTS_INRECVD (2 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN data packet received */ +# define OTGFS_GRXSTSH_PKTSTS_INDONE (3 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN transfer completed */ +# define OTGFS_GRXSTSH_PKTSTS_DTOGERR (5 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Data toggle error */ +# define OTGFS_GRXSTSH_PKTSTS_HALTED (7 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Channel halted */ + /* Bits 21-31: Reserved, must be kept at reset value */ +/* Receive status debug read/OTG status read and pop registers (device mode) */ + +#define OTGFS_GRXSTSD_EPNUM_SHIFT (0) /* Bits 0-3: Endpoint number */ +#define OTGFS_GRXSTSD_EPNUM_MASK (15 << OTGFS_GRXSTSD_EPNUM_SHIFT) +#define OTGFS_GRXSTSD_BCNT_SHIFT (4) /* Bits 4-14: Byte count */ +#define OTGFS_GRXSTSD_BCNT_MASK (0x7ff << OTGFS_GRXSTSD_BCNT_SHIFT) +#define OTGFS_GRXSTSD_DPID_SHIFT (15) /* Bits 15-16: Data PID */ +#define OTGFS_GRXSTSD_DPID_MASK (3 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA0 (0 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA2 (1 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_DATA1 (2 << OTGFS_GRXSTSD_DPID_SHIFT) +# define OTGFS_GRXSTSD_DPID_MDATA (3 << OTGFS_GRXSTSD_DPID_SHIFT) +#define OTGFS_GRXSTSD_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */ +#define OTGFS_GRXSTSD_PKTSTS_MASK (15 << OTGFS_GRXSTSD_PKTSTS_SHIFT) +# define OTGFS_GRXSTSD_PKTSTS_OUTNAK (1 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* Global OUT NAK */ +# define OTGFS_GRXSTSD_PKTSTS_OUTRECVD (2 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT data packet received */ +# define OTGFS_GRXSTSD_PKTSTS_OUTDONE (3 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT transfer completed */ +# define OTGFS_GRXSTSD_PKTSTS_SETUPDONE (4 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP transaction completed */ +# define OTGFS_GRXSTSD_PKTSTS_SETUPRECVD (6 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP data packet received */ +#define OTGFS_GRXSTSD_FRMNUM_SHIFT (21) /* Bits 21-24: Frame number */ +#define OTGFS_GRXSTSD_FRMNUM_MASK (15 << OTGFS_GRXSTSD_FRMNUM_SHIFT) + /* Bits 25-31: Reserved, must be kept at reset value */ +/* Receive FIFO size register */ + +#define OTGFS_GRXFSIZ_MASK (0xffff) + +/* Host non-periodic transmit FIFO size register */ + +#define OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT (0) /* Bits 0-15: Non-periodic transmit RAM start address */ +#define OTGFS_HNPTXFSIZ_NPTXFSA_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT) +#define OTGFS_HNPTXFSIZ_NPTXFD_SHIFT (16) /* Bits 16-31: Non-periodic TxFIFO depth */ +#define OTGFS_HNPTXFSIZ_NPTXFD_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) +# define OTGFS_HNPTXFSIZ_NPTXFD_MIN (16 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) +# define OTGFS_HNPTXFSIZ_NPTXFD_MAX (256 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT) + +/* Endpoint 0 Transmit FIFO size */ + +#define OTGFS_DIEPTXF0_TX0FD_SHIFT (0) /* Bits 0-15: Endpoint 0 transmit RAM start address */ +#define OTGFS_DIEPTXF0_TX0FD_MASK (0xffff << OTGFS_DIEPTXF0_TX0FD_SHIFT) +#define OTGFS_DIEPTXF0_TX0FSA_SHIFT (16) /* Bits 16-31: Endpoint 0 TxFIFO depth */ +#define OTGFS_DIEPTXF0_TX0FSA_MASK (0xffff << OTGFS_DIEPTXF0_TX0FSA_SHIFT) +# define OTGFS_DIEPTXF0_TX0FSA_MIN (16 << OTGFS_DIEPTXF0_TX0FSA_SHIFT) +# define OTGFS_DIEPTXF0_TX0FSA_MAX (256 << OTGFS_DIEPTXF0_TX0FSA_SHIFT) + +/* Non-periodic transmit FIFO/queue status register */ + +#define OTGFS_HNPTXSTS_NPTXFSAV_SHIFT (0) /* Bits 0-15: Non-periodic TxFIFO space available */ +#define OTGFS_HNPTXSTS_NPTXFSAV_MASK (0xffff << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) +# define OTGFS_HNPTXSTS_NPTXFSAV_FULL (0 << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) +#define OTGFS_HNPTXSTS_NPTQXSAV_SHIFT (16) /* Bits 16-23: Non-periodic transmit request queue space available */ +#define OTGFS_HNPTXSTS_NPTQXSAV_MASK (0xff << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT) +# define OTGFS_HNPTXSTS_NPTQXSAV_FULL (0 << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT) +#define OTGFS_HNPTXSTS_NPTXQTOP_SHIFT (24) /* Bits 24-30: Top of the non-periodic transmit request queue */ +#define OTGFS_HNPTXSTS_NPTXQTOP_MASK (0x7f << OTGFS_HNPTXSTS_NPTXQTOP_SHIFT) +# define OTGFS_HNPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */ +# define OTGFS_HNPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Status */ +# define OTGFS_HNPTXSTS_TYPE_MASK (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) +# define OTGFS_HNPTXSTS_TYPE_INOUT (0 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* IN/OUT token */ +# define OTGFS_HNPTXSTS_TYPE_ZLP (1 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet (device IN/host OUT) */ +# define OTGFS_HNPTXSTS_TYPE_HALT (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Channel halt command */ +# define OTGFS_HNPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */ +# define OTGFS_HNPTXSTS_CHNUM_MASK (15 << OTGFS_HNPTXSTS_CHNUM_SHIFT) +# define OTGFS_HNPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */ +# define OTGFS_HNPTXSTS_EPNUM_MASK (15 << OTGFS_HNPTXSTS_EPNUM_SHIFT) + /* Bit 31 Reserved, must be kept at reset value */ +/* General core configuration register */ + /* Bits 15:0 Reserved, must be kept at reset value */ +#define OTGFS_GCCFG_PWRDWN (1 << 16) /* Bit 16: Power down */ + /* Bit 17 Reserved, must be kept at reset value */ +#define OTGFS_GCCFG_VBUSASEN (1 << 18) /* Bit 18: Enable the VBUS sensing “A” device */ +#define OTGFS_GCCFG_VBUSBSEN (1 << 19) /* Bit 19: Enable the VBUS sensing “B” device */ +#define OTGFS_GCCFG_SOFOUTEN (1 << 20) /* Bit 20: SOF output enable */ +#define OTGFS_GCCFG_NOVBUSSENS (1 << 21) /* Bit 21: VBUS sensing disable option */ + /* Bits 31:22 Reserved, must be kept at reset value */ +/* Core ID register (32-bit product ID) */ + +/* Host periodic transmit FIFO size register */ + +#define OTGFS_HPTXFSIZ_PTXSA_SHIFT (0) /* Bits 0-15: Host periodic TxFIFO start address */ +#define OTGFS_HPTXFSIZ_PTXSA_MASK (0xffff << OTGFS_HPTXFSIZ_PTXSA_SHIFT) +#define OTGFS_HPTXFSIZ_PTXFD_SHIFT (16) /* Bits 16-31: Host periodic TxFIFO depth */ +#define OTGFS_HPTXFSIZ_PTXFD_MASK (0xffff << OTGFS_HPTXFSIZ_PTXFD_SHIFT) + +/* Device IN endpoint transmit FIFOn size register */ + +#define OTGFS_DIEPTXF_INEPTXSA_SHIFT (0) /* Bits 0-15: IN endpoint FIFOx transmit RAM start address */ +#define OTGFS_DIEPTXF_INEPTXSA_MASK (0xffff << OTGFS_DIEPTXF_INEPTXSA_SHIFT) +#define OTGFS_DIEPTXF_INEPTXFD_SHIFT (16) /* Bits 16-31: IN endpoint TxFIFO depth */ +#define OTGFS_DIEPTXF_INEPTXFD_MASK (0xffff << OTGFS_DIEPTXF_INEPTXFD_SHIFT) +# define OTGFS_DIEPTXF_INEPTXFD_MIN (16 << OTGFS_DIEPTXF_INEPTXFD_MASK) + +/* Host-mode control and status registers */ + +/* Host configuration register */ + +#define OTGFS_HCFG_FSLSPCS_SHIFT (0) /* Bits 0-1: FS/LS PHY clock select */ +#define OTGFS_HCFG_FSLSPCS_MASK (3 << OTGFS_HCFG_FSLSPCS_SHIFT) +# define OTGFS_HCFG_FSLSPCS_FS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* FS host mode, PHY clock is running at 48 MHz */ +# define OTGFS_HCFG_FSLSPCS_LS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 48 MHz PHY clock frequency */ +# define OTGFS_HCFG_FSLSPCS_LS6MHz (2 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 6 MHz PHY clock frequency */ +#define OTGFS_HCFG_FSLSS (1 << 2) /* Bit 2: FS- and LS-only support */ + /* Bits 31:3 Reserved, must be kept at reset value */ +/* Host frame interval register */ + +#define OTGFS_HFIR_MASK (0xffff) + +/* Host frame number/frame time remaining register */ + +#define OTGFS_HFNUM_FRNUM_SHIFT (0) /* Bits 0-15: Frame number */ +#define OTGFS_HFNUM_FRNUM_MASK (0xffff << OTGFS_HFNUM_FRNUM_SHIFT) +#define OTGFS_HFNUM_FTREM_SHIFT (16) /* Bits 16-31: Frame time remaining */ +#define OTGFS_HFNUM_FTREM_MASK (0xffff << OTGFS_HFNUM_FTREM_SHIFT) + +/* Host periodic transmit FIFO/queue status register */ + +#define OTGFS_HPTXSTS_PTXFSAVL_SHIFT (0) /* Bits 0-15: Periodic transmit data FIFO space available */ +#define OTGFS_HPTXSTS_PTXFSAVL_MASK (0xffff << OTGFS_HPTXSTS_PTXFSAVL_SHIFT) +# define OTGFS_HPTXSTS_PTXFSAVL_FULL (0 << OTGFS_HPTXSTS_PTXFSAVL_SHIFT) +#define OTGFS_HPTXSTS_PTXQSAV_SHIFT (16) /* Bits 16-23: Periodic transmit request queue space available */ +#define OTGFS_HPTXSTS_PTXQSAV_MASK (0xff << OTGFS_HPTXSTS_PTXQSAV_SHIFT) +# define OTGFS_HPTXSTS_PTXQSAV_FULL (0 << OTGFS_HPTXSTS_PTXQSAV_SHIFT) +#define OTGFS_HPTXSTS_PTXQTOP_SHIFT (24) /* Bits 24-31: Top of the periodic transmit request queue */ +#define OTGFS_HPTXSTS_PTXQTOP_MASK (0x7f << OTGFS_HPTXSTS_PTXQTOP_SHIFT) +# define OTGFS_HPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */ +# define OTGFS_HPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Type */ +# define OTGFS_HPTXSTS_TYPE_MASK (3 << OTGFS_HPTXSTS_TYPE_SHIFT) +# define OTGFS_HPTXSTS_TYPE_INOUT (0 << OTGFS_HPTXSTS_TYPE_SHIFT) /* IN/OUT token */ +# define OTGFS_HPTXSTS_TYPE_ZLP (1 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet */ +# define OTGFS_HPTXSTS_TYPE_HALT (3 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Disable channel command */ +# define OTGFS_HPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */ +# define OTGFS_HPTXSTS_EPNUM_MASK (15 << OTGFS_HPTXSTS_EPNUM_SHIFT) +# define OTGFS_HPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */ +# define OTGFS_HPTXSTS_CHNUM_MASK (15 << OTGFS_HPTXSTS_CHNUM_SHIFT) +# define OTGFS_HPTXSTS_ODD (1 << 24) /* Bit 31: Send in odd (vs even) frame */ + +/* Host all channels interrupt and all channels interrupt mask registers */ + +#define OTGFS_HAINT(n) (1 << (n)) /* Bits 15:0 HAINTM: Channel interrupt */ + +/* Host port control and status register */ + +#define OTGFS_HPRT_PCSTS (1 << 0) /* Bit 0: Port connect status */ +#define OTGFS_HPRT_PCDET (1 << 1) /* Bit 1: Port connect detected */ +#define OTGFS_HPRT_PENA (1 << 2) /* Bit 2: Port enable */ +#define OTGFS_HPRT_PENCHNG (1 << 3) /* Bit 3: Port enable/disable change */ +#define OTGFS_HPRT_POCA (1 << 4) /* Bit 4: Port overcurrent active */ +#define OTGFS_HPRT_POCCHNG (1 << 5) /* Bit 5: Port overcurrent change */ +#define OTGFS_HPRT_PRES (1 << 6) /* Bit 6: Port resume */ +#define OTGFS_HPRT_PSUSP (1 << 7) /* Bit 7: Port suspend */ +#define OTGFS_HPRT_PRST (1 << 8) /* Bit 8: Port reset */ + /* Bit 9: Reserved, must be kept at reset value */ +#define OTGFS_HPRT_PLSTS_SHIFT (10) /* Bits 10-11: Port line status */ +#define OTGFS_HPRT_PLSTS_MASK (3 << OTGFS_HPRT_PLSTS_SHIFT) +# define OTGFS_HPRT_PLSTS_DP (1 << 10) /* Bit 10: Logic level of OTG_FS_FS_DP */ +# define OTGFS_HPRT_PLSTS_DM (1 << 11) /* Bit 11: Logic level of OTG_FS_FS_DM */ +#define OTGFS_HPRT_PPWR (1 << 12) /* Bit 12: Port power */ +#define OTGFS_HPRT_PTCTL_SHIFT (13) /* Bits 13-16: Port test control */ +#define OTGFS_HPRT_PTCTL_MASK (15 << OTGFS_HPRT_PTCTL_SHIFT) +# define OTGFS_HPRT_PTCTL_DISABLED (0 << OTGFS_HPRT_PTCTL_SHIFT) /* Test mode disabled */ +# define OTGFS_HPRT_PTCTL_J (1 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_J mode */ +# define OTGFS_HPRT_PTCTL_L (2 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_K mode */ +# define OTGFS_HPRT_PTCTL_SE0_NAK (3 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_SE0_NAK mode */ +# define OTGFS_HPRT_PTCTL_PACKET (4 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Packet mode */ +# define OTGFS_HPRT_PTCTL_FORCE (5 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Force_Enable */ +#define OTGFS_HPRT_PSPD_SHIFT (17) /* Bits 17-18: Port speed */ +#define OTGFS_HPRT_PSPD_MASK (3 << OTGFS_HPRT_PSPD_SHIFT) +# define OTGFS_HPRT_PSPD_FS (1 << OTGFS_HPRT_PSPD_SHIFT) /* Full speed */ +# define OTGFS_HPRT_PSPD_LS (2 << OTGFS_HPRT_PSPD_SHIFT) /* Low speed */ + /* Bits 19-31: Reserved, must be kept at reset value */ + +/* Host channel-n characteristics register */ + +#define OTGFS_HCCHAR_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_HCCHAR_MPSIZ_MASK (0x7ff << OTGFS_HCCHAR_MPSIZ_SHIFT) +#define OTGFS_HCCHAR_EPNUM_SHIFT (11) /* Bits 11-14: Endpoint number */ +#define OTGFS_HCCHAR_EPNUM_MASK (15 << OTGFS_HCCHAR_EPNUM_SHIFT) +#define OTGFS_HCCHAR_EPDIR (1 << 15) /* Bit 15: Endpoint direction */ +# define OTGFS_HCCHAR_EPDIR_OUT (0) +# define OTGFS_HCCHAR_EPDIR_IN OTGFS_HCCHAR_EPDIR + /* Bit 16 Reserved, must be kept at reset value */ +#define OTGFS_HCCHAR_LSDEV (1 << 17) /* Bit 17: Low-speed device */ +#define OTGFS_HCCHAR_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_HCCHAR_EPTYP_MASK (3 << OTGFS_HCCHAR_EPTYP_SHIFT) +# define OTGFS_HCCHAR_EPTYP_CTRL (0 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Control */ +# define OTGFS_HCCHAR_EPTYP_ISOC (1 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_HCCHAR_EPTYP_BULK (2 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_HCCHAR_EPTYP_INTR (3 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Interrupt */ +#define OTGFS_HCCHAR_MCNT_SHIFT (20) /* Bits 20-21: Multicount */ +#define OTGFS_HCCHAR_MCNT_MASK (3 << OTGFS_HCCHAR_MCNT_SHIFT) +#define OTGFS_HCCHAR_DAD_SHIFT (22) /* Bits 22-28: Device address */ +#define OTGFS_HCCHAR_DAD_MASK (0x7f << OTGFS_HCCHAR_DAD_SHIFT) +#define OTGFS_HCCHAR_ODDFRM (1 << 29) /* Bit 29: Odd frame */ +#define OTGFS_HCCHAR_CHDIS (1 << 30) /* Bit 30: Channel disable */ +#define OTGFS_HCCHAR_CHENA (1 << 31) /* Bit 31: Channel enable */ + +/* Host channel-n interrupt and Host channel-0 interrupt mask registers */ + +#define OTGFS_HCINT_XFRC (1 << 0) /* Bit 0: Transfer completed */ +#define OTGFS_HCINT_CHH (1 << 1) /* Bit 1: Channel halted */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_HCINT_STALL (1 << 3) /* Bit 3: STALL response received interrupt */ +#define OTGFS_HCINT_NAK (1 << 4) /* Bit 4: NAK response received interrupt */ +#define OTGFS_HCINT_ACK (1 << 5) /* Bit 5: ACK response received/transmitted interrupt */ +#define OTGFS_HCINT_NYET (1 << 6) /* Bit 6: Response received interrupt */ +#define OTGFS_HCINT_TXERR (1 << 7) /* Bit 7: Transaction error */ +#define OTGFS_HCINT_BBERR (1 << 8) /* Bit 8: Babble error */ +#define OTGFS_HCINT_FRMOR (1 << 9) /* Bit 9: Frame overrun */ +#define OTGFS_HCINT_DTERR (1 << 10) /* Bit 10: Data toggle error */ + /* Bits 11-31 Reserved, must be kept at reset value */ +/* Host channel-n interrupt register */ + +#define OTGFS_HCTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_HCTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_HCTSIZ_XFRSIZ_SHIFT) +#define OTGFS_HCTSIZ_PKTCNT_SHIFT (19) /* Bits 19-28: Packet count */ +#define OTGFS_HCTSIZ_PKTCNT_MASK (0x3ff << OTGFS_HCTSIZ_PKTCNT_SHIFT) +#define OTGFS_HCTSIZ_DPID_SHIFT (29) /* Bits 29-30: Data PID */ +#define OTGFS_HCTSIZ_DPID_MASK (3 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA0 (0 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA2 (1 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_DATA1 (2 << OTGFS_HCTSIZ_DPID_SHIFT) +# define OTGFS_HCTSIZ_DPID_MDATA (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Non-control */ +# define OTGFS_HCTSIZ_PID_SETUP (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Control */ + /* Bit 31 Reserved, must be kept at reset value */ +/* Device-mode control and status registers */ + +/* Device configuration register */ + +#define OTGFS_DCFG_DSPD_SHIFT (0) /* Bits 0-1: Device speed */ +#define OTGFS_DCFG_DSPD_MASK (3 << OTGFS_DCFG_DSPD_SHIFT) +# define OTGFS_DCFG_DSPD_FS (3 << OTGFS_DCFG_DSPD_SHIFT) /* Full speed */ +#define OTGFS_DCFG_NZLSOHSK (1 << 2) /* Bit 2: Non-zero-length status OUT handshake */ + /* Bit 3: Reserved, must be kept at reset value */ +#define OTGFS_DCFG_DAD_SHIFT (4) /* Bits 4-10: Device address */ +#define OTGFS_DCFG_DAD_MASK (0x7f << OTGFS_DCFG_DAD_SHIFT) +#define OTGFS_DCFG_PFIVL_SHIFT (11) /* Bits 11-12: Periodic frame interval */ +#define OTGFS_DCFG_PFIVL_MASK (3 << OTGFS_DCFG_PFIVL_SHIFT) +# define OTGFS_DCFG_PFIVL_80PCT (0 << OTGFS_DCFG_PFIVL_SHIFT) /* 80% of the frame interval */ +# define OTGFS_DCFG_PFIVL_85PCT (1 << OTGFS_DCFG_PFIVL_SHIFT) /* 85% of the frame interval */ +# define OTGFS_DCFG_PFIVL_90PCT (2 << OTGFS_DCFG_PFIVL_SHIFT) /* 90% of the frame interval */ +# define OTGFS_DCFG_PFIVL_95PCT (3 << OTGFS_DCFG_PFIVL_SHIFT) /* 95% of the frame interval */ + /* Bits 13-31 Reserved, must be kept at reset value */ +/* Device control register */ + +#define OTGFS_TESTMODE_DISABLED (0) /* Test mode disabled */ +#define OTGFS_TESTMODE_J (1) /* Test_J mode */ +#define OTGFS_TESTMODE_K (2) /* Test_K mode */ +#define OTGFS_TESTMODE_SE0_NAK (3) /* Test_SE0_NAK mode */ +#define OTGFS_TESTMODE_PACKET (4) /* Test_Packet mode */ +#define OTGFS_TESTMODE_FORCE (5) /* Test_Force_Enable */ + +#define OTGFS_DCTL_RWUSIG (1 << 0) /* Bit 0: Remote wakeup signaling */ +#define OTGFS_DCTL_SDIS (1 << 1) /* Bit 1: Soft disconnect */ +#define OTGFS_DCTL_GINSTS (1 << 2) /* Bit 2: Global IN NAK status */ +#define OTGFS_DCTL_GONSTS (1 << 3) /* Bit 3: Global OUT NAK status */ +#define OTGFS_DCTL_TCTL_SHIFT (4) /* Bits 4-6: Test control */ +#define OTGFS_DCTL_TCTL_MASK (7 << OTGFS_DCTL_TCTL_SHIFT) +# define OTGFS_DCTL_TCTL_DISABLED (0 << OTGFS_DCTL_TCTL_SHIFT) /* Test mode disabled */ +# define OTGFS_DCTL_TCTL_J (1 << OTGFS_DCTL_TCTL_SHIFT) /* Test_J mode */ +# define OTGFS_DCTL_TCTL_K (2 << OTGFS_DCTL_TCTL_SHIFT) /* Test_K mode */ +# define OTGFS_DCTL_TCTL_SE0_NAK (3 << OTGFS_DCTL_TCTL_SHIFT) /* Test_SE0_NAK mode */ +# define OTGFS_DCTL_TCTL_PACKET (4 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Packet mode */ +# define OTGFS_DCTL_TCTL_FORCE (5 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Force_Enable */ +#define OTGFS_DCTL_SGINAK (1 << 7) /* Bit 7: Set global IN NAK */ +#define OTGFS_DCTL_CGINAK (1 << 8) /* Bit 8: Clear global IN NAK */ +#define OTGFS_DCTL_SGONAK (1 << 9) /* Bit 9: Set global OUT NAK */ +#define OTGFS_DCTL_CGONAK (1 << 10) /* Bit 10: Clear global OUT NAK */ +#define OTGFS_DCTL_POPRGDNE (1 << 11) /* Bit 11: Power-on programming done */ + /* Bits 12-31: Reserved, must be kept at reset value */ +/* Device status register */ + +#define OTGFS_DSTS_SUSPSTS (1 << 0) /* Bit 0: Suspend status */ +#define OTGFS_DSTS_ENUMSPD_SHIFT (1) /* Bits 1-2: Enumerated speed */ +#define OTGFS_DSTS_ENUMSPD_MASK (3 << OTGFS_DSTS_ENUMSPD_SHIFT) +# define OTGFS_DSTS_ENUMSPD_FS (3 << OTGFS_DSTS_ENUMSPD_MASK) /* Full speed */ + /* Bits 4-7: Reserved, must be kept at reset value */ +#define OTGFS_DSTS_EERR (1 << 3) /* Bit 3: Erratic error */ +#define OTGFS_DSTS_SOFFN_SHIFT (8) /* Bits 8-21: Frame number of the received SOF */ +#define OTGFS_DSTS_SOFFN_MASK (0x3fff << OTGFS_DSTS_SOFFN_SHIFT) +#define OTGFS_DSTS_SOFFN0 (1 << 8) /* Bits 8: Frame number even/odd bit */ +#define OTGFS_DSTS_SOFFN_EVEN 0 +#define OTGFS_DSTS_SOFFN_ODD OTGFS_DSTS_SOFFN0 + /* Bits 22-31: Reserved, must be kept at reset value */ +/* Device IN endpoint common interrupt mask register */ + +#define OTGFS_DIEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */ +#define OTGFS_DIEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DIEPMSK_TOM (1 << 3) /* Bit 3: Timeout condition mask (Non-isochronous endpoints) */ +#define OTGFS_DIEPMSK_ITTXFEMSK (1 << 4) /* Bit 4: IN token received when TxFIFO empty mask */ +#define OTGFS_DIEPMSK_INEPNMM (1 << 5) /* Bit 5: IN token received with EP mismatch mask */ +#define OTGFS_DIEPMSK_INEPNEM (1 << 6) /* Bit 6: IN endpoint NAK effective mask */ + /* Bits 7-31: Reserved, must be kept at reset value */ +/* Device OUT endpoint common interrupt mask register */ + +#define OTGFS_DOEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */ +#define OTGFS_DOEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DOEPMSK_STUPM (1 << 3) /* Bit 3: SETUP phase done mask */ +#define OTGFS_DOEPMSK_OTEPDM (1 << 4) /* Bit 4: OUT token received when endpoint disabled mask */ + /* Bits 5-31: Reserved, must be kept at reset value */ +/* Device all endpoints interrupt and All endpoints interrupt mask registers */ + +#define OTGFS_DAINT_IEP_SHIFT (0) /* Bits 0-15: IN endpoint interrupt bits */ +#define OTGFS_DAINT_IEP_MASK (0xffff << OTGFS_DAINT_IEP_SHIFT) +# define OTGFS_DAINT_IEP(n) (1 << (n)) +#define OTGFS_DAINT_OEP_SHIFT (16) /* Bits 16-31: OUT endpoint interrupt bits */ +#define OTGFS_DAINT_OEP_MASK (0xffff << OTGFS_DAINT_OEP_SHIFT) +# define OTGFS_DAINT_OEP(n) (1 << ((n)+16)) + +/* Device VBUS discharge time register */ + +#define OTGFS_DVBUSDIS_MASK (0xffff) + +/* Device VBUS pulsing time register */ + +#define OTGFS_DVBUSPULSE_MASK (0xfff) + +/* Device IN endpoint FIFO empty interrupt mask register */ + +#define OTGFS_DIEPEMPMSK(n) (1 << (n)) + +/* Device control IN endpoint 0 control register */ + +#define OTGFS_DIEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */ +#define OTGFS_DIEPCTL0_MPSIZ_MASK (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) +# define OTGFS_DIEPCTL0_MPSIZ_64 (0 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 64 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_32 (1 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 32 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_16 (2 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 16 bytes */ +# define OTGFS_DIEPCTL0_MPSIZ_8 (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 8 bytes */ + /* Bits 2-14: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ + /* Bit 16: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DIEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DIEPCTL0_EPTYP_MASK (3 << OTGFS_DIEPCTL0_EPTYP_SHIFT) +# define OTGFS_DIEPCTL0_EPTYP_CTRL (0 << OTGFS_DIEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */ + /* Bit 20: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */ +#define OTGFS_DIEPCTL0_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */ +#define OTGFS_DIEPCTL0_TXFNUM_MASK (15 << OTGFS_DIEPCTL0_TXFNUM_SHIFT) +#define OTGFS_DIEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DIEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */ + /* Bits 28-29: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DIEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device control IN endpoint n control register */ + +#define OTGFS_DIEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_DIEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DIEPCTL_MPSIZ_SHIFT) + /* Bits 11-14: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ +#define OTGFS_DIEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame */ +# define OTGFS_DIEPCTL_EVEN (0) +# define OTGFS_DIEPCTL_ODD OTGFS_DIEPCTL_EONUM +# define OTGFS_DIEPCTL_DATA0 (0) +# define OTGFS_DIEPCTL_DATA1 OTGFS_DIEPCTL_EONUM +#define OTGFS_DIEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DIEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DIEPCTL_EPTYP_MASK (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) +# define OTGFS_DIEPCTL_EPTYP_CTRL (0 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Control */ +# define OTGFS_DIEPCTL_EPTYP_ISOC (1 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_DIEPCTL_EPTYP_BULK (2 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_DIEPCTL_EPTYP_INTR (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Interrupt */ + /* Bit 20: Reserved, must be kept at reset value */ +#define OTGFS_DIEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */ +#define OTGFS_DIEPCTL_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */ +#define OTGFS_DIEPCTL_TXFNUM_MASK (15 << OTGFS_DIEPCTL_TXFNUM_SHIFT) +#define OTGFS_DIEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DIEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */ +#define OTGFS_DIEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */ +#define OTGFS_DIEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous)) */ +#define OTGFS_DIEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous) */ +#define OTGFS_DIEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DIEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device endpoint-n interrupt register */ + +#define OTGFS_DIEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */ +#define OTGFS_DIEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DIEPINT_TOC (1 << 3) /* Bit 3: Timeout condition */ +#define OTGFS_DIEPINT_ITTXFE (1 << 4) /* Bit 4: IN token received when TxFIFO is empty */ + /* Bit 5: Reserved, must be kept at reset value */ +#define OTGFS_DIEPINT_INEPNE (1 << 6) /* Bit 6: IN endpoint NAK effective */ +#define OTGFS_DIEPINT_TXFE (1 << 7) /* Bit 7: Transmit FIFO empty */ + /* Bits 8-31: Reserved, must be kept at reset value */ +/* Device IN endpoint 0 transfer size register */ + +#define OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */ +#define OTGFS_DIEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT) + /* Bits 7-18: Reserved, must be kept at reset value */ +#define OTGFS_DIEPTSIZ0_PKTCNT_SHIFT (19) /* Bits 19-20: Packet count */ +#define OTGFS_DIEPTSIZ0_PKTCNT_MASK (3 << OTGFS_DIEPTSIZ0_PKTCNT_SHIFT) + /* Bits 21-31: Reserved, must be kept at reset value */ +/* Device IN endpoint n transfer size register */ + +#define OTGFS_DIEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_DIEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DIEPTSIZ_XFRSIZ_SHIFT) +#define OTGFS_DIEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */ +#define OTGFS_DIEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DIEPTSIZ_PKTCNT_SHIFT) +#define OTGFS_DIEPTSIZ_MCNT_SHIFT (29) /* Bits 29-30: Multi count */ +#define OTGFS_DIEPTSIZ_MCNT_MASK (3 << OTGFS_DIEPTSIZ_MCNT_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ +/* Device OUT endpoint TxFIFO status register */ + +#define OTGFS_DTXFSTS_MASK (0xffff) + +/* Device OUT endpoint 0 control register */ + +#define OTGFS_DOEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */ +#define OTGFS_DOEPCTL0_MPSIZ_MASK (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) +# define OTGFS_DOEPCTL0_MPSIZ_64 (0 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 64 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_32 (1 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 32 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_16 (2 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 16 bytes */ +# define OTGFS_DOEPCTL0_MPSIZ_8 (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 8 bytes */ + /* Bits 2-14: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ + /* Bit 16: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DOEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DOEPCTL0_EPTYP_MASK (3 << OTGFS_DOEPCTL0_EPTYP_SHIFT) +# define OTGFS_DOEPCTL0_EPTYP_CTRL (0 << OTGFS_DOEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */ +#define OTGFS_DOEPCTL0_SNPM (1 << 20) /* Bit 20: Snoop mode */ +#define OTGFS_DOEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */ + /* Bits 22-25: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DOEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */ + /* Bits 28-29: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DOEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device OUT endpoint n control register */ + +#define OTGFS_DOEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */ +#define OTGFS_DOEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DOEPCTL_MPSIZ_SHIFT) + /* Bits 11-14: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */ +#define OTGFS_DOEPCTL_DPID (1 << 16) /* Bit 16: Endpoint data PID (interrupt/buld) */ +# define OTGFS_DOEPCTL_DATA0 (0) +# define OTGFS_DOEPCTL_DATA1 OTGFS_DOEPCTL_DPID +#define OTGFS_DOEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame (isochronous) */ +# define OTGFS_DOEPCTL_EVEN (0) +# define OTGFS_DOEPCTL_ODD OTGFS_DOEPCTL_EONUM +#define OTGFS_DOEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */ +#define OTGFS_DOEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */ +#define OTGFS_DOEPCTL_EPTYP_MASK (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) +# define OTGFS_DOEPCTL_EPTYP_CTRL (0 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Control */ +# define OTGFS_DOEPCTL_EPTYP_ISOC (1 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Isochronous */ +# define OTGFS_DOEPCTL_EPTYP_BULK (2 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Bulk */ +# define OTGFS_DOEPCTL_EPTYP_INTR (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Interrupt */ +#define OTGFS_DOEPCTL_SNPM (1 << 20) /* Bit 20: Snoop mode */ +#define OTGFS_DOEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */ + /* Bits 22-25: Reserved, must be kept at reset value */ +#define OTGFS_DOEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */ +#define OTGFS_DOEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */ +#define OTGFS_DOEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */ +#define OTGFS_DOEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous) */ +#define OTGFS_DOEPCTL_SD1PID (1 << 29) /* Bit 29: Set DATA1 PID (interrupt/bulk) */ +#define OTGFS_DOEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous */ +#define OTGFS_DOEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */ +#define OTGFS_DOEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */ + +/* Device endpoint-n interrupt register */ + +#define OTGFS_DOEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */ +#define OTGFS_DOEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */ + /* Bit 2: Reserved, must be kept at reset value */ +#define OTGFS_DOEPINT_SETUP (1 << 3) /* Bit 3: SETUP phase done */ +#define OTGFS_DOEPINT_OTEPDIS (1 << 4) /* Bit 4: OUT token received when endpoint disabled */ + /* Bit 5: Reserved, must be kept at reset value */ +#define OTGFS_DOEPINT_B2BSTUP (1 << 6) /* Bit 6: Back-to-back SETUP packets received */ + /* Bits 7-31: Reserved, must be kept at reset value */ +/* Device OUT endpoint-0 transfer size register */ + +#define OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */ +#define OTGFS_DOEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT) + /* Bits 7-18: Reserved, must be kept at reset value */ +#define OTGFS_DOEPTSIZ0_PKTCNT (1 << 19) /* Bit 19 PKTCNT: Packet count */ + /* Bits 20-28: Reserved, must be kept at reset value */ +#define OTGFS_DOEPTSIZ0_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */ +#define OTGFS_DOEPTSIZ0_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ +/* Device OUT endpoint-n transfer size register */ + +#define OTGFS_DOEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */ +#define OTGFS_DOEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DOEPTSIZ_XFRSIZ_SHIFT) +#define OTGFS_DOEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */ +#define OTGFS_DOEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DOEPTSIZ_PKTCNT_SHIFT) +#define OTGFS_DOEPTSIZ_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */ +#define OTGFS_DOEPTSIZ_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ_STUPCNT_SHIFT) +#define OTGFS_DOEPTSIZ_RXDPID_SHIFT (29) /* Bits 29-30: Received data PID */ +#define OTGFS_DOEPTSIZ_RXDPID_MASK (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA0 (0 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA2 (1 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_DATA1 (2 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) +# define OTGFS_DOEPTSIZ_RXDPID_MDATA (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT) + /* Bit 31: Reserved, must be kept at reset value */ +/* Power and clock gating control register */ + +#define OTGFS_PCGCCTL_STPPCLK (1 << 0) /* Bit 0: Stop PHY clock */ +#define OTGFS_PCGCCTL_GATEHCLK (1 << 1) /* Bit 1: Gate HCLK */ + /* Bits 2-3: Reserved, must be kept at reset value */ +#define OTGFS_PCGCCTL_PHYSUSP (1 << 4) /* Bit 4: PHY Suspended */ + /* Bits 5-31: Reserved, must be kept at reset value */ + +#endif /* __ARCH_ARM_SRC_STM32_CHIP_STM32FXXXXX_OTGFS_H */ diff --git a/arch/arm/src/stm32/stm32_can.c b/arch/arm/src/stm32/stm32_can.c index 297394abd25..fd174ffaffe 100644 --- a/arch/arm/src/stm32/stm32_can.c +++ b/arch/arm/src/stm32/stm32_can.c @@ -1070,6 +1070,7 @@ static int can_rx0interrupt(int irq, void *context) /* Get the CAN identifier. */ regval = can_getreg(priv, STM32_CAN_RI0R_OFFSET); + #ifdef CONFIG_CAN_EXTID if ((regval & CAN_RIR_IDE) != 0) { @@ -1089,17 +1090,22 @@ static int can_rx0interrupt(int irq, void *context) goto errout; } - hdr.ch_id = (regval & CAN_RIR_STID_MASK) >> CAN_RIR_STID_SHIFT; + hdr.ch_id = (regval & CAN_RIR_STID_MASK) >> CAN_RIR_STID_SHIFT; #endif + /* Clear the error indication and unused bits */ + + hdr.ch_error = 0; + hdr.ch_unused = 0; + /* Extract the RTR bit */ - hdr.ch_rtr = (regval & CAN_RIR_RTR) != 0 ? true : false; + hdr.ch_rtr = (regval & CAN_RIR_RTR) != 0 ? true : false; /* Get the DLC */ - regval = can_getreg(priv, STM32_CAN_RDT0R_OFFSET); - hdr.ch_dlc = (regval & CAN_RDTR_DLC_MASK) >> CAN_RDTR_DLC_SHIFT; + regval = can_getreg(priv, STM32_CAN_RDT0R_OFFSET); + hdr.ch_dlc = (regval & CAN_RDTR_DLC_MASK) >> CAN_RDTR_DLC_SHIFT; /* Save the message data */ diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c index 1ef3687c04a..50b441af359 100644 --- a/arch/arm/src/stm32/stm32_eth.c +++ b/arch/arm/src/stm32/stm32_eth.c @@ -1670,6 +1670,16 @@ static void stm32_receive(FAR struct stm32_ethmac_s *priv) if (dev->d_len > CONFIG_NET_ETH_MTU) { nlldbg("DROPPED: Too big: %d\n", dev->d_len); + + /* Free dropped packet buffer */ + + if (dev->d_buf) + { + stm32_freebuffer(priv, dev->d_buf); + dev->d_buf = NULL; + dev->d_len = 0; + } + continue; } @@ -1915,7 +1925,7 @@ static void stm32_txdone(FAR struct stm32_ethmac_s *priv) { DEBUGASSERT(priv->txtail != NULL); - /* Scan the TX desciptor change, returning buffers to free list */ + /* Scan the TX descriptor change, returning buffers to free list */ stm32_freeframe(priv); diff --git a/arch/arm/src/stm32/stm32_irq.c b/arch/arm/src/stm32/stm32_irq.c index a9781cf0cee..c3cc59fc8b9 100644 --- a/arch/arm/src/stm32/stm32_irq.c +++ b/arch/arm/src/stm32/stm32_irq.c @@ -2,7 +2,7 @@ * arch/arm/src/stm32/stm32_irq.c * arch/arm/src/chip/stm32_irq.c * - * Copyright (C) 2009-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2009-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -76,8 +76,18 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; +/* This is the address of the exception vector table (determined by the + * linker script). + */ + +extern uint32_t _vectors[]; + /**************************************************************************** * Private Data ****************************************************************************/ @@ -320,15 +330,16 @@ void up_irqinitialize(void) * at address 0x0800:0000. If we are using the STMicro DFU bootloader, then * the vector table will be offset to a different location in FLASH and we * will need to set the NVIC vector location to this alternative location. - * - * If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#if defined(CONFIG_ARCH_RAMVECTORS) up_ramvec_initialize(); -#elif defined(CONFIG_STM32_DFU) - putreg32((uint32_t)_vectors, NVIC_VECTAB); #endif /* Set all interrupts (and exceptions) to the default priority */ diff --git a/arch/arm/src/stm32/stm32_otgfs.h b/arch/arm/src/stm32/stm32_otgfs.h index 79258168fc0..64369969df8 100644 --- a/arch/arm/src/stm32/stm32_otgfs.h +++ b/arch/arm/src/stm32/stm32_otgfs.h @@ -45,7 +45,12 @@ #include #include "stm32.h" -#include "chip/stm32_otgfs.h" + +#if defined(CONFIG_STM32_STM32F446) +# include "chip/stm32f44xxx_otgfs.h" +#else +# include "chip/stm32fxxxxx_otgfs.h" +#endif #if defined(CONFIG_STM32_OTGFS) diff --git a/arch/arm/src/stm32/stm32_otgfsdev.c b/arch/arm/src/stm32/stm32_otgfsdev.c index a7e90c69499..1da5733f6d1 100644 --- a/arch/arm/src/stm32/stm32_otgfsdev.c +++ b/arch/arm/src/stm32/stm32_otgfsdev.c @@ -5169,16 +5169,45 @@ static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv) /* Deactivate the power down */ +#if defined(CONFIG_STM32_STM32F446) + /* In the case of the STM32F446 the meaning of the bit has changed to VBUS + * Detection Enable when set + */ + + regval = OTGFS_GCCFG_PWRDWN; + +# ifdef CONFIG_USBDEV_VBUSSENSING + regval |= OTGFS_GCCFG_VBDEN; +# endif + +#else + /* In the case of the the all others the meaning of the bit is No VBUS + * Sense when Set + */ + regval = (OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | OTGFS_GCCFG_VBUSBSEN); -#ifndef CONFIG_USBDEV_VBUSSENSING +# ifndef CONFIG_USBDEV_VBUSSENSING regval |= OTGFS_GCCFG_NOVBUSSENS; -#endif -#ifdef CONFIG_STM32_OTGFS_SOFOUTPUT +# endif +# ifdef CONFIG_STM32_OTGFS_SOFOUTPUT regval |= OTGFS_GCCFG_SOFOUTEN; +# endif #endif stm32_putreg(regval, STM32_OTGFS_GCCFG); up_mdelay(20); + /* For the new OTG controller in the F446 when VBUS sensing is not used we + * need to force the B session valid + */ + +#if defined(CONFIG_STM32_STM32F446) +# ifndef CONFIG_USBDEV_VBUSSENSING + regval = stm32_getreg(STM32_OTGFS_GOTGCTL); + regval |= (OTGFS_GOTGCTL_BVALOEN | OTGFS_GOTGCTL_BVALOVAL); + stm32_putreg(regval, STM32_OTGFS_GOTGCTL); +# endif +#endif + /* Force Device Mode */ regval = stm32_getreg(STM32_OTGFS_GUSBCFG); diff --git a/arch/arm/src/stm32/stm32_otgfshost.c b/arch/arm/src/stm32/stm32_otgfshost.c index 56e09db17a5..d717ce2eb01 100644 --- a/arch/arm/src/stm32/stm32_otgfshost.c +++ b/arch/arm/src/stm32/stm32_otgfshost.c @@ -1093,7 +1093,7 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, /* Loop, testing for an end of transfer condition. The channel 'result' * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' * will be set to false and 'result' will be set appropriately when the - * tranfer is completed. + * transfer is completed. */ do diff --git a/arch/arm/src/stm32/stm32_otghshost.c b/arch/arm/src/stm32/stm32_otghshost.c index 9e9cc0e9786..3d7340ca904 100644 --- a/arch/arm/src/stm32/stm32_otghshost.c +++ b/arch/arm/src/stm32/stm32_otghshost.c @@ -1093,7 +1093,7 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, /* Loop, testing for an end of transfer condition. The channel 'result' * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' * will be set to false and 'result' will be set appropriately when the - * tranfer is completed. + * transfer is completed. */ do diff --git a/arch/arm/src/stm32/stm32f42xxx_rcc.c b/arch/arm/src/stm32/stm32f42xxx_rcc.c index c28435842f3..b6082e44e74 100644 --- a/arch/arm/src/stm32/stm32f42xxx_rcc.c +++ b/arch/arm/src/stm32/stm32f42xxx_rcc.c @@ -672,21 +672,21 @@ static void stm32_stdclockconfig(void) /* Set the HCLK source/divider */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_HPRE_MASK; regval |= STM32_RCC_CFGR_HPRE; putreg32(regval, STM32_RCC_CFGR); /* Set the PCLK2 divider */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_PPRE2_MASK; regval |= STM32_RCC_CFGR_PPRE2; putreg32(regval, STM32_RCC_CFGR); /* Set the PCLK1 divider */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_PPRE1_MASK; regval |= STM32_RCC_CFGR_PPRE1; putreg32(regval, STM32_RCC_CFGR); @@ -694,7 +694,7 @@ static void stm32_stdclockconfig(void) #ifdef CONFIG_RTC_HSECLOCK /* Set the RTC clock divisor */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_RTCPRE_MASK; regval |= RCC_CFGR_RTCPRE(HSE_DIVISOR); putreg32(regval, STM32_RCC_CFGR); @@ -713,7 +713,7 @@ static void stm32_stdclockconfig(void) /* Enable the main PLL */ - regval = getreg32(STM32_RCC_CR); + regval = getreg32(STM32_RCC_CR); regval |= RCC_CR_PLLON; putreg32(regval, STM32_RCC_CR); @@ -766,19 +766,19 @@ static void stm32_stdclockconfig(void) #ifdef CONFIG_STM32_LTDC /* Configure PLLSAI */ - regval = getreg32(STM32_RCC_PLLSAICFGR); + regval = getreg32(STM32_RCC_PLLSAICFGR); regval |= (STM32_RCC_PLLSAICFGR_PLLSAIN | STM32_RCC_PLLSAICFGR_PLLSAIR | STM32_RCC_PLLSAICFGR_PLLSAIQ); putreg32(regval, STM32_RCC_PLLSAICFGR); - regval = getreg32(STM32_RCC_DCKCFGR); + regval = getreg32(STM32_RCC_DCKCFGR); regval |= STM32_RCC_DCKCFGR_PLLSAIDIVR; putreg32(regval, STM32_RCC_DCKCFGR); /* Enable PLLSAI */ - regval = getreg32(STM32_RCC_CR); + regval = getreg32(STM32_RCC_CR); regval |= RCC_CR_PLLSAION; putreg32(regval, STM32_RCC_CR); diff --git a/arch/arm/src/stm32/stm32f44xxx_rcc.c b/arch/arm/src/stm32/stm32f44xxx_rcc.c index d7962be922f..903d4183afa 100644 --- a/arch/arm/src/stm32/stm32f44xxx_rcc.c +++ b/arch/arm/src/stm32/stm32f44xxx_rcc.c @@ -604,21 +604,21 @@ static void stm32_stdclockconfig(void) /* Set the HCLK source/divider */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_HPRE_MASK; regval |= STM32_RCC_CFGR_HPRE; putreg32(regval, STM32_RCC_CFGR); /* Set the PCLK2 divider */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_PPRE2_MASK; regval |= STM32_RCC_CFGR_PPRE2; putreg32(regval, STM32_RCC_CFGR); /* Set the PCLK1 divider */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_PPRE1_MASK; regval |= STM32_RCC_CFGR_PPRE1; putreg32(regval, STM32_RCC_CFGR); @@ -626,7 +626,7 @@ static void stm32_stdclockconfig(void) #ifdef CONFIG_RTC_HSECLOCK /* Set the RTC clock divisor */ - regval = getreg32(STM32_RCC_CFGR); + regval = getreg32(STM32_RCC_CFGR); regval &= ~RCC_CFGR_RTCPRE_MASK; regval |= RCC_CFGR_RTCPRE(HSE_DIVISOR); putreg32(regval, STM32_RCC_CFGR); @@ -645,7 +645,7 @@ static void stm32_stdclockconfig(void) /* Enable the main PLL */ - regval = getreg32(STM32_RCC_CR); + regval = getreg32(STM32_RCC_CR); regval |= RCC_CR_PLLON; putreg32(regval, STM32_RCC_CR); @@ -664,7 +664,7 @@ static void stm32_stdclockconfig(void) { } - regval = getreg32(STM32_PWR_CR); + regval = getreg32(STM32_PWR_CR); regval |= PWR_CR_ODSWEN; putreg32(regval, STM32_PWR_CR); while ((getreg32(STM32_PWR_CSR) & PWR_CSR_ODSWRDY) == 0) @@ -697,14 +697,25 @@ static void stm32_stdclockconfig(void) /* Configure PLLSAI */ - regval = getreg32(STM32_RCC_PLLSAICFGR); + regval = getreg32(STM32_RCC_PLLSAICFGR); + regval &= ~(RCC_PLLSAICFGR_PLLSAIM_MASK | + RCC_PLLSAICFGR_PLLSAIN_MASK | + RCC_PLLSAICFGR_PLLSAIP_MASK | + RCC_PLLSAICFGR_PLLSAIQ_MASK); regval |= (STM32_RCC_PLLSAICFGR_PLLSAIM | STM32_RCC_PLLSAICFGR_PLLSAIN | STM32_RCC_PLLSAICFGR_PLLSAIP | STM32_RCC_PLLSAICFGR_PLLSAIQ); putreg32(regval, STM32_RCC_PLLSAICFGR); - regval = getreg32(STM32_RCC_DCKCFGR); + regval = getreg32(STM32_RCC_DCKCFGR); + regval &= ~(RCC_DCKCFGR_PLLI2SDIVQ_MASK | + RCC_DCKCFGR_PLLSAIDIVQ_MASK | + RCC_DCKCFGR_SAI1SRC_MASK | + RCC_DCKCFGR_SAI2SRC_MASK | + RCC_DCKCFGR_I2S1SRC_MASK | + RCC_DCKCFGR_I2S2SRC_MASK); + regval |= (STM32_RCC_DCKCFGR_PLLI2SDIVQ | STM32_RCC_DCKCFGR_PLLSAIDIVQ | STM32_RCC_DCKCFGR_SAI1SRC @@ -717,7 +728,7 @@ static void stm32_stdclockconfig(void) /* Enable PLLSAI */ - regval = getreg32(STM32_RCC_CR); + regval = getreg32(STM32_RCC_CR); regval |= RCC_CR_PLLSAION; putreg32(regval, STM32_RCC_CR); @@ -732,7 +743,11 @@ static void stm32_stdclockconfig(void) /* Configure PLLI2S */ - regval = getreg32(STM32_RCC_PLLI2SCFGR); + regval = getreg32(STM32_RCC_PLLI2SCFGR); + regval &= ~(RCC_PLLI2SCFGR_PLLI2SM_MASK | + RCC_PLLI2SCFGR_PLLI2SN_MASK | + RCC_PLLI2SCFGR_PLLI2SP_MASK | + RCC_PLLI2SCFGR_PLLI2SQ_MASK); regval |= (STM32_RCC_PLLI2SCFGR_PLLI2SM | STM32_RCC_PLLI2SCFGR_PLLI2SN | STM32_RCC_PLLI2SCFGR_PLLI2SP @@ -740,7 +755,12 @@ static void stm32_stdclockconfig(void) | STM32_RCC_PLLI2SCFGR_PLLI2SR); putreg32(regval, STM32_RCC_PLLI2SCFGR); - regval = getreg32(STM32_RCC_DCKCFGR2); + regval = getreg32(STM32_RCC_DCKCFGR2); + regval &= ~(RCC_DCKCFGR2_FMPI2C1SEL_MASK | + RCC_DCKCFGR2_CECSEL_MASK | + RCC_DCKCFGR2_CK48MSEL_MASK | + RCC_DCKCFGR2_SDIOCSEL_MASK | + RCC_DCKCFGR2_SPDIFRXEL_MASK); regval |= (STM32_RCC_DCKCFGR2_FMPI2C1SEL | STM32_RCC_DCKCFGR2_CECSEL | STM32_RCC_DCKCFGR2_CK48MSEL @@ -751,7 +771,7 @@ static void stm32_stdclockconfig(void) /* Enable PLLI2S */ - regval = getreg32(STM32_RCC_CR); + regval = getreg32(STM32_RCC_CR); regval |= RCC_CR_PLLI2SON; putreg32(regval, STM32_RCC_CR); @@ -762,8 +782,6 @@ static void stm32_stdclockconfig(void) } #endif - - #if defined(CONFIG_STM32_IWDG) || defined(CONFIG_RTC_LSICLOCK) /* Low speed internal clock source LSI */ diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c index a2ba9192512..c52e768047b 100644 --- a/arch/arm/src/stm32f7/stm32_ethernet.c +++ b/arch/arm/src/stm32f7/stm32_ethernet.c @@ -2042,7 +2042,7 @@ static void stm32_txdone(struct stm32_ethmac_s *priv) { DEBUGASSERT(priv->txtail != NULL); - /* Scan the TX desciptor change, returning buffers to free list */ + /* Scan the TX descriptor change, returning buffers to free list */ stm32_freeframe(priv); diff --git a/arch/arm/src/stm32f7/stm32_irq.c b/arch/arm/src/stm32f7/stm32_irq.c index 632fad2e2e9..59360736629 100644 --- a/arch/arm/src/stm32f7/stm32_irq.c +++ b/arch/arm/src/stm32f7/stm32_irq.c @@ -80,7 +80,16 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; + +/* This is the address of the exception vector table (determined by the + * linker script). + */ + extern uint32_t _vectors[]; /**************************************************************************** @@ -412,16 +421,21 @@ void up_irqinitialize(void) } #endif - /* Set up the vector table address. - * - * If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS + /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#if defined(CONFIG_ARCH_RAMVECTORS) up_ramvec_initialize(); -#elif defined(CONFIG_STM32F7_BOOTLOADER) - putreg32((uint32_t)_vectors, NVIC_VECTAB); #endif /* Set all interrupts (and exceptions) to the default priority */ diff --git a/arch/arm/src/tiva/tiva_irq.c b/arch/arm/src/tiva/tiva_irq.c index c2fc896e436..c9c9e15127d 100644 --- a/arch/arm/src/tiva/tiva_irq.c +++ b/arch/arm/src/tiva/tiva_irq.c @@ -77,8 +77,18 @@ * Public Data ****************************************************************************/ +/* This is the address of current interrupt saved state data. Used for + * context switching. Only value during interrupt handling. + */ + volatile uint32_t *current_regs; +/* This is the address of the exception vector table (determined by the + * linker script). + */ + +extern uint32_t _vectors[]; + /**************************************************************************** * Private Data ****************************************************************************/ @@ -380,11 +390,20 @@ void up_irqinitialize(void) putreg32(0, regaddr); } + /* Make sure that we are using the correct vector table. The default + * vector address is 0x0000:0000 but if we are executing code that is + * positioned in SRAM or in external FLASH, then we may need to reset + * the interrupt vector so that it refers to the table in SRAM or in + * external FLASH. + */ + + putreg32((uint32_t)_vectors, NVIC_VECTAB); + +#ifdef CONFIG_ARCH_RAMVECTORS /* If CONFIG_ARCH_RAMVECTORS is defined, then we are using a RAM-based * vector table that requires special initialization. */ -#ifdef CONFIG_ARCH_RAMVECTORS up_ramvec_initialize(); #endif @@ -392,7 +411,6 @@ void up_irqinitialize(void) putreg32((uint32_t)CONFIG_RAM_START, NVIC_VECTAB); #endif - /* Set all interrupts (and exceptions) to the default priority */ putreg32(DEFPRIORITY32, NVIC_SYSH4_7_PRIORITY); diff --git a/arch/avr/src/at32uc3/at32uc3_ssc.h b/arch/avr/src/at32uc3/at32uc3_ssc.h index 35b286b6aed..e5c1df3c624 100644 --- a/arch/avr/src/at32uc3/at32uc3_ssc.h +++ b/arch/avr/src/at32uc3/at32uc3_ssc.h @@ -114,7 +114,7 @@ #define SSC_RCMR_CKI (1 << 5) /* Bit 5: Receive Clock Inversion */ #define SSC_RCMR_CKG_SHIFT (6) /* Bits 6-7: Receive Clock Gating Selection */ #define SSC_RCMR_CKG_MASK (3 << SSC_RCMR_CKG_SHIFT) -# define SSC_RCMR_CKG_NONE (0 << SSC_RCMR_CKG_SHIFT) /* None, continous clock */ +# define SSC_RCMR_CKG_NONE (0 << SSC_RCMR_CKG_SHIFT) /* None, continuous clock */ # define SSC_RCMR_CKG_LOW (1 << SSC_RCMR_CKG_SHIFT) /* Enable if RX_FRAME_SYNC low */ # define SSC_RCMR_CKG_HIGH (2 << SSC_RCMR_CKG_SHIFT) /* Enable if RX_FRAME_SYNC high */ #define SSC_RCMR_START_SHIFT (8) /* Bits 8-11: Receive Start Selection */ @@ -171,7 +171,7 @@ #define SSC_TCMR_CKI (1 << 5) /* Bit 5: Transmit Clock Inversion */ #define SSC_TCMR_CKG_SHIFT (6) /* Bits 6-7: Transmit Clock Gating Selection */ #define SSC_TCMR_CKG_MASK (3 << SSC_TCMR_CKG_SHIFT) -# define SSC_TCMR_CKG_NONE (0 << SSC_TCMR_CKG_SHIFT) /* None, continous clock */ +# define SSC_TCMR_CKG_NONE (0 << SSC_TCMR_CKG_SHIFT) /* None, continuous clock */ # define SSC_TCMR_CKG_LOW (1 << SSC_TCMR_CKG_SHIFT) /* Enable if TX_FRAME_SYNC low */ # define SSC_TCMR_CKG_HIGH (2 << SSC_TCMR_CKG_SHIFT) /* Enable if TX_FRAME_SYNC high */ #define SSC_TCMR_START_SHIFT (8) /* Bits 8-11: Transmit Start Selection */ diff --git a/arch/mips/src/pic32mx/pic32mx-ethernet.c b/arch/mips/src/pic32mx/pic32mx-ethernet.c index 1b9c575045e..32120fba1ab 100644 --- a/arch/mips/src/pic32mx/pic32mx-ethernet.c +++ b/arch/mips/src/pic32mx/pic32mx-ethernet.c @@ -1005,7 +1005,7 @@ static struct pic32mx_rxdesc_s *pic32mx_rxdesc(struct pic32mx_driver_s *priv) rxdesc = &priv->pd_rxdesc[i]; if ((rxdesc->status & RXDESC_STATUS_EOWN) == 0) { - /* Yes.. return a pointer to the desciptor */ + /* Yes.. return a pointer to the descriptor */ return rxdesc; } diff --git a/arch/mips/src/pic32mx/pic32mx-usbdev.c b/arch/mips/src/pic32mx/pic32mx-usbdev.c index c9d6c0e9d36..cc05aef6e91 100644 --- a/arch/mips/src/pic32mx/pic32mx-usbdev.c +++ b/arch/mips/src/pic32mx/pic32mx-usbdev.c @@ -2876,7 +2876,7 @@ static int pic32mx_interrupt(int irq, void *context) usbtrace(TRACE_INTDECODE(PIC32MX_TRACEINTID_TRNCS), regval); - /* Handle the endpoint tranfer complete event. */ + /* Handle the endpoint transfer complete event. */ epno = (regval & USB_STAT_ENDPT_MASK) >> USB_STAT_ENDPT_SHIFT; if (epno == 0) diff --git a/arch/mips/src/pic32mz/pic32mz-ethernet.c b/arch/mips/src/pic32mz/pic32mz-ethernet.c index e33c063078c..7a0e65f0975 100644 --- a/arch/mips/src/pic32mz/pic32mz-ethernet.c +++ b/arch/mips/src/pic32mz/pic32mz-ethernet.c @@ -1023,7 +1023,7 @@ static struct pic32mz_rxdesc_s *pic32mz_rxdesc(struct pic32mz_driver_s *priv) rxdesc = &priv->pd_rxdesc[i]; if ((rxdesc->status & RXDESC_STATUS_EOWN) == 0) { - /* Yes.. return a pointer to the desciptor */ + /* Yes.. return a pointer to the descriptor */ return rxdesc; }