X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fmtd%2Faltera_qspi.c;h=1d32febe07c863f7fc7c71e423a54f535ea846c6;hb=a32effd2838a62a5d1dcc01f613508f1d90b5667;hp=50c6e0e58769fe8a290f3fbc3b4c34f500e759c9;hpb=8ed38fa50c2a40851f6201bd795666a850617eb9;p=u-boot diff --git a/drivers/mtd/altera_qspi.c b/drivers/mtd/altera_qspi.c index 50c6e0e587..1d32febe07 100644 --- a/drivers/mtd/altera_qspi.c +++ b/drivers/mtd/altera_qspi.c @@ -1,10 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2015 Thomas Chou - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include #include #include @@ -14,6 +14,14 @@ DECLARE_GLOBAL_DATA_PTR; +/* The STATUS register */ +#define QUADSPI_SR_BP0 BIT(2) +#define QUADSPI_SR_BP1 BIT(3) +#define QUADSPI_SR_BP2 BIT(4) +#define QUADSPI_SR_BP2_0 GENMASK(4, 2) +#define QUADSPI_SR_BP3 BIT(6) +#define QUADSPI_SR_TB BIT(5) + /* * The QUADSPI_MEM_OP register is used to do memory protect and erase operations */ @@ -44,12 +52,32 @@ struct altera_qspi_platdata { unsigned long size; }; +static uint flash_verbose; flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* FLASH chips info */ +static void altera_qspi_get_locked_range(struct mtd_info *mtd, loff_t *ofs, + uint64_t *len); + void flash_print_info(flash_info_t *info) { + struct mtd_info *mtd = info->mtd; + loff_t ofs; + u64 len; + printf("Altera QSPI flash Size: %ld MB in %d Sectors\n", info->size >> 20, info->sector_count); + altera_qspi_get_locked_range(mtd, &ofs, &len); + printf(" %08lX +%lX", info->start[0], info->size); + if (len) { + printf(", protected %08llX +%llX", + info->start[0] + ofs, len); + } + putc('\n'); +} + +void flash_set_verbose(uint v) +{ + flash_verbose = v; } int flash_erase(flash_info_t *info, int s_first, int s_last) @@ -59,12 +87,16 @@ int flash_erase(flash_info_t *info, int s_first, int s_last) int ret; memset(&instr, 0, sizeof(instr)); + instr.mtd = mtd; instr.addr = mtd->erasesize * s_first; instr.len = mtd->erasesize * (s_last + 1 - s_first); + flash_set_verbose(1); ret = mtd_erase(mtd, &instr); + flash_set_verbose(0); if (ret) - return ERR_NOT_ERASED; + return ERR_PROTECTED; + puts(" done\n"); return 0; } @@ -80,7 +112,7 @@ int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) ret = mtd_write(mtd, to, cnt, &retlen, src); if (ret) - return ERR_NOT_ERASED; + return ERR_PROTECTED; return 0; } @@ -108,23 +140,49 @@ static int altera_qspi_erase(struct mtd_info *mtd, struct erase_info *instr) size_t end = addr + len; u32 sect; u32 stat; + u32 *flash, *last; instr->state = MTD_ERASING; addr &= ~(mtd->erasesize - 1); /* get lower aligned address */ while (addr < end) { - sect = addr / mtd->erasesize; - sect <<= 8; - sect |= QUADSPI_MEM_OP_SECTOR_ERASE; - debug("erase %08x\n", sect); - writel(sect, ®s->mem_op); - stat = readl(®s->isr); - if (stat & QUADSPI_ISR_ILLEGAL_ERASE) { - /* erase failed, sector might be protected */ - debug("erase %08x fail %x\n", sect, stat); - writel(stat, ®s->isr); /* clear isr */ + if (ctrlc()) { + if (flash_verbose) + putc('\n'); + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; instr->state = MTD_ERASE_FAILED; + mtd_erase_callback(instr); return -EIO; } + flash = pdata->base + addr; + last = pdata->base + addr + mtd->erasesize; + /* skip erase if sector is blank */ + while (flash < last) { + if (readl(flash) != 0xffffffff) + break; + flash++; + } + if (flash < last) { + sect = addr / mtd->erasesize; + sect <<= 8; + sect |= QUADSPI_MEM_OP_SECTOR_ERASE; + debug("erase %08x\n", sect); + writel(sect, ®s->mem_op); + stat = readl(®s->isr); + if (stat & QUADSPI_ISR_ILLEGAL_ERASE) { + /* erase failed, sector might be protected */ + debug("erase %08x fail %x\n", sect, stat); + writel(stat, ®s->isr); /* clear isr */ + instr->fail_addr = addr; + instr->state = MTD_ERASE_FAILED; + mtd_erase_callback(instr); + return -EIO; + } + if (flash_verbose) + putc('.'); + } else { + if (flash_verbose) + putc(','); + } addr += mtd->erasesize; } instr->state = MTD_ERASE_DONE; @@ -171,6 +229,77 @@ static void altera_qspi_sync(struct mtd_info *mtd) { } +static void altera_qspi_get_locked_range(struct mtd_info *mtd, loff_t *ofs, + uint64_t *len) +{ + struct udevice *dev = mtd->dev; + struct altera_qspi_platdata *pdata = dev_get_platdata(dev); + struct altera_qspi_regs *regs = pdata->regs; + int shift0 = ffs(QUADSPI_SR_BP2_0) - 1; + int shift3 = ffs(QUADSPI_SR_BP3) - 1 - 3; + u32 stat = readl(®s->rd_status); + unsigned pow = ((stat & QUADSPI_SR_BP2_0) >> shift0) | + ((stat & QUADSPI_SR_BP3) >> shift3); + + *ofs = 0; + *len = 0; + if (pow) { + *len = mtd->erasesize << (pow - 1); + if (*len > mtd->size) + *len = mtd->size; + if (!(stat & QUADSPI_SR_TB)) + *ofs = mtd->size - *len; + } +} + +static int altera_qspi_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct udevice *dev = mtd->dev; + struct altera_qspi_platdata *pdata = dev_get_platdata(dev); + struct altera_qspi_regs *regs = pdata->regs; + u32 sector_start, sector_end; + u32 num_sectors; + u32 mem_op; + u32 sr_bp; + u32 sr_tb; + + num_sectors = mtd->size / mtd->erasesize; + sector_start = ofs / mtd->erasesize; + sector_end = (ofs + len) / mtd->erasesize; + + if (sector_start >= num_sectors / 2) { + sr_bp = fls(num_sectors - 1 - sector_start) + 1; + sr_tb = 0; + } else if (sector_end < num_sectors / 2) { + sr_bp = fls(sector_end) + 1; + sr_tb = 1; + } else { + sr_bp = 15; + sr_tb = 0; + } + + mem_op = (sr_tb << 12) | (sr_bp << 8); + mem_op |= QUADSPI_MEM_OP_SECTOR_PROTECT; + debug("lock %08x\n", mem_op); + writel(mem_op, ®s->mem_op); + + return 0; +} + +static int altera_qspi_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct udevice *dev = mtd->dev; + struct altera_qspi_platdata *pdata = dev_get_platdata(dev); + struct altera_qspi_regs *regs = pdata->regs; + u32 mem_op; + + mem_op = QUADSPI_MEM_OP_SECTOR_PROTECT; + debug("unlock %08x\n", mem_op); + writel(mem_op, ®s->mem_op); + + return 0; +} + static int altera_qspi_probe(struct udevice *dev) { struct altera_qspi_platdata *pdata = dev_get_platdata(dev); @@ -196,6 +325,8 @@ static int altera_qspi_probe(struct udevice *dev) mtd->_read = altera_qspi_read; mtd->_write = altera_qspi_write; mtd->_sync = altera_qspi_sync; + mtd->_lock = altera_qspi_lock; + mtd->_unlock = altera_qspi_unlock; mtd->numeraseregions = 0; mtd->erasesize = 0x10000; if (add_mtd_device(mtd)) @@ -217,7 +348,7 @@ static int altera_qspi_ofdata_to_platdata(struct udevice *dev) { struct altera_qspi_platdata *pdata = dev_get_platdata(dev); void *blob = (void *)gd->fdt_blob; - int node = dev->of_offset; + int node = dev_of_offset(dev); const char *list, *end; const fdt32_t *cell; void *base; @@ -230,7 +361,7 @@ static int altera_qspi_ofdata_to_platdata(struct udevice *dev) * match with reg-names. */ parent = fdt_parent_offset(blob, node); - of_bus_default_count_cells(blob, parent, &addrc, &sizec); + fdt_support_default_count_cells(blob, parent, &addrc, &sizec); list = fdt_getprop(blob, node, "reg-names", &len); if (!list) return -ENOENT;