diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 92e6209014..5bda5de53a 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -179,9 +179,38 @@ config STM32L4_FMC bool "FMC" default n -config STM32L4_QUADSPI +config STM32L4_QSPI bool "QuadSPI" default n + ---help--- + The STM32L4 QSPI block is intended to support one serial NOR flash device + +if STM32L4_QSPI + +config STM32L4_QSPI_FLASH_SIZE + int "Size of attached serial flash, bytes" + default 16777216 + range 1 2147483648 + ---help--- + The STM32L4 QSPI peripheral requires the size of the Flash be specified + +config STM32L4_QSPI_FIFO_THESHOLD + int "Number of bytes before asserting FIFO threshold flag" + default 4 + range 1 16 + ---help--- + The STM32L4 QSPI peripheral requires that the FIFO threshold be specified + I would leave it at the default value of 4 unless you know what you are doing. + +config STM32L4_QSPI_CSHT + int "Number of cycles Chip Select must be inactive between transactions" + default 1 + range 1 8 + ---help--- + The STM32L4 QSPI peripheral requires that it be specified the minimum number + of AHB cycles that Chip Select be held inactive between transactions. + +endif comment "APB1 Peripherals" diff --git a/arch/arm/src/stm32l4/Make.defs b/arch/arm/src/stm32l4/Make.defs index 9353e81c99..d9f3fb8341 100644 --- a/arch/arm/src/stm32l4/Make.defs +++ b/arch/arm/src/stm32l4/Make.defs @@ -157,3 +157,7 @@ endif ifeq ($(CONFIG_STM32L4_RNG),y) CHIP_CSRCS += stm32l4_rng.c endif + +ifeq ($(CONFIG_STM32L4_QSPI),y) +CHIP_CSRCS += stm32l4_qspi.c +endif diff --git a/arch/arm/src/stm32l4/chip/stm32l4_qspi.h b/arch/arm/src/stm32l4/chip/stm32l4_qspi.h new file mode 100644 index 0000000000..f6385309be --- /dev/null +++ b/arch/arm/src/stm32l4/chip/stm32l4_qspi.h @@ -0,0 +1,239 @@ +/**************************************************************************** + * arch/arm/src/stm32l4/chip/stm32l4_qspi.h + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: dev@ziggurat29.com + * + * 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_STM32L4_CHIP_STM32L4_QSPI_H +#define __ARCH_ARM_SRC_STM32L4_CHIP_STM32L4_QSPI_H + +/**************************************************************************************** + * Included Files + ****************************************************************************************/ + +#include +#include + +#include "chip/stm32l4_memorymap.h" + +/**************************************************************************************** + * Pre-processor Definitions + ****************************************************************************************/ +/* General Characteristics **************************************************************/ + +#define STM32L4_QSPI_MINBITS 8 /* Minimum word width */ +#define STM32L4_QSPI_MAXBITS 32 /* Maximum word width */ + + +/* QSPI register offsets ****************************************************************/ + +#define STM32L4_QUADSPI_CR_OFFSET 0x0000 /* Control Register */ +#define STM32L4_QUADSPI_DCR_OFFSET 0x0004 /* Device Configuration Register */ +#define STM32L4_QUADSPI_SR_OFFSET 0x0008 /* Status Register */ +#define STM32L4_QUADSPI_FCR_OFFSET 0x000c /* Flag Clear Register */ +#define STM32L4_QUADSPI_DLR_OFFSET 0x0010 /* Data Length Register */ +#define STM32L4_QUADSPI_CCR_OFFSET 0x0014 /* Communication Configuration Register */ +#define STM32L4_QUADSPI_AR_OFFSET 0x0018 /* Address Register */ +#define STM32L4_QUADSPI_ABR_OFFSET 0x001c /* Alternate Bytes Register */ +#define STM32L4_QUADSPI_DR_OFFSET 0x0020 /* Data Register */ +#define STM32L4_QUADSPI_PSMKR_OFFSET 0x0024 /* Polling Status mask Register */ +#define STM32L4_QUADSPI_PSMAR_OFFSET 0x0028 /* Polling Status match Register */ +#define STM32L4_QUADSPI_PIR_OFFSET 0x002c /* Polling Interval Register */ +#define STM32L4_QUADSPI_LPTR_OFFSET 0x0030 /* Low-Power Timeout Register */ + +/* QSPI register addresses **************************************************************/ + +#define STM32L4_QUADSPI_CR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_CR_OFFSET) /* Control Register */ +#define STM32L4_QUADSPI_DCR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_DCR_OFFSET) /* Device Configuration Register */ +#define STM32L4_QUADSPI_SR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_SR_OFFSET) /* Status Register */ +#define STM32L4_QUADSPI_FCR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_FCR_OFFSET) /* Flag Clear Register */ +#define STM32L4_QUADSPI_DLR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_DLR_OFFSET) /* Data Length Register */ +#define STM32L4_QUADSPI_CCR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_CCR_OFFSET) /* Communication Configuration Register */ +#define STM32L4_QUADSPI_AR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_AR_OFFSET) /* Address Register */ +#define STM32L4_QUADSPI_ABR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_ABR_OFFSET) /* Alternate Bytes Register */ +#define STM32L4_QUADSPI_DR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_DR_OFFSET) /* Data Register */ +#define STM32L4_QUADSPI_PSMKR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_PSMKR_OFFSET) /* Polling Status mask Register */ +#define STM32L4_QUADSPI_PSMAR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_PSMAR_OFFSET) /* Polling Status match Register */ +#define STM32L4_QUADSPI_PIR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_PIR_OFFSET) /* Polling Interval Register */ +#define STM32L4_QUADSPI_LPTR (STM32L4_QSPI_BASE+STM32L4_QUADSPI_LPTR_OFFSET) /* Low-Power Timeout Register */ + +/* QSPI register bit definitions ********************************************************/ + +/* Control Register */ + +#define QSPI_CR_EN (1 << 0) /* Bit 0: QSPI Enable */ +#define QSPI_CR_ABORT (1 << 1) /* Bit 1: Abort request */ +#define QSPI_CR_DMAEN (1 << 2) /* Bit 2: DMA enable */ +#define QSPI_CR_TCEN (1 << 3) /* Bit 3: Timeout counter enable */ +#define QSPI_CR_SSHIFT (1 << 4) /* Bit 4: Sample shift */ +#define QSPI_CR_FTHRES_SHIFT (8) /* Bits 8-15: FIFO threshold level */ +#define QSPI_CR_FTHRES_MASK (0xff << QSPI_CR_FTHRES_SHIFT) +#define QSPI_CR_TEIE (1 << 16) /* Bit 16: Transfer error interrupt enable */ +#define QSPI_CR_TCIE (1 << 17) /* Bit 17: Transfer complete interrupt enable */ +#define QSPI_CR_FTIE (1 << 18) /* Bit 18: FIFO threshold interrupt enable */ +#define QSPI_CR_SMIE (1 << 19) /* Bit 19: Status match interrupt enable */ +#define QSPI_CR_TOIE (1 << 20) /* Bit 20: TimeOut interrupt enable */ +#define QSPI_CR_APMS (1 << 22) /* Bit 22: Automatic poll mode stop */ +#define QSPI_CR_PMM (1 << 23) /* Bit 23: Polling match mode */ +#define QSPI_CR_PRESCALER_SHIFT (24) /* Bits 24-31: Clock prescaler */ +#define QSPI_CR_PRESCALER_MASK (0xff << QSPI_CR_PRESCALER_SHIFT) + +/* Device Configuration Register */ + +#define QSPI_DCR_CKMODE (1 << 0) /* Bit 0: Mode 0 / mode 3 */ +#define QSPI_DCR_CSHT_SHIFT (8) /* Bits 8-10: Chip select high time */ +#define QSPI_DCR_CSHT_MASK (0x7 << QSPI_DCR_CSHT_SHIFT) +#define QSPI_DCR_FSIZE_SHIFT (16) /* Bits 16-20: Flash memory size */ +#define QSPI_DCR_FSIZE_MASK (0x1f << QSPI_DCR_FSIZE_SHIFT) + +/* Status Register */ + +#define QSPI_SR_TEF (1 << 0) /* Bit 0: Transfer error flag */ +#define QSPI_SR_TCF (1 << 1) /* Bit 1: Transfer complete flag */ +#define QSPI_SR_FTF (1 << 2) /* Bit 2: FIFO threshold flag */ +#define QSPI_SR_SMF (1 << 3) /* Bit 3: Status match flag */ +#define QSPI_SR_TOF (1 << 4) /* Bit 4: Timeout flag */ +#define QSPI_SR_BUSY (1 << 5) /* Bit 5: Busy */ +#define QSPI_SR_FLEVEL_SHIFT (8) /* Bits 8-12: FIFO threshold level */ +#define QSPI_SR_FLEVEL_MASK (0x1f << QSPI_SR_FLEVEL_SHIFT) + +/* Flag Clear Register */ + +#define QSPI_FCR_CTEF (1 << 0) /* Bit 0: Clear Transfer error flag */ +#define QSPI_FCR_CTCF (1 << 1) /* Bit 1: Clear Transfer complete flag */ +#define QSPI_FCR_CSMF (1 << 3) /* Bit 3: Clear Status match flag */ +#define QSPI_FCR_CTOF (1 << 4) /* Bit 4: Clear Timeout flag */ + +/* Data Length Register */ + +/* Communication Configuration Register */ + +#define CCR_IMODE_NONE 0 /* No instruction */ +#define CCR_IMODE_SINGLE 1 /* Instruction on a single line */ +#define CCR_IMODE_DUAL 2 /* Instruction on two lines */ +#define CCR_IMODE_QUAD 3 /* Instruction on four lines */ + +#define CCR_ADMODE_NONE 0 /* No address */ +#define CCR_ADMODE_SINGLE 1 /* Address on a single line */ +#define CCR_ADMODE_DUAL 2 /* Address on two lines */ +#define CCR_ADMODE_QUAD 3 /* Address on four lines */ + +#define CCR_ADSIZE_8 0 /* 8-bit address */ +#define CCR_ADSIZE_16 1 /* 16-bit address */ +#define CCR_ADSIZE_24 2 /* 24-bit address */ +#define CCR_ADSIZE_32 3 /* 32-bit address */ + +#define CCR_ABMODE_NONE 0 /* No alternate bytes */ +#define CCR_ABMODE_SINGLE 1 /* Alternate bytes on a single line */ +#define CCR_ABMODE_DUAL 2 /* Alternate bytes on two lines */ +#define CCR_ABMODE_QUAD 3 /* Alternate bytes on four lines */ + +#define CCR_ABSIZE_8 0 /* 8-bit alternate byte */ +#define CCR_ABSIZE_16 1 /* 16-bit alternate bytes */ +#define CCR_ABSIZE_24 2 /* 24-bit alternate bytes */ +#define CCR_ABSIZE_32 3 /* 32-bit alternate bytes */ + +#define CCR_DMODE_NONE 0 /* No data */ +#define CCR_DMODE_SINGLE 1 /* Data on a single line */ +#define CCR_DMODE_DUAL 2 /* Data on two lines */ +#define CCR_DMODE_QUAD 3 /* Data on four lines */ + +#define CCR_FMODE_INDWR 0 /* Indirect write mode */ +#define CCR_FMODE_INDRD 1 /* Indirect read mode */ +#define CCR_FMODE_AUTOPOLL 2 /* Automatic polling mode */ +#define CCR_FMODE_MEMMAP 3 /* Memory-mapped mode */ + +#define QSPI_CCR_INSTRUCTION_SHIFT (0) /* Bits 0-7: Instruction */ +#define QSPI_CCR_INSTRUCTION_MASK (0xff << QSPI_CCR_INSTRUCTION_SHIFT) +# define QSPI_CCR_INST(n) ((uint32_t)(n) << QSPI_CCR_INSTRUCTION_SHIFT) +#define QSPI_CCR_IMODE_SHIFT (8) /* Bits 8-9: Instruction mode */ +#define QSPI_CCR_IMODE_MASK (0x3 << QSPI_CCR_IMODE_SHIFT) +# define QSPI_CCR_IMODE(n) ((uint32_t)(n) << QSPI_CCR_IMODE_SHIFT) +#define QSPI_CCR_ADMODE_SHIFT (10) /* Bits 10-11: Address mode */ +#define QSPI_CCR_ADMODE_MASK (0x3 << QSPI_CCR_ADMODE_SHIFT) +# define QSPI_CCR_ADMODE(n) ((uint32_t)(n) << QSPI_CCR_ADMODE_SHIFT) +#define QSPI_CCR_ADSIZE_SHIFT (12) /* Bits 12-13: Address size */ +#define QSPI_CCR_ADSIZE_MASK (0x3 << QSPI_CCR_ADSIZE_SHIFT) +# define QSPI_CCR_ADSIZE(n) ((uint32_t)(n) << QSPI_CCR_ADSIZE_SHIFT) +#define QSPI_CCR_ABMODE_SHIFT (14) /* Bits 14-15: Alternate bytes mode */ +#define QSPI_CCR_ABMODE_MASK (0x3 << QSPI_CCR_ABMODE_SHIFT) +# define QSPI_CCR_ABMODE(n) ((uint32_t)(n) << QSPI_CCR_ABMODE_SHIFT) +#define QSPI_CCR_ABSIZE_SHIFT (16) /* Bits 16-17: Alternate bytes size */ +#define QSPI_CCR_ABSIZE_MASK (0x3 << QSPI_CCR_ABSIZE_SHIFT) +# define QSPI_CCR_ABSIZE(n) ((uint32_t)(n) << QSPI_CCR_ABSIZE_SHIFT) +#define QSPI_CCR_DCYC_SHIFT (18) /* Bits 18-23: Number of dummy cycles */ +#define QSPI_CCR_DCYC_MASK (0x1f << QSPI_CCR_DCYC_SHIFT) +# define QSPI_CCR_DCYC(n) ((uint32_t)(n) << QSPI_CCR_DCYC_SHIFT) +#define QSPI_CCR_DMODE_SHIFT (24) /* Bits 24-25: Data mode */ +#define QSPI_CCR_DMODE_MASK (0x3 << QSPI_CCR_DMODE_SHIFT) +# define QSPI_CCR_DMODE(n) ((uint32_t)(n) << QSPI_CCR_DMODE_SHIFT) +#define QSPI_CCR_FMODE_SHIFT (26) /* Bits 26-27: Functional mode */ +#define QSPI_CCR_FMODE_MASK (0x3 << QSPI_CCR_FMODE_SHIFT) +# define QSPI_CCR_FMODE(n) ((uint32_t)(n) << QSPI_CCR_FMODE_SHIFT) +#define QSPI_CCR_SIOO (1 << 28) /* Bit 28: Send instruction only once mode */ +#define QSPI_CCR_DDRM (1 << 31) /* Bit 31: Double data rate mode */ + +/* Address Register */ + +/* Alternate Bytes Register */ + +/* Data Register */ + +/* Polling Status mask Register */ + +/* Polling Status match Register */ + +/* Polling Interval Register */ + +#define QSPI_PIR_INTERVAL_SHIFT (0) /* Bits 0-15: Polling interval */ +#define QSPI_PIR_INTERVAL_MASK (0xFFff << QSPI_PIR_INTERVAL_SHIFT) + +/* Low-Power Timeout Register */ + +#define QSPI_LPTR_TIMEOUT_SHIFT (0) /* Bits 0-15: Timeout period */ +#define QSPI_LPTR_TIMEOUT_MASK (0xFFff << QSPI_PIR_INTERVAL_SHIFT) + +/**************************************************************************************** + * Public Types + ****************************************************************************************/ + +/**************************************************************************************** + * Public Data + ****************************************************************************************/ + +/**************************************************************************************** + * Public Functions + ****************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_STM32L4_CHIP_STM32L4_QSPI_H */ + + diff --git a/arch/arm/src/stm32l4/chip/stm32l4x6xx_pinmap.h b/arch/arm/src/stm32l4/chip/stm32l4x6xx_pinmap.h index d711f730bf..8a564fc377 100644 --- a/arch/arm/src/stm32l4/chip/stm32l4x6xx_pinmap.h +++ b/arch/arm/src/stm32l4/chip/stm32l4x6xx_pinmap.h @@ -359,18 +359,18 @@ /* QUADSPI */ -#define GPIO_QUADSPI_NCS_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN11) -#define GPIO_QUADSPI_NCS_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN11) -#define GPIO_QUADSPI_CLK_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN10) -#define GPIO_QUADSPI_CLK_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN10) -#define GPIO_QUADSPI_BK1_IO0_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN1) -#define GPIO_QUADSPI_BK1_IO0_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN12) -#define GPIO_QUADSPI_BK1_IO1_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN0) -#define GPIO_QUADSPI_BK1_IO1_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN13) -#define GPIO_QUADSPI_BK1_IO2_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN7) -#define GPIO_QUADSPI_BK1_IO2_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN14) -#define GPIO_QUADSPI_BK1_IO3_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN6) -#define GPIO_QUADSPI_BK1_IO3_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN15) +#define GPIO_QSPI_NCS_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN11) +#define GPIO_QSPI_NCS_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN11) +#define GPIO_QSPI_CLK_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN10) +#define GPIO_QSPI_CLK_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN10) +#define GPIO_QSPI_BK1_IO0_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN1) +#define GPIO_QSPI_BK1_IO0_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN12) +#define GPIO_QSPI_BK1_IO1_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTB|GPIO_PIN0) +#define GPIO_QSPI_BK1_IO1_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN13) +#define GPIO_QSPI_BK1_IO2_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN7) +#define GPIO_QSPI_BK1_IO2_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN14) +#define GPIO_QSPI_BK1_IO3_1 (GPIO_ALT|GPIO_AF10|GPIO_PORTA|GPIO_PIN6) +#define GPIO_QSPI_BK1_IO3_2 (GPIO_ALT|GPIO_AF10|GPIO_PORTE|GPIO_PIN15) /* RTC */ diff --git a/arch/arm/src/stm32l4/stm32l4_qspi.c b/arch/arm/src/stm32l4/stm32l4_qspi.c new file mode 100644 index 0000000000..f23ea40328 --- /dev/null +++ b/arch/arm/src/stm32l4/stm32l4_qspi.c @@ -0,0 +1,1702 @@ +/**************************************************************************** + * arch/arm/src/stm32l4/stm32l4_qspi.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: dev@ziggurat29.com + * + * 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 + +#include "up_internal.h" +#include "up_arch.h" +#include "cache.h" + +#include "stm32l4_gpio.h" +#include "stm32l4_dma.h" +#include "stm32l4_qspi.h" +#include "chip/stm32l4_qspi.h" +#include "chip/stm32l4_pinmap.h" + +#ifdef CONFIG_STM32L4_QSPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + + /* QSPI memory synchronization */ + +#define MEMORY_SYNC() do { ARM_DSB(); ARM_ISB(); } while (0) + +/* Ensure that the DMA buffers are word-aligned. + */ + +#define ALIGN_SHIFT 2 +#define ALIGN_MASK 3 +#define ALIGN_UP(n) (((n)+ALIGN_MASK) & ~ALIGN_MASK) +#define IS_ALIGNED(n) (((uint32_t)(n) & ALIGN_MASK) == 0) + +/* 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_STM32L4_QSPI_DMADEBUG +# undef CONFIG_STM32L4_QSPI_REGDEBUG +#endif + +#ifndef CONFIG_DEBUG_DMA +# undef CONFIG_STM32L4_QSPI_DMADEBUG +#endif + +#ifdef CONFIG_DEBUG_SPI +# define qspidbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define qspivdbg lldbg +# else +# define qspivdbg(x...) +# endif +#else +# define qspidbg(x...) +# define qspivdbg(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 + +#ifdef CONFIG_STM32L4_QSPI_DMA +# error QSPI DMA support not yet implemented +#endif + +#ifdef QSPI_USE_INTERRUPTS +# error QSPI Interrupt support not yet implemented +#endif + +/* QSPI interrupts and dma are not yet implemented */ + +#undef QSPI_USE_INTERRUPTS +#undef CONFIG_STM32L4_QSPI_DMA + +/* sanity check that board.h defines requisite QSPI pinmap options for */ +#if (!defined(GPIO_QSPI_CS) || !defined(GPIO_QSPI_IO0) || !defined(GPIO_QSPI_IO1) || \ + !defined(GPIO_QSPI_IO2) || !defined(GPIO_QSPI_IO3) || !defined(GPIO_QSPI_SCK)) +# error you must define QSPI pinmapping options for GPIO_QSPI_CS GPIO_QSPI_IO0 \ + GPIO_QSPI_IO1 GPIO_QSPI_IO2 GPIO_QSPI_IO3 GPIO_QSPI_SCK in your board.h +#endif + +#ifndef BOARD_AHB_FREQUENCY +# error your board.h needs to define the value of BOARD_AHB_FREQUENCY +#endif + +#if !defined(CONFIG_STM32L4_QSPI_FLASH_SIZE) || 0 == CONFIG_STM32L4_QSPI_FLASH_SIZE +# error you must specify a positive flash size via CONFIG_STM32L4_QSPI_FLASH_SIZE +#endif + +/* Clocking *****************************************************************/ +/* The QSPI bit rate clock is generated by dividing the peripheral clock by + * a value between 1 and 255 + */ + +#define STL32L4_QSPI_CLOCK BOARD_AHB_FREQUENCY /* Frequency of the QSPI clock */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The state of the QSPI controller. + * + * NOTE: the STM32L4 supports only a single QSPI peripheral. Logic here is + * designed to support multiple QSPI peripherals. + */ + +struct stm32l4_qspidev_s +{ + struct qspi_dev_s qspi; /* Externally visible part of the QSPI interface */ + uint32_t base; /* QSPI controller register base address */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + uint8_t mode; /* Mode 0,3 */ + uint8_t nbits; /* Width of word in bits (8 to 32) */ + uint8_t intf; /* QSPI controller number (0) */ + bool initialized; /* TRUE: Controller has been initialized */ + sem_t exclsem; /* Assures mutually exclusive access to QSPI */ + +#ifdef QSPI_USE_INTERRUPTS + xcpt_t handler; /* Interrupt handler */ + uint8_t irq; /* Interrupt number */ +#endif + +#ifdef CONFIG_STM32L4_QSPI_DMA + /* XXX III needs implementation */ +#endif + + /* Debug stuff */ + +#ifdef CONFIG_STM32L4_QSPI_DMADEBUG + struct stm32l4_dmaregs_s dmaregs[DMA_NSAMPLES]; +#endif + +#ifdef CONFIG_STM32L4_QSPI_REGDEBUG + bool wrlast; /* Last was a write */ + uint32_t addresslast; /* Last address */ + uint32_t valuelast; /* Last value */ + int ntimes; /* Number of times */ +#endif +}; + +/* The QSPI transaction specification + * + * This is mostly the values of the CCR and DLR, AR, ABR, broken out into a C struct + * since these fields need to be considered at various phases of the + * transaction processing activity. + */ + +struct qspi_xctnspec_s +{ + uint8_t instrmode; /* 'instruction mode'; 0=none, 1=single, 2=dual, 3=quad */ + uint8_t instr; /* the (8-bit) Instruction (if any) */ + + uint8_t addrmode; /* 'address mode'; 0=none, 1=single, 2=dual, 3=quad */ + uint8_t addrsize; /* address size ( n - 1 ); 0, 1, 2, 3 */ + uint32_t addr; /* the address (if any) (1 to 4 bytes as per addrsize) */ + + uint8_t altbytesmode; /* 'alt bytes mode'; 0=none, 1=single, 2=dual, 3=quad */ + uint8_t altbytessize; /* 'alt bytes' size ( n - 1 ); 0, 1, 2, 3 */ + uint32_t altbytes; /* the 'alt bytes' (if any) */ + + uint8_t dummycycles; /* number of Dummy Cycles; 0 - 32 */ + + uint8_t datamode; /* 'data mode'; 0=none, 1=single, 2=dual, 3=quad */ + uint32_t datasize; /* number of data bytes (0xffffffff == undefined) */ + FAR void *buffer; /* Data buffer */ + + uint32_t isddr; /* true if 'double data rate' */ + uint32_t issioo; /* true if 'send instruction only once' mode */ +}; + + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +#ifdef CONFIG_STM32L4_QSPI_REGDEBUG +static bool qspi_checkreg(struct stm32l4_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 stm32l4_qspidev_s *priv, + unsigned int offset); +static inline void qspi_putreg(struct stm32l4_qspidev_s *priv, uint32_t value, + unsigned int offset); + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE) +static void qspi_dumpregs(struct stm32l4_qspidev_s *priv, const char *msg); +#else +# define qspi_dumpregs(priv,msg) +#endif + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_GPIO) +static void qspi_dumpgpioconfig(const char *msg); +#else +# define qspi_dumpgpioconfig(msg) +#endif + +/* Interrupts */ + +#ifdef QSPI_USE_INTERRUPTS +static int qspi0_interrupt(int irq, void *context); +#endif + +/* QSPI methods */ + +static int qspi_lock(struct qspi_dev_s *dev, bool lock); +static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency); +static void qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode); +static void qspi_setbits(struct qspi_dev_s *dev, int nbits); +static int qspi_command(struct qspi_dev_s *dev, + struct qspi_cmdinfo_s *cmdinfo); +static int qspi_memory(struct qspi_dev_s *dev, + struct qspi_meminfo_s *meminfo); +static FAR void *qspi_alloc(FAR struct qspi_dev_s *dev, size_t buflen); +static void qspi_free(FAR struct qspi_dev_s *dev, FAR void *buffer); + +/* Initialization */ + +static int qspi_hw_initialize(struct stm32l4_qspidev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* QSPI0 driver operations */ + +static const struct qspi_ops_s g_qspi0ops = +{ + .lock = qspi_lock, + .setfrequency = qspi_setfrequency, + .setmode = qspi_setmode, + .setbits = qspi_setbits, + .command = qspi_command, + .memory = qspi_memory, + .alloc = qspi_alloc, + .free = qspi_free, +}; + +/* This is the overall state of the QSPI0 controller */ + +static struct stm32l4_qspidev_s g_qspi0dev = +{ + .qspi = + { + .ops = &g_qspi0ops, + }, + .base = STM32L4_QSPI_BASE, +#ifdef QSPI_USE_INTERRUPTS + .handler = qspi0_interrupt, + .irq = STM32L4_IRQ_QSPI, +#endif + .intf = 0, +#ifdef CONFIG_STM32L4_QSPI_DMA + /* XXX III needs implementation */ +#endif +}; + +/**************************************************************************** + * 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. + * false: This is the same as the preceding register access. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32L4_QSPI_REGDEBUG +static bool qspi_checkreg(struct stm32l4_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 stm32l4_qspidev_s *priv, + unsigned int offset) +{ + uint32_t address = priv->base + offset; + uint32_t value = getreg32(address); + +#ifdef CONFIG_STM32L4_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 stm32l4_qspidev_s *priv, uint32_t value, + unsigned int offset) +{ + uint32_t address = priv->base + offset; + +#ifdef CONFIG_STM32L4_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 stm32l4_qspidev_s *priv, const char *msg) +{ + uint32_t regval; + qspivdbg("%s:\n", msg); + +#if 0 + /* this extra verbose output may be helpful in some cases; you'll need + to make sure your syslog is large enough to accomodate the extra output. + */ + + regval = getreg32(priv->base + STM32L4_QUADSPI_CR_OFFSET); /* Control Register */ + qspivdbg("CR:%08x\n",regval); + qspivdbg(" EN:%1d ABORT:%1d DMAEN:%1d TCEN:%1d SSHIFT:%1d\n" + " FTHRES: %d\n" + " TEIE:%1d TCIE:%1d FTIE:%1d SMIE:%1d TOIE:%1d APMS:%1d PMM:%1d\n" + " PRESCALER: %d\n", + (regval&QSPI_CR_EN)?1:0, + (regval&QSPI_CR_ABORT)?1:0, + (regval&QSPI_CR_DMAEN)?1:0, + (regval&QSPI_CR_TCEN)?1:0, + (regval&QSPI_CR_SSHIFT)?1:0, + (regval&QSPI_CR_FTHRES_MASK)>>QSPI_CR_FTHRES_SHIFT, + (regval&QSPI_CR_TEIE)?1:0, + (regval&QSPI_CR_TCIE)?1:0, + (regval&QSPI_CR_FTIE)?1:0, + (regval&QSPI_CR_SMIE)?1:0, + (regval&QSPI_CR_TOIE)?1:0, + (regval&QSPI_CR_APMS)?1:0, + (regval&QSPI_CR_PMM)?1:0, + (regval&QSPI_CR_PRESCALER_MASK)>>QSPI_CR_PRESCALER_SHIFT + ); + + regval = getreg32(priv->base + STM32L4_QUADSPI_DCR_OFFSET); /* Device Configuration Register */ + qspivdbg("DCR:%08x\n",regval); + qspivdbg(" CKMODE:%1d CSHT:%d FSIZE:%d\n", + (regval&QSPI_DCR_CKMODE)?1:0, + (regval&QSPI_DCR_CSHT_MASK)>>QSPI_DCR_CSHT_SHIFT, + (regval&QSPI_DCR_FSIZE_MASK)>>QSPI_DCR_FSIZE_SHIFT + ); + + regval = getreg32(priv->base + STM32L4_QUADSPI_CCR_OFFSET); /* Communication Configuration Register */ + qspivdbg("CCR:%08x\n",regval); + qspivdbg(" INST:%02x IMODE:%d ADMODE:%d ADSIZE:%d ABMODE:%d\n" + " ABSIZE:%d DCYC:%d DMODE:%d FMODE:%d\n" + " SIOO:%1d DDRM:%1d\n", + (regval&QSPI_CCR_INSTRUCTION_MASK)>>QSPI_CCR_INSTRUCTION_SHIFT, + (regval&QSPI_CCR_IMODE_MASK)>>QSPI_CCR_IMODE_SHIFT, + (regval&QSPI_CCR_ADMODE_MASK)>>QSPI_CCR_ADMODE_SHIFT, + (regval&QSPI_CCR_ADSIZE_MASK)>>QSPI_CCR_ABSIZE_SHIFT, + (regval&QSPI_CCR_ABMODE_MASK)>>QSPI_CCR_ABMODE_SHIFT, + (regval&QSPI_CCR_ABSIZE_MASK)>>QSPI_CCR_ABSIZE_SHIFT, + (regval&QSPI_CCR_DCYC_MASK)>>QSPI_CCR_DCYC_SHIFT, + (regval&QSPI_CCR_DMODE_MASK)>>QSPI_CCR_DMODE_SHIFT, + (regval&QSPI_CCR_FMODE_MASK)>>QSPI_CCR_FMODE_SHIFT, + (regval&QSPI_CCR_SIOO)?1:0, + (regval&QSPI_CCR_DDRM)?1:0 + ); + + regval = getreg32(priv->base + STM32L4_QUADSPI_SR_OFFSET); /* Status Register */ + qspivdbg("SR:%08x\n",regval); + qspivdbg(" TEF:%1d TCF:%1d FTF:%1d SMF:%1d TOF:%1d BUSY:%1d FLEVEL:%d\n", + (regval&QSPI_SR_TEF)?1:0, + (regval&QSPI_SR_TCF)?1:0, + (regval&QSPI_SR_FTF)?1:0, + (regval&QSPI_SR_SMF)?1:0, + (regval&QSPI_SR_TOF)?1:0, + (regval&QSPI_SR_BUSY)?1:0, + (regval&QSPI_SR_FLEVEL_MASK)>>QSPI_SR_FLEVEL_SHIFT + ); + +#else + qspivdbg(" CR:%08x DCR:%08x CCR:%08x SR:%08x\n", + getreg32(priv->base + STM32L4_QUADSPI_CR_OFFSET), /* Control Register */ + getreg32(priv->base + STM32L4_QUADSPI_DCR_OFFSET), /* Device Configuration Register */ + getreg32(priv->base + STM32L4_QUADSPI_CCR_OFFSET), /* Communication Configuration Register */ + getreg32(priv->base + STM32L4_QUADSPI_SR_OFFSET)); /* Status Register */ + qspivdbg(" DLR:%08x ABR:%08x PSMKR:%08x PSMAR:%08x\n", + getreg32(priv->base + STM32L4_QUADSPI_DLR_OFFSET), /* Data Length Register */ + getreg32(priv->base + STM32L4_QUADSPI_ABR_OFFSET), /* Alternate Bytes Register */ + getreg32(priv->base + STM32L4_QUADSPI_PSMKR_OFFSET), /* Polling Status mask Register */ + getreg32(priv->base + STM32L4_QUADSPI_PSMAR_OFFSET)); /* Polling Status match Register */ + qspivdbg(" PIR:%08x LPTR:%08x\n", + getreg32(priv->base + STM32L4_QUADSPI_PIR_OFFSET), /* Polling Interval Register */ + getreg32(priv->base + STM32L4_QUADSPI_LPTR_OFFSET)); /* Low-Power Timeout Register */ + (void)regval; +#endif +} +#endif + +#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_GPIO) +static void qspi_dumpgpioconfig(const char *msg) +{ + uint32_t regval; + qspivdbg("%s:\n", msg); + + regval = getreg32(STM32L4_GPIOE_MODER); + qspivdbg("E_MODER:%08x\n",regval); + + regval = getreg32(STM32L4_GPIOE_OTYPER); + qspivdbg("E_OTYPER:%08x\n",regval); + + regval = getreg32(STM32L4_GPIOE_OSPEED); + qspivdbg("E_OSPEED:%08x\n",regval); + + regval = getreg32(STM32L4_GPIOE_PUPDR); + qspivdbg("E_PUPDR:%08x\n",regval); + + regval = getreg32(STM32L4_GPIOE_AFRL); + qspivdbg("E_AFRL:%08x\n",regval); + + regval = getreg32(STM32L4_GPIOE_AFRH); + qspivdbg("E_AFRH:%08x\n",regval); +} +#endif + +/**************************************************************************** + * Name: qspi_setupxctnfromcmd + * + * Description: + * Setup our transaction descriptor from a command info structure + * + * Input Parameters: + * xctn - the transaction descriptor we setup + * cmdinfo - the command info (originating from the MTD device) + * + * Returned Value: + * OK, or -errno if invalid + * + ****************************************************************************/ + +static int qspi_setupxctnfromcmd(struct qspi_xctnspec_s *xctn, + const struct qspi_cmdinfo_s *cmdinfo) +{ + DEBUGASSERT(xctn != NULL && cmdinfo != NULL); + +#ifdef CONFIG_DEBUG_SPI + qspivdbg("Transfer:\n"); + qspivdbg(" flags: %02x\n", cmdinfo->flags); + qspivdbg(" cmd: %04x\n", cmdinfo->cmd); + + if (QSPICMD_ISADDRESS(cmdinfo->flags)) + { + qspivdbg(" address/length: %08lx/%d\n", + (unsigned long)cmdinfo->addr, cmdinfo->addrlen); + } + + if (QSPICMD_ISDATA(cmdinfo->flags)) + { + qspivdbg(" %s Data:\n", QSPICMD_ISWRITE(cmdinfo->flags) ? "Write" : "Read"); + qspivdbg(" buffer/length: %p/%d\n", cmdinfo->buffer, cmdinfo->buflen); + } +#endif + + DEBUGASSERT(cmdinfo->cmd < 256); + + /* Specify the instruction as per command info */ + + /* XXX III instruction mode, single dual quad option bits */ + xctn->instrmode = CCR_IMODE_SINGLE; + xctn->instr = cmdinfo->cmd; + /* XXX III option bits for 'send instruction only once' */ + xctn->issioo = 0; + + /* XXX III options for alt bytes, dummy cycles */ + xctn->altbytesmode = CCR_ABMODE_NONE; + xctn->altbytessize = CCR_ABSIZE_8; + xctn->altbytes = 0; + xctn->dummycycles = 0; + + /* Specify the address size as needed */ + + if (QSPICMD_ISADDRESS(cmdinfo->flags)) + { + /* XXX III address mode mode, single, dual, quad option bits */ + xctn->addrmode = CCR_ADMODE_SINGLE; + if (cmdinfo->addrlen == 1) + { + xctn->addrsize = CCR_ADSIZE_8; + } + else if (cmdinfo->addrlen == 2) + { + xctn->addrsize = CCR_ADSIZE_16; + } + else if (cmdinfo->addrlen == 3) + { + xctn->addrsize = CCR_ADSIZE_24; + } + else if (cmdinfo->addrlen == 4) + { + xctn->addrsize = CCR_ADSIZE_32; + } + else + { + return -EINVAL; + } + xctn->addr = cmdinfo->addr; + } + else + { + xctn->addrmode = CCR_ADMODE_NONE; + xctn->addrsize = 0; + xctn->addr = cmdinfo->addr; + } + + /* Specify the data as needed */ + + xctn->buffer = cmdinfo->buffer; + if (QSPICMD_ISDATA(cmdinfo->flags)) + { + /* XXX III data mode mode, single, dual, quad option bits */ + xctn->datamode = CCR_DMODE_SINGLE; + xctn->datasize = cmdinfo->buflen; + /* XXX III double data rate option bits */ + xctn->isddr = 0; + } + else + { + xctn->datamode = CCR_DMODE_NONE; + xctn->datasize = 0; + xctn->isddr = 0; + } + + return OK; +} + +/**************************************************************************** + * Name: qspi_setupxctnfrommem + * + * Description: + * Setup our transaction descriptor from a memory info structure + * + * Input Parameters: + * xctn - the transaction descriptor we setup + * meminfo - the memory info (originating from the MTD device) + * + * Returned Value: + * OK, or -errno if invalid + * + ****************************************************************************/ + +static int qspi_setupxctnfrommem(struct qspi_xctnspec_s *xctn, + const struct qspi_meminfo_s *meminfo) +{ + DEBUGASSERT(xctn != NULL && meminfo != NULL); + +#ifdef CONFIG_DEBUG_SPI + qspivdbg("Transfer:\n"); + qspivdbg(" flags: %02x\n", meminfo->flags); + qspivdbg(" cmd: %04x\n", meminfo->cmd); + qspivdbg(" address/length: %08lx/%d\n", + (unsigned long)meminfo->addr, meminfo->addrlen); + qspivdbg(" %s Data:\n", QSPIMEM_ISWRITE(meminfo->flags) ? "Write" : "Read"); + qspivdbg(" buffer/length: %p/%d\n", meminfo->buffer, meminfo->buflen); +#endif + + DEBUGASSERT(meminfo->cmd < 256); + + /* Specify the instruction as per command info */ + + /* XXX III instruction mode, single dual quad option bits */ + xctn->instrmode = CCR_IMODE_SINGLE; + xctn->instr = meminfo->cmd; + /* XXX III option bits for 'send instruction only once' */ + xctn->issioo = 0; + + /* XXX III options for alt bytes */ + xctn->altbytesmode = CCR_ABMODE_NONE; + xctn->altbytessize = CCR_ABSIZE_8; + xctn->altbytes = 0; + + xctn->dummycycles = meminfo->dummies; + + /* Specify the address size as needed */ + + /* XXX III there should be a separate flags for single/dual/quad for each of i,a,d */ + if (QSPIMEM_ISDUALIO(meminfo->flags)) + xctn->addrmode = CCR_ADMODE_DUAL; + else if (QSPIMEM_ISQUADIO(meminfo->flags)) + xctn->addrmode = CCR_ADMODE_QUAD; + else + xctn->addrmode = CCR_ADMODE_SINGLE; + + if (meminfo->addrlen == 1) + { + xctn->addrsize = CCR_ADSIZE_8; + } + else if (meminfo->addrlen == 2) + { + xctn->addrsize = CCR_ADSIZE_16; + } + else if (meminfo->addrlen == 3) + { + xctn->addrsize = CCR_ADSIZE_24; + } + else if (meminfo->addrlen == 4) + { + xctn->addrsize = CCR_ADSIZE_32; + } + else + { + return -EINVAL; + } + xctn->addr = meminfo->addr; + + /* Specify the data as needed */ + + xctn->buffer = meminfo->buffer; + /* XXX III there should be a separate flags for single/dual/quad for each of i,a,d */ + if (QSPIMEM_ISDUALIO(meminfo->flags)) + xctn->datamode = CCR_DMODE_DUAL; + else if (QSPIMEM_ISQUADIO(meminfo->flags)) + xctn->datamode = CCR_DMODE_QUAD; + else + xctn->datamode = CCR_DMODE_SINGLE; + + xctn->datasize = meminfo->buflen; + /* XXX III double data rate option bits */ + xctn->isddr = 0; + + return OK; +} + +/**************************************************************************** + * Name: qspi_waitstatusflags + * + * Description: + * Spin wait for specified status flags to be set as desired + * + * Input Parameters: + * priv - The QSPI controller to dump + * mask - bits to check, can be multiple + * polarity - true wait if any set, false to wait if all reset + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void qspi_waitstatusflags(struct stm32l4_qspidev_s *priv, + uint32_t mask, int polarity) +{ + uint32_t regval; + + if ( polarity ) + { + while ( !((regval = qspi_getreg(priv, STM32L4_QUADSPI_SR_OFFSET)) & mask)) ; + } + else + { + while ( ((regval = qspi_getreg(priv, STM32L4_QUADSPI_SR_OFFSET)) & mask)) ; + } +} + +/**************************************************************************** + * Name: qspi_ccrconfig + * + * Description: + * Do common Communications Configuration Register setup + * + * Input Parameters: + * priv - The QSPI controller to dump + * xctn - the transaction descriptor; CCR setup + * fctn - 'functional mode'; 0=indwrite, 1=indread, 2=autopoll, 3=memmmap + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void qspi_ccrconfig(struct stm32l4_qspidev_s *priv, + struct qspi_xctnspec_s* xctn, + uint8_t fctn) +{ + uint32_t regval; + + /* if we have data, and it's not memory mapped, write the length */ + + if ( CCR_DMODE_NONE != xctn->datamode && CCR_FMODE_MEMMAP != fctn ) + { + qspi_putreg(priv, xctn->datasize-1, STM32L4_QUADSPI_DLR_OFFSET); + } + + /* if we have alternate bytes, stick them in now */ + + if ( CCR_ABMODE_NONE != xctn->altbytesmode ) + { + qspi_putreg(priv, xctn->altbytes, STM32L4_QUADSPI_ABR_OFFSET); + } + + /* build the CCR value and set it */ + + regval = QSPI_CCR_INST(xctn->instr) | + QSPI_CCR_IMODE(xctn->instrmode) | + QSPI_CCR_ADMODE(xctn->addrmode) | + QSPI_CCR_ADSIZE(xctn->addrsize) | + QSPI_CCR_ABMODE(xctn->altbytesmode) | + QSPI_CCR_ABSIZE(xctn->altbytessize) | + QSPI_CCR_DCYC(xctn->dummycycles) | + QSPI_CCR_DMODE(xctn->datamode) | + QSPI_CCR_FMODE(fctn) | + (xctn->isddr ? QSPI_CCR_SIOO : 0) | + (xctn->issioo ? QSPI_CCR_DDRM : 0); + qspi_putreg(priv, regval, STM32L4_QUADSPI_CCR_OFFSET); + + /* if we have and need and address, set that now, too */ + + if ( CCR_ADMODE_NONE != xctn->addrmode && CCR_FMODE_MEMMAP != fctn ) + { + qspi_putreg(priv, xctn->addr, STM32L4_QUADSPI_AR_OFFSET); + } +} + +/**************************************************************************** + * Name: qspi_receive_blocking + * + * Description: + * Do common data receive in a blocking (status polling) way + * + * Input Parameters: + * priv - The QSPI controller to dump + * xctn - the transaction descriptor + * + * Returned Value: + * OK, or -errno on error + * + ****************************************************************************/ + +static int qspi_receive_blocking(struct stm32l4_qspidev_s *priv, + struct qspi_xctnspec_s* xctn) +{ + int ret = OK; + volatile uint32_t *datareg = (volatile uint32_t*)(priv->base + STM32L4_QUADSPI_DR_OFFSET); + uint8_t *dest = (uint8_t*)xctn->buffer; + uint32_t addrval; + uint32_t regval; + + addrval = qspi_getreg(priv, STM32L4_QUADSPI_AR_OFFSET); + if(dest != NULL ) + { + /* counter of remaining data */ + uint32_t remaining = xctn->datasize; + + /* ensure CCR register specifies indirect read */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CCR_OFFSET); + regval &= ~QSPI_CCR_FMODE_MASK; + regval |= QSPI_CCR_FMODE(CCR_FMODE_INDRD); + qspi_putreg(priv, regval, STM32L4_QUADSPI_CCR_OFFSET); + + /* Start the transfer by re-writing the address in AR register */ + + qspi_putreg(priv, addrval, STM32L4_QUADSPI_AR_OFFSET); + + /* transfer loop */ + + while(remaining > 0) + { + /* Wait for Fifo Threshold, or Transfer Complete, to read data */ + + qspi_waitstatusflags(priv, QSPI_SR_FTF|QSPI_SR_TCF, 1); + + *dest = *(volatile uint8_t*)datareg; + dest++; + remaining--; + } + + if (ret == OK) + { + /* Wait for transfer complete, then clear it */ + + qspi_waitstatusflags(priv, QSPI_SR_TCF, 1); + qspi_putreg(priv, QSPI_FCR_CTCF, STM32L4_QUADSPI_FCR); + + /* use Abort to clear the busy flag, and ditch any extra bytes in fifo */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval |= QSPI_CR_ABORT; + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + } + } + else + { + ret = -EINVAL; + } + + return ret; +} + +/**************************************************************************** + * Name: qspi_transmit_blocking + * + * Description: + * Do common data transmit in a blocking (status polling) way + * + * Input Parameters: + * priv - The QSPI controller to dump + * xctn - the transaction descriptor + * + * Returned Value: + * OK, or -errno on error + * + ****************************************************************************/ + +static int qspi_transmit_blocking(struct stm32l4_qspidev_s *priv, + struct qspi_xctnspec_s* xctn) +{ + int ret = OK; + volatile uint32_t *datareg = (volatile uint32_t*)(priv->base + STM32L4_QUADSPI_DR_OFFSET); + uint8_t *src = (uint8_t*)xctn->buffer; + uint32_t regval; + + if(src != NULL ) + { + /* counter of remaining data */ + uint32_t remaining = xctn->datasize; + + /* transfer loop */ + + while(remaining > 0) + { + /* Wait for Fifo Threshold to write data */ + + qspi_waitstatusflags(priv, QSPI_SR_FTF, 1); + + *(volatile uint8_t*)datareg = *src++; + remaining--; + } + + if (ret == OK) + { + /* Wait for transfer complete, then clear it */ + + qspi_waitstatusflags(priv, QSPI_SR_TCF, 1); + qspi_putreg(priv, QSPI_FCR_CTCF, STM32L4_QUADSPI_FCR); + + /* use Abort to cler the Busy flag */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval |= QSPI_CR_ABORT; + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + } + } + else + { + ret = -EINVAL; + } + + return ret; +} + +#ifdef QSPI_USE_INTERRUPTS +/**************************************************************************** + * Name: qspi0_interrupt + * + * Description: + * XXX + * + * Input Parameters: + * irq - XXX + * context - xxx + * + * Returned Value: + * XXX + * + ****************************************************************************/ + +static int qspi0_interrupt(int irq, void *context) +{ + /* XXX III needs implementation */ + (void)g_qspi0dev; + return OK; +} +#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 + * + ****************************************************************************/ + +static int qspi_lock(struct qspi_dev_s *dev, bool lock) +{ + struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)dev; + + qspivdbg("lock=%d\n", lock); + if (lock) + { + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&priv->exclsem) != 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->exclsem); + } + + return OK; +} + +/**************************************************************************** + * 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 + * + ****************************************************************************/ +/*XXX partial*/ +static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency) +{ + struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)dev; + uint32_t actual; + uint32_t prescaler; +#if 0 +#if CONFIG_STM32L4_QSPI_DLYBS > 0 + uint32_t dlybs; +#endif +#if CONFIG_STM32L4_QSPI_DLYBCT > 0 + uint32_t dlybct; +#endif +#endif + uint32_t regval; + + qspivdbg("frequency=%d\n", frequency); + DEBUGASSERT(priv); + + /* Wait till BUSY flag reset */ + + qspi_waitstatusflags(priv, QSPI_SR_BUSY, 0); + + /* Check if the requested frequency is the same as the frequency selection */ + + if (priv->frequency == frequency) + { + /* We are already at this frequency. Return the actual. */ + + return priv->actual; + } + + /* Configure QSPI to a frequency as close as possible to the requested + * frequency. + * + * QSCK frequency = STL32L4_QSPI_CLOCK / prescaler, or + * prescaler = STL32L4_QSPI_CLOCK / frequency + * + * Where prescaler can have the range 1 to 256 and the STM32L4_QUADSPI_CR_OFFSET + * register field holds prescaler - 1. + * NOTE that a "ceiling" type of calculation is performed. + * 'frequency' is treated as a not-to-exceed value. + */ + + prescaler = (frequency + STL32L4_QSPI_CLOCK - 1) / frequency; + + /* Make sure that the divider is within range */ + + if (prescaler < 1) + { + prescaler = 1; + } + else if (prescaler > 256) + { + prescaler = 256; + } + + /* Save the new prescaler value (minus one) */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval &= ~(QSPI_CR_PRESCALER_MASK); + regval |= (prescaler - 1) << QSPI_CR_PRESCALER_SHIFT; + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + + /* Calculate the new actual frequency */ + + actual = STL32L4_QSPI_CLOCK / prescaler; + qspivdbg("prescaler=%d actual=%d\n", prescaler, actual); + + /* Save the frequency setting */ + + priv->frequency = frequency; + priv->actual = actual; + + qspivdbg("Frequency %d->%d\n", frequency, actual); + return actual; +} + +/**************************************************************************** + * Name: qspi_setmode + * + * Description: + * Set the QSPI mode. Optional. See enum qspi_mode_e for mode definitions. + * NOTE: the STM32L4 QSPI supports only modes 0 and 3. + * + * Input Parameters: + * dev - Device-specific state data + * mode - The QSPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode) +{ + struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)dev; + uint32_t regval; + + qspivdbg("mode=%d\n", mode); + + /* Has the mode changed? */ + + if (mode != priv->mode) + { + /* Yes... Set the mode appropriately: + * + * QSPI CPOL CPHA + * MODE + * 0 0 0 + * 1 0 1 + * 2 1 0 + * 3 1 1 + */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_DCR); + regval &= ~(QSPI_DCR_CKMODE); + + switch (mode) + { + case QSPIDEV_MODE0: /* CPOL=0; CPHA=0 */ + break; + + case QSPIDEV_MODE3: /* CPOL=1; CPHA=1 */ + regval |= (QSPI_DCR_CKMODE); + break; + + case QSPIDEV_MODE1: /* CPOL=0; CPHA=1 */ + case QSPIDEV_MODE2: /* CPOL=1; CPHA=0 */ + qspivdbg("unsupported mode=%d\n", mode); + default: + DEBUGASSERT(FALSE); + return; + } + + qspi_putreg(priv, regval, STM32L4_QUADSPI_DCR); + qspivdbg("DCR=%08x\n", regval); + + /* Save the mode so that subsequent re-configurations will be faster */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: qspi_setbits + * + * Description: + * Set the number if bits per word. + * NOTE: the STM32L4 QSPI only supports 8 bits, so this does nothing. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void qspi_setbits(struct qspi_dev_s *dev, int nbits) +{ + /* not meaningful for the STM32L4x6 */ + if ( 8 != nbits ) + { + qspivdbg("unsupported nbits=%d\n", nbits); + DEBUGASSERT(FALSE); + } +} + +/**************************************************************************** + * Name: qspi_command + * + * Description: + * Perform one QSPI data transfer + * + * Input Parameters: + * dev - Device-specific state data + * cmdinfo - Describes the command transfer to be performed. + * + * Returned Value: + * Zero (OK) on SUCCESS, a negated errno on value of failure + * + ****************************************************************************/ + +static int qspi_command(struct qspi_dev_s *dev, + struct qspi_cmdinfo_s *cmdinfo) +{ + struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)dev; + struct qspi_xctnspec_s xctn; + int ret; + + /* Set up the transaction descriptor as per command info */ + + ret = qspi_setupxctnfromcmd(&xctn, cmdinfo); + if ( OK != ret ) + { + return ret; + } + + /* Prepare for transaction */ + + /* wait 'till non-busy */ + + qspi_waitstatusflags(priv, QSPI_SR_BUSY, 0); + + /* Clear flags */ + + qspi_putreg(priv, QSPI_FCR_CTEF | QSPI_FCR_CTCF | QSPI_FCR_CSMF | QSPI_FCR_CTOF, STM32L4_QUADSPI_FCR); + + /* XXX III this is for polling mode; support interrupt and dma modes also and 'autopolling' */ + + /* Set up the Communications Configuration Register as per command info */ + + qspi_ccrconfig(priv, &xctn, + QSPICMD_ISWRITE(cmdinfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD ); + + /* That may be it, unless there is also data to transfer */ + + if (QSPICMD_ISDATA(cmdinfo->flags)) + { + DEBUGASSERT(cmdinfo->buffer != NULL && cmdinfo->buflen > 0); + DEBUGASSERT(IS_ALIGNED(cmdinfo->buffer)); + + if (QSPICMD_ISWRITE(cmdinfo->flags)) + { + /* XXX III we are going to do polling; revisit when we get interrupt and/or DMA up. */ + + + ret = qspi_transmit_blocking(priv, &xctn); + } + else + { + /* XXX III we are going to do polling; revisit when we get interrupt and/or DMA up. */ + + ret = qspi_receive_blocking(priv, &xctn); + } + MEMORY_SYNC(); + } + else + { + ret = OK; + } + + /* XXX III this is for polling mode; support interrupt and dma modes also */ + + /* wait for Transfer complete, and not busy */ + qspi_waitstatusflags(priv, QSPI_SR_TCF,1); + qspi_waitstatusflags(priv, QSPI_SR_BUSY,0); + + return ret; +} + +/**************************************************************************** + * Name: qspi_memory + * + * Description: + * Perform one QSPI memory transfer + * + * Input Parameters: + * dev - Device-specific state data + * meminfo - Describes the memory transfer to be performed. + * + * Returned Value: + * Zero (OK) on SUCCESS, a negated errno on value of failure + * + ****************************************************************************/ + +static int qspi_memory(struct qspi_dev_s *dev, + struct qspi_meminfo_s *meminfo) +{ + struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)dev; + struct qspi_xctnspec_s xctn; + int ret; + + /* Set up the transaction descriptor as per command info */ + + ret = qspi_setupxctnfrommem(&xctn, meminfo); + if ( OK != ret ) + { + return ret; + } + + /* Prepare for transaction */ + + /* wait 'till non-busy */ + + qspi_waitstatusflags(priv, QSPI_SR_BUSY, 0); + + /* Clear flags */ + + qspi_putreg(priv, QSPI_FCR_CTEF | QSPI_FCR_CTCF | QSPI_FCR_CSMF | QSPI_FCR_CTOF, STM32L4_QUADSPI_FCR); + + /* XXX III this is for polling mode; support interrupt and dma modes also and 'autopolling' */ + + /* Set up the Communications Configuration Register as per command info */ + + qspi_ccrconfig(priv, &xctn, + QSPICMD_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD ); + + /* Transfer data */ + + DEBUGASSERT(meminfo->buffer != NULL && meminfo->buflen > 0); + DEBUGASSERT(IS_ALIGNED(meminfo->buffer)); + + if (QSPICMD_ISWRITE(meminfo->flags)) + { + /* XXX III we are going to do polling; revisit when we get interrupt and/or DMA up. */ + + ret = qspi_transmit_blocking(priv, &xctn); + } + else + { + /* XXX III we are going to do polling; revisit when we get interrupt and/or DMA up. */ + + ret = qspi_receive_blocking(priv, &xctn); + } + MEMORY_SYNC(); + +#if 0 +#ifdef CONFIG_STM32L4_QSPI_DMA + /* Can we perform DMA? Should we perform DMA? */ + if (priv->candma && + meminfo->buflen > CONFIG_STM32L4_QSPI_DMATHRESHOLD && + IS_ALIGNED((uintptr_t)meminfo->buffer) && + IS_ALIGNED(meminfo->buflen)) + { + return qspi_memory_dma(priv, meminfo); + } + else +#endif + { + return qspi_memory_nodma(priv, meminfo); + } +#endif + + /* XXX III this is for polling mode; support interrupt and dma modes also */ + + /* wait for Transfer complete, and not busy */ + qspi_waitstatusflags(priv, QSPI_SR_TCF,1); + qspi_waitstatusflags(priv, QSPI_SR_BUSY,0); + + return ret; +} + +/**************************************************************************** + * Name: qspi_alloc + * + * Description: + * Allocate a buffer suitable for DMA data transfer + * + * Input Parameters: + * dev - Device-specific state data + * buflen - Buffer length to allocate in bytes + * + * Returned Value: + * Address of tha allocated memory on success; NULL is returned on any + * failure. + * + ****************************************************************************/ + +static FAR void *qspi_alloc(FAR struct qspi_dev_s *dev, size_t buflen) +{ + /* Here we exploit the carnal knowledge the kmm_malloc() will return memory + * aligned to 64-bit addresses. The buffer length must be large enough to + * hold the rested buflen in units a 32-bits. + */ + + return kmm_malloc(ALIGN_UP(buflen)); +} + +/**************************************************************************** + * Name: QSPI_FREE + * + * Description: + * Free memory returned by QSPI_ALLOC + * + * Input Parameters: + * dev - Device-specific state data + * buffer - Buffer previously allocated via QSPI_ALLOC + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void qspi_free(FAR struct qspi_dev_s *dev, FAR void *buffer) +{ + if (buffer) + { + kmm_free(buffer); + } +} + +/**************************************************************************** + * Name: qspi_hw_initialize + * + * Description: + * Initialize the QSPI peripheral from hardware reset. + * + * Input Parameters: + * priv - Device state structure. + * + * Returned Value: + * Zero (OK) on SUCCESS, a negated errno on value of failure + * + ****************************************************************************/ + +static int qspi_hw_initialize(struct stm32l4_qspidev_s *priv) +{ + uint32_t regval; + + /* Disable the QSPI; abort anything happening, disable, wait for not busy */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval |= QSPI_CR_ABORT; + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval &= ~(QSPI_CR_EN); + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + + /* Wait till BUSY flag reset */ + + qspi_waitstatusflags(priv, QSPI_SR_BUSY, 0); + + /* Disable all interrupt sources for starters */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval &= ~(QSPI_CR_TEIE | QSPI_CR_TCIE | QSPI_CR_FTIE | QSPI_CR_SMIE | QSPI_CR_TOIE); + + /* Configure QSPI FIFO Threshold */ + + regval &= ~(QSPI_CR_FTHRES_MASK); + regval |= ((CONFIG_STM32L4_QSPI_FIFO_THESHOLD-1) << QSPI_CR_FTHRES_SHIFT); + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + + /* Wait till BUSY flag reset */ + + qspi_waitstatusflags(priv, QSPI_SR_BUSY, 0); + + /* Configure QSPI Clock Prescaler and Sample Shift */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval &= ~(QSPI_CR_PRESCALER_MASK | QSPI_CR_SSHIFT); + regval |= (0x01 << QSPI_CR_PRESCALER_SHIFT); + regval |= (0x00); + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + + /* Configure QSPI Flash Size, CS High Time and Clock Mode */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_DCR_OFFSET); + regval &= ~(QSPI_DCR_CKMODE | QSPI_DCR_CSHT_MASK | QSPI_DCR_FSIZE_MASK); + regval |= (0x00); + regval |= ((CONFIG_STM32L4_QSPI_CSHT-1) << QSPI_DCR_CSHT_SHIFT); + if ( 0 != CONFIG_STM32L4_QSPI_FLASH_SIZE ) + { + unsigned int nSize = CONFIG_STM32L4_QSPI_FLASH_SIZE; + int nLog2Size = 31; + while (!(nSize & 0x80000000)) + { + --nLog2Size; + nSize <<= 1; + } + regval |= ((nLog2Size-1) << QSPI_DCR_FSIZE_SHIFT); + } + + qspi_putreg(priv, regval, STM32L4_QUADSPI_DCR_OFFSET); + + /* Enable QSPI */ + + regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET); + regval |= QSPI_CR_EN; + qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET); + + /* Wait till BUSY flag reset */ + + qspi_waitstatusflags(priv, QSPI_SR_BUSY, 0); + + qspi_dumpregs(priv, "After initialization"); + qspi_dumpgpioconfig("GPIO"); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32l4_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 + * + ****************************************************************************/ + +struct qspi_dev_s *stm32l4_qspi_initialize(int intf) +{ + struct stm32l4_qspidev_s *priv; + uint32_t regval; + int ret; + + /* The STM32L4 has only a single QSPI port */ + + qspivdbg("intf: %d\n", intf); + DEBUGASSERT(intf == 0); + + /* Select the QSPI interface */ + + if (intf == 0) + { + /* If this function is called multiple times, the following operations + * will be performed multiple times. + */ + + /* Select QSPI0 */ + + priv = &g_qspi0dev; + + /* Enable clocking to the QSPI peripheral */ + + regval = getreg32(STM32L4_RCC_AHB3ENR); + regval |= RCC_AHB3ENR_QSPIEN; + putreg32(regval, STM32L4_RCC_AHB3ENR); + regval = getreg32(STM32L4_RCC_AHB3ENR); + + /* Reset the QSPI peripheral */ + + regval = getreg32(STM32L4_RCC_AHB3RSTR); + regval |= RCC_AHB3RSTR_QSPIRST; + putreg32(regval, STM32L4_RCC_AHB3RSTR); + regval &= ~RCC_AHB3RSTR_QSPIRST; + putreg32(regval, STM32L4_RCC_AHB3RSTR); + + /* Configure multiplexed pins as connected on the board. */ + + stm32l4_configgpio(GPIO_QSPI_CS); + stm32l4_configgpio(GPIO_QSPI_IO0); + stm32l4_configgpio(GPIO_QSPI_IO1); + stm32l4_configgpio(GPIO_QSPI_IO2); + stm32l4_configgpio(GPIO_QSPI_IO3); + stm32l4_configgpio(GPIO_QSPI_SCK); + } + else + { + qspidbg("ERROR: QSPI%d not supported\n", intf); + return NULL; + } + + /* Has the QSPI hardware been initialized? */ + + if (!priv->initialized) + { + /* Now perform one time initialization */ + /* Initialize the QSPI semaphore that enforces mutually exclusive + * access to the QSPI registers. + */ + + sem_init(&priv->exclsem, 0, 1); + +#ifdef CONFIG_STM32L4_QSPI_DMA + /* XXX III needs implementation */ +#endif + +#ifdef QSPI_USE_INTERRUPTS + /* Attach the interrupt handler */ + + ret = irq_attach(priv->irq, priv->handler); + if (ret < 0) + { + qspidbg("ERROR: Failed to attach irq %d\n", priv->irq); + goto errout_with_dmadog; + } +#endif + + /* Perform hardware initialization. Puts the QSPI into an active + * state. + */ + + ret = qspi_hw_initialize(priv); + if (ret < 0) + { + qspidbg("ERROR: Failed to initialize QSPI hardware\n"); + goto errout_with_irq; + } + + /* Enable interrupts at the NVIC */ + + priv->initialized = true; +#ifdef QSPI_USE_INTERRUPTS + up_enable_irq(priv->irq); +#endif + } + + return &priv->qspi; + +errout_with_irq: +#ifdef QSPI_USE_INTERRUPTS + irq_detach(priv->irq); + +errout_with_dmadog: +#endif +#ifdef CONFIG_STM32L4_QSPI_DMA + /* XXX III needs implementation */ +#endif + + sem_destroy(&priv->exclsem); + return NULL; +} +#endif /* CONFIG_STM32L4_QSPI */ diff --git a/arch/arm/src/stm32l4/stm32l4_qspi.h b/arch/arm/src/stm32l4/stm32l4_qspi.h new file mode 100644 index 0000000000..a62fb7635c --- /dev/null +++ b/arch/arm/src/stm32l4/stm32l4_qspi.h @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/arm/src/stm32l4/stm32l4_qspi.h + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: dev@ziggurat29.com + * + * 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_STM32L4_STM32L4_QSPI_H +#define __ARCH_ARM_SRC_STM32L4_STM32L4_QSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "chip.h" + +#ifdef CONFIG_STM32L4_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: stm32l4_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 + * + ****************************************************************************/ + +struct qspi_dev_s; +FAR struct qspi_dev_s *stm32l4_qspi_initialize(int intf); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_STM32L4_QSPI */ +#endif /* __ARCH_ARM_SRC_STM32L4_STM32L4_QSPI_H */ diff --git a/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c b/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c index 8e4cbe624c..64c8021f95 100644 --- a/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c +++ b/arch/arm/src/stm32l4/stm32l4x6xx_rcc.c @@ -259,7 +259,7 @@ static inline void rcc_enableahb3(void) #endif -#ifdef CONFIG_STM32L4_QUADSPI +#ifdef CONFIG_STM32L4_QSPI /* QuadSPI module clock enable */ regval |= RCC_AHB3ENR_QSPIEN; diff --git a/configs/stm32l476vg-disco/include/board.h b/configs/stm32l476vg-disco/include/board.h index 1c4d5fa334..926094ddee 100644 --- a/configs/stm32l476vg-disco/include/board.h +++ b/configs/stm32l476vg-disco/include/board.h @@ -137,6 +137,21 @@ #endif +/* Quad SPI pin mapping */ + +#define GPIO_QSPI_CS (GPIO_QSPI_NCS_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz) +#define GPIO_QSPI_IO0 (GPIO_QSPI_BK1_IO0_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz) +#define GPIO_QSPI_IO1 (GPIO_QSPI_BK1_IO1_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz) +#define GPIO_QSPI_IO2 (GPIO_QSPI_BK1_IO2_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz) +#define GPIO_QSPI_IO3 (GPIO_QSPI_BK1_IO3_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz) +#define GPIO_QSPI_SCK (GPIO_QSPI_CLK_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz) + +//XXX hmm, elsewhere +//#define QSPI_USE_INTERRUPTS 1 +//XXX hmm, better? (2^(23+1)); this is the value that goes into FSIZE +//#define QSPI_FLASH_SIZE 23 + + /* SPI */ diff --git a/configs/stm32l476vg-disco/include/stm32l476vg-disco-clocking.h b/configs/stm32l476vg-disco/include/stm32l476vg-disco-clocking.h index ef7871c8f2..46639ef9c7 100644 --- a/configs/stm32l476vg-disco/include/stm32l476vg-disco-clocking.h +++ b/configs/stm32l476vg-disco/include/stm32l476vg-disco-clocking.h @@ -67,6 +67,9 @@ #define STM32L4_LSI_FREQUENCY 32000 #define STM32L4_LSE_FREQUENCY 32768 +#define BOARD_AHB_FREQUENCY 80000000ul + + /* XXX review the STM32L4_BOARD_USEHSI usage, it has too much influence in * stm32l4x6xx_rcc.c. I suspect it is fine for it to turn on and off that * ocillator, but really that's all it should do (e.g. it also controls diff --git a/configs/stm32l476vg-disco/nsh/Make.defs b/configs/stm32l476vg-disco/nsh/Make.defs index eac292a8bd..0819e438c2 100644 --- a/configs/stm32l476vg-disco/nsh/Make.defs +++ b/configs/stm32l476vg-disco/nsh/Make.defs @@ -105,6 +105,10 @@ ifeq ($(CONFIG_DEBUG_SYMBOLS),y) LDFLAGS += -g endif +LDFLAGS += -Map=${TOPDIR}/nuttx.map +#CFLAGS += -Wa,-adhln +#CXXFLAGS += -Wa,-adhln + HOSTCC = gcc HOSTINCLUDES = -I. HOSTCFLAGS = -Wall -Wstrict-prototypes -Wshadow -Wundef -g -pipe diff --git a/configs/stm32l476vg-disco/nsh/defconfig b/configs/stm32l476vg-disco/nsh/defconfig index 56aef70f51..8ee16e46cb 100644 --- a/configs/stm32l476vg-disco/nsh/defconfig +++ b/configs/stm32l476vg-disco/nsh/defconfig @@ -49,10 +49,10 @@ CONFIG_DEBUG_VERBOSE=y # # Subsystem Debug Options # -CONFIG_DEBUG_BINFMT=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_GRAPHICS=y -CONFIG_DEBUG_LIB=y +# CONFIG_DEBUG_BINFMT is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_GRAPHICS is not set +# CONFIG_DEBUG_LIB is not set # CONFIG_DEBUG_MM is not set # CONFIG_DEBUG_SCHED is not set @@ -65,11 +65,11 @@ CONFIG_DEBUG_LIB=y # # Driver Debug Options # -CONFIG_DEBUG_LEDS=y -CONFIG_DEBUG_ANALOG=y -CONFIG_DEBUG_GPIO=y +# CONFIG_DEBUG_LEDS is not set +# CONFIG_DEBUG_ANALOG is not set +# CONFIG_DEBUG_GPIO is not set # CONFIG_DEBUG_RTC is not set -CONFIG_DEBUG_SPI=y +# CONFIG_DEBUG_SPI is not set CONFIG_ARCH_HAVE_STACKCHECK=y # CONFIG_STACK_COLORATION is not set CONFIG_DEBUG_SYMBOLS=y @@ -143,6 +143,7 @@ CONFIG_ARCH_CORTEXM4=y # CONFIG_ARCH_CORTEXR7F is not set CONFIG_ARCH_FAMILY="armv7-m" CONFIG_ARCH_CHIP="stm32l4" +# CONFIG_ARM_TOOLCHAIN_IAR is not set CONFIG_ARM_TOOLCHAIN_GNU=y # CONFIG_ARMV7M_USEBASEPRI is not set CONFIG_ARCH_HAVE_CMNVECTOR=y @@ -165,6 +166,7 @@ CONFIG_ARMV7M_HAVE_ITCM=y CONFIG_ARMV7M_HAVE_DTCM=y # CONFIG_ARMV7M_ITCM is not set # CONFIG_ARMV7M_DTCM is not set +# CONFIG_ARMV7M_TOOLCHAIN_IARL is not set # CONFIG_ARMV7M_TOOLCHAIN_BUILDROOT is not set # CONFIG_ARMV7M_TOOLCHAIN_CODEREDL is not set # CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYL is not set @@ -224,7 +226,10 @@ CONFIG_STM32L4_RNG=y # AHB3 Peripherals # # CONFIG_STM32L4_FMC is not set -# CONFIG_STM32L4_QUADSPI is not set +CONFIG_STM32L4_QSPI=y +CONFIG_STM32L4_QSPI_FLASH_SIZE=16777216 +CONFIG_STM32L4_QSPI_FIFO_THESHOLD=4 +CONFIG_STM32L4_QSPI_CSHT=1 # # APB1 Peripherals @@ -372,7 +377,14 @@ CONFIG_NSH_MMCSDMINOR=0 # # Board-Specific Options # -# CONFIG_LIB_BOARDCTL is not set +CONFIG_LIB_BOARDCTL=y +# CONFIG_BOARDCTL_RESET is not set +# CONFIG_BOARDCTL_UNIQUEID is not set +# CONFIG_BOARDCTL_TSCTEST is not set +# CONFIG_BOARDCTL_ADCTEST is not set +# CONFIG_BOARDCTL_PWMTEST is not set +# CONFIG_BOARDCTL_GRAPHICS is not set +# CONFIG_BOARDCTL_IOCTL is not set # # RTOS Features @@ -532,7 +544,38 @@ CONFIG_RTC_IOCTL=y # CONFIG_PCA9635PW is not set # CONFIG_MMCSD is not set # CONFIG_MODEM is not set -# CONFIG_MTD is not set +CONFIG_MTD=y + +# +# MTD Configuration +# +# CONFIG_MTD_PARTITION is not set +# CONFIG_MTD_SECT512 is not set +# CONFIG_MTD_BYTE_WRITE is not set +# CONFIG_MTD_PROGMEM is not set +# CONFIG_MTD_CONFIG is not set + +# +# MTD Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_RAMMTD is not set +# CONFIG_FILEMTD is not set +# CONFIG_MTD_AT24XX is not set +# CONFIG_MTD_AT25 is not set +# CONFIG_MTD_AT45DB is not set +# CONFIG_MTD_M25P is not set +# CONFIG_MTD_S25FL1 is not set +CONFIG_MTD_N25QXXX=y +CONFIG_N25QXXX_QSPIMODE=0 +CONFIG_N25QXXX_QSPI_FREQUENCY=80000000 +# CONFIG_N25QXXX_SECTOR512 is not set +# CONFIG_MTD_SMART is not set +# CONFIG_MTD_RAMTRON is not set +# CONFIG_MTD_SST25 is not set +# CONFIG_MTD_SST25XX is not set +# CONFIG_MTD_SST39FV is not set +# CONFIG_MTD_W25 is not set # CONFIG_EEPROM is not set # CONFIG_PIPES is not set # CONFIG_PM is not set @@ -603,7 +646,12 @@ CONFIG_USART2_2STOP=0 # # System Logging # -# CONFIG_RAMLOG is not set +CONFIG_RAMLOG=y +CONFIG_RAMLOG_SYSLOG=y +# CONFIG_RAMLOG_CONSOLE is not set +CONFIG_RAMLOG_BUFSIZE=8192 +# CONFIG_RAMLOG_CRLF is not set +CONFIG_RAMLOG_NONBLOCKING=y # CONFIG_SYSLOG_CONSOLE is not set # @@ -628,25 +676,41 @@ CONFIG_USART2_2STOP=0 # CONFIG_DISABLE_MOUNTPOINT is not set # CONFIG_FS_AUTOMOUNTER is not set # CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set -# CONFIG_FS_READABLE is not set -# CONFIG_FS_WRITABLE is not set +CONFIG_FS_READABLE=y +CONFIG_FS_WRITABLE=y # CONFIG_FS_NAMED_SEMAPHORES is not set CONFIG_FS_MQUEUE_MPATH="/var/mqueue" # CONFIG_FS_RAMMAP is not set -# CONFIG_FS_FAT is not set +CONFIG_FS_FAT=y +# CONFIG_FAT_LCNAMES is not set +# CONFIG_FAT_LFN is not set +# CONFIG_FS_FATTIME is not set +# CONFIG_FAT_FORCE_INDIRECT is not set +# CONFIG_FAT_DMAMEMORY is not set +# CONFIG_FAT_DIRECT_RETRY is not set # CONFIG_FS_NXFFS is not set # CONFIG_FS_ROMFS is not set # CONFIG_FS_TMPFS is not set # CONFIG_FS_SMARTFS is not set # CONFIG_FS_BINFS is not set -# CONFIG_FS_PROCFS is not set +CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y + +# +# Exclude individual procfs entries +# +# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set +# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set +# CONFIG_FS_PROCFS_EXCLUDE_MOUNTS is not set +# CONFIG_FS_PROCFS_EXCLUDE_MTD is not set # CONFIG_FS_UNIONFS is not set # # System Logging # -# CONFIG_SYSLOG is not set +CONFIG_SYSLOG=y # CONFIG_SYSLOG_TIMESTAMP is not set +# CONFIG_SYSLOG_CHAR is not set # # Graphics Support @@ -707,6 +771,8 @@ CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=1024 CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=2048 # CONFIG_LIBC_STRERROR is not set # CONFIG_LIBC_PERROR_STDOUT is not set +CONFIG_LIBC_TMPDIR="/tmp" +CONFIG_LIBC_MAX_TMPFILE=32 CONFIG_ARCH_LOWPUTC=y # CONFIG_LIBC_LOCALTIME is not set # CONFIG_TIME_EXTENDED is not set @@ -716,6 +782,7 @@ CONFIG_LIB_SENDFILE_BUFSIZE=512 CONFIG_ARCH_HAVE_TLS=y # CONFIG_TLS is not set # CONFIG_LIBC_NETDB is not set +# CONFIG_NETDB_HOSTFILE is not set # # Non-standard Library Support @@ -771,6 +838,14 @@ CONFIG_EXAMPLES_BUTTONS_NAME7="Button 7" # CONFIG_EXAMPLES_CXXTEST is not set # CONFIG_EXAMPLES_DHCPD is not set # CONFIG_EXAMPLES_ELF is not set +CONFIG_EXAMPLES_FSTEST=y +CONFIG_EXAMPLES_FSTEST_MAXNAME=32 +CONFIG_EXAMPLES_FSTEST_MAXFILE=8192 +CONFIG_EXAMPLES_FSTEST_MAXIO=347 +CONFIG_EXAMPLES_FSTEST_MAXOPEN=512 +CONFIG_EXAMPLES_FSTEST_MOUNTPT="/mnt/n25qxxx" +CONFIG_EXAMPLES_FSTEST_NLOOPS=1 +CONFIG_EXAMPLES_FSTEST_VERBOSE=y # CONFIG_EXAMPLES_FTPC is not set # CONFIG_EXAMPLES_FTPD is not set # CONFIG_EXAMPLES_HELLO is not set @@ -779,7 +854,9 @@ CONFIG_EXAMPLES_BUTTONS_NAME7="Button 7" # CONFIG_EXAMPLES_HIDKBD is not set # CONFIG_EXAMPLES_KEYPADTEST is not set # CONFIG_EXAMPLES_IGMP is not set -# CONFIG_EXAMPLES_MEDIA is not set +CONFIG_EXAMPLES_MEDIA=y +CONFIG_EXAMPLES_MEDIA_DEVPATH="/dev/mtd0" +CONFIG_EXAMPLES_MEDIA_BLOCKSIZE=512 # CONFIG_EXAMPLES_MM is not set # CONFIG_EXAMPLES_MODBUS is not set # CONFIG_EXAMPLES_MOUNT is not set @@ -823,6 +900,7 @@ CONFIG_EXAMPLES_NSAMPLES=8 # CONFIG_EXAMPLES_TIFF is not set # CONFIG_EXAMPLES_TOUCHSCREEN is not set # CONFIG_EXAMPLES_WEBSERVER is not set +# CONFIG_EXAMPLES_USBSERIAL is not set # CONFIG_EXAMPLES_USBTERM is not set # CONFIG_EXAMPLES_WATCHDOG is not set @@ -830,6 +908,7 @@ CONFIG_EXAMPLES_NSAMPLES=8 # File System Utilities # # CONFIG_FSUTILS_INIFILE is not set +# CONFIG_FSUTILS_PASSWD is not set # # GPS Utilities @@ -845,6 +924,7 @@ CONFIG_EXAMPLES_NSAMPLES=8 # # Interpreters # +# CONFIG_INTERPRETERS_BAS is not set # CONFIG_INTERPRETERS_FICL is not set # CONFIG_INTERPRETERS_PCODE is not set # CONFIG_INTERPRETERS_MICROPYTHON is not set @@ -911,6 +991,7 @@ CONFIG_NSH_DISABLE_LOSMART=y # CONFIG_NSH_DISABLE_LS is not set # CONFIG_NSH_DISABLE_MB is not set # CONFIG_NSH_DISABLE_MKDIR is not set +# CONFIG_NSH_DISABLE_MKFATFS is not set # CONFIG_NSH_DISABLE_MKFIFO is not set # CONFIG_NSH_DISABLE_MKRD is not set # CONFIG_NSH_DISABLE_MH is not set @@ -940,6 +1021,7 @@ CONFIG_NSH_DISABLE_LOSMART=y # CONFIG_NSH_CMDOPT_DF_H is not set CONFIG_NSH_CODECS_BUFSIZE=128 # CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_NSH_PROC_MOUNTPOINT="/proc" CONFIG_NSH_FILEIOSIZE=512 # @@ -954,7 +1036,7 @@ CONFIG_NSH_FILEIOSIZE=512 # CONFIG_NSH_CONSOLE=y # CONFIG_NSH_ALTCONDEV is not set -# CONFIG_NSH_ARCHINIT is not set +CONFIG_NSH_ARCHINIT=y # CONFIG_NSH_LOGIN is not set # CONFIG_NSH_CONSOLE_LOGIN is not set @@ -974,6 +1056,7 @@ CONFIG_NSH_CONSOLE=y # CONFIG_SYSTEM_CLE is not set # CONFIG_SYSTEM_CUTERM is not set # CONFIG_SYSTEM_INSTALL is not set +# CONFIG_SYSTEM_FLASH_ERASEALL is not set # CONFIG_SYSTEM_HEX2BIN is not set # CONFIG_SYSTEM_HEXED is not set # CONFIG_SYSTEM_RAMTEST is not set diff --git a/configs/stm32l476vg-disco/src/stm32_appinit.c b/configs/stm32l476vg-disco/src/stm32_appinit.c index 1b9056b75d..f1a65067e6 100644 --- a/configs/stm32l476vg-disco/src/stm32_appinit.c +++ b/configs/stm32l476vg-disco/src/stm32_appinit.c @@ -39,9 +39,12 @@ #include +#include +#include #include #include #include +#include #include #include @@ -51,8 +54,45 @@ #include +#include +#include +#include +#include +#include + #include "stm32l476vg-disco.h" +/* Conditional logic in stm32l476vg-disco.h will determine if certain features + * are supported. Tests for these features need to be made after including + * stm32l476vg-disco.h. + */ + +#ifdef HAVE_RTC_DRIVER +# include +# include "stm32l4_rtc.h" +#endif + +#if defined(HAVE_N25QXXX) || defined(HAVE_PROGMEM_CHARDEV) +# include +#endif + +#ifdef HAVE_N25QXXX +# include +# include "stm32l4_qspi.h" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Debug ********************************************************************/ + +#ifdef CONFIG_BOARD_INITIALIZE +# define SYSLOG lldbg +#else +# define SYSLOG dbg +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -61,17 +101,159 @@ * Name: board_app_initialize * * Description: - * Perform architecture specific initialization + * Application initialization stub for boardctl() * ****************************************************************************/ +#ifdef CONFIG_LIB_BOARDCTL int board_app_initialize(void) { +#ifdef HAVE_RTC_DRIVER + FAR struct rtc_lowerhalf_s *lower; +#endif +#ifdef HAVE_N25QXXX + FAR struct qspi_dev_s *qspi; +#endif +#if defined(HAVE_N25QXXX) || defined(HAVE_PROGMEM_CHARDEV) + FAR struct mtd_dev_s *mtd; +#endif +#if defined(HAVE_N25QXXX_CHARDEV) || defined(HAVE_PROGMEM_CHARDEV) + char blockdev[18]; + char chardev[12]; +#endif + int ret; + + (void)ret; + /* Configure CPU load estimation */ #ifdef CONFIG_SCHED_INSTRUMENTATION cpuload_initialize_once(); #endif +#ifdef HAVE_PROC + /* mount the proc filesystem */ + + syslog(LOG_INFO, "Mounting procfs to /proc\n"); + + ret = mount(NULL, CONFIG_NSH_PROC_MOUNTPOINT, "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to mount the PROC filesystem: %d (%d)\n", + ret, errno); + return ret; + } +#endif + +#ifdef HAVE_RTC_DRIVER + /* Instantiate the STM32 lower-half RTC driver */ + + lower = stm32l4_rtc_lowerhalf(); + if (!lower) + { + sdbg("ERROR: Failed to instantiate the RTC lower-half driver\n"); + return -ENOMEM; + } + else + { + /* Bind the lower half driver and register the combined RTC driver + * as /dev/rtc0 + */ + + ret = rtc_initialize(0, lower); + if (ret < 0) + { + sdbg("ERROR: Failed to bind/register the RTC driver: %d\n", ret); + return ret; + } + } +#endif + +#ifdef HAVE_N25QXXX + /* Create an instance of the STM32L4 QSPI device driver */ + + qspi = stm32l4_qspi_initialize(0); + if (!qspi) + { + SYSLOG("ERROR: sam_qspi_initialize failed\n"); + } + else + { + /* Use the QSPI device instance to initialize the + * N25QXXX device. + */ + + mtd = n25qxxx_initialize(qspi, true); + if (!mtd) + { + SYSLOG("ERROR: n25qxxx_initialize failed\n"); + } + +#ifdef HAVE_N25QXXX_SMARTFS + /* Configure the device with no partition support */ + + ret = smart_initialize(N25QXXX_SMART_MINOR, mtd, NULL); + if (ret != OK) + { + SYSLOG("ERROR: Failed to initialize SmartFS: %d\n", ret); + } + +#elif defined(HAVE_N25QXXX_NXFFS) + /* Initialize to provide NXFFS on the N25QXXX MTD interface */ + + ret = nxffs_initialize(mtd); + if (ret < 0) + { + SYSLOG("ERROR: NXFFS initialization failed: %d\n", ret); + } + + /* Mount the file system at /mnt/n25qxxx */ + + ret = mount(NULL, "/mnt/n25qxxx", "nxffs", 0, NULL); + if (ret < 0) + { + SYSLOG("ERROR: Failed to mount the NXFFS volume: %d\n", errno); + return ret; + } + +#else /* if defined(HAVE_N25QXXX_CHARDEV) */ + /* Use the FTL layer to wrap the MTD driver as a block driver */ + + ret = ftl_initialize(N25QXXX_MTD_MINOR, mtd); + if (ret < 0) + { + SYSLOG("ERROR: Failed to initialize the FTL layer: %d\n", ret); + return ret; + } + + /* Use the minor number to create device paths */ + + snprintf(blockdev, 18, "/dev/mtdblock%d", N25QXXX_MTD_MINOR); + snprintf(chardev, 12, "/dev/mtd%d", N25QXXX_MTD_MINOR); + + /* Now create a character device on the block device */ + + /* NOTE: for this to work, you will need to make sure that + * CONFIG_FS_WRITABLE is set in the config. It's not a user- + * visible setting, but you can make it set by selecting an + * arbitrary writeable file system (you don't have to actually + * use it, just select it so that the block device created via + * ftl_initialize() will be writeable). Personally, I chose FAT, + * because SMARTFS and NXFFS will cause the other code branches + * above to become active. + */ + + ret = bchdev_register(blockdev, chardev, false); + if (ret < 0) + { + SYSLOG("ERROR: bchdev_register %s failed: %d\n", chardev, ret); + return ret; + } +#endif + } +#endif + return OK; } +#endif /* CONFIG_LIB_BOARDCTL */ diff --git a/configs/stm32l476vg-disco/src/stm32l476vg-disco.h b/configs/stm32l476vg-disco/src/stm32l476vg-disco.h index ba184d19e6..03c63bc3ea 100644 --- a/configs/stm32l476vg-disco/src/stm32l476vg-disco.h +++ b/configs/stm32l476vg-disco/src/stm32l476vg-disco.h @@ -53,6 +53,84 @@ ************************************************************************************/ /* Configuration ********************************************************************/ +#define HAVE_PROC 1 +#define HAVE_RTC_DRIVER 1 +#define HAVE_N25QXXX 1 +#define HAVE_N25QXXX_NXFFS 1 +#define HAVE_N25QXXX_SMARTFS 1 +#define HAVE_N25QXXX_CHARDEV 1 +#define HAVE_PROGMEM_CHARDEV 1 + +#if !defined(CONFIG_FS_PROCFS) +# undef HAVE_PROC +#endif + +#if defined(HAVE_PROC) && defined(CONFIG_DISABLE_MOUNTPOINT) +# warning Mountpoints disabled. No procfs support +# undef HAVE_PROC +#endif + +/* Check if we can support the RTC driver */ + +#if !defined(CONFIG_RTC) || !defined(CONFIG_RTC_DRIVER) +# undef HAVE_RTC_DRIVER +#endif + +/* N25QXXX QuadSPI FLASH */ + +#ifndef CONFIG_MTD_N25QXXX +# undef HAVE_N25QXXX +# undef HAVE_N25QXXX_NXFFS +# undef HAVE_N25QXXX_SMARTFS +# undef HAVE_N25QXXX_CHARDEV +#endif + +#ifndef CONFIG_STM32L4_QSPI +# undef HAVE_N25QXXX +# undef HAVE_N25QXXX_NXFFS +# undef HAVE_N25QXXX_SMARTFS +# undef HAVE_N25QXXX_CHARDEV +#endif + +#ifndef CONFIG_FS_NXFFS +# undef HAVE_N25QXXX_NXFFS +#endif + +#if !defined(CONFIG_MTD_SMART) || !defined(CONFIG_FS_SMARTFS) +# undef HAVE_N25QXXX_SMARTFS +#endif + +#if defined(HAVE_N25QXXX_NXFFS) && defined(HAVE_N25QXXX_SMARTFS) +# undef HAVE_N25QXXX_NXFFS +#endif + +#if defined(HAVE_N25QXXX_NXFFS) || defined(HAVE_N25QXXX_SMARTFS) +# undef HAVE_N25QXXX_CHARDEV +#endif + +/* On-chip Programming Memory */ + +#if !defined(CONFIG_STM32L4_PROGMEM) || !defined(CONFIG_MTD_PROGMEM) +# undef HAVE_PROGMEM_CHARDEV +#endif + +/* If both the N25QXXX FLASH and SmartFS, then this is the minor device + * number of the Smart block driver (/dev/smartN) + */ + +#define N25QXXX_SMART_MINOR 0 + +/* If the N25QXXX FLASH is enabled but not SmartFS, then the N25QXXX will be + * wrapped as a character device. This is the minor number of both the + * block device (/dev/mtdblockN) and the character device (/dev/mtdN). + */ + +#define N25QXXX_MTD_MINOR 0 + +/* This is the on-chip progmem memroy driver minor number */ + +#define PROGMEM_MTD_MINOR 1 + /* LED. * LD4: the red LED on PB2 * LD5: the green LED on PE8 @@ -110,7 +188,7 @@ /* XXX IS this 'unshifted'? */ -#define NUCLEO_I2C_OBDEV_CS43L22 0x94 +#define DISCO_I2C_OBDEV_CS43L22 0x94 /************************************************************************************ * Public Data