📄 pflash.c
字号:
} for (ii = 0; ii < (length-3); ii+=4, data+=4) { *(RMuint32 *)data = gbus_read_remapped_uint32(h, pcfi->gbus_address + addroffs) ; addroffs+=4; } while ((length & 0x3) > 0) { *(RMuint8 *)(data++) = gbus_read_remapped_uint8(h, pcfi->gbus_address + addroffs); addroffs++; length--; } } return RM_OK;}/******************************************* RMstatus flash_write_data(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint8 *data, RMuint32 length, void(*cb_usleep)(struct gbus*, RMuint32))** Description :* Write a region of specified parallel flash chip ** Input parameters:* pcfi: Pointer to parallel flash structure* addroffs: start offset address of parallel flash write region (0 - pflash size)* *data: source address of write data* length: write length** Return values:* OK: operation successful; * fail: error message******************************************/#define UNLOCKBYPASSPROGRAM_UNITBITS 12 // 2^12 = 4KBRMstatus flash_write_data(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint8 *data, RMuint32 length, void(*cb_usleep)(struct gbus*, RMuint32)){ RMint32 len = length; RMint32 maxbufwords, nwords; RMuint32 addr = addroffs + pcfi->gbus_address; RMstatus rc; RMint32 prtloop=0; if (!pcfi->exist) return RM_NOT_FOUND; rc = flash_writable(h, addr, len); if( rc != RM_OK) return rc ; if (addr & 0x01) { rc = flash_write_onebyte(h, pcfi, addr++, *data++, cb_usleep); if( rc != RM_OK) return rc ; --len; } if (pcfi->ident.max_multibyte_write == 0) maxbufwords = 1 << (UNLOCKBYPASSPROGRAM_UNITBITS - 1); else maxbufwords = 1 << (pcfi->ident.max_multibyte_write - 1); //prints '.' after this block is written, 0x1000 RMDBGPRINT((LOCALDBG,".")); while (len > 1) { //RMDBGPRINT((LOCALDBG,"$")); nwords = (len >> 1); //((len + 1) >> 1); if (nwords > maxbufwords) nwords = maxbufwords; rc = flash_write_data_internal(h, addr, (RMuint16 *) data, nwords, pcfi, cb_usleep); if( rc != RM_OK) return rc ; nwords <<= 1; addr += nwords; data += nwords; len -= nwords; prtloop += nwords; if(prtloop >= 0x800) { RMDBGPRINT((LOCALDBG,".")); prtloop -= 0x800; } } if (len == 1) { rc = flash_write_onebyte(h, pcfi, addr, *data, cb_usleep); if( rc != RM_OK) return rc ; } return RM_OK;}RMstatus flash_save_write_data(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint32 ramaddr, RMuint32 length, void(*cb_usleep)(struct gbus*, RMuint32)){ RMuint32 start, blocksize; RMuint32 wraddr,wrlen; RMuint32 prtloop=0; if (length == 0) return RM_OK; if (!pcfi->exist) return RM_NOT_FOUND; if( flash_writable(h, pcfi->gbus_address + addroffs, length) == RM_OK) { if( flash_write_data(h, pcfi, addroffs, (RMuint8 *)ramaddr, length, cb_usleep) != RM_OK) return RM_ERROR; else return RM_OK; } // need erase first if (flash_calcblock(h, pcfi, addroffs, &start, &blocksize) < 0) return RM_NOT_FOUND; do { if (blocksize > MAXREGIONSIZE) { RMDBGPRINT((LOCALDBG,"Please increase save buffer size!!\n")); return !RM_OK; } flash_read_data(h, pcfi, start, savebuf, blocksize); wraddr = addroffs - start; wrlen = (length <= blocksize - wraddr ? length : blocksize - wraddr ); memcpy( &savebuf[wraddr], (RMuint8 *)ramaddr, wrlen); if( flash_erase_oneblock(h, pcfi, start + pcfi->gbus_address, cb_usleep) != RM_OK) return RM_ERROR; if( flash_write_data(h, pcfi, start, savebuf, blocksize, cb_usleep) != RM_OK) return RM_ERROR; start += blocksize; if (flash_calcblock(h, pcfi, start, &start, &blocksize) < 0) break; ramaddr += wrlen; addroffs += wrlen; length -= wrlen; prtloop += blocksize; if(prtloop >= 0x40000) { RMDBGPRINT((LOCALDBG,"\n")); prtloop -= 0x40000; } } while (start < addroffs + length); return RM_OK;}/******************************************* RMint32 flash_calcblock(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint32 *pstart, RMuint32 *plen)** Description :* Calculate the block start address and length of parallel flash at given address offset* It can be used to calculate the block address and length that will be erased.** Input parameters:* pcfi: Pointer to parallel flash structure* addroffs: offset address of parallel flash * *pstart: point to block start address* *plen: point to block length** Return values:* OK: operation successful; * fail: error message******************************************/RMint32 flash_calcblock(struct gbus *h, cfi_info *pcfi, RMuint32 addroffs, RMuint32 *pstart, RMuint32 *plen){ RMint32 i; if (!pcfi->exist) return RM_NOT_FOUND; *pstart = 0; *plen = 0; for (i = pcfi->ident.num_erase_regions - 1; i >= 0; --i) { if (addroffs >= pcfi->erase_regions[i].start) { *pstart = pcfi->erase_regions[i].start; *plen = pcfi->erase_regions[i].size; addroffs -= *pstart; while (addroffs >= *plen) { addroffs -= *plen; *pstart += *plen; } return 0; } } return -1;}/************************************************************************ * Implementation : Static functions ************************************************************************/static void dqx_wait(struct gbus *h, RMuint32 addr, RMuint32 buswidth, RMuint32 datum, RMuint32 wait, void(*cb_usleep)(struct gbus *,RMuint32)){ RMuint32 dq6, dq5; RMuint32 status, oldstatus, res; unsigned int waitloop=0; dq6 = cfi_build_cmd(1<<6,buswidth); dq5 = cfi_build_cmd(1<<5,buswidth); (*cb_usleep)(h,wait); oldstatus = cfi_read(h,addr,buswidth); status = cfi_read(h,addr,buswidth); if((buswidth==CFIDEV_BUSWIDTH_16) && (datum==0xff)) { oldstatus &= 0xff; status &= 0xff; } if (flash_wait_div <= 1) res = wait; else res = wait/flash_wait_div; while ((status != datum) || (((status & dq6) != (oldstatus & dq6)) && ((status & dq5) != dq5))) { (*cb_usleep)(h,res); oldstatus = cfi_read(h,addr,buswidth); status = cfi_read(h,addr,buswidth); if(waitloop==5) { RMDBGPRINT((LOCALDBG,"pflash write/erase timeout fails.\n")); break; } else { RMDBGPRINT((LOCALDBG,"*")); waitloop++; } }}//// CFI basic I/O//static RMuint32 cfi_read(struct gbus *h, RMuint32 addr, RMuint32 bwidth){ RMuint32 data; switch (bwidth) { case CFIDEV_BUSWIDTH_8 : data = gbus_read_remapped_uint8(h, addr); break; case CFIDEV_BUSWIDTH_16 : data = gbus_read_remapped_uint16(h, addr); break; case CFIDEV_BUSWIDTH_32 : data = gbus_read_remapped_uint32(h, addr); break; default : return 0; } RMDBGLOG((DISABLE,"FLASH Read addr = 0x%x, data = 0x%x\n", addr, data)); return data;}static void cfi_write(struct gbus *h, RMuint32 bwidth, RMuint32 val, RMuint32 addr){ RMDBGLOG((DISABLE,"FLASH Write addr = %08lx, data = 0x%x\n", addr, val)); switch (bwidth) { case CFIDEV_BUSWIDTH_8 : gbus_write_remapped_uint8(h, addr, val); break; case CFIDEV_BUSWIDTH_16 : gbus_write_remapped_uint16(h, addr, val); break; case CFIDEV_BUSWIDTH_32 : gbus_write_remapped_uint32(h, addr, val); break; default : return; }}// // CFI advanced I/O//// bus width address => byte addressstatic RMuint32 cfi_build_cmd_addr(RMuint32 addr){ return addr * CFIDEV_DEVTYPE * CFIDEV_INTERLEAVE;}static RMuint32 cfi_build_cmd(RMuint32 cmd, RMuint32 bwidth){ RMuint32 val = 0; switch (bwidth) { case CFIDEV_BUSWIDTH_8 : val = cmd; break; case CFIDEV_BUSWIDTH_16 : if (CFIDEV_INTERLEAVE == 1) val = cpu_to_cfi16(cmd); else if (CFIDEV_INTERLEAVE == 2) val = cpu_to_cfi16((cmd << 8) | cmd); break; case CFIDEV_BUSWIDTH_32 : if (CFIDEV_INTERLEAVE == 1) val = cpu_to_cfi32(cmd); else if (CFIDEV_INTERLEAVE == 2) val = cpu_to_cfi32((cmd << 16) | cmd); else if (CFIDEV_INTERLEAVE == 4) { val = (cmd << 16) | cmd; val = cpu_to_cfi32((val << 8) | val); } break; default : break; } return val;}static void cfi_send_cmd(struct gbus *h, RMuint32 bwidth, RMuint32 cmd, RMuint32 cmd_addr, RMuint32 base){ cfi_write(h, bwidth, cfi_build_cmd(cmd,bwidth), base + cmd_addr);}//// probing & setup// static RMstatus cfi_probe_chip(struct gbus *h, cfi_info *pcfi){ RMint32 ret; RMuint32 addr_probe1, addr_probe2; RMuint32 data_probe1, data_probe2; addr_probe1 = pcfi->gbus_address + cfi_build_cmd_addr(0); addr_probe2 = pcfi->gbus_address + cfi_build_cmd_addr(0x55); data_probe1 = cfi_read(h, addr_probe1, pcfi->buswidth); data_probe2 = cfi_read(h, addr_probe2, pcfi->buswidth); // Reset cfi_send_cmd(h, pcfi->buswidth, 0xf0, 0, pcfi->gbus_address); // Enter CFI Query mode cfi_send_cmd(h, pcfi->buswidth, 0x98, cfi_build_cmd_addr(0x55), pcfi->gbus_address); if ((ret = cfi_query_present(h, pcfi->gbus_address, pcfi->buswidth)) != RM_OK) { cfi_write(h, pcfi->buswidth, data_probe1, addr_probe1); cfi_write(h, pcfi->buswidth, data_probe2, addr_probe2); return ret; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -