From patchwork Wed May 21 11:21:01 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 30544 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f198.google.com (mail-vc0-f198.google.com [209.85.220.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 0CDA520671 for ; Wed, 21 May 2014 11:24:42 +0000 (UTC) Received: by mail-vc0-f198.google.com with SMTP id ij19sf5935095vcb.9 for ; Wed, 21 May 2014 04:24:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id :in-reply-to:references:mime-version:cc:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :sender:errors-to:x-original-sender :x-original-authentication-results:mailing-list:content-type :content-transfer-encoding; bh=9DZD8YlPrYZstZnxrbZI4EIA7uoOPGBYh0tI78bqk5I=; b=XDRbDdjELhbsdIMMdUPpXt3wg/swYLYa9GdDv4S9mfsB2OpF75OZLj94h9fgYMIZMs 7BlWhiuiz8w2yFc0HcoHiUTZbcpmhnXjkg7qTRJdf59HfhvZ2IYS7/sqvLOMcer4+rrd ltm+a974rw9AbmGYsNNfmgP3RsM+k7dUj3ruZGwbUbNSNG0tGzXAWRzjwoRgPAKZE0ER 22Nx4KEArRPf6dnMDK2Xm+Yqa+EoBGq0tvCgGFm/bSAfaJL44JU/9JhOeKwTijC8D3sJ RnIBiSniDtkI6lKzUMF5Xp/0dc2gszOMYK3pI0K6oJsGkRORv8LLZMqS6b+9vBotEBCg oskA== X-Gm-Message-State: ALoCoQkWq1+x5sK5W+l3n5YH9Div0p1szgQNHp+mjsqkIXZGEfRCS+zuKJIkwiP+epqSgkOPxWgm X-Received: by 10.236.128.112 with SMTP id e76mr19370097yhi.38.1400671482295; Wed, 21 May 2014 04:24:42 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.82.37 with SMTP id g34ls678173qgd.64.gmail; Wed, 21 May 2014 04:24:42 -0700 (PDT) X-Received: by 10.221.26.10 with SMTP id rk10mr2601596vcb.0.1400671482065; Wed, 21 May 2014 04:24:42 -0700 (PDT) Received: from mail-ve0-f176.google.com (mail-ve0-f176.google.com [209.85.128.176]) by mx.google.com with ESMTPS id tx9si2694969vcb.102.2014.05.21.04.24.42 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 21 May 2014 04:24:42 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.176 as permitted sender) client-ip=209.85.128.176; Received: by mail-ve0-f176.google.com with SMTP id jz11so2275453veb.21 for ; Wed, 21 May 2014 04:24:41 -0700 (PDT) X-Received: by 10.58.29.234 with SMTP id n10mr1252323veh.16.1400671481950; Wed, 21 May 2014 04:24:41 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp104726vcb; Wed, 21 May 2014 04:24:41 -0700 (PDT) X-Received: by 10.224.161.10 with SMTP id p10mr66612771qax.12.1400671481342; Wed, 21 May 2014 04:24:41 -0700 (PDT) Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id o6si959994qge.68.2014.05.21.04.24.41 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 May 2014 04:24:41 -0700 (PDT) Received-SPF: none (google.com: linux-mtd-bounces+patch=linaro.org@lists.infradead.org does not designate permitted sender hosts) client-ip=2001:1868:205::9; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wn4bp-0000On-74; Wed, 21 May 2014 11:22:57 +0000 Received: from comal.ext.ti.com ([198.47.26.152]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wn4bM-0008Kq-BN; Wed, 21 May 2014 11:22:30 +0000 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id s4LBM44B024137; Wed, 21 May 2014 06:22:04 -0500 Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id s4LBM4OB027524; Wed, 21 May 2014 06:22:04 -0500 Received: from dflp32.itg.ti.com (10.64.6.15) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.174.1; Wed, 21 May 2014 06:22:04 -0500 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id s4LBLAAi018495; Wed, 21 May 2014 06:22:01 -0500 From: Roger Quadros To: , Subject: [RFC PATCH 13/16] mtd: nand: omap: True device tree support Date: Wed, 21 May 2014 14:21:01 +0300 Message-ID: <1400671264-10702-14-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1400671264-10702-1-git-send-email-rogerq@ti.com> References: <1400671264-10702-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140521_042228_666189_F70ABA46 X-CRM114-Status: GOOD ( 21.02 ) X-Spam-Score: -5.7 (-----) X-Spam-Report: SpamAssassin version 3.3.2 on bombadil.infradead.org summary: Content analysis details: (-5.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [198.47.26.152 listed in list.dnswl.org] -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record Cc: devicetree@vger.kernel.org, robertcnelson@gmail.com, jg1.han@samsung.com, nsekhar@ti.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, pekon@ti.com, ezequiel.garcia@free-electrons.com, javier@dowhile0.org, linux-omap@vger.kernel.org, dwmw2@infradead.org, Roger Quadros X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+patch=linaro.org@lists.infradead.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: rogerq@ti.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.176 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 The NAND controller must be a child node of the Chip select (CS) node. NAND specific parameters are moved to the NAND node. Move NAND specific device tree parsing to NAND driver. Signed-off-by: Roger Quadros --- arch/arm/mach-omap2/gpmc.c | 183 +++++++++++++-------------- drivers/mtd/nand/omap2.c | 124 +++++++++++++++--- include/linux/platform_data/mtd-nand-omap2.h | 6 +- 3 files changed, 195 insertions(+), 118 deletions(-) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 132f786..6493010 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -27,9 +27,7 @@ #include #include #include -#include #include -#include #include #include @@ -40,7 +38,6 @@ #include "common.h" #include "omap_device.h" #include "gpmc.h" -#include "gpmc-nand.h" #include "gpmc-onenand.h" #define DEVICE_NAME "omap-gpmc" @@ -1153,96 +1150,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, of_property_read_bool(np, "gpmc,time-para-granularity"); } -#if IS_ENABLED(CONFIG_MTD_NAND) - -static const char * const nand_xfer_types[] = { - [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", - [NAND_OMAP_POLLED] = "polled", - [NAND_OMAP_PREFETCH_DMA] = "prefetch-dma", - [NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq", -}; - -static int gpmc_probe_nand_child(struct platform_device *pdev, - struct device_node *child) -{ - u32 val; - const char *s; - struct gpmc_timings gpmc_t; - struct omap_nand_platform_data *gpmc_nand_data; - - if (of_property_read_u32(child, "reg", &val) < 0) { - dev_err(&pdev->dev, "%s has no 'reg' property\n", - child->full_name); - return -ENODEV; - } - - gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data), - GFP_KERNEL); - if (!gpmc_nand_data) - return -ENOMEM; - - gpmc_nand_data->cs = val; - gpmc_nand_data->of_node = child; - - /* Detect availability of ELM module */ - gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0); - if (gpmc_nand_data->elm_of_node == NULL) - gpmc_nand_data->elm_of_node = - of_parse_phandle(child, "elm_id", 0); - if (gpmc_nand_data->elm_of_node == NULL) - pr_warn("%s: ti,elm-id property not found\n", __func__); - - /* select ecc-scheme for NAND */ - if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) { - pr_err("%s: ti,nand-ecc-opt not found\n", __func__); - return -ENODEV; - } - if (!strcmp(s, "ham1") || !strcmp(s, "sw") || - !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) - gpmc_nand_data->ecc_opt = - OMAP_ECC_HAM1_CODE_HW; - else if (!strcmp(s, "bch4")) - if (gpmc_nand_data->elm_of_node) - gpmc_nand_data->ecc_opt = - OMAP_ECC_BCH4_CODE_HW; - else - gpmc_nand_data->ecc_opt = - OMAP_ECC_BCH4_CODE_HW_DETECTION_SW; - else if (!strcmp(s, "bch8")) - if (gpmc_nand_data->elm_of_node) - gpmc_nand_data->ecc_opt = - OMAP_ECC_BCH8_CODE_HW; - else - gpmc_nand_data->ecc_opt = - OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; - else - pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__); - - /* select data transfer mode for NAND controller */ - if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) - for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++) - if (!strcasecmp(s, nand_xfer_types[val])) { - gpmc_nand_data->xfer_type = val; - break; - } - - val = of_get_nand_bus_width(child); - if (val == 16) - gpmc_nand_data->devsize = NAND_BUSWIDTH_16; - - gpmc_read_timings_dt(child, &gpmc_t); - gpmc_nand_init(gpmc_nand_data, &gpmc_t); - - return 0; -} -#else -static int gpmc_probe_nand_child(struct platform_device *pdev, - struct device_node *child) -{ - return 0; -} -#endif - #if IS_ENABLED(CONFIG_MTD_ONENAND) static int gpmc_probe_onenand_child(struct platform_device *pdev, struct device_node *child) @@ -1372,6 +1279,90 @@ err: return ret; } +static int gpmc_probe_child(struct platform_device *pdev, + struct device_node *child) +{ + struct gpmc_settings gpmc_s; + struct gpmc_timings gpmc_t; + struct resource res; + unsigned long base; + int ret, cs; + struct device *dev = &pdev->dev; + const char *child_name = child->full_name; + u32 val; + + if (of_property_read_u32(child, "gpmc,cs", &cs) < 0) { + dev_err(dev, "%s: has no 'gpmc,cs' property\n", child_name); + return -EINVAL; + } + + if (of_address_to_resource(child, 0, &res) < 0) { + dev_err(dev, "%s: has malformed 'reg' property\n", child_name); + return -EINVAL; + } + + ret = gpmc_cs_request(cs, resource_size(&res), &base); + if (ret < 0) { + dev_err(dev, "%s: cannot request GPMC CS %d\n", child_name, cs); + return ret; + } + + ret = gpmc_cs_remap(cs, res.start); + if (ret < 0) { + dev_err(dev, "%s: cannot remap GPMC CS %d to %pa\n", + child_name, cs, (void *)res.start); + goto err; + } + + gpmc_read_settings_dt(child, &gpmc_s); + + ret = of_property_read_u32(child, "gpmc,device-width", &val); + if (ret) { + dev_err(dev, "%s: has no 'gpmc,device-width' property\n", + child_name); + goto err; + } + + switch (val) { + case 1: + gpmc_s.device_width = GPMC_DEVWIDTH_8BIT; + break; + case 2: + gpmc_s.device_width = GPMC_DEVWIDTH_16BIT; + break; + default: + dev_err(dev, "%s: invalid 'gpmc,device-width'\n", child_name); + ret = -EINVAL; + goto err; + } + + gpmc_s.device_nand = of_property_read_bool(child, "gpmc,nand"); + + ret = gpmc_cs_program_settings(cs, &gpmc_s); + if (ret < 0) { + dev_err(dev, "%s: failed to program GPMC settings\n", + child_name); + goto err; + } + + gpmc_read_timings_dt(child, &gpmc_t); + gpmc_cs_set_timings(cs, &gpmc_t); + + ret = of_platform_populate(child, NULL, NULL, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to create gpmc child %s\n", + child_name); + goto err; + } + + return 0; + +err: + gpmc_cs_free(cs); + + return ret; +} + static int gpmc_probe_dt(struct platform_device *pdev) { int ret; @@ -1408,14 +1399,14 @@ static int gpmc_probe_dt(struct platform_device *pdev) if (!child->name) continue; - if (of_node_cmp(child->name, "nand") == 0) - ret = gpmc_probe_nand_child(pdev, child); - else if (of_node_cmp(child->name, "onenand") == 0) + if (of_node_cmp(child->name, "onenand") == 0) ret = gpmc_probe_onenand_child(pdev, child); else if (of_node_cmp(child->name, "ethernet") == 0 || of_node_cmp(child->name, "nor") == 0 || of_node_cmp(child->name, "uart") == 0) ret = gpmc_probe_generic_child(pdev, child); + else + ret = gpmc_probe_child(pdev, child); if (WARN(ret < 0, "%s: probing gpmc child %s failed\n", __func__, child->full_name)) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 7ff5cb3..4ca1f48 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1676,10 +1677,81 @@ static void gpmc_update_nand_reg(struct omap_nand_info *info) } } +static const char * const nand_xfer_types[] = { + [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", + [NAND_OMAP_POLLED] = "polled", + [NAND_OMAP_PREFETCH_DMA] = "prefetch-dma", + [NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq", +}; + +static int omap_get_dt_info(struct device *dev, struct omap_nand_info *info) +{ + struct device_node *child = dev->of_node; + int i; + const char *s; + + if (of_property_read_u32(child, "ti,nand-cs", &info->gpmc_cs)) { + dev_err(dev, "ti,nand-cs not found in DT\n"); + return -EINVAL; + } + + /* detect availability of ELM module. Won't be present pre-OMAP4 */ + info->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0); + if (info->elm_of_node == NULL) + dev_dbg(dev, "ti,elm-id not in DT\n"); + + /* select ecc-scheme */ + if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) { + /* default to HAM1 */ + info->ecc_opt = OMAP_ECC_HAM1_CODE_HW; + goto ecc_done; + } + + if (!strcmp(s, "ham1") || !strcmp(s, "sw") || + !strcmp(s, "hw") || !strcmp(s, "hw-romcode")) { + info->ecc_opt = OMAP_ECC_HAM1_CODE_HW; + + } else if (!strcmp(s, "bch4")) { + if (info->elm_of_node) + info->ecc_opt = OMAP_ECC_BCH4_CODE_HW; + else + info->ecc_opt = OMAP_ECC_BCH4_CODE_HW_DETECTION_SW; + + } else if (!strcmp(s, "bch8")) { + if (info->elm_of_node) + info->ecc_opt = OMAP_ECC_BCH8_CODE_HW; + else + info->ecc_opt = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; + } else { + dev_err(dev, "unrecognized value for ti,nand-ecc-opt\n"); + return -EINVAL; + } + +ecc_done: + /* select data transfer mode */ + if (!of_property_read_string(child, "ti,nand-xfer-type", &s)) { + for (i = 0; i < ARRAY_SIZE(nand_xfer_types); i++) { + if (!strcasecmp(s, nand_xfer_types[i])) { + info->xfer_type = i; + goto found; + } + } + + dev_err(dev, "unrecognized value for ti,nand-xfer-type\n"); + return -EINVAL; + } + +found: + if (of_get_nand_bus_width(child) == 16) + info->devsize = NAND_BUSWIDTH_16; + + return 0; +} + static int omap_nand_probe(struct platform_device *pdev) { struct omap_nand_info *info; - struct omap_nand_platform_data *pdata; + struct omap_nand_platform_data *pdata = NULL; struct mtd_info *mtd; struct nand_chip *nand_chip; struct nand_ecclayout *ecclayout; @@ -1692,31 +1764,37 @@ static int omap_nand_probe(struct platform_device *pdev) struct mtd_part_parser_data ppdata = {}; struct device *dev = &pdev->dev; - pdata = dev_get_platdata(&pdev->dev); - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data missing\n"); - return -ENODEV; - } info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info), GFP_KERNEL); if (!info) return -ENOMEM; + info->pdev = pdev; + + if (dev->of_node) { + if (omap_get_dt_info(dev, info)) + return -EINVAL; + } else { + pdata = dev_get_platdata(&pdev->dev); + if (pdata == NULL) { + dev_err(&pdev->dev, "platform data missing\n"); + return -EINVAL; + } + + info->gpmc_cs = pdata->cs; + info->of_node = pdata->of_node; + info->ecc_opt = pdata->ecc_opt; + info->dev_ready = pdata->dev_ready; + info->xfer_type = pdata->xfer_type; + info->devsize = pdata->devsize; + } + platform_set_drvdata(pdev, info); spin_lock_init(&info->controller.lock); init_waitqueue_head(&info->controller.wq); - info->pdev = pdev; - info->gpmc_cs = pdata->cs; - info->of_node = pdata->of_node; - info->ecc_opt = pdata->ecc_opt; - info->dev_ready = pdata->dev_ready; - info->xfer_type = pdata->xfer_type; - info->devsize = pdata->devsize; - info->elm_of_node = pdata->elm_of_node; - mtd = &info->mtd; mtd->priv = &info->nand; mtd->name = dev_name(&pdev->dev); @@ -2067,9 +2145,13 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } - ppdata.of_node = pdata->of_node; - mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts, - pdata->nr_parts); + if (dev->of_node) { + ppdata.of_node = dev->of_node; + mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); + + } else { + mtd_device_register(mtd, pdata->parts, pdata->nr_parts); + } platform_set_drvdata(pdev, mtd); @@ -2101,12 +2183,18 @@ static int omap_nand_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id omap_nand_ids[] = { + { .compatible = "ti,omap2-nand", }, + {}, +}; + static struct platform_driver omap_nand_driver = { .probe = omap_nand_probe, .remove = omap_nand_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_nand_ids), }, }; diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 62a855e..45203a5 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -64,10 +64,8 @@ struct omap_nand_platform_data { int devsize; enum omap_ecc ecc_opt; - /* for passing the partitions */ - struct device_node *of_node; - struct device_node *elm_of_node; - struct gpmc_nand_regs reg; /* deprecated */ + struct device_node *elm_of_node; /* deprecated */ + struct device_node *of_node; /* deprecated */ }; #endif