--- /dev/null
+#include "projectconfig.h"
+#include "diskio.h"
+#include "iobase.h"
+#include "core/ssp/ssp.h"
+
+#include <r0ketports.h>
+
+/* Opcodes */
+#define OP_POWERDOWN (0xB9)
+#define OP_RESUME (0xAB)
+#define OP_PAGEREAD (0xD2)
+#define OP_BUFFER1READ (0xD1) /* Low Frequency (<=33MHz) */
+#define OP_BUFFER2READ (0xD3) /* Low Frequency (<=33MHz) */
+#define OP_BUFFER1WRITE (0x84)
+#define OP_BUFFER2WRITE (0x87)
+#define OP_BUFFER1PROG (0x83) /* with builtin erase */
+#define OP_BUFFER2PROG (0x86) /* with builtin erase */
+#define OP_STATUSREAD (0xD7)
+#define OP_DEVICEID (0x9F)
+#define OP_PAGE2BUFFER1 (0x53)
+#define OP_PAGE2BUFFER2 (0x55)
+#define OP_BUFFER1PAGECMP (0x60)
+#define OP_BUFFER2PAGECMP (0x61)
+#define OP_AUTOREWRITE1 (0x58) /* Auto Page Rewrite throught Buffer 1 */
+#define OP_AUTOREWRITE2 (0x59) /* Auto Page Rewrite throught Buffer 2 */
+
+#define SB_READY (1 << 7)
+#define SB_COMP (1 << 6)
+#define SB_PROTECT (1 << 1)
+#define SB_PAGESIZE (1 << 0)
+
+#define MAX_PAGE (2048)
+
+#define CS_LOW() gpioSetValue(RB_SPI_CS_DF, 0)
+#define CS_HIGH() gpioSetValue(RB_SPI_CS_DF, 1)
+
+static volatile DSTATUS status = STA_NOINIT;
+
+static void wait_for_ready() {
+ BYTE reg_status = 0xFF;
+
+ CS_LOW();
+ xmit_spi(OP_STATUSREAD);
+ do {
+ rcvr_spi_m((uint8_t *) ®_status);
+ } while (!(reg_status & SB_READY));
+ CS_HIGH();
+}
+
+static void dataflash_powerdown() {
+ CS_LOW();
+ xmit_spi(OP_POWERDOWN);
+ CS_HIGH();
+}
+
+static void dataflash_resume() {
+ CS_LOW();
+ xmit_spi(OP_RESUME);
+ CS_HIGH();
+}
+
+DSTATUS dataflash_initialize() {
+ sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
+
+ gpioSetDir(RB_SPI_CS_DF, gpioDirection_Output);
+
+ dataflash_resume();
+ status &= ~STA_NOINIT;
+ return status;
+}
+
+DSTATUS dataflash_status() {
+ return status;
+}
+
+DRESULT dataflash_random_read(BYTE *buff, DWORD offset, DWORD length) {
+ if (!length) return RES_PARERR;
+ if (status & STA_NOINIT) return RES_NOTRDY;
+ if (offset+length > MAX_PAGE*256) return RES_PARERR;
+
+ do {
+ wait_for_ready();
+ DWORD pageaddr = ((offset/256) << 9) | (offset%256);
+ DWORD remaining = 256 - offset%256;
+ if (remaining > length) {
+ remaining = length;
+ }
+ length -= remaining;
+ offset += remaining;
+
+ CS_LOW();
+ xmit_spi(OP_PAGEREAD);
+ xmit_spi((BYTE)(pageaddr >> 16));
+ xmit_spi((BYTE)(pageaddr >> 8));
+ xmit_spi((BYTE)pageaddr);
+ xmit_spi(0x00); // follow up with 4 don't care bytes
+ xmit_spi(0x00);
+ xmit_spi(0x00);
+ xmit_spi(0x00);
+ do {
+ rcvr_spi_m(buff++);
+ } while (--remaining);
+ CS_HIGH();
+ } while (length);
+
+ return length ? RES_ERROR : RES_OK;
+}
+
+DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count) {
+ return dataflash_random_read(buff, sector*512, count*512);
+}
+
+#if _READONLY == 0
+DRESULT dataflash_random_write(const BYTE *buff, DWORD offset, DWORD length) {
+ if (!length) return RES_PARERR;
+ if (status & STA_NOINIT) return RES_NOTRDY;
+ if (offset+length > MAX_PAGE*256) return RES_PARERR;
+
+ do {
+ wait_for_ready();
+ DWORD pageaddr = (offset/256) << 9;
+ DWORD buffaddr = (offset%256);
+ DWORD remaining = 256 - offset%256;
+ if (remaining > length) {
+ remaining = length;
+ }
+ length -= remaining;
+ offset += remaining;
+
+ // read page into the internal buffer
+ CS_LOW();
+ xmit_spi(OP_PAGE2BUFFER1);
+ xmit_spi((BYTE)(pageaddr >> 16));
+ xmit_spi((BYTE)(pageaddr >> 8));
+ xmit_spi((BYTE)pageaddr);
+ CS_HIGH();
+ wait_for_ready();
+
+ // write bytes into the dataflash buffer
+ CS_LOW();
+ xmit_spi(OP_BUFFER1WRITE);
+ xmit_spi((BYTE)(buffaddr >> 16));
+ xmit_spi((BYTE)(buffaddr >> 8));
+ xmit_spi((BYTE)buffaddr);
+ do {
+ xmit_spi(*buff++);
+ } while (--remaining);
+ CS_HIGH();
+ wait_for_ready();
+
+ // compare buffer with target memory page
+ CS_LOW();
+ xmit_spi(OP_BUFFER1PAGECMP);
+ xmit_spi((BYTE)(pageaddr >> 16));
+ xmit_spi((BYTE)(pageaddr >> 8));
+ xmit_spi((BYTE)pageaddr);
+ CS_HIGH();
+ wait_for_ready();
+ CS_LOW();
+ BYTE reg_status = 0xFF;
+ xmit_spi(OP_STATUSREAD);
+ rcvr_spi_m((uint8_t *) ®_status);
+ CS_HIGH();
+
+ // trigger program only if data changed
+ if (reg_status & SB_COMP) {
+ CS_LOW();
+ xmit_spi(OP_BUFFER1PROG);
+ xmit_spi((BYTE)(pageaddr >> 16));
+ xmit_spi((BYTE)(pageaddr >> 8));
+ xmit_spi((BYTE)pageaddr);
+ CS_HIGH();
+ }
+ } while (length);
+
+ return length ? RES_ERROR : RES_OK;
+}
+
+DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count) {
+ return dataflash_random_write(buff, sector*512, count*512);
+}
+#endif /* _READONLY */
+
+#if _USE_IOCTL != 0
+DRESULT dataflash_ioctl(BYTE ctrl, void *buff) {
+ DRESULT res;
+ BYTE *ptr = buff;
+
+ res = RES_ERROR;
+
+
+ if (ctrl == CTRL_POWER) {
+ switch (*ptr) {
+ case 0: /* Sub control code == 0 (POWER_OFF) */
+ dataflash_powerdown();
+ res = RES_OK;
+ break;
+ case 1: /* Sub control code == 1 (POWER_ON) */
+ dataflash_resume();
+ res = RES_OK;
+ break;
+ case 2: /* Sub control code == 2 (POWER_GET) */
+ // TODO: figure out a way to retrieve the powerstate
+ *(ptr+1) = (BYTE)1;
+ res = RES_OK;
+ break;
+ default :
+ res = RES_PARERR;
+ }
+ } else {
+ if (status & STA_NOINIT) return RES_NOTRDY;
+
+ switch (ctrl) {
+ case CTRL_SYNC:
+ wait_for_ready();
+ res = RES_OK;
+ break;
+ case GET_SECTOR_COUNT:
+ // TODO: read from device ID register
+ *(WORD*)buff = MAX_PAGE/2;
+ res = RES_OK;
+ break;
+ case GET_SECTOR_SIZE:
+ *(WORD*)buff = 512;
+ res = RES_OK;
+ break;
+ case GET_BLOCK_SIZE:
+ *(WORD*)buff = 1;
+ res = RES_OK;
+ break;
+ default:
+ res = RES_PARERR;
+ }
+ }
+
+ return res;
+}
+#endif /* _USE_IOCTL != 0 */
+
+DWORD get_fattime () {
+ return 0;
+ /*
+ struct tm* tm=mygmtime(getSeconds());
+ DWORD t= (((tm->tm_year-80)<<9)|
+ ((tm->tm_mon+1)<<5)|
+ (tm->tm_mday))<<16 |
+ ((tm->tm_hour<<11)|
+ (tm->tm_min<<5)|
+ (tm->tm_sec>>1));
+ return t;
+ */
+}