From 0da66a454d0b1869cbaeffebb2a20f4ead5f496a Mon Sep 17 00:00:00 2001 From: Daniel Jobson Date: Thu, 22 Aug 2024 14:48:09 +0200 Subject: [PATCH] add flash lib and test sequence --- hw/application_fpga/Makefile | 10 +- hw/application_fpga/fw/tk1/flash.c | 193 +++++++++++++++++++++++++++++ hw/application_fpga/fw/tk1/flash.h | 60 +++++++++ hw/application_fpga/fw/tk1/main.c | 32 ++++- hw/application_fpga/fw/tk1/proto.c | 4 +- hw/application_fpga/fw/tk1/proto.h | 1 + 6 files changed, 294 insertions(+), 6 deletions(-) create mode 100644 hw/application_fpga/fw/tk1/flash.c create mode 100644 hw/application_fpga/fw/tk1/flash.h diff --git a/hw/application_fpga/Makefile b/hw/application_fpga/Makefile index 022dbc5..530ea4c 100644 --- a/hw/application_fpga/Makefile +++ b/hw/application_fpga/Makefile @@ -85,7 +85,9 @@ FIRMWARE_DEPS = \ $(P)/fw/tk1/lib.h \ $(P)/fw/tk1/proto.h \ $(P)/fw/tk1/assert.h \ - $(P)/fw/tk1/led.h + $(P)/fw/tk1/led.h \ + $(P)/fw/tk1/spi.h \ + $(P)/fw/tk1/flash.h FIRMWARE_OBJS = \ $(P)/fw/tk1/main.o \ @@ -95,7 +97,8 @@ FIRMWARE_OBJS = \ $(P)/fw/tk1/assert.o \ $(P)/fw/tk1/led.o \ $(P)/fw/tk1/blake2s/blake2s.o \ - $(P)/fw/tk1/spi.o + $(P)/fw/tk1/spi.o \ + $(P)/fw/tk1/flash.o FIRMWARE_SOURCES = \ $(P)/fw/tk1/main.c \ @@ -104,7 +107,8 @@ FIRMWARE_SOURCES = \ $(P)/fw/tk1/assert.c \ $(P)/fw/tk1/led.c \ $(P)/fw/tk1/blake2s/blake2s.c \ - $(P)/fw/tk1/spi.c + $(P)/fw/tk1/spi.c \ + $(P)/fw/tk1/flash.c TESTFW_OBJS = \ $(P)/fw/testfw/main.o \ diff --git a/hw/application_fpga/fw/tk1/flash.c b/hw/application_fpga/fw/tk1/flash.c new file mode 100644 index 0000000..23fd1e2 --- /dev/null +++ b/hw/application_fpga/fw/tk1/flash.c @@ -0,0 +1,193 @@ +// Copyright (C) 2022, 2023 - Tillitis AB +// SPDX-License-Identifier: GPL-2.0-only + +#include "flash.h" +#include "spi.h" +#include +// #include +// #include +#include "types.h" + +#include "../tk1_mem.h" + +// clang-format off +static volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER; +static volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER; +static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS; +static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL; +// clang-format on + +// CPU clock frequency in Hz +#define CPUFREQ 18000000 + +static void delay(int timeout_ms) +{ + // Tick once every centisecond + *timer_prescaler = CPUFREQ / 100; + *timer = timeout_ms / 10; + + *timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_START_BIT); + + while (*timer_status != 0) { + } + + // Stop timer + *timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT); +} + +bool flash_is_busy() +{ + uint8_t tx_buf = READ_STATUS_REG_1; + uint8_t rx_buf = {0x00}; + + spi_transfer(&tx_buf, sizeof(tx_buf), &rx_buf, sizeof(rx_buf)); + + if (rx_buf & (1 << STATUS_REG_BUSY_BIT)) { + return true; + } + + return false; +} + +// Blocking until !busy +void flash_wait_busy() +{ + while (flash_is_busy()) { + delay(10); + } +} + +void flash_write_enable() +{ + uint8_t tx_buf = WRITE_ENABLE; + + spi_write(&tx_buf, sizeof(tx_buf), NULL, 0); +} + +void flash_write_disable() +{ + uint8_t tx_buf = WRITE_DISABLE; + + spi_write(&tx_buf, sizeof(tx_buf), NULL, 0); +} + +void flash_sector_erase(uint32_t address) +{ + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = SECTOR_ERASE; + tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF; + tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF; + tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF; + + flash_write_enable(); + spi_write(tx_buf, sizeof(tx_buf), NULL, 0); + flash_wait_busy(); +} + +void flash_block_32_erase(uint32_t address) +{ + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = BLOCK_ERASE_32K; + tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF; + tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF; + tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF; + + flash_write_enable(); + spi_write(tx_buf, sizeof(tx_buf), NULL, 0); + flash_wait_busy(); +} + +void flash_block_64_erase(uint32_t address) +{ + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = BLOCK_ERASE_64K; + tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF; + tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF; + tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF; + + flash_write_enable(); + spi_write(tx_buf, sizeof(tx_buf), NULL, 0); + flash_wait_busy(); +} + +void flash_release_powerdown() +{ + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = RELEASE_POWER_DOWN; + + spi_write(tx_buf, sizeof(tx_buf), NULL, 0); +} + +void flash_powerdown() +{ + uint8_t tx_buf = POWER_DOWN; + + spi_write(&tx_buf, sizeof(tx_buf), NULL, 0); +} + +void flash_read_manufacturer_device_id(uint8_t *device_id) +{ + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = READ_MANUFACTURER_ID; + + spi_transfer(tx_buf, sizeof(tx_buf), device_id, 2); +} + +void flash_read_jedec_id(uint8_t *jedec_id) +{ + uint8_t tx_buf = READ_JEDEC_ID; + + spi_transfer(&tx_buf, sizeof(tx_buf), jedec_id, 3); +} + +void flash_read_unique_id(uint8_t *unique_id) +{ + uint8_t tx_buf[5] = {0x00}; + tx_buf[0] = READ_UNIQUE_ID; + + spi_transfer(tx_buf, sizeof(tx_buf), unique_id, 8); +} + +void flash_read_status(uint8_t *status_reg) +{ + uint8_t tx_buf = READ_STATUS_REG_1; + + spi_transfer(&tx_buf, sizeof(tx_buf), status_reg, 1); + + tx_buf = READ_STATUS_REG_2; + spi_transfer(&tx_buf, sizeof(tx_buf), status_reg + 1, 1); +} + +int flash_read_data(uint32_t address, uint8_t *dest_buf, size_t size) +{ + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = READ_DATA; + tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF; + tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF; + tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF; + + return spi_transfer(tx_buf, sizeof(tx_buf), dest_buf, size); +} + +int flash_write_data(uint32_t address, uint8_t *data, size_t size) +{ + if (size <= 0 || size > 256) { + return -1; + } + + uint8_t tx_buf[4] = {0x00}; + tx_buf[0] = PAGE_PROGRAM; + tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF; + tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF; + tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF; + + flash_write_enable(); + + if (spi_write(tx_buf, sizeof(tx_buf), data, size) != 0) { + return -1; + } else { + flash_wait_busy(); + } + + return 0; +} diff --git a/hw/application_fpga/fw/tk1/flash.h b/hw/application_fpga/fw/tk1/flash.h new file mode 100644 index 0000000..44d1ce0 --- /dev/null +++ b/hw/application_fpga/fw/tk1/flash.h @@ -0,0 +1,60 @@ +// Copyright (C) 2022, 2023 - Tillitis AB +// SPDX-License-Identifier: GPL-2.0-only + +#ifndef TKEY_FLASH_H +#define TKEY_FLASH_H + +#include +// #include +// #include + +#include "types.h" + +#define WRITE_ENABLE 0x06 +#define WRITE_DISABLE 0x04 + +#define READ_STATUS_REG_1 0x05 +#define READ_STATUS_REG_2 0x35 +#define WRITE_STATUS_REG 0x01 + +#define PAGE_PROGRAM 0x02 +#define SECTOR_ERASE 0x20 +#define BLOCK_ERASE_32K 0x52 +#define BLOCK_ERASE_64K 0xD8 +#define CHIP_ERASE 0xC7 + +#define POWER_DOWN 0xB9 +#define READ_DATA 0x03 +#define RELEASE_POWER_DOWN 0xAB + +#define READ_MANUFACTURER_ID 0x90 +#define READ_JEDEC_ID 0x9F +#define READ_UNIQUE_ID 0x4B + +#define ENABLE_RESET 0x66 +#define RESET 0x99 + +#define ADDR_BYTE_3_BIT 16 +#define ADDR_BYTE_2_BIT 8 +#define ADDR_BYTE_1_BIT 0 + +#define STATUS_REG_BUSY_BIT 0 +#define STATUS_REG_WEL_BIT 1 + +bool flash_is_busy(void); +void flash_wait_busy(void); +void flash_write_enable(void); +void flash_write_disable(void); +void flash_sector_erase(uint32_t address); +void flash_block_32_erase(uint32_t address); +void flash_block_64_erase(uint32_t address); +void flash_release_powerdown(void); +void flash_powerdown(void); +void flash_read_manufacturer_device_id(uint8_t *device_id); +void flash_read_jedec_id(uint8_t *jedec_id); +void flash_read_unique_id(uint8_t *unique_id); +void flash_read_status(uint8_t *status_reg); +int flash_read_data(uint32_t address, uint8_t *dest_buf, size_t size); +int flash_write_data(uint32_t address, uint8_t *data, size_t size); + +#endif diff --git a/hw/application_fpga/fw/tk1/main.c b/hw/application_fpga/fw/tk1/main.c index 3cff710..00de646 100644 --- a/hw/application_fpga/fw/tk1/main.c +++ b/hw/application_fpga/fw/tk1/main.c @@ -6,6 +6,7 @@ #include "../tk1_mem.h" #include "assert.h" #include "blake2s/blake2s.h" +#include "flash.h" #include "lib.h" #include "proto.h" #include "spi.h" @@ -394,6 +395,35 @@ static void scramble_ram(void) *ram_data_rand = rnd_word(); } +int spi_test(void) +{ + + // Idea: + // Test reading out certain info, and print it to app. + + if (!spi_ready()) { + assert(1 == 2); + } + + uint8_t read_buf[0xff] = {0x00}; + + flash_release_powerdown(); + + // Read out IDs + flash_read_manufacturer_device_id(read_buf); + write(read_buf, 2); + + memset(read_buf, 0x00, sizeof(read_buf)); + flash_read_unique_id(read_buf); + write(read_buf, 8); + + memset(read_buf, 0x00, sizeof(read_buf)); + flash_read_jedec_id(read_buf); + write(read_buf, 3); + + return 0; +} + int main(void) { struct context ctx = {0}; @@ -405,7 +435,7 @@ int main(void) // Let the app know the function adddress for blake2s() *fw_blake2s_addr = (uint32_t)blake2s; - *spi_func_addr = (uint32_t)spi_ready; + *spi_func_addr = (uint32_t)spi_test; /*@-mustfreeonly@*/ /* Yes, splint, this points directly to RAM and we don't care diff --git a/hw/application_fpga/fw/tk1/proto.c b/hw/application_fpga/fw/tk1/proto.c index 4acbce4..6822205 100644 --- a/hw/application_fpga/fw/tk1/proto.c +++ b/hw/application_fpga/fw/tk1/proto.c @@ -21,7 +21,7 @@ static volatile uint32_t *tx = (volatile uint32_t *)TK1_MMIO_UART_TX_DATA; static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len); static int parseframe(uint8_t b, struct frame_header *hdr); -static void write(uint8_t *buf, size_t nbytes); +void write(uint8_t *buf, size_t nbytes); static int read(uint8_t *buf, size_t bufsize, size_t nbytes); static int bytelen(enum cmdlen cmdlen); @@ -135,7 +135,7 @@ void writebyte(uint8_t b) } } -static void write(uint8_t *buf, size_t nbytes) +void write(uint8_t *buf, size_t nbytes) { for (int i = 0; i < nbytes; i++) { writebyte(buf[i]); diff --git a/hw/application_fpga/fw/tk1/proto.h b/hw/application_fpga/fw/tk1/proto.h index 1c13c5c..9147892 100644 --- a/hw/application_fpga/fw/tk1/proto.h +++ b/hw/application_fpga/fw/tk1/proto.h @@ -55,4 +55,5 @@ void writebyte(uint8_t b); uint8_t readbyte(void); void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf); int readcommand(struct frame_header *hdr, uint8_t *cmd, int state); +void write(uint8_t *buf, size_t nbytes); #endif