#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); }