* [PATCH] port ndfc driver to arch/powerpc
@ 2008-08-02 3:30 Sean MacLennan
2008-08-04 16:25 ` Arnd Bergmann
0 siblings, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-02 3:30 UTC (permalink / raw)
To: linuxppc-dev
This is a port of the ndfc driver from arch/ppc to arch/powerpc. Since
arch/ppc has been removed, references to CONFIG_PPC_MERGE where removed.
For an example of how to use the driver see
arch/powerpc/platforms/44x/warp-nand.c .
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 02f9cc3..b0d408e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -165,7 +165,7 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
- depends on 4xx && !PPC_MERGE
+ depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 955959e..efb1ab6 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -21,14 +21,11 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/ndfc.h>
#include <linux/mtd/mtd.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <asm/io.h>
-#ifdef CONFIG_40x
-#include <asm/ibm405.h>
-#else
-#include <asm/ibm44x.h>
-#endif
struct ndfc_nand_mtd {
struct mtd_info mtd;
@@ -103,8 +100,9 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
wmb();
ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
- ecc_code[0] = p[1];
- ecc_code[1] = p[2];
+ /* The NDFC uses Smart Media (SMC) bytes order */
+ ecc_code[0] = p[2];
+ ecc_code[1] = p[1];
ecc_code[2] = p[3];
return 0;
@@ -234,11 +232,7 @@ static int ndfc_nand_probe(struct platform_device *pdev)
struct ndfc_controller *ndfc = &ndfc_ctrl;
unsigned long long phys = settings->ndfc_erpn | res->start;
-#ifndef CONFIG_PHYS_64BIT
ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
-#else
- ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
-#endif
if (!ndfc->ndfcbase) {
printk(KERN_ERR "NDFC: ioremap failed\n");
return -EIO;
@@ -300,9 +294,16 @@ static int __init ndfc_nand_init(void)
init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
ret = platform_driver_register(&ndfc_nand_driver);
- if (!ret)
- ret = platform_driver_register(&ndfc_chip_driver);
- return ret;
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&ndfc_chip_driver);
+ if (ret) {
+ platform_driver_unregister(&ndfc_nand_driver);
+ return ret;
+ }
+
+ return 0;
}
static void __exit ndfc_nand_exit(void)
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH] port ndfc driver to arch/powerpc
2008-08-02 3:30 [PATCH] port ndfc driver to arch/powerpc Sean MacLennan
@ 2008-08-04 16:25 ` Arnd Bergmann
2008-08-04 17:24 ` Sean MacLennan
0 siblings, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2008-08-04 16:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Sean MacLennan
On Saturday 02 August 2008, Sean MacLennan wrote:
> This is a port of the ndfc driver from arch/ppc to arch/powerpc. Since
> arch/ppc has been removed, references to CONFIG_PPC_MERGE where removed.
>
> For an example of how to use the driver see
> arch/powerpc/platforms/44x/warp-nand.c .
>
> Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
Shouldn't this instead use the device tree, like fsl_elbc, fsl_upm
and pasemi_nand do?
It feels awfully backwards to hardcode this stuff in the platform
source code.
Arnd <><
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH] port ndfc driver to arch/powerpc
2008-08-04 16:25 ` Arnd Bergmann
@ 2008-08-04 17:24 ` Sean MacLennan
2008-08-13 21:36 ` [PATCH 1/2] port ndfc driver to of platform Sean MacLennan
2008-08-13 21:45 ` [PATCH 2/2] " Sean MacLennan
0 siblings, 2 replies; 18+ messages in thread
From: Sean MacLennan @ 2008-08-04 17:24 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, Sean MacLennan
On Mon, 4 Aug 2008 18:25:02 +0200
"Arnd Bergmann" <arnd@arndb.de> wrote:
> Shouldn't this instead use the device tree, like fsl_elbc, fsl_upm
> and pasemi_nand do?
> It feels awfully backwards to hardcode this stuff in the platform
> source code.
Yes, yes it should. This is just a patch to get the driver working... it
is not a full blown of platform driver.
Currently there is no working NDFC driver in the kernel. I felt a
working driver, even if less than optimal, is better than not
supporting NAND on the 44x. This driver is no worse than the
arch/ppc version was, it is just no better ;)
Cheers,
Sean
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-04 17:24 ` Sean MacLennan
@ 2008-08-13 21:36 ` Sean MacLennan
2008-08-14 9:53 ` Arnd Bergmann
2008-08-13 21:45 ` [PATCH 2/2] " Sean MacLennan
1 sibling, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-13 21:36 UTC (permalink / raw)
To: linuxppc-dev, dwmw2; +Cc: Arnd Bergmann
Port of the ndfc driver to an of platform driver.
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index efb1ab6..55aec25 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -5,9 +5,13 @@
* Platform independend driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
*
+ * Ported to an OF platform driver by Sean MacLennan
+ *
* Author: Thomas Gleixner
*
* Copyright 2006 IBM
+ * Copyright 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -23,38 +27,30 @@
#include <linux/mtd/mtd.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/platform_device.h>
-
+#include <linux/of_platform.h>
#include <asm/io.h>
-struct ndfc_nand_mtd {
- struct mtd_info mtd;
- struct nand_chip chip;
- struct platform_nand_chip *pl_chip;
-};
-
-static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
-struct ndfc_controller {
- void __iomem *ndfcbase;
- struct nand_hw_control ndfc_control;
- atomic_t childs_active;
+struct ndfc_ctrl {
+ struct device *dev;
+ void __iomem *ndfcbase;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int chip_select;
+ struct nand_hw_control ndfc_control;
};
-static struct ndfc_controller ndfc_ctrl;
+static struct ndfc_ctrl ndfc_ctrl;
static void ndfc_select_chip(struct mtd_info *mtd, int chip)
{
uint32_t ccr;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *nandchip = mtd->priv;
- struct ndfc_nand_mtd *nandmtd = nandchip->priv;
- struct platform_nand_chip *pchip = nandmtd->pl_chip;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
ccr &= ~NDFC_CCR_BS_MASK;
- ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
+ ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
} else
ccr |= NDFC_CCR_RESET_CE;
__raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
@@ -62,7 +58,7 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
if (cmd == NAND_CMD_NONE)
return;
@@ -75,7 +71,7 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
static int ndfc_ready(struct mtd_info *mtd)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
@@ -83,7 +79,7 @@ static int ndfc_ready(struct mtd_info *mtd)
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
{
uint32_t ccr;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
@@ -94,7 +90,7 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
static int ndfc_calculate_ecc(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
uint32_t ecc;
uint8_t *p = (uint8_t *)&ecc;
@@ -117,7 +113,7 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
*/
static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
@@ -126,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
@@ -135,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
@@ -147,10 +143,18 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Initialize chip structure
*/
-static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
+static int ndfc_chip_init(struct ndfc_ctrl *ndfc, struct device_node *node)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *chip = &mtd->chip;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_types[] = { "cmdlinepart", NULL };
+#else
+ static const char *part_types[] = { NULL };
+#endif
+ struct mtd_partition *parts;
+#endif
+ struct nand_chip *chip = &ndfc->chip;
+ int ret;
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
@@ -158,8 +162,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
chip->chip_delay = 50;
- chip->priv = mtd;
- chip->options = mtd->pl_chip->options;
chip->controller = &ndfc->ndfc_control;
chip->read_buf = ndfc_read_buf;
chip->write_buf = ndfc_write_buf;
@@ -170,153 +172,125 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
- chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
- mtd->mtd.priv = chip;
- mtd->mtd.owner = THIS_MODULE;
-}
-static int ndfc_chip_probe(struct platform_device *pdev)
-{
- struct platform_nand_chip *nc = pdev->dev.platform_data;
- struct ndfc_chip_settings *settings = nc->priv;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct ndfc_nand_mtd *nandmtd;
-
- if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
- return -EINVAL;
-
- /* Set the bank settings */
- __raw_writel(settings->bank_settings,
- ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
+ ndfc->mtd.priv = chip;
+ ndfc->mtd.owner = THIS_MODULE;
- nandmtd = &ndfc_mtd[pdev->id];
- if (nandmtd->pl_chip)
- return -EBUSY;
-
- nandmtd->pl_chip = nc;
- ndfc_chip_init(nandmtd);
+ ret = nand_scan(&ndfc->mtd, 1);
+ if (ret)
+ return ret;
- /* Scan for chips */
- if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
- nandmtd->pl_chip = NULL;
- return -ENODEV;
- }
+ ndfc->mtd.name = ndfc->dev->bus_id;
#ifdef CONFIG_MTD_PARTITIONS
- printk("Number of partitions %d\n", nc->nr_partitions);
- if (nc->nr_partitions) {
- /* Add the full device, so complete dumps can be made */
- add_mtd_device(&nandmtd->mtd);
- add_mtd_partitions(&nandmtd->mtd, nc->partitions,
- nc->nr_partitions);
+ ret = parse_mtd_partitions(&ndfc->mtd, part_types, &parts, 0);
+ if (ret < 0)
+ return ret;
- } else
-#else
- add_mtd_device(&nandmtd->mtd);
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0) {
+ ret = of_mtd_parse_partitions(ndfc->dev, &ndfc->mtd,
+ node, &parts);
+ if (ret < 0)
+ return ret;
+ }
#endif
- atomic_inc(&ndfc->childs_active);
- return 0;
+ if (ret > 0)
+ return add_mtd_partitions(&ndfc->mtd, parts, ret);
+#endif
+ return add_mtd_device(&ndfc->mtd);
}
-static int ndfc_chip_remove(struct platform_device *pdev)
+static int __devinit ndfc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- return 0;
-}
+ struct ndfc_ctrl *ndfc = &ndfc_ctrl;
+ const u32 *reg;
+ u32 ccr, bank_settings;
+ int err, len;
-static int ndfc_nand_probe(struct platform_device *pdev)
-{
- struct platform_nand_ctrl *nc = pdev->dev.platform_data;
- struct ndfc_controller_settings *settings = nc->priv;
- struct resource *res = pdev->resource;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- unsigned long long phys = settings->ndfc_erpn | res->start;
+ spin_lock_init(&ndfc->ndfc_control.lock);
+ init_waitqueue_head(&ndfc->ndfc_control.wq);
+ ndfc->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, ndfc);
+
+ /* Read the reg property to get the chip select */
+ reg = of_get_property(ofdev->node, "reg", &len);
+ if (reg == NULL || len != 12) {
+ dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+ return -ENOENT;
+ }
+ ndfc->chip_select = *reg;
- ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
+ ndfc->ndfcbase = ioremap(reg[1], reg[2]);
if (!ndfc->ndfcbase) {
- printk(KERN_ERR "NDFC: ioremap failed\n");
+ dev_err(&ofdev->dev, "failed to get memory\n");
return -EIO;
}
- __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
+ ccr = NDFC_CCR_BS(ndfc->chip_select);
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ /* It is ok if ccr does not exist - just default to 0 */
+ reg = of_get_property(ofdev->node, "ccr", NULL);
+ if (reg)
+ ccr |= *reg;
- platform_set_drvdata(pdev, ndfc);
+ __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
- printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
- __raw_readl(ndfc->ndfcbase + NDFC_REVID));
+ /* Set the bank settings */
+ reg = of_get_property(ofdev->node, "bank_settings", NULL);
+ bank_settings = reg ? *reg : 0x80002222;
+
+ __raw_writel(bank_settings,
+ ndfc->ndfcbase + NDFC_BCFG0 + (ndfc->chip_select << 2));
+
+ err = ndfc_chip_init(ndfc, ofdev->node);
+ if (err)
+ goto error_cleanup;
return 0;
+
+error_cleanup:
+ iounmap(ndfc->ndfcbase);
+ return err;
}
-static int ndfc_nand_remove(struct platform_device *pdev)
+static int __devexit ndfc_remove(struct of_device *ofdev)
{
- struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
+ struct ndfc_ctrl *ndfc = dev_get_drvdata(&ofdev->dev);
- if (atomic_read(&ndfc->childs_active))
- return -EBUSY;
+ nand_release(&ndfc->mtd);
- if (ndfc) {
- platform_set_drvdata(pdev, NULL);
- iounmap(ndfc_ctrl.ndfcbase);
- ndfc_ctrl.ndfcbase = NULL;
- }
return 0;
}
-/* driver device registration */
-
-static struct platform_driver ndfc_chip_driver = {
- .probe = ndfc_chip_probe,
- .remove = ndfc_chip_remove,
- .driver = {
- .name = "ndfc-chip",
- .owner = THIS_MODULE,
- },
+static const struct of_device_id ndfc_match[] = {
+ { .compatible = "amcc,ndfc", },
+ {}
};
-static struct platform_driver ndfc_nand_driver = {
- .probe = ndfc_nand_probe,
- .remove = ndfc_nand_remove,
- .driver = {
- .name = "ndfc-nand",
- .owner = THIS_MODULE,
+static struct of_platform_driver ndfc_driver = {
+ .driver = {
+ .name = "ndfc",
},
+ .match_table = ndfc_match,
+ .probe = ndfc_probe,
+ .remove = __devexit_p(ndfc_remove),
};
static int __init ndfc_nand_init(void)
{
- int ret;
-
- spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
- init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
-
- ret = platform_driver_register(&ndfc_nand_driver);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&ndfc_chip_driver);
- if (ret) {
- platform_driver_unregister(&ndfc_nand_driver);
- return ret;
- }
-
- return 0;
+ return of_register_platform_driver(&ndfc_driver);
}
+module_init(ndfc_nand_init);
static void __exit ndfc_nand_exit(void)
{
- platform_driver_unregister(&ndfc_chip_driver);
- platform_driver_unregister(&ndfc_nand_driver);
+ of_unregister_platform_driver(&ndfc_driver);
}
-
-module_init(ndfc_nand_init);
module_exit(ndfc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Platform driver for NDFC");
-MODULE_ALIAS("platform:ndfc-chip");
-MODULE_ALIAS("platform:ndfc-nand");
+MODULE_DESCRIPTION("OF Platform driver for NDFC");
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/2] port ndfc driver to of platform
2008-08-04 17:24 ` Sean MacLennan
2008-08-13 21:36 ` [PATCH 1/2] port ndfc driver to of platform Sean MacLennan
@ 2008-08-13 21:45 ` Sean MacLennan
2008-08-14 10:08 ` Arnd Bergmann
1 sibling, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-13 21:45 UTC (permalink / raw)
Cc: linuxppc-dev, Arnd Bergmann
Changes to the warp platform with the ndfc as an of platform device.
The main changes are:
* moving the NAND information to the DTS
* removing warp-nand.c
* moving the NAND fixups to cuboot-warp.c
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/arch/powerpc/boot/cuboot-warp.c b/arch/powerpc/boot/cuboot-warp.c
index 2178021..6d20a46 100644
--- a/arch/powerpc/boot/cuboot-warp.c
+++ b/arch/powerpc/boot/cuboot-warp.c
@@ -34,10 +34,30 @@ static void warp_fixup_one_nor(u32 from, u32 to)
v[0] = to;
setprop(devp, "reg", v, sizeof(v));
- printf("NOR 64M fixup %x -> %x\r\n", from, to);
+ printf("NOR 64M fixup %x -> %x\r\n", from, to);
}
}
+static void warp_fixup_one_nand(u32 from, u32 to, u32 size)
+{
+ void *devp;
+ char name[50];
+ u32 v[2];
+
+ sprintf(name, "/plb/opb/ebc/nand_flash@1,d0000000/partition@%x", from);
+
+ devp = finddevice(name);
+ if (!devp)
+ return;
+
+ if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
+ v[0] = to;
+ v[1] = size;
+ setprop(devp, "reg", v, sizeof(v));
+
+ printf("NAND 64M fixup %x -> %x\r\n", from, to);
+ }
+}
static void warp_fixups(void)
{
@@ -46,25 +66,39 @@ static void warp_fixups(void)
ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
- /* Fixup for 64M flash on Rev A boards. */
+ /* Fixup flash on Rev A boards. */
if (bd.bi_flashsize == 0x4000000) {
void *devp;
u32 v[3];
+ /* NOR */
devp = finddevice("/plb/opb/ebc/nor_flash@0,0");
- if (!devp)
- return;
-
- /* Fixup the size */
- if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
- v[2] = bd.bi_flashsize;
- setprop(devp, "reg", v, sizeof(v));
+ if (devp) {
+ /* Fixup the size */
+ if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
+ v[2] = bd.bi_flashsize;
+ setprop(devp, "reg", v, sizeof(v));
+ }
+
+ /* Fixup parition offsets */
+ warp_fixup_one_nor(0x300000, 0x3f00000);
+ warp_fixup_one_nor(0x340000, 0x3f40000);
+ warp_fixup_one_nor(0x380000, 0x3f80000);
}
- /* Fixup parition offsets */
- warp_fixup_one_nor(0x300000, 0x3f00000);
- warp_fixup_one_nor(0x340000, 0x3f40000);
- warp_fixup_one_nor(0x380000, 0x3f80000);
+ /* NAND */
+ devp = finddevice("/plb/opb/ebc/nand_flash@1,d0000000");
+ if (devp) {
+ /* Fixup the size */
+ if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
+ v[2] = bd.bi_flashsize;
+ setprop(devp, "reg", v, sizeof(v));
+ }
+
+ /* Fixup parition offsets */
+ warp_fixup_one_nand(0x00200000, 0x0200000, 0x3000000);
+ warp_fixup_one_nand(0x40000000, 0x3200000, 0x0e00000);
+ }
}
}
diff --git a/arch/powerpc/boot/dts/warp.dts b/arch/powerpc/boot/dts/warp.dts
index f4e4ba6..c058e3c 100644
--- a/arch/powerpc/boot/dts/warp.dts
+++ b/arch/powerpc/boot/dts/warp.dts
@@ -155,6 +155,10 @@
reg = <0x00000000 0x00000000 0x00400000>;
#address-cells = <1>;
#size-cells = <1>;
+ partition@0 {
+ label = "splash";
+ reg = <0x00000000 0x00020000>;
+ };
partition@300000 {
label = "fpga";
reg = <0x0300000 0x00040000>;
@@ -168,6 +172,36 @@
reg = <0x0380000 0x00080000>;
};
};
+
+ nand_flash@1,d0000000 {
+ compatible = "amcc,ndfc";
+ reg = <0x00000001 0xd0000000 0x00002000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ccr = <0x00001000>;
+ bank_settings = <0x80002222>;
+
+ partition@0 {
+ label = "kernel";
+ reg = <0x00000000 0x00200000>;
+ };
+ partition@200000 {
+ label = "root";
+ reg = <0x00200000 0x03E00000>;
+ };
+ partition@40000000 {
+ label = "persistent";
+ reg = <0x04000000 0x04000000>;
+ };
+ partition@80000000 {
+ label = "persistent1";
+ reg = <0x08000000 0x04000000>;
+ };
+ partition@C0000000 {
+ label = "persistent2";
+ reg = <0x0C000000 0x04000000>;
+ };
+ };
};
UART0: serial@ef600300 {
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 8d0b1a1..53fc7ec 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -8,6 +8,5 @@ obj-$(CONFIG_SEQUOIA) += sequoia.o
obj-$(CONFIG_KATMAI) += katmai.o
obj-$(CONFIG_RAINIER) += rainier.o
obj-$(CONFIG_WARP) += warp.o
-obj-$(CONFIG_WARP) += warp-nand.o
obj-$(CONFIG_CANYONLANDS) += canyonlands.o
obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c
deleted file mode 100644
index 89ecd76..0000000
--- a/arch/powerpc/platforms/44x/warp-nand.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * PIKA Warp(tm) NAND flash specific routines
- *
- * Copyright (c) 2008 PIKA Technologies
- * Sean MacLennan <smaclennan@pikatech.com>
- */
-
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/ndfc.h>
-#include <linux/of.h>
-#include <asm/machdep.h>
-
-
-#ifdef CONFIG_MTD_NAND_NDFC
-
-#define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */
-
-#define WARP_NAND_FLASH_REG_ADDR 0xD0000000UL
-#define WARP_NAND_FLASH_REG_SIZE 0x2000
-
-static struct resource warp_ndfc = {
- .start = WARP_NAND_FLASH_REG_ADDR,
- .end = WARP_NAND_FLASH_REG_ADDR + WARP_NAND_FLASH_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct mtd_partition nand_parts[] = {
- {
- .name = "kernel",
- .offset = 0,
- .size = 0x0200000
- },
- {
- .name = "root",
- .offset = 0x0200000,
- .size = 0x3E00000
- },
- {
- .name = "persistent",
- .offset = 0x4000000,
- .size = 0x4000000
- },
- {
- .name = "persistent1",
- .offset = 0x8000000,
- .size = 0x4000000
- },
- {
- .name = "persistent2",
- .offset = 0xC000000,
- .size = 0x4000000
- }
-};
-
-struct ndfc_controller_settings warp_ndfc_settings = {
- .ccr_settings = (NDFC_CCR_BS(CS_NAND_0) | NDFC_CCR_ARAC1),
- .ndfc_erpn = 0,
-};
-
-static struct ndfc_chip_settings warp_chip0_settings = {
- .bank_settings = 0x80002222,
-};
-
-struct platform_nand_ctrl warp_nand_ctrl = {
- .priv = &warp_ndfc_settings,
-};
-
-static struct platform_device warp_ndfc_device = {
- .name = "ndfc-nand",
- .id = 0,
- .dev = {
- .platform_data = &warp_nand_ctrl,
- },
- .num_resources = 1,
- .resource = &warp_ndfc,
-};
-
-/* Do NOT set the ecclayout: let it default so it is correct for both
- * 64M and 256M flash chips.
- */
-static struct platform_nand_chip warp_nand_chip0 = {
- .nr_chips = 1,
- .chip_offset = CS_NAND_0,
- .nr_partitions = ARRAY_SIZE(nand_parts),
- .partitions = nand_parts,
- .chip_delay = 20,
- .priv = &warp_chip0_settings,
-};
-
-static struct platform_device warp_nand_device = {
- .name = "ndfc-chip",
- .id = 0,
- .num_resources = 0,
- .dev = {
- .platform_data = &warp_nand_chip0,
- .parent = &warp_ndfc_device.dev,
- }
-};
-
-static int warp_setup_nand_flash(void)
-{
- struct device_node *np;
-
- /* Try to detect a rev A based on NOR size. */
- np = of_find_compatible_node(NULL, NULL, "cfi-flash");
- if (np) {
- struct property *pp;
-
- pp = of_find_property(np, "reg", NULL);
- if (pp && (pp->length == 12)) {
- u32 *v = pp->value;
- if (v[2] == 0x4000000) {
- /* Rev A = 64M NAND */
- warp_nand_chip0.nr_partitions = 3;
-
- nand_parts[1].size = 0x3000000;
- nand_parts[2].offset = 0x3200000;
- nand_parts[2].size = 0x0e00000;
- }
- }
- of_node_put(np);
- }
-
- platform_device_register(&warp_ndfc_device);
- platform_device_register(&warp_nand_device);
-
- return 0;
-}
-machine_device_initcall(warp, warp_setup_nand_flash);
-
-#endif
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-13 21:36 ` [PATCH 1/2] port ndfc driver to of platform Sean MacLennan
@ 2008-08-14 9:53 ` Arnd Bergmann
2008-08-14 16:08 ` Sean MacLennan
0 siblings, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2008-08-14 9:53 UTC (permalink / raw)
To: linuxppc-dev; +Cc: dwmw2, Sean MacLennan
On Wednesday 13 August 2008, Sean MacLennan wrote:
> Port of the ndfc driver to an of platform driver.
Look good overall, thanks for following up on this.
> +struct ndfc_ctrl {
> + struct device *dev;
> + void __iomem *ndfcbase;
> + struct mtd_info mtd;
> + struct nand_chip chip;
> + int chip_select;
> + struct nand_hw_control ndfc_control;
> };
conceptually, I would lint to the ofdev, not the dev, even if you
don't need the extra information.
> static void ndfc_select_chip(struct mtd_info *mtd, int chip)
> {
> uint32_t ccr;
> - struct ndfc_controller *ndfc = &ndfc_ctrl;
> - struct nand_chip *nandchip = mtd->priv;
> - struct ndfc_nand_mtd *nandmtd = nandchip->priv;
> - struct platform_nand_chip *pchip = nandmtd->pl_chip;
> + struct ndfc_ctrl *ndfc = &ndfc_ctrl;
>
> ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
This already exists, but I noticed it now: device drivers should
not user __raw_readl/__raw_writel for accessing ioremapped storage.
Instead, you should use ioread32_be or in_be32.
> @@ -83,7 +79,7 @@ static int ndfc_ready(struct mtd_info *mtd)
> static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
> {
> uint32_t ccr;
> - struct ndfc_controller *ndfc = &ndfc_ctrl;
> + struct ndfc_ctrl *ndfc = &ndfc_ctrl;
>
> ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
> ccr |= NDFC_CCR_RESET_ECC;
You have lots of these changes, which do not appear necessary -- if you
just keep the struct ndfc_controller name, your patch will be a lot
smaller.
> -static int ndfc_nand_probe(struct platform_device *pdev)
> -{
> - struct platform_nand_ctrl *nc = pdev->dev.platform_data;
> - struct ndfc_controller_settings *settings = nc->priv;
> - struct resource *res = pdev->resource;
> - struct ndfc_controller *ndfc = &ndfc_ctrl;
> - unsigned long long phys = settings->ndfc_erpn | res->start;
> + spin_lock_init(&ndfc->ndfc_control.lock);
> + init_waitqueue_head(&ndfc->ndfc_control.wq);
> + ndfc->dev = &ofdev->dev;
> + dev_set_drvdata(&ofdev->dev, ndfc);
> +
> + /* Read the reg property to get the chip select */
> + reg = of_get_property(ofdev->node, "reg", &len);
> + if (reg == NULL || len != 12) {
> + dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
> + return -ENOENT;
> + }
> + ndfc->chip_select = *reg;
>
> - ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
> + ndfc->ndfcbase = ioremap(reg[1], reg[2]);
This could be better expressed as of_iomap().
> - platform_set_drvdata(pdev, ndfc);
> + __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
>
> - printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
> - __raw_readl(ndfc->ndfcbase + NDFC_REVID));
> + /* Set the bank settings */
> + reg = of_get_property(ofdev->node, "bank_settings", NULL);
> + bank_settings = reg ? *reg : 0x80002222;
Your device tree does have a bank_setting, so why not assume that
all others will have it as well? I would remove the default.
Arnd <><
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 2/2] port ndfc driver to of platform
2008-08-13 21:45 ` [PATCH 2/2] " Sean MacLennan
@ 2008-08-14 10:08 ` Arnd Bergmann
2008-08-14 16:32 ` Jon Loeliger
2008-08-14 23:20 ` Sean MacLennan
0 siblings, 2 replies; 18+ messages in thread
From: Arnd Bergmann @ 2008-08-14 10:08 UTC (permalink / raw)
To: Sean MacLennan; +Cc: linuxppc-dev, devicetree-discuss
On Wednesday 13 August 2008, Sean MacLennan wrote:
> Changes to the warp platform with the ndfc as an of platform device.
> The main changes are:
>
> * moving the NAND information to the DTS
> * removing warp-nand.c
> * moving the NAND fixups to cuboot-warp.c
The device tree stuff looks good, but the significant fixups you still
need to for the old hw do look like an indication that we should really
have a different way of producing almost-identical dts files.
The cleanest solution for now would be to have two dts files for warp,
but I can understand that you don't want to do that.
Did we ever come to a conclusion on how this could be done, e.g. with
preprocessed dts files or simpler dynamic patching of binary device
trees?
Arnd <><
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-14 9:53 ` Arnd Bergmann
@ 2008-08-14 16:08 ` Sean MacLennan
2008-08-14 17:21 ` Sean MacLennan
2008-08-14 20:16 ` Arnd Bergmann
0 siblings, 2 replies; 18+ messages in thread
From: Sean MacLennan @ 2008-08-14 16:08 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, dwmw2
On Thu, 14 Aug 2008 11:53:07 +0200
"Arnd Bergmann" <arnd@arndb.de> wrote:
> > + ndfc->ndfcbase = ioremap(reg[1], reg[2]);
>
> This could be better expressed as of_iomap().
I tried of_iomap(), but it doesn't seem to like the 3 value reg. i.e.
It doesn't skip the chip select. And since I need to read the reg
property to get the chip select any way, I just used the value directly.
>
> > - platform_set_drvdata(pdev, ndfc);
> > + __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
> >
> > - printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
> > - __raw_readl(ndfc->ndfcbase + NDFC_REVID));
> > + /* Set the bank settings */
> > + reg = of_get_property(ofdev->node, "bank_settings", NULL);
> > + bank_settings = reg ? *reg : 0x80002222;
>
> Your device tree does have a bank_setting, so why not assume that
> all others will have it as well? I would remove the default.
I am thinking of making the bank settings an optional value. I assume
most people with 44x chips with NAND will be using u-boot. If you
enable NAND in u-boot, it should configure the bank settings for you.
I put the bank setting in my dts just to show a "complete"
configuration.
Cheers,
Sean
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 2/2] port ndfc driver to of platform
2008-08-14 10:08 ` Arnd Bergmann
@ 2008-08-14 16:32 ` Jon Loeliger
2008-08-14 23:20 ` Sean MacLennan
1 sibling, 0 replies; 18+ messages in thread
From: Jon Loeliger @ 2008-08-14 16:32 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, devicetree-discuss, Sean MacLennan
Arnd Bergmann wrote:
> Did we ever come to a conclusion on how this could be done, e.g. with
> preprocessed dts files or simpler dynamic patching of binary device
> trees?
>
I am working on it.
jdl
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-14 16:08 ` Sean MacLennan
@ 2008-08-14 17:21 ` Sean MacLennan
2008-08-14 20:16 ` Arnd Bergmann
1 sibling, 0 replies; 18+ messages in thread
From: Sean MacLennan @ 2008-08-14 17:21 UTC (permalink / raw)
Cc: linuxppc-dev, dwmw2, Arnd Bergmann
Second version of patch with cleanups. Note that this patch is slightly
different.... I diffed the last patch against my master git rather than
Linus' master git :( The difference is that my git already had the
ports to arch/powerpc.
Cheers,
Sean
Port of the ndfc driver to an of platform driver.
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 955959e..f09cd27 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -5,9 +5,13 @@
* Platform independend driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
*
+ * Ported to an OF platform driver by Sean MacLennan
+ *
* Author: Thomas Gleixner
*
* Copyright 2006 IBM
+ * Copyright 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -21,27 +25,17 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/ndfc.h>
#include <linux/mtd/mtd.h>
-#include <linux/platform_device.h>
-
+#include <linux/of_platform.h>
#include <asm/io.h>
-#ifdef CONFIG_40x
-#include <asm/ibm405.h>
-#else
-#include <asm/ibm44x.h>
-#endif
-
-struct ndfc_nand_mtd {
- struct mtd_info mtd;
- struct nand_chip chip;
- struct platform_nand_chip *pl_chip;
-};
-static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
struct ndfc_controller {
- void __iomem *ndfcbase;
- struct nand_hw_control ndfc_control;
- atomic_t childs_active;
+ struct of_device *ofdev;
+ void __iomem *ndfcbase;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int chip_select;
+ struct nand_hw_control ndfc_control;
};
static struct ndfc_controller ndfc_ctrl;
@@ -50,17 +44,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
{
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *nandchip = mtd->priv;
- struct ndfc_nand_mtd *nandmtd = nandchip->priv;
- struct platform_nand_chip *pchip = nandmtd->pl_chip;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
ccr &= ~NDFC_CCR_BS_MASK;
- ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
+ ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
} else
ccr |= NDFC_CCR_RESET_CE;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
}
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -80,7 +71,7 @@ static int ndfc_ready(struct mtd_info *mtd)
{
struct ndfc_controller *ndfc = &ndfc_ctrl;
- return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+ return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -88,9 +79,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
wmb();
}
@@ -102,9 +93,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
uint8_t *p = (uint8_t *)&ecc;
wmb();
- ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
- ecc_code[0] = p[1];
- ecc_code[1] = p[2];
+ ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+ /* The NDFC uses Smart Media (SMC) bytes order */
+ ecc_code[0] = p[2];
+ ecc_code[1] = p[1];
ecc_code[2] = p[3];
return 0;
@@ -123,7 +115,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA);
+ *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
}
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -132,7 +124,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA);
+ out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
}
static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -141,7 +133,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA))
+ if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA))
return -EFAULT;
return 0;
}
@@ -149,10 +141,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Initialize chip structure
*/
-static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
+static int ndfc_chip_init(struct ndfc_controller *ndfc,
+ struct device_node *node)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *chip = &mtd->chip;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_types[] = { "cmdlinepart", NULL };
+#else
+ static const char *part_types[] = { NULL };
+#endif
+ struct mtd_partition *parts;
+#endif
+ struct nand_chip *chip = &ndfc->chip;
+ int ret;
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
@@ -160,8 +161,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
chip->chip_delay = 50;
- chip->priv = mtd;
- chip->options = mtd->pl_chip->options;
chip->controller = &ndfc->ndfc_control;
chip->read_buf = ndfc_read_buf;
chip->write_buf = ndfc_write_buf;
@@ -172,143 +171,120 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
- chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
- mtd->mtd.priv = chip;
- mtd->mtd.owner = THIS_MODULE;
-}
-
-static int ndfc_chip_probe(struct platform_device *pdev)
-{
- struct platform_nand_chip *nc = pdev->dev.platform_data;
- struct ndfc_chip_settings *settings = nc->priv;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct ndfc_nand_mtd *nandmtd;
-
- if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
- return -EINVAL;
- /* Set the bank settings */
- __raw_writel(settings->bank_settings,
- ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
+ ndfc->mtd.priv = chip;
+ ndfc->mtd.owner = THIS_MODULE;
- nandmtd = &ndfc_mtd[pdev->id];
- if (nandmtd->pl_chip)
- return -EBUSY;
+ ret = nand_scan(&ndfc->mtd, 1);
+ if (ret)
+ return ret;
- nandmtd->pl_chip = nc;
- ndfc_chip_init(nandmtd);
-
- /* Scan for chips */
- if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
- nandmtd->pl_chip = NULL;
- return -ENODEV;
- }
+ ndfc->mtd.name = ndfc->ofdev->dev.bus_id;
#ifdef CONFIG_MTD_PARTITIONS
- printk("Number of partitions %d\n", nc->nr_partitions);
- if (nc->nr_partitions) {
- /* Add the full device, so complete dumps can be made */
- add_mtd_device(&nandmtd->mtd);
- add_mtd_partitions(&nandmtd->mtd, nc->partitions,
- nc->nr_partitions);
-
- } else
-#else
- add_mtd_device(&nandmtd->mtd);
+ ret = parse_mtd_partitions(&ndfc->mtd, part_types, &parts, 0);
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0) {
+ ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, &ndfc->mtd,
+ node, &parts);
+ if (ret < 0)
+ return ret;
+ }
#endif
- atomic_inc(&ndfc->childs_active);
- return 0;
-}
+ if (ret > 0)
+ return add_mtd_partitions(&ndfc->mtd, parts, ret);
+#endif
-static int ndfc_chip_remove(struct platform_device *pdev)
-{
- return 0;
+ return add_mtd_device(&ndfc->mtd);
}
-static int ndfc_nand_probe(struct platform_device *pdev)
+static int __devinit ndfc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- struct platform_nand_ctrl *nc = pdev->dev.platform_data;
- struct ndfc_controller_settings *settings = nc->priv;
- struct resource *res = pdev->resource;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- unsigned long long phys = settings->ndfc_erpn | res->start;
+ const u32 *reg;
+ u32 ccr;
+ int err, len;
-#ifndef CONFIG_PHYS_64BIT
- ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
-#else
- ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
-#endif
+ spin_lock_init(&ndfc->ndfc_control.lock);
+ init_waitqueue_head(&ndfc->ndfc_control.wq);
+ ndfc->ofdev = ofdev;
+ dev_set_drvdata(&ofdev->dev, ndfc);
+
+ /* Read the reg property to get the chip select */
+ reg = of_get_property(ofdev->node, "reg", &len);
+ if (reg == NULL || len != 12) {
+ dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+ return -ENOENT;
+ }
+ ndfc->chip_select = reg[0];
+
+ ndfc->ndfcbase = ioremap(reg[1], reg[2]);
if (!ndfc->ndfcbase) {
- printk(KERN_ERR "NDFC: ioremap failed\n");
+ dev_err(&ofdev->dev, "failed to get memory\n");
return -EIO;
}
- __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
+ ccr = NDFC_CCR_BS(ndfc->chip_select);
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ /* It is ok if ccr does not exist - just default to 0 */
+ reg = of_get_property(ofdev->node, "ccr", NULL);
+ if (reg)
+ ccr |= *reg;
+
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
- platform_set_drvdata(pdev, ndfc);
+ /* Set the bank settings if given */
+ reg = of_get_property(ofdev->node, "bank-settings", NULL);
+ if (reg) {
+ int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
+ out_be32(ndfc->ndfcbase + offset, *reg);
+ }
- printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
- __raw_readl(ndfc->ndfcbase + NDFC_REVID));
+ err = ndfc_chip_init(ndfc, ofdev->node);
+ if (err) {
+ iounmap(ndfc->ndfcbase);
+ return err;
+ }
return 0;
}
-static int ndfc_nand_remove(struct platform_device *pdev)
+static int __devexit ndfc_remove(struct of_device *ofdev)
{
- struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
+ struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
- if (atomic_read(&ndfc->childs_active))
- return -EBUSY;
+ nand_release(&ndfc->mtd);
- if (ndfc) {
- platform_set_drvdata(pdev, NULL);
- iounmap(ndfc_ctrl.ndfcbase);
- ndfc_ctrl.ndfcbase = NULL;
- }
return 0;
}
-/* driver device registration */
-
-static struct platform_driver ndfc_chip_driver = {
- .probe = ndfc_chip_probe,
- .remove = ndfc_chip_remove,
- .driver = {
- .name = "ndfc-chip",
- .owner = THIS_MODULE,
- },
+static const struct of_device_id ndfc_match[] = {
+ { .compatible = "amcc,ndfc", },
+ {}
};
-static struct platform_driver ndfc_nand_driver = {
- .probe = ndfc_nand_probe,
- .remove = ndfc_nand_remove,
- .driver = {
- .name = "ndfc-nand",
- .owner = THIS_MODULE,
+static struct of_platform_driver ndfc_driver = {
+ .driver = {
+ .name = "ndfc",
},
+ .match_table = ndfc_match,
+ .probe = ndfc_probe,
+ .remove = __devexit_p(ndfc_remove),
};
static int __init ndfc_nand_init(void)
{
- int ret;
-
- spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
- init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
-
- ret = platform_driver_register(&ndfc_nand_driver);
- if (!ret)
- ret = platform_driver_register(&ndfc_chip_driver);
- return ret;
+ return of_register_platform_driver(&ndfc_driver);
}
static void __exit ndfc_nand_exit(void)
{
- platform_driver_unregister(&ndfc_chip_driver);
- platform_driver_unregister(&ndfc_nand_driver);
+ of_unregister_platform_driver(&ndfc_driver);
}
module_init(ndfc_nand_init);
@@ -316,6 +292,4 @@ module_exit(ndfc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Platform driver for NDFC");
-MODULE_ALIAS("platform:ndfc-chip");
-MODULE_ALIAS("platform:ndfc-nand");
+MODULE_DESCRIPTION("OF Platform driver for NDFC");
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-14 16:08 ` Sean MacLennan
2008-08-14 17:21 ` Sean MacLennan
@ 2008-08-14 20:16 ` Arnd Bergmann
2008-08-14 20:54 ` Sean MacLennan
1 sibling, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2008-08-14 20:16 UTC (permalink / raw)
To: Sean MacLennan; +Cc: linuxppc-dev, dwmw2
On Thursday 14 August 2008, Sean MacLennan wrote:
> On Thu, 14 Aug 2008 11:53:07 +0200
> "Arnd Bergmann" <arnd@arndb.de> wrote:
>
> > > + ndfc->ndfcbase = ioremap(reg[1], reg[2]);
> >
> > This could be better expressed as of_iomap().
>
> I tried of_iomap(), but it doesn't seem to like the 3 value reg. i.e.
> It doesn't skip the chip select. And since I need to read the reg
> property to get the chip select any way, I just used the value directly.
If of_iomap and of_address_to_resource don't work properly, there
is probably something wrong in your device tree, maybe an incorrect
#size-cells or #address-cells or ranges property in one of
the parents. You need to fix this anyway.
> > > - platform_set_drvdata(pdev, ndfc);
> > > + __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
> > >
> > > - printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
> > > - __raw_readl(ndfc->ndfcbase + NDFC_REVID));
> > > + /* Set the bank settings */
> > > + reg = of_get_property(ofdev->node, "bank_settings", NULL);
> > > + bank_settings = reg ? *reg : 0x80002222;
> >
> > Your device tree does have a bank_setting, so why not assume that
> > all others will have it as well? I would remove the default.
>
> I am thinking of making the bank settings an optional value. I assume
> most people with 44x chips with NAND will be using u-boot. If you
> enable NAND in u-boot, it should configure the bank settings for you.
>
> I put the bank setting in my dts just to show a "complete"
> configuration.
Ok, I guess that in the absence of the property, you should not do anything
with this value then, rather than assuming a default.
Arnd <><
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-14 20:16 ` Arnd Bergmann
@ 2008-08-14 20:54 ` Sean MacLennan
2008-08-14 23:10 ` Sean MacLennan
0 siblings, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-14 20:54 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, dwmw2
On Thu, 14 Aug 2008 22:16:45 +0200
"Arnd Bergmann" <arnd@arndb.de> wrote:
> If of_iomap and of_address_to_resource don't work properly, there
> is probably something wrong in your device tree, maybe an incorrect
> #size-cells or #address-cells or ranges property in one of
> the parents. You need to fix this anyway.
Gahhhh, no my dts is wrong. I must have looked at it a dozen times
before I clued in that now that ndfc is a proper of driver I need to
specify the chip select and the *offset*, not the chip select and the
*address*.
New patches soon.
Cheers,
Sean
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-14 20:54 ` Sean MacLennan
@ 2008-08-14 23:10 ` Sean MacLennan
2008-08-15 7:27 ` Arnd Bergmann
0 siblings, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-14 23:10 UTC (permalink / raw)
Cc: linuxppc-dev, dwmw2, Arnd Bergmann
Port the ndfc driver to an OF platform driver.
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 41f361c..ab0d77e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -165,7 +165,7 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
- depends on 4xx && !PPC_MERGE
+ depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 955959e..75a3bf0 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -5,9 +5,13 @@
* Platform independend driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
*
+ * Ported to an OF platform driver by Sean MacLennan
+ *
* Author: Thomas Gleixner
*
* Copyright 2006 IBM
+ * Copyright 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -21,27 +25,17 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/ndfc.h>
#include <linux/mtd/mtd.h>
-#include <linux/platform_device.h>
-
+#include <linux/of_platform.h>
#include <asm/io.h>
-#ifdef CONFIG_40x
-#include <asm/ibm405.h>
-#else
-#include <asm/ibm44x.h>
-#endif
-
-struct ndfc_nand_mtd {
- struct mtd_info mtd;
- struct nand_chip chip;
- struct platform_nand_chip *pl_chip;
-};
-static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
struct ndfc_controller {
- void __iomem *ndfcbase;
- struct nand_hw_control ndfc_control;
- atomic_t childs_active;
+ struct of_device *ofdev;
+ void __iomem *ndfcbase;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int chip_select;
+ struct nand_hw_control ndfc_control;
};
static struct ndfc_controller ndfc_ctrl;
@@ -50,17 +44,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
{
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *nandchip = mtd->priv;
- struct ndfc_nand_mtd *nandmtd = nandchip->priv;
- struct platform_nand_chip *pchip = nandmtd->pl_chip;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
ccr &= ~NDFC_CCR_BS_MASK;
- ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
+ ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
} else
ccr |= NDFC_CCR_RESET_CE;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
}
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -80,7 +71,7 @@ static int ndfc_ready(struct mtd_info *mtd)
{
struct ndfc_controller *ndfc = &ndfc_ctrl;
- return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+ return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -88,9 +79,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
wmb();
}
@@ -102,9 +93,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
uint8_t *p = (uint8_t *)&ecc;
wmb();
- ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
- ecc_code[0] = p[1];
- ecc_code[1] = p[2];
+ ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+ /* The NDFC uses Smart Media (SMC) bytes order */
+ ecc_code[0] = p[2];
+ ecc_code[1] = p[1];
ecc_code[2] = p[3];
return 0;
@@ -123,7 +115,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA);
+ *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
}
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -132,7 +124,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA);
+ out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
}
static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -141,7 +133,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA))
+ if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA))
return -EFAULT;
return 0;
}
@@ -149,10 +141,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Initialize chip structure
*/
-static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
+static int ndfc_chip_init(struct ndfc_controller *ndfc,
+ struct device_node *node)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *chip = &mtd->chip;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_types[] = { "cmdlinepart", NULL };
+#else
+ static const char *part_types[] = { NULL };
+#endif
+ struct mtd_partition *parts;
+#endif
+ struct nand_chip *chip = &ndfc->chip;
+ int ret;
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
@@ -160,8 +161,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
chip->chip_delay = 50;
- chip->priv = mtd;
- chip->options = mtd->pl_chip->options;
chip->controller = &ndfc->ndfc_control;
chip->read_buf = ndfc_read_buf;
chip->write_buf = ndfc_write_buf;
@@ -172,143 +171,120 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
- chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
- mtd->mtd.priv = chip;
- mtd->mtd.owner = THIS_MODULE;
-}
-
-static int ndfc_chip_probe(struct platform_device *pdev)
-{
- struct platform_nand_chip *nc = pdev->dev.platform_data;
- struct ndfc_chip_settings *settings = nc->priv;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct ndfc_nand_mtd *nandmtd;
-
- if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
- return -EINVAL;
- /* Set the bank settings */
- __raw_writel(settings->bank_settings,
- ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
+ ndfc->mtd.priv = chip;
+ ndfc->mtd.owner = THIS_MODULE;
- nandmtd = &ndfc_mtd[pdev->id];
- if (nandmtd->pl_chip)
- return -EBUSY;
+ ret = nand_scan(&ndfc->mtd, 1);
+ if (ret)
+ return ret;
- nandmtd->pl_chip = nc;
- ndfc_chip_init(nandmtd);
-
- /* Scan for chips */
- if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
- nandmtd->pl_chip = NULL;
- return -ENODEV;
- }
+ ndfc->mtd.name = ndfc->ofdev->dev.bus_id;
#ifdef CONFIG_MTD_PARTITIONS
- printk("Number of partitions %d\n", nc->nr_partitions);
- if (nc->nr_partitions) {
- /* Add the full device, so complete dumps can be made */
- add_mtd_device(&nandmtd->mtd);
- add_mtd_partitions(&nandmtd->mtd, nc->partitions,
- nc->nr_partitions);
-
- } else
-#else
- add_mtd_device(&nandmtd->mtd);
+ ret = parse_mtd_partitions(&ndfc->mtd, part_types, &parts, 0);
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0) {
+ ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, &ndfc->mtd,
+ node, &parts);
+ if (ret < 0)
+ return ret;
+ }
#endif
- atomic_inc(&ndfc->childs_active);
- return 0;
-}
+ if (ret > 0)
+ return add_mtd_partitions(&ndfc->mtd, parts, ret);
+#endif
-static int ndfc_chip_remove(struct platform_device *pdev)
-{
- return 0;
+ return add_mtd_device(&ndfc->mtd);
}
-static int ndfc_nand_probe(struct platform_device *pdev)
+static int __devinit ndfc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- struct platform_nand_ctrl *nc = pdev->dev.platform_data;
- struct ndfc_controller_settings *settings = nc->priv;
- struct resource *res = pdev->resource;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- unsigned long long phys = settings->ndfc_erpn | res->start;
+ const u32 *reg;
+ u32 ccr;
+ int err, len;
-#ifndef CONFIG_PHYS_64BIT
- ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
-#else
- ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
-#endif
+ spin_lock_init(&ndfc->ndfc_control.lock);
+ init_waitqueue_head(&ndfc->ndfc_control.wq);
+ ndfc->ofdev = ofdev;
+ dev_set_drvdata(&ofdev->dev, ndfc);
+
+ /* Read the reg property to get the chip select */
+ reg = of_get_property(ofdev->node, "reg", &len);
+ if (reg == NULL || len != 12) {
+ dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+ return -ENOENT;
+ }
+ ndfc->chip_select = reg[0];
+
+ ndfc->ndfcbase = of_iomap(ofdev->node, 0);
if (!ndfc->ndfcbase) {
- printk(KERN_ERR "NDFC: ioremap failed\n");
+ dev_err(&ofdev->dev, "failed to get memory\n");
return -EIO;
}
- __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
+ ccr = NDFC_CCR_BS(ndfc->chip_select);
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ /* It is ok if ccr does not exist - just default to 0 */
+ reg = of_get_property(ofdev->node, "ccr", NULL);
+ if (reg)
+ ccr |= *reg;
+
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
- platform_set_drvdata(pdev, ndfc);
+ /* Set the bank settings if given */
+ reg = of_get_property(ofdev->node, "bank-settings", NULL);
+ if (reg) {
+ int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
+ out_be32(ndfc->ndfcbase + offset, *reg);
+ }
- printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
- __raw_readl(ndfc->ndfcbase + NDFC_REVID));
+ err = ndfc_chip_init(ndfc, ofdev->node);
+ if (err) {
+ iounmap(ndfc->ndfcbase);
+ return err;
+ }
return 0;
}
-static int ndfc_nand_remove(struct platform_device *pdev)
+static int __devexit ndfc_remove(struct of_device *ofdev)
{
- struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
+ struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
- if (atomic_read(&ndfc->childs_active))
- return -EBUSY;
+ nand_release(&ndfc->mtd);
- if (ndfc) {
- platform_set_drvdata(pdev, NULL);
- iounmap(ndfc_ctrl.ndfcbase);
- ndfc_ctrl.ndfcbase = NULL;
- }
return 0;
}
-/* driver device registration */
-
-static struct platform_driver ndfc_chip_driver = {
- .probe = ndfc_chip_probe,
- .remove = ndfc_chip_remove,
- .driver = {
- .name = "ndfc-chip",
- .owner = THIS_MODULE,
- },
+static const struct of_device_id ndfc_match[] = {
+ { .compatible = "amcc,ndfc", },
+ {}
};
-static struct platform_driver ndfc_nand_driver = {
- .probe = ndfc_nand_probe,
- .remove = ndfc_nand_remove,
- .driver = {
- .name = "ndfc-nand",
- .owner = THIS_MODULE,
+static struct of_platform_driver ndfc_driver = {
+ .driver = {
+ .name = "ndfc",
},
+ .match_table = ndfc_match,
+ .probe = ndfc_probe,
+ .remove = __devexit_p(ndfc_remove),
};
static int __init ndfc_nand_init(void)
{
- int ret;
-
- spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
- init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
-
- ret = platform_driver_register(&ndfc_nand_driver);
- if (!ret)
- ret = platform_driver_register(&ndfc_chip_driver);
- return ret;
+ return of_register_platform_driver(&ndfc_driver);
}
static void __exit ndfc_nand_exit(void)
{
- platform_driver_unregister(&ndfc_chip_driver);
- platform_driver_unregister(&ndfc_nand_driver);
+ of_unregister_platform_driver(&ndfc_driver);
}
module_init(ndfc_nand_init);
@@ -316,6 +292,4 @@ module_exit(ndfc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Platform driver for NDFC");
-MODULE_ALIAS("platform:ndfc-chip");
-MODULE_ALIAS("platform:ndfc-nand");
+MODULE_DESCRIPTION("OF Platform driver for NDFC");
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/2] port ndfc driver to of platform
2008-08-14 10:08 ` Arnd Bergmann
2008-08-14 16:32 ` Jon Loeliger
@ 2008-08-14 23:20 ` Sean MacLennan
2008-08-15 5:24 ` Sean MacLennan
1 sibling, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-14 23:20 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, devicetree-discuss
The only real change from the last version was the updating of the dts
to use the chip select and offset for the NAND address rather than the
chip select and address.
Cheers,
Sean
Changes to the warp platform with the ndfc as an of platform device.
The main changes are:
* moving the NAND information to the DTS
* removing warp-nand.c
* moving the NAND fixups to cuboot-warp.c
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/arch/powerpc/boot/cuboot-warp.c b/arch/powerpc/boot/cuboot-warp.c
index 2178021..6d20a46 100644
--- a/arch/powerpc/boot/cuboot-warp.c
+++ b/arch/powerpc/boot/cuboot-warp.c
@@ -34,10 +34,30 @@ static void warp_fixup_one_nor(u32 from, u32 to)
v[0] = to;
setprop(devp, "reg", v, sizeof(v));
- printf("NOR 64M fixup %x -> %x\r\n", from, to);
+ printf("NOR 64M fixup %x -> %x\r\n", from, to);
}
}
+static void warp_fixup_one_nand(u32 from, u32 to, u32 size)
+{
+ void *devp;
+ char name[50];
+ u32 v[2];
+
+ sprintf(name, "/plb/opb/ebc/nand_flash@1,d0000000/partition@%x", from);
+
+ devp = finddevice(name);
+ if (!devp)
+ return;
+
+ if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
+ v[0] = to;
+ v[1] = size;
+ setprop(devp, "reg", v, sizeof(v));
+
+ printf("NAND 64M fixup %x -> %x\r\n", from, to);
+ }
+}
static void warp_fixups(void)
{
@@ -46,25 +66,39 @@ static void warp_fixups(void)
ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
- /* Fixup for 64M flash on Rev A boards. */
+ /* Fixup flash on Rev A boards. */
if (bd.bi_flashsize == 0x4000000) {
void *devp;
u32 v[3];
+ /* NOR */
devp = finddevice("/plb/opb/ebc/nor_flash@0,0");
- if (!devp)
- return;
-
- /* Fixup the size */
- if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
- v[2] = bd.bi_flashsize;
- setprop(devp, "reg", v, sizeof(v));
+ if (devp) {
+ /* Fixup the size */
+ if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
+ v[2] = bd.bi_flashsize;
+ setprop(devp, "reg", v, sizeof(v));
+ }
+
+ /* Fixup parition offsets */
+ warp_fixup_one_nor(0x300000, 0x3f00000);
+ warp_fixup_one_nor(0x340000, 0x3f40000);
+ warp_fixup_one_nor(0x380000, 0x3f80000);
}
- /* Fixup parition offsets */
- warp_fixup_one_nor(0x300000, 0x3f00000);
- warp_fixup_one_nor(0x340000, 0x3f40000);
- warp_fixup_one_nor(0x380000, 0x3f80000);
+ /* NAND */
+ devp = finddevice("/plb/opb/ebc/nand_flash@1,d0000000");
+ if (devp) {
+ /* Fixup the size */
+ if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
+ v[2] = bd.bi_flashsize;
+ setprop(devp, "reg", v, sizeof(v));
+ }
+
+ /* Fixup parition offsets */
+ warp_fixup_one_nand(0x00200000, 0x0200000, 0x3000000);
+ warp_fixup_one_nand(0x40000000, 0x3200000, 0x0e00000);
+ }
}
}
diff --git a/arch/powerpc/boot/dts/warp.dts b/arch/powerpc/boot/dts/warp.dts
index f4e4ba6..ffff81a 100644
--- a/arch/powerpc/boot/dts/warp.dts
+++ b/arch/powerpc/boot/dts/warp.dts
@@ -155,6 +155,11 @@
reg = <0x00000000 0x00000000 0x00400000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ partition@0 {
+ label = "splash";
+ reg = <0x00000000 0x00020000>;
+ };
partition@300000 {
label = "fpga";
reg = <0x0300000 0x00040000>;
@@ -168,6 +173,36 @@
reg = <0x0380000 0x00080000>;
};
};
+
+ nand_flash@1,0 {
+ compatible = "amcc,ndfc";
+ reg = <0x00000001 0x00000000 0x00002000>;
+ ccr = <0x00001000>;
+ bank-settings = <0x80002222>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "kernel";
+ reg = <0x00000000 0x00200000>;
+ };
+ partition@200000 {
+ label = "root";
+ reg = <0x00200000 0x03E00000>;
+ };
+ partition@40000000 {
+ label = "persistent";
+ reg = <0x04000000 0x04000000>;
+ };
+ partition@80000000 {
+ label = "persistent1";
+ reg = <0x08000000 0x04000000>;
+ };
+ partition@C0000000 {
+ label = "persistent2";
+ reg = <0x0C000000 0x04000000>;
+ };
+ };
};
UART0: serial@ef600300 {
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 8d0b1a1..53fc7ec 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -8,6 +8,5 @@ obj-$(CONFIG_SEQUOIA) += sequoia.o
obj-$(CONFIG_KATMAI) += katmai.o
obj-$(CONFIG_RAINIER) += rainier.o
obj-$(CONFIG_WARP) += warp.o
-obj-$(CONFIG_WARP) += warp-nand.o
obj-$(CONFIG_CANYONLANDS) += canyonlands.o
obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c
deleted file mode 100644
index 89ecd76..0000000
--- a/arch/powerpc/platforms/44x/warp-nand.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * PIKA Warp(tm) NAND flash specific routines
- *
- * Copyright (c) 2008 PIKA Technologies
- * Sean MacLennan <smaclennan@pikatech.com>
- */
-
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/ndfc.h>
-#include <linux/of.h>
-#include <asm/machdep.h>
-
-
-#ifdef CONFIG_MTD_NAND_NDFC
-
-#define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */
-
-#define WARP_NAND_FLASH_REG_ADDR 0xD0000000UL
-#define WARP_NAND_FLASH_REG_SIZE 0x2000
-
-static struct resource warp_ndfc = {
- .start = WARP_NAND_FLASH_REG_ADDR,
- .end = WARP_NAND_FLASH_REG_ADDR + WARP_NAND_FLASH_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct mtd_partition nand_parts[] = {
- {
- .name = "kernel",
- .offset = 0,
- .size = 0x0200000
- },
- {
- .name = "root",
- .offset = 0x0200000,
- .size = 0x3E00000
- },
- {
- .name = "persistent",
- .offset = 0x4000000,
- .size = 0x4000000
- },
- {
- .name = "persistent1",
- .offset = 0x8000000,
- .size = 0x4000000
- },
- {
- .name = "persistent2",
- .offset = 0xC000000,
- .size = 0x4000000
- }
-};
-
-struct ndfc_controller_settings warp_ndfc_settings = {
- .ccr_settings = (NDFC_CCR_BS(CS_NAND_0) | NDFC_CCR_ARAC1),
- .ndfc_erpn = 0,
-};
-
-static struct ndfc_chip_settings warp_chip0_settings = {
- .bank_settings = 0x80002222,
-};
-
-struct platform_nand_ctrl warp_nand_ctrl = {
- .priv = &warp_ndfc_settings,
-};
-
-static struct platform_device warp_ndfc_device = {
- .name = "ndfc-nand",
- .id = 0,
- .dev = {
- .platform_data = &warp_nand_ctrl,
- },
- .num_resources = 1,
- .resource = &warp_ndfc,
-};
-
-/* Do NOT set the ecclayout: let it default so it is correct for both
- * 64M and 256M flash chips.
- */
-static struct platform_nand_chip warp_nand_chip0 = {
- .nr_chips = 1,
- .chip_offset = CS_NAND_0,
- .nr_partitions = ARRAY_SIZE(nand_parts),
- .partitions = nand_parts,
- .chip_delay = 20,
- .priv = &warp_chip0_settings,
-};
-
-static struct platform_device warp_nand_device = {
- .name = "ndfc-chip",
- .id = 0,
- .num_resources = 0,
- .dev = {
- .platform_data = &warp_nand_chip0,
- .parent = &warp_ndfc_device.dev,
- }
-};
-
-static int warp_setup_nand_flash(void)
-{
- struct device_node *np;
-
- /* Try to detect a rev A based on NOR size. */
- np = of_find_compatible_node(NULL, NULL, "cfi-flash");
- if (np) {
- struct property *pp;
-
- pp = of_find_property(np, "reg", NULL);
- if (pp && (pp->length == 12)) {
- u32 *v = pp->value;
- if (v[2] == 0x4000000) {
- /* Rev A = 64M NAND */
- warp_nand_chip0.nr_partitions = 3;
-
- nand_parts[1].size = 0x3000000;
- nand_parts[2].offset = 0x3200000;
- nand_parts[2].size = 0x0e00000;
- }
- }
- of_node_put(np);
- }
-
- platform_device_register(&warp_ndfc_device);
- platform_device_register(&warp_nand_device);
-
- return 0;
-}
-machine_device_initcall(warp, warp_setup_nand_flash);
-
-#endif
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/2] port ndfc driver to of platform
2008-08-14 23:20 ` Sean MacLennan
@ 2008-08-15 5:24 ` Sean MacLennan
2008-08-15 7:28 ` Arnd Bergmann
0 siblings, 1 reply; 18+ messages in thread
From: Sean MacLennan @ 2008-08-15 5:24 UTC (permalink / raw)
Cc: linuxppc-dev, Arnd Bergmann
Hopefully the last change. I decided to remove all the rev A fixups
from the cuboot-warp file. I am the only person using a rev A, and I
can use the command line to specify any needed partitions. There is
really only one partition needed to boot from nand since u-boot can be
used to flash the images.
Note the patch is now smaller since we don't need the NAND fixups!
Cheers,
Sean
Changes to the warp platform with the ndfc as an of platform device.
The main changes are:
* move the NAND information to the DTS
* remove warp-nand.c
* remove rev A fixups from cuboot-warp.c
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/arch/powerpc/boot/cuboot-warp.c b/arch/powerpc/boot/cuboot-warp.c
index 2178021..806df69 100644
--- a/arch/powerpc/boot/cuboot-warp.c
+++ b/arch/powerpc/boot/cuboot-warp.c
@@ -18,57 +18,14 @@
static bd_t bd;
-static void warp_fixup_one_nor(u32 from, u32 to)
-{
- void *devp;
- char name[50];
- u32 v[2];
-
- sprintf(name, "/plb/opb/ebc/nor_flash@0,0/partition@%x", from);
-
- devp = finddevice(name);
- if (!devp)
- return;
-
- if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
- v[0] = to;
- setprop(devp, "reg", v, sizeof(v));
-
- printf("NOR 64M fixup %x -> %x\r\n", from, to);
- }
-}
-
-
static void warp_fixups(void)
{
ibm440ep_fixup_clocks(66000000, 11059200, 50000000);
ibm4xx_sdram_fixup_memsize();
ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
-
- /* Fixup for 64M flash on Rev A boards. */
- if (bd.bi_flashsize == 0x4000000) {
- void *devp;
- u32 v[3];
-
- devp = finddevice("/plb/opb/ebc/nor_flash@0,0");
- if (!devp)
- return;
-
- /* Fixup the size */
- if (getprop(devp, "reg", v, sizeof(v)) == sizeof(v)) {
- v[2] = bd.bi_flashsize;
- setprop(devp, "reg", v, sizeof(v));
- }
-
- /* Fixup parition offsets */
- warp_fixup_one_nor(0x300000, 0x3f00000);
- warp_fixup_one_nor(0x340000, 0x3f40000);
- warp_fixup_one_nor(0x380000, 0x3f80000);
- }
}
-
void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
diff --git a/arch/powerpc/boot/dts/warp.dts b/arch/powerpc/boot/dts/warp.dts
index f4e4ba6..b92089c 100644
--- a/arch/powerpc/boot/dts/warp.dts
+++ b/arch/powerpc/boot/dts/warp.dts
@@ -149,12 +149,17 @@
reg = <0x00000002 0x00004000 0x00000A00>;
};
- nor_flash@0,0 {
+ nor@0,0 {
compatible = "amd,s29gl032a", "cfi-flash";
bank-width = <2>;
reg = <0x00000000 0x00000000 0x00400000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ partition@0 {
+ label = "splash";
+ reg = <0x00000000 0x00020000>;
+ };
partition@300000 {
label = "fpga";
reg = <0x0300000 0x00040000>;
@@ -168,6 +173,36 @@
reg = <0x0380000 0x00080000>;
};
};
+
+ nand@1,0 {
+ compatible = "amcc,ndfc";
+ reg = <0x00000001 0x00000000 0x00002000>;
+ ccr = <0x00001000>;
+ bank-settings = <0x80002222>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "kernel";
+ reg = <0x00000000 0x00200000>;
+ };
+ partition@200000 {
+ label = "root";
+ reg = <0x00200000 0x03E00000>;
+ };
+ partition@40000000 {
+ label = "persistent";
+ reg = <0x04000000 0x04000000>;
+ };
+ partition@80000000 {
+ label = "persistent1";
+ reg = <0x08000000 0x04000000>;
+ };
+ partition@C0000000 {
+ label = "persistent2";
+ reg = <0x0C000000 0x04000000>;
+ };
+ };
};
UART0: serial@ef600300 {
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 8d0b1a1..53fc7ec 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -8,6 +8,5 @@ obj-$(CONFIG_SEQUOIA) += sequoia.o
obj-$(CONFIG_KATMAI) += katmai.o
obj-$(CONFIG_RAINIER) += rainier.o
obj-$(CONFIG_WARP) += warp.o
-obj-$(CONFIG_WARP) += warp-nand.o
obj-$(CONFIG_CANYONLANDS) += canyonlands.o
obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c
deleted file mode 100644
index 89ecd76..0000000
--- a/arch/powerpc/platforms/44x/warp-nand.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * PIKA Warp(tm) NAND flash specific routines
- *
- * Copyright (c) 2008 PIKA Technologies
- * Sean MacLennan <smaclennan@pikatech.com>
- */
-
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/ndfc.h>
-#include <linux/of.h>
-#include <asm/machdep.h>
-
-
-#ifdef CONFIG_MTD_NAND_NDFC
-
-#define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */
-
-#define WARP_NAND_FLASH_REG_ADDR 0xD0000000UL
-#define WARP_NAND_FLASH_REG_SIZE 0x2000
-
-static struct resource warp_ndfc = {
- .start = WARP_NAND_FLASH_REG_ADDR,
- .end = WARP_NAND_FLASH_REG_ADDR + WARP_NAND_FLASH_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct mtd_partition nand_parts[] = {
- {
- .name = "kernel",
- .offset = 0,
- .size = 0x0200000
- },
- {
- .name = "root",
- .offset = 0x0200000,
- .size = 0x3E00000
- },
- {
- .name = "persistent",
- .offset = 0x4000000,
- .size = 0x4000000
- },
- {
- .name = "persistent1",
- .offset = 0x8000000,
- .size = 0x4000000
- },
- {
- .name = "persistent2",
- .offset = 0xC000000,
- .size = 0x4000000
- }
-};
-
-struct ndfc_controller_settings warp_ndfc_settings = {
- .ccr_settings = (NDFC_CCR_BS(CS_NAND_0) | NDFC_CCR_ARAC1),
- .ndfc_erpn = 0,
-};
-
-static struct ndfc_chip_settings warp_chip0_settings = {
- .bank_settings = 0x80002222,
-};
-
-struct platform_nand_ctrl warp_nand_ctrl = {
- .priv = &warp_ndfc_settings,
-};
-
-static struct platform_device warp_ndfc_device = {
- .name = "ndfc-nand",
- .id = 0,
- .dev = {
- .platform_data = &warp_nand_ctrl,
- },
- .num_resources = 1,
- .resource = &warp_ndfc,
-};
-
-/* Do NOT set the ecclayout: let it default so it is correct for both
- * 64M and 256M flash chips.
- */
-static struct platform_nand_chip warp_nand_chip0 = {
- .nr_chips = 1,
- .chip_offset = CS_NAND_0,
- .nr_partitions = ARRAY_SIZE(nand_parts),
- .partitions = nand_parts,
- .chip_delay = 20,
- .priv = &warp_chip0_settings,
-};
-
-static struct platform_device warp_nand_device = {
- .name = "ndfc-chip",
- .id = 0,
- .num_resources = 0,
- .dev = {
- .platform_data = &warp_nand_chip0,
- .parent = &warp_ndfc_device.dev,
- }
-};
-
-static int warp_setup_nand_flash(void)
-{
- struct device_node *np;
-
- /* Try to detect a rev A based on NOR size. */
- np = of_find_compatible_node(NULL, NULL, "cfi-flash");
- if (np) {
- struct property *pp;
-
- pp = of_find_property(np, "reg", NULL);
- if (pp && (pp->length == 12)) {
- u32 *v = pp->value;
- if (v[2] == 0x4000000) {
- /* Rev A = 64M NAND */
- warp_nand_chip0.nr_partitions = 3;
-
- nand_parts[1].size = 0x3000000;
- nand_parts[2].offset = 0x3200000;
- nand_parts[2].size = 0x0e00000;
- }
- }
- of_node_put(np);
- }
-
- platform_device_register(&warp_ndfc_device);
- platform_device_register(&warp_nand_device);
-
- return 0;
-}
-machine_device_initcall(warp, warp_setup_nand_flash);
-
-#endif
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-14 23:10 ` Sean MacLennan
@ 2008-08-15 7:27 ` Arnd Bergmann
2008-08-15 17:29 ` Sean MacLennan
0 siblings, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2008-08-15 7:27 UTC (permalink / raw)
To: Sean MacLennan; +Cc: linuxppc-dev, dwmw2
On Friday 15 August 2008, Sean MacLennan wrote:
> Port the ndfc driver to an OF platform driver.
>
> Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Looks great, but I just noticed one more detail:
> +static const struct of_device_id ndfc_match[] = {
> + { .compatible = "amcc,ndfc", },
> + {}
> };
>
You should add
MODULE_DEVICE_TABLE(of, &ndfc_match);
to enable module auto-loading.
Arnd <><
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 2/2] port ndfc driver to of platform
2008-08-15 5:24 ` Sean MacLennan
@ 2008-08-15 7:28 ` Arnd Bergmann
0 siblings, 0 replies; 18+ messages in thread
From: Arnd Bergmann @ 2008-08-15 7:28 UTC (permalink / raw)
To: Sean MacLennan; +Cc: linuxppc-dev
On Friday 15 August 2008, Sean MacLennan wrote:
> Changes to the warp platform with the ndfc as an of platform device.
> The main changes are:
>
> * move the NAND information to the DTS
> * remove warp-nand.c
> * remove rev A fixups from cuboot-warp.c
>
> Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 1/2] port ndfc driver to of platform
2008-08-15 7:27 ` Arnd Bergmann
@ 2008-08-15 17:29 ` Sean MacLennan
0 siblings, 0 replies; 18+ messages in thread
From: Sean MacLennan @ 2008-08-15 17:29 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, dwmw2
Added in the MODULE_DEVICE_TABLE.
Cheers,
Sean
Port of the ndfc driver to an of platform driver.
Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 41f361c..ab0d77e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -165,7 +165,7 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
- depends on 4xx && !PPC_MERGE
+ depends on 4xx
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 955959e..abdb42f 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -5,9 +5,13 @@
* Platform independend driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
*
+ * Ported to an OF platform driver by Sean MacLennan
+ *
* Author: Thomas Gleixner
*
* Copyright 2006 IBM
+ * Copyright 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -21,27 +25,17 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/ndfc.h>
#include <linux/mtd/mtd.h>
-#include <linux/platform_device.h>
-
+#include <linux/of_platform.h>
#include <asm/io.h>
-#ifdef CONFIG_40x
-#include <asm/ibm405.h>
-#else
-#include <asm/ibm44x.h>
-#endif
-
-struct ndfc_nand_mtd {
- struct mtd_info mtd;
- struct nand_chip chip;
- struct platform_nand_chip *pl_chip;
-};
-static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
struct ndfc_controller {
- void __iomem *ndfcbase;
- struct nand_hw_control ndfc_control;
- atomic_t childs_active;
+ struct of_device *ofdev;
+ void __iomem *ndfcbase;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int chip_select;
+ struct nand_hw_control ndfc_control;
};
static struct ndfc_controller ndfc_ctrl;
@@ -50,17 +44,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
{
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *nandchip = mtd->priv;
- struct ndfc_nand_mtd *nandmtd = nandchip->priv;
- struct platform_nand_chip *pchip = nandmtd->pl_chip;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
ccr &= ~NDFC_CCR_BS_MASK;
- ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
+ ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
} else
ccr |= NDFC_CCR_RESET_CE;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
}
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -80,7 +71,7 @@ static int ndfc_ready(struct mtd_info *mtd)
{
struct ndfc_controller *ndfc = &ndfc_ctrl;
- return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+ return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -88,9 +79,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
wmb();
}
@@ -102,9 +93,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
uint8_t *p = (uint8_t *)&ecc;
wmb();
- ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
- ecc_code[0] = p[1];
- ecc_code[1] = p[2];
+ ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+ /* The NDFC uses Smart Media (SMC) bytes order */
+ ecc_code[0] = p[2];
+ ecc_code[1] = p[1];
ecc_code[2] = p[3];
return 0;
@@ -123,7 +115,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA);
+ *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
}
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -132,7 +124,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA);
+ out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
}
static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -141,7 +133,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA))
+ if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA))
return -EFAULT;
return 0;
}
@@ -149,10 +141,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Initialize chip structure
*/
-static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
+static int ndfc_chip_init(struct ndfc_controller *ndfc,
+ struct device_node *node)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *chip = &mtd->chip;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_types[] = { "cmdlinepart", NULL };
+#else
+ static const char *part_types[] = { NULL };
+#endif
+ struct mtd_partition *parts;
+#endif
+ struct nand_chip *chip = &ndfc->chip;
+ int ret;
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
@@ -160,8 +161,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
chip->chip_delay = 50;
- chip->priv = mtd;
- chip->options = mtd->pl_chip->options;
chip->controller = &ndfc->ndfc_control;
chip->read_buf = ndfc_read_buf;
chip->write_buf = ndfc_write_buf;
@@ -172,143 +171,121 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
- chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
- mtd->mtd.priv = chip;
- mtd->mtd.owner = THIS_MODULE;
-}
-
-static int ndfc_chip_probe(struct platform_device *pdev)
-{
- struct platform_nand_chip *nc = pdev->dev.platform_data;
- struct ndfc_chip_settings *settings = nc->priv;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct ndfc_nand_mtd *nandmtd;
-
- if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
- return -EINVAL;
- /* Set the bank settings */
- __raw_writel(settings->bank_settings,
- ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
+ ndfc->mtd.priv = chip;
+ ndfc->mtd.owner = THIS_MODULE;
- nandmtd = &ndfc_mtd[pdev->id];
- if (nandmtd->pl_chip)
- return -EBUSY;
+ ret = nand_scan(&ndfc->mtd, 1);
+ if (ret)
+ return ret;
- nandmtd->pl_chip = nc;
- ndfc_chip_init(nandmtd);
-
- /* Scan for chips */
- if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
- nandmtd->pl_chip = NULL;
- return -ENODEV;
- }
+ ndfc->mtd.name = ndfc->ofdev->dev.bus_id;
#ifdef CONFIG_MTD_PARTITIONS
- printk("Number of partitions %d\n", nc->nr_partitions);
- if (nc->nr_partitions) {
- /* Add the full device, so complete dumps can be made */
- add_mtd_device(&nandmtd->mtd);
- add_mtd_partitions(&nandmtd->mtd, nc->partitions,
- nc->nr_partitions);
-
- } else
-#else
- add_mtd_device(&nandmtd->mtd);
+ ret = parse_mtd_partitions(&ndfc->mtd, part_types, &parts, 0);
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0) {
+ ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, &ndfc->mtd,
+ node, &parts);
+ if (ret < 0)
+ return ret;
+ }
#endif
- atomic_inc(&ndfc->childs_active);
- return 0;
-}
+ if (ret > 0)
+ return add_mtd_partitions(&ndfc->mtd, parts, ret);
+#endif
-static int ndfc_chip_remove(struct platform_device *pdev)
-{
- return 0;
+ return add_mtd_device(&ndfc->mtd);
}
-static int ndfc_nand_probe(struct platform_device *pdev)
+static int __devinit ndfc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- struct platform_nand_ctrl *nc = pdev->dev.platform_data;
- struct ndfc_controller_settings *settings = nc->priv;
- struct resource *res = pdev->resource;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- unsigned long long phys = settings->ndfc_erpn | res->start;
+ const u32 *reg;
+ u32 ccr;
+ int err, len;
-#ifndef CONFIG_PHYS_64BIT
- ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
-#else
- ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
-#endif
+ spin_lock_init(&ndfc->ndfc_control.lock);
+ init_waitqueue_head(&ndfc->ndfc_control.wq);
+ ndfc->ofdev = ofdev;
+ dev_set_drvdata(&ofdev->dev, ndfc);
+
+ /* Read the reg property to get the chip select */
+ reg = of_get_property(ofdev->node, "reg", &len);
+ if (reg == NULL || len != 12) {
+ dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+ return -ENOENT;
+ }
+ ndfc->chip_select = reg[0];
+
+ ndfc->ndfcbase = of_iomap(ofdev->node, 0);
if (!ndfc->ndfcbase) {
- printk(KERN_ERR "NDFC: ioremap failed\n");
+ dev_err(&ofdev->dev, "failed to get memory\n");
return -EIO;
}
- __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
+ ccr = NDFC_CCR_BS(ndfc->chip_select);
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ /* It is ok if ccr does not exist - just default to 0 */
+ reg = of_get_property(ofdev->node, "ccr", NULL);
+ if (reg)
+ ccr |= *reg;
+
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
- platform_set_drvdata(pdev, ndfc);
+ /* Set the bank settings if given */
+ reg = of_get_property(ofdev->node, "bank-settings", NULL);
+ if (reg) {
+ int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
+ out_be32(ndfc->ndfcbase + offset, *reg);
+ }
- printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
- __raw_readl(ndfc->ndfcbase + NDFC_REVID));
+ err = ndfc_chip_init(ndfc, ofdev->node);
+ if (err) {
+ iounmap(ndfc->ndfcbase);
+ return err;
+ }
return 0;
}
-static int ndfc_nand_remove(struct platform_device *pdev)
+static int __devexit ndfc_remove(struct of_device *ofdev)
{
- struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
+ struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
- if (atomic_read(&ndfc->childs_active))
- return -EBUSY;
+ nand_release(&ndfc->mtd);
- if (ndfc) {
- platform_set_drvdata(pdev, NULL);
- iounmap(ndfc_ctrl.ndfcbase);
- ndfc_ctrl.ndfcbase = NULL;
- }
return 0;
}
-/* driver device registration */
-
-static struct platform_driver ndfc_chip_driver = {
- .probe = ndfc_chip_probe,
- .remove = ndfc_chip_remove,
- .driver = {
- .name = "ndfc-chip",
- .owner = THIS_MODULE,
- },
+static const struct of_device_id ndfc_match[] = {
+ { .compatible = "amcc,ndfc", },
+ {}
};
+MODULE_DEVICE_TABLE(of, ndfc_match);
-static struct platform_driver ndfc_nand_driver = {
- .probe = ndfc_nand_probe,
- .remove = ndfc_nand_remove,
- .driver = {
- .name = "ndfc-nand",
- .owner = THIS_MODULE,
+static struct of_platform_driver ndfc_driver = {
+ .driver = {
+ .name = "ndfc",
},
+ .match_table = ndfc_match,
+ .probe = ndfc_probe,
+ .remove = __devexit_p(ndfc_remove),
};
static int __init ndfc_nand_init(void)
{
- int ret;
-
- spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
- init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
-
- ret = platform_driver_register(&ndfc_nand_driver);
- if (!ret)
- ret = platform_driver_register(&ndfc_chip_driver);
- return ret;
+ return of_register_platform_driver(&ndfc_driver);
}
static void __exit ndfc_nand_exit(void)
{
- platform_driver_unregister(&ndfc_chip_driver);
- platform_driver_unregister(&ndfc_nand_driver);
+ of_unregister_platform_driver(&ndfc_driver);
}
module_init(ndfc_nand_init);
@@ -316,6 +293,4 @@ module_exit(ndfc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Platform driver for NDFC");
-MODULE_ALIAS("platform:ndfc-chip");
-MODULE_ALIAS("platform:ndfc-nand");
+MODULE_DESCRIPTION("OF Platform driver for NDFC");
^ permalink raw reply related [flat|nested] 18+ messages in thread
end of thread, other threads:[~2008-08-15 17:29 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-02 3:30 [PATCH] port ndfc driver to arch/powerpc Sean MacLennan
2008-08-04 16:25 ` Arnd Bergmann
2008-08-04 17:24 ` Sean MacLennan
2008-08-13 21:36 ` [PATCH 1/2] port ndfc driver to of platform Sean MacLennan
2008-08-14 9:53 ` Arnd Bergmann
2008-08-14 16:08 ` Sean MacLennan
2008-08-14 17:21 ` Sean MacLennan
2008-08-14 20:16 ` Arnd Bergmann
2008-08-14 20:54 ` Sean MacLennan
2008-08-14 23:10 ` Sean MacLennan
2008-08-15 7:27 ` Arnd Bergmann
2008-08-15 17:29 ` Sean MacLennan
2008-08-13 21:45 ` [PATCH 2/2] " Sean MacLennan
2008-08-14 10:08 ` Arnd Bergmann
2008-08-14 16:32 ` Jon Loeliger
2008-08-14 23:20 ` Sean MacLennan
2008-08-15 5:24 ` Sean MacLennan
2008-08-15 7:28 ` Arnd Bergmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).