mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 11:06:49 +01:00
324 lines
6.2 KiB
C
324 lines
6.2 KiB
C
#include "asmUtil.h"
|
|
#include "screen.h"
|
|
#include "eeprom.h"
|
|
#include "printf.h"
|
|
#include "board.h"
|
|
#include "cpu.h"
|
|
|
|
static uint32_t __xdata mEepromSize;
|
|
static uint8_t __xdata mOpcodeErz4K = 0, mOpcodeErz32K = 0, mOpcodeErz64K = 0;
|
|
|
|
//extern uint8_t __xdata* tempBuffer;
|
|
uint8_t __xdata tempBufferE[320] = {0};
|
|
|
|
uint32_t eepromGetSize(void)
|
|
{
|
|
return mEepromSize;
|
|
}
|
|
|
|
void eepromReadStart(uint32_t addr) __reentrant
|
|
{
|
|
eepromPrvSelect();
|
|
eepromByte(0x03);
|
|
eepromByte(addr >> 16);
|
|
eepromByte(addr >> 8);
|
|
eepromByte(addr & 0xff);
|
|
}
|
|
|
|
void eepromRead(uint32_t addr, void __xdata *dstP, uint16_t len) __reentrant
|
|
{
|
|
uint8_t __xdata *dst = (uint8_t __xdata*)dstP;
|
|
|
|
eepromPrvSelect();
|
|
eepromByte(0x03);
|
|
eepromByte(addr >> 16);
|
|
eepromByte(addr >> 8);
|
|
eepromByte(addr & 0xff);
|
|
|
|
while (len--)
|
|
*dst++ = eepromByte(0);
|
|
eepromPrvDeselect();
|
|
}
|
|
|
|
static void eepromPrvSimpleCmd(uint8_t cmd)
|
|
{
|
|
eepromPrvSelect();
|
|
eepromByte(cmd);
|
|
eepromPrvDeselect();
|
|
}
|
|
|
|
static bool eepromPrvBusyWait(void)
|
|
{
|
|
uint8_t val;
|
|
|
|
eepromPrvSelect();
|
|
eepromByte(0x05);
|
|
while ((val = eepromByte(0x00)) & 1);
|
|
eepromPrvDeselect();
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool eepromWriteLL(uint32_t addr, const void __xdata *srcP, uint16_t len)
|
|
{
|
|
const uint8_t __xdata *src = (const uint8_t __xdata*)srcP;
|
|
|
|
eepromPrvSimpleCmd(0x06);
|
|
|
|
eepromPrvSelect();
|
|
eepromByte(0x02);
|
|
eepromByte(addr >> 16);
|
|
eepromByte(addr >> 8);
|
|
eepromByte(addr & 0xff);
|
|
|
|
while (len--)
|
|
eepromByte(*src++);
|
|
eepromPrvDeselect();
|
|
|
|
return eepromPrvBusyWait();
|
|
}
|
|
|
|
void eepromDeepPowerDown(void)
|
|
{
|
|
eepromPrvSimpleCmd(0xb9);
|
|
}
|
|
|
|
static void eepromPrvWakeFromPowerdown(void)
|
|
{
|
|
eepromPrvSimpleCmd(0xab);
|
|
}
|
|
|
|
#pragma callee_saves eepromPrvSfdpRead
|
|
static void eepromPrvSfdpRead(uint16_t ofst, uint8_t __xdata *dst, uint8_t len)
|
|
{
|
|
eepromPrvSelect();
|
|
eepromByte(0x5a); //cmd
|
|
eepromByte(0); //addr
|
|
eepromByte(ofst >> 8);
|
|
eepromByte(ofst);
|
|
eepromByte(0x00); //dummy
|
|
while(len--)
|
|
*dst++ = eepromByte(0);
|
|
eepromPrvDeselect();
|
|
}
|
|
|
|
__bit eepromInit(void)
|
|
{
|
|
uint8_t __xdata buf[8];
|
|
uint8_t i, nParamHdrs;
|
|
|
|
eepromPrvWakeFromPowerdown();
|
|
|
|
//process SFDP
|
|
|
|
eepromPrvSfdpRead(0, buf, 8);
|
|
if (buf[0] != 0x53 || buf[1] != 0x46 || buf[2] != 0x44 || buf[3] != 0x50 || buf[7] != 0xff) {
|
|
pr("SFDP: header not found\n");
|
|
|
|
__bit valid = false;
|
|
|
|
//try manual ID for chips we know of
|
|
eepromPrvSelect();
|
|
eepromByte(0x90);
|
|
eepromByte(0x00);
|
|
eepromByte(0x00);
|
|
eepromByte(0x00);
|
|
if (eepromByte(0) == 0xc2) { //old macronix chips
|
|
valid = true;
|
|
mOpcodeErz4K = 0x20;
|
|
switch (eepromByte(0)) {
|
|
case 0x05: //MX25V512
|
|
mEepromSize = 0x00010000ul;
|
|
break;
|
|
|
|
case 0x12: //MX25V4005
|
|
mEepromSize = 0x00080000ul;
|
|
break;
|
|
|
|
default:
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
eepromPrvDeselect();
|
|
|
|
return valid;
|
|
}
|
|
if (buf[5] != 0x01) {
|
|
pr("SFDP: version wrong: %u.%d\n", buf[5], buf[4]);
|
|
return false;
|
|
}
|
|
nParamHdrs = buf[6];
|
|
if (nParamHdrs == 0xff) //that case is very unlikely and we just do not care
|
|
nParamHdrs--;
|
|
|
|
//now we need to find the JEDEC parameter table header
|
|
for (i = 0; i <= nParamHdrs; i++) {
|
|
|
|
eepromPrvSfdpRead(mathPrvMul8x8(i, 8) + 8, buf, 8);
|
|
if (buf[0] == 0x00 && buf[2] == 0x01 && buf[3] >= 9) {
|
|
|
|
uint8_t j;
|
|
|
|
eepromPrvSfdpRead(*(uint16_t __xdata*)(buf + 4), tempBufferE, 9 * 4);
|
|
if ((tempBufferE[0] & 3) != 1) {
|
|
pr("SFDP: no 4K ERZ\n");
|
|
break;
|
|
}
|
|
if (!(tempBufferE[0] & 0x04)) {
|
|
pr("SFDP: no large write buf\n");
|
|
break;
|
|
}
|
|
if ((tempBufferE[2] & 0x06)) {
|
|
pr("SFDP: addr.len != 3\n");
|
|
break;
|
|
}
|
|
|
|
if (!tempBufferE[1] || tempBufferE[1] == 0xff) {
|
|
pr("SFDP: 4K ERZ opcode invalid\n");
|
|
break;
|
|
}
|
|
mOpcodeErz4K = tempBufferE[1];
|
|
|
|
if (tempBufferE[7] & 0x80) {
|
|
|
|
pr("SFDP: device too big\n");
|
|
break;
|
|
}
|
|
else {
|
|
|
|
uint8_t t;
|
|
|
|
if (t = tempBufferE[7])
|
|
mEepromSize = 0x00200000UL;
|
|
else if (t = tempBufferE[6])
|
|
mEepromSize = 0x00002000UL;
|
|
else if (t = tempBufferE[5])
|
|
mEepromSize = 0x00000020UL;
|
|
else {
|
|
pr("SFDP: device so small?!\n");
|
|
break;
|
|
}
|
|
|
|
while (t) {
|
|
mEepromSize <<= 1;
|
|
t >>= 1;
|
|
}
|
|
}
|
|
|
|
//get erase opcodes
|
|
for (j = 0x1c; j < 0x24; j += 2) {
|
|
uint8_t instr = tempBufferE[j + 1];
|
|
|
|
if (!instr || instr == 0xff)
|
|
continue;
|
|
|
|
switch (tempBufferE[j]) {
|
|
case 0x0c:
|
|
if (mOpcodeErz4K != instr) {
|
|
pr("4K ERZ opcode disagreement\n");
|
|
return false;
|
|
}
|
|
break;
|
|
|
|
case 0x0f: //32K erase
|
|
mOpcodeErz32K = instr;
|
|
break;
|
|
|
|
case 0x10: //64K erase
|
|
mOpcodeErz64K = instr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
pr("EEPROM accepted\n");
|
|
pr(" ERZ opcodes: \n");
|
|
if (mOpcodeErz4K)
|
|
pr(" 4K: %02xh\n", mOpcodeErz4K);
|
|
if (mOpcodeErz32K)
|
|
pr(" 32K: %02xh\n", mOpcodeErz32K);
|
|
if (mOpcodeErz64K)
|
|
pr(" 64K: %02xh\n", mOpcodeErz64K);
|
|
pr(" Size: 0x%*08lx\n", (uint16_t)&mEepromSize);
|
|
*/
|
|
return true;
|
|
}
|
|
}
|
|
|
|
pr("SFDP: no JEDEC table of expected version found\n");
|
|
return false;
|
|
}
|
|
|
|
bool eepromWrite(uint32_t addr, const void __xdata *srcP, uint16_t len) __reentrant
|
|
{
|
|
const uint8_t __xdata *src = (const uint8_t __xdata*)srcP;
|
|
|
|
while (len) {
|
|
|
|
uint16_t lenNow = EEPROM_WRITE_PAGE_SZ - (addr & (EEPROM_WRITE_PAGE_SZ - 1));
|
|
|
|
if (lenNow > len)
|
|
lenNow = len;
|
|
|
|
if (!eepromWriteLL(addr, src, lenNow))
|
|
return false;
|
|
|
|
addr += lenNow;
|
|
src += lenNow;
|
|
len -= lenNow;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool eepromErase(uint32_t addr, uint16_t nSec) __reentrant
|
|
{
|
|
uint8_t now;
|
|
|
|
if (((uint16_t)addr) & 0x0fff)
|
|
return false;
|
|
|
|
for (;nSec; nSec -= now) {
|
|
|
|
eepromPrvSimpleCmd(0x06);
|
|
eepromPrvSelect();
|
|
|
|
if (nSec >= 16 && !(uint16_t)addr && mOpcodeErz64K) { //erase 64K
|
|
|
|
eepromByte(mOpcodeErz64K);
|
|
now = 16;
|
|
}
|
|
else if (nSec >= 8 && !(((uint16_t)addr) & 0x7fff) && mOpcodeErz32K) { //erase 32K
|
|
|
|
eepromByte(mOpcodeErz32K);
|
|
now = 8;
|
|
}
|
|
else { //erase 4K
|
|
|
|
eepromByte(mOpcodeErz4K);
|
|
now = 1;
|
|
}
|
|
|
|
eepromByte(addr >> 16);
|
|
eepromByte(addr >> 8);
|
|
eepromByte(addr);
|
|
eepromPrvDeselect();
|
|
|
|
if (!eepromPrvBusyWait())
|
|
return false;
|
|
|
|
addr += mathPrvMul16x8(EEPROM_ERZ_SECTOR_SZ, now);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void eepromOtpModeEnter(void)
|
|
{
|
|
eepromPrvSimpleCmd(0xb1);
|
|
}
|
|
|
|
void eepromOtpModeExit(void)
|
|
{
|
|
eepromPrvSimpleCmd(0xc1);
|
|
} |