All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chin Liang See <clsee@altera.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v4 1/6] nand: denali: add Denali NAND driver for SPL
Date: Fri, 12 Sep 2014 02:09:31 -0500	[thread overview]
Message-ID: <1410505771.1904.16.camel@clsee-VirtualBox.altera.com> (raw)
In-Reply-To: <1409896223-15994-2-git-send-email-yamada.m@jp.panasonic.com>

Hi Masahiro,

On Fri, 2014-09-05 at 14:50 +0900, Masahiro Yamada wrote:
> The SPL-mode driver for Denali(Cadence) NAND Flash Memory Controller IP.
> 
> This driver requires two CONFIG macros:
>  - CONFIG_SPL_NAND_DENALI
>      Define to enable this driver.
>  - CONFIG_SYS_NAND_BAD_BLOCK_POS
>      Specify bad block mark position in the oob space. Typically 0.
> 
> Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Chin Liang See <clsee@altera.com>
> Cc: Scott Wood <scottwood@freescale.com>
> ---
> 
> Changes in v4:
>   - Add a workaround to not depend on the Denali driver
>     posted by Chin Liang See.
>     This driver has been taking too long:
>     http://patchwork.ozlabs.org/patch/381305/
> 

Yup, hopefully v10 would be the final patch.


> Changes in v3: None
> Changes in v2:
>   - Avoid unaligned access
>   - Replace a magic number 0x2000 with PIPELINE_ACCESS
> 
>  drivers/mtd/nand/Makefile     |   1 +
>  drivers/mtd/nand/denali_spl.c | 245 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 246 insertions(+)
>  create mode 100644 drivers/mtd/nand/denali_spl.c
> 
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index bf1312a..f90f9a0 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -12,6 +12,7 @@ NORMAL_DRIVERS=y
>  endif
>  
>  obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o
> +obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
>  obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o
>  obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
>  obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
> diff --git a/drivers/mtd/nand/denali_spl.c b/drivers/mtd/nand/denali_spl.c
> new file mode 100644
> index 0000000..ab23743
> --- /dev/null
> +++ b/drivers/mtd/nand/denali_spl.c
> @@ -0,0 +1,245 @@
> +/*
> + * Copyright (C) 2014       Panasonic Corporation
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/unaligned.h>
> +#include <linux/mtd/nand.h>
> +#if 0
> +#include "denali.h"
> +#else
> +/* workaround until denali.h is merged */
> +#define TRANSFER_SPARE_REG			0x10
> +#define ECC_ENABLE				0xe0
> +#define PAGES_PER_BLOCK				0x150
> +#define DEVICE_MAIN_AREA_SIZE			0x170
> +#define DEVICE_SPARE_AREA_SIZE			0x180
> +
> +#define INTR_STATUS(__bank)	(0x410 + ((__bank) * 0x50))
> +#define     INTR_STATUS__ECC_UNCOR_ERR			0x0001
> +#define     INTR_STATUS__LOAD_COMP			0x0040
> +
> +#define INDEX_CTRL_REG    0x0
> +#define INDEX_DATA_REG    0x10
> +#define MODE_01    0x04000000
> +#define MODE_10    0x08000000
> +#endif
> +
> +#define SPARE_ACCESS		0x41
> +#define MAIN_ACCESS		0x42
> +#define PIPELINE_ACCESS		0x2000
> +
> +#define BANK(x) ((x) << 24)
> +
> +static void __iomem *denali_flash_mem =
> +			(void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
> +static void __iomem *denali_flash_reg =
> +			(void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
> +
> +static const int flash_bank;
> +static uint8_t page_buffer[NAND_MAX_PAGESIZE];
> +static int page_size, oob_size, pages_per_block;
> +
> +static void index_addr(uint32_t address, uint32_t data)
> +{
> +	writel(address, denali_flash_mem + INDEX_CTRL_REG);
> +	writel(data, denali_flash_mem + INDEX_DATA_REG);
> +}
> +
> +static int wait_for_irq(uint32_t irq_mask)
> +{
> +	unsigned long timeout = 1000000;
> +	uint32_t intr_status;
> +
> +	do {
> +		intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
> +
> +		if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
> +			debug("Uncorrected ECC detected\n");
> +			return -EIO;
> +		}
> +
> +		if (intr_status & irq_mask)
> +			break;
> +
> +		udelay(1);
> +		timeout--;
> +	} while (timeout);
> +
> +	if (!timeout) {
> +		debug("Timeout with interrupt status %08x\n", intr_status);
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static void read_data_from_flash_mem(uint8_t *buf, int len)
> +{
> +	int i;
> +	uint32_t *buf32;
> +
> +	/* transfer the data from the flash */
> +	buf32 = (uint32_t *)buf;
> +
> +	/*
> +	 * Let's take care of unaligned access although it rarely happens.
> +	 * Avoid put_unaligned() for the normal use cases since it leads to
> +	 * a bit performance regression.
> +	 */
> +	if ((unsigned long)buf32 % 4) {
> +		for (i = 0; i < len / 4; i++)
> +			put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG),
> +				      buf32++);
> +	} else {
> +		for (i = 0; i < len / 4; i++)
> +			*buf32++ = readl(denali_flash_mem + INDEX_DATA_REG);
> +	}
> +
> +	if (len % 4) {
> +		u32 tmp;
> +
> +		tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG));
> +		buf = (uint8_t *)buf32;
> +		for (i = 0; i < len % 4; i++) {
> +			*buf++ = tmp;
> +			tmp >>= 8;
> +		}
> +	}
> +}
> +
> +int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
> +{
> +	uint32_t addr, cmd;
> +	static uint32_t page_count = 1;
> +
> +	writel(ecc_en, denali_flash_reg + ECC_ENABLE);
> +
> +	/* clear all bits of intr_status. */
> +	writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank));
> +
> +	addr = BANK(flash_bank) | page;
> +
> +	/* setup the acccess type */
> +	cmd = MODE_10 | addr;
> +	index_addr(cmd, access_type);
> +
> +	/* setup the pipeline command */
> +	index_addr(cmd, PIPELINE_ACCESS | page_count);
> +
> +	cmd = MODE_01 | addr;
> +	writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
> +
> +	return wait_for_irq(INTR_STATUS__LOAD_COMP);
> +}
> +
> +static int nand_read_oob(void *buf, int page)
> +{
> +	int ret;
> +
> +	ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS);
> +	if (ret < 0)
> +		return ret;
> +
> +	read_data_from_flash_mem(buf, oob_size);
> +
> +	return 0;
> +}
> +
> +static int nand_read_page(void *buf, int page)
> +{
> +	int ret;
> +
> +	ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS);
> +	if (ret < 0)
> +		return ret;
> +
> +	read_data_from_flash_mem(buf, page_size);
> +
> +	return 0;
> +}
> +
> +static int nand_block_isbad(int block)
> +{
> +	int ret;
> +
> +	ret = nand_read_oob(page_buffer, block * pages_per_block);
> +	if (ret < 0)
> +		return ret;
> +
> +	return page_buffer[CONFIG_SYS_NAND_BAD_BLOCK_POS] != 0xff;
> +}
> +
> +/* nand_init() - initialize data to make nand usable by SPL */
> +void nand_init(void)
> +{
> +	/* access to main area */
> +	writel(0, denali_flash_reg + TRANSFER_SPARE_REG);
> +
> +	page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE);
> +	oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE);
> +	pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK);


