Skip to content

Commit

Permalink
Fixes for nRF5340 QSPI driver.
Browse files Browse the repository at this point in the history
  • Loading branch information
dgarske committed Sep 3, 2024
1 parent bc1a282 commit c5f3d29
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 43 deletions.
1 change: 1 addition & 0 deletions .gdbinit
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
tar rem:3333
file wolfboot.elf
add-symbol-file test-app/image.elf
set pagination off
foc c


10 changes: 10 additions & 0 deletions hal/nrf5340.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ static void clock_init(void)
while (CLOCK_HFCLKSTARTED == 0);
}

/* CPU is running at 128MHz so 128 NOP's = 1us */
void sleep_us(unsigned int us)
{
unsigned int nop_us = (CPU_CLOCK / 1000000);
us *= nop_us;
while (us-- > 0) {
NOP();
}
}

void hal_init(void)
{
clock_init();
Expand Down
47 changes: 36 additions & 11 deletions hal/nrf5340.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@
#ifndef _HAL_NRF5340_H_
#define _HAL_NRF5340_H_

#define CPU_CLOCK 128000000UL /* 128MHz */

/* Assembly helpers */
#define DMB() __asm__ volatile ("dmb")
#define NOP() __asm__ volatile ("nop")

void sleep_us(unsigned int us);

/* PSEL Port (bit 5) - Used for various PSEL (UART,SPI,QSPI,I2C,NFC) */
#define PSEL_PORT(n) (((n) & 0x1) << 5)

Expand All @@ -47,19 +51,30 @@

/* Clock control */
#ifdef TZEN
#define CLOCK_BASE_APP (0x50005000)
#define CLOCK_BASE_APP (0x50005000)
#else
#define CLOCK_BASE_APP (0x40005000)
#define CLOCK_BASE_APP (0x40005000)
#endif
#define CLOCK_BASE_NET (0x41005000) /* network core */
#define CLOCK_HFCLKSTART *((volatile uint32_t *)(CLOCK_BASE_APP + 0x000))
#define CLOCK_HFCLKSTOP *((volatile uint32_t *)(CLOCK_BASE_APP + 0x004))
#define CLOCK_HFCLKSTARTED *((volatile uint32_t *)(CLOCK_BASE_APP + 0x100))
#define CLOCK_HFCLKSTAT *((volatile uint32_t *)(CLOCK_BASE_APP + 0x40C))
#define CLOCK_HFCLKSRC *((volatile uint32_t *)(CLOCK_BASE_APP + 0x514))

#define CLOCK_BASE_NET (0x41005000) /* network core */
#define CLOCK_HFCLKSTART *((volatile uint32_t *)(CLOCK_BASE_APP + 0x000))
#define CLOCK_HFCLKSTOP *((volatile uint32_t *)(CLOCK_BASE_APP + 0x004))
#define CLOCK_HFCLKSTARTED *((volatile uint32_t *)(CLOCK_BASE_APP + 0x100))
#define CLOCK_HFCLKSTAT *((volatile uint32_t *)(CLOCK_BASE_APP + 0x40C))
#define CLOCK_HFCLKSRC *((volatile uint32_t *)(CLOCK_BASE_APP + 0x514))
#define CLOCK_HFCLKSRC_HFXO 1

/* Used by QSPI */
#define CLOCK_HFCLK192MSTART *((volatile uint32_t *)(CLOCK_BASE_APP + 0x020))
#define CLOCK_HFCLK192MSTARTED *((volatile uint32_t *)(CLOCK_BASE_APP + 0x124))
#define CLOCK_HFCLK192MSRC *((volatile uint32_t *)(CLOCK_BASE_APP + 0x580))
#define CLOCK_HFCLK192MSRC_HFXO 1
#define CLOCK_HFCLK192MCTRL *((volatile uint32_t *)(CLOCK_BASE_APP + 0x5B8))
#define CLOCK_HFCLK192MCTRL_DIV1 0
#define CLOCK_HFCLK192MCTRL_DIV2 1
#define CLOCK_HFCLK192MCTRL_DIV4 2



/* GPIO Port (0-1) */
#ifdef TZEN
#define GPIO_BASE_APP(n) (0x50842500 + (((n) & 0x1) * 0x300))
Expand Down Expand Up @@ -139,7 +154,6 @@ void uart_write_sz(const char* c, unsigned int sz);
#define SPI_FREQ_M32 0x14000000

/* QSPI */
#define QSPI_CLK 96000000
#ifdef TZEN
#define QSPI_BASE (0x5002B000)
#else
Expand All @@ -151,6 +165,11 @@ void uart_write_sz(const char* c, unsigned int sz);
#define QSPI_TASKS_ERASESTART *((volatile uint32_t *)(QSPI_BASE + 0x00C))
#define QSPI_TASKS_DEACTIVATE *((volatile uint32_t *)(QSPI_BASE + 0x010))
#define QSPI_EVENTS_READY *((volatile uint32_t *)(QSPI_BASE + 0x100))

#define QSPI_INTEN *((volatile uint32_t *)(QSPI_BASE + 0x300))
#define QSPI_INTENSET *((volatile uint32_t *)(QSPI_BASE + 0x304))
#define QSPI_INTENCLR *((volatile uint32_t *)(QSPI_BASE + 0x308))

#define QSPI_ENABLE *((volatile uint32_t *)(QSPI_BASE + 0x500))

#define QSPI_READ_SRC *((volatile uint32_t *)(QSPI_BASE + 0x504))
Expand Down Expand Up @@ -179,11 +198,13 @@ void uart_write_sz(const char* c, unsigned int sz);
#define QSPI_CINSTRDAT1 *((volatile uint32_t *)(QSPI_BASE + 0x63C))
#define QSPI_IFTIMING *((volatile uint32_t *)(QSPI_BASE + 0x640))

#define QSPI_IFCONFIG0_READOC_MASK 0x7
#define QSPI_IFCONFIG0_READOC_FASTREAD (0) /* opcode 0x0B */
#define QSPI_IFCONFIG0_READOC_READ2O (1) /* opcode 0x3B */
#define QSPI_IFCONFIG0_READOC_READ2IO (2) /* opcode 0xBB */
#define QSPI_IFCONFIG0_READOC_READ4O (3) /* opcode 0x6B */
#define QSPI_IFCONFIG0_READOC_READ4IO (4) /* opcode 0xEB */
#define QSPI_IFCONFIG0_WRITEOC_MASK ((0x7) << 3)
#define QSPI_IFCONFIG0_WRITEOC_PP ((0) << 3) /* opcode 0x02 */
#define QSPI_IFCONFIG0_WRITEOC_PP2O ((1) << 3) /* opcode 0xA2 */
#define QSPI_IFCONFIG0_WRITEOC_PP4O ((2) << 3) /* opcode 0x32 */
Expand All @@ -194,13 +215,17 @@ void uart_write_sz(const char* c, unsigned int sz);
#define QSPI_IFCONFIG0_PPSIZE_256 ((0) << 12)
#define QSPI_IFCONFIG0_PPSIZE_512 ((1) << 12)

#define QSPI_IFCONFIG1_SCKDEKLAY(n) ((n) & 0xFF)
#define QSPI_IFCONFIG1_SCKDEKLAY_MASK 0xFF
#define QSPI_IFCONFIG1_SCKDEKLAY(n) ((n) & QSPI_IFCONFIG1_SCKDEKLAY_MASK)
#define QSPI_IFCONFIG1_SPIMODE0 0
#define QSPI_IFCONFIG1_SPIMODE3 (1UL << 25)
#define QSPI_IFCONFIG1_SCKFREQ_MASK ((0xF) << 28)
#define QSPI_IFCONFIG1_SCKFREQ(n) (((n) & 0xF) << 28)

#define QSPI_CINSTRCONF_OPCODE(n) ((n) & 0xFF)
#define QSPI_CINSTRCONF_LENGTH(n) (((n) & 0xF) << 8)
#define QSPI_CINSTRCONF_LIO2 (1 << 12)
#define QSPI_CINSTRCONF_LIO3 (1 << 13)
#define QSPI_CINSTRCONF_WREN (1 << 15) /* send WREN opcode 0x6 before */


Expand Down
117 changes: 95 additions & 22 deletions hal/spi/spi_drv_nrf5340.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "spi_drv.h"
#include "spi_flash.h"
#include "string.h"
#include "printf.h"

#ifdef TARGET_nrf5340

Expand Down Expand Up @@ -70,26 +71,44 @@ void spi_write(const char byte)
#endif

#ifdef QSPI_FLASH

void qspi_wait_ready(void)
{
int timeout = 1000000;
while (QSPI_EVENTS_READY == 0 && --timeout > 0) {
NOP();
}
if (timeout == 0) {
#ifdef DEBUG_QSPI
wolfBoot_printf("QSPI Wait timeout!\n");
#endif
}
}

int qspi_transfer(uint8_t fmode, const uint8_t cmd,
uint32_t addr, uint32_t addrSz, uint32_t addrMode,
uint32_t alt, uint32_t altSz, uint32_t altMode,
uint32_t dummySz,
uint8_t* data, uint32_t dataSz, uint32_t dataMode)
{
/* command only operation */
if (addrSz == 0) {
uint32_t reg[2] = {0, 0};
if (dataSz > sizeof(reg))
dataSz = sizeof(reg);
uint32_t cintData[2] = {0, 0};

QSPI_EVENTS_READY = 0; /* clear events */

if (addrSz == 0) { /* command only operation */
if (dataSz > sizeof(cintData))
dataSz = sizeof(cintData);
if (fmode == QSPI_MODE_WRITE) {
memcpy(reg, data, dataSz);
memcpy(cintData, data, dataSz);
if (dataSz >= 4)
QSPI_CINSTRDAT1 = cintData[1];
if (dataSz > 0)
QSPI_CINSTRDAT0 = cintData[0];
}
QSPI_CINSTRDAT0 = reg[0];
QSPI_CINSTRDAT1 = reg[1];
QSPI_CINSTRCONF = (
QSPI_CINSTRCONF_OPCODE(cmd) |
QSPI_CINSTRCONF_LENGTH(1 + dataSz)
QSPI_CINSTRCONF_LENGTH(1 + dataSz) |
QSPI_CINSTRCONF_LIO3 /* IO3 high (not reset) */
);
}
else if (fmode == QSPI_MODE_WRITE && dataSz == 0) { /* erase */
Expand All @@ -112,7 +131,14 @@ int qspi_transfer(uint8_t fmode, const uint8_t cmd,
}

/* wait for generated ready event */
while (QSPI_EVENTS_READY == 0);
qspi_wait_ready();

/* command only read */
if (addrSz == 0 && fmode == QSPI_MODE_READ) {
cintData[1] = QSPI_CINSTRDAT1;
cintData[0] = QSPI_CINSTRDAT0;
memcpy(data, cintData, dataSz);
}

return 0;
}
Expand Down Expand Up @@ -141,48 +167,95 @@ void spi_init(int polarity, int phase)
SPI_CONFIG(SPI_PORT) = 0; /* mode 0,0 default */
SPI_ENABLE(SPI_PORT) = 1;
(void)reg;
#endif
#endif /* SPI_FLASH || WOLFBOOT_TPM */

#ifdef QSPI_FLASH
/* issue hard reset to chip by driving IO3 low */
GPIO_PIN_CNF(QSPI_IO3_PORT, QSPI_IO3_PIN) = GPIO_CNF_OUT;
GPIO_OUTSET(QSPI_IO3_PORT) &= ~(1 << QSPI_IO3_PIN);
while ((GPIO_OUT(QSPI_IO3_PORT) & (1 << QSPI_IO3_PIN)) != 0);
/* must hold for 10us */
sleep_us(10);
GPIO_OUTSET(QSPI_IO3_PORT) |= (1 << QSPI_IO3_PIN);
while ((GPIO_OUT(QSPI_IO3_PORT) & (1 << QSPI_IO3_PIN)) == 0);

/* Enable QSPI Clock */
CLOCK_HFCLK192MSRC = 0; /* internal osc */
CLOCK_HFCLK192MCTRL = QSPI_CLK_DIV;
CLOCK_HFCLK192MSTART = 1;
while (CLOCK_HFCLK192MSTARTED == 0);

/* Configure QSPI Pins */
QSPI_PSEL_SCK = PSEL_PORT(QSPI_CLK_PORT) | QSPI_CLK_PIN;
QSPI_PSEL_SCK = PSEL_PORT(QSPI_CS_PORT) | QSPI_CS_PIN;
QSPI_PSEL_SCK = PSEL_PORT(QSPI_IO0_PORT) | QSPI_IO0_PIN;
QSPI_PSEL_SCK = PSEL_PORT(QSPI_IO1_PORT) | QSPI_IO1_PIN;
QSPI_PSEL_SCK = PSEL_PORT(QSPI_IO2_PORT) | QSPI_IO2_PIN;
QSPI_PSEL_SCK = PSEL_PORT(QSPI_IO3_PORT) | QSPI_IO3_PIN;
QSPI_PSEL_CSN = PSEL_PORT(QSPI_CS_PORT) | QSPI_CS_PIN;
QSPI_PSEL_IO0 = PSEL_PORT(QSPI_IO0_PORT) | QSPI_IO0_PIN;
QSPI_PSEL_IO1 = PSEL_PORT(QSPI_IO1_PORT) | QSPI_IO1_PIN;
QSPI_PSEL_IO2 = PSEL_PORT(QSPI_IO2_PORT) | QSPI_IO2_PIN;
QSPI_PSEL_IO3 = PSEL_PORT(QSPI_IO3_PORT) | QSPI_IO3_PIN;

/* Configure all pins for GPIO input */
GPIO_PIN_CNF(QSPI_CLK_PORT, QSPI_CLK_PIN) = GPIO_CNF_HIGH_DRIVE;
GPIO_PIN_CNF(QSPI_CS_PORT, QSPI_CS_PIN) = GPIO_CNF_HIGH_DRIVE;
GPIO_PIN_CNF(QSPI_CS_PORT, QSPI_CS_PIN) = GPIO_CNF_HIGH_DRIVE;
GPIO_PIN_CNF(QSPI_IO0_PORT, QSPI_IO0_PIN) = GPIO_CNF_HIGH_DRIVE;
GPIO_PIN_CNF(QSPI_IO1_PORT, QSPI_IO1_PIN) = GPIO_CNF_HIGH_DRIVE;
GPIO_PIN_CNF(QSPI_IO2_PORT, QSPI_IO2_PIN) = GPIO_CNF_HIGH_DRIVE;
GPIO_PIN_CNF(QSPI_IO3_PORT, QSPI_IO3_PIN) = GPIO_CNF_HIGH_DRIVE;

reg = QSPI_IFCONFIG0;
reg &= ~(QSPI_IFCONFIG0_READOC_MASK | QSPI_IFCONFIG0_WRITEOC_MASK);
#if QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI
reg = QSPI_IFCONFIG0_READOC_READ4O | QSPI_IFCONFIG0_WRITEOC_PP4O;
reg |= QSPI_IFCONFIG0_READOC_READ4O | QSPI_IFCONFIG0_WRITEOC_PP4O;
#elif QSPI_DATA_MODE == QSPI_DATA_MODE_DSPI
reg = QSPI_IFCONFIG0_READOC_READ2O | QSPI_IFCONFIG0_WRITEOC_PP2O;
reg |= QSPI_IFCONFIG0_READOC_READ2O | QSPI_IFCONFIG0_WRITEOC_PP2O;
#else
reg = QSPI_IFCONFIG0_READOC_FASTREAD | QSPI_IFCONFIG0_WRITEOC_PP;
reg |= QSPI_IFCONFIG0_READOC_FASTREAD | QSPI_IFCONFIG0_WRITEOC_PP;
#endif
#if QSPI_ADDR_MODE == 4
reg |= QSPI_IFCONFIG0_ADDRMODE_32BIT;
#else
reg &= ~QSPI_IFCONFIG0_ADDRMODE_32BIT;
#endif
#if SPI_FLASH_PAGE_SIZE == 512
reg |= QSPI_IFCONFIG0_PPSIZE_512;
#else
reg &= ~QSPI_IFCONFIG0_PPSIZE_512;
#endif
QSPI_IFCONFIG0 = reg;

reg = QSPI_IFCONFIG1_SCKDEKLAY(128);
#if 1 /* errata 121 */
QSPI_IFTIMING = 6; /* RXDELAY=6 */
reg = QSPI_IFCONFIG0;
#if QSPI_CLOCK_MHZ >= 6000000 && QSPI_CLOCK_MHZ <= 48000000
reg &= ~(1 << 17);
reg |= (1 << 16);
#elif QSPI_CLOCK_MHZ == 96000000
reg |= (1 << 16) | (1<<17);
#endif
QSPI_IFCONFIG0 = reg;
#endif /* errata 121 */

reg = QSPI_IFCONFIG1;
reg &= ~QSPI_IFCONFIG1_SCKDEKLAY_MASK;
reg |= QSPI_IFCONFIG1_SCKDEKLAY(5);
/* SCK = 96MHz / (SCKFREQ + 1) */
reg &= ~QSPI_IFCONFIG1_SCKFREQ_MASK;
reg |= QSPI_IFCONFIG1_SCKFREQ((QSPI_CLK / QSPI_CLOCK_MHZ) - 1);
if (polarity != 0 && phase != 0)
reg |= QSPI_IFCONFIG1_SPIMODE3;
else
reg &= ~QSPI_IFCONFIG1_SPIMODE3;
QSPI_IFCONFIG1 = reg;

QSPI_ENABLE = 1;
#endif

/* make sure interrupts are disabled */
QSPI_INTENCLR = 1; /* write "1" to disable READY interrupt */

/* Activate QSPI */
QSPI_EVENTS_READY = 0; /* clear events */
QSPI_TASKS_ACTIVATE = 1;
qspi_wait_ready();
#endif /* QSPI_FLASH */
}
(void)polarity;
(void)phase;
Expand Down
11 changes: 11 additions & 0 deletions hal/spi/spi_drv_nrf5340.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,15 @@
#define QSPI_CLOCK_MHZ 16000000
#endif

/* MX25R6435F */
#define QSPI_NO_SR2

#if QSPI_CLOCK_MHZ <= 48000000
#define QSPI_CLK_DIV CLOCK_HFCLK192MCTRL_DIV4
#define QSPI_CLK 48000000
#else
#define QSPI_CLK_DIV CLOCK_HFCLK192MCTRL_DIV2
#define QSPI_CLK 96000000
#endif

#endif /* !SPI_DRV_NRF53_H_INCLUDED */
4 changes: 4 additions & 0 deletions include/spi_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ int qspi_transfer(uint8_t fmode, const uint8_t cmd,
uint32_t dummySz,
uint8_t* data, uint32_t dataSz, uint32_t dataMode
);

#if !defined(DEBUG_QSPI) && defined(DEBUG_UART)
#define DEBUG_QSPI 1
#endif
#endif /* QSPI_FLASH || OCTOSPI_FLASH */

#ifndef SPI_CS_FLASH
Expand Down
Loading

0 comments on commit c5f3d29

Please sign in to comment.