X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmtd%2Fst_smi.c;h=208119c5f06e74342e85e3991deacb10f248967f;hb=45fe3809b9923b92f221d70eb45ae071059fd5e0;hp=088c7c7b7c5c0f52c40fac863852b05e3eb02522;hpb=0befe7d7a396339067ccb7018ab69a097ff62cf4;p=oweals%2Fu-boot.git diff --git a/drivers/mtd/st_smi.c b/drivers/mtd/st_smi.c index 088c7c7b7c..208119c5f0 100644 --- a/drivers/mtd/st_smi.c +++ b/drivers/mtd/st_smi.c @@ -2,23 +2,7 @@ * (C) Copyright 2009 * Vipin Kumar, ST Microelectronics, 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 + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -37,19 +21,61 @@ static ulong bank_base[CONFIG_SYS_MAX_FLASH_BANKS] = CONFIG_SYS_FLASH_ADDR_BASE; flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; -#define ST_M25Pxx_ID 0x00002020 - -static struct flash_dev flash_ids[] = { - {0x10, 0x10000, 2}, /* 64K Byte */ - {0x11, 0x20000, 4}, /* 128K Byte */ - {0x12, 0x40000, 4}, /* 256K Byte */ - {0x13, 0x80000, 8}, /* 512K Byte */ - {0x14, 0x100000, 16}, /* 1M Byte */ - {0x15, 0x200000, 32}, /* 2M Byte */ - {0x16, 0x400000, 64}, /* 4M Byte */ - {0x17, 0x800000, 128}, /* 8M Byte */ - {0x18, 0x1000000, 64}, /* 16M Byte */ - {0x00,} +/* data structure to maintain flash ids from different vendors */ +struct flash_device { + char *name; + u8 erase_cmd; + u32 device_id; + u32 pagesize; + unsigned long sectorsize; + unsigned long size_in_bytes; +}; + +#define FLASH_ID(n, es, id, psize, ssize, size) \ +{ \ + .name = n, \ + .erase_cmd = es, \ + .device_id = id, \ + .pagesize = psize, \ + .sectorsize = ssize, \ + .size_in_bytes = size \ +} + +/* + * List of supported flash devices. + * Currently the erase_cmd field is not used in this driver. + */ +static struct flash_device flash_devices[] = { + FLASH_ID("st m25p16" , 0xd8, 0x00152020, 0x100, 0x10000, 0x200000), + FLASH_ID("st m25p32" , 0xd8, 0x00162020, 0x100, 0x10000, 0x400000), + FLASH_ID("st m25p64" , 0xd8, 0x00172020, 0x100, 0x10000, 0x800000), + FLASH_ID("st m25p128" , 0xd8, 0x00182020, 0x100, 0x40000, 0x1000000), + FLASH_ID("st m25p05" , 0xd8, 0x00102020, 0x80 , 0x8000 , 0x10000), + FLASH_ID("st m25p10" , 0xd8, 0x00112020, 0x80 , 0x8000 , 0x20000), + FLASH_ID("st m25p20" , 0xd8, 0x00122020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m25p40" , 0xd8, 0x00132020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m25p80" , 0xd8, 0x00142020, 0x100, 0x10000, 0x100000), + FLASH_ID("st m45pe10" , 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), + FLASH_ID("st m45pe20" , 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m45pe40" , 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m45pe80" , 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl004" , 0xd8, 0x00120201, 0x100, 0x10000, 0x80000), + FLASH_ID("sp s25fl008" , 0xd8, 0x00130201, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl016" , 0xd8, 0x00140201, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl032" , 0xd8, 0x00150201, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl064" , 0xd8, 0x00160201, 0x100, 0x10000, 0x800000), + FLASH_ID("mac 25l512" , 0xd8, 0x001020C2, 0x010, 0x10000, 0x10000), + FLASH_ID("mac 25l1005" , 0xd8, 0x001120C2, 0x010, 0x10000, 0x20000), + FLASH_ID("mac 25l2005" , 0xd8, 0x001220C2, 0x010, 0x10000, 0x40000), + FLASH_ID("mac 25l4005" , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000), + FLASH_ID("mac 25l4005a" , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000), + FLASH_ID("mac 25l8005" , 0xd8, 0x001420C2, 0x010, 0x10000, 0x100000), + FLASH_ID("mac 25l1605" , 0xd8, 0x001520C2, 0x100, 0x10000, 0x200000), + FLASH_ID("mac 25l1605a" , 0xd8, 0x001520C2, 0x010, 0x10000, 0x200000), + FLASH_ID("mac 25l3205" , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000), + FLASH_ID("mac 25l3205a" , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000), + FLASH_ID("mac 25l6405" , 0xd8, 0x001720C2, 0x100, 0x10000, 0x800000), + FLASH_ID("wbd w25q128" , 0xd8, 0x001840EF, 0x100, 0x10000, 0x1000000), }; /* @@ -60,11 +86,15 @@ static struct flash_dev flash_ids[] = { */ static int smi_wait_xfer_finish(int timeout) { - do { + ulong start = get_timer(0); + + while (get_timer(start) < timeout) { if (readl(&smicntl->smi_sr) & TFF) return 0; - udelay(1000); - } while (timeout--); + + /* Try after 10 ms */ + udelay(10); + }; return -1; } @@ -107,9 +137,7 @@ static unsigned int smi_read_id(flash_info_t *info, int banknum) static ulong flash_get_size(ulong base, int banknum) { flash_info_t *info = &flash_info[banknum]; - struct flash_dev *dev; int value; - unsigned int density; int i; value = smi_read_id(info, banknum); @@ -119,24 +147,20 @@ static ulong flash_get_size(ulong base, int banknum) return 0; } - density = (value >> 16) & 0xff; + /* Matches chip-id to entire list of 'serial-nor flash' ids */ + for (i = 0; i < ARRAY_SIZE(flash_devices); i++) { + if (flash_devices[i].device_id == value) { + info->size = flash_devices[i].size_in_bytes; + info->flash_id = value; + info->start[0] = base; + info->sector_count = + info->size/flash_devices[i].sectorsize; - 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; + return info->size; } } - if (dev->density == 0x0) - return 0; - - info->flash_id = value & 0xffff; - info->start[0] = base; - - return info->size; + return 0; } /* @@ -148,7 +172,7 @@ static ulong flash_get_size(ulong base, int banknum) */ static int smi_read_sr(int bank) { - u32 ctrlreg1; + u32 ctrlreg1, val; /* store the CTRL REG1 state */ ctrlreg1 = readl(&smicntl->smi_cr1); @@ -163,10 +187,12 @@ static int smi_read_sr(int bank) if (smi_wait_xfer_finish(XFER_FINISH_TOUT)) return -1; + val = readl(&smicntl->smi_sr); + /* Restore the CTRL REG1 state */ writel(ctrlreg1, &smicntl->smi_cr1); - return readl(&smicntl->smi_sr); + return val; } /* @@ -181,18 +207,17 @@ static int smi_read_sr(int bank) static int smi_wait_till_ready(int bank, int timeout) { int sr; + ulong start = get_timer(0); /* One chip guarantees max 5 msec wait here after page writes, but potentially three seconds (!) after page erase. */ - do { + while (get_timer(start) < timeout) { sr = smi_read_sr(bank); - if (sr < 0) - continue; /* try until timeout */ - else if (!(sr & WIP_BIT)) + if ((sr >= 0) && (!(sr & WIP_BIT))) return 0; - /* Try again after 1m-sec */ - udelay(1000); + /* Try again after 10 usec */ + udelay(10); } while (timeout--); printf("SMI controller is still in wait, timeout=%d\n", timeout); @@ -209,6 +234,7 @@ static int smi_wait_till_ready(int bank, int timeout) static int smi_write_enable(int bank) { u32 ctrlreg1; + u32 start; int timeout = WMODE_TOUT; int sr; @@ -227,16 +253,15 @@ static int smi_write_enable(int bank) /* Restore the CTRL REG1 state */ writel(ctrlreg1, &smicntl->smi_cr1); - do { + start = get_timer(0); + while (get_timer(start) < timeout) { sr = smi_read_sr(bank); - if (sr < 0) - break; - else if (sr & (1 << (bank + WM_SHIFT))) + if ((sr >= 0) && (sr & (1 << (bank + WM_SHIFT)))) return 0; - /* Try again after 1m-sec */ - udelay(1000); - } while (timeout--); + /* Try again after 10 usec */ + udelay(10); + }; return -1; } @@ -289,46 +314,39 @@ static int smi_sector_erase(flash_info_t *info, unsigned int sector) 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; + /* 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; + /* 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); + /* 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, + /* Send Sector Erase command in SW Mode */ + writel(instruction, &smicntl->smi_tr); + writel((bank << BANKSEL_SHIFT) | SEND | TX_LEN_4, &smicntl->smi_cr2); - if (smi_wait_xfer_finish(XFER_FINISH_TOUT)) - return -EIO; + if (smi_wait_xfer_finish(XFER_FINISH_TOUT)) + return -EIO; - if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT)) - return -EBUSY; + 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, + /* 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; - } + return 0; } /* * smi_write - Write to SMI flash * @src_addr: source buffer * @dst_addr: destination buffer - * @length: length to write in words + * @length: length to write in bytes * @bank: bank base address * * Write to SMI flash @@ -336,7 +354,10 @@ static int smi_sector_erase(flash_info_t *info, unsigned int sector) static int smi_write(unsigned int *src_addr, unsigned int *dst_addr, unsigned int length, ulong bank_addr) { + u8 *src_addr8 = (u8 *)src_addr; + u8 *dst_addr8 = (u8 *)dst_addr; int banknum; + int i; switch (bank_addr) { case SMIBANK0_BASE: @@ -365,7 +386,7 @@ static int smi_write(unsigned int *src_addr, unsigned int *dst_addr, return -EIO; /* Perform the write command */ - while (length--) { + for (i = 0; i < length; i += 4) { if (((ulong) (dst_addr) % SFLASH_PAGE_SIZE) == 0) { if (smi_wait_till_ready(banknum, CONFIG_SYS_FLASH_WRITE_TOUT)) @@ -375,7 +396,18 @@ static int smi_write(unsigned int *src_addr, unsigned int *dst_addr, return -EIO; } - *dst_addr++ = *src_addr++; + if (length < 4) { + int k; + + /* + * Handle special case, where length < 4 (redundant env) + */ + for (k = 0; k < length; k++) + *dst_addr8++ = *src_addr8++; + } else { + /* Normal 32bit write */ + *dst_addr++ = *src_addr++; + } if ((readl(&smicntl->smi_sr) & (ERF1 | ERF2))) return -EIO; @@ -401,7 +433,7 @@ static int smi_write(unsigned int *src_addr, unsigned int *dst_addr, int write_buff(flash_info_t *info, uchar *src, ulong dest_addr, ulong length) { return smi_write((unsigned int *)src, (unsigned int *)dest_addr, - (length + 3) / 4, info->start[0]); + length, info->start[0]); } /* @@ -444,8 +476,13 @@ void flash_print_info(flash_info_t *info) puts("missing or unknown FLASH type\n"); return; } - printf(" Size: %ld MB in %d Sectors\n", - info->size >> 20, info->sector_count); + + if (info->size >= 0x100000) + printf(" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + else + printf(" Size: %ld KB in %d Sectors\n", + info->size >> 10, info->sector_count); puts(" Sector Start Addresses:"); for (i = 0; i < info->sector_count; ++i) { @@ -498,11 +535,6 @@ int flash_erase(flash_info_t *info, int s_first, int s_last) int prot = 0; flash_sect_t sect; - if (info->flash_id != ST_M25Pxx_ID) { - 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;