arch/nrf53: add QSPI support
This commit is contained in:
parent
5ff6c8b403
commit
8b89730e61
arch/arm/src/nrf53
@ -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
|
||||
|
@ -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
|
||||
|
224
arch/arm/src/nrf53/hardware/nrf53_qspi.h
Normal file
224
arch/arm/src/nrf53/hardware/nrf53_qspi.h
Normal 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 */
|
@ -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 */
|
||||
|
942
arch/arm/src/nrf53/nrf53_qspi.c
Normal file
942
arch/arm/src/nrf53/nrf53_qspi.c
Normal 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;
|
||||
}
|
52
arch/arm/src/nrf53/nrf53_qspi.h
Normal file
52
arch/arm/src/nrf53/nrf53_qspi.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user