From patchwork Wed Jul 27 09:37:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Trimarchi X-Patchwork-Id: 2268 Return-Path: X-Original-To: linux-amarula@patchwork.amarulasolutions.com Delivered-To: linux-amarula@patchwork.amarulasolutions.com Received: from mail-ed1-f71.google.com (mail-ed1-f71.google.com [209.85.208.71]) by ganimede.amarulasolutions.com (Postfix) with ESMTPS id A38893F330 for ; Wed, 27 Jul 2022 11:38:03 +0200 (CEST) Received: by mail-ed1-f71.google.com with SMTP id b15-20020a056402278f00b0043acaf76f8dsf10523854ede.21 for ; Wed, 27 Jul 2022 02:38:03 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1658914683; cv=pass; d=google.com; s=arc-20160816; b=Yway9joLw+q35PJf4muTGRgg5XEtkCNDuPK7dYzudxl/GAMtZwaM+LycHlF/4s6BK5 AI+qF+Aln+96cYr4u8owh+Lp4af6j1rIeNhuhUBnh881uqUItQggFjoeTN0NM//tTlMt GQJnNM5wNLEeCQ89F7KoEOOIYFDPEfldf5p25hGrfLRFRlueUETbHUS9S5G9g/5/LtWT EywJCP5lJUF+pV9ZhmggMG8cDWHbwJgUaEFYm/rwANsfc54FuZrnIpc4at6GyrGF7hc8 wl2cOHmGD1jAXj7ZRjXV/3EOOtg0LOlMojKRRI7J5wfy9EmpadvpDg3FJJUP5x2jD0i2 7VmA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-archive:list-help:list-post:list-id :mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:to:from:dkim-signature; bh=hGQK7q3kYEStFWJxXj+NZCTCHwxTvLngnioWV2DdpOo=; b=zG655dUrjwXF8UH/O8YT9T0c/ZAjh8DNxpQ9zjfOZJmvrgyoG+3hXaDZT1PLCYI7x5 6gTNMqUNBzWsDL++7ly4NQsh0yqR4FvodVvwUn3WVBJb5Okh6gtalmu8mTDOKc+kwn1d xS0Qpgkz4K1pDVhELMmpMZg6cw1H6tcw9Wzzn/o/xYOfl4X0f66cQAtnVc3zf+6qLViX TwjdbT3Bv0RpSgEXENK4ELfrRK0WROVNUxUjFLp+0lgCaFOMbUWWAAVTAf+1E70e0gU9 uttwwiN8M9UnTKEuwzJWxw/UK3XBvgnGjnVMji+gcuTRSLTJ7pC9CA37o30tfCsu2ZRO dPjg== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=KZ8hSNfI; spf=pass (google.com: domain of michael@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=michael@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :x-original-sender:x-original-authentication-results:precedence :mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=hGQK7q3kYEStFWJxXj+NZCTCHwxTvLngnioWV2DdpOo=; b=I0UHHJ5fK+PZwUW3F5QgIu2vQ0s57+nZc5Yp6kQrpq9W5AUOwGwAlimYuCi8hycQI4 TSgPP6wBwJcMtQshUfJsmNbZ3ICT9M0uTBpotb2/XQj1pmavwpaxwfX6Tb4PDCb0NNcJ lU6K6Yq1AlxZldy3TSVq90iKW47wQhP24PcvE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-spam-checked-in-group:list-post:list-help:list-archive :list-unsubscribe; bh=hGQK7q3kYEStFWJxXj+NZCTCHwxTvLngnioWV2DdpOo=; b=DxkyvLtWq4SbgUNOfqqaHwaLmIi/C9ZmcgxhBEakhC1Cfvso72w/jH8/OgF61xy2sI 2DNi6cmoKt3jHzw8KhpQjKlyaAjGdEew03q+4Ifzv5eo8C21CL+wzqFmxKDaVgx5Paa+ 9lPB4pHF2AureVqZGBhW0PqD00p99drT+NImynVdPF5WfT3t0zWhYUpQLSHtjUO8dBx8 YvG09pOCRH0lVi93hV0806bN8qWl8qynXy83FmXqU15PJ1m0+tvBuBDpcOifzPLVoxsd qO6JryoAMNUkp++eaekmtr0yyAHPvJGDP1FhD4atfdk7iJgzLq050sZl1tu0V7S7eEch y15Q== X-Gm-Message-State: AJIora9rt2dLwDP9TxwSKnoxGpLOO5xXTKPEdFSCP/i6WoJYOdJfUldO fA361IKNpj4XmL3eU8ytKhCaVOiM X-Google-Smtp-Source: AGRyM1tNprOv8Hi6kXRG0y/OUSt3tllS/qQx8ZiWsvbY9NRv29hRowOx8hzz0gOCh/DgG/gTuiH0ZQ== X-Received: by 2002:a17:907:2722:b0:72b:735a:d3b4 with SMTP id d2-20020a170907272200b0072b735ad3b4mr17032431ejl.363.1658914683266; Wed, 27 Jul 2022 02:38:03 -0700 (PDT) X-BeenThere: linux-amarula@amarulasolutions.com Received: by 2002:a17:906:9419:b0:72f:5c1f:1852 with SMTP id q25-20020a170906941900b0072f5c1f1852ls1901926ejx.0.-pod-prod-gmail; Wed, 27 Jul 2022 02:38:02 -0700 (PDT) X-Received: by 2002:a17:906:49d4:b0:6d6:e5ec:9a23 with SMTP id w20-20020a17090649d400b006d6e5ec9a23mr17385093ejv.79.1658914681870; Wed, 27 Jul 2022 02:38:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658914681; cv=none; d=google.com; s=arc-20160816; b=wQZZnY9nbfbdoB/PpqqM6yYg5VxXEHhrDzhXkMwezDQ/pytDdYy0dnYeXNmNCJkSdt RIx0jqkFGXKwLJLtGJtVgieJh0Ihdz3ITO91zJGORxmvHyBlLBGbjE0HleOXJi6nUJ2F +Z512a7NmmouNMv0HJ4WVpY6u5VDRxQIQrHPWUWR/21pscV1eVCra/cJcJGb68OxoL3Y abBWO7yV3kKTvAbEoFre3ja65ZFLhvHscbVvxbP9MSTz0mcAjlUHAcoaivjpy8fqJ2PK BWSRFKMbB0/jcdUKs5nnL+OYhx6pj673qGSA14//8pKa4ShcNLC51sHSdoWAFmJvN3+6 TA1A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:dkim-signature; bh=UZUZXKxTq2eFYFCwdvp9L9eetpmBXu2yxepeYUnvBdw=; b=r6C4HUfdrDkvpv1lmSoWDv2EU8bnwU7oAW7MXoZCkjQVjOdUjtWQLEZOstErFoKj1W 9xWtmfsNzv7lEkFbtuiP+2H3wX3erGk6sEHLdA7XExJazS0bhBNq1aS5UnVAwkq+yIIT f2500pbmOmTN8wLrY8D3cizc3BEt43CWwYZcPF65ZffYpbC4ZFLLAkWOJVYMA35hvnnC 3Y0ohkSXhczhahaF27pKE3bfLM2TnQEufOyeH9QNmCMnEaiuENTmcWHkJR9KPwxLHSkX OzETbe6HDKDeX1kw6so6l6GxL+xSXu51wirozltFEt+C9w0zZOAge2UwTnV1deX6edIi oWtA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=KZ8hSNfI; spf=pass (google.com: domain of michael@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=michael@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) by mx.google.com with SMTPS id d16-20020a50f690000000b0043ba4f8d2e5sor8286748edn.52.2022.07.27.02.38.01 for (Google Transport Security); Wed, 27 Jul 2022 02:38:01 -0700 (PDT) Received-SPF: pass (google.com: domain of michael@amarulasolutions.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41; X-Received: by 2002:a05:6402:5193:b0:43b:e957:cdef with SMTP id q19-20020a056402519300b0043be957cdefmr17067650edd.345.1658914681537; Wed, 27 Jul 2022 02:38:01 -0700 (PDT) Received: from panicking.amarulasolutions.com (mob-37-181-33-55.net.vodafone.it. [37.181.33.55]) by smtp.gmail.com with ESMTPSA id q22-20020a17090676d600b006fece722508sm7317678ejn.135.2022.07.27.02.38.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Jul 2022 02:38:01 -0700 (PDT) From: Michael Trimarchi To: dario.binacchi@amarulasolutions.com, Tommaso Merciai , linux-amarula@amarulasolutions.com Subject: [PATCH 7/7] mtd: nand: Add a common spl layer for nand subsystem Date: Wed, 27 Jul 2022 11:37:48 +0200 Message-Id: <20220727093748.1415135-8-michael@amarulasolutions.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220727093748.1415135-1-michael@amarulasolutions.com> References: <20220727093748.1415135-1-michael@amarulasolutions.com> MIME-Version: 1.0 X-Original-Sender: michael@amarulasolutions.com X-Original-Authentication-Results: mx.google.com; dkim=pass header.i=@amarulasolutions.com header.s=google header.b=KZ8hSNfI; spf=pass (google.com: domain of michael@amarulasolutions.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=michael@amarulasolutions.com; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=amarulasolutions.com Content-Type: text/plain; charset="UTF-8" Precedence: list Mailing-list: list linux-amarula@amarulasolutions.com; contact linux-amarula+owners@amarulasolutions.com List-ID: X-Spam-Checked-In-Group: linux-amarula@amarulasolutions.com X-Google-Group-Id: 476853432473 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Avoid code duplication accross drivers but make them use the same implementation. Create nand_common_spl to implement the part that does not depend on nand chipset. Apply to - mxs nand spl driver - mt7621 spl driver The mt7621 now as side effect implement nand_spl_adjust_offset, that implements bad block handle for complex image like fitImage Signed-off-by: Michael Trimarchi --- drivers/mtd/nand/raw/Makefile | 4 +- drivers/mtd/nand/raw/mt7621_nand_spl.c | 188 +------------------ drivers/mtd/nand/raw/mxs_nand_spl.c | 176 +----------------- drivers/mtd/nand/raw/nand_common_spl.c | 245 +++++++++++++++++++++++++ drivers/mtd/nand/raw/nand_common_spl.h | 15 ++ 5 files changed, 269 insertions(+), 359 deletions(-) create mode 100644 drivers/mtd/nand/raw/nand_common_spl.c create mode 100644 drivers/mtd/nand/raw/nand_common_spl.h diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index a398aa9d88..82ddb2b5d8 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -87,8 +87,8 @@ else # minimal SPL drivers obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o -obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o +obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o nand_common_spl.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o -obj-$(CONFIG_NAND_MT7621) += mt7621_nand_spl.o mt7621_nand.o +obj-$(CONFIG_NAND_MT7621) += mt7621_nand_spl.o mt7621_nand.o nand_common_spl.o endif # drivers diff --git a/drivers/mtd/nand/raw/mt7621_nand_spl.c b/drivers/mtd/nand/raw/mt7621_nand_spl.c index 114fc8b7ce..254e14a553 100644 --- a/drivers/mtd/nand/raw/mt7621_nand_spl.c +++ b/drivers/mtd/nand/raw/mt7621_nand_spl.c @@ -10,187 +10,13 @@ #include #include #include +#include "nand_common_spl.h" #include "mt7621_nand.h" +#include "nand_common_spl.h" static struct mt7621_nfc nfc_dev; -static u8 *buffer; static int nand_valid; -static void nand_command_lp(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - - /* Command latch cycle */ - chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - - if (column != -1 || page_addr != -1) { - int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; - - /* Serially input address */ - if (column != -1) { - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - if (command != NAND_CMD_READID) - chip->cmd_ctrl(mtd, column >> 8, ctrl); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - chip->cmd_ctrl(mtd, page_addr >> 8, - NAND_NCE | NAND_ALE); - if (chip->options & NAND_ROW_ADDR_3) - chip->cmd_ctrl(mtd, page_addr >> 16, - NAND_NCE | NAND_ALE); - } - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Program and erase have their own busy handlers status, sequential - * in and status need no delay. - */ - switch (command) { - case NAND_CMD_STATUS: - case NAND_CMD_READID: - case NAND_CMD_SET_FEATURES: - return; - - case NAND_CMD_READ0: - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - } - - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(100); - - nand_wait_ready(mtd); -} - -static int nfc_read_page_hwecc(struct mtd_info *mtd, void *buf, - unsigned int page) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); - - ret = chip->ecc.read_page(mtd, chip, buf, 1, page); - if (ret < 0 || ret > chip->ecc.strength) - return -1; - - return 0; -} - -static int nfc_read_oob_hwecc(struct mtd_info *mtd, void *buf, u32 len, - unsigned int page) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); - - ret = chip->ecc.read_page(mtd, chip, NULL, 1, page); - if (ret < 0) - return -1; - - if (len > mtd->oobsize) - len = mtd->oobsize; - - memcpy(buf, chip->oob_poi, len); - - return 0; -} - -static int nfc_check_bad_block(struct mtd_info *mtd, unsigned int page) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u32 pages_per_block, i = 0; - int ret; - u8 bad; - - pages_per_block = 1 << (mtd->erasesize_shift - mtd->writesize_shift); - - /* Read from first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) { - page += pages_per_block - 1; - if (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) - page--; - } - - do { - ret = nfc_read_oob_hwecc(mtd, &bad, 1, page); - if (ret) - return ret; - - ret = bad != 0xFF; - - i++; - page++; - } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); - - return ret; -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) -{ - struct mt7621_nfc *nfc = &nfc_dev; - struct nand_chip *chip = &nfc->nand; - struct mtd_info *mtd = &chip->mtd; - u32 addr, col, page, chksz; - bool check_bad = true; - - if (!nand_valid) - return -ENODEV; - - while (size) { - if (check_bad || !(offs & mtd->erasesize_mask)) { - addr = offs & (~mtd->erasesize_mask); - page = addr >> mtd->writesize_shift; - if (nfc_check_bad_block(mtd, page)) { - /* Skip bad block */ - if (addr >= mtd->size - mtd->erasesize) - return -1; - - offs += mtd->erasesize; - continue; - } - - check_bad = false; - } - - col = offs & mtd->writesize_mask; - page = offs >> mtd->writesize_shift; - chksz = min(mtd->writesize - col, (uint32_t)size); - - if (unlikely(chksz < mtd->writesize)) { - /* Not reading a full page */ - if (nfc_read_page_hwecc(mtd, buffer, page)) - return -1; - - memcpy(dest, buffer + col, chksz); - } else { - if (nfc_read_page_hwecc(mtd, dest, page)) - return -1; - } - - dest += chksz; - offs += chksz; - size -= chksz; - } - - return 0; -} - -int nand_default_bbt(struct mtd_info *mtd) -{ - return 0; -} - unsigned long nand_size(void) { if (!nand_valid) @@ -203,10 +29,6 @@ unsigned long nand_size(void) return SZ_2G; } -void nand_deselect(void) -{ -} - void nand_init(void) { struct mtd_info *mtd; @@ -219,7 +41,7 @@ void nand_init(void) chip = &nfc_dev.nand; mtd = &chip->mtd; - chip->cmdfunc = nand_command_lp; + chip->cmdfunc = nand_spl_command_lp; if (mt7621_nfc_spl_post_init(&nfc_dev)) return; @@ -229,9 +51,7 @@ void nand_init(void) mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; - buffer = malloc(mtd->writesize); - if (!buffer) - return; + nand_spl_init(chip); nand_valid = 1; } diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c index c7ea09e2f9..5cff6020c4 100644 --- a/drivers/mtd/nand/raw/mxs_nand_spl.c +++ b/drivers/mtd/nand/raw/mxs_nand_spl.c @@ -14,66 +14,11 @@ #include #include #include +#include "nand_common_spl.h" static struct mtd_info *mtd; static struct nand_chip nand_chip; -static void mxs_nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - u32 timeo, time_start; - - /* write out the command to the device */ - chip->cmd_ctrl(mtd, command, NAND_CLE); - - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16 && - !nand_opcode_8bits(command)) - column >>= 1; - chip->cmd_ctrl(mtd, column, NAND_ALE); - - /* - * Assume LP NAND here, so use two bytes column address - * but not for CMD_READID and CMD_PARAM, which require - * only one byte column address - */ - if (command != NAND_CMD_READID && - command != NAND_CMD_PARAM) - chip->cmd_ctrl(mtd, column >> 8, NAND_ALE); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, NAND_ALE); - chip->cmd_ctrl(mtd, page_addr >> 8, NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, NAND_ALE); - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); - - if (command == NAND_CMD_READ0) { - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_CLE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0); - } else if (command == NAND_CMD_RNDOUT) { - /* No ready / busy check necessary */ - chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, - NAND_NCE | NAND_CLE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE); - } - - /* wait for nand ready */ - ndelay(100); - timeo = (CONFIG_SYS_HZ * 20) / 1000; - time_start = get_timer(0); - while (get_timer(time_start) < timeo) { - if (chip->dev_ready(mtd)) - break; - } -} - #if defined (CONFIG_SPL_NAND_IDENT) /* Trying to detect the NAND flash using ONFi, JEDEC, and (extended) IDs */ @@ -175,35 +120,6 @@ static int mxs_flash_ident(struct mtd_info *mtd) return ret; } -static int mxs_read_page_ecc(struct mtd_info *mtd, void *buf, unsigned int page) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); - ret = nand_chip.ecc.read_page(mtd, chip, buf, 1, page); - if (ret < 0) { - printf("read_page failed %d\n", ret); - return -1; - } - return 0; -} - -static int is_badblock(struct mtd_info *mtd, loff_t offs, int allowbbt) -{ - register struct nand_chip *chip = mtd_to_nand(mtd); - unsigned int block = offs >> chip->phys_erase_shift; - unsigned int page = offs >> chip->page_shift; - - debug("%s offs=0x%08x block:%d page:%d\n", __func__, (int)offs, block, - page); - chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - memset(chip->oob_poi, 0, mtd->oobsize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - - return chip->oob_poi[0] != 0xff; -} - /* setup mtd and nand structs and init mxs_nand driver */ void nand_init(void) { @@ -215,7 +131,7 @@ void nand_init(void) mxs_nand_init_spl(&nand_chip); mtd = nand_to_mtd(&nand_chip); /* set mtd functions */ - nand_chip.cmdfunc = mxs_nand_command; + nand_chip.cmdfunc = nand_spl_command_lp; nand_chip.scan_bbt = nand_default_bbt; nand_chip.numchips = 1; @@ -234,92 +150,6 @@ void nand_init(void) mtd->size = nand_chip.chipsize; nand_chip.scan_bbt(mtd); mxs_nand_setup_ecc(mtd); -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int sz; - unsigned int block, lastblock; - unsigned int page, page_offset; - unsigned int nand_page_per_block; - struct nand_chip *chip; - u8 *page_buf = NULL; - - chip = mtd_to_nand(mtd); - if (!chip->numchips) - return -ENODEV; - - page_buf = malloc(mtd->writesize); - if (!page_buf) - return -ENOMEM; - - /* offs has to be aligned to a page address! */ - block = offs / mtd->erasesize; - lastblock = (offs + size - 1) / mtd->erasesize; - page = (offs % mtd->erasesize) / mtd->writesize; - page_offset = offs % mtd->writesize; - nand_page_per_block = mtd->erasesize / mtd->writesize; - - while (block <= lastblock) { - if (!is_badblock(mtd, mtd->erasesize * block, 1)) { - /* Skip bad blocks */ - while (page < nand_page_per_block && size > 0) { - int curr_page = nand_page_per_block * block + page; - - if (mxs_read_page_ecc(mtd, page_buf, curr_page) < 0) { - free(page_buf); - return -EIO; - } - - if (size > (mtd->writesize - page_offset)) - sz = (mtd->writesize - page_offset); - else - sz = size; - - memcpy(dst, page_buf + page_offset, sz); - dst += sz; - size -= sz; - page_offset = 0; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - free(page_buf); - - return 0; -} - -int nand_default_bbt(struct mtd_info *mtd) -{ - return 0; -} - -void nand_deselect(void) -{ -} - -u32 nand_spl_adjust_offset(u32 sector, u32 offs) -{ - unsigned int block, lastblock; - - block = sector / mtd->erasesize; - lastblock = (sector + offs) / mtd->erasesize; - - while (block <= lastblock) { - if (is_badblock(mtd, block * mtd->erasesize, 1)) { - offs += mtd->erasesize; - lastblock++; - } - - block++; - } - return offs; + nand_spl_init(&nand_chip); } diff --git a/drivers/mtd/nand/raw/nand_common_spl.c b/drivers/mtd/nand/raw/nand_common_spl.c new file mode 100644 index 0000000000..0595fcbc26 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_common_spl.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Amarula Solutions B.V. All rights reserved. + * + * Author: Michael Trimarchi + * Author: Weijie Gao + */ + +#include +#include +#include +#include +#include +#include + +static struct nand_chip *nand; +static u8 *buffer; +static int nand_valid; + +int nand_spl_init(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (!mtd) + return -EINVAL; + + buffer = malloc(mtd->writesize); + if (!buffer) + return -ENOMEM; + + nand = chip; + nand_valid = 1; + + return 0; +} + +static struct nand_chip *nand_spl_get_chip(void) +{ + return nand; +} + +void nand_spl_command_lp(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + u32 timeo, time_start; + + /* Command latch cycle */ + chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + if (column != -1 || page_addr != -1) { + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + + /* Serially input address */ + if (column != -1) { + chip->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + if (command != NAND_CMD_READID) + chip->cmd_ctrl(mtd, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->cmd_ctrl(mtd, page_addr, ctrl); + chip->cmd_ctrl(mtd, page_addr >> 8, + NAND_NCE | NAND_ALE); + if (chip->options & NAND_ROW_ADDR_3) + chip->cmd_ctrl(mtd, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + } + chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status, sequential + * in and status need no delay. + */ + switch (command) { + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_READ0: + chip->cmd_ctrl(mtd, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + } + + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + timeo = (CONFIG_SYS_HZ * 20) / 1000; + time_start = get_timer(0); + while (get_timer(time_start) < timeo) { + if (chip->dev_ready(mtd)) + break; + } +} + +static int nand_spl_read_page_hwecc(struct mtd_info *mtd, void *buf, + unsigned int page) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int ret; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); + + ret = chip->ecc.read_page(mtd, chip, buf, 1, page); + if (ret < 0 || ret > chip->ecc.strength) + return -1; + + return 0; +} + +static int nand_spl_read_oob_hwecc(struct mtd_info *mtd, void *buf, u32 len, + unsigned int page) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int ret; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); + + ret = chip->ecc.read_page(mtd, chip, NULL, 1, page); + if (ret < 0) + return -1; + + if (len > mtd->oobsize) + len = mtd->oobsize; + + memcpy(buf, chip->oob_poi, len); + + return 0; +} + +static int nand_spl_check_bad_block(struct mtd_info *mtd, unsigned int page) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u32 pages_per_block, i = 0; + int ret; + u8 bad; + + pages_per_block = 1 << (mtd->erasesize_shift - mtd->writesize_shift); + + /* Read from first/last page(s) if necessary */ + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) { + page += pages_per_block - 1; + if (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) + page--; + } + + do { + ret = nand_spl_read_oob_hwecc(mtd, &bad, 1, page); + if (ret) + return ret; + + ret = bad != 0xFF; + + i++; + page++; + } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + + return ret; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + struct nand_chip *chip = nand_spl_get_chip(); + struct mtd_info *mtd = &chip->mtd; + u32 addr, col, page, chksz; + bool check_bad = true; + + if (!nand_valid) + return -ENODEV; + + while (size) { + if (check_bad || !(offs & mtd->erasesize_mask)) { + addr = offs & (~mtd->erasesize_mask); + page = addr >> mtd->writesize_shift; + if (nand_spl_check_bad_block(mtd, page)) { + /* Skip bad block */ + if (addr >= mtd->size - mtd->erasesize) + return -ENXIO; + + offs += mtd->erasesize; + continue; + } + + check_bad = false; + } + + col = offs & mtd->writesize_mask; + page = offs >> mtd->writesize_shift; + chksz = min(mtd->writesize - col, (uint32_t)size); + + if (unlikely(chksz < mtd->writesize)) { + /* Not reading a full page */ + if (nand_spl_read_page_hwecc(mtd, buffer, page)) + return -EIO; + + memcpy(dest, buffer + col, chksz); + } else { + if (nand_spl_read_page_hwecc(mtd, dest, page)) + return -EIO; + } + + dest += chksz; + offs += chksz; + size -= chksz; + } + + return 0; +} + +int nand_default_bbt(struct mtd_info *mtd) +{ + return 0; +} + +void nand_deselect(void) +{ +} + +u32 nand_spl_adjust_offset(u32 sector, u32 offs) +{ + struct nand_chip *chip = nand_spl_get_chip(); + struct mtd_info *mtd = nand_to_mtd(chip); + unsigned int block, lastblock; + + block = sector / mtd->erasesize; + lastblock = (sector + offs) / mtd->erasesize; + + while (block <= lastblock) { + if (nand_spl_check_bad_block(mtd, block * mtd->erasesize)) { + offs += mtd->erasesize; + lastblock++; + } + + block++; + } + + return offs; +} diff --git a/drivers/mtd/nand/raw/nand_common_spl.h b/drivers/mtd/nand/raw/nand_common_spl.h new file mode 100644 index 0000000000..36bf63b230 --- /dev/null +++ b/drivers/mtd/nand/raw/nand_common_spl.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Amarula Solution B.V. All rights reserved. + * + * Author: Michael Trimarchi + */ + +#ifndef _NAND_COMMON_SPL_H +#define _NAND_COMMON_SPL_H + +void nand_spl_command_lp(struct mtd_info *mtd, unsigned int command, + int column, int page_addr); +int nand_spl_init(struct nand_chip *chip); + +#endif /* _NAND_COMMON_SPL_H_ */