[U-Boot] [PATCH v4 04/12] SPEAr : smi driver support for SPEAr SoCs

SPEAr SoCs contain a serial memory interface controller. This controller is used to interface with spi based memories. This patch adds the driver for this IP.
Signed-off-by: Vipin vipin.kumar@st.com --- drivers/mtd/Makefile | 1 + drivers/mtd/spr_smi.c | 529 ++++++++++++++++++++++++++++++++++ include/asm-arm/arch-spear/spr_smi.h | 117 ++++++++ 3 files changed, 647 insertions(+), 0 deletions(-) mode change 100644 => 100755 drivers/mtd/Makefile create mode 100755 drivers/mtd/spr_smi.c create mode 100755 include/asm-arm/arch-spear/spr_smi.h
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile old mode 100644 new mode 100755 index 754d648..cbf6f15 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -34,6 +34,7 @@ COBJS-$(CONFIG_FLASH_CFI_MTD) += cfi_mtd.o COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o COBJS-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o COBJS-$(CONFIG_MW_EEPROM) += mw_eeprom.o +COBJS-$(CONFIG_SPEARSMI) += spr_smi.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mtd/spr_smi.c b/drivers/mtd/spr_smi.c new file mode 100755 index 0000000..092e313 --- /dev/null +++ b/drivers/mtd/spr_smi.c @@ -0,0 +1,529 @@ +/* <snip> + +#if !defined(CONFIG_SYS_NO_FLASH) + +static struct smi_regs *const smicntl = + (struct smi_regs * const)CONFIG_SYS_SMI_BASE; +static ulong bank_base[CONFIG_SYS_MAX_FLASH_BANKS] = CONFIG_SYS_FLASH_ADDR_BASE; ws 80 chars per line
+flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; + +#define ST_M25Pxx_ID 0x00002020 + +static struct flash_dev flash_ids[] = { + {0x10, 64 * 1024, 2}, + {0x11, 128 * 1024, 4}, + {0x12, 256 * 1024, 4}, + {0x13, 512 * 1024, 8}, + {0x14, 1 * 1024 * 1024, 16}, + {0x15, 2 * 1024 * 1024, 32}, + {0x16, 4 * 1024 * 1024, 64}, + {0x17, 8 * 1024 * 1024, 128}, + {0x18, 16 * 1024 * 1024, 64}, + {0x00,} +}; + Could be accessed like { .densisty = xxx, .size = xxx, .sector_count = xxx, }
The 'density' field looks more like an id
+/* + * smi_wait_xfer_finish - Wait until TFF is set in status register + * @timeout: timeout in milliseconds + * + * Wait until TFF is set in status register + */ +static inline void smi_wait_xfer_finish(int timeout) +{ Inline ? Normally inline is for *.h files or maybe if you want something optimized. With the sleep, this isn't likely. Please justify or remove. Apply change globally.
+ while (timeout--) { + if (readl(&smicntl->smi_sr) & TFF) + break; + udelay(1000); + } +} +
A timeout implies failure. This function should return status And the status checked.
+/* + * smi_read_id - Read flash id + * @info: flash_info structure pointer + * @banknum: bank number + * + * Read the flash id present at bank #banknum + */ +static unsigned int smi_read_id(flash_info_t *info, int banknum) +{ + unsigned int value; + + writel(readl(&smicntl->smi_cr1) | SW_MODE, &smicntl->smi_cr1); + writel(READ_ID, &smicntl->smi_tr); + writel((banknum << BANKSEL_SHIFT) | SEND | TX_LEN_1 | RX_LEN_3, + &smicntl->smi_cr2); + smi_wait_xfer_finish(XFER_FINISH_TOUT); + + value = (readl(&smicntl->smi_rr) & 0x00FFFFFF); + + writel(readl(&smicntl->smi_sr) & ~(TFF), &smicntl->smi_sr); + writel(readl(&smicntl->smi_cr1) & ~(SW_MODE), &smicntl->smi_cr1); + Some of these '()''s are not strictly needed. optionally reduce
+ return value; +} + +/* + * flash_get_size - Detect the SMI flash by reading the ID. + * @base: Base address of the flash area bank #banknum + * @banknum: Bank number + * + * Detect the SMI flash by reading the ID. Initializes the flash_info structure + * with size, sector count etc. + */ +static ulong flash_get_size(ulong base, int banknum) +{ + flash_info_t *info = &flash_info[banknum]; + struct flash_dev *dev; + unsigned int value; + unsigned int density; + int i; + + value = smi_read_id(info, banknum); + density = (value >> 16) & 0xff; + + for (i = 0, dev = &flash_ids[0]; dev->density != 0x0; + i++, dev = &flash_ids[i]) { + if (dev->density == density) { + info->size = dev->size; + info->sector_count = dev->sector_count; + break; + } + } From the flash_ids's struct, it looks like 'density' field is unique and increasing by 1. You may be able to replay this loop with somthing like
density -= DENSITY_START if (density < 0) bail else if (density > DESITY_END) bail
then use desity as an index into the flash_ids array info->size = flash_ids[density].size
+ + if (0x0 == dev->density) + return 0; swap operands
+ + info->flash_id = value & 0xffff; + info->start[0] = base; + + return info->size; +} + +/* + * smi_read_sr - Read status register of SMI + * @bank: bank number + * + * This routine will get the status register of the flash chip present at the + * given bank + */ +static int smi_read_sr(int bank) +{ + u32 ctrlreg1; + + /* store the CTRL REG1 state */ + ctrlreg1 = readl(&smicntl->smi_cr1); + + /* Program SMI in HW Mode */ + writel(readl(&smicntl->smi_cr1) & ~(SW_MODE | WB_MODE), + &smicntl->smi_cr1); + + /* Performing a RSR instruction in HW mode */ + writel((bank << BANKSEL_SHIFT) | RD_STATUS_REG, &smicntl->smi_cr2); + + smi_wait_xfer_finish(XFER_FINISH_TOUT); + + /* Restore the CTRL REG1 state */ + writel(ctrlreg1, &smicntl->smi_cr1); + + return readl(&smicntl->smi_sr);
readl returns unsigned int you may have problems with returning this as an int.
+} + +/* + * smi_wait_till_ready - Wait till last operation is over. + * @bank: bank number shifted. + * @timeout: timeout in milliseconds. + * + * This routine checks for WIP(write in progress)bit in Status register(SMSR-b0) + * The routine checks for #timeout loops, each at interval of 1 milli-second. + * If successful the routine returns 0. + */ +static int smi_wait_till_ready(int bank, int timeout) +{ + int count; + int sr; + + /* One chip guarantees max 5 msec wait here after page writes, + but potentially three seconds (!) after page erase. */ + for (count = 0; count < timeout; count++) { + + sr = smi_read_sr(bank); + if (sr < 0) + break; + else if (!(sr & WIP_BIT)) + return 0; + + /* Try again after 1m-sec */ + udelay(1000); + } + printf("SMI controller is still in wait, timeout=%d\n", timeout); + return -EIO;
Always failure ?
+} + +/* + * smi_write_enable - Enable the flash to do write operation + * @bank: bank number + * + * Set write enable latch with Write Enable command. + * Returns negative if error occurred.
Only returns 0. please fix.
+ */ +static inline int smi_write_enable(int bank) +{
Inline ? See inline comments above
+ u32 ctrlreg1; + int timeout = WMODE_TOUT; + + /* Store the CTRL REG1 state */ + ctrlreg1 = readl(&smicntl->smi_cr1); + + /* Program SMI in H/W Mode */ + writel(readl(&smicntl->smi_cr1) & ~SW_MODE, &smicntl->smi_cr1); + + /* Give the Flash, Write Enable command */ + writel((bank << BANKSEL_SHIFT) | WE, &smicntl->smi_cr2); + + smi_wait_xfer_finish(XFER_FINISH_TOUT); + + /* Restore the CTRL REG1 state */ + writel(ctrlreg1, &smicntl->smi_cr1); + + while (timeout--) { + if (smi_read_sr(bank) & (1 << (bank + WM_SHIFT))) + break; + udelay(1000); + } + + return 0; +} + +/* + * smi_init - SMI initialization routine + * + * SMI initialization routine. Sets SMI control register1. + */ +static void smi_init(void) +{ + /* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */ + writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4, + &smicntl->smi_cr1); +} + +/* + * smi_sector_erase - Erase flash sector + * @info: flash_info structure pointer + * @sector: sector number + * + * Set write enable latch with Write Enable command. + * Returns negative if error occurred. + */ +static int smi_sector_erase(flash_info_t *info, unsigned int sector) +{ + int bank; + unsigned int sect_add; + unsigned int instruction; + + switch (info->start[0]) { + case SMIBANK0_BASE: + bank = BANK0; + break; + case SMIBANK1_BASE: + bank = BANK1; + break; + case SMIBANK2_BASE: + bank = BANK2; + break; + case SMIBANK3_BASE: + bank = BANK3; + break; + default: + return -1; + } + + sect_add = sector * (info->size / info->sector_count); + instruction = ((sect_add >> 8) & 0x0000FF00) | SECTOR_ERASE; + + writel(readl(&smicntl->smi_sr) & ~(ERF1 | ERF2), &smicntl->smi_sr); + + if (info->flash_id == ST_M25Pxx_ID) { + /* Wait until finished previous write command. */ + if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT)) + return -EBUSY; + + /* Send write enable, before erase commands. */ + if (smi_write_enable(bank)) + return -EIO; + + /* Put SMI in SW mode */ + writel(readl(&smicntl->smi_cr1) | SW_MODE, &smicntl->smi_cr1); + + /* Send Sector Erase command in SW Mode */ + writel(instruction, &smicntl->smi_tr); + writel((bank << BANKSEL_SHIFT) | SEND | TX_LEN_4, + &smicntl->smi_cr2); + smi_wait_xfer_finish(XFER_FINISH_TOUT); + + if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT)) + return -EBUSY; + + /* Put SMI in HW mode */ + writel(readl(&smicntl->smi_cr1) & ~(SW_MODE), + &smicntl->smi_cr1); + + return 0; + } else { + /* Put SMI in HW mode */ + writel(readl(&smicntl->smi_cr1) & ~(SW_MODE), + &smicntl->smi_cr1); + return -EINVAL; + } +} + +/* + * smi_write - Write to SMI flash + * @src_addr: source buffer + * @dst_addr: destination buffer + * @length: length to write in words + * @bank: bank base address + * + * Write to SMI flash + */ +static int smi_write(unsigned int *src_addr, unsigned int *dst_addr, + unsigned int length, ulong bank_addr) +{ + int banknum; + unsigned int WM; + + switch (bank_addr) { + case SMIBANK0_BASE: + banknum = BANK0; + WM = WM0; + break; + case SMIBANK1_BASE: + banknum = BANK1; + WM = WM1; + break; + case SMIBANK2_BASE: + banknum = BANK2; + WM = WM2; + break; + case SMIBANK3_BASE: + banknum = BANK3; + WM = WM3; + break; + default: + return -1; + } + + if (smi_wait_till_ready(banknum, CONFIG_SYS_FLASH_WRITE_TOUT)) + return -EBUSY; + + /* Set SMI in Hardware Mode */ + writel(readl(&smicntl->smi_cr1) & ~(SW_MODE), &smicntl->smi_cr1); + + if (smi_write_enable(banknum)) + return -EIO; + + /* Perform the write command */ + while (length--) { + if (((ulong) (dst_addr) % SFLASH_PAGE_SIZE) == 0) { + if (smi_wait_till_ready(banknum, + CONFIG_SYS_FLASH_WRITE_TOUT)) + return -EBUSY; + + if (smi_write_enable(banknum)) + return -EIO; + } + + *dst_addr++ = *src_addr++; + + if ((readl(&smicntl->smi_sr) & (ERF1 | ERF2))) + return -EIO; + } + + if (smi_wait_till_ready(banknum, CONFIG_SYS_FLASH_WRITE_TOUT)) + return -EBUSY; + + writel(readl(&smicntl->smi_sr) & ~(WCF), &smicntl->smi_sr); + + return 0; +} + +/* + * write_buff - Write to SMI flash + * @info: flash info structure + * @src: source buffer + * @dest_addr: destination buffer + * @length: length to write in words + * + * Write to SMI flash + */ +int write_buff(flash_info_t *info, uchar *src, ulong dest_addr, ulong length) +{ + smi_write((unsigned int *)src, (unsigned int *)dest_addr, + (length + 3) / 4, info->start[0]); smi_write returns status. This status should be returned to the callee. + return 0; +} + +/* + * flash_init - SMI flash initialization + * + * SMI flash initialization + */ +unsigned long flash_init(void) +{ + unsigned long size = 0; + int i, j; + + smi_init(); + + for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { + flash_info[i].flash_id = FLASH_UNKNOWN; + size += flash_info[i].size = flash_get_size(bank_base[i], i); + } + + for (j = 0; j < CONFIG_SYS_MAX_FLASH_BANKS; j++) { + for (i = 1; i < flash_info[j].sector_count; i++) + flash_info[j].start[i] = + flash_info[j].start[i - 1] + + flash_info->size / flash_info->sector_count; + + } + + return size; +} + +/* + * flash_print_info - Print SMI flash information + * + * Print SMI flash information + */ +void flash_print_info(flash_info_t *info) +{ + int i; + if (info->flash_id == FLASH_UNKNOWN) { + puts("missing or unknown FLASH type\n"); + return; + } + printf(" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + + puts(" Sector Start Addresses:"); + for (i = 0; i < info->sector_count; ++i) { +#ifdef CONFIG_SYS_FLASH_EMPTY_INFO + int size; + int erased; + u32 *flash; + + /* + * Check if whole sector is erased + */ + size = (info->size) / (info->sector_count); + flash = (u32 *) info->start[i]; + size = size / sizeof(int); + + while ((size--) && (*flash++ == ~0)) + ; + + size++; + if (size) + erased = 0; + else + erased = 1; + + if ((i % 5) == 0) + printf("\n"); + + printf(" %08lX%s%s", + info->start[i], + erased ? " E" : " ", info->protect[i] ? "RO " : " "); +#else + if ((i % 5) == 0) + printf("\n "); + printf(" %08lX%s", + info->start[i], info->protect[i] ? " (RO) " : " "); +#endif + } + putc('\n'); + return; +} + +/* + * flash_erase - Erase SMI flash + * + * Erase SMI flash + */ +int flash_erase(flash_info_t *info, int s_first, int s_last) +{ + int rcode = 0; + int prot = 0; + flash_sect_t sect; + + if (info->flash_id == FLASH_UNKNOWN) { + puts("Can't erase unknown flash type - aborted\n"); + return 1; + } + + if ((s_first < 0) || (s_first > s_last)) { + puts("- no sectors to erase\n"); + return 1; + } + + for (sect = s_first; sect <= s_last; ++sect) { + if (info->protect[sect]) + prot++; + } + if (prot) { + printf("- Warning: %d protected sectors will not be erased!\n", + prot); + } else { + putc('\n'); + } + + for (sect = s_first; sect <= s_last; sect++) { + if (info->protect[sect] == 0) { + switch (info->flash_id) { + case ST_M25Pxx_ID: + if (smi_sector_erase(info, sect)) + rcode = 1; + else + putc('.'); + + break; + + default: + printf("Unkown flash vendor 0x%x\n", + (u32) info->flash_id); + break; This check can happen outside of the loop and likely earlier in the function so you can bail earlier. + } + } + } + puts(" done\n"); + return rcode; +} +#endif diff --git a/include/asm-arm/arch-spear/spr_smi.h b/include/asm-arm/arch-spear/spr_smi.h new file mode 100755 index 0000000..a42a874 --- /dev/null +++ b/include/asm-arm/arch-spear/spr_smi.h @@ -0,0 +1,117 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef SPR_SMI_H +#define SPR_SMI_H + +/* 0xF800.0000 . 0xFBFF.FFFF 64MB SMI (Serial Flash Mem) */ +/* 0xFC00.0000 . 0xFC1F.FFFF 2MB SMI (Serial Flash Reg.) */ + +#define SMI_BASE CONFIG_SYS_SMI_BASE ws some extra spaces in the line above please use tabs
+ +#define FLASH_START_ADDRESS CONFIG_SYS_FLASH_BASE +#define FLASH_BANK_SIZE CONFIG_SYS_FLASH_BANK_SIZE + +#define SMIBANK0_BASE (FLASH_START_ADDRESS) +#define SMIBANK1_BASE (SMIBANK0_BASE + FLASH_BANK_SIZE) +#define SMIBANK2_BASE (SMIBANK1_BASE + FLASH_BANK_SIZE) +#define SMIBANK3_BASE (SMIBANK2_BASE + FLASH_BANK_SIZE) ws some extra spaces in the 4 lines above please use tabs + +#define BANK0 0 +#define BANK1 1 +#define BANK2 2 +#define BANK3 3 + +struct smi_regs { + u32 smi_cr1; + u32 smi_cr2; + u32 smi_sr; + u32 smi_tr; + u32 smi_rr; +}; + +/* CONTROL REG 1 */ +#define BANK_EN 0x0000000F /* enables all banks */ +#define DSEL_TIME 0x00000060 /* Deselect time 6+1 SMI_CK periods */ +#define PRESCAL5 0x00000500 /* AHB_CK prescaling value */ +#define PRESCALA 0x00000A00 /* AHB_CK prescaling value */ +#define PRESCAL3 0x00000300 /* AHB_CK prescaling value */ +#define PRESCAL4 0x00000400 /* AHB_CK prescaling value */ +#define SW_MODE 0x10000000 /* enables SW Mode */ +#define WB_MODE 0x20000000 /* Write Burst Mode */ +#define FAST_MODE 0x00008000 /* Fast Mode */ +#define HOLD1 0x00010000 ws Convert spaces to tabs Similar from the next sections, apply this globally
+ +/* CONTROL REG 2 */ +#define RD_STATUS_REG 0x00000400 /* reads status reg */ +#define WE 0x00000800 /* Write Enable */ +#define BANK0_SEL 0x00000000 /* Select Banck0 */ +#define BANK1_SEL 0x00001000 /* Select Banck1 */ +#define BANK2_SEL 0x00002000 /* Select Banck2 */ +#define BANK3_SEL 0x00003000 /* Select Banck3 */ +#define BANKSEL_SHIFT 12 +#define SEND 0x00000080 /* Send data */ +#define TX_LEN_1 0x00000001 /* data length = 1 byte */ +#define TX_LEN_2 0x00000002 /* data length = 2 byte */ +#define TX_LEN_3 0x00000003 /* data length = 3 byte */ +#define TX_LEN_4 0x00000004 /* data length = 4 byte */ +#define RX_LEN_1 0x00000010 /* data length = 1 byte */ +#define RX_LEN_2 0x00000020 /* data length = 2 byte */ +#define RX_LEN_3 0x00000030 /* data length = 3 byte */ +#define RX_LEN_4 0x00000040 /* data length = 4 byte */ +#define TFIE 0x00000100 /* Transmission Flag Interrupt Enable */ +#define WCIE 0x00000200 /* Write Complete Interrupt Enable */ + +/* STATUS_REG */ +#define INT_WCF_CLR 0xFFFFFDFF /* clear: WCF clear */ +#define INT_TFF_CLR 0xFFFFFEFF /* clear: TFF clear */ +#define WIP_BIT 0x00000001 /* WIP Bit of SPI SR on SMI SR */ +#define WEL_BIT 0x00000002 /* WEL Bit of SPI SR on SMI SR */ +#define RSR 0x00000005 /* Read Status regiser */ +#define TFF 0x00000100 /* Transfer Finished FLag */ +#define WCF 0x00000200 /* Transfer Finished FLag */ +#define ERF1 0x00000400 /* Error Flag 1 */ +#define ERF2 0x00000800 /* Error Flag 2 */ +#define WM0 0x00001000 /* WM Bank 0 */ +#define WM1 0x00002000 /* WM Bank 1 */ +#define WM2 0x00004000 /* WM Bank 2 */ +#define WM3 0x00008000 /* WM Bank 3 */ +#define WM_SHIFT 12 + +/* TR REG */ +#define READ_ID 0x0000009F /* Read Identification */ +#define BULK_ERASE 0x000000C7 /* BULK erase */ +#define SECTOR_ERASE 0x000000D8 /* SECTOR erase */ +#define WRITE_ENABLE 0x00000006 /* Wenable command to FLASH */ + +struct flash_dev { + u32 density; + ulong size; + ushort sector_count; +}; + +#define SFLASH_PAGE_SIZE 0x100 +#define XFER_FINISH_TOUT 2 +#define WMODE_TOUT 2 + A comment on these variables would help.
Tom

Hello Tom,
+#define ST_M25Pxx_ID 0x00002020
+static struct flash_dev flash_ids[] = {
- {0x10, 64 * 1024, 2},
- {0x11, 128 * 1024, 4},
- {0x12, 256 * 1024, 4},
- {0x13, 512 * 1024, 8},
- {0x14, 1 * 1024 * 1024, 16},
- {0x15, 2 * 1024 * 1024, 32},
- {0x16, 4 * 1024 * 1024, 64},
- {0x17, 8 * 1024 * 1024, 128},
- {0x18, 16 * 1024 * 1024, 64},
- {0x00,}
+};
Could be accessed like { .densisty = xxx, .size = xxx, .sector_count = xxx, }
This is meant to be a look up table, that's why I think the previous way is batter. Actually, I got the inspiration from drivers/mtd/nand/nand_ids.c Still, I have changed it to look as below {0x10, 0x10000, 2}, {0x11, 0x20000, 4}, {0x12, 0x40000, 4}, {0x13, 0x80000, 8}, size is changed to hex to stay vertically aligned Please let me know if this is OK
- Detect the SMI flash by reading the ID. Initializes the flash_info structure
- with size, sector count etc.
- */
+static ulong flash_get_size(ulong base, int banknum) +{
- flash_info_t *info = &flash_info[banknum];
- struct flash_dev *dev;
- unsigned int value;
- unsigned int density;
- int i;
- value = smi_read_id(info, banknum);
- density = (value >> 16) & 0xff;
- for (i = 0, dev = &flash_ids[0]; dev->density != 0x0;
- i++, dev = &flash_ids[i]) {
- if (dev->density == density) {
- info->size = dev->size;
- info->sector_count = dev->sector_count;
- break;
- }
- }
From the flash_ids's struct, it looks like 'density' field is unique and increasing by 1. You may be able to replay this loop with somthing like
density -= DENSITY_START if (density < 0) bail else if (density > DESITY_END) bail
then use desity as an index into the flash_ids array info->size = flash_ids[density].size
density is one byte of the read id which is read from flash itself as of now, we are supporting consecutive values but these values may be rendom in future Thats why I used a look up table
+static int smi_wait_till_ready(int bank, int timeout) +{
- int count;
- int sr;
- /* One chip guarantees max 5 msec wait here after page writes,
- but potentially three seconds (!) after page erase. */
- for (count = 0; count < timeout; count++) {
- sr = smi_read_sr(bank);
- if (sr < 0)
- break;
- else if (!(sr & WIP_BIT))
- return 0;
- /* Try again after 1m-sec */
- udelay(1000);
- }
- printf("SMI controller is still in wait, timeout=%d\n", timeout);
- return -EIO;
Always failure ?
There is a return 0 in case WIP_BIT gets reset else if (!(sr & WIP_BIT)) return 0;
All the other comments are accepted and I would send a patchset v5 soon
Regards Vipin

Vipin Kumar wrote:
Hello Tom,
+#define ST_M25Pxx_ID 0x00002020
+static struct flash_dev flash_ids[] = {
{0x10, 64 * 1024, 2},
{0x11, 128 * 1024, 4},
{0x12, 256 * 1024, 4},
{0x13, 512 * 1024, 8},
{0x14, 1 * 1024 * 1024, 16},
{0x15, 2 * 1024 * 1024, 32},
{0x16, 4 * 1024 * 1024, 64},
{0x17, 8 * 1024 * 1024, 128},
{0x18, 16 * 1024 * 1024, 64},
{0x00,}
+};
Could be accessed like { .densisty = xxx, .size = xxx, .sector_count = xxx, }
This is meant to be a look up table, that's why I think the previous way is batter. Actually, I got the inspiration from drivers/mtd/nand/nand_ids.c Still, I have changed it to look as below {0x10, 0x10000, 2}, {0x11, 0x20000, 4}, {0x12, 0x40000, 4}, {0x13, 0x80000, 8}, size is changed to hex to stay vertically aligned Please let me know if this is OK
This is fine. Improved readability a plus!
- Detect the SMI flash by reading the ID. Initializes the flash_info structure
- with size, sector count etc.
- */
+static ulong flash_get_size(ulong base, int banknum) +{
flash_info_t *info = &flash_info[banknum];
struct flash_dev *dev;
unsigned int value;
unsigned int density;
int i;
value = smi_read_id(info, banknum);
density = (value >> 16) & 0xff;
for (i = 0, dev = &flash_ids[0]; dev->density != 0x0;
i++, dev = &flash_ids[i]) {
if (dev->density == density) {
info->size = dev->size;
info->sector_count = dev->sector_count;
break;
}
}
From the flash_ids's struct, it looks like 'density' field is unique and increasing by 1. You may be able to replay this loop with somthing like
density -= DENSITY_START if (density < 0) bail else if (density > DESITY_END) bail
then use desity as an index into the flash_ids array info->size = flash_ids[density].size
density is one byte of the read id which is read from flash itself as of now, we are supporting consecutive values but these values may be rendom in future Thats why I used a look up table
Ok.
+static int smi_wait_till_ready(int bank, int timeout) +{
int count;
int sr;
/* One chip guarantees max 5 msec wait here after page writes,
but potentially three seconds (!) after page erase. */
for (count = 0; count < timeout; count++) {
sr = smi_read_sr(bank);
if (sr < 0)
break;
else if (!(sr & WIP_BIT))
return 0;
/* Try again after 1m-sec */
udelay(1000);
}
printf("SMI controller is still in wait, timeout=%d\n", timeout);
return -EIO;
Always failure ?
There is a return 0 in case WIP_BIT gets reset else if (!(sr & WIP_BIT)) return 0;
Sorry missed that
Tom
All the other comments are accepted and I would send a patchset v5 soon
Regards Vipin
participants (2)
-
Tom
-
Vipin Kumar