Skip to content

Commit

Permalink
mtd: onenand: omap2: Configure driver from DT
Browse files Browse the repository at this point in the history
Move away from platform data configuration and use pure DT approach.

Use generic probe function to deal with OneNAND node and remove now useless
gpmc_probe_onenand_child function. Import sync mode timing calculation
function from mach-omap2/gpmc-onenand.c

Signed-off-by: Ladislav Michl <[email protected]>
Reviewed-by: Peter Ujfalusi <[email protected]>
Tested-by: Tony Lindgren <[email protected]>
Tested-by: Aaro Koskinen <[email protected]>
Acked-by: Roger Quadros <[email protected]>
Signed-off-by: Boris Brezillon <[email protected]>
  • Loading branch information
3x380V authored and Boris Brezillon committed Jan 12, 2018
1 parent bdaca93 commit a758f50
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 139 deletions.
158 changes: 117 additions & 41 deletions drivers/memory/omap-gpmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include <linux/pm_runtime.h>

#include <linux/platform_data/mtd-nand-omap2.h>
#include <linux/platform_data/mtd-onenand-omap2.h>

#include <asm/mach-types.h>

Expand Down Expand Up @@ -1138,6 +1137,112 @@ struct gpmc_nand_ops *gpmc_omap_get_nand_ops(struct gpmc_nand_regs *reg, int cs)
}
EXPORT_SYMBOL_GPL(gpmc_omap_get_nand_ops);

static void gpmc_omap_onenand_calc_sync_timings(struct gpmc_timings *t,
struct gpmc_settings *s,
int freq, int latency)
{
struct gpmc_device_timings dev_t;
const int t_cer = 15;
const int t_avdp = 12;
const int t_cez = 20; /* max of t_cez, t_oez */
const int t_wpl = 40;
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;

switch (freq) {
case 104:
min_gpmc_clk_period = 9600; /* 104 MHz */
t_ces = 3;
t_avds = 4;
t_avdh = 2;
t_ach = 3;
t_aavdh = 6;
t_rdyo = 6;
break;
case 83:
min_gpmc_clk_period = 12000; /* 83 MHz */
t_ces = 5;
t_avds = 4;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 9;
break;
case 66:
min_gpmc_clk_period = 15000; /* 66 MHz */
t_ces = 6;
t_avds = 5;
t_avdh = 2;
t_ach = 6;
t_aavdh = 6;
t_rdyo = 11;
break;
default:
min_gpmc_clk_period = 18500; /* 54 MHz */
t_ces = 7;
t_avds = 7;
t_avdh = 7;
t_ach = 9;
t_aavdh = 7;
t_rdyo = 15;
break;
}

/* Set synchronous read timings */
memset(&dev_t, 0, sizeof(dev_t));

if (!s->sync_write) {
dev_t.t_avdp_w = max(t_avdp, t_cer) * 1000;
dev_t.t_wpl = t_wpl * 1000;
dev_t.t_wph = t_wph * 1000;
dev_t.t_aavdh = t_aavdh * 1000;
}
dev_t.ce_xdelay = true;
dev_t.avd_xdelay = true;
dev_t.oe_xdelay = true;
dev_t.we_xdelay = true;
dev_t.clk = min_gpmc_clk_period;
dev_t.t_bacc = dev_t.clk;
dev_t.t_ces = t_ces * 1000;
dev_t.t_avds = t_avds * 1000;
dev_t.t_avdh = t_avdh * 1000;
dev_t.t_ach = t_ach * 1000;
dev_t.cyc_iaa = (latency + 1);
dev_t.t_cez_r = t_cez * 1000;
dev_t.t_cez_w = dev_t.t_cez_r;
dev_t.cyc_aavdh_oe = 1;
dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;

gpmc_calc_timings(t, s, &dev_t);
}

int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq,
int latency,
struct gpmc_onenand_info *info)
{
int ret;
struct gpmc_timings gpmc_t;
struct gpmc_settings gpmc_s;

gpmc_read_settings_dt(dev->of_node, &gpmc_s);

info->sync_read = gpmc_s.sync_read;
info->sync_write = gpmc_s.sync_write;
info->burst_len = gpmc_s.burst_len;

if (!gpmc_s.sync_read && !gpmc_s.sync_write)
return 0;

gpmc_omap_onenand_calc_sync_timings(&gpmc_t, &gpmc_s, freq, latency);

ret = gpmc_cs_program_settings(cs, &gpmc_s);
if (ret < 0)
return ret;

return gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s);
}
EXPORT_SYMBOL_GPL(gpmc_omap_onenand_set_timings);

int gpmc_get_client_irq(unsigned irq_config)
{
if (!gpmc_irq_domain) {
Expand Down Expand Up @@ -1916,41 +2021,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
of_property_read_bool(np, "gpmc,time-para-granularity");
}

#if IS_ENABLED(CONFIG_MTD_ONENAND)
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
{
u32 val;
struct omap_onenand_platform_data *gpmc_onenand_data;

if (of_property_read_u32(child, "reg", &val) < 0) {
dev_err(&pdev->dev, "%pOF has no 'reg' property\n",
child);
return -ENODEV;
}

gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data),
GFP_KERNEL);
if (!gpmc_onenand_data)
return -ENOMEM;

gpmc_onenand_data->cs = val;
gpmc_onenand_data->of_node = child;
gpmc_onenand_data->dma_channel = -1;

if (!of_property_read_u32(child, "dma-channel", &val))
gpmc_onenand_data->dma_channel = val;

return gpmc_onenand_init(gpmc_onenand_data);
}
#else
static int gpmc_probe_onenand_child(struct platform_device *pdev,
struct device_node *child)
{
return 0;
}
#endif

/**
* gpmc_probe_generic_child - configures the gpmc for a child device
* @pdev: pointer to gpmc platform device
Expand Down Expand Up @@ -2053,6 +2123,16 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
}
}

if (of_node_cmp(child->name, "onenand") == 0) {
/* Warn about older DT blobs with no compatible property */
if (!of_property_read_bool(child, "compatible")) {
dev_warn(&pdev->dev,
"Incompatible OneNAND node: missing compatible");
ret = -EINVAL;
goto err;
}
}

if (of_device_is_compatible(child, "ti,omap2-nand")) {
/* NAND specific setup */
val = 8;
Expand Down Expand Up @@ -2189,11 +2269,7 @@ static void gpmc_probe_dt_children(struct platform_device *pdev)
if (!child->name)
continue;

if (of_node_cmp(child->name, "onenand") == 0)
ret = gpmc_probe_onenand_child(pdev, child);
else
ret = gpmc_probe_generic_child(pdev, child);

ret = gpmc_probe_generic_child(pdev, child);
if (ret) {
dev_err(&pdev->dev, "failed to probe DT child '%s': %d\n",
child->name, ret);
Expand Down
4 changes: 3 additions & 1 deletion drivers/mtd/onenand/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ config MTD_ONENAND_GENERIC
config MTD_ONENAND_OMAP2
tristate "OneNAND on OMAP2/OMAP3 support"
depends on ARCH_OMAP2 || ARCH_OMAP3
depends on OF || COMPILE_TEST
help
Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC
via the GPMC memory controller.
Enable dmaengine and gpiolib for better performance.

config MTD_ONENAND_SAMSUNG
tristate "OneNAND on Samsung SOC controller support"
Expand Down
Loading

0 comments on commit a758f50

Please sign in to comment.