From patchwork Thu Sep 27 16:58:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: dinguyen@altera.com X-Patchwork-Id: 187407 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (unknown [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id CC0222C0096 for ; Fri, 28 Sep 2012 01:59:51 +1000 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1THGUE-0006cN-Jx; Thu, 27 Sep 2012 15:58:50 +0000 Received: from co1ehsobe004.messaging.microsoft.com ([216.32.180.187] helo=co1outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1THGU3-0006ae-21 for linux-mtd@lists.infradead.org; Thu, 27 Sep 2012 15:58:42 +0000 Received: from mail123-co1-R.bigfish.com (10.243.78.243) by CO1EHSOBE012.bigfish.com (10.243.66.75) with Microsoft SMTP Server id 14.1.225.23; Thu, 27 Sep 2012 15:58:35 +0000 Received: from mail123-co1 (localhost [127.0.0.1]) by mail123-co1-R.bigfish.com (Postfix) with ESMTP id F2F34200170; Thu, 27 Sep 2012 15:58:34 +0000 (UTC) X-Forefront-Antispam-Report: CIP:66.35.236.232; KIP:(null); UIP:(null); IPV:NLI; H:SJ-ITEXEDGE02.altera.priv.altera.com; RD:none; EFVD:NLI X-SpamScore: 20 X-BigFish: VS20(z3e12hzc89bh8d0Ic8kd6f1izz1202h1d1ah1d2ahzz8275bh8275dh84d07hz30ih2a8h668h839h93fhd24he5bhf0ah107ah1288h12a5h12a9h12bdh137ah139eh13b6h1307i1155h) Received-SPF: fail (mail123-co1: domain of altera.com does not designate 66.35.236.232 as permitted sender) client-ip=66.35.236.232; envelope-from=dinguyen@altera.com; helo=SJ-ITEXEDGE02.altera.priv.altera.com ; v.altera.com ; Received: from mail123-co1 (localhost.localdomain [127.0.0.1]) by mail123-co1 (MessageSwitch) id 1348761512381000_8930; Thu, 27 Sep 2012 15:58:32 +0000 (UTC) Received: from CO1EHSMHS001.bigfish.com (unknown [10.243.78.249]) by mail123-co1.bigfish.com (Postfix) with ESMTP id 591666001A0; Thu, 27 Sep 2012 15:58:32 +0000 (UTC) Received: from SJ-ITEXEDGE02.altera.priv.altera.com (66.35.236.232) by CO1EHSMHS001.bigfish.com (10.243.66.11) with Microsoft SMTP Server (TLS) id 14.1.225.23; Thu, 27 Sep 2012 15:58:28 +0000 Received: from sj-mail01.altera.com (137.57.1.6) by SJ-ITEXEDGE02.altera.priv.altera.com (66.35.236.232) with Microsoft SMTP Server id 8.3.279.1; Thu, 27 Sep 2012 08:50:55 -0700 Received: from dinh-ubuntu.altera.com (dinh-ubuntu.altera.com [137.57.188.77]) by sj-mail01.altera.com (8.13.7+Sun/8.13.7) with ESMTP id q8RFwKnl005128; Thu, 27 Sep 2012 08:58:26 -0700 (PDT) From: To: Subject: =?UTF-8?q?=5BPATCH=20v2=201/2=5D=20nand/denali=3A=20split=20the=20generic=20driver=20and=20PCI=20layer?= Date: Thu, 27 Sep 2012 10:58:05 -0600 Message-ID: <1348765086-27286-2-git-send-email-dinguyen@altera.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1348765086-27286-1-git-send-email-dinguyen@altera.com> References: <1348765086-27286-1-git-send-email-dinguyen@altera.com> MIME-Version: 1.0 X-OriginatorOrg: altera.com X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [216.32.180.187 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: David Woodhouse , dinh.linux@gmail.com, Jamie Iles , Dinh Nguyen , Chuanxiao Dong X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Dinh Nguyen The Denali controller can also be found in SoC devices attached to a simple bus. Move the PCI specific parts into denali_pci so that we can add a denali_dt that uses the same driver but for a device tree driver instead of a PCI based device. Cc: David Woodhouse Cc: Chuanxiao Dong Signed-off-by: Jamie Iles --- drivers/mtd/nand/Kconfig | 11 ++- drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/denali.c | 160 ++++++++--------------------------------- drivers/mtd/nand/denali.h | 4 ++ drivers/mtd/nand/denali_pci.c | 144 +++++++++++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+), 134 deletions(-) create mode 100644 drivers/mtd/nand/denali_pci.c diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8ca4176..f5659c1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -66,8 +66,15 @@ config MTD_NAND_AUTCPU12 access the SmartMediaCard. config MTD_NAND_DENALI - depends on PCI + tristate "Support Denali NAND controller" + help + Enable support for the Denali NAND controller. This should be + combined with either the PCI or platform drivers to provide device + registration. + +config MTD_NAND_DENALI_PCI tristate "Support Denali NAND controller on Intel Moorestown" + depends on PCI && MTD_NAND_DENALI help Enable the driver for NAND flash on Intel Moorestown, using the Denali NAND controller core. @@ -75,7 +82,7 @@ config MTD_NAND_DENALI config MTD_NAND_DENALI_SCRATCH_REG_ADDR hex "Denali NAND size scratch register address" default "0xFF108018" - depends on MTD_NAND_DENALI + depends on MTD_NAND_DENALI_PCI help Some platforms place the NAND chip size in a scratch register because (some versions of) the driver aren't able to automatically diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d4b4d87..0b3c9e2 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_DENALI) += denali.o +obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0650aaf..870c542 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -16,14 +16,12 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ - #include #include #include #include #include #include -#include #include #include @@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." * format the bank into the proper bits for the controller */ #define BANK(x) ((x) << 24) -/* List of platforms this NAND controller has be integrated into */ -static const struct pci_device_id denali_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, - { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, - { /* end: all zeroes */ } -}; - /* forward declarations */ static void clear_interrupts(struct denali_nand_info *denali); static uint32_t wait_for_irq(struct denali_nand_info *denali, @@ -699,7 +690,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) if (comp_res == 0) { /* timeout */ - printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n", + pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n", intr_status, irq_mask); intr_status = 0; @@ -1303,8 +1294,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, /* TODO: Read OOB data */ break; default: - printk(KERN_ERR ": unsupported command" - " received 0x%x\n", cmd); + pr_err(": unsupported command received 0x%x\n", cmd); break; } } @@ -1423,107 +1413,48 @@ void denali_drv_init(struct denali_nand_info *denali) denali->irq_status = 0; } -/* driver entry point */ -static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +int denali_init(struct denali_nand_info *denali) { - int ret = -ENODEV; - resource_size_t csr_base, mem_base; - unsigned long csr_len, mem_len; - struct denali_nand_info *denali; - - denali = kzalloc(sizeof(*denali), GFP_KERNEL); - if (!denali) - return -ENOMEM; + int ret; - ret = pci_enable_device(dev); - if (ret) { - printk(KERN_ERR "Spectra: pci_enable_device failed.\n"); - goto failed_alloc_memery; - } - - if (id->driver_data == INTEL_CE4100) { + if (denali->platform == INTEL_CE4100) { /* Due to a silicon limitation, we can only support * ONFI timing mode 1 and below. */ if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { - printk(KERN_ERR "Intel CE4100 only supports" - " ONFI timing mode 1 or below\n"); - ret = -EINVAL; - goto failed_enable_dev; - } - denali->platform = INTEL_CE4100; - mem_base = pci_resource_start(dev, 0); - mem_len = pci_resource_len(dev, 1); - csr_base = pci_resource_start(dev, 1); - csr_len = pci_resource_len(dev, 1); - } else { - denali->platform = INTEL_MRST; - csr_base = pci_resource_start(dev, 0); - csr_len = pci_resource_len(dev, 0); - mem_base = pci_resource_start(dev, 1); - mem_len = pci_resource_len(dev, 1); - if (!mem_len) { - mem_base = csr_base + csr_len; - mem_len = csr_len; + pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n"); + return -EINVAL; } } /* Is 32-bit DMA supported? */ - ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); if (ret) { - printk(KERN_ERR "Spectra: no usable DMA configuration\n"); - goto failed_enable_dev; + pr_err("Spectra: no usable DMA configuration\n"); + return ret; } - denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf, + denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, DENALI_BUF_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) { - dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n"); - goto failed_enable_dev; - } - - pci_set_master(dev); - denali->dev = &dev->dev; - denali->mtd.dev.parent = &dev->dev; - - ret = pci_request_regions(dev, DENALI_NAND_NAME); - if (ret) { - printk(KERN_ERR "Spectra: Unable to request memory regions\n"); - goto failed_dma_map; - } - - denali->flash_reg = ioremap_nocache(csr_base, csr_len); - if (!denali->flash_reg) { - printk(KERN_ERR "Spectra: Unable to remap memory region\n"); - ret = -ENOMEM; - goto failed_req_regions; - } - - denali->flash_mem = ioremap_nocache(mem_base, mem_len); - if (!denali->flash_mem) { - printk(KERN_ERR "Spectra: ioremap_nocache failed!"); - ret = -ENOMEM; - goto failed_remap_reg; + if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { + dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); + return -EIO; } - + denali->mtd.dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); /* denali_isr register is done after all the hardware * initilization is finished*/ - if (request_irq(dev->irq, denali_isr, IRQF_SHARED, + if (request_irq(denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali)) { - printk(KERN_ERR "Spectra: Unable to allocate IRQ\n"); - ret = -ENODEV; - goto failed_remap_mem; + pr_err("Spectra: Unable to allocate IRQ\n"); + return -ENODEV; } /* now that our ISR is registered, we can enable interrupts */ denali_set_intr_modes(denali, true); - - pci_set_drvdata(dev, denali); - denali->mtd.name = "denali-nand"; denali->mtd.owner = THIS_MODULE; denali->mtd.priv = &denali->nand; @@ -1547,8 +1478,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) */ if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { ret = -ENODEV; - printk(KERN_ERR "Spectra: device size not supported by this " - "version of MTD."); + pr_err("Spectra: device size not supported by this version of MTD."); goto failed_req_irq; } @@ -1600,8 +1530,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } else if (denali->mtd.oobsize < (denali->bbtskipbytes + ECC_8BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE))) { - printk(KERN_ERR "Your NAND chip OOB is not large enough to" - " contain 8bit ECC correction codes"); + pr_err("Your NAND chip OOB is not large enough to \ + contain 8bit ECC correction codes"); goto failed_req_irq; } else { denali->nand.ecc.strength = 8; @@ -1653,56 +1583,22 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ret = mtd_device_register(&denali->mtd, NULL, 0); if (ret) { - dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n", + dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n", ret); goto failed_req_irq; } return 0; failed_req_irq: - denali_irq_cleanup(dev->irq, denali); -failed_remap_mem: - iounmap(denali->flash_mem); -failed_remap_reg: - iounmap(denali->flash_reg); -failed_req_regions: - pci_release_regions(dev); -failed_dma_map: - dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, - DMA_BIDIRECTIONAL); -failed_enable_dev: - pci_disable_device(dev); -failed_alloc_memery: - kfree(denali); + denali_irq_cleanup(denali->irq, denali); + return ret; } /* driver exit point */ -static void denali_pci_remove(struct pci_dev *dev) +void denali_remove(struct denali_nand_info *denali) { - struct denali_nand_info *denali = pci_get_drvdata(dev); - - nand_release(&denali->mtd); - - denali_irq_cleanup(dev->irq, denali); - - iounmap(denali->flash_reg); - iounmap(denali->flash_mem); - pci_release_regions(dev); - pci_disable_device(dev); - dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, - DMA_BIDIRECTIONAL); - pci_set_drvdata(dev, NULL); - kfree(denali); + denali_irq_cleanup(denali->irq, denali); + dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, + DMA_BIDIRECTIONAL); } - -MODULE_DEVICE_TABLE(pci, denali_pci_ids); - -static struct pci_driver denali_pci_driver = { - .name = DENALI_NAND_NAME, - .id_table = denali_pci_ids, - .probe = denali_pci_probe, - .remove = denali_pci_remove, -}; - -module_pci_driver(denali_pci_driver); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index fabb9d5..e5aa995 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -487,6 +487,7 @@ struct denali_nand_info { uint32_t irq_status; int irq_debug_array[32]; int idx; + int irq; uint32_t devnum; /* represent how many nands connected */ uint32_t fwblks; /* represent how many blocks FW used */ @@ -496,4 +497,7 @@ struct denali_nand_info { uint32_t max_banks; }; +extern int denali_init(struct denali_nand_info *denali); +extern void denali_remove(struct denali_nand_info *denali); + #endif /*_LLD_NAND_*/ diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c new file mode 100644 index 0000000..ea074e6 --- /dev/null +++ b/drivers/mtd/nand/denali_pci.c @@ -0,0 +1,144 @@ +/* + * NAND Flash Controller Device Driver + * Copyright © 2009-2010, Intel Corporation and its suppliers. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include +#include +#include +#include + +#include "denali.h" + +#define DENALI_NAND_NAME "denali-nand-pci" + +/* List of platforms this NAND controller has be integrated into */ +static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = { + { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, + { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, denali_pci_ids); + +static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int ret = -ENODEV; + resource_size_t csr_base, mem_base; + unsigned long csr_len, mem_len; + struct denali_nand_info *denali; + + denali = kzalloc(sizeof(*denali), GFP_KERNEL); + if (!denali) + return -ENOMEM; + + ret = pci_enable_device(dev); + if (ret) { + pr_err("Spectra: pci_enable_device failed.\n"); + goto failed_alloc_memery; + } + + if (id->driver_data == INTEL_CE4100) { + denali->platform = INTEL_CE4100; + mem_base = pci_resource_start(dev, 0); + mem_len = pci_resource_len(dev, 1); + csr_base = pci_resource_start(dev, 1); + csr_len = pci_resource_len(dev, 1); + } else { + denali->platform = INTEL_MRST; + csr_base = pci_resource_start(dev, 0); + csr_len = pci_resource_len(dev, 0); + mem_base = pci_resource_start(dev, 1); + mem_len = pci_resource_len(dev, 1); + if (!mem_len) { + mem_base = csr_base + csr_len; + mem_len = csr_len; + } + } + + pci_set_master(dev); + denali->dev = &dev->dev; + denali->irq = dev->irq; + + ret = pci_request_regions(dev, DENALI_NAND_NAME); + if (ret) { + pr_err("Spectra: Unable to request memory regions\n"); + goto failed_enable_dev; + } + + denali->flash_reg = ioremap_nocache(csr_base, csr_len); + if (!denali->flash_reg) { + pr_err("Spectra: Unable to remap memory region\n"); + ret = -ENOMEM; + goto failed_req_regions; + } + + denali->flash_mem = ioremap_nocache(mem_base, mem_len); + if (!denali->flash_mem) { + pr_err("Spectra: ioremap_nocache failed!"); + ret = -ENOMEM; + goto failed_remap_reg; + } + + ret = denali_init(denali); + if (ret) + goto failed_remap_mem; + + pci_set_drvdata(dev, denali); + + return 0; + +failed_remap_mem: + iounmap(denali->flash_mem); +failed_remap_reg: + iounmap(denali->flash_reg); +failed_req_regions: + pci_release_regions(dev); +failed_enable_dev: + pci_disable_device(dev); +failed_alloc_memery: + kfree(denali); + + return ret; +} + +/* driver exit point */ +static void denali_pci_remove(struct pci_dev *dev) +{ + struct denali_nand_info *denali = pci_get_drvdata(dev); + + denali_remove(denali); + iounmap(denali->flash_reg); + iounmap(denali->flash_mem); + pci_release_regions(dev); + pci_disable_device(dev); + pci_set_drvdata(dev, NULL); + kfree(denali); +} + +static struct pci_driver denali_pci_driver = { + .name = DENALI_NAND_NAME, + .id_table = denali_pci_ids, + .probe = denali_pci_probe, + .remove = denali_pci_remove, +}; + +static int __devinit denali_init_pci(void) +{ + pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__); + return pci_register_driver(&denali_pci_driver); +} +module_init(denali_init_pci); + +static void __devexit denali_exit_pci(void) +{ + pci_unregister_driver(&denali_pci_driver); +} +module_exit(denali_exit_pci);