Files
microchip-application-bmd38…/gd25d10c.c
T

276 lines
6.2 KiB
C

#include "gd25d10c.h"
#include <string.h>
#if (DEF_GD25D10C_ENABLED)
#define ERASE_BLOCK_SIZE (32 * 1024)
#define ERASE_SECT_SIZE 4096
#define PROG_PAGE_SIZE 256
#define PAGE_PER_SECT 16
#define PAGE_PER_BLOCK 128
#define SECT_PER_BLOCK 8
#define BLOCK_PER_DEV 4
#define CMD_READ 0x03
#define CMD_WREN 0x06
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_WRSR 0x01
#define CMD_PP 0x02
#define CMD_RDID 0x9F
#define CMD_SE 0x20
#define CMD_BE 0x52
#define WIP_BIT 0x01
#define WEL_BIT 0x02
#define MANUFACTURER_ID 0xC8
#define MEMORY_TYPE 0x40
#define CAPACITY 0x11
#define EXPECT_ID ((MANUFACTURER_ID << 16) | (MEMORY_TYPE << 8) | (CAPACITY << 0))
uint8_t xfer_buf[4096 + 32];
static int read_data(uint8_t *p_dest, uint32_t addr, uint32_t size)
{
struct send
{
union
{
uint32_t val;
struct
{
uint32_t addr : 24;
uint32_t cmd : 8;
};
};
} *p_tx = (void *)xfer_buf;
struct recv
{
uint32_t dummy;
uint8_t recv[0];
} *p_rx = (void *)xfer_buf;
p_tx->cmd = CMD_READ;
p_tx->addr = addr;
p_tx->val = __REV(p_tx->val);
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), (void *)p_rx, offsetof(struct recv, recv) + size);
memcpy(p_dest, &xfer_buf[sizeof(*p_tx)], size);
return BLOCK_DEV_SUCCESS;
}
static void write_enable(void)
{
uint32_t tx = 0;
struct send
{
uint8_t cmd;
} *p_tx = (void *)&tx;
p_tx->cmd = CMD_WREN;
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), NULL, 0);
}
static void write_disable(void)
{
uint32_t tx = 0;
struct send
{
uint8_t cmd;
} *p_tx = (void *)&tx;
p_tx->cmd = CMD_WRDI;
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), NULL, 0);
}
static uint32_t read_status(void)
{
uint32_t tx = 0, rx = 0;
struct send
{
uint8_t cmd;
uint8_t dummy;
} *p_tx = (void *)&tx;
struct recv
{
uint8_t dummy;
uint8_t status;
} *p_rx = (void *)&rx;
p_tx->cmd = CMD_RDSR;
p_tx->dummy = 0xFF;
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), (void *)p_rx, offsetof(struct recv, status) + sizeof(p_rx->status));
return p_rx->status;
}
static void write_status(uint8_t stauts)
{
uint32_t tx = 0;
struct send
{
uint8_t cmd;
uint8_t stauts;
} *p_tx = (void *)&tx;
p_tx->cmd = CMD_RDSR;
p_tx->stauts = stauts;
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), NULL, 0);
}
static int page_prog(uint8_t *p_src, uint32_t addr, uint32_t page_cnt)
{
for (uint32_t i = 0; i < page_cnt; i++)
{
write_enable();
struct send
{
union
{
uint32_t val;
struct
{
uint32_t addr : 24;
uint32_t cmd : 8;
};
};
uint8_t data[256];
} *p_tx = (void *)xfer_buf;
p_tx->cmd = CMD_PP;
p_tx->addr = addr + PROG_PAGE_SIZE * i;
p_tx->val = __REV(p_tx->val);
memcpy(p_tx->data, (void *)(&p_src[PROG_PAGE_SIZE * i]), PROG_PAGE_SIZE);
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), NULL, 0);
do {
} while ((read_status() & WIP_BIT));
}
return BLOCK_DEV_SUCCESS;
}
int sect_erase(uint32_t addr, uint32_t sect_cnt)
{
for (uint32_t i = 0; i < sect_cnt; i++)
{
write_enable();
struct send
{
union
{
uint32_t val;
struct
{
uint32_t addr : 24;
uint32_t cmd : 8;
};
};
} *p_tx = (void *)xfer_buf;
p_tx->cmd = CMD_SE;
p_tx->addr = addr + i * ERASE_SECT_SIZE;
p_tx->val = __REV(p_tx->val);
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), NULL, 0);
do {
} while ((read_status() & WIP_BIT));
}
return BLOCK_DEV_SUCCESS;
}
int block_erase(uint32_t addr, uint32_t block_cnt)
{
for (uint32_t i = 0; i < block_cnt; i++)
{
write_enable();
struct send
{
union
{
uint32_t val;
struct
{
uint32_t addr : 24;
uint32_t cmd : 8;
};
};
} *p_tx = (void *)xfer_buf;
p_tx->cmd = CMD_BE;
p_tx->addr = addr + i * ERASE_BLOCK_SIZE;
p_tx->val = __REV(p_tx->val);
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), NULL, 0);
do {
} while ((read_status() & WIP_BIT));
}
return BLOCK_DEV_SUCCESS;
}
uint32_t dev_id(void)
{
uint32_t tx = 0, rx = 0;
struct send
{
uint32_t cmd : 8;
uint32_t dummy : 24;
} *p_tx = (void *)&tx;
p_tx->cmd = CMD_RDID;
p_tx->dummy = 0x000000;
struct recv
{
uint32_t dummy : 8;
uint32_t manufacturer : 8;
uint32_t memory_type : 8;
uint32_t capacity : 8;
} *p_rx = (void *)&rx;
spim_xfer(CS_MEM_PIN, NRF_SPIM_MODE_0, (void *)p_tx, sizeof(*p_tx), (void *)p_rx, sizeof(*p_rx));
return __REV(rx) & 0x00FFFFFF;
}
static int init(void)
{
uint32_t id = dev_id();
if (EXPECT_ID == id)
{
return BLOCK_DEV_SUCCESS;
}
return BLOCK_DEV_ERROR;
}
static int reset(void)
{
// Do nothing
return 0;
}
const block_dev_drv_if_t gd25d110c = {
.init = init,
.reset = reset,
.read_data = read_data,
.page_prog = page_prog,
.sect_erase = sect_erase,
.block_erase = block_erase,
.block_size = ERASE_BLOCK_SIZE,
.sect_size = ERASE_SECT_SIZE,
.sect_count = BLOCK_PER_DEV * SECT_PER_BLOCK,
.page_size = PROG_PAGE_SIZE,
.page_per_sect = (ERASE_SECT_SIZE / PROG_PAGE_SIZE)
};
#endif /* ! DEF_GD25D10C_ENABLED */