From patchwork Fri Apr 1 11:29:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mugunthan V N X-Patchwork-Id: 604742 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3qbzjM3fyDz9s36 for ; Fri, 1 Apr 2016 22:31:19 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A78D7A7616; Fri, 1 Apr 2016 13:30:44 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VXl2rO9AHIlo; Fri, 1 Apr 2016 13:30:44 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 59ADDA7624; Fri, 1 Apr 2016 13:30:29 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 67903A75DE for ; Fri, 1 Apr 2016 13:30:24 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 8b8IXbC40aZW for ; Fri, 1 Apr 2016 13:30:24 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from arroyo.ext.ti.com (arroyo.ext.ti.com [192.94.94.40]) by theia.denx.de (Postfix) with ESMTPS id 822C4A75F3 for ; Fri, 1 Apr 2016 13:30:14 +0200 (CEST) Received: from dflxv15.itg.ti.com ([128.247.5.124]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id u31BU8wP006284; Fri, 1 Apr 2016 06:30:08 -0500 Received: from DLEE70.ent.ti.com (dlee70.ent.ti.com [157.170.170.113]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id u31BU7WV017911; Fri, 1 Apr 2016 06:30:08 -0500 Received: from dflp33.itg.ti.com (10.64.6.16) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.224.2; Fri, 1 Apr 2016 06:30:07 -0500 Received: from a0131834lt.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id u31BTpUM026432; Fri, 1 Apr 2016 06:30:05 -0500 From: Mugunthan V N To: Date: Fri, 1 Apr 2016 16:59:46 +0530 Message-ID: <1459510190-26306-6-git-send-email-mugunthanvnm@ti.com> X-Mailer: git-send-email 2.8.0.rc3.9.g44915db In-Reply-To: <1459510190-26306-1-git-send-email-mugunthanvnm@ti.com> References: <1459510190-26306-1-git-send-email-mugunthanvnm@ti.com> MIME-Version: 1.0 Cc: Tom Rini , Sekhar Nori , Scott Wood Subject: [U-Boot] [PATCH 5/9] drivers: nand: omap_gpmc: convert driver to adopt driver model X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" adopt omap_gpmc driver to driver model. Signed-off-by: Mugunthan V N Reviewed-by: Tom Rini --- drivers/mtd/nand/omap_gpmc.c | 205 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 4814fa2..df63491 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -16,6 +16,10 @@ #include #include +#include + +DECLARE_GLOBAL_DATA_PTR; + #define BADBLOCK_MARKER_LENGTH 2 #define SECTOR_BYTES 512 #define ECCCLEAR (0x1 << 8) @@ -46,11 +50,22 @@ struct omap_nand_info { enum omap_ecc ecc_scheme; uint8_t cs; uint8_t ws; /* wait status pin (0,1) */ + uint8_t bus_width; /* Bus width of NAND device */ }; +#ifndef CONFIG_DM_NAND /* We are wasting a bit of memory but al least we are safe */ static struct omap_nand_info omap_nand_info[GPMC_MAX_CS]; +#else + +struct omap_gpmc_platdata { + struct omap_nand_info *omap_nand_info; + struct gpmc *gpmc_cfg; + int max_cs; +}; +#endif + /* * omap_nand_hwcontrol - Set the address pointers corretly for the * following address/data/command operation @@ -943,6 +958,8 @@ int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) } #endif /* CONFIG_SPL_BUILD */ +#ifndef CONFIG_DM_NAND + /* * Board-specific NAND initialization. The following members of the * argument are board-specific: @@ -1034,3 +1051,191 @@ int board_nand_init(struct nand_chip *nand) return 0; } + +#else /* CONFIG_DM_NAND */ + +static int omap_gpmc_probe(struct udevice *dev) +{ + struct nand_chip *nand = dev_get_priv(dev); + struct omap_gpmc_platdata *pdata = dev_get_platdata(dev); + struct gpmc *gpmc_cfg = pdata->gpmc_cfg; + int32_t gpmc_config = 0; + int ecc_opt; + int cs = cs_next++; + int err = 0; + + while (cs < pdata->max_cs) { + /* Check if NAND type is set */ + if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) { + /* Found it!! */ + break; + } + cs++; + } + + if (cs >= pdata->max_cs) { + printf("nand: error: Unable to find NAND settings in GPMC Configuration - quitting\n"); + return -ENODEV; + } + + gpmc_config = readl(&gpmc_cfg->config); + /* Disable Write protect */ + gpmc_config |= 0x10; + writel(gpmc_config, &gpmc_cfg->config); + + nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; + nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; + nand->priv = &pdata->omap_nand_info[cs]; + nand->cmd_ctrl = omap_nand_hwcontrol; + nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; + nand->chip_delay = 100; + nand->ecc.layout = &omap_ecclayout; + + /* configure driver and controller based on NAND device bus-width */ + gpmc_config = readl(&gpmc_cfg->cs[cs].config1); + if (pdata->omap_nand_info[cs].bus_width == 16) { + nand->options |= NAND_BUSWIDTH_16; + writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1); + } else { + nand->options &= ~NAND_BUSWIDTH_16; + writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1); + } + + ecc_opt = pdata->omap_nand_info[cs].ecc_scheme; + /* select ECC scheme */ + if (ecc_opt != OMAP_ECC_HAM1_CODE_SW) { + err = omap_select_ecc_scheme(nand, ecc_opt, + CONFIG_SYS_NAND_PAGE_SIZE, + CONFIG_SYS_NAND_OOBSIZE); + } else { + /* + * pagesize and oobsize are not required to + * configure sw ecc-scheme + */ + err = omap_select_ecc_scheme(nand, ecc_opt, 0, 0); + } + if (err) + return err; + +#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH + nand->read_buf = omap_nand_read_prefetch; +#else + if (nand->options & NAND_BUSWIDTH_16) + nand->read_buf = nand_read_buf16; + else + nand->read_buf = nand_read_buf; +#endif + + nand->dev_ready = omap_dev_ready; + + return 0; +} + +static int omap_gpmc_get_ecc_opt(int node, int elm_node) +{ + const void *fdt = gd->fdt_blob; + const char *ecc_str; + int ecc_opt = -ENOENT; + + ecc_str = fdt_getprop(fdt, node, "ti,nand-ecc-opt", NULL); + if (!ecc_str) { + error("DT entry for ti,nand-ecc-opt not found\n"); + return -ENOENT; + } + + if (!strcmp(ecc_str, "sw")) { + ecc_opt = OMAP_ECC_HAM1_CODE_SW; + } else if (!strcmp(ecc_str, "ham1") || + !strcmp(ecc_str, "hw") || + !strcmp(ecc_str, "hw-romcode")) { + ecc_opt = OMAP_ECC_HAM1_CODE_HW; + } else if (!strcmp(ecc_str, "bch4")) { + if (elm_node > 0) + ecc_opt = OMAP_ECC_BCH4_CODE_HW; + else + ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW; + } else if (!strcmp(ecc_str, "bch8")) { + if (elm_node > 0) + ecc_opt = OMAP_ECC_BCH8_CODE_HW; + else + ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; + } else if (!strcmp(ecc_str, "bch16")) { + if (elm_node > 0) + ecc_opt = OMAP_ECC_BCH16_CODE_HW; + else + error("BCH16 requires ELM support\n"); + } else { + error("ti,nand-ecc-opt invalid value\n"); + return -EINVAL; + } + + return ecc_opt; +} + +static int omap_gpmc_ofdata_to_platdata(struct udevice *dev) +{ + struct omap_gpmc_platdata *pdata = dev_get_platdata(dev); + const void *fdt = gd->fdt_blob; + int node = dev->of_offset; + int subnode; + + pdata->gpmc_cfg = (struct gpmc *)dev_get_addr(dev); + pdata->max_cs = fdtdec_get_int(fdt, node, "gpmc,num-cs", -1); + if (pdata->max_cs < 0) { + error("max chip select not found in DT\n"); + return -ENOENT; + } + + pdata->omap_nand_info = calloc(pdata->max_cs, + sizeof(struct omap_nand_info)); + if (!pdata->omap_nand_info) + return -ENOMEM; + + fdt_for_each_subnode(fdt, subnode, node) { + int cs; + int len; + int elm_node; + const char *name; + struct omap_nand_info *nand_info; + + name = fdt_get_name(fdt, subnode, &len); + if (strncmp(name, "nand", 4)) + continue; + + cs = fdtdec_get_int(fdt, subnode, "reg", -1); + if (cs < 0 || cs >= pdata->max_cs) { + error("Invalid cs for nand device\n"); + return -EINVAL; + } + nand_info = &pdata->omap_nand_info[cs]; + + /* get bus width 8 or 16, if not present 8 */ + nand_info->bus_width = fdtdec_get_int(fdt, subnode, + "nand-bus-width", 8); + + elm_node = fdtdec_lookup_phandle(fdt, subnode, "ti,elm-id"); + + nand_info->ecc_scheme = omap_gpmc_get_ecc_opt(subnode, + elm_node); + if (nand_info->ecc_scheme < 0) + return nand_info->ecc_scheme; + } + return 0; +} + +static const struct udevice_id omap_gpmc_ids[] = { + { .compatible = "ti,am3352-gpmc" }, + { } +}; + +U_BOOT_DRIVER(omap_gpmc) = { + .name = "omap_gpmc", + .id = UCLASS_NAND, + .of_match = omap_gpmc_ids, + .ofdata_to_platdata = omap_gpmc_ofdata_to_platdata, + .probe = omap_gpmc_probe, + .priv_auto_alloc_size = sizeof(struct nand_chip), + .platdata_auto_alloc_size = sizeof(struct omap_gpmc_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif /* CONFIG_DM_NAND */