Commit e10db1f0 authored by Huang Shijie's avatar Huang Shijie Committed by David Woodhouse

mtd: gpmi: add device tree support to gpmi-nand

This patch just adds the DT support to gpmi-nand.
Signed-off-by: default avatarHuang Shijie <b32955@freescale.com>
Signed-off-by: default avatarHuang Shijie <shijie8@gmail.com>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 279f08d4
* Freescale General-Purpose Media Interface (GPMI)
The GPMI nand controller provides an interface to control the
NAND flash chips. We support only one NAND chip now.
Required properties:
- compatible : should be "fsl,<chip>-gpmi-nand"
- reg : should contain registers location and length for gpmi and bch.
- reg-names: Should contain the reg names "gpmi-nand" and "bch"
- interrupts : The first is the DMA interrupt number for GPMI.
The second is the BCH interrupt number.
- interrupt-names : The interrupt names "gpmi-dma", "bch";
- fsl,gpmi-dma-channel : Should contain the dma channel it uses.
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
Examples:
gpmi-nand@8000c000 {
compatible = "fsl,imx28-gpmi-nand";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x8000c000 2000>, <0x8000a000 2000>;
reg-names = "gpmi-nand", "bch";
interrupts = <88>, <41>;
interrupt-names = "gpmi-dma", "bch";
fsl,gpmi-dma-channel = <4>;
partition@0 {
...
};
};
...@@ -256,11 +256,12 @@ static unsigned int ns_to_cycles(unsigned int time, ...@@ -256,11 +256,12 @@ static unsigned int ns_to_cycles(unsigned int time,
return max(k, min); return max(k, min);
} }
#define DEF_MIN_PROP_DELAY 5
#define DEF_MAX_PROP_DELAY 9
/* Apply timing to current hardware conditions. */ /* Apply timing to current hardware conditions. */
static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw) struct gpmi_nfc_hardware_timing *hw)
{ {
struct gpmi_nand_platform_data *pdata = this->pdata;
struct timing_threshod *nfc = &timing_default_threshold; struct timing_threshod *nfc = &timing_default_threshold;
struct nand_chip *nand = &this->nand; struct nand_chip *nand = &this->nand;
struct nand_timing target = this->timing; struct nand_timing target = this->timing;
...@@ -277,8 +278,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, ...@@ -277,8 +278,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
int ideal_sample_delay_in_ns; int ideal_sample_delay_in_ns;
unsigned int sample_delay_factor; unsigned int sample_delay_factor;
int tEYE; int tEYE;
unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
/* /*
* If there are multiple chips, we need to relax the timings to allow * If there are multiple chips, we need to relax the timings to allow
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mtd/gpmi-nand.h> #include <linux/mtd/gpmi-nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "gpmi-nand.h" #include "gpmi-nand.h"
/* add our owner bbt descriptor */ /* add our owner bbt descriptor */
...@@ -386,7 +388,7 @@ static void release_bch_irq(struct gpmi_nand_data *this) ...@@ -386,7 +388,7 @@ static void release_bch_irq(struct gpmi_nand_data *this)
static bool gpmi_dma_filter(struct dma_chan *chan, void *param) static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
{ {
struct gpmi_nand_data *this = param; struct gpmi_nand_data *this = param;
struct resource *r = this->private; int dma_channel = (int)this->private;
if (!mxs_dma_is_apbh(chan)) if (!mxs_dma_is_apbh(chan))
return false; return false;
...@@ -398,7 +400,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param) ...@@ -398,7 +400,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
* for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
* (These eight channels share the same IRQ!) * (These eight channels share the same IRQ!)
*/ */
if (r->start <= chan->chan_id && chan->chan_id <= r->end) { if (dma_channel == chan->chan_id) {
chan->private = &this->dma_data; chan->private = &this->dma_data;
return true; return true;
} }
...@@ -418,57 +420,45 @@ static void release_dma_channels(struct gpmi_nand_data *this) ...@@ -418,57 +420,45 @@ static void release_dma_channels(struct gpmi_nand_data *this)
static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
{ {
struct platform_device *pdev = this->pdev; struct platform_device *pdev = this->pdev;
struct gpmi_nand_platform_data *pdata = this->pdata; struct resource *r_dma;
struct resources *res = &this->resources; struct device_node *dn;
struct resource *r, *r_dma; int dma_channel;
unsigned int i; unsigned int ret;
struct dma_chan *dma_chan;
dma_cap_mask_t mask;
/* dma channel, we only use the first one. */
dn = pdev->dev.of_node;
ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel);
if (ret) {
pr_err("unable to get DMA channel from dt.\n");
goto acquire_err;
}
this->private = (void *)dma_channel;
r = platform_get_resource_byname(pdev, IORESOURCE_DMA, /* gpmi dma interrupt */
GPMI_NAND_DMA_CHANNELS_RES_NAME);
r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
GPMI_NAND_DMA_INTERRUPT_RES_NAME); GPMI_NAND_DMA_INTERRUPT_RES_NAME);
if (!r || !r_dma) { if (!r_dma) {
pr_err("Can't get resource for DMA\n"); pr_err("Can't get resource for DMA\n");
return -ENXIO; goto acquire_err;
} }
this->dma_data.chan_irq = r_dma->start;
/* used in gpmi_dma_filter() */ /* request dma channel */
this->private = r; dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
for (i = r->start; i <= r->end; i++) {
struct dma_chan *dma_chan;
dma_cap_mask_t mask;
if (i - r->start >= pdata->max_chip_count) dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
break; if (!dma_chan) {
pr_err("dma_request_channel failed.\n");
dma_cap_zero(mask); goto acquire_err;
dma_cap_set(DMA_SLAVE, mask);
/* get the DMA interrupt */
if (r_dma->start == r_dma->end) {
/* only register the first. */
if (i == r->start)
this->dma_data.chan_irq = r_dma->start;
else
this->dma_data.chan_irq = NO_IRQ;
} else
this->dma_data.chan_irq = r_dma->start + (i - r->start);
dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
if (!dma_chan)
goto acquire_err;
/* fill the first empty item */
this->dma_chans[i - r->start] = dma_chan;
} }
res->dma_low_channel = r->start; this->dma_chans[0] = dma_chan;
res->dma_high_channel = i;
return 0; return 0;
acquire_err: acquire_err:
pr_err("Can't acquire DMA channel %u\n", i);
release_dma_channels(this); release_dma_channels(this);
return -EINVAL; return -EINVAL;
} }
...@@ -1465,9 +1455,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this) ...@@ -1465,9 +1455,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this)
static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
{ {
struct gpmi_nand_platform_data *pdata = this->pdata;
struct mtd_info *mtd = &this->mtd; struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand; struct nand_chip *chip = &this->nand;
struct mtd_part_parser_data ppdata = {};
int ret; int ret;
/* init current chip */ /* init current chip */
...@@ -1505,14 +1495,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) ...@@ -1505,14 +1495,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
if (ret) if (ret)
goto err_out; goto err_out;
ret = nand_scan(mtd, pdata->max_chip_count); ret = nand_scan(mtd, 1);
if (ret) { if (ret) {
pr_err("Chip scan failed\n"); pr_err("Chip scan failed\n");
goto err_out; goto err_out;
} }
ret = mtd_device_parse_register(mtd, NULL, NULL, ppdata.of_node = this->pdev->dev.of_node;
pdata->partitions, pdata->partition_count); ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret) if (ret)
goto err_out; goto err_out;
return 0; return 0;
...@@ -1522,12 +1512,37 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) ...@@ -1522,12 +1512,37 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
return ret; return ret;
} }
static const struct platform_device_id gpmi_ids[] = {
{ .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
{ .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
{},
};
static const struct of_device_id gpmi_nand_id_table[] = {
{
.compatible = "fsl,imx23-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX23]
}, {
.compatible = "fsl,imx28-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX28]
}, {}
};
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
static int __devinit gpmi_nand_probe(struct platform_device *pdev) static int __devinit gpmi_nand_probe(struct platform_device *pdev)
{ {
struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data;
struct gpmi_nand_data *this; struct gpmi_nand_data *this;
const struct of_device_id *of_id;
int ret; int ret;
of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
if (of_id) {
pdev->id_entry = of_id->data;
} else {
pr_err("Failed to find the right device id.\n");
return -ENOMEM;
}
this = kzalloc(sizeof(*this), GFP_KERNEL); this = kzalloc(sizeof(*this), GFP_KERNEL);
if (!this) { if (!this) {
pr_err("Failed to allocate per-device memory\n"); pr_err("Failed to allocate per-device memory\n");
...@@ -1537,13 +1552,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev) ...@@ -1537,13 +1552,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, this); platform_set_drvdata(pdev, this);
this->pdev = pdev; this->pdev = pdev;
this->dev = &pdev->dev; this->dev = &pdev->dev;
this->pdata = pdata;
if (pdata->platform_init) {
ret = pdata->platform_init();
if (ret)
goto platform_init_error;
}
ret = acquire_resources(this); ret = acquire_resources(this);
if (ret) if (ret)
...@@ -1561,7 +1569,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev) ...@@ -1561,7 +1569,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
exit_nfc_init: exit_nfc_init:
release_resources(this); release_resources(this);
platform_init_error:
exit_acquire_resources: exit_acquire_resources:
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
kfree(this); kfree(this);
...@@ -1579,19 +1586,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev) ...@@ -1579,19 +1586,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct platform_device_id gpmi_ids[] = {
{
.name = "imx23-gpmi-nand",
.driver_data = IS_MX23,
}, {
.name = "imx28-gpmi-nand",
.driver_data = IS_MX28,
}, {},
};
static struct platform_driver gpmi_nand_driver = { static struct platform_driver gpmi_nand_driver = {
.driver = { .driver = {
.name = "gpmi-nand", .name = "gpmi-nand",
.of_match_table = gpmi_nand_id_table,
}, },
.probe = gpmi_nand_probe, .probe = gpmi_nand_probe,
.remove = __exit_p(gpmi_nand_remove), .remove = __exit_p(gpmi_nand_remove),
......
...@@ -266,8 +266,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *, ...@@ -266,8 +266,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
#define STATUS_UNCORRECTABLE 0xfe #define STATUS_UNCORRECTABLE 0xfe
/* Use the platform_id to distinguish different Archs. */ /* Use the platform_id to distinguish different Archs. */
#define IS_MX23 0x1 #define IS_MX23 0x0
#define IS_MX28 0x2 #define IS_MX28 0x1
#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) #define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23)
#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) #define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28)
#endif #endif
...@@ -23,12 +23,12 @@ ...@@ -23,12 +23,12 @@
#define GPMI_NAND_RES_SIZE 6 #define GPMI_NAND_RES_SIZE 6
/* Resource names for the GPMI NAND driver. */ /* Resource names for the GPMI NAND driver. */
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "GPMI NAND GPMI Registers" #define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt" #define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt"
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "GPMI NAND BCH Registers" #define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "GPMI NAND BCH Interrupt" #define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels" #define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels"
#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "GPMI NAND DMA Interrupt" #define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma"
/** /**
* struct gpmi_nand_platform_data - GPMI NAND driver platform data. * struct gpmi_nand_platform_data - GPMI NAND driver platform data.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment