From c8b3288ba915e3dc22f641544aa702c421527d6b Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Wed, 20 Jan 2021 22:00:16 +1000 Subject: [PATCH] Addd spi flash read/write/erase --- software/SCSI2SD/src/config.c | 79 ++++++++++ software/SCSI2SD/src/flash.c | 225 ++++++++++++++++++++++++----- software/SCSI2SD/src/sd.c | 21 +++ software/SCSI2SD/src/storedevice.h | 4 + 4 files changed, 289 insertions(+), 40 deletions(-) diff --git a/software/SCSI2SD/src/config.c b/software/SCSI2SD/src/config.c index 5b4195c..953a3df 100755 --- a/software/SCSI2SD/src/config.c +++ b/software/SCSI2SD/src/config.c @@ -222,6 +222,73 @@ deviceListCommand() hidPacket_send(response, pos); } +static void +deviceEraseCommand(const uint8_t* cmd) +{ + int deviceCount; + S2S_Device** devices = s2s_GetDevices(&deviceCount); + + uint32_t sectorNum = + ((uint32_t)cmd[2]) << 24 | + ((uint32_t)cmd[3]) << 16 | + ((uint32_t)cmd[4]) << 8 | + ((uint32_t)cmd[5]); + + uint32_t count = + ((uint32_t)cmd[6]) << 24 | + ((uint32_t)cmd[7]) << 16 | + ((uint32_t)cmd[8]) << 8 | + ((uint32_t)cmd[9]); + + devices[cmd[1]]->erase(devices[cmd[1]], sectorNum, count); + + uint8_t response[] = + { + CONFIG_STATUS_GOOD + }; + hidPacket_send(response, sizeof(response)); +} + +static void +deviceWriteCommand(const uint8_t* cmd) +{ + int deviceCount; + S2S_Device** devices = s2s_GetDevices(&deviceCount); + + uint32_t sectorNum = + ((uint32_t)cmd[2]) << 24 | + ((uint32_t)cmd[3]) << 16 | + ((uint32_t)cmd[4]) << 8 | + ((uint32_t)cmd[5]); + + devices[cmd[1]]->write(devices[cmd[1]], sectorNum, 1, &cmd[6]); + + uint8_t response[] = + { + CONFIG_STATUS_GOOD + }; + hidPacket_send(response, sizeof(response)); +} + + +static void +deviceReadCommand(const uint8_t* cmd) +{ + int deviceCount; + S2S_Device** devices = s2s_GetDevices(&deviceCount); + + uint32_t sectorNum = + ((uint32_t)cmd[2]) << 24 | + ((uint32_t)cmd[3]) << 16 | + ((uint32_t)cmd[4]) << 8 | + ((uint32_t)cmd[5]); + + uint32_t response[512]; + devices[cmd[1]]->read(devices[cmd[1]], sectorNum, 1, &response[0]); + + hidPacket_send(&response[0], 512); +} + static void processCommand(const uint8_t* cmd, size_t cmdSize) { @@ -254,6 +321,18 @@ processCommand(const uint8_t* cmd, size_t cmdSize) case S2S_CMD_DEV_LIST: deviceListCommand(); break; + + case S2S_CMD_DEV_ERASE: + deviceEraseCommand(cmd); + break; + + case S2S_CMD_DEV_WRITE: + deviceWriteCommand(cmd); + break; + + case S2S_CMD_DEV_READ: + deviceReadCommand(cmd); + break; case CONFIG_NONE: // invalid default: diff --git a/software/SCSI2SD/src/flash.c b/software/SCSI2SD/src/flash.c index fe493dc..7bfaae6 100644 --- a/software/SCSI2SD/src/flash.c +++ b/software/SCSI2SD/src/flash.c @@ -1,19 +1,19 @@ -// Copyright (C) 2013 Michael McMaster +// Copyright (C) 2013 Michael McMaster // -// This file is part of SCSI2SD. +// This file is part of SCSI2SD. // -// SCSI2SD is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// SCSI2SD is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// SCSI2SD is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// SCSI2SD is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with SCSI2SD. If not, see . +// You should have received a copy of the GNU General Public License +// along with SCSI2SD. If not, see . #include "device.h" #include "flash.h" @@ -24,9 +24,9 @@ typedef struct { - S2S_Device dev; + S2S_Device dev; - S2S_Target targets[MAX_SCSI_TARGETS]; + S2S_Target targets[MAX_SCSI_TARGETS]; uint32_t capacity; // in 512 byte blocks @@ -43,18 +43,24 @@ static S2S_Target* spiFlash_getTargets(S2S_Device* dev, int* count); static uint32_t spiFlash_getCapacity(S2S_Device* dev); static int spiFlash_pollMediaChange(S2S_Device* dev); static void spiFlash_pollMediaBusy(S2S_Device* dev); +static void spiFlash_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count); +static void spiFlash_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer); +static void spiFlash_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer); SpiFlash spiFlash = { - { - spiFlash_earlyInit, + { + spiFlash_earlyInit, spiFlash_init, - spiFlash_getTargets, - spiFlash_getCapacity, - spiFlash_pollMediaChange, - spiFlash_pollMediaBusy, + spiFlash_getTargets, + spiFlash_getCapacity, + spiFlash_pollMediaChange, + spiFlash_pollMediaBusy, + spiFlash_erase, + spiFlash_read, + spiFlash_write, 0, // initial mediaState CONFIG_STOREDEVICE_FLASH - } + } }; S2S_Device* spiFlashDevice = &(spiFlash.dev); @@ -62,32 +68,32 @@ S2S_Device* spiFlashDevice = &(spiFlash.dev); // Read and write 1 byte. static uint8_t spiFlashByte(uint8_t value) { - NOR_SPI_WriteTxData(value); - while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {} - return NOR_SPI_ReadRxData(); + NOR_SPI_WriteTxData(value); + while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {} + return NOR_SPI_ReadRxData(); } static void spiFlash_earlyInit(S2S_Device* dev) { - SpiFlash* spiFlash = (SpiFlash*)dev; + SpiFlash* spiFlash = (SpiFlash*)dev; - for (int i = 0; i < MAX_SCSI_TARGETS; ++i) - { - spiFlash->targets[i].device = dev; + for (int i = 0; i < MAX_SCSI_TARGETS; ++i) + { + spiFlash->targets[i].device = dev; const S2S_TargetCfg* cfg = getConfigByIndex(i); if (cfg->storageDevice == CONFIG_STOREDEVICE_FLASH) { - spiFlash->targets[i].cfg = (S2S_TargetCfg*)cfg; + spiFlash->targets[i].cfg = (S2S_TargetCfg*)cfg; } else { spiFlash->targets[i].cfg = NULL; } - } + } - // Don't require the host to send us a START STOP UNIT command - spiFlash->dev.mediaState = MEDIA_STARTED; + // Don't require the host to send us a START STOP UNIT command + spiFlash->dev.mediaState = MEDIA_STARTED; } static void spiFlash_init(S2S_Device* dev) @@ -95,7 +101,7 @@ static void spiFlash_init(S2S_Device* dev) SpiFlash* spiFlash = (SpiFlash*)dev; spiFlash->capacity = 0; - nNOR_WP_Write(0); // Enable Write Protect + nNOR_WP_Write(1); // We don't need write Protect nNOR_CS_Write(1); // Deselect NOR_SPI_Start(); @@ -132,20 +138,19 @@ static void spiFlash_init(S2S_Device* dev) // Don't bother reading the rest. Deselecting will cancel the command. nNOR_CS_Write(1); // Deselect - } static S2S_Target* spiFlash_getTargets(S2S_Device* dev, int* count) { - SpiFlash* spiFlash = (SpiFlash*)dev; - *count = MAX_SCSI_TARGETS; - return spiFlash->targets; + SpiFlash* spiFlash = (SpiFlash*)dev; + *count = MAX_SCSI_TARGETS; + return spiFlash->targets; } static uint32_t spiFlash_getCapacity(S2S_Device* dev) { - SpiFlash* spiFlash = (SpiFlash*)dev; - return spiFlash->capacity; + SpiFlash* spiFlash = (SpiFlash*)dev; + return spiFlash->capacity; } static int spiFlash_pollMediaChange(S2S_Device* dev) @@ -156,6 +161,146 @@ static int spiFlash_pollMediaChange(S2S_Device* dev) static void spiFlash_pollMediaBusy(S2S_Device* dev) { - // Non-removable + // Non-removable +} + +static void spiFlash_WaitForWIP() +{ + int inProgress = 1; + while (inProgress) + { + nNOR_CS_Write(0); + uint8_t status = spiFlashByte(0x05); // Read Status Register 1; + inProgress = status & 1; + nNOR_CS_Write(1); + } +} + +static void spiFlash_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count) +{ + SpiFlash* spiFlash = (SpiFlash*)dev; + + nNOR_CS_Write(0); // Select + + // Send the WREN - Write Enable command + spiFlashByte(0x06); + + // We NEED to deselect the device now for writes to work + nNOR_CS_Write(1); + + // For now we assume 256kb sectors. This needs to be expanded to cater for + // different sector sizes. We safely assume it will always be >= 512 bytes. + const uint32_t flashSectorSize = 256*1024; + + // We don't have enough memory to do a read-modify-write cycle, so the caller + // had better line these up on sector boundaries. + for (uint32_t linearAddress = sectorNumber * 512; + linearAddress < (sectorNumber + count) * 512; + linearAddress += flashSectorSize) + { + nNOR_CS_Write(0); + + spiFlashByte(0xDC); + + // 4-byte address + spiFlashByte(linearAddress >> 24); + spiFlashByte(linearAddress >> 16); + spiFlashByte(linearAddress >> 8); + spiFlashByte(linearAddress); + + // Initiate erase + nNOR_CS_Write(1) + + spiFlash_WaitForWIP(); + } + + nNOR_CS_Write(0) + + // Send the WREN - Write Disable command + spiFlashByte(0x04); + + nNOR_CS_Write(1); // Deselect +} + +static void spiFlash_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer) +{ + SpiFlash* spiFlash = (SpiFlash*)dev; + + nNOR_CS_Write(0); // Select + + // Send the WREN - Write Enable command + spiFlashByte(0x06); + + // We NEED to deselect the device now for writes to work + nNOR_CS_Write(1); + + // We're assuming here that the page size is 512 bytes or more. + for (int i = 0; i < count; ++i) + { + nNOR_CS_Write(0); + + spiFlashByte(0x12); + + uint32_t linearAddress = (sectorNumber + i) * 512; + spiFlashByte(linearAddress >> 24); + spiFlashByte(linearAddress >> 16); + spiFlashByte(linearAddress >> 8); + spiFlashByte(linearAddress); + + for (int off = 0; off < 512; ++off) + { + spiFlashByte(buffer[i * 512 + off]); + } + + // Initiate write + nNOR_CS_Write(1) + + spiFlash_WaitForWIP(); + } + + nNOR_CS_Write(0) + + // Send the WREN - Write Disable command + spiFlashByte(0x04); + + nNOR_CS_Write(1); // Deselect +} + +static void spiFlash_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer) +{ + SpiFlash* spiFlash = (SpiFlash*)dev; + + nNOR_CS_Write(0); // Select + spiFlashByte(0x13); + + uint32_t linearAddress = sectorNumber * 512; + spiFlashByte(linearAddress >> 24); + spiFlashByte(linearAddress >> 16); + spiFlashByte(linearAddress >> 8); + spiFlashByte(linearAddress); + + // There's no harm in reading -extra- data, so keep the FIFO + // one step ahead. + NOR_SPI_WriteTxData(0xFF); + NOR_SPI_WriteTxData(0xFF); + NOR_SPI_WriteTxData(0xFF); + + for (int off = 0; off < count * 512; ++off) + { + NOR_SPI_WriteTxData(0xFF); + + while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {} + buffer[off] = NOR_SPI_ReadRxData(); + } + + // Read and discard the extra bytes of data. It was only used to improve + // performance with a full FIFO. + for (int i = 0; i < 3; ++i) + { + while (!(NOR_SPI_ReadRxStatus() & NOR_SPI_STS_RX_FIFO_NOT_EMPTY)) {} + NOR_SPI_ReadRxData(); + } + + nNOR_CS_Write(1); // Deselect } diff --git a/software/SCSI2SD/src/sd.c b/software/SCSI2SD/src/sd.c index abeac8e..1eb563e 100755 --- a/software/SCSI2SD/src/sd.c +++ b/software/SCSI2SD/src/sd.c @@ -34,6 +34,10 @@ static S2S_Target* sd_getTargets(S2S_Device* dev, int* count); static uint32_t sd_getCapacity(S2S_Device* dev); static int sd_pollMediaChange(S2S_Device* dev); static void sd_pollMediaBusy(S2S_Device* dev); +static void sd_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count); +static void sd_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer); +static void sd_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer); + // Global SdCard sdCard = { @@ -44,6 +48,9 @@ SdCard sdCard = { sd_getCapacity, sd_pollMediaChange, sd_pollMediaBusy, + sd_erase, + sd_read, + sd_write, 0, // initial mediaState CONFIG_STOREDEVICE_SD } @@ -1098,3 +1105,17 @@ static void sd_pollMediaBusy(S2S_Device* dev) sdCardDevice->lastPollMediaTime = getTime_ms(); } +static void sd_erase(S2S_Device* dev, uint32_t sectorNumber, uint32_t count) +{ + // TODO +} + +static void sd_read(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer) +{ + // TODO +} + +static void sd_write(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer) +{ + // TODO +} diff --git a/software/SCSI2SD/src/storedevice.h b/software/SCSI2SD/src/storedevice.h index a394ef6..4cd7735 100644 --- a/software/SCSI2SD/src/storedevice.h +++ b/software/SCSI2SD/src/storedevice.h @@ -76,6 +76,10 @@ struct S2S_DeviceStruct int (*pollMediaChange)(S2S_Device* dev); void (*pollMediaBusy)(S2S_Device* dev); + void (*erase)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count); + void (*read)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer); + void (*write)(S2S_Device* dev, uint32_t sectorNumber, uint32_t count, uint8_t* buffer); + MEDIA_STATE mediaState; CONFIG_STOREDEVICE deviceType; };