I believe this will work for ONFI NAND devices only.
For non-ONFI, the value might not correct.


> +}
> +
> +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
> +{
> +	int block, page, column, readlen;
> +	int ret;
> +	int force_bad_block_check = 1;
> +
> +	page = offs / page_size;
> +	column = offs % page_size;
> +
> +	block = page / pages_per_block;
> +	page = page % pages_per_block;
> +
> +	while (size) {

I believe we need to error out when reading beyond last block.


> +		if (force_bad_block_check || page == 0) {
> +			ret = nand_block_isbad(block);
> +			if (ret < 0)
> +				return ret;
> +
> +			if (ret) {
> +				block++;
> +				continue;
> +			}
> +		}
> +
> +		force_bad_block_check = 0;

I believe we still need to check the subsequent block whether is bad or
not too. This can be enable when cross the block boundary.

> +
> +		if (unlikely(column || size < page_size)) {
> +			/* Partial page read */
> +			ret = nand_read_page(page_buffer,
> +					     block * pages_per_block + page);
> +			if (ret < 0)
> +				return ret;
> +
> +			readlen = min(page_size - column, size);
> +			memcpy(dst, page_buffer, readlen);
> +
> +			column = 0;
> +		} else {
> +			ret = nand_read_page(dst,
> +					     block * pages_per_block + page);
> +			if (ret < 0)
> +				return ret;
> +
> +			readlen = page_size;
> +		}
> +
> +		size -= readlen;
> +		dst += readlen;
> +		page++;
> +		if (page == pages_per_block) {
> +			block++;
> +			page = 0;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +void nand_deselect(void) {}


Currently U-Boot has drivers/mtd/nand/nand_spl_simple.c which handling
the SPL NAND image load. Wonder this driver will be integrated into
nand_spl_simple.c once drivers/mtd/nand/denali.c is applied?

Thanks
Chin Liang

  reply	other threads:[~2014-09-12  7:09 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-05  5:50 [U-Boot] [PATCH v4 0/6] Add support for Panasonic UniPhier SoCs/boards Masahiro Yamada
2014-09-05  5:50 ` [U-Boot] [PATCH v4 1/6] nand: denali: add Denali NAND driver for SPL Masahiro Yamada
2014-09-12  7:09   ` Chin Liang See [this message]
2014-09-12  8:06     ` Masahiro Yamada
2014-09-15  6:39       ` Chin Liang See
2014-09-17  9:09         ` Masahiro Yamada
2014-09-17 12:10           ` Chin Liang See
2014-09-05  5:50 ` [U-Boot] [PATCH v4 2/6] serial: add UniPhier serial driver Masahiro Yamada
2014-09-05 10:35   ` Marek Vasut
2014-09-05 12:03     ` Masahiro Yamada
2014-09-05 12:59       ` Marek Vasut
2014-09-05 16:41       ` Simon Glass
2014-09-06 14:49         ` Masahiro YAMADA
2014-09-19 12:15         ` Masahiro Yamada
2014-09-19 16:30           ` Simon Glass
2014-09-20  7:18             ` Masahiro YAMADA
2014-09-22  6:35               ` Simon Glass
2014-09-05  5:50 ` [U-Boot] [PATCH v4 3/6] arm: uniphier: add UniPhier SoC support code Masahiro Yamada
2014-09-05 18:59   ` Simon Glass
2014-09-06 15:34     ` Masahiro YAMADA
2014-09-06 16:39       ` Simon Glass
2014-09-05  5:50 ` [U-Boot] [PATCH v4 4/6] arm: uniphier: add Kconfig and defconfig Masahiro Yamada
2014-09-05  5:50 ` [U-Boot] [PATCH v4 5/6] MAINTAINERS: add me as a maintainer of UniPhier platform Masahiro Yamada
2014-09-18 11:33   ` Albert ARIBAUD
2014-09-18 11:40     ` Michal Simek
2014-09-05  5:50 ` [U-Boot] [PATCH v4 6/6] git-mailrc: " Masahiro Yamada

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1410505771.1904.16.camel@clsee-VirtualBox.altera.com \
    --to=clsee@altera.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.