flash/nor: add DesignWare SPI controller driver
Driver for DesignWare SPI controller, found on many SoCs (see compatible list in Linux device tree bindings Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml). This implementation only supports MIPS as it was the only one available for the tests, however, adding support for other architectures should require only few adjustments. Driver relies on flash/nor/spi.h to find Flash chip info. Driver internal functions support 24bit addressing mode, but due to limitations of flash/nor/spi.h, it is not used. The reported writing speed is about 60kb/s. Lint, sanitizer and valgrind reported warnings were not related to the driver. Change-Id: Id3df5626ab88055f034f74f274823051dedefeb1 Signed-off-by: Sergey Matsievskiy <matsievskiysv@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/8400 Tested-by: jenkins Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
parent
ce38758e3d
commit
eb6f2745b7
|
@ -0,0 +1,35 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
TOOLCHAIN:=mipsel-linux-gnu-
|
||||||
|
CC:=$(TOOLCHAIN)gcc
|
||||||
|
OBJCOPY:=$(TOOLCHAIN)objcopy
|
||||||
|
CFLAGS:=-O2 -Wall -Wextra -fpic -Wno-int-to-pointer-cast
|
||||||
|
SRC=dw-spi.c
|
||||||
|
OBJ=$(patsubst %.c, %.o,$(SRC))
|
||||||
|
|
||||||
|
# sparx-iv
|
||||||
|
ifeq ($(TOOLCHAIN),mipsel-linux-gnu-)
|
||||||
|
CFLAGS+= -march=24kec
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: \
|
||||||
|
$(TOOLCHAIN)transaction.inc \
|
||||||
|
$(TOOLCHAIN)erase.inc \
|
||||||
|
$(TOOLCHAIN)check_fill.inc \
|
||||||
|
$(TOOLCHAIN)program.inc \
|
||||||
|
$(TOOLCHAIN)read.inc
|
||||||
|
|
||||||
|
$(TOOLCHAIN)%.bin: $(OBJ)
|
||||||
|
$(OBJCOPY) --dump-section .$*=$@ $<
|
||||||
|
|
||||||
|
%.inc: %.bin
|
||||||
|
xxd -i > $@ < $<
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf .ccls-cache
|
||||||
|
find . \( \
|
||||||
|
-iname "*.o" \
|
||||||
|
-o -iname "*.bin" \
|
||||||
|
-o -iname "*.inc" \
|
||||||
|
\) -delete
|
|
@ -0,0 +1,246 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Helper functions for DesignWare SPI Core driver.
|
||||||
|
* These helpers are loaded into CPU and execute Flash manipulation algorithms
|
||||||
|
* at full CPU speed. Due to inability to control nCS pin, this is the only way
|
||||||
|
* to communicate with Flash chips connected via DW SPI serial interface.
|
||||||
|
*
|
||||||
|
* In order to avoid using stack, all functions used in helpers are inlined.
|
||||||
|
* Software breakpoints are used to terminate helpers.
|
||||||
|
*
|
||||||
|
* Pushing byte to TX FIFO does not make byte immediately available in RX FIFO
|
||||||
|
* and nCS is only asserted when TX FIFO is not empty. General approach is to
|
||||||
|
* fill TX FIFO with as many bytes as possible, at the same time reading
|
||||||
|
* available bytes from RX FIFO.
|
||||||
|
*
|
||||||
|
* This file contains helper functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dw-spi.h"
|
||||||
|
|
||||||
|
#include "../../../../src/flash/nor/dw-spi-helper.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generic flash transaction.
|
||||||
|
*
|
||||||
|
* @param[in] arg: Function arguments.
|
||||||
|
*/
|
||||||
|
__attribute__((section(".transaction"))) void
|
||||||
|
transaction(struct dw_spi_transaction *arg)
|
||||||
|
{
|
||||||
|
register uint8_t *buffer_tx = (uint8_t *)arg->buffer;
|
||||||
|
register uint8_t *buffer_rx = buffer_tx;
|
||||||
|
register uint32_t size = arg->size;
|
||||||
|
register volatile uint8_t *status = (uint8_t *)arg->status_reg;
|
||||||
|
register volatile uint8_t *data = (uint8_t *)arg->data_reg;
|
||||||
|
|
||||||
|
wait_tx_finish(status);
|
||||||
|
flush_rx(status, data);
|
||||||
|
|
||||||
|
for (; size > 0; size--) {
|
||||||
|
send_u8(status, data, *buffer_tx++);
|
||||||
|
if (arg->read_flag && rx_available(status))
|
||||||
|
*buffer_rx++ = rcv_byte(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pushed all data to TX FIFO. Read bytes left in RX FIFO.
|
||||||
|
if (arg->read_flag) {
|
||||||
|
while (buffer_rx < buffer_tx) {
|
||||||
|
wait_rx_available(status);
|
||||||
|
*buffer_rx++ = rcv_byte(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check flash sectors are filled with pattern. Primary use for
|
||||||
|
* checking sector erase state.
|
||||||
|
*
|
||||||
|
* @param[in] arg: Function arguments.
|
||||||
|
*/
|
||||||
|
__attribute__((section(".check_fill"))) void
|
||||||
|
check_fill(struct dw_spi_check_fill *arg)
|
||||||
|
{
|
||||||
|
register uint32_t tx_size;
|
||||||
|
register uint32_t rx_size;
|
||||||
|
register uint32_t dummy_count;
|
||||||
|
register uint8_t filled;
|
||||||
|
register uint8_t *fill_status_array = (uint8_t *)arg->fill_status_array;
|
||||||
|
register volatile uint8_t *status = (uint8_t *)arg->status_reg;
|
||||||
|
register volatile uint8_t *data = (uint8_t *)arg->data_reg;
|
||||||
|
|
||||||
|
for (; arg->sector_count > 0; arg->sector_count--,
|
||||||
|
arg->address += arg->sector_size,
|
||||||
|
fill_status_array++) {
|
||||||
|
wait_tx_finish(status);
|
||||||
|
flush_rx(status, data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command byte and address bytes make up for dummy_count number of
|
||||||
|
* bytes, that must be skipped in RX FIFO before actual data arrives.
|
||||||
|
*/
|
||||||
|
send_u8(status, data, arg->read_cmd);
|
||||||
|
if (arg->four_byte_mode) {
|
||||||
|
dummy_count = 1 + 4; // Command byte + 4 address bytes
|
||||||
|
send_u32(status, data, arg->address);
|
||||||
|
} else {
|
||||||
|
dummy_count = 1 + 3; // Command byte + 3 address bytes
|
||||||
|
send_u24(status, data, arg->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (tx_size = arg->sector_size, rx_size = arg->sector_size, filled = 1;
|
||||||
|
tx_size > 0; tx_size--) {
|
||||||
|
send_u8(status, data, 0); // Dummy write to push out read data.
|
||||||
|
if (rx_available(status)) {
|
||||||
|
if (dummy_count > 0) {
|
||||||
|
// Read data not arrived yet.
|
||||||
|
rcv_byte(data);
|
||||||
|
dummy_count--;
|
||||||
|
} else {
|
||||||
|
if (rcv_byte(data) != arg->pattern) {
|
||||||
|
filled = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rx_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filled) {
|
||||||
|
for (; rx_size > 0; rx_size--) {
|
||||||
|
wait_rx_available(status);
|
||||||
|
if (rcv_byte(data) != arg->pattern) {
|
||||||
|
filled = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*fill_status_array = filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erase flash sectors.
|
||||||
|
*
|
||||||
|
* @param[in] arg: Function arguments.
|
||||||
|
*/
|
||||||
|
__attribute__((section(".erase"))) void
|
||||||
|
erase(struct dw_spi_erase *arg)
|
||||||
|
{
|
||||||
|
register uint32_t address = arg->address;
|
||||||
|
register uint32_t count = arg->sector_count;
|
||||||
|
register volatile uint8_t *status = (uint8_t *)arg->status_reg;
|
||||||
|
register volatile uint8_t *data = (uint8_t *)arg->data_reg;
|
||||||
|
|
||||||
|
for (; count > 0; count--, address += arg->sector_size) {
|
||||||
|
write_enable(status, data, arg->write_enable_cmd);
|
||||||
|
wait_write_enable(status, data, arg->read_status_cmd,
|
||||||
|
arg->write_enable_mask);
|
||||||
|
|
||||||
|
erase_sector(status, data, arg->erase_sector_cmd, address,
|
||||||
|
arg->four_byte_mode);
|
||||||
|
wait_busy(status, data, arg->read_status_cmd, arg->busy_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flash program.
|
||||||
|
*
|
||||||
|
* @param[in] arg: Function arguments.
|
||||||
|
*/
|
||||||
|
__attribute__((section(".program"))) void
|
||||||
|
program(struct dw_spi_program *arg)
|
||||||
|
{
|
||||||
|
register uint8_t *buffer = (uint8_t *)arg->buffer;
|
||||||
|
register uint32_t buffer_size = arg->buffer_size;
|
||||||
|
register volatile uint8_t *status = (uint8_t *)arg->status_reg;
|
||||||
|
register volatile uint8_t *data = (uint8_t *)arg->data_reg;
|
||||||
|
register uint32_t page_size;
|
||||||
|
|
||||||
|
while (buffer_size > 0) {
|
||||||
|
write_enable(status, data, arg->write_enable_cmd);
|
||||||
|
wait_write_enable(status, data, arg->read_status_cmd,
|
||||||
|
arg->write_enable_mask);
|
||||||
|
|
||||||
|
wait_tx_finish(status);
|
||||||
|
|
||||||
|
send_u8(status, data, arg->program_cmd);
|
||||||
|
if (arg->four_byte_mode)
|
||||||
|
send_u32(status, data, arg->address);
|
||||||
|
else
|
||||||
|
send_u24(status, data, arg->address);
|
||||||
|
|
||||||
|
for (page_size = MIN(arg->page_size, buffer_size); page_size > 0;
|
||||||
|
page_size--, buffer_size--) {
|
||||||
|
send_u8(status, data, *buffer++);
|
||||||
|
}
|
||||||
|
arg->address += arg->page_size;
|
||||||
|
wait_busy(status, data, arg->read_status_cmd, arg->busy_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from flash.
|
||||||
|
*
|
||||||
|
* @param[in] arg: Function arguments.
|
||||||
|
*/
|
||||||
|
__attribute__((section(".read"))) void
|
||||||
|
read(struct dw_spi_read *arg)
|
||||||
|
{
|
||||||
|
register uint32_t tx_size = arg->buffer_size;
|
||||||
|
register uint32_t rx_size = arg->buffer_size;
|
||||||
|
register uint32_t dummy_count;
|
||||||
|
register uint8_t *buffer = (uint8_t *)arg->buffer;
|
||||||
|
register volatile uint8_t *status = (uint8_t *)arg->status_reg;
|
||||||
|
register volatile uint8_t *data = (uint8_t *)arg->data_reg;
|
||||||
|
|
||||||
|
wait_tx_finish(status);
|
||||||
|
flush_rx(status, data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command byte and address bytes make up for dummy_count number of
|
||||||
|
* bytes, that must be skipped in RX FIFO before actual data arrives.
|
||||||
|
*/
|
||||||
|
send_u8(status, data, arg->read_cmd);
|
||||||
|
if (arg->four_byte_mode) {
|
||||||
|
dummy_count = 1 + 4; // Command byte + 4 address bytes
|
||||||
|
send_u32(status, data, arg->address);
|
||||||
|
} else {
|
||||||
|
dummy_count = 1 + 3; // Command byte + 3 address bytes
|
||||||
|
send_u24(status, data, arg->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; tx_size > 0; tx_size--) {
|
||||||
|
send_u8(status, data, 0); // Dummy write to push out read data.
|
||||||
|
if (rx_available(status)) {
|
||||||
|
if (dummy_count > 0) {
|
||||||
|
rcv_byte(data);
|
||||||
|
dummy_count--;
|
||||||
|
} else {
|
||||||
|
*buffer++ = rcv_byte(data);
|
||||||
|
rx_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (rx_size > 0) {
|
||||||
|
wait_rx_available(status);
|
||||||
|
if (dummy_count > 0) {
|
||||||
|
// Read data not arrived yet.
|
||||||
|
rcv_byte(data);
|
||||||
|
dummy_count--;
|
||||||
|
} else {
|
||||||
|
*buffer++ = rcv_byte(data);
|
||||||
|
rx_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
}
|
|
@ -0,0 +1,313 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Helper functions for DesignWare SPI Core driver.
|
||||||
|
* These helpers are loaded into CPU and execute Flash manipulation algorithms
|
||||||
|
* at full CPU speed. Due to inability to control nCS pin, this is the only way
|
||||||
|
* to communicate with Flash chips connected via DW SPI serial interface.
|
||||||
|
*
|
||||||
|
* In order to avoid using stack, all functions used in helpers are inlined.
|
||||||
|
* Software breakpoints are used to terminate helpers.
|
||||||
|
*
|
||||||
|
* This file contains functions, common to helpers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DW_SPI_H_
|
||||||
|
#define _DW_SPI_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include "../../../../src/helper/types.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SI busy status bit.
|
||||||
|
*
|
||||||
|
* Set when serial transfer is in progress, cleared when master is idle or
|
||||||
|
* disabled.
|
||||||
|
*/
|
||||||
|
#define DW_SPI_STATUS_BUSY 0x01
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SI TX FIFO not full status bit.
|
||||||
|
*
|
||||||
|
* Set when TX FIFO has room for one or more data-word.
|
||||||
|
*/
|
||||||
|
#define DW_SPI_STATUS_TFNF 0x02
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SI TX FIFO empty status bit.
|
||||||
|
*/
|
||||||
|
#define DW_SPI_STATUS_TFE 0x04
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SI RX FIFO not empty status bit.
|
||||||
|
*/
|
||||||
|
#define DW_SPI_STATUS_RFNE 0x08
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return from helper function.
|
||||||
|
*/
|
||||||
|
#define RETURN \
|
||||||
|
do { \
|
||||||
|
asm("sdbbp\n\t"); \
|
||||||
|
return; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append byte to TX FIFO.
|
||||||
|
*
|
||||||
|
* For each transferred byte, DW SPI controller receives a byte into RX FIFO.
|
||||||
|
* Slave data are read by pushing dummy bytes to TX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] byte: Data to push.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
_send_byte(volatile uint8_t *dr, uint8_t byte)
|
||||||
|
{
|
||||||
|
*dr = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get byte from RX FIFO.
|
||||||
|
*
|
||||||
|
* Reading RX byte removes it from RX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @return RX FIFO byte.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline uint8_t
|
||||||
|
rcv_byte(volatile uint8_t *dr)
|
||||||
|
{
|
||||||
|
return *dr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check transmission is currently in progress.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @retval 1: Transmission is in progress.
|
||||||
|
* @retval 0: Controller is idle or off.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline int
|
||||||
|
tx_in_progress(volatile uint8_t *sr)
|
||||||
|
{
|
||||||
|
return (*sr ^ DW_SPI_STATUS_TFE) & (DW_SPI_STATUS_BUSY | DW_SPI_STATUS_TFE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for controller to finish previous transaction.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
wait_tx_finish(volatile uint8_t *sr)
|
||||||
|
{
|
||||||
|
while (tx_in_progress(sr))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for room in TX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
wait_tx_available(volatile uint8_t *sr)
|
||||||
|
{
|
||||||
|
while (!(*sr & DW_SPI_STATUS_TFNF))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check for data available in RX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @retval 1: Data available.
|
||||||
|
* @retval 0: No data available.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline int
|
||||||
|
rx_available(volatile uint8_t *sr)
|
||||||
|
{
|
||||||
|
return *sr & DW_SPI_STATUS_RFNE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for data in RX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
wait_rx_available(volatile uint8_t *sr)
|
||||||
|
{
|
||||||
|
while (!rx_available(sr))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flush RX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
flush_rx(volatile uint8_t *sr, volatile uint8_t *dr)
|
||||||
|
{
|
||||||
|
while (*sr & DW_SPI_STATUS_RFNE)
|
||||||
|
*dr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append variable number of bytes to TX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] word: Data to append.
|
||||||
|
* @param[in] bytes: Number of bytes to append.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
_send_bytes(volatile uint8_t *sr, volatile uint8_t *dr, uint32_t word,
|
||||||
|
int bytes)
|
||||||
|
{
|
||||||
|
for (register int i = bytes - 1; i >= 0; i--) {
|
||||||
|
wait_tx_available(sr);
|
||||||
|
_send_byte(dr, (word >> (i * 8)) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append 8 bit value to TX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] word: Data to push.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
send_u8(volatile uint8_t *sr, volatile uint8_t *dr, uint8_t byte)
|
||||||
|
{
|
||||||
|
wait_tx_available(sr);
|
||||||
|
_send_byte(dr, byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append 24 bit value to TX FIFO.
|
||||||
|
*
|
||||||
|
* Used to send Flash addresses in 24 bit mode.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] word: Data to push.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
send_u24(volatile uint8_t *sr, volatile uint8_t *dr, uint32_t word)
|
||||||
|
{
|
||||||
|
_send_bytes(sr, dr, word, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Append 32 bit value to TX FIFO.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] word: Data to push.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
send_u32(volatile uint8_t *sr, volatile uint8_t *dr, uint32_t word)
|
||||||
|
{
|
||||||
|
_send_bytes(sr, dr, word, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read chip status register.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] stat_cmd: Read status command.
|
||||||
|
* @return Chip status.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline uint8_t
|
||||||
|
read_status(volatile uint8_t *sr, volatile uint8_t *dr, uint8_t stat_cmd)
|
||||||
|
{
|
||||||
|
wait_tx_finish(sr);
|
||||||
|
flush_rx(sr, dr);
|
||||||
|
/*
|
||||||
|
* Don't bother with wait_tx_available() as TX FIFO is empty
|
||||||
|
* and we only send two bytes.
|
||||||
|
*/
|
||||||
|
_send_byte(dr, stat_cmd);
|
||||||
|
_send_byte(dr, 0); // Dummy write to push out read data.
|
||||||
|
wait_rx_available(sr);
|
||||||
|
rcv_byte(dr); // Dummy read to skip command byte.
|
||||||
|
wait_rx_available(sr);
|
||||||
|
return rcv_byte(dr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable Flash chip write.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] we_cmd: Write enable command.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
write_enable(volatile uint8_t *sr, volatile uint8_t *dr, uint8_t we_cmd)
|
||||||
|
{
|
||||||
|
wait_tx_finish(sr);
|
||||||
|
_send_byte(dr, we_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erase Flash sector.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] erase_cmd: Erase sector cmd.
|
||||||
|
* @param[in] address: Sector address.
|
||||||
|
* @param[in] four_byte_mode: Device is in 32 bit mode flag.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
erase_sector(volatile uint8_t *sr, volatile uint8_t *dr, uint8_t erase_cmd,
|
||||||
|
uint32_t address, uint8_t four_byte_mode)
|
||||||
|
{
|
||||||
|
wait_tx_finish(sr);
|
||||||
|
_send_byte(dr, erase_cmd);
|
||||||
|
if (four_byte_mode)
|
||||||
|
send_u32(sr, dr, address);
|
||||||
|
else
|
||||||
|
send_u24(sr, dr, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for write enable flag.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] stat_cmd: Read status command.
|
||||||
|
* @param[in] we_mask: Write enable status mask.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
wait_write_enable(volatile uint8_t *sr, volatile uint8_t *dr, uint8_t stat_cmd,
|
||||||
|
uint8_t we_mask)
|
||||||
|
{
|
||||||
|
while (!(read_status(sr, dr, stat_cmd) & we_mask))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait while flash is busy.
|
||||||
|
*
|
||||||
|
* @param[in] sr: Pointer to SR register.
|
||||||
|
* @param[in] dr: Pointer to DR register.
|
||||||
|
* @param[in] stat_cmd: Read status command.
|
||||||
|
* @param[in] busy_mask: Flash busy mask.
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline)) static inline void
|
||||||
|
wait_busy(volatile uint8_t *sr, volatile uint8_t *dr, uint8_t stat_cmd,
|
||||||
|
uint8_t busy_mask)
|
||||||
|
{
|
||||||
|
while (read_status(sr, dr, stat_cmd) & busy_mask)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _DW_SPI_H_
|
|
@ -0,0 +1,39 @@
|
||||||
|
0x0b, 0x00, 0x82, 0x88, 0x1f, 0x00, 0x8a, 0x88, 0x0f, 0x00, 0x83, 0x88,
|
||||||
|
0x17, 0x00, 0x86, 0x88, 0x08, 0x00, 0x82, 0x98, 0x1c, 0x00, 0x8a, 0x98,
|
||||||
|
0x0c, 0x00, 0x83, 0x98, 0x14, 0x00, 0x86, 0x98, 0x25, 0x38, 0x80, 0x00,
|
||||||
|
0x54, 0x00, 0x40, 0x10, 0xf8, 0xff, 0x09, 0x24, 0x00, 0x00, 0x64, 0x90,
|
||||||
|
0x05, 0x00, 0x84, 0x30, 0x04, 0x00, 0x84, 0x38, 0xfc, 0xff, 0x80, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30,
|
||||||
|
0x07, 0x00, 0x40, 0x50, 0x25, 0x00, 0xe5, 0x90, 0x00, 0x00, 0xc2, 0x90,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0xfc, 0xff, 0x40, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0xe5, 0x90, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x02, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xc5, 0xa0, 0x26, 0x00, 0xe2, 0x90, 0x45, 0x00, 0x40, 0x10,
|
||||||
|
0x03, 0x00, 0xe8, 0x88, 0x00, 0x00, 0xe8, 0x98, 0x18, 0x00, 0x05, 0x24,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x02, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10,
|
||||||
|
0x06, 0x10, 0xa8, 0x00, 0xff, 0x00, 0x42, 0x30, 0xf8, 0xff, 0xa5, 0x24,
|
||||||
|
0x00, 0x00, 0xc2, 0xa0, 0xf8, 0xff, 0xa9, 0x14, 0x05, 0x00, 0x0b, 0x24,
|
||||||
|
0x07, 0x00, 0xe8, 0x88, 0x04, 0x00, 0xe8, 0x98, 0x1e, 0x00, 0x00, 0x11,
|
||||||
|
0x25, 0x28, 0x00, 0x01, 0x00, 0x00, 0x62, 0x90, 0x02, 0x00, 0x42, 0x30,
|
||||||
|
0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa0,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0x06, 0x00, 0x40, 0x50,
|
||||||
|
0xff, 0xff, 0xa5, 0x24, 0x00, 0x00, 0xc2, 0x90, 0x25, 0x00, 0x60, 0x51,
|
||||||
|
0x24, 0x00, 0xec, 0x90, 0xff, 0xff, 0x6b, 0x25, 0xff, 0xff, 0xa5, 0x24,
|
||||||
|
0xf1, 0xff, 0xa0, 0x14, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x51,
|
||||||
|
0x01, 0x00, 0x04, 0x24, 0x24, 0x00, 0xe5, 0x90, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x08, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xc2, 0x90, 0xff, 0x00, 0x42, 0x30, 0x04, 0x00, 0xa2, 0x14,
|
||||||
|
0xff, 0xff, 0x08, 0x25, 0xf7, 0xff, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x04, 0x24, 0x00, 0x00, 0x44, 0xa1, 0x0b, 0x00, 0xe2, 0x88,
|
||||||
|
0x01, 0x00, 0x4a, 0x25, 0x08, 0x00, 0xe2, 0x98, 0xff, 0xff, 0x42, 0x24,
|
||||||
|
0x0b, 0x00, 0xe2, 0xa8, 0x08, 0x00, 0xe2, 0xb8, 0x03, 0x00, 0xe4, 0x88,
|
||||||
|
0x07, 0x00, 0xe5, 0x88, 0x00, 0x00, 0xe4, 0x98, 0x04, 0x00, 0xe5, 0x98,
|
||||||
|
0x21, 0x20, 0x85, 0x00, 0x03, 0x00, 0xe4, 0xa8, 0xae, 0xff, 0x40, 0x14,
|
||||||
|
0x00, 0x00, 0xe4, 0xb8, 0x3f, 0x00, 0x00, 0x70, 0x08, 0x00, 0xe0, 0x03,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x42, 0x30, 0xed, 0xff, 0x82, 0x55,
|
||||||
|
0x00, 0x00, 0x44, 0xa1, 0xd9, 0xff, 0x00, 0x10, 0xff, 0xff, 0x08, 0x25,
|
||||||
|
0x00, 0x00, 0xe8, 0x98, 0x10, 0x00, 0x05, 0x24, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x02, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10, 0x06, 0x10, 0xa8, 0x00,
|
||||||
|
0xff, 0x00, 0x42, 0x30, 0xf8, 0xff, 0xa5, 0x24, 0x00, 0x00, 0xc2, 0xa0,
|
||||||
|
0xf8, 0xff, 0xa9, 0x14, 0x04, 0x00, 0x0b, 0x24, 0xbc, 0xff, 0x00, 0x10,
|
||||||
|
0x07, 0x00, 0xe8, 0x88
|
|
@ -0,0 +1,39 @@
|
||||||
|
0x0b, 0x00, 0x88, 0x88, 0x25, 0x28, 0x80, 0x00, 0x03, 0x00, 0x86, 0x88,
|
||||||
|
0x0f, 0x00, 0x82, 0x88, 0x17, 0x00, 0x84, 0x88, 0x08, 0x00, 0xa8, 0x98,
|
||||||
|
0x00, 0x00, 0xa6, 0x98, 0x0c, 0x00, 0xa2, 0x98, 0x5f, 0x00, 0x00, 0x11,
|
||||||
|
0x14, 0x00, 0xa4, 0x98, 0xf8, 0xff, 0x07, 0x24, 0x1d, 0x00, 0xa9, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x05, 0x00, 0x63, 0x30, 0x04, 0x00, 0x63, 0x38,
|
||||||
|
0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xa0,
|
||||||
|
0x1c, 0x00, 0xaa, 0x90, 0x1f, 0x00, 0xa9, 0x90, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x05, 0x00, 0x63, 0x30, 0x04, 0x00, 0x63, 0x38, 0xfc, 0xff, 0x60, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30,
|
||||||
|
0x06, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30, 0xfc, 0xff, 0x60, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0xa0, 0x00, 0x00, 0x80, 0xa0,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x08, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x83, 0x90, 0x24, 0x18, 0x23, 0x01, 0xe4, 0xff, 0x60, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xaa, 0x90, 0x21, 0x00, 0xa9, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x05, 0x00, 0x63, 0x30, 0x04, 0x00, 0x63, 0x38,
|
||||||
|
0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0xa0,
|
||||||
|
0x31, 0x00, 0x20, 0x11, 0x10, 0x00, 0x09, 0x24, 0x18, 0x00, 0x09, 0x24,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x02, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10,
|
||||||
|
0x06, 0x18, 0x26, 0x01, 0xff, 0x00, 0x63, 0x30, 0xf8, 0xff, 0x29, 0x25,
|
||||||
|
0xf9, 0xff, 0x27, 0x15, 0x00, 0x00, 0x83, 0xa0, 0x1c, 0x00, 0xaa, 0x90,
|
||||||
|
0x20, 0x00, 0xa9, 0x90, 0x00, 0x00, 0x43, 0x90, 0x05, 0x00, 0x63, 0x30,
|
||||||
|
0x04, 0x00, 0x63, 0x38, 0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30, 0x06, 0x00, 0x60, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x08, 0x00, 0x63, 0x30, 0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x8a, 0xa0, 0x00, 0x00, 0x80, 0xa0, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x08, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x83, 0x90, 0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30,
|
||||||
|
0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90,
|
||||||
|
0x24, 0x18, 0x23, 0x01, 0xe4, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0xa3, 0x88, 0xff, 0xff, 0x08, 0x25, 0x04, 0x00, 0xa3, 0x98,
|
||||||
|
0xa4, 0xff, 0x00, 0x15, 0x21, 0x30, 0xc3, 0x00, 0x3f, 0x00, 0x00, 0x70,
|
||||||
|
0x08, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x02, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10, 0x06, 0x18, 0x26, 0x01,
|
||||||
|
0xff, 0x00, 0x63, 0x30, 0xf8, 0xff, 0x29, 0x25, 0xf9, 0xff, 0x27, 0x15,
|
||||||
|
0x00, 0x00, 0x83, 0xa0, 0xd1, 0xff, 0x00, 0x10, 0x1c, 0x00, 0xaa, 0x90
|
|
@ -0,0 +1,51 @@
|
||||||
|
0x13, 0x00, 0x88, 0x88, 0x25, 0x30, 0x80, 0x00, 0x0b, 0x00, 0x85, 0x88,
|
||||||
|
0x17, 0x00, 0x82, 0x88, 0x1f, 0x00, 0x84, 0x88, 0x10, 0x00, 0xc8, 0x98,
|
||||||
|
0x08, 0x00, 0xc5, 0x98, 0x14, 0x00, 0xc2, 0x98, 0x1c, 0x00, 0xc4, 0x98,
|
||||||
|
0x78, 0x00, 0x00, 0x11, 0xf8, 0xff, 0x07, 0x24, 0x25, 0x00, 0xc9, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x05, 0x00, 0x63, 0x30, 0x04, 0x00, 0x63, 0x38,
|
||||||
|
0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xa0,
|
||||||
|
0x24, 0x00, 0xca, 0x90, 0x27, 0x00, 0xc9, 0x90, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x05, 0x00, 0x63, 0x30, 0x04, 0x00, 0x63, 0x38, 0xfc, 0xff, 0x60, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30,
|
||||||
|
0x06, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30, 0xfc, 0xff, 0x60, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0xa0, 0x00, 0x00, 0x80, 0xa0,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x08, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x83, 0x90, 0x24, 0x18, 0x23, 0x01, 0xe4, 0xff, 0x60, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x90, 0x05, 0x00, 0x63, 0x30,
|
||||||
|
0x04, 0x00, 0x63, 0x38, 0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x26, 0x00, 0xc9, 0x90, 0x00, 0x00, 0x43, 0x90, 0x02, 0x00, 0x63, 0x30,
|
||||||
|
0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xa0,
|
||||||
|
0x29, 0x00, 0xc3, 0x90, 0x47, 0x00, 0x60, 0x10, 0x03, 0x00, 0xca, 0x88,
|
||||||
|
0x00, 0x00, 0xca, 0x98, 0x18, 0x00, 0x09, 0x24, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x02, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10, 0x06, 0x18, 0x2a, 0x01,
|
||||||
|
0xff, 0x00, 0x63, 0x30, 0xf8, 0xff, 0x29, 0x25, 0x00, 0x00, 0x83, 0xa0,
|
||||||
|
0xf8, 0xff, 0x27, 0x15, 0x25, 0x58, 0x00, 0x01, 0x07, 0x00, 0xc3, 0x88,
|
||||||
|
0x04, 0x00, 0xc3, 0x98, 0x2b, 0x48, 0x03, 0x01, 0x0a, 0x58, 0x69, 0x00,
|
||||||
|
0x0d, 0x00, 0x60, 0x11, 0x21, 0x50, 0xab, 0x00, 0x00, 0x00, 0xa9, 0x90,
|
||||||
|
0x01, 0x00, 0xa5, 0x24, 0x00, 0x00, 0x43, 0x90, 0x02, 0x00, 0x63, 0x30,
|
||||||
|
0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xa0,
|
||||||
|
0xf9, 0xff, 0xaa, 0x54, 0x00, 0x00, 0xa9, 0x90, 0x07, 0x00, 0xc3, 0x88,
|
||||||
|
0x23, 0x40, 0x0b, 0x01, 0x04, 0x00, 0xc3, 0x98, 0x03, 0x00, 0xc9, 0x88,
|
||||||
|
0x00, 0x00, 0xc9, 0x98, 0x21, 0x18, 0x23, 0x01, 0x03, 0x00, 0xc3, 0xa8,
|
||||||
|
0x00, 0x00, 0xc3, 0xb8, 0x24, 0x00, 0xca, 0x90, 0x28, 0x00, 0xc9, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x05, 0x00, 0x63, 0x30, 0x04, 0x00, 0x63, 0x38,
|
||||||
|
0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x90,
|
||||||
|
0x08, 0x00, 0x63, 0x30, 0x06, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x83, 0x90, 0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30,
|
||||||
|
0xfc, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0xa0,
|
||||||
|
0x00, 0x00, 0x80, 0xa0, 0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30,
|
||||||
|
0xfd, 0xff, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x08, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x90, 0x24, 0x18, 0x23, 0x01,
|
||||||
|
0xe4, 0xff, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x8b, 0xff, 0x00, 0x55,
|
||||||
|
0x25, 0x00, 0xc9, 0x90, 0x3f, 0x00, 0x00, 0x70, 0x08, 0x00, 0xe0, 0x03,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x98, 0x10, 0x00, 0x09, 0x24,
|
||||||
|
0x00, 0x00, 0x43, 0x90, 0x02, 0x00, 0x63, 0x30, 0xfd, 0xff, 0x60, 0x10,
|
||||||
|
0x06, 0x18, 0x2a, 0x01, 0xff, 0x00, 0x63, 0x30, 0xf8, 0xff, 0x29, 0x25,
|
||||||
|
0x00, 0x00, 0x83, 0xa0, 0xf8, 0xff, 0x27, 0x15, 0x25, 0x58, 0x00, 0x01,
|
||||||
|
0x07, 0x00, 0xc3, 0x88, 0x04, 0x00, 0xc3, 0x98, 0x2b, 0x48, 0x03, 0x01,
|
||||||
|
0x0a, 0x58, 0x69, 0x00, 0xbb, 0xff, 0x60, 0x15, 0x21, 0x50, 0xab, 0x00,
|
||||||
|
0xc6, 0xff, 0x00, 0x10, 0x03, 0x00, 0xc9, 0x88
|
|
@ -0,0 +1,33 @@
|
||||||
|
0x0f, 0x00, 0x87, 0x88, 0x07, 0x00, 0x88, 0x88, 0x13, 0x00, 0x83, 0x88,
|
||||||
|
0x1b, 0x00, 0x85, 0x88, 0x0c, 0x00, 0x87, 0x98, 0x04, 0x00, 0x88, 0x98,
|
||||||
|
0x10, 0x00, 0x83, 0x98, 0x18, 0x00, 0x85, 0x98, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x05, 0x00, 0x42, 0x30, 0x04, 0x00, 0x42, 0x38, 0xfc, 0xff, 0x40, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30,
|
||||||
|
0x07, 0x00, 0x40, 0x50, 0x20, 0x00, 0x86, 0x90, 0x00, 0x00, 0xa2, 0x90,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0xfc, 0xff, 0x40, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x86, 0x90, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x02, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xa6, 0xa0, 0x21, 0x00, 0x82, 0x90, 0x35, 0x00, 0x40, 0x10,
|
||||||
|
0x03, 0x00, 0x82, 0x88, 0x18, 0x00, 0x06, 0x24, 0xf8, 0xff, 0x09, 0x24,
|
||||||
|
0x00, 0x00, 0x82, 0x98, 0x25, 0x20, 0x40, 0x00, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x02, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10, 0x06, 0x10, 0xc4, 0x00,
|
||||||
|
0xff, 0x00, 0x42, 0x30, 0xf8, 0xff, 0xc6, 0x24, 0xf9, 0xff, 0xc9, 0x14,
|
||||||
|
0x00, 0x00, 0xa2, 0xa0, 0x05, 0x00, 0x06, 0x24, 0x23, 0x00, 0xe0, 0x10,
|
||||||
|
0x25, 0x20, 0xe0, 0x00, 0x00, 0x00, 0x62, 0x90, 0x02, 0x00, 0x42, 0x30,
|
||||||
|
0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xa0,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0x06, 0x00, 0x40, 0x50,
|
||||||
|
0xff, 0xff, 0x84, 0x24, 0x00, 0x00, 0xa2, 0x90, 0x14, 0x00, 0xc0, 0x50,
|
||||||
|
0x00, 0x00, 0x02, 0xa1, 0xff, 0xff, 0xc6, 0x24, 0xff, 0xff, 0x84, 0x24,
|
||||||
|
0xf1, 0xff, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0xe0, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30,
|
||||||
|
0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x90,
|
||||||
|
0x03, 0x00, 0xc0, 0x50, 0xff, 0xff, 0xe7, 0x24, 0xf8, 0xff, 0x00, 0x10,
|
||||||
|
0xff, 0xff, 0xc6, 0x24, 0x06, 0x00, 0xe0, 0x10, 0x00, 0x00, 0x02, 0xa1,
|
||||||
|
0xf4, 0xff, 0x00, 0x10, 0x01, 0x00, 0x08, 0x25, 0xff, 0xff, 0xe7, 0x24,
|
||||||
|
0xec, 0xff, 0x00, 0x10, 0x01, 0x00, 0x08, 0x25, 0x3f, 0x00, 0x00, 0x70,
|
||||||
|
0x08, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x24,
|
||||||
|
0xf8, 0xff, 0x09, 0x24, 0x00, 0x00, 0x82, 0x98, 0x25, 0x20, 0x40, 0x00,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x02, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10,
|
||||||
|
0x06, 0x10, 0xc4, 0x00, 0xff, 0x00, 0x42, 0x30, 0xf8, 0xff, 0xc6, 0x24,
|
||||||
|
0xf9, 0xff, 0xc9, 0x14, 0x00, 0x00, 0xa2, 0xa0, 0xcc, 0xff, 0x00, 0x10,
|
||||||
|
0x04, 0x00, 0x06, 0x24
|
|
@ -0,0 +1,21 @@
|
||||||
|
0x03, 0x00, 0x85, 0x88, 0x0b, 0x00, 0x88, 0x88, 0x0f, 0x00, 0x83, 0x88,
|
||||||
|
0x17, 0x00, 0x86, 0x88, 0x00, 0x00, 0x85, 0x98, 0x08, 0x00, 0x88, 0x98,
|
||||||
|
0x0c, 0x00, 0x83, 0x98, 0x14, 0x00, 0x86, 0x98, 0x00, 0x00, 0x62, 0x90,
|
||||||
|
0x05, 0x00, 0x42, 0x30, 0x04, 0x00, 0x42, 0x38, 0xfc, 0xff, 0x40, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30,
|
||||||
|
0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x90,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0xfc, 0xff, 0x40, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x25, 0x38, 0xa0, 0x00, 0x21, 0x40, 0x05, 0x01, 0x00, 0x00, 0xa9, 0x90,
|
||||||
|
0x01, 0x00, 0xa5, 0x24, 0x00, 0x00, 0x62, 0x90, 0x02, 0x00, 0x42, 0x30,
|
||||||
|
0xfd, 0xff, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0xa0,
|
||||||
|
0x1c, 0x00, 0x82, 0x90, 0x08, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0x04, 0x00, 0x40, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x90, 0x01, 0x00, 0xe7, 0x24,
|
||||||
|
0xff, 0xff, 0xe2, 0xa0, 0xef, 0xff, 0xa8, 0x54, 0x00, 0x00, 0xa9, 0x90,
|
||||||
|
0x1c, 0x00, 0x82, 0x90, 0x0c, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x2b, 0x10, 0xe8, 0x00, 0x09, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x62, 0x90, 0x08, 0x00, 0x42, 0x30, 0xfd, 0xff, 0x40, 0x10,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x90, 0x01, 0x00, 0xe7, 0x24,
|
||||||
|
0xf9, 0xff, 0x07, 0x15, 0xff, 0xff, 0xe2, 0xa0, 0x3f, 0x00, 0x00, 0x70,
|
||||||
|
0x08, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00
|
|
@ -6421,6 +6421,75 @@ flash bank $_FLASHNAME fespi 0x20000000 0 0 0 $_TARGETNAME
|
||||||
@end example
|
@end example
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} {dw-spi}
|
||||||
|
@cindex DesignWare SPI controller driver
|
||||||
|
@cindex DW-SPI
|
||||||
|
Driver for SPI NOR flash chips connected via DesignWare SPI Core, used
|
||||||
|
in number of MCUs.
|
||||||
|
Currently, only MIPS M4K CPU architecture is supported.
|
||||||
|
|
||||||
|
The flash size is autodetected based on the table of known JEDEC IDs hardcoded
|
||||||
|
in the OpenOCD sources. When flash size is set to @var{0}, probed Flash
|
||||||
|
size is used.
|
||||||
|
|
||||||
|
This driver requires configuring DRAM controller first, setting up a
|
||||||
|
working area big enough to hold read/write buffers and switching Flash
|
||||||
|
chip to 32bit mode via Tcl commands.
|
||||||
|
|
||||||
|
@quotation Note
|
||||||
|
If chip contains Boot controller, its 24/32bit setting must match
|
||||||
|
Flash chip. If Flash chip's reset line is not connected to JTAG adapter,
|
||||||
|
CPU reset may cause these configurations to be out of sync.
|
||||||
|
@end quotation
|
||||||
|
|
||||||
|
|
||||||
|
Mandatory driver's arguments are
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item @var{-freq} ... core frequency in Hz, used in communication speed
|
||||||
|
calculation.
|
||||||
|
@item @var{-simc} ... @var{SIMC} register block absolute address.
|
||||||
|
This value is the same as for Linux's driver device tree register field.
|
||||||
|
@item @var{-spi_mst} ... @var{SPI_MST} register address. When available,
|
||||||
|
it is used for switching between SPI Boot and Master controllers. This
|
||||||
|
value is the same as for Linux's driver device tree register field
|
||||||
|
second argument. Set to @var{0} if SPI Boot controller not available.
|
||||||
|
@item @var{-if_owner_offset} ... offset of @var{if_owner} field inside
|
||||||
|
@var{SPI_MST} register. Set to @var{0} if SPI Boot controller not available.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Optional driver's arguments are
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item @var{-speed} ... SPI device communication speed in Hz. Minimal
|
||||||
|
speed depends on the @var{-freq} variable and has the value of
|
||||||
|
@var{freq/0xfffe}. The default value is @var{1000000}.
|
||||||
|
@item @var{-chip_select} ... Chip select pin. The default value
|
||||||
|
is @var{0}.
|
||||||
|
@item @var{-timeout} ... flash communication timeout in
|
||||||
|
seconds. The default value is @var{600}.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
For some SoCs there are shortcuts for mandatory arguments
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item @var{-jaguar2} ... configuration for MSCC Jaguar2 SoC family.
|
||||||
|
@item @var{-ocelot} ... configuration for MSCC Ocelot SoC family.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Driver provides shortcut arguments for MSCC @var{-jaguar2} and
|
||||||
|
@var{-ocelot} network switch SOCs, which set the correct values for @var{-freq},
|
||||||
|
@var{-simc}, @var{-spi_mst} and @var{-if_owner_offset} arguments.
|
||||||
|
|
||||||
|
Example of equivalent configurations for Jaguar2 SoC
|
||||||
|
|
||||||
|
@example
|
||||||
|
flash bank $_FLASHNAME dw-spi 0x40000000 0x02000000 4 4 $_TARGETNAME -freq 250000000 -simc 0x70101000 -spi_mst 0x70000024 -if_owner_offset 6 -speed 3000000
|
||||||
|
flash bank $_FLASHNAME dw-spi 0x40000000 0x02000000 4 4 $_TARGETNAME -jaguar2 -speed 3000000
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@subsection Internal Flash (Microcontrollers)
|
@subsection Internal Flash (Microcontrollers)
|
||||||
|
|
||||||
@deffn {Flash Driver} {aduc702x}
|
@deffn {Flash Driver} {aduc702x}
|
||||||
|
|
|
@ -26,6 +26,7 @@ NOR_DRIVERS = \
|
||||||
%D%/cc26xx.c \
|
%D%/cc26xx.c \
|
||||||
%D%/cfi.c \
|
%D%/cfi.c \
|
||||||
%D%/dsp5680xx_flash.c \
|
%D%/dsp5680xx_flash.c \
|
||||||
|
%D%/dw-spi.c \
|
||||||
%D%/efm32.c \
|
%D%/efm32.c \
|
||||||
%D%/em357.c \
|
%D%/em357.c \
|
||||||
%D%/eneispif.c \
|
%D%/eneispif.c \
|
||||||
|
@ -89,6 +90,7 @@ NORHEADERS = \
|
||||||
%D%/cc26xx.h \
|
%D%/cc26xx.h \
|
||||||
%D%/cfi.h \
|
%D%/cfi.h \
|
||||||
%D%/driver.h \
|
%D%/driver.h \
|
||||||
|
%D%/dw-spi-helper.h \
|
||||||
%D%/imp.h \
|
%D%/imp.h \
|
||||||
%D%/non_cfi.h \
|
%D%/non_cfi.h \
|
||||||
%D%/ocl.h \
|
%D%/ocl.h \
|
||||||
|
|
|
@ -254,6 +254,7 @@ extern const struct flash_driver cc26xx_flash;
|
||||||
extern const struct flash_driver cc3220sf_flash;
|
extern const struct flash_driver cc3220sf_flash;
|
||||||
extern const struct flash_driver cfi_flash;
|
extern const struct flash_driver cfi_flash;
|
||||||
extern const struct flash_driver dsp5680xx_flash;
|
extern const struct flash_driver dsp5680xx_flash;
|
||||||
|
extern const struct flash_driver dw_spi_flash;
|
||||||
extern const struct flash_driver efm32_flash;
|
extern const struct flash_driver efm32_flash;
|
||||||
extern const struct flash_driver em357_flash;
|
extern const struct flash_driver em357_flash;
|
||||||
extern const struct flash_driver eneispif_flash;
|
extern const struct flash_driver eneispif_flash;
|
||||||
|
|
|
@ -31,6 +31,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&cc26xx_flash,
|
&cc26xx_flash,
|
||||||
&cfi_flash,
|
&cfi_flash,
|
||||||
&dsp5680xx_flash,
|
&dsp5680xx_flash,
|
||||||
|
&dw_spi_flash,
|
||||||
&efm32_flash,
|
&efm32_flash,
|
||||||
&em357_flash,
|
&em357_flash,
|
||||||
&eneispif_flash,
|
&eneispif_flash,
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Driver for SPI NOR flash chips connected via DesignWare SPI Core.
|
||||||
|
*
|
||||||
|
* In order to avoid using stack, all helper function arguments are packed
|
||||||
|
* into a single struct, passed by pointer.
|
||||||
|
*
|
||||||
|
* Pointers are represented by 64 bit integers to make structs compatible
|
||||||
|
* with 64 bit targets.
|
||||||
|
*
|
||||||
|
* This file contains helper function argument structures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPENOCD_FLASH_NOR_DW_SPI_HELPER_H
|
||||||
|
#define OPENOCD_FLASH_NOR_DW_SPI_HELPER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Arguments for transaction helper function.
|
||||||
|
*/
|
||||||
|
struct dw_spi_transaction {
|
||||||
|
uint64_t buffer;
|
||||||
|
///< Pointer to data buffer to send over SPI.
|
||||||
|
///< Return values are stored in place of output data when
|
||||||
|
///< dw_spi_transaction::read_flag is 1.
|
||||||
|
uint32_t size; ///< Size of dw_spi_transaction::buffer.
|
||||||
|
uint64_t status_reg; ///< Pointer to SR register.
|
||||||
|
uint64_t data_reg; ///< Pointer to DR register.
|
||||||
|
uint8_t read_flag;
|
||||||
|
///< When 1, store RX FIFO data to dw_spi_transaction::buffer.
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Arguments for check_fill helper function.
|
||||||
|
*/
|
||||||
|
struct dw_spi_check_fill {
|
||||||
|
uint32_t address; ///< Starting address. Sector aligned.
|
||||||
|
uint32_t sector_size; ///< Sector size.
|
||||||
|
uint32_t sector_count; ///< Number of sectors to check.
|
||||||
|
uint64_t status_reg; ///< Pointer to SR register.
|
||||||
|
uint64_t data_reg; ///< Pointer to DR register.
|
||||||
|
uint64_t fill_status_array;
|
||||||
|
///< Pointer to array describing sectors fill status.
|
||||||
|
///< 1 if filled, 0 if not filled.
|
||||||
|
uint8_t pattern; ///< Fill pattern.
|
||||||
|
uint8_t read_cmd; ///< Read data command.
|
||||||
|
uint8_t four_byte_mode; ///< Four byte addressing mode flag.
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Arguments for erase helper function.
|
||||||
|
*/
|
||||||
|
struct dw_spi_erase {
|
||||||
|
uint32_t address; ///< First sector address. Sector aligned.
|
||||||
|
uint32_t sector_size; ///< Sector size.
|
||||||
|
uint32_t sector_count; ///< Number of sectors to erase.
|
||||||
|
uint64_t status_reg; ///< Pointer to SR register.
|
||||||
|
uint64_t data_reg; ///< Pointer to DR register.
|
||||||
|
uint8_t read_status_cmd; ///< Read status command.
|
||||||
|
uint8_t write_enable_cmd; ///< Write enable command.
|
||||||
|
uint8_t erase_sector_cmd; ///< Erase sector command.
|
||||||
|
uint8_t write_enable_mask; ///< Write enable mask.
|
||||||
|
uint8_t busy_mask; ///< Busy mask.
|
||||||
|
uint8_t four_byte_mode; ///< Four byte addressing mode flag.
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Arguments for program helper function.
|
||||||
|
*/
|
||||||
|
struct dw_spi_program {
|
||||||
|
uint32_t address;
|
||||||
|
///< First page address. Page aligned when write is crossing
|
||||||
|
///< the page boundary.
|
||||||
|
uint32_t page_size; ///< Page size.
|
||||||
|
uint64_t buffer; ///< Data buffer pointer.
|
||||||
|
uint32_t buffer_size; ///< Size of dw_spi_program::buffer.
|
||||||
|
uint64_t status_reg; ///< Pointer to SR register.
|
||||||
|
uint64_t data_reg; ///< Pointer to DR register.
|
||||||
|
uint8_t read_status_cmd; ///< Read status command.
|
||||||
|
uint8_t write_enable_cmd; ///< Write enable command.
|
||||||
|
uint8_t program_cmd; ///< Program command.
|
||||||
|
uint8_t write_enable_mask; ///< Write enable mask.
|
||||||
|
uint8_t busy_mask; ///< Busy mask.
|
||||||
|
uint8_t four_byte_mode; ///< Four byte addressing mode flag.
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Arguments for read helper function.
|
||||||
|
*/
|
||||||
|
struct dw_spi_read {
|
||||||
|
uint32_t address; ///< First sector address.
|
||||||
|
uint64_t buffer; ///< Data buffer pointer.
|
||||||
|
uint32_t buffer_size; ///< Size of dw_spi_read::buffer.
|
||||||
|
uint64_t status_reg; ///< Pointer to SR register.
|
||||||
|
uint64_t data_reg; ///< Pointer to DR register.
|
||||||
|
uint8_t read_cmd; ///< Read data command.
|
||||||
|
uint8_t four_byte_mode; ///< Four byte addressing mode flag.
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#endif /* OPENOCD_FLASH_NOR_DW_SPI_HELPER_H */
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue