diff options
Diffstat (limited to 'meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0012-mtd-m25p80-add-support-for-AAI-programming-with-SST-.patch')
-rw-r--r-- | meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0012-mtd-m25p80-add-support-for-AAI-programming-with-SST-.patch | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0012-mtd-m25p80-add-support-for-AAI-programming-with-SST-.patch b/meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0012-mtd-m25p80-add-support-for-AAI-programming-with-SST-.patch new file mode 100644 index 0000000..e726dc7 --- /dev/null +++ b/meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0012-mtd-m25p80-add-support-for-AAI-programming-with-SST-.patch @@ -0,0 +1,179 @@ +From 49aac4aec53c523f16343b4668a5a239b69659f1 Mon Sep 17 00:00:00 2001 +From: Graf Yang <graf.yang@analog.com> +Date: Mon, 15 Jun 2009 08:23:41 +0000 +Subject: [PATCH 012/130] mtd: m25p80: add support for AAI programming with SST + SPI flashes + +The SST SPI flashes are a bit non-standard in that they can be programmed +one byte at a time (including address!), or they can be written two bytes +at a time with auto address incrementing (AAI). The latter form is +obviously much better for performance, so let's use it when possible. + +Signed-off-by: Graf Yang <graf.yang@analog.com> +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> +--- + drivers/mtd/devices/m25p80.c | 126 ++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 125 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c +index 6d8d265..53de9f0 100644 +--- a/drivers/mtd/devices/m25p80.c ++++ b/drivers/mtd/devices/m25p80.c +@@ -44,6 +44,11 @@ + #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ + #define OPCODE_RDID 0x9f /* Read JEDEC ID */ + ++/* Used for SST flashes only. */ ++#define OPCODE_BP 0x02 /* Byte program */ ++#define OPCODE_WRDI 0x04 /* Write disable */ ++#define OPCODE_AAI_WP 0xad /* Auto address increment word program */ ++ + /* Status Register bits. */ + #define SR_WIP 1 /* Write in progress */ + #define SR_WEL 2 /* Write enable latch */ +@@ -132,6 +137,15 @@ static inline int write_enable(struct m25p *flash) + return spi_write_then_read(flash->spi, &code, 1, NULL, 0); + } + ++/* ++ * Send write disble instruction to the chip. ++ */ ++static inline int write_disable(struct m25p *flash) ++{ ++ u8 code = OPCODE_WRDI; ++ ++ return spi_write_then_read(flash->spi, &code, 1, NULL, 0); ++} + + /* + * Service routine to read status register until ready, or timeout occurs. +@@ -454,6 +468,111 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, + return 0; + } + ++static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t *retlen, const u_char *buf) ++{ ++ struct m25p *flash = mtd_to_m25p(mtd); ++ struct spi_transfer t[2]; ++ struct spi_message m; ++ size_t actual; ++ int cmd_sz, ret; ++ ++ if (retlen) ++ *retlen = 0; ++ ++ /* sanity checks */ ++ if (!len) ++ return 0; ++ ++ if (to + len > flash->mtd.size) ++ return -EINVAL; ++ ++ spi_message_init(&m); ++ memset(t, 0, (sizeof t)); ++ ++ t[0].tx_buf = flash->command; ++ t[0].len = CMD_SIZE; ++ spi_message_add_tail(&t[0], &m); ++ ++ t[1].tx_buf = buf; ++ spi_message_add_tail(&t[1], &m); ++ ++ mutex_lock(&flash->lock); ++ ++ /* Wait until finished previous write command. */ ++ ret = wait_till_ready(flash); ++ if (ret) ++ goto time_out; ++ ++ write_enable(flash); ++ ++ actual = to % 2; ++ /* Start write from odd address. */ ++ if (actual) { ++ flash->command[0] = OPCODE_BP; ++ flash->command[1] = to >> 16; ++ flash->command[2] = to >> 8; ++ flash->command[3] = to; ++ ++ /* write one byte. */ ++ t[1].len = 1; ++ spi_sync(flash->spi, &m); ++ ret = wait_till_ready(flash); ++ if (ret) ++ goto time_out; ++ *retlen += m.actual_length - CMD_SIZE; ++ } ++ to += actual; ++ ++ flash->command[0] = OPCODE_AAI_WP; ++ flash->command[1] = to >> 16; ++ flash->command[2] = to >> 8; ++ flash->command[3] = to; ++ ++ /* Write out most of the data here. */ ++ cmd_sz = CMD_SIZE; ++ for (; actual < len - 1; actual += 2) { ++ t[0].len = cmd_sz; ++ /* write two bytes. */ ++ t[1].len = 2; ++ t[1].tx_buf = buf + actual; ++ ++ spi_sync(flash->spi, &m); ++ ret = wait_till_ready(flash); ++ if (ret) ++ goto time_out; ++ *retlen += m.actual_length - cmd_sz; ++ cmd_sz = 1; ++ to += 2; ++ } ++ write_disable(flash); ++ ret = wait_till_ready(flash); ++ if (ret) ++ goto time_out; ++ ++ /* Write out trailing byte if it exists. */ ++ if (actual != len) { ++ write_enable(flash); ++ flash->command[0] = OPCODE_BP; ++ flash->command[1] = to >> 16; ++ flash->command[2] = to >> 8; ++ flash->command[3] = to; ++ t[0].len = CMD_SIZE; ++ t[1].len = 1; ++ t[1].tx_buf = buf + actual; ++ ++ spi_sync(flash->spi, &m); ++ ret = wait_till_ready(flash); ++ if (ret) ++ goto time_out; ++ *retlen += m.actual_length - CMD_SIZE; ++ write_disable(flash); ++ } ++ ++time_out: ++ mutex_unlock(&flash->lock); ++ return ret; ++} + + /****************************************************************************/ + +@@ -670,7 +789,12 @@ static int __devinit m25p_probe(struct spi_device *spi) + flash->mtd.size = info->sector_size * info->n_sectors; + flash->mtd.erase = m25p80_erase; + flash->mtd.read = m25p80_read; +- flash->mtd.write = m25p80_write; ++ ++ /* sst flash chips use AAI word program */ ++ if (info->jedec_id >> 16 == 0xbf) ++ flash->mtd.write = sst_write; ++ else ++ flash->mtd.write = m25p80_write; + + /* prefer "small sector" erase if possible */ + if (info->flags & SECT_4K) { +-- +1.8.1 + |