diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2007-07-05 18:01:45 +0200 |
---|---|---|
committer | Sascha Hauer <sha@octopus.labnet.pengutronix.de> | 2007-07-05 18:01:45 +0200 |
commit | 52f6ce11a944e74af1df556e02212061474bd40b (patch) | |
tree | cea8857a937ddc27a8e50b305294c6d7ab0e09a6 /drivers/cfi_flash_amd.c | |
parent | cc43d146a811e8807ba30c2c10a3e0318290b80f (diff) | |
download | barebox-52f6ce11a944e74af1df556e02212061474bd40b.tar.gz barebox-52f6ce11a944e74af1df556e02212061474bd40b.tar.xz |
svn_rev_351
Diffstat (limited to 'drivers/cfi_flash_amd.c')
-rw-r--r-- | drivers/cfi_flash_amd.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/cfi_flash_amd.c b/drivers/cfi_flash_amd.c new file mode 100644 index 0000000000..21150db619 --- /dev/null +++ b/drivers/cfi_flash_amd.c @@ -0,0 +1,158 @@ +#include <cfi_flash.h> + +static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) +{ + flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START); + flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK); +} + +/*----------------------------------------------------------------------- + * read jedec ids from device and set corresponding fields in info struct + * + * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct + * +*/ +static void amd_read_jedec_ids (flash_info_t * info) +{ + info->manufacturer_id = 0; + info->device_id = 0; + info->device_id2 = 0; + + flash_write_cmd(info, 0, 0, AMD_CMD_RESET); + flash_unlock_seq(info, 0); + flash_write_cmd(info, 0, AMD_ADDR_START, FLASH_CMD_READ_ID); + udelay(1000); /* some flash are slow to respond */ + info->manufacturer_id = flash_read_uchar (info, + FLASH_OFFSET_MANUFACTURER_ID); + info->device_id = flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID); + if (info->device_id == 0x7E) { + /* AMD 3-byte (expanded) device ids */ + info->device_id2 = flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID2); + info->device_id2 <<= 8; + info->device_id2 |= flash_read_uchar (info, + FLASH_OFFSET_DEVICE_ID3); + } + flash_write_cmd(info, 0, 0, AMD_CMD_RESET); +} + +static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + + cptr.cp = flash_make_addr (info, sect, offset); + flash_make_cmd (info, cmd, &cword); + switch (info->portwidth) { + case FLASH_CFI_8BIT: + retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); + break; + case FLASH_CFI_16BIT: + retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); + break; + case FLASH_CFI_32BIT: + retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); + break; + case FLASH_CFI_64BIT: + retval = ((cptr.llp[0] & cword.ll) != + (cptr.llp[0] & cword.ll)); + break; + default: + retval = 0; + break; + } + return retval; +} + +/* + * flash_is_busy - check to see if the flash is busy + * This routine checks the status of the chip and returns true if the chip is busy + */ +static int amd_flash_is_busy (flash_info_t * info, flash_sect_t sect) +{ + return flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); +} + +static int amd_flash_erase_one (flash_info_t * info, long sect) +{ + int rcode = 0; + + flash_unlock_seq (info, sect); + flash_write_cmd (info, sect, AMD_ADDR_ERASE_START, + AMD_CMD_ERASE_START); + flash_unlock_seq (info, sect); + flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR); + + if (flash_status_check + (info, sect, info->erase_blk_tout, "erase")) { + rcode = 1; + } else + putc ('.'); + return rcode; +} + +static void amd_flash_prepare_write(flash_info_t * info) +{ + flash_unlock_seq (info, 0); + flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE); +} + +#ifdef CONFIG_CFI_BUFFER_WRITE +static int amd_flash_write_cfibuffer (flash_info_t * info, ulong dest, const uchar * cp, + int len) +{ + flash_sect_t sector; + int cnt; + int retcode; + volatile cfiptr_t src; + volatile cfiptr_t dst; + + src.cp = (uchar *)cp; + dst.cp = (uchar *) dest; + sector = find_sector (info, dest); + + flash_unlock_seq(info,0); + flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); + + switch (info->portwidth) { + case FLASH_CFI_8BIT: + cnt = len; + flash_write_cmd (info, sector, 0, (uchar) cnt - 1); + while (cnt-- > 0) *dst.cp++ = *src.cp++; + break; + case FLASH_CFI_16BIT: + cnt = len >> 1; + flash_write_cmd (info, sector, 0, (uchar) cnt - 1); + while (cnt-- > 0) *dst.wp++ = *src.wp++; + break; + case FLASH_CFI_32BIT: + cnt = len >> 2; + flash_write_cmd (info, sector, 0, (uchar) cnt - 1); + while (cnt-- > 0) *dst.lp++ = *src.lp++; + break; + case FLASH_CFI_64BIT: + cnt = len >> 3; + flash_write_cmd (info, sector, 0, (uchar) cnt - 1); + while (cnt-- > 0) *dst.llp++ = *src.llp++; + break; + default: + return ERR_INVAL; + } + + flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); + retcode = flash_status_check (info, sector, info->buffer_write_tout, + "buffer write"); + return retcode; +} +#endif /* CONFIG_CFI_BUFFER_WRITE */ + +struct cfi_cmd_set cfi_cmd_set_amd = { + .flash_write_cfibuffer = amd_flash_write_cfibuffer, + .flash_erase_one = amd_flash_erase_one, + .flash_is_busy = amd_flash_is_busy, + .flash_read_jedec_ids = amd_read_jedec_ids, + .flash_prepare_write = amd_flash_prepare_write, +}; + |