omap: gpmc-nand: add ability to keep timings defined by the bootloader
Subsystems (5)
cover omap: gpmc-nand: add ability to keep timings defined by the bootloader
These patches add ability to keep GPMC timings configured by the bootloader. The platforms have to either define NAND GPMC timinings explicitly via gpmc_t field of omap_nand_platform_data or set keep_timings flag to allow detection of current timing configuration and its subsequent use in omap2_nand_gpmc_retime.
The following changes since commit 104a77440f05430f29f9d3f4ecb88c1536819585:
Tony Lindgren (1):
Linux-omap rebuilt: Merged in i2c-omap-for-ben branch and cleaned up cbus branch
Mike Rapoport (2):
omap: gpmc: add gpmc_cs_get_timings
omap: gpmc-nand: add ability to keep timings defined by the
bootloader
arch/arm/mach-omap2/gpmc-nand.c | 19 +++++++- arch/arm/mach-omap2/gpmc.c | 79 ++++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/gpmc.h | 1 + arch/arm/plat-omap/include/plat/nand.h | 1 + 4 files changed, 99 insertions(+), 1 deletions(-)
PATCH 1/2 omap: gpmc: add gpmc_cs_get_timings
Add gpmc_cs_get_timings counterpart of gpmc_cs_set_timings and convinience macros to read particular timing configuration fields
--- arch/arm/mach-omap2/gpmc.c | 79 ++++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/gpmc.h | 1 + 2 files changed, 80 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/gpmc.c +79 -0
@@ -163,6 +163,36 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns) }#ifdef DEBUG +static int get_gpmc_timing_reg (int cs,int reg,int st_bit,int end_bit, + const char *name) +#else +static int get_gpmc_timing_reg (int cs,int reg,int st_bit,int end_bit) +#endif +{ +u32 l; +int ticks, mask, nr_bits, time; + + nr_bits = end_bit - st_bit +1 ; + mask = ((1 << nr_bits) -1 ); + + l =gpmc_cs_read_reg (cs, reg); + ticks = (l >> st_bit) & mask; + +if (ticks ==0 ) + time =0 ; +else + time =gpmc_ticks_to_ns (ticks); + +#ifdef DEBUG +printk (KERN_INFO +"GPMC CS%d: %-10s: %3d ticks, %3d ns\n" , + cs, name, ticks, time); +#endif + +return time; +} + +#ifdef DEBUG static int set_gpmc_timing_reg (int cs,int reg,int st_bit,int end_bit,int time,const char *name) #else
@@ -206,10 +236,14 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, if (set_gpmc_timing_reg(cs, (reg), (st), (end), \ t->field, #field) < 0) \ return -1 +#define GPMC_GET_ONE(reg, st, end, field) \ + t->field = get_gpmc_timing_reg(cs, (reg), (st), (end), #field) #else #define GPMC_SET_ONE(reg, st, end, field) \ if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \ return -1 +#define GPMC_GET_ONE(reg, st, end, field) \ + t->field = get_gpmc_timing_reg(cs, (reg), (st), (end)) #endif int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
@@ -227,6 +261,51 @@ int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)return div; } +void gpmc_cs_get_timings (int cs,struct gpmc_timings *t) +{ +int div; +u32 l; + +GPMC_GET_ONE (GPMC_CS_CONFIG2 ,0 ,3 , cs_on); +GPMC_GET_ONE (GPMC_CS_CONFIG2 ,8 ,12 , cs_rd_off); +GPMC_GET_ONE (GPMC_CS_CONFIG2 ,16 ,20 , cs_wr_off); + +GPMC_GET_ONE (GPMC_CS_CONFIG3 ,0 ,3 , adv_on); +GPMC_GET_ONE (GPMC_CS_CONFIG3 ,8 ,12 , adv_rd_off); +GPMC_GET_ONE (GPMC_CS_CONFIG3 ,16 ,20 , adv_wr_off); + +GPMC_GET_ONE (GPMC_CS_CONFIG4 ,0 ,3 , oe_on); +GPMC_GET_ONE (GPMC_CS_CONFIG4 ,8 ,12 , oe_off); +GPMC_GET_ONE (GPMC_CS_CONFIG4 ,16 ,19 , we_on); +GPMC_GET_ONE (GPMC_CS_CONFIG4 ,24 ,28 , we_off); + +GPMC_GET_ONE (GPMC_CS_CONFIG5 ,0 ,4 , rd_cycle); +GPMC_GET_ONE (GPMC_CS_CONFIG5 ,8 ,12 , wr_cycle); +GPMC_GET_ONE (GPMC_CS_CONFIG5 ,16 ,20 , access); + +GPMC_GET_ONE (GPMC_CS_CONFIG5 ,24 ,27 , page_burst_access); + +if (cpu_is_omap34xx ()) { +GPMC_GET_ONE (GPMC_CS_CONFIG6 ,16 ,19 , wr_data_mux_bus); +GPMC_GET_ONE (GPMC_CS_CONFIG6 ,24 ,28 , wr_access); + } + + l =gpmc_cs_read_reg (cs,GPMC_CS_CONFIG1 ); +if (l & (GPMC_CONFIG1_READTYPE_SYNC |GPMC_CONFIG1_WRITETYPE_SYNC )) { + div = (l &0x03 ) +1 ; +#ifdef DEBUG +printk (KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n" , + cs, (div *gpmc_get_fclk_period ()) /1000 , div); +#endif + t->sync_clk = (div *gpmc_get_fclk_period ()) /1000 ; + }else { + t->sync_clk =0 ; + } + +gpmc_dump_regs (cs); +gpmc_dump_timings (t); +} +int gpmc_cs_set_timings (int cs,const struct gpmc_timings *t) {int div;
arch/arm/plat-omap/include/plat/gpmc.h +1 -0
@@ -102,6 +102,7 @@ extern void gpmc_cs_write_reg(int cs, int idx, u32 val);extern u32 gpmc_cs_read_reg (int cs,int idx);extern int gpmc_cs_calc_divider (int cs,unsigned int sync_clk);extern int gpmc_cs_set_timings (int cs,const struct gpmc_timings *t); +extern void gpmc_cs_get_timings (int cs,struct gpmc_timings *t);extern int gpmc_cs_request (int cs,unsigned long size,unsigned long *base);extern void gpmc_cs_free (int cs);extern int gpmc_cs_set_reserved (int cs,int reserved);
Signature · 1 line
1.6.6.2
PATCH 2/2 omap: gpmc-nand: add ability to keep timings defined by the bootloader
In reply to Mike Rapoport--- arch/arm/mach-omap2/gpmc-nand.c | 19 ++++++++++++++++++- arch/arm/plat-omap/include/plat/nand.h | 1 + 2 files changed, 19 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/gpmc-nand.c +18 -1
@@ -22,6 +22,7 @@#define WR_RD_PIN_MONITORING 0x00600000static struct omap_nand_platform_data *gpmc_nand_data; +static struct gpmc_timings gpmc_default_timings;static struct resource gpmc_nand_resource = { .flags =IORESOURCE_MEM ,
@@ -34,13 +35,24 @@ static struct platform_device gpmc_nand_device = { .resource = &gpmc_nand_resource, }; +static void gpmc_nand_detect_timings (void ) +{ +struct gpmc_timings t; + +memset (&t,0 ,sizeof (t)); +gpmc_cs_get_timings (gpmc_nand_data->cs, &gpmc_default_timings); +} +static int omap2_nand_gpmc_retime (void ) { +struct device *dev = &gpmc_nand_device.dev;struct gpmc_timings t;int err; -if (!gpmc_nand_data->gpmc_t) +if (!gpmc_nand_data->gpmc_t) { +dev_warn (dev,"No timings provided, skipping retime\n" );return 0 ; + }memset (&t,0 ,sizeof (t)); t.sync_clk =gpmc_round_ns_to_ticks (gpmc_nand_data->gpmc_t->sync_clk);
@@ -112,6 +124,11 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)return err; } +if (gpmc_nand_data->keep_timings) { +gpmc_nand_detect_timings (); + gpmc_nand_data->gpmc_t = &gpmc_default_timings; + } + err =gpmc_nand_setup ();if (err <0 ) {dev_err (dev,"NAND platform setup failed: %d\n" , err);
arch/arm/plat-omap/include/plat/nand.h +1 -0
@@ -24,6 +24,7 @@ struct omap_nand_platform_data {void __iomem *gpmc_cs_baseaddr;void __iomem *gpmc_baseaddr;int devsize; +bool keep_timings; };/* size (4 KiB) for IO mapping */
Signature · 1 line
1.6.6.2
Quoted 45 lines · Mike Rapoport
Signed-off-by Mike Rapoport <[email protected]>---
arch/arm/mach-omap2/gpmc-nand.c | 19 ++++++++++++++++++-arch/arm/plat-omap/include/plat/nand.h| 1 +2 files changed, 19 insertions(+), 1 deletions(-)arch/arm/mach-omap2/gpmc-nand.c +13
-1@@ -22,6 +22,7 @@ #define WR_RD_PIN_MONITORING 0x00600000 static struct omap_nand_platform_data *gpmc_nand_data; +static struct gpmc_timings gpmc_default_timings; static struct resource gpmc_nand_resource = { .flags = IORESOURCE_MEM,@@ -34,13 +35,24 @@ static struct platform_device gpmc_nand_device = { .resource = &gpmc_nand_resource, }; +static void gpmc_nand_detect_timings (void ) +{ + struct gpmc_timings t; + + memset(&t, 0, sizeof(t)); + gpmc_cs_get_timings(gpmc_nand_data->cs, &gpmc_default_timings); +} + static int omap2_nand_gpmc_retime(void) { + struct device *dev = &gpmc_nand_device.dev; struct gpmc_timings t; int err; - if (!gpmc_nand_data->gpmc_t) + if (!gpmc_nand_data->gpmc_t) { + dev_warn(dev, "No timings provided, skipping retime\n"); return 0; + } memset(&t, 0, sizeof(t)); t.sync_clk = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->sync_clk);
arch/arm/mach-omap2/gpmc-nand.c int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data) · line 131
Quoted 8 lines
arch/arm/mach-omap2/gpmc-nand.c +5
-0@@ -112,6 +124,11 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data) return err; } + if (gpmc_nand_data->keep_timings) { + gpmc_nand_detect_timings(); + gpmc_nand_data->gpmc_t = &gpmc_default_timings; + } +
I guess moving this part to omap2_nand_gpmc_retime will be a good idea. As there, once we get old/default timings we can simply skip the rounding part and directly jump to setting the timings.
Rest looks fine to me.
Signature · 6 lines
Regards, Vimal Singh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 49 lines · Vimal Singh
Quoted 48 lines · Mike Rapoport
Signed-off-by Mike Rapoport <[email protected]>--- arch/arm/mach-omap2/gpmc-nand.c | 19 ++++++++++++++++++- arch/arm/plat-omap/include/plat/nand.h | 1 + 2 files changed, 19 insertions(+), 1 deletions(-)arch/arm/mach-omap2/gpmc-nand.c +13
-1@@ -22,6 +22,7 @@#define WR_RD_PIN_MONITORING 0x00600000static struct omap_nand_platform_data *gpmc_nand_data; +static struct gpmc_timings gpmc_default_timings;static struct resource gpmc_nand_resource = { .flags =IORESOURCE_MEM ,@@ -34,13 +35,24 @@ static struct platform_device gpmc_nand_device = { .resource = &gpmc_nand_resource, }; +static void gpmc_nand_detect_timings (void ) +{ +struct gpmc_timings t; + +memset (&t,0 ,sizeof (t)); +gpmc_cs_get_timings (gpmc_nand_data->cs, &gpmc_default_timings); +} +static int omap2_nand_gpmc_retime (void ) { +struct device *dev = &gpmc_nand_device.dev;struct gpmc_timings t;int err; -if (!gpmc_nand_data->gpmc_t) +if (!gpmc_nand_data->gpmc_t) { +dev_warn (dev,"No timings provided, skipping retime\n" );return 0 ; + }memset (&t,0 ,sizeof (t)); t.sync_clk =gpmc_round_ns_to_ticks (gpmc_nand_data->gpmc_t->sync_clk);@@ -112,6 +124,11 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data)return err; }
Quoted 9 lines
arch/arm/mach-omap2/gpmc-nand.c int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data) · line 131
Quoted 5 lines
arch/arm/mach-omap2/gpmc-nand.c +5
-0+if (gpmc_nand_data->keep_timings) { +gpmc_nand_detect_timings (); + gpmc_nand_data->gpmc_t = &gpmc_default_timings; + } +I guess moving this part to
omap2_nand_gpmc_retimewill be a good idea. As there, once we get old/default timings we can simply skip the rounding part and directly jump to setting the timings.
This way it would be the same as to pass 'gpmc_nand_data->gpmc_t = NULL'. If I correctly understood the previous comments ([1]), the problem with skipping retime is that when L3 clock changes, the gpmc timings became wrong. So, if we convert old/default timings to nanoseconds early during startup every time retime is called it will use the timing settings in nanoseconds thus yielding proper gpmc registers configuration.
And, if I'm not terribly mistaken retime should be called each time L3 frequency changes, though with current kernel it's not yet the case...
--
[1] http://thread.gmane.org/gmane.linux.ports.arm.omap/34164/focus=34558
Quoted 2 lines
Rest looks fine to me.
Signature · 2 lines
Sincerely yours, Mike.
Quoted 16 lines · Mike Rapoport
Quoted 11 lines · Vimal Singh
Quoted 7 lines · Mike Rapoport
Signed-off-by Mike Rapoport <[email protected]>+ if (
gpmc_nand_data->keep_timings) {
+gpmc_nand_detect_timings();
+gpmc_nand_data->gpmc_t=&gpmc_default_timings;
+ }
+Quoted 3 lines
I guess moving this part to
omap2_nand_gpmc_retimewill be a good idea. As there, once we get old/default timings we can simply skip the rounding part and directly jump to setting the timings.
Quoted 7 lines
This way it would be the same as to pass '
gpmc_nand_data->gpmc_t= NULL'. If I correctly understood the previous comments ([1]), the problem with skipping retime is that when L3 clock changes, the gpmc timings became wrong. So, if we convert old/default timings to nanoseconds early during startup every time retime is called it will use the timing settings in nanoseconds thus yielding proper gpmc registers configuration.
OK. Then I think we can at least put __rounding__ code inside an 'if' case, something like:
if (!gpmc_nand_data->keep_timings) {
...
do rounding for supplied timings from board file.
...
}
Quoted 2 lines
And, if I'm not terribly mistaken retime should be called each time L3 frequency changes, though with current kernel it's not yet the case...
Yes. This is still left.
Signature · 6 lines
Regards, Vimal Singh -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 21 lines · Vimal Singh
Quoted 12 lines · Mike Rapoport
Quoted 11 lines · Vimal Singh
arch/arm/mach-omap2/gpmc-nand.c int __init gpmc_nand_init(struct omap_nand_platform_data *_nand_data) · line 131
Quoted 6 lines · Mike Rapoport
Signed-off-by Mike Rapoport <[email protected]>arch/arm/mach-omap2/gpmc-nand.c +5
-0+if (gpmc_nand_data->keep_timings) { +gpmc_nand_detect_timings (); + gpmc_nand_data->gpmc_t = &gpmc_default_timings; + } +I guess moving this part to
omap2_nand_gpmc_retimewill be a good idea. As there, once we get old/default timings we can simply skip the rounding part and directly jump to setting the timings.Quoted 7 lines
This way it would be the same as to pass '
gpmc_nand_data->gpmc_t= NULL'. If I correctly understood the previous comments ([1]), the problem with skipping retime is that when L3 clock changes, the gpmc timings became wrong. So, if we convert old/default timings to nanoseconds early during startup every time retime is called it will use the timing settings in nanoseconds thus yielding proper gpmc registers configuration.
Quoted 7 lines
OK. Then I think we can at least put
__rounding__code inside an 'if' case, something like:
if (!gpmc_nand_data->keep_timings) {
...
do rounding for supplied timings from board file.
...
}
Sure, no problem.
Quoted 5 lines
Quoted 2 lines
And, if I'm not terribly mistaken retime should be called each time L3 frequency changes, though with current kernel it's not yet the case...
Yes. This is still left.
Signature · 2 lines
Sincerely yours, Mike.