summaryrefslogtreecommitdiffstats
path: root/drivers/cfi_flash_amd.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:01:45 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:01:45 +0200
commit52f6ce11a944e74af1df556e02212061474bd40b (patch)
treecea8857a937ddc27a8e50b305294c6d7ab0e09a6 /drivers/cfi_flash_amd.c
parentcc43d146a811e8807ba30c2c10a3e0318290b80f (diff)
downloadbarebox-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.c158
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,
+};
+