Omap GPMC (General Purpose Memory Controller) changes.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRuLfbAAoJEBvUPslcq6VzVo4QANR8LkzUsXO20mPyKY3SMnBt tscbZ42h5MydZBJ9fyoL0nJWYTXkbO8vu40+vYOSUvkBtgNPht8aQ6G7Ui/4uN5h Cnvi2NkuYPwx7rgTyskJkzWlIFIp+J1WZZ4ShQz2w/+LGwTLc5n9Cr/gycoST7T+ I8CcGfuwuLBitaewCsXaLCRlpOSD0pgC4u3KK0xr10IefkjZRK26iGnFZRMsQGh0 bPdW5sXyM1c0T6tXZXEA5v1AFQOSvH9je/eopLihYGZjZoYMEn2jU6BBwboiom6p 9pA1mHl2uhmAa7rysklszIozL6h4XmrmSVSI7J3BOV6HGqX1lsofIfrW0yhU6Nwy Hqj3aWxbDJl5vqC5XByyfx4xUyROKCNk3Iir4C1vmsPWEPUENCFcHdksgI3Ra+aV Pz0dl4p86+JOGwdALvfMv5BOdgN7oXcCzmjECB8W6pKbhuFjmGh8fafn3wephZue dE0QiMBnP/ICUcWJrtDEeNB2qn1hbeY3qZGWGHFDbgJrEqHCr3uV7cV6gp2CkmQP KDDt5XoUY7Q5l8vQDu05BkU3Lv64uiWEQXxk8lI2Uvt9RGsQpW4IMYiJtfwtnLGF jQojVu7GLo7vw8eBTB7fLGC3GQyViZXJ/fXrDMf6H+WNRhzLbzf72dbx1ijtaq4P HbN+6Q80Wkt/Hpsh4oty =fNss -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.11/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers From Tony Lindgren: Omap GPMC (General Purpose Memory Controller) changes. * tag 'omap-for-v3.11/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP2+: gpmc: Converts GPMC driver to pm_runtime capable ARM: OMAP2+: gpmc: get number of useable GPMC chip-selects via DT ARM: dts: OMAP2+: Simplify NAND support ARM: OMAP2+: Allow NAND transfer mode to be specified in DT ARM: OMAP2+: nand: reorganize gpmc timing values Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
f54ffe0fef
|
@ -95,7 +95,6 @@ GPMC chip-select settings properties for child nodes. All are optional.
|
|||
- gpmc,burst-wrap Enables wrap bursting
|
||||
- gpmc,burst-read Enables read page/burst mode
|
||||
- gpmc,burst-write Enables write page/burst mode
|
||||
- gpmc,device-nand Device is NAND
|
||||
- gpmc,device-width Total width of device(s) connected to a GPMC
|
||||
chip-select in bytes. The GPMC supports 8-bit
|
||||
and 16-bit devices and so this property must be
|
||||
|
|
|
@ -29,6 +29,13 @@ Optional properties:
|
|||
"bch4" 4-bit BCH ecc code
|
||||
"bch8" 8-bit BCH ecc code
|
||||
|
||||
- ti,nand-xfer-type: A string setting the data transfer type. One of:
|
||||
|
||||
"prefetch-polled" Prefetch polled mode (default)
|
||||
"polled" Polled mode, without prefetch
|
||||
"prefetch-dma" Prefetch enabled sDMA mode
|
||||
"prefetch-irq" Prefetch enabled irq mode
|
||||
|
||||
- elm_id: Specifies elm device node. This is required to support BCH
|
||||
error correction using ELM module.
|
||||
|
||||
|
@ -55,6 +62,7 @@ Example for an AM33xx board:
|
|||
reg = <0 0 0>; /* CS0, offset 0 */
|
||||
nand-bus-width = <16>;
|
||||
ti,nand-ecc-opt = "bch8";
|
||||
ti,nand-xfer-type = "polled";
|
||||
|
||||
gpmc,sync-clk-ps = <0>;
|
||||
gpmc,cs-on-ns = <0>;
|
||||
|
|
|
@ -105,7 +105,6 @@
|
|||
nand-bus-width = <8>;
|
||||
|
||||
ti,nand-ecc-opt = "sw";
|
||||
gpmc,device-nand;
|
||||
gpmc,cs-on-ns = <0>;
|
||||
gpmc,cs-rd-off-ns = <36>;
|
||||
gpmc,cs-wr-off-ns = <36>;
|
||||
|
|
|
@ -112,6 +112,9 @@ struct gpmc_timings nand_default_timings[1] = {
|
|||
.cs_rd_off = 36,
|
||||
.cs_wr_off = 36,
|
||||
|
||||
.we_on = 6,
|
||||
.oe_on = 6,
|
||||
|
||||
.adv_on = 6,
|
||||
.adv_rd_off = 24,
|
||||
.adv_wr_off = 36,
|
||||
|
|
|
@ -43,44 +43,6 @@ static struct platform_device gpmc_nand_device = {
|
|||
.resource = gpmc_nand_resource,
|
||||
};
|
||||
|
||||
static int omap2_nand_gpmc_retime(
|
||||
struct omap_nand_platform_data *gpmc_nand_data,
|
||||
struct gpmc_timings *gpmc_t)
|
||||
{
|
||||
struct gpmc_timings t;
|
||||
int err;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.sync_clk = gpmc_t->sync_clk;
|
||||
t.cs_on = gpmc_t->cs_on;
|
||||
t.adv_on = gpmc_t->adv_on;
|
||||
|
||||
/* Read */
|
||||
t.adv_rd_off = gpmc_t->adv_rd_off;
|
||||
t.oe_on = t.adv_on;
|
||||
t.access = gpmc_t->access;
|
||||
t.oe_off = gpmc_t->oe_off;
|
||||
t.cs_rd_off = gpmc_t->cs_rd_off;
|
||||
t.rd_cycle = gpmc_t->rd_cycle;
|
||||
|
||||
/* Write */
|
||||
t.adv_wr_off = gpmc_t->adv_wr_off;
|
||||
t.we_on = t.oe_on;
|
||||
if (cpu_is_omap34xx()) {
|
||||
t.wr_data_mux_bus = gpmc_t->wr_data_mux_bus;
|
||||
t.wr_access = gpmc_t->wr_access;
|
||||
}
|
||||
t.we_off = gpmc_t->we_off;
|
||||
t.cs_wr_off = gpmc_t->cs_wr_off;
|
||||
t.wr_cycle = gpmc_t->wr_cycle;
|
||||
|
||||
err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
|
||||
{
|
||||
/* support only OMAP3 class */
|
||||
|
@ -131,7 +93,7 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
|||
gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
|
||||
|
||||
if (gpmc_t) {
|
||||
err = omap2_nand_gpmc_retime(gpmc_nand_data, gpmc_t);
|
||||
err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to set gpmc timings: %d\n", err);
|
||||
return err;
|
||||
|
@ -140,8 +102,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
|||
if (gpmc_nand_data->of_node) {
|
||||
gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
|
||||
} else {
|
||||
s.device_nand = true;
|
||||
|
||||
/* Enable RD PIN Monitoring Reg */
|
||||
if (gpmc_nand_data->dev_ready) {
|
||||
s.wait_on_read = true;
|
||||
|
@ -149,6 +109,8 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
|
|||
}
|
||||
}
|
||||
|
||||
s.device_nand = true;
|
||||
|
||||
if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)
|
||||
s.device_width = GPMC_DEVWIDTH_16BIT;
|
||||
else
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/of_mtd.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
|
@ -155,6 +156,7 @@ static struct resource gpmc_cs_mem[GPMC_CS_NUM];
|
|||
static DEFINE_SPINLOCK(gpmc_mem_lock);
|
||||
/* Define chip-selects as reserved by default until probe completes */
|
||||
static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
|
||||
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
|
||||
static unsigned int gpmc_nr_waitpins;
|
||||
static struct device *gpmc_dev;
|
||||
static int gpmc_irq;
|
||||
|
@ -521,8 +523,10 @@ static int gpmc_cs_remap(int cs, u32 base)
|
|||
int ret;
|
||||
u32 old_base, size;
|
||||
|
||||
if (cs > GPMC_CS_NUM)
|
||||
if (cs > gpmc_cs_num) {
|
||||
pr_err("%s: requested chip-select is disabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
gpmc_cs_get_memconf(cs, &old_base, &size);
|
||||
if (base == old_base)
|
||||
return 0;
|
||||
|
@ -545,9 +549,10 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
|
|||
struct resource *res = &gpmc_cs_mem[cs];
|
||||
int r = -1;
|
||||
|
||||
if (cs > GPMC_CS_NUM)
|
||||
if (cs > gpmc_cs_num) {
|
||||
pr_err("%s: requested chip-select is disabled\n", __func__);
|
||||
return -ENODEV;
|
||||
|
||||
}
|
||||
size = gpmc_mem_align(size);
|
||||
if (size > (1 << GPMC_SECTION_SHIFT))
|
||||
return -ENOMEM;
|
||||
|
@ -582,7 +587,7 @@ EXPORT_SYMBOL(gpmc_cs_request);
|
|||
void gpmc_cs_free(int cs)
|
||||
{
|
||||
spin_lock(&gpmc_mem_lock);
|
||||
if (cs >= GPMC_CS_NUM || cs < 0 || !gpmc_cs_reserved(cs)) {
|
||||
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
|
||||
printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
|
||||
BUG();
|
||||
spin_unlock(&gpmc_mem_lock);
|
||||
|
@ -777,7 +782,7 @@ static void gpmc_mem_exit(void)
|
|||
{
|
||||
int cs;
|
||||
|
||||
for (cs = 0; cs < GPMC_CS_NUM; cs++) {
|
||||
for (cs = 0; cs < gpmc_cs_num; cs++) {
|
||||
if (!gpmc_cs_mem_enabled(cs))
|
||||
continue;
|
||||
gpmc_cs_delete_mem(cs);
|
||||
|
@ -798,7 +803,7 @@ static void gpmc_mem_init(void)
|
|||
gpmc_mem_root.end = GPMC_MEM_END;
|
||||
|
||||
/* Reserve all regions that has been set up by bootloader */
|
||||
for (cs = 0; cs < GPMC_CS_NUM; cs++) {
|
||||
for (cs = 0; cs < gpmc_cs_num; cs++) {
|
||||
u32 base, size;
|
||||
|
||||
if (!gpmc_cs_mem_enabled(cs))
|
||||
|
@ -1245,7 +1250,6 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
|
|||
|
||||
p->sync_read = of_property_read_bool(np, "gpmc,sync-read");
|
||||
p->sync_write = of_property_read_bool(np, "gpmc,sync-write");
|
||||
p->device_nand = of_property_read_bool(np, "gpmc,device-nand");
|
||||
of_property_read_u32(np, "gpmc,device-width", &p->device_width);
|
||||
of_property_read_u32(np, "gpmc,mux-add-data", &p->mux_add_data);
|
||||
|
||||
|
@ -1345,6 +1349,13 @@ static const char * const nand_ecc_opts[] = {
|
|||
[OMAP_ECC_BCH8_CODE_HW] = "bch8",
|
||||
};
|
||||
|
||||
static const char * const nand_xfer_types[] = {
|
||||
[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
|
||||
[NAND_OMAP_POLLED] = "polled",
|
||||
[NAND_OMAP_PREFETCH_DMA] = "prefetch-dma",
|
||||
[NAND_OMAP_PREFETCH_IRQ] = "prefetch-irq",
|
||||
};
|
||||
|
||||
static int gpmc_probe_nand_child(struct platform_device *pdev,
|
||||
struct device_node *child)
|
||||
{
|
||||
|
@ -1374,6 +1385,13 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
|
||||
for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
|
||||
if (!strcasecmp(s, nand_xfer_types[val])) {
|
||||
gpmc_nand_data->xfer_type = val;
|
||||
break;
|
||||
}
|
||||
|
||||
val = of_get_nand_bus_width(child);
|
||||
if (val == 16)
|
||||
gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
|
||||
|
@ -1513,6 +1531,20 @@ static int gpmc_probe_dt(struct platform_device *pdev)
|
|||
if (!of_id)
|
||||
return 0;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-cs",
|
||||
&gpmc_cs_num);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: number of chip-selects not defined\n", __func__);
|
||||
return ret;
|
||||
} else if (gpmc_cs_num < 1) {
|
||||
pr_err("%s: all chip-selects are disabled\n", __func__);
|
||||
return -EINVAL;
|
||||
} else if (gpmc_cs_num > GPMC_CS_NUM) {
|
||||
pr_err("%s: number of supported chip-selects cannot be > %d\n",
|
||||
__func__, GPMC_CS_NUM);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "gpmc,num-waitpins",
|
||||
&gpmc_nr_waitpins);
|
||||
if (ret < 0) {
|
||||
|
@ -1577,7 +1609,8 @@ static int gpmc_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(gpmc_l3_clk);
|
||||
}
|
||||
|
||||
clk_prepare_enable(gpmc_l3_clk);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
gpmc_dev = &pdev->dev;
|
||||
|
||||
|
@ -1610,12 +1643,14 @@ static int gpmc_probe(struct platform_device *pdev)
|
|||
/* Now the GPMC is initialised, unreserve the chip-selects */
|
||||
gpmc_cs_map = 0;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
if (!pdev->dev.of_node) {
|
||||
gpmc_cs_num = GPMC_CS_NUM;
|
||||
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
|
||||
}
|
||||
|
||||
rc = gpmc_probe_dt(pdev);
|
||||
if (rc < 0) {
|
||||
clk_disable_unprepare(gpmc_l3_clk);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
clk_put(gpmc_l3_clk);
|
||||
dev_err(gpmc_dev, "failed to probe DT parameters\n");
|
||||
return rc;
|
||||
|
@ -1628,6 +1663,8 @@ static int gpmc_remove(struct platform_device *pdev)
|
|||
{
|
||||
gpmc_free_irq();
|
||||
gpmc_mem_exit();
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
gpmc_dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1715,7 +1752,7 @@ void omap3_gpmc_save_context(void)
|
|||
gpmc_context.prefetch_config1 = gpmc_read_reg(GPMC_PREFETCH_CONFIG1);
|
||||
gpmc_context.prefetch_config2 = gpmc_read_reg(GPMC_PREFETCH_CONFIG2);
|
||||
gpmc_context.prefetch_control = gpmc_read_reg(GPMC_PREFETCH_CONTROL);
|
||||
for (i = 0; i < GPMC_CS_NUM; i++) {
|
||||
for (i = 0; i < gpmc_cs_num; i++) {
|
||||
gpmc_context.cs_context[i].is_valid = gpmc_cs_mem_enabled(i);
|
||||
if (gpmc_context.cs_context[i].is_valid) {
|
||||
gpmc_context.cs_context[i].config1 =
|
||||
|
@ -1747,7 +1784,7 @@ void omap3_gpmc_restore_context(void)
|
|||
gpmc_write_reg(GPMC_PREFETCH_CONFIG1, gpmc_context.prefetch_config1);
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONFIG2, gpmc_context.prefetch_config2);
|
||||
gpmc_write_reg(GPMC_PREFETCH_CONTROL, gpmc_context.prefetch_control);
|
||||
for (i = 0; i < GPMC_CS_NUM; i++) {
|
||||
for (i = 0; i < gpmc_cs_num; i++) {
|
||||
if (gpmc_context.cs_context[i].is_valid) {
|
||||
gpmc_cs_write_reg(i, GPMC_CS_CONFIG1,
|
||||
gpmc_context.cs_context[i].config1);
|
||||
|
|
Loading…
Reference in New Issue