diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig index 5f4a831156..fc4a279b2b 100644 --- a/arch/arm/src/nrf53/Kconfig +++ b/arch/arm/src/nrf53/Kconfig @@ -29,6 +29,7 @@ config NRF53_APPCORE select NRF53_HAVE_I2C123 select NRF53_HAVE_SPI1234 select NRF53_HAVE_HFCLK192M + select NRF53_HAVE_QSPI config NRF53_NETCORE bool @@ -103,6 +104,10 @@ config NRF53_HAVE_HFCLK192M bool default n +config NRF53_HAVE_QSPI + bool + default n + # Peripheral Selection config NRF53_I2C_MASTER @@ -212,6 +217,11 @@ config NRF53_UART1 select UART1_SERIALDRIVER select NRF53_UART +config NRF53_QSPI + bool "QSPI" + default n + depends on NRF53_HAVE_QSPI + config NRF53_TIMER0 bool "TIMER0" select NRF53_TIMER @@ -325,6 +335,8 @@ config NRF53_HFCLK192M_48 endchoice +endif # NRF53_USE_HFCLK192M + config NRF53_OSCILLATOR_LFXO bool "Configure LFXO oscillator" default y if NRF53_LFCLK_XTAL @@ -610,6 +622,21 @@ config NRF53_I2C_MASTER_COPY_BUF_SIZE endmenu +menu "QSPI Configuration" + +if NRF53_QSPI + +config NRF53_QSPI_RXDELAY + int "QSPI RX delay" + default 2 + range 0 7 + ---help--- + The input serial data sampling delay. + +endif # NRF53_QSPI + +endmenu # QSPI Configuration + menuconfig NRF53_SOFTDEVICE_CONTROLLER bool "SoftDevice Controller" depends on ALLOW_BSDNORDIC_COMPONENTS diff --git a/arch/arm/src/nrf53/Make.defs b/arch/arm/src/nrf53/Make.defs index b56975db25..faf0f4a698 100644 --- a/arch/arm/src/nrf53/Make.defs +++ b/arch/arm/src/nrf53/Make.defs @@ -95,6 +95,10 @@ ifeq ($(CONFIG_USBDEV),y) CHIP_CSRCS += nrf53_usbd.c endif +ifeq ($(CONFIG_NRF53_QSPI),y) +CHIP_CSRCS += nrf53_qspi.c +endif + ifeq ($(CONFIG_NRF53_SOFTDEVICE_CONTROLLER),y) NRFXLIB_UNPACK := sdk-nrfxlib diff --git a/arch/arm/src/nrf53/hardware/nrf53_qspi.h b/arch/arm/src/nrf53/hardware/nrf53_qspi.h new file mode 100644 index 0000000000..7ac201aa43 --- /dev/null +++ b/arch/arm/src/nrf53/hardware/nrf53_qspi.h @@ -0,0 +1,224 @@ +/**************************************************************************** + * arch/arm/src/nrf53/hardware/nrf53_qspi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_QSPI_H +#define __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_QSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/nrf53_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define NRF53_QSPI_TASKS_ACTIVATE_OFFSET 0x0000 /* Activate QSPI interface */ +#define NRF53_QSPI_TASKS_READSTART_OFFSET 0x0004 /* Start transfer from external flash memory to internal RAM */ +#define NRF53_QSPI_TASKS_WRITESTART_OFFSET 0x0008 /* Start transfer from internal RAM to external flash memory */ +#define NRF53_QSPI_TASKS_ERASESTART_OFFSET 0x000c /* Start external flash memory erase operation */ +#define NRF53_QSPI_TASKS_DEACTIVATE_OFFSET 0x0010 /* Deactivate QSPI interface */ +#define NRF53_QSPI_EVENTS_READY_OFFSET 0x0100 /* QSPI peripheral is ready */ +#define NRF53_QSPI_INTEN_OFFSET 0x0300 /* Enable or disable interrupt */ +#define NRF53_QSPI_INTENSET_OFFSET 0x0304 /* Enable interrupt */ +#define NRF53_QSPI_INTENCLR_OFFSET 0x0308 /* Disable interrupt */ +#define NRF53_QSPI_ENABLE_OFFSET 0x0500 /* Enable QSPI peripheral */ +#define NRF53_QSPI_READ_SRC_OFFSET 0x0504 /* Flash memory source address */ +#define NRF53_QSPI_READ_DST_OFFSET 0x0508 /* RAM destination address */ +#define NRF53_QSPI_READ_CNT_OFFSET 0x050c /* Read transfer length */ +#define NRF53_QSPI_WRITE_SRC_OFFSET 0x0510 /* Flash destination address */ +#define NRF53_QSPI_WRITE_DST_OFFSET 0x0514 /* RAM source address */ +#define NRF53_QSPI_WRITE_CNT_OFFSET 0x0518 /* Write transfer length */ +#define NRF53_QSPI_ERASE_PTR_OFFSET 0x051c /* Start address of flash block to be erased */ +#define NRF53_QSPI_ERASE_LEN_OFFSET 0x0520 /* Size of block to be erased */ +#define NRF53_QSPI_PSEL_SCK_OFFSET 0x0524 /* Pin select for serial clock SCK */ +#define NRF53_QSPI_PSEL_CSN_OFFSET 0x0528 /* Pin select for chip select signal CSN */ +#define NRF53_QSPI_PSEL_IO0_OFFSET 0x0530 /* Pin select for serial data MOSI/IO0 */ +#define NRF53_QSPI_PSEL_IO1_OFFSET 0x0534 /* Pin select for serial data MISO/IO1 */ +#define NRF53_QSPI_PSEL_IO2_OFFSET 0x0538 /* Pin select for serial data IO2 */ +#define NRF53_QSPI_PSEL_IO3_OFFSET 0x053c /* Pin select for serial data IO3 */ +#define NRF53_QSPI_XIPOFFSET_OFFSET 0x0540 /* Address offset into the external memory for XIP */ +#define NRF53_QSPI_IFCONFIG0_OFFSET 0x0544 /* Interface configuration */ +#define NRF53_QSPI_XIPEN_OFFSET 0x054c /* Enable Execute in Place operation. */ +#define NRF53_QSPI_XIPENC_KEY0_OFFSET 0x0560 /* Bits 31:0 of XIP AES KEY */ +#define NRF53_QSPI_XIPENC_KEY1_OFFSET 0x0564 /* Bits 63:32 of XIP AES KEY */ +#define NRF53_QSPI_XIPENC_KEY2_OFFSET 0x0568 /* Bits 95:64 of XIP AES KEY */ +#define NRF53_QSPI_XIPENC_KEY3_OFFSET 0x056c /* Bits 95:64 of XIP AES KEY */ +#define NRF53_QSPI_XIPENC_NONCE0_OFFSET 0x0570 /* Bits 127:96 of XIP AES KEY */ +#define NRF53_QSPI_XIPENC_NONCE1_OFFSET 0x0574 /* Bits 31:0 of XIP NONCE */ +#define NRF53_QSPI_XIPENC_NONCE2_OFFSET 0x0578 /* Bits 63:32 of XIP NONCE */ +#define NRF53_QSPI_XIPENC_ENABLE_OFFSET 0x057c /* Enable stream cipher for XIP */ +#define NRF53_QSPI_DMAENC_KEY0_OFFSET 0x0580 /* Bits 31:0 of DMA AES KEY */ +#define NRF53_QSPI_DMAENC_KEY1_OFFSET 0x0584 /* Bits 63:32 of DMA AES KEY */ +#define NRF53_QSPI_DMAENC_KEY2_OFFSET 0x0588 /* Bits 95:64 of DMA AES KEY */ +#define NRF53_QSPI_DMAENC_KEY3_OFFSET 0x058c /* Bits 127:96 of DMA AES KEY */ +#define NRF53_QSPI_DMAENC_NONCE0_OFFSET 0x0590 /* Bits 31:0 of DMA NONCE */ +#define NRF53_QSPI_DMAENC_NONCE1_OFFSET 0x0594 /* Bits 63:32 of DMA NONCE */ +#define NRF53_QSPI_DMAENC_NONCE2_OFFSET 0x0598 /* Bits 95:64 of DMA NONCE */ +#define NRF53_QSPI_DMAENC_ENABLE_OFFSET 0x059c /* Enable stream cipher for EasyDMA */ +#define NRF53_QSPI_IFCONFIG1_OFFSET 0x0600 /* Interface configuration */ +#define NRF53_QSPI_STATUS_OFFSET 0x0604 /* Status register */ +#define NRF53_QSPI_DPMDUR_OFFSET 0x0614 /* DPM duration */ +#define NRF53_QSPI_ADDRCONF_OFFSET 0x0624 /* Extended address configuration. */ +#define NRF53_QSPI_CINSTRCONF_OFFSET 0x0634 /* Custom instruction configuration register. */ +#define NRF53_QSPI_CINSTRDAT0_OFFSET 0x0638 /* Custom instruction data register 0. */ +#define NRF53_QSPI_CINSTRDAT1_OFFSET 0x063c /* Custom instruction data register 1. */ +#define NRF53_QSPI_IFTIMING_OFFSET 0x0640 /* SPI interface timing. */ + +/* Register Bitfield Definitions ********************************************/ + +/* INTEN/INTENSET/INTENCLR */ + +#define QSPI_INT_READY (1 << 0) + +/* ENABLE */ + +#define QSPI_ENABLE_EN (1) +#define QSPI_ENABLE_DIS (0) + +/* ERASE.LEN */ + +#define QSPI_ERASE_SECTOR (0) +#define QSPI_ERASE_PAGE (1) +#define QSPI_ERASE_ALL (2) + +/* PSEL */ + +#define QSPI_PSEL_PIN_SHIFT (0) +#define QSPI_PSEL_PORT_SHIFT (5) +#define QSPI_PSEL_CONNECT (1 << 31) + +/* IFCONFIG0 */ + +#define QSPI_IFCONFIG0_READOC_SHIFT (0) +#define QSPI_IFCONFIG0_READOC_MASK (0x7 << QSPI_IFCONFIG0_READOC_SHIFT) +# define QSPI_IFCONFIG0_READOC_FASTREAD (0 << QSPI_IFCONFIG0_READOC_SHIFT) +# define QSPI_IFCONFIG0_READOC_READ2O (1 << QSPI_IFCONFIG0_READOC_SHIFT) +# define QSPI_IFCONFIG0_READOC_READ2IO (2 << QSPI_IFCONFIG0_READOC_SHIFT) +# define QSPI_IFCONFIG0_READOC_READ4O (3 << QSPI_IFCONFIG0_READOC_SHIFT) +# define QSPI_IFCONFIG0_READOC_READ4IO (4 << QSPI_IFCONFIG0_READOC_SHIFT) +#define QSPI_IFCONFIG0_WRITEOC_SHIFT (3) +#define QSPI_IFCONFIG0_WRITEOC_MASK (0x7 << QSPI_IFCONFIG0_WRITEOC_SHIFT) +# define QSPI_IFCONFIG0_WRITEOC_PP (0 << QSPI_IFCONFIG0_WRITEOC_SHIFT) +# define QSPI_IFCONFIG0_WRITEOC_PP2O (1 << QSPI_IFCONFIG0_WRITEOC_SHIFT) +# define QSPI_IFCONFIG0_WRITEOC_PP4O (2 << QSPI_IFCONFIG0_WRITEOC_SHIFT) +# define QSPI_IFCONFIG0_WRITEOC_PP4IO (3 << QSPI_IFCONFIG0_WRITEOC_SHIFT) +#define QSPI_IFCONFIG0_ADDRMODE_24 (0 << 6) +#define QSPI_IFCONFIG0_ADDRMODE_32 (1 << 6) +#define QSPI_IFCONFIG0_DPMENABLE (1 << 7) +#define QSPI_IFCONFIG0_PPSIZE_512 (1 << 12) + +/* IFCONFIG1 */ + +#define QSPI_IFCONFIG1_SCKDELAY_SHIFT (0) +#define QSPI_IFCONFIG1_SCKDELAY_MASK (0xff << QSPI_IFCONFIG1_SCKDELAY_SHIFT) +#define QSPI_IFCONFIG1_DPMEN_EXIT (0 << 24) +#define QSPI_IFCONFIG1_DPMEN_ENTER (1 << 24) +#define QSPI_IFCONFIG1_SPIMODE_0 (0 << 25) +#define QSPI_IFCONFIG1_SPIMODE_3 (1 << 25) +#define QSPI_IFCONFIG1_SCKFREQ_SHIFT (28) +#define QSPI_IFCONFIG1_SCKFREQ_MASK (0xf << QSPI_IFCONFIG1_SCKFREQ_SHIFT) + +/* STATUS */ + +#define QSPI_STATUS_DPM (1 << 2) +#define QSPI_STATUS_READY (1 << 3) +#define QSPI_STATUS_SREG_SHIFT (24) +#define QSPI_STATUS_SREG_MASK (0xff << QSPI_STATUS_SREG_SHIFT) + +/* DPMDUR */ + +#define QSPI_DPMDUR_ENTER_SHIFT (0) +#define QSPI_DPMDUR_ENTER_MASK (0xffff << QSPI_DPMDUR_ENTER_SHIFT) +#define QSPI_DPMDUR_EXIT_SHIFT (16) +#define QSPI_DPMDUR_EXIT_MASK (0xffff << QSPI_DPMDUR_EXIT_SHIFT) + +/* ADDRCONF */ + +#define QSPI_ADDRCONF_OPCODE_SHIFT (0) +#define QSPI_ADDRCONF_OPCODE_MASK (0xff << QSPI_ADDRCONF_OPCODE_SHIFT) +#define QSPI_ADDRCONF_BYTE0_SHIFT (8) +#define QSPI_ADDRCONF_BYTE0_MASK (0xff << QSPI_ADDRCONF_BYTE0_SHIFT) +#define QSPI_ADDRCONF_BYTE1_SHIFT (16) +#define QSPI_ADDRCONF_BYTE1_MASK (0xff << QSPI_ADDRCONF_BYTE1_SHIFT) +#define QSPI_ADDRCONF_MODE_SHIFT (24) +#define QSPI_ADDRCONF_MODE_MASK (0x3 << QSPI_ADDRCONF_MODE_SHIFT) +# define QSPI_ADDRCONF_MODE_NOINSTR (0 << QSPI_ADDRCONF_MODE_SHIFT) +# define QSPI_ADDRCONF_MODE_OPCODE (1 << QSPI_ADDRCONF_MODE_SHIFT) +# define QSPI_ADDRCONF_MODE_OPBYTE0 (2 << QSPI_ADDRCONF_MODE_SHIFT) +# define QSPI_ADDRCONF_MODE_ALL (3 << QSPI_ADDRCONF_MODE_SHIFT) +#define QSPI_ADDRCONF_WIPWAIT (1 << 26) +#define QSPI_ADDRCONF_WREN (1 << 27) + +/* CINSTRCONF */ + +#define QSPI_CINSTRCONF_OPCODE_SHIFT (0) +#define QSPI_CINSTRCONF_OPCODE_MASK (0xff << QSPI_CINSTRCONF_OPCODE_SHIFT) +#define QSPI_CINSTRCONF_LENGTH_SHIFT (8) +#define QSPI_CINSTRCONF_LENGTH_MASK (0xf << QSPI_CINSTRCONF_LENGTH_SHIFT) +#define QSPI_CINSTRCONF_LENGTH(n) ((n) << QSPI_CINSTRCONF_LENGTH_SHIFT) +#define QSPI_CINSTRCONF_LIO2 (1 << 12) +#define QSPI_CINSTRCONF_LIO3 (1 << 13) +#define QSPI_CINSTRCONF_WIPWAIT (1 << 14) +#define QSPI_CINSTRCONF_WREN (1 << 15) +#define QSPI_CINSTRCONF_LFEN (1 << 16) +#define QSPI_CINSTRCONF_LFSTOP_STOP (1 << 17) + +/* CINSTRDAT0 */ + +#define QSPI_CINSTRDAT0_BYTE0_SHIFT (0) +#define QSPI_CINSTRDAT0_BYTE0_MASK (0xff << QSPI_CINSTRDAT0_BYTE0_SHIFT) +#define QSPI_CINSTRDAT0_BYTE0(n) ((n) << QSPI_CINSTRDAT0_BYTE0_SHIFT) +#define QSPI_CINSTRDAT0_BYTE1_SHIFT (8) +#define QSPI_CINSTRDAT0_BYTE1_MASK (0xff << QSPI_CINSTRDAT0_BYTE1_SHIFT) +#define QSPI_CINSTRDAT0_BYTE1(n) ((n) << QSPI_CINSTRDAT0_BYTE1_SHIFT) +#define QSPI_CINSTRDAT0_BYTE2_SHIFT (16) +#define QSPI_CINSTRDAT0_BYTE2_MASK (0xff << QSPI_CINSTRDAT0_BYTE2_SHIFT) +#define QSPI_CINSTRDAT0_BYTE2(n) ((n) << QSPI_CINSTRDAT0_BYTE2_SHIFT) +#define QSPI_CINSTRDAT0_BYTE3_SHIFT (24) +#define QSPI_CINSTRDAT0_BYTE3_MASK (0xff << QSPI_CINSTRDAT0_BYTE3_SHIFT) +#define QSPI_CINSTRDAT0_BYTE3(n) ((n) << QSPI_CINSTRDAT0_BYTE3_SHIFT) + +/* CINSTRDAT1 */ + +#define QSPI_CINSTRDAT1_BYTE0_SHIFT (0) +#define QSPI_CINSTRDAT1_BYTE0_MASK (0xff << QSPI_CINSTRDAT1_BYTE0_SHIFT) +#define QSPI_CINSTRDAT1_BYTE0(n) ((n) << QSPI_CINSTRDAT1_BYTE0_SHIFT) +#define QSPI_CINSTRDAT1_BYTE1_SHIFT (8) +#define QSPI_CINSTRDAT1_BYTE1_MASK (0xff << QSPI_CINSTRDAT1_BYTE1_SHIFT) +#define QSPI_CINSTRDAT1_BYTE1(n) ((n) << QSPI_CINSTRDAT1_BYTE1_SHIFT) +#define QSPI_CINSTRDAT1_BYTE2_SHIFT (16) +#define QSPI_CINSTRDAT1_BYTE2_MASK (0xff << QSPI_CINSTRDAT1_BYTE2_SHIFT) +#define QSPI_CINSTRDAT1_BYTE2(n) ((n) << QSPI_CINSTRDAT1_BYTE2_SHIFT) +#define QSPI_CINSTRDAT1_BYTE3_SHIFT (24) +#define QSPI_CINSTRDAT1_BYTE3_MASK (0xff << QSPI_CINSTRDAT1_BYTE3_SHIFT) +#define QSPI_CINSTRDAT1_BYTE3(n) ((n) << QSPI_CINSTRDAT1_BYTE3_SHIFT) + +/* IFTIMING */ + +#define QSPI_IFTIMING_RXDELAY_SHIFT (8) +#define QSPI_IFTIMING_RXDELAY_MASK (0xff << QSPI_IFTIMING_RXDELAY_SHIFT) +#define QSPI_IFTIMING_RXDELAY(n) ((n) << QSPI_IFTIMING_RXDELAY_SHIFT) + +#endif /* __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_QSPI_H */ diff --git a/arch/arm/src/nrf53/nrf53_clockconfig.c b/arch/arm/src/nrf53/nrf53_clockconfig.c index 19bb9a346c..e205b33634 100644 --- a/arch/arm/src/nrf53/nrf53_clockconfig.c +++ b/arch/arm/src/nrf53/nrf53_clockconfig.c @@ -111,11 +111,11 @@ void nrf53_clockconfig(void) /* Initialize HFCLK192M */ #if defined(CONFIG_NRF53_HFCLK192M_192) - putreg32(NRF53_CLOCK_HFCLK192MSRC, CLOCK_HFCLK192MSRC_DIV1); + putreg32(CLOCK_HFCLK192MSRC_DIV1, NRF53_CLOCK_HFCLK192MSRC); #elif defined(CONFIG_NRF53_HFCLK192M_96) - putreg32(NRF53_CLOCK_HFCLK192MSRC, CLOCK_HFCLK192MSRC_DIV2); + putreg32(CLOCK_HFCLK192MSRC_DIV2, NRF53_CLOCK_HFCLK192MSRC); #elif defined(CONFIG_NRF53_HFCLK192M_48) - putreg32(NRF53_CLOCK_HFCLK192MSRC, CLOCK_HFCLK192MSRC_DIV4); + putreg32(CLOCK_HFCLK192MSRC_DIV4, NRF53_CLOCK_HFCLK192MSRC); #endif /* Trigger HFCLK192M start */ diff --git a/arch/arm/src/nrf53/nrf53_qspi.c b/arch/arm/src/nrf53/nrf53_qspi.c new file mode 100644 index 0000000000..7f06a96596 --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_qspi.c @@ -0,0 +1,942 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_qspi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "arm_internal.h" + +#include "hardware/nrf53_qspi.h" + +#include "nrf53_clockconfig.h" +#include "nrf53_gpio.h" +#include "nrf53_qspi.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if ((NRF53_PCLK192M_FREQ != 192000000) && (NRF53_PCLK192M_FREQ != 96000000)) +# error not supported PCLK192M frequency +#endif + +/* QSPI frequency limits */ + +#define NRF53_QSPI_FREQMAX (NRF53_PCLK192M_FREQ / (2 * 1)) +#define NRF53_QSPI_FREQMIN (NRF53_PCLK192M_FREQ / (2 * 16)) + +/* Instruction handled by the NRF53 QSPI peripheral */ + +#define QSPI_SECTOR_ERASE 0x20 +#define QSPI_BLOCK_ERASE 0xd8 +#define QSPI_ALL_ERASE 0xc7 + +/* 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) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct nrf53_qspidev_s +{ + struct qspi_dev_s qspi; /* Externally visible part of the QSPI interface */ + mutex_t lock; /* Assures mutually exclusive access to QSPI */ + uint32_t base; /* QSPI base address */ + uint32_t actual; /* Actual clock frequency */ + uint32_t frequency; /* Requested clock frequency */ + bool initialized; /* TRUE: Controller has been initialized */ + uint8_t intf; /* QSPI controller number (0) */ + uint8_t mode; /* Mode 0,3 */ + sem_t op_sem; /* Block until complete */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +static inline void nrf53_qspi_putreg(struct nrf53_qspidev_s *priv, + uint32_t offset, + uint32_t value); +static inline uint32_t nrf53_qspi_getreg(struct nrf53_qspidev_s *priv, + uint32_t offset); +static void nrf53_qspi_cinstrdata_get(struct nrf53_qspidev_s *priv, + struct qspi_cmdinfo_s *cmdinfo); +static void nrf53_qspi_cinstrdata_put(struct nrf53_qspidev_s *priv, + struct qspi_cmdinfo_s *cmdinfo); + +/* QSPI operations */ + +static int nrf53_qspi_lock(struct qspi_dev_s *dev, bool lock); + +static int nrf53_qspi_lock(struct qspi_dev_s *dev, bool lock); +static uint32_t nrf53_qspi_setfrequency(struct qspi_dev_s *dev, + uint32_t frequency); +static void nrf53_qspi_setmode(struct qspi_dev_s *dev, + enum qspi_mode_e mode); +static void nrf53_qspi_setbits(struct qspi_dev_s *dev, int nbits); +static int nrf53_qspi_command(struct qspi_dev_s *dev, + struct qspi_cmdinfo_s *cmdinfo); +static int nrf53_qspi_memory(struct qspi_dev_s *dev, + struct qspi_meminfo_s *meminfo); +static void *nrf53_qspi_alloc(struct qspi_dev_s *dev, size_t buflen); +static void nrf53_qspi_free(struct qspi_dev_s *dev, void *buffer); + +static int nrf53_qspi_interrupt(int irq, void *context, void *arg); +static int nrf53_qspi_hw_initialize(struct nrf53_qspidev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct qspi_ops_s g_qspi_ops = +{ + .lock = nrf53_qspi_lock, + .setfrequency = nrf53_qspi_setfrequency, + .setmode = nrf53_qspi_setmode, + .setbits = nrf53_qspi_setbits, + .command = nrf53_qspi_command, + .memory = nrf53_qspi_memory, + .alloc = nrf53_qspi_alloc, + .free = nrf53_qspi_free, +}; + +static struct nrf53_qspidev_s g_qspi0_dev = +{ + .qspi = + { + .ops = &g_qspi_ops, + }, + .lock = NXMUTEX_INITIALIZER, + .op_sem = SEM_INITIALIZER(0), + .base = NRF53_QSPI_BASE, + .intf = 0 +}; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_qspi_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void nrf53_qspi_putreg(struct nrf53_qspidev_s *priv, + uint32_t offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: nrf53_qspi_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline uint32_t nrf53_qspi_getreg(struct nrf53_qspidev_s *priv, + uint32_t offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: nrf53_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 nrf53_qspi_lock(struct qspi_dev_s *dev, bool lock) +{ + struct nrf53_qspidev_s *priv = (struct nrf53_qspidev_s *)dev; + int ret; + + spiinfo("lock=%d\n", lock); + if (lock) + { + ret = nxmutex_lock(&priv->lock); + } + else + { + ret = nxmutex_unlock(&priv->lock); + } + + return ret; +} + +/**************************************************************************** + * Name: nrf53_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 nrf53_qspi_setfrequency(struct qspi_dev_s *dev, + uint32_t frequency) +{ + struct nrf53_qspidev_s *priv = (struct nrf53_qspidev_s *)dev; + uint32_t sckfreq = 0; + uint32_t actual = 0; + uint32_t regval = 0; + + spiinfo("frequency=%ld\n", frequency); + DEBUGASSERT(priv); + + /* 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; + } + + /* Get prescaler */ + + if (frequency <= NRF53_QSPI_FREQMIN) + { + sckfreq = 15; + } + else if (frequency <= NRF53_QSPI_FREQMAX) + { + sckfreq = ((NRF53_PCLK192M_FREQ / 2) / frequency) - 1; + } + else + { + sckfreq = 0; + } + + /* Modify register */ + + regval = nrf53_qspi_getreg(priv, NRF53_QSPI_IFCONFIG1_OFFSET); + regval &= ~QSPI_IFCONFIG1_SCKFREQ_MASK; + regval |= sckfreq << QSPI_IFCONFIG1_SCKFREQ_SHIFT; + nrf53_qspi_putreg(priv, NRF53_QSPI_IFCONFIG1_OFFSET, regval); + + /* Calculate the new actual frequency */ + + actual = NRF53_PCLK192M_FREQ / (2 * (sckfreq + 1)); + + /* Save the frequency setting */ + + priv->frequency = frequency; + priv->actual = actual; + + spiinfo("Frequency %ld->%ld\n", frequency, actual); + + return actual; +} + +/**************************************************************************** + * Name: nrf53_qspi_setmode + * + * Description: + * Set the QSPI mode. Optional. See enum qspi_mode_e for mode definitions. + * NOTE: the NRF53 QSPI supports only modes 0 and 3. + * + * Input Parameters: + * dev - Device-specific state data + * mode - The QSPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void nrf53_qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode) +{ + struct nrf53_qspidev_s *priv = (struct nrf53_qspidev_s *)dev; + uint32_t regval = 0; + + spiinfo("mode=%d\n", mode); + + /* Has the mode changed? */ + + if (mode != priv->mode) + { + regval = nrf53_qspi_getreg(priv, NRF53_QSPI_IFCONFIG1_OFFSET); + + switch (mode) + { + case QSPIDEV_MODE0: + { + regval |= (QSPI_IFCONFIG1_SPIMODE_0); + break; + } + + case QSPIDEV_MODE3: + { + regval |= (QSPI_IFCONFIG1_SPIMODE_3); + break; + } + + case QSPIDEV_MODE1: + case QSPIDEV_MODE2: + { + spiinfo("unsupported mode=%d\n", mode); + + /* No break here */ + } + default: + { + DEBUGASSERT(0); + return; + } + } + + /* Write new mode */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_IFCONFIG1_OFFSET, regval); + + /* Save the mode so that subsequent re-configurations will be faster */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: nrf53_qspi_setbits + * + * Description: + * Set the number of bits per word. + * NOTE: the NRF53 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 nrf53_qspi_setbits(struct qspi_dev_s *dev, int nbits) +{ + if (nbits != 8) + { + spiinfo("unsupported nbits=%d\n", nbits); + DEBUGASSERT(FALSE); + } +} + +/**************************************************************************** + * Name: nrf53_qspi_cinstrdata_get + * + * Description: + * Get command data + * + * Input Parameters: + * priv - Device state structure. + * cmdinfo - Describes the command transfer to be performed. + * + * Returned Value: + * Zero (OK) on SUCCESS, a negated errno on value of failure + * + ****************************************************************************/ + +static void nrf53_qspi_cinstrdata_get(struct nrf53_qspidev_s *priv, + struct qspi_cmdinfo_s *cmdinfo) +{ + uint32_t regval = 0; + int i = 0; + uint8_t *buffer = cmdinfo->buffer; + + DEBUGASSERT(cmdinfo->buflen <= 8); + + /* Get Bytes 0-3 */ + + regval = nrf53_qspi_getreg(priv, NRF53_QSPI_CINSTRDAT0_OFFSET); + + if (cmdinfo->buflen > 0) + { + for (i = 0; (i < 4) && (i < cmdinfo->buflen); i += 1) + { + buffer[i] = (regval >> (i * 8)) & 0xff; + } + } + + /* Write Bytes 4-7 */ + + regval = nrf53_qspi_getreg(priv, NRF53_QSPI_CINSTRDAT1_OFFSET); + + if (cmdinfo->buflen > 4) + { + for (i = 4; (i < 8) && (i < cmdinfo->buflen); i += 1) + { + buffer[i] = (regval >> ((i - 4) * 8)) & 0xff; + } + } +} + +/**************************************************************************** + * Name: nrf53_qspi_cinstrdata_put + * + * Description: + * Put command data + * + * Input Parameters: + * priv - Device state structure. + * cmdinfo - Describes the command transfer to be performed. + * + * Returned Value: + * Zero (OK) on SUCCESS, a negated errno on value of failure + * + ****************************************************************************/ + +static void nrf53_qspi_cinstrdata_put(struct nrf53_qspidev_s *priv, + struct qspi_cmdinfo_s *cmdinfo) +{ + uint32_t regval = 0; + int i = 0; + uint8_t *buffer = cmdinfo->buffer; + + DEBUGASSERT(cmdinfo->buflen <= 8); + + regval = 0; + + if (cmdinfo->buflen > 0) + { + for (i = 0; (i < 4) && (i < cmdinfo->buflen); i += 1) + { + regval |= (buffer[i] << (i * 8)); + } + } + + /* Write Bytes 0-3 */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_CINSTRDAT0_OFFSET, regval); + + regval = 0; + if (cmdinfo->buflen > 4) + { + for (i = 4; (i < 8) && (i < cmdinfo->buflen); i += 1) + { + regval |= (buffer[i] << ((i - 4) * 8)); + } + } + + /* Write Bytes 4-7 */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_CINSTRDAT1_OFFSET, regval); +} + +/**************************************************************************** + * Name: nrf53_qspi_command + * + * Description: + * Perform one QSPI data transfer + * + * TODO: long frame mode not supported + * + * 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 nrf53_qspi_command(struct qspi_dev_s *dev, + struct qspi_cmdinfo_s *cmdinfo) +{ + struct nrf53_qspidev_s *priv = (struct nrf53_qspidev_s *)dev; + uint32_t regval = 0; + + DEBUGASSERT(cmdinfo->cmd < 256); + + if (QSPICMD_ISADDRESS(cmdinfo->flags)) + { + /* Only ERASE commands supported */ + + switch (cmdinfo->cmd) + { + case QSPI_SECTOR_ERASE: + { + regval = QSPI_ERASE_SECTOR; + break; + } + + case QSPI_BLOCK_ERASE: + { + regval = QSPI_ERASE_PAGE; + break; + } + + case QSPI_ALL_ERASE: + { + regval = QSPI_ERASE_ALL; + break; + } + + default: + { + /* Not supported addressed command */ + + DEBUGASSERT(0); + return -EINVAL; + } + } + + /* Configure erase length */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_ERASE_LEN_OFFSET, regval); + + /* Configure erase address */ + + regval = cmdinfo->addr; + nrf53_qspi_putreg(priv, NRF53_QSPI_ERASE_PTR_OFFSET, regval); + + /* Start erase operation */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_TASKS_ERASESTART_OFFSET, 1); + + /* Wait for the READY event. + * TODO: add timeout. + * + * NOTE: READ event only signals that the erase operation + * has been started. + */ + + nxsem_wait(&priv->op_sem); + + return OK; + } + + if (QSPICMD_ISWRITE(cmdinfo->flags)) + { + /* Write data to CINSTRDAT registers */ + + nrf53_qspi_cinstrdata_put(priv, cmdinfo); + } + + /* Configure custom instruction */ + + regval = cmdinfo->cmd << QSPI_ADDRCONF_OPCODE_SHIFT; + regval |= QSPI_CINSTRCONF_LENGTH(cmdinfo->buflen + 1); + + if (QSPICMD_ISWRITE(cmdinfo->flags)) + { + /* Write request */ + + regval |= QSPI_CINSTRCONF_WREN; + + /* Wait for write complete before sending command */ + + regval |= QSPI_CINSTRCONF_WIPWAIT; + } + + /* IO2 and IO3 high during transmission of custom instruction */ + + regval |= QSPI_CINSTRCONF_LIO2 | QSPI_CINSTRCONF_LIO3; + + /* Write CINSTRCONF register to initiate transfer */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_CINSTRCONF_OFFSET, regval); + + /* Wait for the READY event. + * TODO: add timeout. + */ + + nxsem_wait(&priv->op_sem); + + if (QSPICMD_ISREAD(cmdinfo->flags)) + { + /* Get response */ + + nrf53_qspi_cinstrdata_get(priv, cmdinfo); + } + + return OK; +} + +/**************************************************************************** + * Name: nrf53_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 nrf53_qspi_memory(struct qspi_dev_s *dev, + struct qspi_meminfo_s *meminfo) +{ + struct nrf53_qspidev_s *priv = (struct nrf53_qspidev_s *)dev; + + DEBUGASSERT(meminfo->buffer != NULL && meminfo->buflen > 0); + + if (QSPIMEM_ISWRITE(meminfo->flags)) + { + /* Configure data transfer */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_WRITE_SRC_OFFSET, + meminfo->addr); + nrf53_qspi_putreg(priv, NRF53_QSPI_WRITE_DST_OFFSET, + (uint32_t) meminfo->buffer); + nrf53_qspi_putreg(priv, NRF53_QSPI_WRITE_CNT_OFFSET, + meminfo->buflen); + + /* Start WRITE task */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_TASKS_WRITESTART_OFFSET, 1); + } + else + { + /* Configure data transfer */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_READ_SRC_OFFSET, + meminfo->addr); + nrf53_qspi_putreg(priv, NRF53_QSPI_READ_DST_OFFSET, + (uint32_t) meminfo->buffer); + nrf53_qspi_putreg(priv, NRF53_QSPI_READ_CNT_OFFSET, + meminfo->buflen); + + /* Start READ task */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_TASKS_READSTART_OFFSET, 1); + } + + /* Wait for the READY event. + * TODO: add timeout. + */ + + nxsem_wait(&priv->op_sem); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_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 the allocated memory on success; NULL is returned on any + * failure. + * + ****************************************************************************/ + +static void *nrf53_qspi_alloc(struct qspi_dev_s *dev, size_t buflen) +{ + return kmm_malloc(ALIGN_UP(buflen)); +} + +/**************************************************************************** + * Name: nrf53_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 nrf53_qspi_free(struct qspi_dev_s *dev, void *buffer) +{ + if (buffer) + { + kmm_free(buffer); + } +} + +/**************************************************************************** + * Name: nrf53_qspi_interrupt + * + * Description: + * Interrupt handler; we handle all QSPI cases -- reads, writes, + * automatic status polling, etc. + * + * Input Parameters: + * irq - + * context - + * qrg - + * + * Returned Value: + * OK means we handled it + * + ****************************************************************************/ + +static int nrf53_qspi_interrupt(int irq, void *context, void *arg) +{ + struct nrf53_qspidev_s *priv = arg; + + /* Clear READY event */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_EVENTS_READY_OFFSET, 0); + + /* Signal TASK complete */ + + nxsem_post(&g_qspi0_dev.op_sem); + + return OK; +} + +/**************************************************************************** + * Name: nrf53_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 nrf53_qspi_hw_initialize(struct nrf53_qspidev_s *priv) +{ + uint32_t regval = 0; + int pin = 0; + int port = 0; + int ret = 0; + + /* Only for QSPI0 */ + + DEBUGASSERT(priv->intf == 0); + + /* Attach the interrupt handler */ + + ret = irq_attach(NRF53_IRQ_QSPI, nrf53_qspi_interrupt, priv); + if (ret < 0) + { + spierr("ERROR: Failed to attach QSPI irq\n"); + return ret; + } + + /* SCK pin */ + + nrf53_gpio_config(NRF53_QSPI0_SCK_PIN | GPIO_DRIVE_H0H1); + pin = GPIO_PIN_DECODE(NRF53_QSPI0_SCK_PIN); + port = GPIO_PORT_DECODE(NRF53_QSPI0_SCK_PIN); + regval = (pin << QSPI_PSEL_PIN_SHIFT) | (port << QSPI_PSEL_PORT_SHIFT); + nrf53_qspi_putreg(priv, NRF53_QSPI_PSEL_SCK_OFFSET, regval); + + /* CSN pin */ + + nrf53_gpio_config(NRF53_QSPI0_CSN_PIN | GPIO_DRIVE_H0H1); + pin = GPIO_PIN_DECODE(NRF53_QSPI0_CSN_PIN); + port = GPIO_PORT_DECODE(NRF53_QSPI0_CSN_PIN); + regval = (pin << QSPI_PSEL_PIN_SHIFT) | (port << QSPI_PSEL_PORT_SHIFT); + nrf53_qspi_putreg(priv, NRF53_QSPI_PSEL_CSN_OFFSET, regval); + + /* IO0 pin */ + + nrf53_gpio_config(NRF53_QSPI0_IO0_PIN | GPIO_DRIVE_H0H1); + pin = GPIO_PIN_DECODE(NRF53_QSPI0_IO0_PIN); + port = GPIO_PORT_DECODE(NRF53_QSPI0_IO0_PIN); + regval = (pin << QSPI_PSEL_PIN_SHIFT) | (port << QSPI_PSEL_PORT_SHIFT); + nrf53_qspi_putreg(priv, NRF53_QSPI_PSEL_IO0_OFFSET, regval); + + /* IO1 pin */ + + nrf53_gpio_config(NRF53_QSPI0_IO1_PIN | GPIO_DRIVE_H0H1); + pin = GPIO_PIN_DECODE(NRF53_QSPI0_IO1_PIN); + port = GPIO_PORT_DECODE(NRF53_QSPI0_IO1_PIN); + regval = (pin << QSPI_PSEL_PIN_SHIFT) | (port << QSPI_PSEL_PORT_SHIFT); + nrf53_qspi_putreg(priv, NRF53_QSPI_PSEL_IO1_OFFSET, regval); + + /* IO2 pin */ + + nrf53_gpio_config(NRF53_QSPI0_IO2_PIN | GPIO_DRIVE_H0H1); + pin = GPIO_PIN_DECODE(NRF53_QSPI0_IO2_PIN); + port = GPIO_PORT_DECODE(NRF53_QSPI0_IO2_PIN); + regval = (pin << QSPI_PSEL_PIN_SHIFT) | (port << QSPI_PSEL_PORT_SHIFT); + nrf53_qspi_putreg(priv, NRF53_QSPI_PSEL_IO2_OFFSET, regval); + + /* IO3 pin */ + + nrf53_gpio_config(NRF53_QSPI0_IO3_PIN | GPIO_DRIVE_H0H1); + pin = GPIO_PIN_DECODE(NRF53_QSPI0_IO3_PIN); + port = GPIO_PORT_DECODE(NRF53_QSPI0_IO3_PIN); + regval = (pin << QSPI_PSEL_PIN_SHIFT) | (port << QSPI_PSEL_PORT_SHIFT); + nrf53_qspi_putreg(priv, NRF53_QSPI_PSEL_IO3_OFFSET, regval); + + /* Configure quad data line SPI */ + + regval = (QSPI_IFCONFIG0_READOC_READ4IO | QSPI_IFCONFIG0_WRITEOC_PP4IO); + regval |= QSPI_IFCONFIG0_PPSIZE_512; + nrf53_qspi_putreg(priv, NRF53_QSPI_IFCONFIG0_OFFSET, regval); + + /* Enable READY interrupt */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_INTENSET_OFFSET, QSPI_INT_READY); + + /* Configure RX delay */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_IFTIMING_OFFSET, + QSPI_IFTIMING_RXDELAY(CONFIG_NRF53_QSPI_RXDELAY)); + + /* Enable QSPI interrupts */ + + up_enable_irq(NRF53_IRQ_QSPI); + + /* Enable QSPI */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_ENABLE_OFFSET, 1); + + /* Activate QSPI */ + + nrf53_qspi_putreg(priv, NRF53_QSPI_TASKS_ACTIVATE_OFFSET, 1); + + /* Wait for READY event. + * TODO: add timeout. + */ + + nxsem_wait(&priv->op_sem); + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_qspi_initialize + * + * Description: + * Initialize the selected QSPI port in master mode + * + * Input Parameters: + * intf - Interface number(must be zero) + * + * Returned Value: + * Valid QSPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct qspi_dev_s *nrf53_qspi_initialize(int intf) +{ + struct nrf53_qspidev_s *priv = NULL; + int ret = OK; + + /* The NRF53 has only a single QSPI port */ + + spiinfo("intf: %d\n", intf); + DEBUGASSERT(intf == 0); + + /* Select the QSPI interface */ + + if (intf == 0) + { + /* Select QSPI0 */ + + priv = &g_qspi0_dev; + } + else + { + spierr("ERROR: QSPI%d not supported\n", intf); + return NULL; + } + + /* Has the QSPI hardware been initialized? */ + + if (!priv->initialized) + { + /* Perform hardware initialization. Puts the QSPI into an active + * state. + */ + + ret = nrf53_qspi_hw_initialize(priv); + if (ret < 0) + { + spierr("ERROR: Failed to initialize QSPI hardware\n"); + irq_detach(NRF53_IRQ_QSPI); + return NULL; + } + + /* Enable interrupts at the NVIC */ + + priv->initialized = true; + } + + return &priv->qspi; +} diff --git a/arch/arm/src/nrf53/nrf53_qspi.h b/arch/arm/src/nrf53/nrf53_qspi.h new file mode 100644 index 0000000000..f0c1d3a660 --- /dev/null +++ b/arch/arm/src/nrf53/nrf53_qspi.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * arch/arm/src/nrf53/nrf53_qspi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF53_NRF53_QSPI_H +#define __ARCH_ARM_SRC_NRF53_NRF53_QSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf53_qspi_initialize + * + * Description: + * Initialize the selected QSPI port in master mode + * + * Input Parameters: + * intf - Interface number(must be zero) + * + * Returned Value: + * Valid QSPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct qspi_dev_s *nrf53_qspi_initialize(int intf); + +#endif /* __ARCH_ARM_SRC_NRF53_NRF53_QSPI_H */