コード例 #1
0
/* 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;
}
コード例 #2
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;
}
コード例 #3
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;
}
コード例 #4
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;
}
コード例 #5
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;
}
コード例 #6
0
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;
}
コード例 #7
0
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;
}