arch/nrf53: add QSPI support

This commit is contained in:
raiden00pl 2023-05-23 11:45:16 +02:00 committed by Xiang Xiao
parent 5ff6c8b403
commit 8b89730e61
6 changed files with 1252 additions and 3 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <nuttx/config.h>
#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 */

View File

@ -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 */

View File

@ -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 <nuttx/config.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <arch/board/board.h>
#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;
}

View File

@ -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 <nuttx/config.h>
#include <nuttx/spi/qspi.h>
/****************************************************************************
* 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 */