Reorganize gpmc-onenand initialization so that changes required for gpmc driver migration can be made smooth. Ensuring sync read/write are disabled in onenand cannot be expected to work properly unless GPMC is setup, this has been removed. Refactor set_async_mode & set_sync_mode functions to separate out timing calculation & actual configuration (GPMC & OneNAND side). Thanks to Jon for his suggestions. Signed-off-by: Afzal Mohammed <afzal@xxxxxx> Reviewed-by: Jon Hunter <jon-hunter@xxxxxx> --- v5: Use flags for sync_read/write, hv, vhf v4: Reorganize set_sync/async functions in a better way v3: Refactor set_sync/async functions to separate out timing and configurations v2: Move ensuring that async mode in OneNAND has been setup from set_sync to setup function, improve commit message arch/arm/mach-omap2/gpmc-onenand.c | 197 ++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 86 deletions(-) diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 8863e0a..c8a9487 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/mtd/onenand_regs.h> #include <linux/io.h> +#include <linux/err.h> #include <asm/mach/flash.h> @@ -25,6 +26,14 @@ #define ONENAND_IO_SIZE SZ_128K +#define ONENAND_FLAG_SYNCREAD (1 << 0) +#define ONENAND_FLAG_SYNCWRITE (1 << 1) +#define ONENAND_FLAG_HF (1 << 2) +#define ONENAND_FLAG_VHF (1 << 3) + +static unsigned onenand_flags; +static unsigned latency; + static struct omap_onenand_platform_data *gpmc_onenand_data; static struct resource gpmc_onenand_resource = { @@ -38,11 +47,9 @@ static struct platform_device gpmc_onenand_device = { .resource = &gpmc_onenand_resource, }; -static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) +static struct gpmc_timings omap2_onenand_calc_async_timings(void) { struct gpmc_timings t; - u32 reg; - int err; const int t_cer = 15; const int t_avdp = 12; @@ -55,11 +62,6 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) const int t_wpl = 40; const int t_wph = 30; - /* Ensure sync read and sync write are disabled */ - reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); - reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; - writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); - memset(&t, 0, sizeof(t)); t.sync_clk = 0; t.cs_on = 0; @@ -86,25 +88,30 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph); t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez); + return t; +} + +static int gpmc_set_async_mode(int cs, struct gpmc_timings *t) +{ /* Configure GPMC for asynchronous read */ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, GPMC_CONFIG1_DEVICESIZE_16 | GPMC_CONFIG1_MUXADDDATA); - err = gpmc_cs_set_timings(cs, &t); - if (err) - return err; + return gpmc_cs_set_timings(cs, t); +} + +static void omap2_onenand_set_async_mode(void __iomem *onenand_base) +{ + u32 reg; /* Ensure sync read and sync write are disabled */ reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); - - return 0; } -static void set_onenand_cfg(void __iomem *onenand_base, int latency, - int sync_read, int sync_write, int hf, int vhf) +static void set_onenand_cfg(void __iomem *onenand_base) { u32 reg; @@ -112,19 +119,19 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency, reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9)); reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) | ONENAND_SYS_CFG1_BL_16; - if (sync_read) + if (onenand_flags & ONENAND_FLAG_SYNCREAD) reg |= ONENAND_SYS_CFG1_SYNC_READ; else reg &= ~ONENAND_SYS_CFG1_SYNC_READ; - if (sync_write) + if (onenand_flags & ONENAND_FLAG_SYNCWRITE) reg |= ONENAND_SYS_CFG1_SYNC_WRITE; else reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE; - if (hf) + if (onenand_flags & ONENAND_FLAG_HF) reg |= ONENAND_SYS_CFG1_HF; else reg &= ~ONENAND_SYS_CFG1_HF; - if (vhf) + if (onenand_flags & ONENAND_FLAG_VHF) reg |= ONENAND_SYS_CFG1_VHF; else reg &= ~ONENAND_SYS_CFG1_VHF; @@ -172,9 +179,9 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg, return freq; } -static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, - void __iomem *onenand_base, - int *freq_ptr) +static struct gpmc_timings +omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg, + int freq, bool clk_dep) { struct gpmc_timings t; const int t_cer = 15; @@ -184,29 +191,14 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, 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; - int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency; - int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0; - int err, ticks_cez; - int cs = cfg->cs, freq = *freq_ptr; - u32 reg; - bool clk_dep = false; - - if (cfg->flags & ONENAND_SYNC_READ) { - sync_read = 1; - } else if (cfg->flags & ONENAND_SYNC_READWRITE) { - sync_read = 1; - sync_write = 1; - } else - return omap2_onenand_set_async_mode(cs, onenand_base); + int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns; + int ticks_cez; + int cs = cfg->cs; - if (!freq) { - /* Very first call freq is not known */ - err = omap2_onenand_set_async_mode(cs, onenand_base); - if (err) - return err; - freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep); - first_time = 1; - } + if (cfg->flags & ONENAND_SYNC_READ) + onenand_flags = ONENAND_FLAG_SYNCREAD; + else if (cfg->flags & ONENAND_SYNC_READWRITE) + onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE; switch (freq) { case 104: @@ -244,19 +236,23 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, t_ach = 9; t_aavdh = 7; t_rdyo = 15; - sync_write = 0; + onenand_flags &= ~ONENAND_FLAG_SYNCWRITE; break; } div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period); gpmc_clk_ns = gpmc_ticks_to_ns(div); if (gpmc_clk_ns < 15) /* >66Mhz */ - hf = 1; + onenand_flags |= ONENAND_FLAG_HF; + else + onenand_flags &= ~ONENAND_FLAG_HF; if (gpmc_clk_ns < 12) /* >83Mhz */ - vhf = 1; - if (vhf) + onenand_flags |= ONENAND_FLAG_VHF; + else + onenand_flags &= ~ONENAND_FLAG_VHF; + if (onenand_flags & ONENAND_FLAG_VHF) latency = 8; - else if (hf) + else if (onenand_flags & ONENAND_FLAG_HF) latency = 6; else if (gpmc_clk_ns >= 25) /* 40 MHz*/ latency = 3; @@ -279,36 +275,16 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, } } - if (first_time) - set_onenand_cfg(onenand_base, latency, - sync_read, sync_write, hf, vhf); + /* Set synchronous read timings */ + memset(&t, 0, sizeof(t)); if (div == 1) { - reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); - reg |= (1 << 7); - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg); - reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3); - reg |= (1 << 7); - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg); - reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4); - reg |= (1 << 7); - reg |= (1 << 23); - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg); - } else { - reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2); - reg &= ~(1 << 7); - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg); - reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3); - reg &= ~(1 << 7); - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg); - reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4); - reg &= ~(1 << 7); - reg &= ~(1 << 23); - gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg); + t.bool_timings.cs_extra_delay = true; + t.bool_timings.adv_extra_delay = true; + t.bool_timings.oe_extra_delay = true; + t.bool_timings.we_extra_delay = true; } - /* Set synchronous read timings */ - memset(&t, 0, sizeof(t)); t.sync_clk = min_gpmc_clk_period; t.cs_on = 0; t.adv_on = 0; @@ -332,7 +308,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, t.clk_activation = fclk_offset_ns; /* Write */ - if (sync_write) { + if (onenand_flags & ONENAND_FLAG_SYNCWRITE) { t.adv_wr_off = t.adv_rd_off; t.we_on = 0; t.we_off = t.cs_rd_off; @@ -357,6 +333,14 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, } } + return t; +} + +static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t) +{ + unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD; + unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE; + /* Configure GPMC for synchronous read */ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, GPMC_CONFIG1_WRAPBURST_SUPP | @@ -372,11 +356,45 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, GPMC_CONFIG1_DEVICETYPE_NOR | GPMC_CONFIG1_MUXADDDATA); - err = gpmc_cs_set_timings(cs, &t); - if (err) - return err; + return gpmc_cs_set_timings(cs, t); +} + +static int omap2_onenand_setup_async(void __iomem *onenand_base) +{ + struct gpmc_timings t; + int ret; + + t = omap2_onenand_calc_async_timings(); + + ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t); + if (IS_ERR_VALUE(ret)) + return ret; + + omap2_onenand_set_async_mode(onenand_base); + + return 0; +} + +static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) +{ + int ret, freq = *freq_ptr; + struct gpmc_timings t; + bool clk_dep = false; + + if (!freq) { + /* Very first call freq is not known */ + freq = omap2_onenand_get_freq(gpmc_onenand_data, + onenand_base, &clk_dep); + set_onenand_cfg(onenand_base); + } + + t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq, clk_dep); - set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf, vhf); + ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t); + if (IS_ERR_VALUE(ret)) + return ret; + + set_onenand_cfg(onenand_base); *freq_ptr = freq; @@ -386,15 +404,22 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) { struct device *dev = &gpmc_onenand_device.dev; + unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE; + int ret; - /* Set sync timings in GPMC */ - if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base, - freq_ptr) < 0) { - dev_err(dev, "Unable to set synchronous mode\n"); - return -EINVAL; + ret = omap2_onenand_setup_async(onenand_base); + if (ret) { + dev_err(dev, "unable to set to async mode\n"); + return ret; } - return 0; + if (!(gpmc_onenand_data->flags & l)) + return 0; + + ret = omap2_onenand_setup_sync(onenand_base, freq_ptr); + if (ret) + dev_err(dev, "unable to set to sync mode\n"); + return ret; } void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) -- 1.7.10.2 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html