/* Get NAND parameter table. */ static int __init parse_nand_param(const struct tag *tag) { if (tag->hdr.size <= 2) return 0; nand_otp_len = ((tag->hdr.size << 2) - sizeof(struct tag_header)); if (nand_otp_len > sizeof(nand_otp)) { PR_BUG("tag->hdr.size <= 2\n"); return 0; } memcpy(nand_otp, &tag->u, nand_otp_len); return 0; }
int hisfc350_reg_erase(struct hisfc_host *host, unsigned long long prt_size, unsigned long long offset, unsigned long long length, int *state) { struct hisfc_spi *spi = host->spi; if (offset + length > prt_size) { PR_WARN("erase area out of range of mtd.\n"); return -EINVAL; } if ((unsigned int)offset & (host->erasesize-1)) { PR_WARN("erase start address is not alignment.\n"); return -EINVAL; } if ((unsigned int)length & (host->erasesize-1)) { PR_WARN("erase length is not alignment.\n"); return -EINVAL; } while (length) { if (spi->chipsize <= offset) { offset -= spi->chipsize; spi++; if (!spi->name) PR_BUG("erase memory out of range.\n"); } if (hisfc350_reg_erase_one_block(host, spi, offset)) { mutex_unlock(&host->lock); return -1; } offset += spi->erase->size; length -= spi->erase->size; } *state = MTD_ERASE_DONE; return 0; }
int hinfc610_get_sync_info(struct hinfc_host *host) { int type = 0; if (IS_NAND_ONFI(host)) hinfc610_get_onfi_info(host, &type); else hinfc610_get_toggle_info(host, &type); if (!type) { host->flags &= ~NAND_MODE_SYNC_ASYNC; return 0; } host->sync = hinfc610_find_sync_type(type); if (!host->sync) PR_BUG(ERSTR_DRIVER "This Nand Flash need to enable the 'synchronous' feature. " "but the driver dose not offer the feature"); return 0; }
static int __init parse_nand_partitions(const struct tag *tag) { int i; if (tag->hdr.size <= 2) { PR_BUG("tag->hdr.size <= 2\n"); return 0; } ptn_info.parts_num = (tag->hdr.size - 2) / (sizeof(struct partition_entry)/sizeof(int)); memcpy(ptn_info.entry, &tag->u, ptn_info.parts_num * sizeof(struct partition_entry)); for (i = 0; i < ptn_info.parts_num; i++) { ptn_info.parts[i].name = ptn_info.entry[i].name; ptn_info.parts[i].size = (ptn_info.entry[i].length); ptn_info.parts[i].offset = (ptn_info.entry[i].start); ptn_info.parts[i].mask_flags = 0; ptn_info.parts[i].ecclayout = 0; } return 0; }
int hisfc350_dma_write(struct hisfc_host *host, unsigned long long prt_size, unsigned int to, unsigned int len, unsigned int *retlen, unsigned char *buf) { int num; int result = -EIO; unsigned char *ptr = (unsigned char *)buf; struct hisfc_spi *spi = host->spi; if ((unsigned long long)(to + len) > prt_size) { PR_WARN("write data out of range.\n"); return -EINVAL; } *retlen = 0; if (!len) { PR_WARN("write length is 0.\n"); return 0; } if (spi->driver->wait_ready(spi)) goto fail; spi->driver->write_enable(spi); spi->driver->bus_prepare(spi, WRITE); if (to & HISFC350_DMA_ALIGN_MASK) { num = HISFC350_DMA_ALIGN_SIZE - (to & HISFC350_DMA_ALIGN_MASK); if (num > len) num = len; while (to >= spi->chipsize) { to -= spi->chipsize; spi++; if (!spi->name) PR_BUG("write memory out of range.\n"); if (spi->driver->wait_ready(spi)) goto fail; spi->driver->write_enable(spi); spi->driver->bus_prepare(spi, WRITE); } memcpy(host->buffer, ptr, num); hisfc350_dma_transfer(host, to, (unsigned char *)host->dma_buffer, WRITE, num, spi->chipselect); to += num; ptr += num; len -= num; } while (len > 0) { num = ((len >= HISFC350_DMA_MAX_SIZE) ? HISFC350_DMA_MAX_SIZE : len); while (to >= spi->chipsize) { to -= spi->chipsize; spi++; if (!spi->name) PR_BUG("write memory out of range.\n"); if (spi->driver->wait_ready(spi)) goto fail; spi->driver->write_enable(spi); spi->driver->bus_prepare(spi, WRITE); } memcpy(host->buffer, ptr, num); hisfc350_dma_transfer(host, to, (unsigned char *)host->dma_buffer, WRITE, num, spi->chipselect); to += num; ptr += num; len -= num; } *retlen = (unsigned int)(ptr - buf); result = 0; fail: return result; }
int hisfc350_dma_read(struct hisfc_host *host, unsigned long long prt_size, unsigned int from, unsigned int len, unsigned int *retlen, unsigned char *buf) { int num; int result = -EIO; unsigned char *ptr = buf; struct hisfc_spi *spi = host->spi; if ((unsigned long long)(from + len) > prt_size) { PR_WARN("read area out of range.\n"); return -EINVAL; } *retlen = 0; if (!len) { PR_WARN("read length is 0.\n"); return 0; } if (spi->driver->wait_ready(spi)) goto fail; spi->driver->bus_prepare(spi, READ); if (from & HISFC350_DMA_ALIGN_MASK) { num = HISFC350_DMA_ALIGN_SIZE - (from & HISFC350_DMA_ALIGN_MASK); if (num > len) num = len; while (from >= spi->chipsize) { from -= spi->chipsize; spi++; if (!spi->name) PR_BUG("write memory out of range.\n"); if (spi->driver->wait_ready(spi)) goto fail; spi->driver->bus_prepare(spi, READ); } hisfc350_dma_transfer(host, from, (unsigned char *)host->dma_buffer, READ, num, spi->chipselect); memcpy(ptr, host->buffer, num); from += num; ptr += num; len -= num; } while (len > 0) { while (from >= spi->chipsize) { from -= spi->chipsize; spi++; if (!spi->name) PR_BUG("read memory out of range.\n"); if (spi->driver->wait_ready(spi)) goto fail; spi->driver->bus_prepare(spi, READ); } num = ((from + len) >= spi->chipsize) ? (spi->chipsize - from) : len; while (num >= HISFC350_DMA_MAX_SIZE) { hisfc350_dma_transfer(host, from, (unsigned char *)host->dma_buffer, READ, HISFC350_DMA_MAX_SIZE, spi->chipselect); memcpy(ptr, host->buffer, HISFC350_DMA_MAX_SIZE); ptr += HISFC350_DMA_MAX_SIZE; from += HISFC350_DMA_MAX_SIZE; len -= HISFC350_DMA_MAX_SIZE; num -= HISFC350_DMA_MAX_SIZE; } if (num) { hisfc350_dma_transfer(host, from, (unsigned char *)host->dma_buffer, READ, num, spi->chipselect); memcpy(ptr, host->buffer, num); from += num; ptr += num; len -= num; } } result = 0; *retlen = (unsigned int)(ptr - buf); fail: return result; }
static int hinfc504_os_probe(struct platform_device * pltdev) { int size; int result = 0; struct hinfc_host *host; struct nand_chip *chip; struct mtd_info *mtd; struct resource *res; size = sizeof(struct hinfc_host) + sizeof(struct nand_chip) + sizeof(struct mtd_info); host = kmalloc(size, GFP_KERNEL); if (!host) { PR_BUG("failed to allocate device structure.\n"); return -ENOMEM; } memset((char *)host, 0, size); platform_set_drvdata(pltdev, host); host->dev = &pltdev->dev; host->chip = chip = (struct nand_chip *)&host[1]; host->mtd = mtd = (struct mtd_info *)&chip[1]; res = platform_get_resource_byname(pltdev, IORESOURCE_MEM, "base"); if (!res) { PR_BUG("Can't get resource.\n"); return -EIO; } host->iobase = ioremap(res->start, res->end - res->start + 1); if (!host->iobase) { PR_BUG("ioremap failed\n"); kfree(host); return -EIO; } mtd->priv = chip; mtd->owner = THIS_MODULE; mtd->name = (char*)(pltdev->name); res = platform_get_resource_byname(pltdev, IORESOURCE_MEM, "buffer"); if (!res) { PR_BUG("Can't get resource.\n"); return -EIO; } chip->IO_ADDR_R = chip->IO_ADDR_W = ioremap_nocache(res->start, res->end - res->start + 1); if (!chip->IO_ADDR_R) { PR_BUG("ioremap failed\n"); return -EIO; } host->buffer = dma_alloc_coherent(host->dev, (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE), &host->dma_buffer, GFP_KERNEL); if (!host->buffer) { PR_BUG("Can't malloc memory for NAND driver."); return -EIO; } chip->priv = host; host->chip = chip; chip->cmd_ctrl = hinfc504_cmd_ctrl; chip->dev_ready = hinfc504_dev_ready; chip->select_chip = hinfc504_select_chip; chip->read_byte = hinfc504_read_byte; chip->read_word = hinfc504_read_word; chip->write_buf = hinfc504_write_buf; chip->read_buf = hinfc504_read_buf; chip->chip_delay = HINFC504_CHIP_DELAY; chip->options = NAND_NO_AUTOINCR | NAND_SKIP_BBTSCAN; chip->ecc.layout = NULL; chip->ecc.mode = NAND_ECC_NONE; host->clk = clk_get_sys("hinfc504", NULL); if (IS_ERR(host->clk)) { PR_BUG("hinfc504 clock not found.\n"); return -EIO; } host->enable = hinfc504_os_enable; if (hinfc504_nand_init(host, chip)) { PR_BUG("failed to allocate device buffer.\n"); return -EIO; } if (nand_otp_len) { PR_MSG("Copy Nand read retry parameter from boot," " parameter length %d.\n", nand_otp_len); memcpy(host->rr_data, nand_otp, nand_otp_len); } if (nand_scan(mtd, CONFIG_HINFC504_MAX_CHIP)) { result = -ENXIO; goto fail; } register_mtd_partdev(host->mtd); if (!mtd_device_parse_register(mtd, part_probes_type, NULL, ptn_info.parts, ptn_info.parts_num)) return 0; unregister_mtd_partdev(host->mtd); result = -ENODEV; nand_release(mtd); fail: if (host->buffer) { dma_free_coherent(host->dev, (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE), host->buffer, host->dma_buffer); host->buffer = NULL; } iounmap(chip->IO_ADDR_W); iounmap(host->iobase); kfree(host); platform_set_drvdata(pltdev, NULL); return result; }