aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert ABEL <rabel@cit-ec.uni-bielefeld.de>2015-02-27 10:56:53 -0500
committerRoger Quadros <rogerq@ti.com>2015-03-06 05:39:48 -0500
commit2e67690137f3a7bac660edd548f8846709c55381 (patch)
tree33262ac06753bd02df92a27fe520f24761dd1847
parentf585070b91950a0269eb20f497cceeee0aeefe0e (diff)
ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles, even though the access is defined as asynchronous, and no GPMC_CLK clock is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider for the GPMC clock, so it must be programmed to define the correct WAITMONITORINGTIME delay. Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for pure asynchronous accesses, i.e. both read and write asynchronous. Signed-off-by: Robert ABEL <rabel@cit-ec.uni-bielefeld.de> Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Roger Quadros <rogerq@ti.com>
-rw-r--r--arch/arm/mach-omap2/gpmc-nand.c18
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c4
-rw-r--r--arch/arm/mach-omap2/usb-tusb6010.c4
-rw-r--r--drivers/memory/omap-gpmc.c86
-rw-r--r--include/linux/omap-gpmc.h3
5 files changed, 95 insertions, 20 deletions
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index d5951b17b736..72918c4973ea 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
96 gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); 96 gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
97 gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); 97 gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
98 98
99 if (gpmc_t) {
100 err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
101 if (err < 0) {
102 pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", err);
103 return err;
104 }
105 }
106
107 memset(&s, 0, sizeof(struct gpmc_settings)); 99 memset(&s, 0, sizeof(struct gpmc_settings));
108 if (gpmc_nand_data->of_node) 100 if (gpmc_nand_data->of_node)
109 gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); 101 gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
@@ -111,6 +103,16 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
111 gpmc_set_legacy(gpmc_nand_data, &s); 103 gpmc_set_legacy(gpmc_nand_data, &s);
112 104
113 s.device_nand = true; 105 s.device_nand = true;
106
107 if (gpmc_t) {
108 err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t, &s);
109 if (err < 0) {
110 pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n",
111 err);
112 return err;
113 }
114 }
115
114 err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); 116 err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s);
115 if (err < 0) 117 if (err < 0)
116 goto out_free_cs; 118 goto out_free_cs;
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 53d197e0c1f3..f899e77ff5e6 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
293 if (ret < 0) 293 if (ret < 0)
294 return ret; 294 return ret;
295 295
296 ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); 296 ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_async);
297 if (ret < 0) 297 if (ret < 0)
298 return ret; 298 return ret;
299 299
@@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
331 if (ret < 0) 331 if (ret < 0)
332 return ret; 332 return ret;
333 333
334 ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); 334 ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_sync);
335 if (ret < 0) 335 if (ret < 0)
336 return ret; 336 return ret;
337 337
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 8333400898fb..e554d9e66a1c 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
71 71
72 gpmc_calc_timings(&t, &tusb_async, &dev_t); 72 gpmc_calc_timings(&t, &tusb_async, &dev_t);
73 73
74 return gpmc_cs_set_timings(async_cs, &t); 74 return gpmc_cs_set_timings(async_cs, &t, &tusb_async);
75} 75}
76 76
77static int tusb_set_sync_mode(unsigned sysclk_ps) 77static int tusb_set_sync_mode(unsigned sysclk_ps)
@@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
98 98
99 gpmc_calc_timings(&t, &tusb_sync, &dev_t); 99 gpmc_calc_timings(&t, &tusb_sync, &dev_t);
100 100
101 return gpmc_cs_set_timings(sync_cs, &t); 101 return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync);
102} 102}
103 103
104/* tusb driver calls this when it changes the chip's clocking */ 104/* tusb driver calls this when it changes the chip's clocking */
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 5c36ff397b73..768bab233196 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -138,7 +138,9 @@
138#define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23) 138#define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23)
139#define GPMC_CONFIG1_WAIT_READ_MON (1 << 22) 139#define GPMC_CONFIG1_WAIT_READ_MON (1 << 22)
140#define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21) 140#define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
141#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18) 141#define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18)
142/** WAITMONITORINGTIME Max Ticks */
143#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX 2
142#define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16) 144#define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16)
143#define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12) 145#define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12)
144#define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) 146#define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1)
@@ -525,13 +527,48 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
525 t->field, #field) < 0) \ 527 t->field, #field) < 0) \
526 return -1 528 return -1
527 529
530/**
531 * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME
532 * WAITMONITORINGTIME will be _at least_ as long as desired, i.e.
533 * read --> don't sample bus too early
534 * write --> data is longer on bus
535 *
536 * Formula:
537 * gpmc_clk_div + 1 = ceil(ceil(waitmonitoringtime_ns / gpmc_fclk_ns)
538 * / waitmonitoring_ticks)
539 * WAITMONITORINGTIME resulting in 0 or 1 tick with div = 1 are caught by
540 * div <= 0 check.
541 *
542 * @wait_monitoring: WAITMONITORINGTIME in ns.
543 * @return: -1 on failure to scale, else proper divider > 0.
544 */
545static int gpmc_calc_waitmonitoring_divider(unsigned int wait_monitoring)
546{
547
548 int div = gpmc_ns_to_ticks(wait_monitoring);
549
550 div += GPMC_CONFIG1_WAITMONITORINGTIME_MAX - 1;
551 div /= GPMC_CONFIG1_WAITMONITORINGTIME_MAX;
552
553 if (div > 4)
554 return -1;
555 if (div <= 0)
556 div = 1;
557
558 return div;
559
560}
561
562/**
563 * gpmc_calc_divider - calculate GPMC_FCLK divider for sync_clk GPMC_CLK period.
564 * @sync_clk: GPMC_CLK period in ps.
565 * @return: Returns at least 1 if GPMC_FCLK can be divided to GPMC_CLK.
566 * Else, returns -1.
567 */
528int gpmc_calc_divider(unsigned int sync_clk) 568int gpmc_calc_divider(unsigned int sync_clk)
529{ 569{
530 int div; 570 int div = gpmc_ps_to_ticks(sync_clk);
531 u32 l;
532 571
533 l = sync_clk + (gpmc_get_fclk_period() - 1);
534 div = l / gpmc_get_fclk_period();
535 if (div > 4) 572 if (div > 4)
536 return -1; 573 return -1;
537 if (div <= 0) 574 if (div <= 0)
@@ -540,7 +577,15 @@ int gpmc_calc_divider(unsigned int sync_clk)
540 return div; 577 return div;
541} 578}
542 579
543int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) 580/**
581 * gpmc_cs_set_timings - program timing parameters for Chip Select Region.
582 * @cs: Chip Select Region.
583 * @t: GPMC timing parameters.
584 * @s: GPMC timing settings.
585 * @return: 0 on success, -1 on error.
586 */
587int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
588 const struct gpmc_settings *s)
544{ 589{
545 int div; 590 int div;
546 u32 l; 591 u32 l;
@@ -550,6 +595,33 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
550 if (div < 0) 595 if (div < 0)
551 return div; 596 return div;
552 597
598 /*
599 * See if we need to change the divider for waitmonitoringtime.
600 *
601 * Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for
602 * pure asynchronous accesses, i.e. both read and write asynchronous.
603 * However, only do so if WAITMONITORINGTIME is actually used, i.e.
604 * either WAITREADMONITORING or WAITWRITEMONITORING is set.
605 *
606 * This statement must not change div to scale async WAITMONITORINGTIME
607 * to protect mixed synchronous and asynchronous accesses.
608 *
609 * We raise an error later if WAITMONITORINGTIME does not fit.
610 */
611 if (!s->sync_read && !s->sync_write &&
612 (s->wait_on_read || s->wait_on_write)
613 ) {
614
615 div = gpmc_calc_waitmonitoring_divider(t->wait_monitoring);
616 if (div < 0) {
617 pr_err("%s: waitmonitoringtime %3d ns too large for greatest gpmcfclkdivider.\n",
618 __func__,
619 t->wait_monitoring
620 );
621 return -1;
622 }
623 }
624
553 GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on); 625 GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on);
554 GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off); 626 GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off);
555 GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off); 627 GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off);
@@ -1810,7 +1882,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
1810 if (ret < 0) 1882 if (ret < 0)
1811 goto err; 1883 goto err;
1812 1884
1813 ret = gpmc_cs_set_timings(cs, &gpmc_t); 1885 ret = gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s);
1814 if (ret) { 1886 if (ret) {
1815 dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n", 1887 dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
1816 child->name); 1888 child->name);
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
index c2080eebbb47..7dee00143afd 100644
--- a/include/linux/omap-gpmc.h
+++ b/include/linux/omap-gpmc.h
@@ -163,7 +163,8 @@ extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
163 163
164extern void gpmc_cs_write_reg(int cs, int idx, u32 val); 164extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
165extern int gpmc_calc_divider(unsigned int sync_clk); 165extern int gpmc_calc_divider(unsigned int sync_clk);
166extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t); 166extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
167 const struct gpmc_settings *s);
167extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p); 168extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
168extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); 169extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
169extern void gpmc_cs_free(int cs); 170extern void gpmc_cs_free(int cs);