[PATCH 2/3] ARM: i.MX: implement GPMI NAND xload

Sascha Hauer sha at pengutronix.de
Thu Jan 21 04:01:48 EST 2021


Hi Andrej,

Some comments inline.

On Wed, Jan 20, 2021 at 01:51:06PM +0100, Andrej Picej wrote:
> From: Sascha Hauer <s.hauer at pengutronix.de>
> 
> Commit is based on initial Sascha Hauer's work. It implements PBL xload
> mechanism to load image from GPMI NAND flash.
> 
> Additional work was done, so that the NAND's size, page size and OOB's
> size are autodetected and not hardcoded. Detection method follows the
> same methods as used in NAND driver, meaning NAND ONFI support is probed
> and if NAND supports ONFI, NAND memory organization is read from ONFI
> parameter page otherwise "READ ID" is used.
> 
> Currently only implemented for i.MX6 familly of SoCs.
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Primoz Fiser <primoz.fiser at norik.com>
> Signed-off-by: Andrej Picej <andrej.picej at norik.com>
> ---
>  arch/arm/mach-imx/Makefile             |    2 +-
>  arch/arm/mach-imx/include/mach/xload.h |    1 +
>  arch/arm/mach-imx/xload-gpmi-nand.c    | 1163 ++++++++++++++++++++++++
>  3 files changed, 1165 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/mach-imx/xload-gpmi-nand.c
> 
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> index e45f758e9..d94c846a1 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> +static int mxs_nand_get_info(struct mxs_nand_info *info, void *databuf)
> +{
> +	int ret, i;
> +
> +	ret = mxs_nand_check_onfi(info, databuf);
> +	if (ret) {
> +		if (ret != 1)
> +			return ret;
> +		pr_warn("ONFI not supported, try \"READ ID\"...\n");

You already printed a "ONFI not supported\n" message. Printing it once
is enough. Also this message appears with every non-ONFI nand, right? In
that case it should rather be pr_info()

> +	/*
> +	 * If ONFI is not supported or if it fails try to get NAND's info from
> +	 * "READ ID" command.
> +	 */
> +	pr_debug("Trying \"READ ID\" command...\n");
> +	ret = mxs_nand_get_readid(info, databuf);
> +	if (ret) {
> +		if (ret != -EOVERFLOW)
> +			return ret;
> +
> +		/*
> +		 * If NAND's "READ ID" returns bad values, try to set them to
> +		 * default (most common NAND memory org.) and continue.
> +		 */
> +		pr_warn("NANDs READ ID command returned bad values" \
> +			" set them to default and try to continue!\n");
> +		info->organization.pagesize = 2048;
> +		info->organization.oobsize = 64;
> +		info->nand_size = SZ_1G;

Is this worth it? READ ID is the most basic command, when this doesn't
work I don't think there's a point in continuing.

> +	}
> +succ:
> +	pr_debug("NAND page_size: %d\n", info->organization.pagesize);
> +	pr_debug("NAND block_size: %d\n",
> +		info->organization.pages_per_eraseblock
> +		* info->organization.pagesize);
> +	pr_debug("NAND oob_size: %d\n", info->organization.oobsize);
> +	pr_debug("NAND nand_size: %lu\n", info->nand_size);
> +	pr_debug("NAND bits_per_cell: %d\n", info->organization.bits_per_cell);
> +	pr_debug("NAND planes_per_lun: %d\n",
> +		info->organization.planes_per_lun);
> +	pr_debug("NAND luns_per_target: %d\n",
> +		info->organization.luns_per_target);
> +	pr_debug("NAND eraseblocks_per_lun: %d\n",
> +		info->organization.eraseblocks_per_lun);
> +	pr_debug("NAND ntargets: %d\n", info->organization.ntargets);
> +
> +
> +	return 0;
> +}
> +
> +/* ---------------------------- BCB handling part -------------------------- */
> +
> +static uint32_t calc_chksum(void *buf, size_t size)
> +{
> +	u32 chksum = 0;
> +	u8 *bp = buf;
> +	size_t i;
> +
> +	for (i = 0; i < size; i++)
> +		chksum += bp[i];
> +
> +	return ~chksum;
> +}
> +
> +static int get_fcb(struct mxs_nand_info *info, void *databuf)
> +{
> +	int i, pagenum, ret;
> +	uint32_t checksum;
> +	struct fcb_block *fcb = &info->fcb;
> +
> +	/* First page read fails, this shouldn't be necessary */
> +	mxs_nand_read_page(info, info->organization.pagesize,
> +		info->organization.oobsize, 0, databuf, 1);
> +
> +	for (i = 0; i < 4; i++) {
> +		pagenum = 64 * i;

I haven't looked at the documentation, but the '64' should probably be pages
per block, so better info->organization.pages_per_eraseblock?

> +
> +		ret = mxs_nand_read_page(info, info->organization.pagesize,
> +			info->organization.oobsize, pagenum, databuf, 1);
> +		if (ret)
> +			continue;
> +
> +		memcpy(fcb, databuf + mxs_nand_aux_status_offset(),
> +			sizeof(*fcb));
> +
> +		if (fcb->FingerPrint != FCB_FINGERPRINT) {
> +			pr_err("No FCB found on page %d\n", pagenum);
> +			continue;
> +		}
> +
> +		checksum = calc_chksum((void *)fcb +
> +			sizeof(uint32_t), sizeof(*fcb) - sizeof(uint32_t));
> +
> +		if (checksum != fcb->Checksum) {
> +			pr_err("FCB on page %d has invalid checksum. " \
> +				"Expected: 0x%08x, calculated: 0x%08x",
> +				pagenum, fcb->Checksum, checksum);
> +			continue;
> +		}
> +
> +		pr_debug("Found FCB:\n");
> +		pr_debug("PageDataSize:     0x%08x\n", fcb->PageDataSize);
> +		pr_debug("TotalPageSize:    0x%08x\n", fcb->TotalPageSize);
> +		pr_debug("SectorsPerBlock:  0x%08x\n", fcb->SectorsPerBlock);
> +		pr_debug("FW1_startingPage: 0x%08x\n",
> +			fcb->Firmware1_startingPage);
> +		pr_debug("PagesInFW1:       0x%08x\n", fcb->PagesInFirmware1);
> +		pr_debug("FW2_startingPage: 0x%08x\n",
> +			fcb->Firmware2_startingPage);
> +		pr_debug("PagesInFW2:       0x%08x\n", fcb->PagesInFirmware2);
> +
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int get_dbbt(struct mxs_nand_info *info, void *databuf)
> +{
> +	int i, ret;
> +	int page;
> +	int startpage = info->fcb.DBBTSearchAreaStartAddress;
> +	struct dbbt_block dbbt;
> +
> +	for (i = 0; i < 4; i++) {
> +		page = startpage + i * 64;

Same here.

Regards,
 Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



More information about the barebox mailing list