Skip to contentSkip to conversation

OMAP-GPMC: generic time calc, prepare for driver

PATCH Superseded Afzal Mohammed 6 participants 37 messages Aug 21, 2012 – Sep 19, 2012

Subsystems (6)

v6 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v6 cover OMAP-GPMC: generic time calc, prepare for driver

Hi,

This series provides a generic gpmc timing calculation routine. There were three peripherals (OneNAND, tusb6010, smc91x) using custom timing calculations, they are migrated to use the generic timing calculation.

Such a generic routine would help create a driver out of gpmc platform code, which would be peripheral agnostic and thus lead to DT finally. Input to generic timing calculation routine would be gpmc peripheral timings, output - translated timings that gpmc can understand. Later, to DT'ify, gpmc peripheral timings could be passed through DT. Input timings that has been used here are selected such that it represents those that are present in peripheral timing datasheets.

Proposed generic routine has been tested on OneNAND (async) on OMAP3EVM rev C (as mainline does not have the OneNAND support for this, local patch were used to test). For other cases of custom timing calculation (tusb6010, smc91x non-muxed, OneNAND sync), generic timing calculation routine was verified by simulating on OMAP3EVM. Codebase for such a testing is available
@ git://gitorious.org/x0148406-public/linux-kernel.git gpmc-prep-v6-verify

Regarding "we_on" for onenand async, it was found that even for muxed address/data, it need not be greater than "adv_wr_off", but rather could be derived from write setup time for peripheral from start of access, hence would more be in line with peripheral timings. With "we_on" calculated this way, it was working fine. If it is required in some cases to have "we_on" same as "wr_data_mux_bus" (i.e. greater than "adv_wr_off") other than for IP's not having "wr_data_mux_bus", another variable could be added to indicate it, but such a requirement is not expected though.

It has been observed that "adv_rd_off" & "adv_wr_off" are currently calculated by adding an offset over "oe_on" & "we_on" respectively in the case of smc91x. But peripheral datasheet does not specify so and so "adv_rd(wr)_off" has been derived (to be specific, made ignorant of "oe_on" & "we_on") observing datasheet rather than adding an offset. Hence this generic routine is expected to work for smc91x (91C96 RX51 board). This was verified on smsc911x (9220 on OMAP3EVM)
- a similar ethernet controller.

Also this series contains, patches 1-3 of v5 in addition to minor cleanups that were low hanging fruits came across upon implementing generic timing routine. One such is credited to Jon Hunter, relevant patch is 1/2 of his series
@ http://marc.info/?l=linux-omap&m=134090910321284&w=2

This series has been tested on OMAP3EVM. As mentioned above, generic timing could be tested on OneNAND hardware working in async mode. Also generic timing calculation for other cases was validated by comparing output values of existing custom timing calculation routine & the new generic one, these conditions were simulated on OMAP3EVM

This series is available

	@ git://gitorious.org/x0148406-public/linux-kernel.git gpmc-prep-v6

and is made on top of

	http://marc.info/?l=linux-omap&m=134554192102899&w=2

which is based over 3.6-rc1.

Regards
Afzal

v6:
1. Generic timing calculation, move existing users of custom calculation to use the new generic one
2. Set OneNAND part to async mode before gpmc configuration
3. Move extra delay time user handling to proper patch (3/10 -> 2/10)
4. Modify nand init for OMAP3EVM too as support got added
v5:
Use flags for sync_read/write, hv, vhf
v4:
Reorganize OneNAND set_sync/async functions in a better way
v3:
1. Refactor OneNAND set_sync/async functions to separate out timing and configurations
2. Handle bool type timings too
3. Swap patches 2 & 3 due to dependency of OneNAND change on newly added bool type timings
v2:
1. Make use of timing api for setting clock activation time, and remove direct writing to register for clock activation.
2. Move ensuring that async mode in OneNAND has been setup from set_sync to setup function, improve commit message

Afzal Mohammed (9):
ARM: OMAP2+: nand: unify init functions
ARM: OMAP2+: gpmc: handle additional timings
ARM: OMAP2+: onenand: refactor for clarity
ARM: OMAP2+: gpmc: find features by ip rev check
ARM: OMAP2+: gpmc: remove cs# in sync clk div calc
ARM: OMAP2+: gpmc: generic timing calculation
ARM: OMAP2+: onenand: generic timing calculation
ARM: OMAP2+: smc91x: generic timing calculation
ARM: OMAP2+: tusb6010: generic timing calculation

Jon Hunter (1):
ARM: OMAP2+: GPMC: Remove unused OneNAND get_freq() platform function

 arch/arm/mach-omap2/board-devkit8000.c     |    8 +-
 arch/arm/mach-omap2/board-flash.c          |   45 ++--
 arch/arm/mach-omap2/board-flash.h          |    6 +-
 arch/arm/mach-omap2/board-igep0020.c       |    2 +-
 arch/arm/mach-omap2/board-ldp.c            |    4 +-
 arch/arm/mach-omap2/board-omap3beagle.c    |    8 +-
 arch/arm/mach-omap2/board-omap3evm.c       |    8 +-
 arch/arm/mach-omap2/board-omap3touchbook.c |    8 +-
 arch/arm/mach-omap2/board-overo.c          |    7 +-
 arch/arm/mach-omap2/board-zoom.c           |    5 +-
 arch/arm/mach-omap2/common-board-devices.c |   46 ----
 arch/arm/mach-omap2/common-board-devices.h |    1 -
 arch/arm/mach-omap2/gpmc-onenand.c         |  334 +++++++++++---------------
 arch/arm/mach-omap2/gpmc-smc91x.c          |   43 ++--
 arch/arm/mach-omap2/gpmc.c                 |  363 +++++++++++++++++++++++++++-
 arch/arm/mach-omap2/usb-tusb6010.c         |  180 ++++-----------
 arch/arm/plat-omap/include/plat/gpmc.h     |   82 ++++++-
 arch/arm/plat-omap/include/plat/onenand.h  |    8 -
 18 files changed, 707 insertions(+), 451 deletions(-)
#1 lore raw

PATCH v6 1/10 ARM: OMAP2+: nand: unify init functions

Helper function for updating nand platform data has been added the capability to take timing structure arguement. Usage of omap_nand_flash_init() has been replaced by modifed one, omap_nand_flash_init was doing things similar to board_nand_init except that NAND CS# were being acquired based on bootloader setting. As CS# is hardwired for a given board, acquiring gpmc CS# has been removed, and updated with the value on board.

NAND CS# used in beagle board & omap3evm was found to be CS0. Thomas Weber <[email protected]> reported that value of devkit8000 to be CS0. Overo board was found to be using CS0 based on u-boot, while google grep says omap3touchbook too has CS0.

---

v6: Modify nand init for OMAP3EVM too as support got added

 arch/arm/mach-omap2/board-devkit8000.c     |    8 ++++-
 arch/arm/mach-omap2/board-flash.c          |   45 ++++++++++++++-------------
 arch/arm/mach-omap2/board-flash.h          |    6 ++-
 arch/arm/mach-omap2/board-igep0020.c       |    2 +-
 arch/arm/mach-omap2/board-ldp.c            |    4 +-
 arch/arm/mach-omap2/board-omap3beagle.c    |    8 ++++-
 arch/arm/mach-omap2/board-omap3evm.c       |    8 ++++-
 arch/arm/mach-omap2/board-omap3touchbook.c |    8 ++++-
 arch/arm/mach-omap2/board-overo.c          |    7 +++-
 arch/arm/mach-omap2/board-zoom.c           |    5 ++-
 arch/arm/mach-omap2/common-board-devices.c |   46 ----------------------------
 arch/arm/mach-omap2/common-board-devices.h |    1 -
 12 files changed, 62 insertions(+), 86 deletions(-)
arch/arm/mach-omap2/board-devkit8000.c +6 -2
index 6567c1c..6ee429a 100644
@@ -59,8 +59,11 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "board-flash.h"
 #include "common-board-devices.h"
 
+#define	NAND_CS			0
+
 #define OMAP_DM9000_GPIO_IRQ	25
 #define OMAP3_DEVKIT_TS_GPIO	27
 
@@ -628,8 +631,9 @@ static void __init devkit8000_init(void)
 
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
-	omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,
-			     ARRAY_SIZE(devkit8000_nand_partitions));
+	board_nand_init(devkit8000_nand_partitions,
+		ARRAY_SIZE(devkit8000_nand_partitions), NAND_CS,
+		NAND_BUSWIDTH_16, NULL);
 
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
arch/arm/mach-omap2/board-flash.c +23 -22

69 lines not on this page · raw message

arch/arm/mach-omap2/board-flash.h +4 -2
index c44b70d..a3aa5fc 100644
@@ -40,12 +40,14 @@ static inline void board_flash_init(struct flash_partitions part[],
 #if defined(CONFIG_MTD_NAND_OMAP2) || \
 		defined(CONFIG_MTD_NAND_OMAP2_MODULE)
 extern void board_nand_init(struct mtd_partition *nand_parts,
-					u8 nr_parts, u8 cs, int nand_type);
+		u8 nr_parts, u8 cs, int nand_type, struct gpmc_timings *gpmc_t);
+extern struct gpmc_timings nand_default_timings[];
 #else
 static inline void board_nand_init(struct mtd_partition *nand_parts,
-					u8 nr_parts, u8 cs, int nand_type)
+		u8 nr_parts, u8 cs, int nand_type, struct gpmc_timings *gpmc_t)
 {
 }
+#define	nand_default_timings	NULL
 #endif
 
 #if defined(CONFIG_MTD_ONENAND_OMAP2) || \
arch/arm/mach-omap2/board-igep0020.c +1 -1
index 2821448..b7401f7 100644
@@ -175,7 +175,7 @@ static void __init igep_flash_init(void)
 		pr_info("IGEP: initializing NAND memory device\n");
 		board_nand_init(igep_flash_partitions,
 				ARRAY_SIZE(igep_flash_partitions),
-				0, NAND_BUSWIDTH_16);
+				0, NAND_BUSWIDTH_16, nand_default_timings);
 	} else if (mux == IGEP_SYSBOOT_ONENAND) {
 		pr_info("IGEP: initializing OneNAND memory device\n");
 		board_onenand_init(igep_flash_partitions,
arch/arm/mach-omap2/board-ldp.c +2 -2
index ef9e829..5d8fa99 100644
@@ -427,8 +427,8 @@ static void __init omap_ldp_init(void)
 	omap_serial_init();
 	omap_sdrc_init(NULL, NULL);
 	usb_musb_init(NULL);
-	board_nand_init(ldp_nand_partitions,
-		ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
+	board_nand_init(ldp_nand_partitions, ARRAY_SIZE(ldp_nand_partitions),
+				ZOOM_NAND_CS, 0, nand_default_timings);
 
 	omap_hsmmc_init(mmc);
 	ldp_display_init();
arch/arm/mach-omap2/board-omap3beagle.c +6 -2
index 6202fc7..940ab49 100644
@@ -51,8 +51,11 @@
 #include "mux.h"
 #include "hsmmc.h"
 #include "pm.h"
+#include "board-flash.h"
 #include "common-board-devices.h"
 
+#define	NAND_CS	0
+
 /*
  * OMAP3 Beagle revision
  * Run time detection of Beagle revision is done by reading GPIO.
@@ -517,8 +520,9 @@ static void __init omap3_beagle_init(void)
 
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
-	omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,
-			     ARRAY_SIZE(omap3beagle_nand_partitions));
+	board_nand_init(omap3beagle_nand_partitions,
+		ARRAY_SIZE(omap3beagle_nand_partitions), NAND_CS,
+		NAND_BUSWIDTH_16, NULL);
 
 	/* Ensure msecure is mux'd to be able to set the RTC. */
 	omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
arch/arm/mach-omap2/board-omap3evm.c +6 -2
index 0d362e9..833c42c 100644
@@ -57,6 +57,9 @@
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "hsmmc.h"
 #include "common-board-devices.h"
+#include "board-flash.h"
+
+#define	NAND_CS			0
 
 #define OMAP3_EVM_TS_GPIO	175
 #define OMAP3_EVM_EHCI_VBUS	22
@@ -730,8 +733,9 @@ static void __init omap3_evm_init(void)
 	}
 	usb_musb_init(&musb_board_data);
 	usbhs_init(&usbhs_bdata);
-	omap_nand_flash_init(NAND_BUSWIDTH_16, omap3evm_nand_partitions,
-			     ARRAY_SIZE(omap3evm_nand_partitions));
+	board_nand_init(omap3evm_nand_partitions,
+		ARRAY_SIZE(omap3evm_nand_partitions), NAND_CS,
+		NAND_BUSWIDTH_16, NULL);
 
 	omap_ads7846_init(1, OMAP3_EVM_TS_GPIO, 310, NULL);
 	omap3evm_init_smsc911x();
arch/arm/mach-omap2/board-omap3touchbook.c +6 -2
index 485d14d..75e07f6 100644
@@ -52,6 +52,7 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "board-flash.h"
 #include "common-board-devices.h"
 
 #include <asm/setup.h>
@@ -61,6 +62,8 @@
 #define TB_BL_PWM_TIMER		9
 #define TB_KILL_POWER_GPIO	168
 
+#define	NAND_CS			0
+
 static unsigned long touchbook_revision;
 
 static struct mtd_partition omap3touchbook_nand_partitions[] = {
@@ -370,8 +373,9 @@ static void __init omap3_touchbook_init(void)
 	omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
-	omap_nand_flash_init(NAND_BUSWIDTH_16, omap3touchbook_nand_partitions,
-			     ARRAY_SIZE(omap3touchbook_nand_partitions));
+	board_nand_init(omap3touchbook_nand_partitions,
+		ARRAY_SIZE(omap3touchbook_nand_partitions), NAND_CS,
+		NAND_BUSWIDTH_16, NULL);
 
 	/* Ensure SDRC pins are mux'd for self-refresh */
 	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
arch/arm/mach-omap2/board-overo.c +5 -2
index 779734d..56d5b9e 100644
@@ -57,8 +57,11 @@
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "hsmmc.h"
+#include "board-flash.h"
 #include "common-board-devices.h"
 
+#define	NAND_CS			0
+
 #define OVERO_GPIO_BT_XGATE	15
 #define OVERO_GPIO_W2W_NRESET	16
 #define OVERO_GPIO_PENDOWN	114
@@ -500,8 +503,8 @@ static void __init overo_init(void)
 	omap_serial_init();
 	omap_sdrc_init(mt46h32m32lf6_sdrc_params,
 				  mt46h32m32lf6_sdrc_params);
-	omap_nand_flash_init(0, overo_nand_partitions,
-			     ARRAY_SIZE(overo_nand_partitions));
+	board_nand_init(overo_nand_partitions,
+		ARRAY_SIZE(overo_nand_partitions), NAND_CS, 0, NULL);
 	usb_musb_init(NULL);
 	usbhs_init(&usbhs_bdata);
 	overo_spi_init();
arch/arm/mach-omap2/board-zoom.c +3 -2
index 4e7e561..a04dd85 100644
@@ -114,8 +114,9 @@ static void __init omap_zoom_init(void)
 		usbhs_init(&usbhs_bdata);
 	}
 
-	board_nand_init(zoom_nand_partitions, ARRAY_SIZE(zoom_nand_partitions),
-						ZOOM_NAND_CS, NAND_BUSWIDTH_16);
+	board_nand_init(zoom_nand_partitions,
+			ARRAY_SIZE(zoom_nand_partitions), ZOOM_NAND_CS,
+			NAND_BUSWIDTH_16, nand_default_timings);
 	zoom_debugboard_init();
 	zoom_peripherals_init();
 
arch/arm/mach-omap2/common-board-devices.c +0 -46

49 lines not on this page · raw message

arch/arm/mach-omap2/common-board-devices.h +0 -1
index a0b4a42..72bb41b 100644
@@ -10,6 +10,5 @@ struct ads7846_platform_data;
 
 void omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
 		       struct ads7846_platform_data *board_pdata);
-void omap_nand_flash_init(int opts, struct mtd_partition *parts, int n_parts);
 
 #endif /* __OMAP_COMMON_BOARD_DEVICES__ */
Signature · 1 line
1.7.1
#2 lore raw

PATCH v6 1/10 ARM: OMAP2+: nand: unify init functions

Hi Afzal,

Thanks for the patches!

Quoted 9 lines · Afzal Mohammed

Helper function for updating nand platform data has been added the capability to take timing structure arguement. Usage of omap_nand_flash_init() has been replaced by modifed one, omap_nand_flash_init was doing things similar to board_nand_init except that NAND CS# were being acquired based on bootloader setting. As CS# is hardwired for a given board, acquiring gpmc CS# has been removed, and updated with the value on board.

Quoted 8 lines

NAND CS# used in beagle board & omap3evm was found to be CS0. Thomas Weber <[email protected]> reported that value of devkit8000 to be CS0. Overo board was found to be using CS0 based on u-boot, while google grep says omap3touchbook too has CS0.

Signature · 2 lines
Regards,
Igor.
#3 lore raw

PATCH v6 2/10 ARM: OMAP2+: gpmc: handle additional timings

In reply to Afzal Mohammed

Configure busturnaround, cycle2cycledelay, waitmonitoringtime, clkactivationtime in gpmc_cs_set_timings(). This is done so that boards can configure these parameters of gpmc in Kernel instead of relying on bootloader. Also configure bool type timings like extradelay.

This needed change to the existing users that were configuring clk activation time and extra delay by directly writing to registers. Thanks to Tony for making me aware of users of clk activation and being kind enough to test the modified one.

---

v6: Move extra delay time user handling to present one from 3/10
v3: Handle bool type timings too
v2: Make use of timing api for setting clock activation time,
and remove direct writing to register for clock activation.

 arch/arm/mach-omap2/gpmc-onenand.c     |   28 ++++---------------
 arch/arm/mach-omap2/gpmc.c             |   45 ++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/usb-tusb6010.c     |    3 +-
 arch/arm/plat-omap/include/plat/gpmc.h |   19 +++++++++++++
 4 files changed, 72 insertions(+), 23 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +6 -22
index 71d7c07..977b71d 100644
@@ -284,27 +284,10 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
 					sync_read, sync_write, hf, vhf);
 
 	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 */
@@ -329,6 +312,8 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
 	t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
 		     ticks_cez);
 
+	t.clk_activation = fclk_offset_ns;
+
 	/* Write */
 	if (sync_write) {
 		t.adv_wr_off = t.adv_rd_off;
@@ -362,7 +347,6 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
 			  (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
 			  (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
 			  (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
-			  GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
 			  GPMC_CONFIG1_PAGE_LEN(2) |
 			  (cpu_is_omap34xx() ? 0 :
 				(GPMC_CONFIG1_WAIT_READ_MON |
arch/arm/mach-omap2/gpmc.c +45 -0

69 lines not on this page · raw message

arch/arm/mach-omap2/usb-tusb6010.c +2 -1
index 805bea6..7a85ebe 100644
@@ -174,6 +174,8 @@ static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
 	tmp = t.cs_wr_off * 1000 + 7000 /* t_scsn_rdy_z */;
 	t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
 
+	t.clk_activation = gpmc_ticks_to_ns(1);
+
 	return gpmc_cs_set_timings(sync_cs, &t);
 }
 
@@ -283,7 +285,6 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
 			| GPMC_CONFIG1_READTYPE_SYNC
 			| GPMC_CONFIG1_WRITEMULTIPLE_SUPP
 			| GPMC_CONFIG1_WRITETYPE_SYNC
-			| GPMC_CONFIG1_CLKACTIVATIONTIME(1)
 			| GPMC_CONFIG1_PAGE_LEN(2)
 			| GPMC_CONFIG1_WAIT_READ_MON
 			| GPMC_CONFIG1_WAIT_WRITE_MON
arch/arm/plat-omap/include/plat/gpmc.h +19 -0
index 2e6e259..b7c9ea6 100644
@@ -96,6 +96,17 @@ enum omap_ecc {
 	OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
 };
 
+/* bool type time settings */
+struct gpmc_bool_timings {
+	bool cycle2cyclediffcsen;
+	bool cycle2cyclesamecsen;
+	bool we_extra_delay;
+	bool oe_extra_delay;
+	bool adv_extra_delay;
+	bool cs_extra_delay;
+	bool time_para_granularity;
+};
+
 /*
  * Note that all values in this struct are in nanoseconds except sync_clk
  * (which is in picoseconds), while the register values are in gpmc_fck cycles.
@@ -128,9 +139,17 @@ struct gpmc_timings {
 	u16 rd_cycle;		/* Total read cycle time */
 	u16 wr_cycle;		/* Total write cycle time */
 
+	u16 bus_turnaround;
+	u16 cycle2cycle_delay;
+
+	u16 wait_monitoring;
+	u16 clk_activation;
+
 	/* The following are only on OMAP3430 */
 	u16 wr_access;		/* WRACCESSTIME */
 	u16 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+
+	struct gpmc_bool_timings bool_timings;
 };
 
 struct gpmc_nand_regs {
Signature · 1 line
1.7.1
#4 lore raw

PATCH v6 3/10 ARM: OMAP2+: onenand: refactor for clarity

In reply to Afzal Mohammed

Refactor set_async_mode & set_sync_mode functions to separate out timing calculation & actual configuration (GPMC & OneNAND side).

Thanks to Jon for his suggestions.

---

v6:
1. Set OneNAND part to async mode before gpmc configuration
2. Move extra delay time user handling away from this patch (3/10 -> 2/10)
v5: Use flags for sync_read/write, hv, vhf
v4: Reorganize OneNAND set_sync/async functions in a better way
v3: Refactor OneNAND 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 |  174 ++++++++++++++++++++++-------------
 1 files changed, 109 insertions(+), 65 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +109 -65
index 977b71d..bbae674 100644
@@ -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,9 +275,8 @@ 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) {
 		t.bool_timings.cs_extra_delay = true;
@@ -290,8 +285,6 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
 		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;
@@ -315,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;
@@ -340,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 |
@@ -355,11 +356,47 @@ 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;
+
+	omap2_onenand_set_async_mode(onenand_base);
+
+	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;
 
@@ -369,15 +406,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)
Signature · 1 line
1.7.1
#5 lore raw

PATCH v6 4/10 ARM: OMAP2+: GPMC: Remove unused OneNAND get_freq() platform function

In reply to Afzal Mohammed

From: Jon Hunter <[email protected]>

A platform function pointer for getting the frequency of a OneNAND device was added so that a platform could specify a custom function for returning the frequency and not just rely on the OneNAND version to determine the frequency. However, this platform function pointer is not currently being used and I am not sure if it ever has.

OneNAND devices are not so common these days and as far as I know not being used with new devices. Therefore, it is most likely that this get_freq() function pointer will not be used and so remove it.

Given that the get_freq() function pointer is not used, neither is the clk_dep variable and so all references to it can also be removed.

---
 arch/arm/mach-omap2/gpmc-onenand.c        |   39 +++-------------------------
 arch/arm/plat-omap/include/plat/onenand.h |    8 ------
 2 files changed, 5 insertions(+), 42 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +5 -34
index bbae674..8a301f3 100644
@@ -139,21 +139,10 @@ static void set_onenand_cfg(void __iomem *onenand_base)
 }
 
 static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
-				  void __iomem *onenand_base, bool *clk_dep)
+				  void __iomem *onenand_base)
 {
 	u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
-	int freq = 0;
-
-	if (cfg->get_freq) {
-		struct onenand_freq_info fi;
-
-		fi.maf_id = readw(onenand_base + ONENAND_REG_MANUFACTURER_ID);
-		fi.dev_id = readw(onenand_base + ONENAND_REG_DEVICE_ID);
-		fi.ver_id = ver;
-		freq = cfg->get_freq(&fi, clk_dep);
-		if (freq)
-			return freq;
-	}
+	int freq;
 
 	switch ((ver >> 4) & 0xf) {
 	case 0:
@@ -181,7 +170,7 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
 
 static struct gpmc_timings
 omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
-						int freq, bool clk_dep)
+						int freq)
 {
 	struct gpmc_timings t;
 	const int t_cer  = 15;
@@ -259,22 +248,6 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 	else
 		latency = 4;
 
-	if (clk_dep) {
-		if (gpmc_clk_ns < 12) { /* >83Mhz */
-			t_ces   = 3;
-			t_avds  = 4;
-		} else if (gpmc_clk_ns < 15) { /* >66Mhz */
-			t_ces   = 5;
-			t_avds  = 4;
-		} else if (gpmc_clk_ns < 25) { /* >40Mhz */
-			t_ces   = 6;
-			t_avds  = 5;
-		} else {
-			t_ces   = 7;
-			t_avds  = 7;
-		}
-	}
-
 	/* Set synchronous read timings */
 	memset(&t, 0, sizeof(t));
 
@@ -381,16 +354,14 @@ 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);
+		freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
 		set_onenand_cfg(onenand_base);
 	}
 
-	t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq, clk_dep);
+	t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq);
 
 	ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t);
 	if (IS_ERR_VALUE(ret))
arch/arm/plat-omap/include/plat/onenand.h +0 -8
index 2858667..21bb0ff 100644
@@ -15,20 +15,12 @@
 #define ONENAND_SYNC_READ	(1 << 0)
 #define ONENAND_SYNC_READWRITE	(1 << 1)
 
-struct onenand_freq_info {
-	u16			maf_id;
-	u16			dev_id;
-	u16			ver_id;
-};
-
 struct omap_onenand_platform_data {
 	int			cs;
 	int			gpio_irq;
 	struct mtd_partition	*parts;
 	int			nr_parts;
 	int			(*onenand_setup)(void __iomem *, int *freq_ptr);
-	int		(*get_freq)(const struct onenand_freq_info *freq_info,
-				    bool *clk_dep);
 	int			dma_channel;
 	u8			flags;
 	u8			regulator_can_sleep;
Signature · 1 line
1.7.1
#6 lore raw

PATCH v6 5/10 ARM: OMAP2+: gpmc: find features by ip rev check

In reply to Afzal Mohammed

Newer IP's have wr_access and wr_data_mux_bus fields. Use IP revision values to determine availability of these fields and hence decide on whether to configure them.

---
 arch/arm/mach-omap2/gpmc.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/gpmc.c +10 -2
index 070fac5..68123d0 100644
@@ -85,6 +85,11 @@
 #define ENABLE_PREFETCH		(0x1 << 7)
 #define DMA_MPU_MODE		2
 
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+
 /* XXX: Only NAND irq has been considered,currently these are the only ones used
  */
 #define	GPMC_NR_IRQ		2
@@ -131,6 +136,7 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned int gpmc_cs_map;	/* flag for cs which are initialized */
 static int gpmc_ecc_used = -EINVAL;	/* cs using ecc engine */
 
+static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
@@ -356,10 +362,10 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
 	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
 
-	if (cpu_is_omap34xx()) {
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
-	}
 
 	/* caller is expected to have initialized CONFIG1 to cover
 	 * at least sync vs async
@@ -922,6 +928,8 @@ static int __init gpmc_init(void)
 	clk_enable(gpmc_l3_clk);
 
 	l = gpmc_read_reg(GPMC_REVISION);
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 	printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
 	/* Set smart idle mode and automatic L3 clock gating */
 	l = gpmc_read_reg(GPMC_SYSCONFIG);
Signature · 1 line
1.7.1
#7 lore raw

PATCH v6 5/10 ARM: OMAP2+: gpmc: find features by ip rev check

Quoted 48 lines · Afzal Mohammed

Newer IP's have wr_access and wr_data_mux_bus fields. Use IP revision values to determine availability of these fields and hence decide on whether to configure them.

---
 arch/arm/mach-omap2/gpmc.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/gpmc.c +8 -2
index 070fac5..68123d0 100644
@@ -85,6 +85,11 @@
 #define ENABLE_PREFETCH		(0x1 << 7)
 #define DMA_MPU_MODE		2
 
+#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)
+
+#define	GPMC_HAS_WR_ACCESS		0x1
+#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2
+
 /* XXX: Only NAND irq has been considered,currently these are the only ones used
  */
 #define	GPMC_NR_IRQ		2
@@ -131,6 +136,7 @@ static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned int gpmc_cs_map;	/* flag for cs which are initialized */
 static int gpmc_ecc_used = -EINVAL;	/* cs using ecc engine */
 
+static unsigned gpmc_capability;
 static void __iomem *gpmc_base;
 
 static struct clk *gpmc_l3_clk;
@@ -356,10 +362,10 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring);
 	GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation);
 
-	if (cpu_is_omap34xx()) {
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+	if (gpmc_capability & GPMC_HAS_WR_ACCESS)
 		GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
-	}
 
 	/* caller is expected to have initialized CONFIG1 to cover
 	 * at least sync vs async

arch/arm/mach-omap2/gpmc.c static int __init gpmc_init(void) · line 935

Quoted 8 lines
arch/arm/mach-omap2/gpmc.c +2 -0
@@ -922,6 +928,8 @@ static int __init gpmc_init(void)
 	clk_enable(gpmc_l3_clk);
 
 	l = gpmc_read_reg(GPMC_REVISION);
+	if (GPMC_REVISION_MAJOR(l) > 0x4)
+		gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
 	printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
 	/* Set smart idle mode and automatic L3 clock gating */
 	l = gpmc_read_reg(GPMC_SYSCONFIG);

Thanks!
Jon

#8 lore raw

PATCH v6 6/10 ARM: OMAP2+: gpmc: remove cs# in sync clk div calc

In reply to Afzal Mohammed

Divider value for a certain sync clk is determined solely based on gpmc fclk. CS# does not have any role here, thus remove presence of CS# in clock divider calculation API.

---
 arch/arm/mach-omap2/gpmc-onenand.c     |    3 +--
 arch/arm/mach-omap2/gpmc.c             |    4 ++--
 arch/arm/plat-omap/include/plat/gpmc.h |    2 +-
 3 files changed, 4 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +1 -2
index 8a301f3..e139e3f 100644
@@ -182,7 +182,6 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 	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;
 	int ticks_cez;
-	int cs = cfg->cs;
 
 	if (cfg->flags & ONENAND_SYNC_READ)
 		onenand_flags = ONENAND_FLAG_SYNCREAD;
@@ -229,7 +228,7 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 		break;
 	}
 
-	div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+	div = gpmc_calc_divider(min_gpmc_clk_period);
 	gpmc_clk_ns = gpmc_ticks_to_ns(div);
 	if (gpmc_clk_ns < 15) /* >66Mhz */
 		onenand_flags |= ONENAND_FLAG_HF;
arch/arm/mach-omap2/gpmc.c +2 -2
index 68123d0..d005b3a 100644
@@ -313,7 +313,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 		return -1
 #endif
 
-int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
+int gpmc_calc_divider(unsigned int sync_clk)
 {
 	int div;
 	u32 l;
@@ -333,7 +333,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	int div;
 	u32 l;
 
-	div = gpmc_cs_calc_divider(cs, t->sync_clk);
+	div = gpmc_calc_divider(t->sync_clk);
 	if (div < 0)
 		return -1;
 
arch/arm/plat-omap/include/plat/gpmc.h +1 -1
index b7c9ea6..1cafbfd 100644
@@ -179,7 +179,7 @@ extern unsigned long gpmc_get_fclk_period(void);
 
 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_calc_divider(unsigned int sync_clk);
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
Signature · 1 line
1.7.1
#9 lore raw

PATCH v6 6/10 ARM: OMAP2+: gpmc: remove cs# in sync clk div calc

Quoted 60 lines · Afzal Mohammed

Divider value for a certain sync clk is determined solely based on gpmc fclk. CS# does not have any role here, thus remove presence of CS# in clock divider calculation API.

---
 arch/arm/mach-omap2/gpmc-onenand.c     |    3 +--
 arch/arm/mach-omap2/gpmc.c             |    4 ++--
 arch/arm/plat-omap/include/plat/gpmc.h |    2 +-
 3 files changed, 4 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +1 -2
index 8a301f3..e139e3f 100644
@@ -182,7 +182,6 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 	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;
 	int ticks_cez;
-	int cs = cfg->cs;
 
 	if (cfg->flags & ONENAND_SYNC_READ)
 		onenand_flags = ONENAND_FLAG_SYNCREAD;
@@ -229,7 +228,7 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 		break;
 	}
 
-	div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+	div = gpmc_calc_divider(min_gpmc_clk_period);
 	gpmc_clk_ns = gpmc_ticks_to_ns(div);
 	if (gpmc_clk_ns < 15) /* >66Mhz */
 		onenand_flags |= ONENAND_FLAG_HF;
arch/arm/mach-omap2/gpmc.c +2 -2
index 68123d0..d005b3a 100644
@@ -313,7 +313,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 		return -1
 #endif
 
-int gpmc_cs_calc_divider(int cs, unsigned int sync_clk)
+int gpmc_calc_divider(unsigned int sync_clk)
 {
 	int div;
 	u32 l;
@@ -333,7 +333,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	int div;
 	u32 l;
 
-	div = gpmc_cs_calc_divider(cs, t->sync_clk);
+	div = gpmc_calc_divider(t->sync_clk);
 	if (div < 0)
 		return -1;
 
arch/arm/plat-omap/include/plat/gpmc.h +0 -0
index b7c9ea6..1cafbfd 100644

arch/arm/plat-omap/include/plat/gpmc.h extern unsigned long gpmc_get_fclk_period(void); · line 185

Quoted 8 lines
arch/arm/plat-omap/include/plat/gpmc.h +1 -1
@@ -179,7 +179,7 @@ extern unsigned long gpmc_get_fclk_period(void);
 
 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_calc_divider(unsigned int sync_clk);
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);

Thanks!
Jon

#10 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

In reply to Afzal Mohammed

Presently there are three peripherals that gets it timing by runtime calculation. Those peripherals can work with frequency scaling that affects gpmc clock. But timing calculation for them are in different ways.

Here a generic runtime calculation method is proposed. Input to this function were selected so that they represent timing variables that are present in peripheral datasheets. Motive behind this was to achieve DT bindings for the inputs as is. Even though a few of the tusb6010 timings could not be made directly related to timings normally found on peripherals, expressions used were translated to those that could be justified.

There are possibilities of improving the calculations, like calculating timing for read & write operations in a more similar way. Expressions derived here were tested for async onenand on omap3evm (as vanilla Kernel does not have omap3evm onenand support, local patch was used). Other peripherals, tusb6010, smc91x calculations were validated by simulating on omap3evm.

Regarding "we_on" for onenand async, it was found that even for muxed address/data, it need not be greater than "adv_wr_off", but rather could be derived from write setup time for peripheral from start of access time, hence would more be in line with peripheral timings. With this method it was working fine. If it is required in some cases to have "we_on" same as "wr_data_mux_bus" (i.e. greater than "adv_wr_off"), another variable could be added to indicate it. But such a requirement is not expected though.

Whole of this exercise is being done to achieve driver and DT conversion. If timings could not be calculated in a peripheral agnostic way, either gpmc driver would have to be peripheral gnostic or a wrapper arrangement over gpmc driver would be required.

---
 arch/arm/mach-omap2/gpmc.c             |  302 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |   61 +++++++
 2 files changed, 363 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/gpmc.c +302 -0
index d005b3a..d8e5b08 100644
@@ -233,6 +233,18 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
 	return ticks * gpmc_get_fclk_period() / 1000;
 }
 
+unsigned int gpmc_ticks_to_ps(unsigned int ticks)
+{
+	return ticks * gpmc_get_fclk_period();
+}
+
+unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
+
+	return ticks * gpmc_get_fclk_period();
+}
+
 static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
 {
 	u32 l;
@@ -884,6 +896,296 @@ static void __init gpmc_mem_init(void)
 	}
 }
 
+static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
+{
+	u32 temp;
+	int div;
+
+	div = gpmc_calc_divider(sync_clk);
+	temp = gpmc_ps_to_ticks(time_ps);
+	temp = (temp + div - 1) / div;
+	return gpmc_ticks_to_ps(temp * div);
+}
+
+/* can the cycles be avoided ? */
+static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
+				struct gpmc_device_timings *dev_t)
+{
+	bool mux = dev_t->mux;
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	/* mux check required ? */
+	if (mux) {
+		/* t_avdp not to be required for sync, only added for tusb this
+		 * indirectly necessitates requirement of t_avdp_r & t_avdp_w
+		 * instead of having a single t_avdp
+		 */
+		temp = max_t(u32, temp,	gpmc_t->clk_activation * 1000 +
+							dev_t->t_avdh);
+		temp = max_t(u32,
+			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+	}
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* oe_on */
+	temp = dev_t->t_oeasu; /* remove this ? */
+	if (mux) {
+		temp = max_t(u32, temp,
+			gpmc_t->clk_activation * 1000 + dev_t->t_ach);
+		temp = max_t(u32, temp, (gpmc_t->adv_rd_off +
+				gpmc_ticks_to_ns(dev_t->cyc_aavdh_oe)) * 1000);
+	}
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* access */
+	/* any scope for improvement ?, by combining oe_on & clk_activation,
+	 * need to check whether access = clk_activation + round to sync clk ?
+	 */
+	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
+	temp += gpmc_t->clk_activation * 1000;
+	if (dev_t->cyc_oe)
+		temp = max_t(u32, temp, (gpmc_t->oe_on +
+				gpmc_ticks_to_ns(dev_t->cyc_oe)) * 1000);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ns(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
+	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
+							gpmc_t->access * 1000;
+	/* barter t_ce_rdyz with t_cez_r ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,
+				gpmc_t->cs_rd_off * 1000 + dev_t->t_ce_rdyz);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	return 0;
+}
+
+static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
+				struct gpmc_device_timings *dev_t)
+{
+	bool mux = dev_t->mux;
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux) {
+		temp = max_t(u32, temp,
+			gpmc_t->clk_activation * 1000 + dev_t->t_avdh);
+		temp = max_t(u32,
+			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+	}
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* wr_data_mux_bus */
+	temp = max_t(u32, dev_t->t_weasu,
+			gpmc_t->clk_activation * 1000 + dev_t->t_rdyo);
+	/* shouldn't mux be kept as a whole for wr_data_mux_bus ?,
+	 * and in that case remember to handle we_on properly
+	 */
+	if (mux) {
+		temp = max_t(u32, temp,
+			gpmc_t->adv_wr_off * 1000 + dev_t->t_aavdh);
+		temp = max_t(u32, temp, (gpmc_t->adv_wr_off +
+				gpmc_ticks_to_ns(dev_t->cyc_aavdh_we)) * 1000);
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu) / 1000;
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* wr_access */
+	/* gpmc_capability check reqd ? , even if not, will not harm */
+	gpmc_t->wr_access = gpmc_t->access;
+
+	/* we_off */
+	temp = gpmc_t->we_on * 1000 + dev_t->t_wpl;
+	temp = max_t(u32, temp,
+			(gpmc_t->wr_access + gpmc_ticks_to_ns(1)) * 1000);
+	temp = max_t(u32, temp,
+		(gpmc_t->we_on + gpmc_ticks_to_ns(dev_t->cyc_wpl)) * 1000);
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off * 1000 +
+							dev_t->t_wph) / 1000;
+
+	/* wr_cycle */
+	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
+	temp += gpmc_t->wr_access * 1000;
+	/* barter t_ce_rdyz with t_cez_w ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,
+				 gpmc_t->cs_wr_off * 1000 + dev_t->t_ce_rdyz);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	return 0;
+}
+
+static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
+				struct gpmc_device_timings *dev_t)
+{
+	bool mux = dev_t->mux;
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	if (mux)
+		temp = max_t(u32,
+			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* oe_on */
+	temp = dev_t->t_oeasu;
+	if (mux)
+		temp = max_t(u32, temp,
+			gpmc_t->adv_rd_off * 1000 + dev_t->t_aavdh);
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* access */
+	temp = max_t(u32, dev_t->t_iaa, /* remove t_iaa in async ? */
+				gpmc_t->oe_on * 1000 + dev_t->t_oe);
+	temp = max_t(u32, temp,
+				gpmc_t->cs_on * 1000 + dev_t->t_ce);
+	temp = max_t(u32, temp,
+				gpmc_t->adv_on * 1000 + dev_t->t_aa);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ns(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_rd_cycle,
+			gpmc_t->cs_rd_off * 1000 + dev_t->t_cez_r);
+	temp = max_t(u32, temp,
+			gpmc_t->oe_off * 1000 + dev_t->t_oez);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	return 0;
+}
+
+static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
+				struct gpmc_device_timings *dev_t)
+{
+	bool mux = dev_t->mux;
+	u32 temp;
+
+	/* adv_wr_off */
+	temp = dev_t->t_avdp_w;
+	if (mux)
+		temp = max_t(u32,
+			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* wr_data_mux_bus */
+	temp = dev_t->t_weasu;
+	if (mux) {
+		temp = max_t(u32, temp,
+			gpmc_t->adv_wr_off * 1000 + dev_t->t_aavdh);
+		temp = max_t(u32, temp, (gpmc_t->adv_wr_off +
+				gpmc_ticks_to_ns(dev_t->cyc_aavdh_we)) * 1000);
+	}
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* we_on */
+	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu) / 1000;
+	else
+		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
+
+	/* we_off */
+	temp = gpmc_t->we_on * 1000 + dev_t->t_wpl;
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks((gpmc_t->we_off * 1000 +
+				dev_t->t_wph)) / 1000;
+
+	/* wr_cycle */
+	temp = max_t(u32, dev_t->t_wr_cycle,
+				gpmc_t->cs_wr_off * 1000 + dev_t->t_cez_w);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	return 0;
+}
+
+static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
+			struct gpmc_device_timings *dev_t)
+{
+	u32 temp;
+
+	gpmc_t->sync_clk = gpmc_calc_divider(dev_t->clk) *
+						gpmc_get_fclk_period();
+
+	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
+					dev_t->t_bacc,
+					gpmc_t->sync_clk) / 1000;
+
+	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
+	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
+		return 0;
+
+	if (dev_t->ce_xdelay)
+		gpmc_t->bool_timings.cs_extra_delay = true;
+	if (dev_t->avd_xdelay)
+		gpmc_t->bool_timings.adv_extra_delay = true;
+	if (dev_t->oe_xdelay)
+		gpmc_t->bool_timings.oe_extra_delay = true;
+	if (dev_t->we_xdelay)
+		gpmc_t->bool_timings.we_extra_delay = true;
+
+	return 0;
+}
+
+static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
+			struct gpmc_device_timings *dev_t)
+{
+	u32 temp;
+
+	/* cs_on */
+	gpmc_t->cs_on = gpmc_round_ns_to_ticks(dev_t->t_ceasu / 1000);
+
+	/* adv_on */
+	temp = dev_t->t_avdasu;
+	if (dev_t->t_ce_avd)
+		temp = max_t(u32, temp,
+				gpmc_t->cs_on * 1000 + dev_t->t_ce_avd);
+	gpmc_t->adv_on = gpmc_round_ns_to_ticks(temp / 1000);
+
+	if (dev_t->sync_write || dev_t->sync_read)
+		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
+
+	return 0;
+}
+
+int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+			struct gpmc_device_timings *dev_t)
+{
+	memset(gpmc_t, 0, sizeof(*gpmc_t));
+
+	gpmc_calc_common_timings(gpmc_t, dev_t);
+
+	if (dev_t->sync_read)
+		gpmc_calc_sync_read_timings(gpmc_t, dev_t);
+	else
+		gpmc_calc_async_read_timings(gpmc_t, dev_t);
+
+	if (dev_t->sync_write)
+		gpmc_calc_sync_write_timings(gpmc_t, dev_t);
+	else
+		gpmc_calc_async_write_timings(gpmc_t, dev_t);
+
+	return 0;
+}
+
 static int __init gpmc_init(void)
 {
 	u32 l;
arch/arm/plat-omap/include/plat/gpmc.h +61 -0

67 lines not on this page · raw message

Signature · 1 line
1.7.1
#11 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

Hi Afzal,

Quoted 73 lines · Afzal Mohammed

Presently there are three peripherals that gets it timing by runtime calculation. Those peripherals can work with frequency scaling that affects gpmc clock. But timing calculation for them are in different ways.

Here a generic runtime calculation method is proposed. Input to this function were selected so that they represent timing variables that are present in peripheral datasheets. Motive behind this was to achieve DT bindings for the inputs as is. Even though a few of the tusb6010 timings could not be made directly related to timings normally found on peripherals, expressions used were translated to those that could be justified.

There are possibilities of improving the calculations, like calculating timing for read & write operations in a more similar way. Expressions derived here were tested for async onenand on omap3evm (as vanilla Kernel does not have omap3evm onenand support, local patch was used). Other peripherals, tusb6010, smc91x calculations were validated by simulating on omap3evm.

Regarding "we_on" for onenand async, it was found that even for muxed address/data, it need not be greater than "adv_wr_off", but rather could be derived from write setup time for peripheral from start of access time, hence would more be in line with peripheral timings. With this method it was working fine. If it is required in some cases to have "we_on" same as "wr_data_mux_bus" (i.e. greater than "adv_wr_off"), another variable could be added to indicate it. But such a requirement is not expected though.

Whole of this exercise is being done to achieve driver and DT conversion. If timings could not be calculated in a peripheral agnostic way, either gpmc driver would have to be peripheral gnostic or a wrapper arrangement over gpmc driver would be required.

---
 arch/arm/mach-omap2/gpmc.c             |  302 ++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/gpmc.h |   61 +++++++
 2 files changed, 363 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/gpmc.c +14 -0
index d005b3a..d8e5b08 100644
@@ -233,6 +233,18 @@ unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
 	return ticks * gpmc_get_fclk_period() / 1000;
 }
 
+unsigned int gpmc_ticks_to_ps(unsigned int ticks)
+{
+	return ticks * gpmc_get_fclk_period();
+}
+
+unsigned int gpmc_round_ps_to_ticks(unsigned int time_ps)
+{
+	unsigned long ticks = gpmc_ps_to_ticks(time_ps);
+
+	return ticks * gpmc_get_fclk_period();
+}
+
 static inline void gpmc_cs_modify_reg(int cs, int reg, u32 mask, bool value)
 {
 	u32 l;
@@ -884,6 +896,296 @@ static void __init gpmc_mem_init(void)
 	}
 }
 
+static u32 gpmc_round_ps_to_sync_clk(u32 time_ps, u32 sync_clk)
+{

arch/arm/mach-omap2/gpmc.c static void __init gpmc_mem_init(void) · line 910

Quoted 10 lines
arch/arm/mach-omap2/gpmc.c +10 -0
+	u32 temp;
+	int div;
+
+	div = gpmc_calc_divider(sync_clk);
+	temp = gpmc_ps_to_ticks(time_ps);
+	temp = (temp + div - 1) / div;
+	return gpmc_ticks_to_ps(temp * div);
+}
+
+/* can the cycles be avoided ? */

What is the above comment referring too?

Quoted 57 lines
arch/arm/mach-omap2/gpmc.c +57 -0
+static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
+				struct gpmc_device_timings *dev_t)
+{
+	bool mux = dev_t->mux;
+	u32 temp;
+
+	/* adv_rd_off */
+	temp = dev_t->t_avdp_r;
+	/* mux check required ? */
+	if (mux) {
+		/* t_avdp not to be required for sync, only added for tusb this
+		 * indirectly necessitates requirement of t_avdp_r & t_avdp_w
+		 * instead of having a single t_avdp
+		 */
+		temp = max_t(u32, temp,	gpmc_t->clk_activation * 1000 +
+							dev_t->t_avdh);
+		temp = max_t(u32,
+			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+	}
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* oe_on */
+	temp = dev_t->t_oeasu; /* remove this ? */
+	if (mux) {
+		temp = max_t(u32, temp,
+			gpmc_t->clk_activation * 1000 + dev_t->t_ach);
+		temp = max_t(u32, temp, (gpmc_t->adv_rd_off +
+				gpmc_ticks_to_ns(dev_t->cyc_aavdh_oe)) * 1000);
+	}
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	/* access */
+	/* any scope for improvement ?, by combining oe_on & clk_activation,
+	 * need to check whether access = clk_activation + round to sync clk ?
+	 */
+	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
+	temp += gpmc_t->clk_activation * 1000;
+	if (dev_t->cyc_oe)
+		temp = max_t(u32, temp, (gpmc_t->oe_on +
+				gpmc_ticks_to_ns(dev_t->cyc_oe)) * 1000);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ns(1);
+	gpmc_t->cs_rd_off = gpmc_t->oe_off;
+
+	/* rd_cycle */
+	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
+	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
+							gpmc_t->access * 1000;
+	/* barter t_ce_rdyz with t_cez_r ? */
+	if (dev_t->t_ce_rdyz)
+		temp = max_t(u32, temp,
+				gpmc_t->cs_rd_off * 1000 + dev_t->t_ce_rdyz);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+
+	return 0;
+}

[...]

arch/arm/plat-omap/include/plat/gpmc.h struct gpmc_timings { · line 155

Quoted 9 lines
arch/arm/plat-omap/include/plat/gpmc.h +1 -0
index 1cafbfd..e59a932 100644
@@ -152,6 +152,67 @@ struct gpmc_timings {
 	struct gpmc_bool_timings bool_timings;
 };
 
+/* Device timings in picoseconds */

Why pico seconds and not nanoseconds? I understand you may need to temporarily convert to pico-secs for rounding, but when providing timing it seems nano-secs is more suitable.

Quoted 46 lines
arch/arm/plat-omap/include/plat/gpmc.h +46 -0
+struct gpmc_device_timings {
+	u32     t_ceasu;	/* address setup to CS valid */
+	u32     t_avdasu;	/* address setup to ADV valid */
+	/* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+	 * of tusb using these timings even for sync whilst
+	 * ideally for adv_rd/(wr)_off it should have considered
+	 * t_avdh instead. This indirectly necessitates r/w
+	 * variations of t_avdp as it is possible to have one
+	 * sync & other async
+	 */
+	u32	t_avdp_r;	/* ADV low time (what about t_cer ?) */
+	u32	t_avdp_w;
+	u32	t_aavdh;	/* address hold time */
+	u32     t_oeasu;	/* address setup to OE valid */
+	u32     t_aa;		/* access time from ADV assertion */
+	u32     t_iaa;		/* initial access time */
+	u32     t_oe;		/* access time from OE assertion */
+	u32     t_ce;		/* access time from CS asertion */
+	u32     t_rd_cycle;	/* read cycle time */
+	u32     t_cez_r;	/* read CS deassertion to high Z */
+	u32     t_cez_w;	/* write CS deassertion to high Z */
+	u32     t_oez;		/* OE deassertion to high Z */
+	u32     t_weasu;	/* address setup to WE valid */
+	u32     t_wpl;		/* write assertion time */
+	u32     t_wph;		/* write deassertion time */
+	u32     t_wr_cycle;	/* write cycle time */
+
+	u32	clk;
+	u32	t_bacc;		/* burst access valid clock to output delay */
+	u32	t_ces;		/* CS setup time to clk */
+	u32	t_avds;		/* ADV setup time to clk */
+	u32	t_avdh;		/* ADV hold time from clk */
+	u32     t_ach;		/* address hold time from clk */
+	u32	t_rdyo;		/* clk to ready valid */
+
+	u32	t_ce_rdyz;	/* XXX: description ?, or use t_cez instead */
+	u32	t_ce_avd;	/* CS on to ADV on delay */
+
+	/* XXX: check the possibility of combining
+	 * cyc_aavhd_oe & cyc_aavdh_we
+	 */
+	u8	cyc_aavdh_oe;
+	u8	cyc_aavdh_we;
+	u8	cyc_oe;
+	u8	cyc_wpl;
+	u32     cyc_iaa;

arch/arm/plat-omap/include/plat/gpmc.h struct gpmc_timings { · line 211

Quoted 10 lines
arch/arm/plat-omap/include/plat/gpmc.h +10 -0
+
+	bool	mux;		/* address & data muxed */
+	bool	sync_write;	/* synchronous write */
+	bool	sync_read;	/* synchronous read */
+
+	bool	ce_xdelay;
+	bool	avd_xdelay;
+	bool	oe_xdelay;
+	bool	we_xdelay;
+};

I am a little concerned about the above timings structure. For example, if I am adding support for a new devices it is not clear ...

1. Which are required
2. Which are applicable for async, sync, address-data multiplexed etc.
3. Exactly how these relate to the fields in the gpmc registers.

I understand that this is based upon how timings for onenand and tusb are being calculated today, but I am not sure that this is the way to go for all devices. Personally, I would like to see us get away from how those devices are calculating timings for any new device.

In general, I am concerned that we are abstracting the timings further from the actual register fields. For example, the timings parameter "t_ceasu" is described "address setup to CS valid" which is not incorrect but this value is really just programming the CSONTIME field and so why not call this cs_on?

So although this may consolidate how the timings are calculated today, I am concerned it will be confusing to add timings for a new device. At least if I am calculating timings, I am taking the timing information for the device and translating that to the how I need to program the gpmc register fields.

Cheers
Jon

maintainer
#12 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

Quoted 6 lines · Jon Hunter

So although this may consolidate how the timings are calculated today, I am concerned it will be confusing to add timings for a new device. At least if I am calculating timings, I am taking the timing information for the device and translating that to the how I need to program the gpmc register fields.

Yes agreed. Also as some values make sense only in cycles, converting them back and forth to time is wrong. So at least some values should have an option to specify them in cycles directly, and then ignore any time based values.

Regards,

Tony

#13 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

Hi Tony,

Quoted 4 lines · Tony Lindgren

Yes agreed. Also as some values make sense only in cycles, converting them back and forth to time is wrong. So at least some values should have an option to specify them in cycles directly, and then ignore any time based values.

Which values in struct gpmc_device_timings are you referring to ?

Values that need to have an option to specify in cycles has been provided such an option, while not updating time based field value, you can achieve what you mentioned above. But if you want that to be handled in in generic routine, I will do so.

Regards
Afzal

#14 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

In reply to Jon Hunter

Hi Jon,

Quoted 5 lines · Jon
Quoted 1 line · Afzal Mohammed

+/* can the cycles be avoided ? */

What is the above comment referring too?

This was added in the initial stages and refers to the usage of cycles in struct gpmc_device_timings. I wanted to avoid usage of cycles, but it seems it is required logically as well. This was mentioned as a note for future to find out whether at any future point of time this can be removed.

Quoted 5 lines
Quoted 1 line

+/* Device timings in picoseconds */

Why pico seconds and not nanoseconds? I understand you may need to temporarily convert to pico-secs for rounding, but when providing timing it seems nano-secs is more suitable.

For more accuracy, if you see some of the tusb6010 calculation are in picoseconds, this can be true for any device although only tusb does so. If we hold on to picoseconds till the last moment, value would be more accurate. For eg. 300 ps has to be used in the case of tusb, and with ns, it can't be accounted for

Quoted 6 lines

I am a little concerned about the above timings structure. For example, if I am adding support for a new devices it is not clear ...

1. Which are required
2. Which are applicable for async, sync, address-data multiplexed etc.
3. Exactly how these relate to the fields in the gpmc registers.

Please see at the end

Quoted 5 lines

I understand that this is based upon how timings for onenand and tusb are being calculated today, but I am not sure that this is the way to go for all devices. Personally, I would like to see us get away from how those devices are calculating timings for any new device.

You cannot do away with many of the those, as logically they are right. Eg. read data should be available at access time, assuming a zero data hold time, we can very well derive an expression as,

read de-assertion time (oe_off) = access time plus 1 gpmc clock,

and this is what the existing calculations do, and also the generic routine. There could be other constraints, but this certainly should be one (I do realize that oe_off could be optimized to be less than access time, by relying on read hold time, then again effect of it would be in similar way for different peripherals, but let's forget about optimization in the beginning)

Quoted 5 lines

In general, I am concerned that we are abstracting the timings further from the actual register fields. For example, the timings parameter "t_ceasu" is described "address setup to CS valid" which is not incorrect but this value is really just programming the CSONTIME field and so why not call this cs_on?

Timing fields of struct gpmc_device_timings are selected such that they should be bindable by DT. At least one of the peripheral datasheet has these fields. If user knows timings in terms of gpmc values, he can directly use struct gpmc_timings, but then all the values should be updated in struct gpmc_timings. User should not update some of the values in terms of peripheral timings, others in terms of gpmc timings, that would make things complex and does not seem the right way to me.

cs_on and other gpmc aware timings could be binded by DT, not as peripheral timing, but as gpmc timing.

Bindings for peripheral DT timings should be something that can be obtained from peripheral datasheet, here accidentally it is same as gpmc timings, but not most timings are this way. Also there could be other constraints that can come for cs_on, even though I have not come across any till now.

Quoted 6 lines

So although this may consolidate how the timings are calculated today, I am concerned it will be confusing to add timings for a new device. At least if I am calculating timings, I am taking the timing information for the device and translating that to the how I need to program the gpmc register fields.

If I am not wrong, GPMC IP has been present for around a decade, and so far I have not come across any generic time calculation method that can be applied to all peripherals. Getting to work same peripheral for a different gpmc frequency is another problem.

Here we are trying to generalize based on the understanding of gpmc & peripheral timings, as well as by a kind of reverse engineering without most of the hardware or datasheet. Think of this as an attempt to create one, let it evolve and become a robust one. If a new user want to add a peripheral, let him add support, input timings are selected such that it is found in peripheral datasheet, if that does not work, let him try to add any new timing field or alter existing expression as he deems to be proper and verify that it does not break others. And I can help provided I am not heavily loaded with other works.

And at least for initial users, they are expected to have some grasp on how to calculate timings, such a user will not be much worried about your 3 concerns above, anyway as of now they need to have a good grasp on it.

Meanwhile I will try to document more.

Regards
Afzal

#15 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

Hi Afzal,

Quoted 1 line · Afzal

On Thu, Aug 23, 2012 at 08:28:44, Hunter, Jon wrote:

[snip]

Quoted 9 lines
Quoted 4 lines

I understand that this is based upon how timings for onenand and tusb are being calculated today, but I am not sure that this is the way to go for all devices. Personally, I would like to see us get away from how those devices are calculating timings for any new device.

You cannot do away with many of the those, as logically they are right. Eg. read data should be available at access time, assuming a zero data hold time, we can very well derive an expression as,

I am not saying that we do away with them for current devices, just maintain them as is.

Quoted 16 lines

read de-assertion time (oe_off) = access time plus 1 gpmc clock,

and this is what the existing calculations do, and also the generic routine. There could be other constraints, but this certainly should be one (I do realize that oe_off could be optimized to be less than access time, by relying on read hold time, then again effect of it would be in similar way for different peripherals, but let's forget about optimization in the beginning)

Quoted 5 lines

In general, I am concerned that we are abstracting the timings further from the actual register fields. For example, the timings parameter "t_ceasu" is described "address setup to CS valid" which is not incorrect but this value is really just programming the CSONTIME field and so why not call this cs_on?

Quoted 3 lines

Timing fields of struct gpmc_device_timings are selected such that they should be bindable by DT. At least one of the peripheral datasheet has these fields.

Right, but these are not applicable to every device and so I worry this could be confusing. However, more documentation may help clear this up.

Quoted 24 lines

If user knows timings in terms of
gpmc values, he can directly use struct gpmc_timings, but then all the values should be updated in struct gpmc_timings. User should not update some of the values in terms of peripheral timings, others in terms of gpmc timings, that would make things complex and does not seem the right way to me.

cs_on and other gpmc aware timings could be binded by DT, not as peripheral timing, but as gpmc timing.

Bindings for peripheral DT timings should be something that can be obtained from peripheral datasheet, here accidentally it is same as gpmc timings, but not most timings are this way. Also there could be other constraints that can come for cs_on, even though I have not come across any till now.

Quoted 6 lines

So although this may consolidate how the timings are calculated today, I am concerned it will be confusing to add timings for a new device. At least if I am calculating timings, I am taking the timing information for the device and translating that to the how I need to program the gpmc register fields.

Quoted 3 lines

If I am not wrong, GPMC IP has been present for around a decade, and so far I have not come across any generic time calculation method that can be applied to all peripherals.

Yes not an easy problem to solve :-(

Quoted 14 lines

Getting to work same peripheral for a different gpmc frequency is another problem.

Here we are trying to generalize based on the understanding of gpmc & peripheral timings, as well as by a kind of reverse engineering without most of the hardware or datasheet. Think of this as an attempt to create one, let it evolve and become a robust one. If a new user want to add a peripheral, let him add support, input timings are selected such that it is found in peripheral datasheet, if that does not work, let him try to add any new timing field or alter existing expression as he deems to be proper and verify that it does not break others. And I can help provided I am not heavily loaded with other works.

So long as it is maintainable ;-)

Quoted 4 lines

And at least for initial users, they are expected to have some grasp on how to calculate timings, such a user will not be much worried about your 3 concerns above, anyway as of now they need to have a good grasp on it.

I would consider myself to be an initial user and I am concerned, doesn't that count?

An example, would be the following where you have 4 timing parameters for access time. You need to dig through the code to understand how these are being used.

+	u32     t_aa;		/* access time from ADV assertion */
+	u32     t_iaa;		/* initial access time */
+	u32     t_oe;		/* access time from OE assertion */
+	u32     t_ce;		/* access time from CS asertion */
Quoted 1 line

Meanwhile I will try to document more.

Yes more documentation is definitely needed.

Cheers
Jon

#16 lore raw

PATCH v6 7/10 ARM: OMAP2+: gpmc: generic timing calculation

Hi Jon,

Quoted 9 lines · Jon
Quoted 4 lines · Afzal

And at least for initial users, they are expected to have some grasp on how to calculate timings, such a user will not be much worried about your 3 concerns above, anyway as of now they need to have a good grasp on it.

I would consider myself to be an initial user and I am concerned, doesn't that count?

Yes sir, what I meant was new users who want to have runtime calculation using the generic timing routine. For the peripherals already making use of custom timing routine, I am into that role too, hence the patches 8-10.

And if you have any board that makes use of existing custom timing calculation routines (OneNAND, tusb6010 or smc91x), can you please give this series a try.

Regards
Afzal

#17 lore raw

PATCH v6 8/10 ARM: OMAP2+: onenand: generic timing calculation

In reply to Afzal Mohammed

Generic gpmc timing calculation helper is available now, use it instead of custom timing calculation.

---
 arch/arm/mach-omap2/gpmc-onenand.c |  124 ++++++++++++------------------------
 1 files changed, 41 insertions(+), 83 deletions(-)
arch/arm/mach-omap2/gpmc-onenand.c +41 -83
index e139e3f..700f9a6 100644
@@ -49,6 +49,7 @@ static struct platform_device gpmc_onenand_device = {
 
 static struct gpmc_timings omap2_onenand_calc_async_timings(void)
 {
+	struct gpmc_device_timings dev_t;
 	struct gpmc_timings t;
 
 	const int t_cer = 15;
@@ -58,35 +59,22 @@ static struct gpmc_timings omap2_onenand_calc_async_timings(void)
 	const int t_aa = 76;
 	const int t_oe = 20;
 	const int t_cez = 20; /* max of t_cez, t_oez */
-	const int t_ds = 30;
 	const int t_wpl = 40;
 	const int t_wph = 30;
 
-	memset(&t, 0, sizeof(t));
-	t.sync_clk = 0;
-	t.cs_on = 0;
-	t.adv_on = 0;
-
-	/* Read */
-	t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
-	t.oe_on  = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
-	t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
-	t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
-	t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
-	t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
-	t.cs_rd_off = t.oe_off;
-	t.rd_cycle  = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
-
-	/* Write */
-	t.adv_wr_off = t.adv_rd_off;
-	t.we_on  = t.oe_on;
-	if (cpu_is_omap34xx()) {
-		t.wr_data_mux_bus = t.we_on;
-		t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
-	}
-	t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
-	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);
+	memset(&dev_t, 0, sizeof(dev_t));
+
+	dev_t.mux = true;
+	dev_t.t_avdp_r = dev_t.t_avdp_w = max_t(int, t_avdp, t_cer) * 1000;
+	dev_t.t_aavdh = t_aavdh * 1000;
+	dev_t.t_aa = t_aa * 1000;
+	dev_t.t_ce = t_ce * 1000;
+	dev_t.t_oe = t_oe * 1000;
+	dev_t.t_cez_r = dev_t.t_cez_w = t_cez * 1000;
+	dev_t.t_wpl = t_wpl * 1000;
+	dev_t.t_wph = t_wph * 1000;
+
+	gpmc_calc_timings(&t, &dev_t);
 
 	return t;
 }
@@ -172,16 +160,15 @@ static struct gpmc_timings
 omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 						int freq)
 {
+	struct gpmc_device_timings dev_t;
 	struct gpmc_timings 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_ds   = 30;
 	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;
-	int ticks_cez;
+	int div, gpmc_clk_ns;
 
 	if (cfg->flags & ONENAND_SYNC_READ)
 		onenand_flags = ONENAND_FLAG_SYNCREAD;
@@ -248,62 +235,33 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
 		latency = 4;
 
 	/* Set synchronous read timings */
-	memset(&t, 0, sizeof(t));
+	memset(&dev_t, 0, sizeof(dev_t));
 
-	if (div == 1) {
-		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;
-	}
-
-	t.sync_clk = min_gpmc_clk_period;
-	t.cs_on = 0;
-	t.adv_on = 0;
-	fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
-	fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
-	t.page_burst_access = gpmc_clk_ns;
-
-	/* Read */
-	t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
-	t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
-	/* Force at least 1 clk between AVD High to OE Low */
-	if (t.oe_on <= t.adv_rd_off)
-		t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(1);
-	t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
-	t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
-	t.cs_rd_off = t.oe_off;
-	ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
-	t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
-		     ticks_cez);
-
-	t.clk_activation = fclk_offset_ns;
-
-	/* 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;
-		t.cs_wr_off = t.cs_rd_off;
-		t.wr_cycle  = t.rd_cycle;
-		if (cpu_is_omap34xx()) {
-			t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
-					gpmc_ps_to_ticks(min_gpmc_clk_period +
-					t_rdyo * 1000));
-			t.wr_access = t.access;
-		}
-	} else {
-		t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
-							t_avdp, t_cer));
-		t.we_on  = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
-		t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
-		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);
-		if (cpu_is_omap34xx()) {
-			t.wr_data_mux_bus = t.we_on;
-			t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
-		}
+	dev_t.mux = true;
+	dev_t.sync_read = true;
+	if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
+		dev_t.sync_write = true;
+	else {
+		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 = dev_t.t_bacc = min_gpmc_clk_period;
+	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 = dev_t.t_cez_w = t_cez * 1000;
+	dev_t.cyc_aavdh_oe = 1;
+	dev_t.t_rdyo = t_rdyo * 1000 + min_gpmc_clk_period;
+
+	gpmc_calc_timings(&t, &dev_t);
 
 	return t;
 }
Signature · 1 line
1.7.1
#18 lore raw

PATCH v6 9/10 ARM: OMAP2+: smc91x: generic timing calculation

In reply to Afzal Mohammed

Generic gpmc timing calculation helper is available now, use it instead of custom timing calculation.

---
 arch/arm/mach-omap2/gpmc-smc91x.c |   43 ++++++++++++++----------------------
 1 files changed, 17 insertions(+), 26 deletions(-)
arch/arm/mach-omap2/gpmc-smc91x.c +17 -26
index ba10c24..43900f9 100644
@@ -57,6 +57,7 @@ static struct platform_device gpmc_smc91x_device = {
 static int smc91c96_gpmc_retime(void)
 {
 	struct gpmc_timings t;
+	struct gpmc_device_timings dev_t;
 	const int t3 = 10;	/* Figure 12.2 read and 12.4 write */
 	const int t4_r = 20;	/* Figure 12.2 read */
 	const int t4_w = 5;	/* Figure 12.4 write */
@@ -67,32 +68,6 @@ static int smc91c96_gpmc_retime(void)
 	const int t20 = 185;	/* Figure 12.2 read and 12.4 write */
 	u32 l;
 
-	memset(&t, 0, sizeof(t));
-
-	/* Read timings */
-	t.cs_on = 0;
-	t.adv_on = t.cs_on;
-	t.oe_on = t.adv_on + t3;
-	t.access = t.oe_on + t5;
-	t.oe_off = t.access;
-	t.adv_rd_off = t.oe_off + max(t4_r, t6);
-	t.cs_rd_off = t.oe_off;
-	t.rd_cycle = t20 - t.oe_on;
-
-	/* Write timings */
-	t.we_on = t.adv_on + t3;
-
-	if (cpu_is_omap34xx() && (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)) {
-		t.wr_data_mux_bus = t.we_on;
-		t.we_off = t.wr_data_mux_bus + t7;
-	} else
-		t.we_off = t.we_on + t7;
-	if (cpu_is_omap34xx())
-		t.wr_access = t.we_off;
-	t.adv_wr_off = t.we_off + max(t4_w, t8);
-	t.cs_wr_off = t.we_off + t4_w;
-	t.wr_cycle = t20 - t.we_on;
-
 	l = GPMC_CONFIG1_DEVICESIZE_16;
 	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
 		l |= GPMC_CONFIG1_MUXADDDATA;
@@ -114,6 +89,22 @@ static int smc91c96_gpmc_retime(void)
 	if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
 		return 0;
 
+	memset(&dev_t, 0, sizeof(dev_t));
+
+	dev_t.t_oeasu = t3 * 1000;
+	dev_t.t_oe = t5 * 1000;
+	dev_t.t_cez_r = t4_r * 1000;
+	dev_t.t_oez = t6 * 1000;
+	dev_t.t_rd_cycle = (t20 - t3) * 1000;
+
+	dev_t.t_weasu = t3 * 1000;
+	dev_t.t_wpl = t7 * 1000;
+	dev_t.t_wph = t8 * 1000;
+	dev_t.t_cez_w = t4_w * 1000;
+	dev_t.t_wr_cycle = (t20 - t3) * 1000;
+
+	gpmc_calc_timings(&t, &dev_t);
+
 	return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
 }
 
Signature · 1 line
1.7.1
#19 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

In reply to Afzal Mohammed

Generic gpmc timing calculation helper is available now, use it instead of custom timing calculation.

---
 arch/arm/mach-omap2/usb-tusb6010.c |  181 +++++++++---------------------------
 1 files changed, 43 insertions(+), 138 deletions(-)
arch/arm/mach-omap2/usb-tusb6010.c +43 -138
index 7a85ebe..cce1f06 100644
@@ -26,182 +26,87 @@ static u8		async_cs, sync_cs;
 static unsigned		refclk_psec;
 
 
-/* t2_ps, when quantized to fclk units, must happen no earlier than
- * the clock after after t1_NS.
- *
- * Return a possibly updated value of t2_ps, converted to nsec.
- */
-static unsigned
-next_clk(unsigned t1_NS, unsigned t2_ps, unsigned fclk_ps)
-{
-	unsigned	t1_ps = t1_NS * 1000;
-	unsigned	t1_f, t2_f;
-
-	if ((t1_ps + fclk_ps) < t2_ps)
-		return t2_ps / 1000;
-
-	t1_f = (t1_ps + fclk_ps - 1) / fclk_ps;
-	t2_f = (t2_ps + fclk_ps - 1) / fclk_ps;
-
-	if (t1_f >= t2_f)
-		t2_f = t1_f + 1;
-
-	return (t2_f * fclk_ps) / 1000;
-}
-
 /* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
 
-static int tusb_set_async_mode(unsigned sysclk_ps, unsigned fclk_ps)
+static int tusb_set_async_mode(unsigned sysclk_ps)
 {
+	struct gpmc_device_timings dev_t;
 	struct gpmc_timings	t;
 	unsigned		t_acsnh_advnh = sysclk_ps + 3000;
-	unsigned		tmp;
-
-	memset(&t, 0, sizeof(t));
-
-	/* CS_ON = t_acsnh_acsnl */
-	t.cs_on = 8;
-	/* ADV_ON = t_acsnh_advnh - t_advn */
-	t.adv_on = next_clk(t.cs_on, t_acsnh_advnh - 7000, fclk_ps);
-
-	/*
-	 * READ ... from omap2420 TRM fig 12-13
-	 */
-
-	/* ADV_RD_OFF = t_acsnh_advnh */
-	t.adv_rd_off = next_clk(t.adv_on, t_acsnh_advnh, fclk_ps);
-
-	/* OE_ON = t_acsnh_advnh + t_advn_oen (then wait for nRDY) */
-	t.oe_on = next_clk(t.adv_on, t_acsnh_advnh + 1000, fclk_ps);
-
-	/* ACCESS = counters continue only after nRDY */
-	tmp = t.oe_on * 1000 + 300;
-	t.access = next_clk(t.oe_on, tmp, fclk_ps);
-
-	/* OE_OFF = after data gets sampled */
-	tmp = t.access * 1000;
-	t.oe_off = next_clk(t.access, tmp, fclk_ps);
-
-	t.cs_rd_off = t.oe_off;
-
-	tmp = t.cs_rd_off * 1000 + 7000 /* t_acsn_rdy_z */;
-	t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
-
-	/*
-	 * WRITE ... from omap2420 TRM fig 12-15
-	 */
 
-	/* ADV_WR_OFF = t_acsnh_advnh */
-	t.adv_wr_off = t.adv_rd_off;
+	memset(&dev_t, 0, sizeof(dev_t));
 
-	/* WE_ON = t_acsnh_advnh + t_advn_wen (then wait for nRDY) */
-	t.we_on = next_clk(t.adv_wr_off, t_acsnh_advnh + 1000, fclk_ps);
+	dev_t.mux = true;
 
-	/* WE_OFF = after data gets sampled */
-	tmp = t.we_on * 1000 + 300;
-	t.we_off = next_clk(t.we_on, tmp, fclk_ps);
+	dev_t.t_ceasu = 8 * 1000;
+	dev_t.t_avdasu = t_acsnh_advnh - 7000;
+	dev_t.t_ce_avd = 1000;
+	dev_t.t_avdp_r = t_acsnh_advnh;
+	dev_t.t_oeasu = t_acsnh_advnh + 1000;
+	dev_t.t_oe = 300;
+	dev_t.t_cez_r = dev_t.t_cez_w = 7000;
+	dev_t.t_avdp_w = t_acsnh_advnh;
+	dev_t.t_weasu = t_acsnh_advnh + 1000;
+	dev_t.t_wpl = 300;
+	dev_t.cyc_aavdh_we = 1;
 
-	t.cs_wr_off = t.we_off;
-
-	tmp = t.cs_wr_off * 1000 + 7000 /* t_acsn_rdy_z */;
-	t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
+	gpmc_calc_timings(&t, &dev_t);
 
 	return gpmc_cs_set_timings(async_cs, &t);
 }
 
-static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
+static int tusb_set_sync_mode(unsigned sysclk_ps)
 {
+	struct gpmc_device_timings dev_t;
 	struct gpmc_timings	t;
 	unsigned		t_scsnh_advnh = sysclk_ps + 3000;
-	unsigned		tmp;
-
-	memset(&t, 0, sizeof(t));
-	t.cs_on = 8;
-
-	/* ADV_ON = t_acsnh_advnh - t_advn */
-	t.adv_on = next_clk(t.cs_on, t_scsnh_advnh - 7000, fclk_ps);
-
-	/* GPMC_CLK rate = fclk rate / div */
-	t.sync_clk = 11100 /* 11.1 nsec */;
-	tmp = (t.sync_clk + fclk_ps - 1) / fclk_ps;
-	if (tmp > 4)
-		return -ERANGE;
-	if (tmp == 0)
-		tmp = 1;
-	t.page_burst_access = (fclk_ps * tmp) / 1000;
-
-	/*
-	 * READ ... based on omap2420 TRM fig 12-19, 12-20
-	 */
-
-	/* ADV_RD_OFF = t_scsnh_advnh */
-	t.adv_rd_off = next_clk(t.adv_on, t_scsnh_advnh, fclk_ps);
-
-	/* OE_ON = t_scsnh_advnh + t_advn_oen * fclk_ps (then wait for nRDY) */
-	tmp = (t.adv_rd_off * 1000) + (3 * fclk_ps);
-	t.oe_on = next_clk(t.adv_on, tmp, fclk_ps);
-
-	/* ACCESS = number of clock cycles after t_adv_eon */
-	tmp = (t.oe_on * 1000) + (5 * fclk_ps);
-	t.access = next_clk(t.oe_on, tmp, fclk_ps);
-
-	/* OE_OFF = after data gets sampled */
-	tmp = (t.access * 1000) + (1 * fclk_ps);
-	t.oe_off = next_clk(t.access, tmp, fclk_ps);
 
-	t.cs_rd_off = t.oe_off;
-
-	tmp = t.cs_rd_off * 1000 + 7000 /* t_scsn_rdy_z */;
-	t.rd_cycle = next_clk(t.cs_rd_off, tmp, fclk_ps);
-
-	/*
-	 * WRITE ... based on omap2420 TRM fig 12-21
-	 */
-
-	/* ADV_WR_OFF = t_scsnh_advnh */
-	t.adv_wr_off = t.adv_rd_off;
-
-	/* WE_ON = t_scsnh_advnh + t_advn_wen * fclk_ps (then wait for nRDY) */
-	tmp = (t.adv_wr_off * 1000) + (3 * fclk_ps);
-	t.we_on = next_clk(t.adv_wr_off, tmp, fclk_ps);
-
-	/* WE_OFF = number of clock cycles after t_adv_wen */
-	tmp = (t.we_on * 1000) + (6 * fclk_ps);
-	t.we_off = next_clk(t.we_on, tmp, fclk_ps);
-
-	t.cs_wr_off = t.we_off;
-
-	tmp = t.cs_wr_off * 1000 + 7000 /* t_scsn_rdy_z */;
-	t.wr_cycle = next_clk(t.cs_wr_off, tmp, fclk_ps);
-
-	t.clk_activation = gpmc_ticks_to_ns(1);
+	memset(&dev_t, 0, sizeof(dev_t));
+
+	dev_t.mux = true;
+	dev_t.sync_read = true;
+	dev_t.sync_write = true;
+
+	dev_t.clk = 11100;
+	dev_t.t_bacc = 1000;
+	dev_t.t_ces = 1000;
+	dev_t.t_ceasu = 8 * 1000;
+	dev_t.t_avdasu = t_scsnh_advnh - 7000;
+	dev_t.t_ce_avd = 1000;
+	dev_t.t_avdp_r = t_scsnh_advnh;
+	dev_t.cyc_aavdh_oe = 3;
+	dev_t.cyc_oe = 5;
+	dev_t.t_ce_rdyz = 7000;
+	dev_t.t_avdp_w = t_scsnh_advnh;
+	dev_t.cyc_aavdh_we = 3;
+	dev_t.cyc_wpl = 6;
+	dev_t.t_ce_rdyz = 7000;
+
+	gpmc_calc_timings(&t, &dev_t);
 
 	return gpmc_cs_set_timings(sync_cs, &t);
 }
 
-extern unsigned long gpmc_get_fclk_period(void);
-
 /* tusb driver calls this when it changes the chip's clocking */
 int tusb6010_platform_retime(unsigned is_refclk)
 {
 	static const char	error[] =
 		KERN_ERR "tusb6010 %s retime error %d\n";
 
-	unsigned	fclk_ps = gpmc_get_fclk_period();
 	unsigned	sysclk_ps;
 	int		status;
 
-	if (!refclk_psec || fclk_ps == 0)
+	if (!refclk_psec)
 		return -ENODEV;
 
 	sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
 
-	status = tusb_set_async_mode(sysclk_ps, fclk_ps);
+	status = tusb_set_async_mode(sysclk_ps);
 	if (status < 0) {
 		printk(error, "async", status);
 		goto done;
 	}
-	status = tusb_set_sync_mode(sysclk_ps, fclk_ps);
+	status = tusb_set_sync_mode(sysclk_ps);
 	if (status < 0)
 		printk(error, "sync", status);
 done:
Signature · 1 line
1.7.1
maintainer
#20 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Quoted 2 lines · Afzal Mohammed

Generic gpmc timing calculation helper is available now, use it instead of custom timing calculation.

This hangs n800 during the boot.

Tony

#21 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Hi Tony,

Quoted 1 line · Tony Lindgren

This hangs n800 during the boot.

Shall I read the above as n800 boot without patch 10/10, but with the other patches in this series ?

As per the board file, n800 has tusb6010 as well as OneNAND in sync read & async write mode, was OneNAND working without 10/10.

Do you have any idea, which timing could have gone wrong, can you please sent me DEBUG enabled gpmc log with and without 10/10.

Regards
Afzal

#22 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Hi Tony,

Quoted 7 lines · Afzal
Quoted 1 line · Tony Lindgren

This hangs n800 during the boot.

Shall I read the above as n800 boot without patch 10/10, but with the other patches in this series ?

Quoted 7 lines

As per the board file, n800 has tusb6010 as well as OneNAND in sync read & async write mode, was OneNAND working without 10/10.

Do you have any idea, which timing could have gone wrong, can you please sent me DEBUG enabled gpmc log with and without 10/10.

Can you please sent me GPMC DEBUG enabled logs with and without this series.

Regards
Afzal

#23 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Hi Tony,

Quoted 4 lines · Afzal
Quoted 3 lines · Afzal
Quoted 1 line · Tony Lindgren

This hangs n800 during the boot.

Paul reported that n800 stopped booting on OMAP baseline [1] due to an mmc issue and has posted a solution [2].

Are you facing the same issue ?, if so, then it is not due to this series.

I tried to get an n800, but has been unsuccessful.

Regards
Afzal

[1] http://marc.info/?l=linux-omap&m=134685988517580&w=2
[2] http://www.spinics.net/lists/arm-kernel/msg190879.html

Quoted 14 lines
Quoted 11 lines

Shall I read the above as n800 boot without patch 10/10, but with the other patches in this series ?

As per the board file, n800 has tusb6010 as well as OneNAND in sync read & async write mode, was OneNAND working without 10/10.

Do you have any idea, which timing could have gone wrong, can you please sent me DEBUG enabled gpmc log with and without 10/10.

Can you please sent me GPMC DEBUG enabled logs with and without this series.

maintainer
#24 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Quoted 6 lines · Mohammed, Afzal

Hi Tony,

Quoted 2 lines · Afzal
Quoted 1 line · Afzal

On Sat, Aug 25, 2012 at 01:16:30, Tony Lindgren wrote:

Quoted 7 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

This hangs n800 during the boot.

Paul reported that n800 stopped booting on OMAP baseline [1] due to an mmc issue and has posted a solution [2].

Are you facing the same issue ?, if so, then it is not due to this series.

No that's a separate issue. Your series works except for this patch makes thing hang.

Regards,

Tony

Quoted 24 lines

I tried to get an n800, but has been unsuccessful.

Regards
Afzal

[1] http://marc.info/?l=linux-omap&m=134685988517580&w=2
[2] http://www.spinics.net/lists/arm-kernel/msg190879.html

Quoted 14 lines
Quoted 11 lines

Shall I read the above as n800 boot without patch 10/10, but with the other patches in this series ?

As per the board file, n800 has tusb6010 as well as OneNAND in sync read & async write mode, was OneNAND working without 10/10.

Do you have any idea, which timing could have gone wrong, can you please sent me DEBUG enabled gpmc log with and without 10/10.

Can you please sent me GPMC DEBUG enabled logs with and without this series.

maintainer
#25 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Quoted 9 lines · Tony Lindgren
Quoted 8 lines · Mohammed, Afzal

Hi Tony,

Quoted 4 lines · Afzal
Quoted 3 lines · Afzal
Quoted 1 line · Tony Lindgren

This hangs n800 during the boot.

Quoted 8 lines
Quoted 5 lines

Paul reported that n800 stopped booting on OMAP baseline [1] due to an mmc issue and has posted a solution [2].

Are you facing the same issue ?, if so, then it is not due to this series.

No that's a separate issue. Your series works except for this patch makes thing hang.

Here are the timing changes with and without this patch from my n800. You can just diff the two files to see some differences.

Regards,

Tony
-------------- next part --------------
GPMC CS1: cs_on : 1 ticks, 9 ns (was 0 ticks) 9 ns
GPMC CS1: cs_rd_off : 8 ticks, 72 ns (was 5 ticks) 72 ns
GPMC CS1: cs_wr_off : 8 ticks, 72 ns (was 5 ticks) 72 ns
GPMC CS1: adv_on : 6 ticks, 54 ns (was 0 ticks) 54 ns
GPMC CS1: adv_rd_off: 7 ticks, 63 ns (was 3 ticks) 63 ns
GPMC CS1: adv_wr_off: 7 ticks, 63 ns (was 3 ticks) 63 ns
GPMC CS1: oe_on : 7 ticks, 63 ns (was 4 ticks) 63 ns
GPMC CS1: oe_off : 8 ticks, 72 ns (was 5 ticks) 72 ns
GPMC CS1: we_on : 8 ticks, 72 ns (was 4 ticks) 72 ns
GPMC CS1: we_off : 8 ticks, 72 ns (was 5 ticks) 72 ns
GPMC CS1: rd_cycle : 9 ticks, 82 ns (was 5 ticks) 82 ns
GPMC CS1: wr_cycle : 9 ticks, 82 ns (was 5 ticks) 82 ns
GPMC CS1: access : 7 ticks, 63 ns (was 5 ticks) 63 ns
GPMC CS1: page_burst_access: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: clk_activation: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: cs_on : 1 ticks, 9 ns (was 0 ticks) 9 ns
GPMC CS4: cs_rd_off : 16 ticks, 145 ns (was 7 ticks) 145 ns
GPMC CS4: cs_wr_off : 16 ticks, 145 ns (was 7 ticks) 145 ns
GPMC CS4: adv_on : 6 ticks, 54 ns (was 2 ticks) 54 ns
GPMC CS4: adv_rd_off: 7 ticks, 63 ns (was 4 ticks) 63 ns
GPMC CS4: adv_wr_off: 7 ticks, 63 ns (was 4 ticks) 63 ns
GPMC CS4: oe_on : 10 ticks, 91 ns (was 5 ticks) 91 ns
GPMC CS4: oe_off : 16 ticks, 145 ns (was 7 ticks) 145 ns
GPMC CS4: we_on : 10 ticks, 91 ns (was 5 ticks) 91 ns
GPMC CS4: we_off : 16 ticks, 145 ns (was 6 ticks) 145 ns
GPMC CS4: rd_cycle : 17 ticks, 154 ns (was 8 ticks) 154 ns
GPMC CS4: wr_cycle : 17 ticks, 154 ns (was 8 ticks) 154 ns
GPMC CS4: access : 15 ticks, 136 ns (was 6 ticks) 136 ns
GPMC CS4: page_burst_access: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS4: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: clk_activation: 1 ticks, 9 ns (was 0 ticks) 9 ns
GPMC CS4 CLK period is 18 ns (div 2)
TUSB 6010
...
OneNAND driver initializing
GPMC CS0: cs_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cs_rd_off : 10 ticks, 91 ns (was 12 ticks) 91 ns
GPMC CS0: cs_wr_off : 12 ticks, 109 ns (was 9 ticks) 109 ns
GPMC CS0: adv_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: adv_rd_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: adv_wr_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: oe_on : 3 ticks, 27 ns (was 2 ticks) 27 ns
GPMC CS0: oe_off : 10 ticks, 91 ns (was 12 ticks) 91 ns
GPMC CS0: we_on : 3 ticks, 27 ns (was 3 ticks) 27 ns
GPMC CS0: we_off : 8 ticks, 72 ns (was 8 ticks) 72 ns
GPMC CS0: rd_cycle : 13 ticks, 118 ns (was 13 ticks) 118 ns
GPMC CS0: wr_cycle : 15 ticks, 136 ns (was 10 ticks) 136 ns
GPMC CS0: access : 9 ticks, 82 ns (was 11 ticks) 82 ns
GPMC CS0: page_burst_access: 0 ticks, 0 ns (was 2 ticks) 0 ns
GPMC CS0: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: clk_activation: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cs_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cs_rd_off : 14 ticks, 127 ns (was 10 ticks) 127 ns
GPMC CS0: cs_wr_off : 12 ticks, 109 ns (was 12 ticks) 109 ns
GPMC CS0: adv_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: adv_rd_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: adv_wr_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: oe_on : 3 ticks, 27 ns (was 3 ticks) 27 ns
GPMC CS0: oe_off : 14 ticks, 127 ns (was 10 ticks) 127 ns
GPMC CS0: we_on : 3 ticks, 27 ns (was 3 ticks) 27 ns
GPMC CS0: we_off : 8 ticks, 72 ns (was 8 ticks) 72 ns
GPMC CS0: rd_cycle : 16 ticks, 145 ns (was 13 ticks) 145 ns
GPMC CS0: wr_cycle : 15 ticks, 136 ns (was 15 ticks) 136 ns
GPMC CS0: access : 13 ticks, 118 ns (was 9 ticks) 118 ns
GPMC CS0: page_burst_access: 3 ticks, 27 ns (was 0 ticks) 27 ns
GPMC CS0: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: clk_activation: 1 ticks, 9 ns (was 0 ticks) 9 ns
GPMC CS0 CLK period is 27 ns (div 3)
omap2-onenand omap2-onenand: initializing on CS0, phys base 0x04000000, virtual base c88c0000, freq 54 MHz OneNAND Manufacturer: Samsung (0xec)
Muxed OneNAND(DDP) 256MB 1.8V 16-bit (0x48)
OneNAND version = 0x0011
Chip support all block unlock
onenand_wait: controller error! state 15 ctrl 0x0400 intr 0x8000
Scanning device for bad blocks
Creating 5 MTD partitions on "omap2-onenand":
0x000000000000-0x000000020000 : "bootloader"
0x000000020000-0x000000080000 : "config"
0x000000080000-0x000000280000 : "kernel"
0x000000280000-0x000000680000 : "initfs"
0x000000680000-0x000010000000 : "rootfs"
omap-dma-engine omap-dma-engine: allocating channel for 44
omap-dma-engine omap-dma-engine: allocating channel for 43

-------------- next part --------------
GPMC CS1: cs_on : 1 ticks, 9 ns (was 0 ticks) 8 ns
GPMC CS1: cs_rd_off : 9 ticks, 82 ns (was 5 ticks) 82 ns
GPMC CS1: cs_wr_off : 9 ticks, 82 ns (was 5 ticks) 82 ns
GPMC CS1: adv_on : 6 ticks, 54 ns (was 0 ticks) 48 ns
GPMC CS1: adv_rd_off: 7 ticks, 63 ns (was 3 ticks) 63 ns
GPMC CS1: adv_wr_off: 7 ticks, 63 ns (was 3 ticks) 63 ns
GPMC CS1: oe_on : 7 ticks, 63 ns (was 4 ticks) 63 ns
GPMC CS1: oe_off : 9 ticks, 82 ns (was 5 ticks) 82 ns
GPMC CS1: we_on : 8 ticks, 72 ns (was 4 ticks) 72 ns
GPMC CS1: we_off : 9 ticks, 82 ns (was 5 ticks) 82 ns
GPMC CS1: rd_cycle : 10 ticks, 91 ns (was 5 ticks) 91 ns
GPMC CS1: wr_cycle : 10 ticks, 91 ns (was 5 ticks) 91 ns
GPMC CS1: access : 8 ticks, 72 ns (was 5 ticks) 72 ns
GPMC CS1: page_burst_access: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS1: clk_activation: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: cs_on : 1 ticks, 9 ns (was 0 ticks) 8 ns
GPMC CS4: cs_rd_off : 16 ticks, 145 ns (was 7 ticks) 145 ns
GPMC CS4: cs_wr_off : 16 ticks, 145 ns (was 7 ticks) 144 ns
GPMC CS4: adv_on : 6 ticks, 54 ns (was 2 ticks) 48 ns
GPMC CS4: adv_rd_off: 7 ticks, 63 ns (was 4 ticks) 63 ns
GPMC CS4: adv_wr_off: 7 ticks, 63 ns (was 4 ticks) 63 ns
GPMC CS4: oe_on : 10 ticks, 91 ns (was 5 ticks) 90 ns
GPMC CS4: oe_off : 16 ticks, 145 ns (was 7 ticks) 145 ns
GPMC CS4: we_on : 10 ticks, 91 ns (was 5 ticks) 90 ns
GPMC CS4: we_off : 16 ticks, 145 ns (was 6 ticks) 144 ns
GPMC CS4: rd_cycle : 17 ticks, 154 ns (was 8 ticks) 154 ns
GPMC CS4: wr_cycle : 17 ticks, 154 ns (was 8 ticks) 154 ns
GPMC CS4: access : 15 ticks, 136 ns (was 6 ticks) 135 ns
GPMC CS4: page_burst_access: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS4: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS4: clk_activation: 1 ticks, 9 ns (was 0 ticks) 9 ns
GPMC CS4 CLK period is 18 ns (div 2)
TUSB 6010
...

OneNAND driver initializing
GPMC CS0: cs_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cs_rd_off : 10 ticks, 91 ns (was 12 ticks) 91 ns
GPMC CS0: cs_wr_off : 12 ticks, 109 ns (was 9 ticks) 108 ns
GPMC CS0: adv_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: adv_rd_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: adv_wr_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: oe_on : 3 ticks, 27 ns (was 2 ticks) 27 ns
GPMC CS0: oe_off : 10 ticks, 91 ns (was 12 ticks) 91 ns
GPMC CS0: we_on : 3 ticks, 27 ns (was 3 ticks) 27 ns
GPMC CS0: we_off : 8 ticks, 72 ns (was 8 ticks) 72 ns
GPMC CS0: rd_cycle : 13 ticks, 118 ns (was 13 ticks) 118 ns
GPMC CS0: wr_cycle : 15 ticks, 136 ns (was 10 ticks) 135 ns
GPMC CS0: access : 9 ticks, 82 ns (was 11 ticks) 82 ns
GPMC CS0: page_burst_access: 0 ticks, 0 ns (was 2 ticks) 0 ns
GPMC CS0: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: clk_activation: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cs_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cs_rd_off : 14 ticks, 127 ns (was 10 ticks) 127 ns
GPMC CS0: cs_wr_off : 12 ticks, 109 ns (was 12 ticks) 108 ns
GPMC CS0: adv_on : 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: adv_rd_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: adv_wr_off: 2 ticks, 18 ns (was 2 ticks) 18 ns
GPMC CS0: oe_on : 3 ticks, 27 ns (was 3 ticks) 27 ns
GPMC CS0: oe_off : 14 ticks, 127 ns (was 10 ticks) 127 ns
GPMC CS0: we_on : 3 ticks, 27 ns (was 3 ticks) 27 ns
GPMC CS0: we_off : 8 ticks, 72 ns (was 8 ticks) 72 ns
GPMC CS0: rd_cycle : 16 ticks, 145 ns (was 13 ticks) 145 ns
GPMC CS0: wr_cycle : 15 ticks, 136 ns (was 15 ticks) 135 ns
GPMC CS0: access : 13 ticks, 118 ns (was 9 ticks) 118 ns
GPMC CS0: page_burst_access: 3 ticks, 27 ns (was 0 ticks) 27 ns
GPMC CS0: bus_turnaround: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: cycle2cycle_delay: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: wait_monitoring: 0 ticks, 0 ns (was 0 ticks) 0 ns
GPMC CS0: clk_activation: 1 ticks, 9 ns (was 0 ticks) 9 ns
GPMC CS0 CLK period is 27 ns (div 3)
omap2-onenand omap2-onenand: initializing on CS0, phys base 0x04000000, virtual base c88c0000, freq 54 MHz OneNAND Manufacturer: Samsung (0xec)
Muxed OneNAND(DDP) 256MB 1.8V 16-bit (0x48)
OneNAND version = 0x0011
Chip support all block unlock
onenand_wait: controller error! state 15 ctrl 0x0400 intr 0x8000
Scanning device for bad blocks
Creating 5 MTD partitions on "omap2-onenand":
0x000000000000-0x000000020000 : "bootloader"
0x000000020000-0x000000080000 : "config"
0x000000080000-0x000000280000 : "kernel"
0x000000280000-0x000000680000 : "initfs"
0x000000680000-0x000010000000 : "rootfs"
omap-dma-engine omap-dma-engine: allocating channel for 44
omap-dma-engine omap-dma-engine: allocating channel for 43

#26 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Hi Tony,

Quoted 2 lines · Tony Lindgren

Here are the timing changes with and without this patch from my n800. You can just diff the two files to see some differences.

Hmm.. that was pretty close, OneNAND async,sync as well as tusb sync values were same.

But some of the tusb async values is less by one. I need to get it right.

And thanks for sending me the easily diff-able logs.

Regards
Afzal

#27 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

* Mohammed, Afzal: Wednesday, September 12, 2012 3:20 PM

Quoted 2 lines

But some of the tusb async values is less by one. I need to get it right.

Reason has been identified. It was due to rounding error, no changes are required in the expressions. Moving completely to picoseconds resolves the issue.

Can you please try with the attached patch ?

Once it is confirmed that issue is resolved, I will cleanup gpmc-nand.c too (which would also take care of picoseconds)

Note: As this mail is sent via exchange, I am attaching the patch so that it reaches you in proper way.

Regards
Afzal
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-gpmc-rounding-error-fix.patch
Type: text/x-patch
Size: 14228 bytes
Desc: 0001-gpmc-rounding-error-fix.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20120914/5b0b4601/attachment.bin>

#28 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Hi Tony,

Quoted 10 lines · Afzal

* Mohammed, Afzal: Wednesday, September 12, 2012 3:20 PM

Quoted 2 lines

But some of the tusb async values is less by one. I need to get it right.

Reason has been identified. It was due to rounding error, no changes are required in the expressions. Moving completely to picoseconds resolves the issue.

Can you please try with the attached patch ?

Can you please try with patch attached in previous message of this thread and check whether it makes n800 gpmc peripherals work properly

Changes as in above mentioned patch has been pasted below again.

Regards
Afzal

---8<------------------------

arch/arm/mach-omap2/gpmc.c +70 -80
index d8e5b08..e9d57db 100644
@@ -289,11 +289,11 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	if (time == 0)
 		ticks = 0;
 	else
-		ticks = gpmc_ns_to_ticks(time);
+		ticks = gpmc_ps_to_ticks(time);
 	nr_bits = end_bit - st_bit + 1;
 	if (ticks >= 1 << nr_bits) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
+		pr_info("GPMC CS%d: %-10s* %3d ps, %3d ticks >= %d\n",
 				cs, name, time, ticks, 1 << nr_bits);
 #endif
 		return -1;
@@ -302,10 +302,9 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
 	mask = (1 << nr_bits) - 1;
 	l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-	printk(KERN_INFO
-		"GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
-	       cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
-			(l >> st_bit) & mask, time);
+	pr_info("GPMC CS%d: %-10s: %3d ticks, %3lu ps (was %3i ticks) %3d ps\n",
+		cs, name, ticks, gpmc_get_fclk_period() * ticks,
+		(l >> st_bit) & mask, time);
 #endif
 	l &= ~(mask << st_bit);
 	l |= ticks << st_bit;
@@ -385,8 +384,8 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 	l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
 	if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-		printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-				cs, (div * gpmc_get_fclk_period()) / 1000, div);
+		pr_info("GPMC CS%d CLK period is %lu ps (div %d)\n",
+				cs, div * gpmc_get_fclk_period(), div);
 #endif
 		l &= ~0x03;
 		l |= (div - 1);
@@ -922,46 +921,42 @@ static int gpmc_calc_sync_read_timings(struct gpmc_timings *gpmc_t,
 		 * indirectly necessitates requirement of t_avdp_r & t_avdp_w
 		 * instead of having a single t_avdp
 		 */
-		temp = max_t(u32, temp,	gpmc_t->clk_activation * 1000 +
-							dev_t->t_avdh);
-		temp = max_t(u32,
-			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 	}
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp) / 1000;
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
 
 	/* oe_on */
 	temp = dev_t->t_oeasu; /* remove this ? */
 	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->clk_activation * 1000 + dev_t->t_ach);
-		temp = max_t(u32, temp, (gpmc_t->adv_rd_off +
-				gpmc_ticks_to_ns(dev_t->cyc_aavdh_oe)) * 1000);
+		temp = max_t(u32, temp,	gpmc_t->clk_activation + dev_t->t_ach);
+		temp = max_t(u32, temp, gpmc_t->adv_rd_off +
+				gpmc_ticks_to_ps(dev_t->cyc_aavdh_oe));
 	}
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp) / 1000;
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
 	/* access */
 	/* any scope for improvement ?, by combining oe_on & clk_activation,
 	 * need to check whether access = clk_activation + round to sync clk ?
 	 */
 	temp = max_t(u32, dev_t->t_iaa,	dev_t->cyc_iaa * gpmc_t->sync_clk);
-	temp += gpmc_t->clk_activation * 1000;
+	temp += gpmc_t->clk_activation;
 	if (dev_t->cyc_oe)
-		temp = max_t(u32, temp, (gpmc_t->oe_on +
-				gpmc_ticks_to_ns(dev_t->cyc_oe)) * 1000);
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp) / 1000;
+		temp = max_t(u32, temp, gpmc_t->oe_on +
+				gpmc_ticks_to_ps(dev_t->cyc_oe));
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ns(1);
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
 	gpmc_t->cs_rd_off = gpmc_t->oe_off;
 
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_cez_r, dev_t->t_oez);
 	temp = gpmc_round_ps_to_sync_clk(temp, gpmc_t->sync_clk) +
-							gpmc_t->access * 1000;
+							gpmc_t->access;
 	/* barter t_ce_rdyz with t_cez_r ? */
 	if (dev_t->t_ce_rdyz)
-		temp = max_t(u32, temp,
-				gpmc_t->cs_rd_off * 1000 + dev_t->t_ce_rdyz);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+		temp = max_t(u32, temp,	gpmc_t->cs_rd_off + dev_t->t_ce_rdyz);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
@@ -976,29 +971,28 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	temp = dev_t->t_avdp_w;
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->clk_activation * 1000 + dev_t->t_avdh);
-		temp = max_t(u32,
-			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
+			gpmc_t->clk_activation + dev_t->t_avdh);
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
 	}
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp) / 1000;
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 
 	/* wr_data_mux_bus */
 	temp = max_t(u32, dev_t->t_weasu,
-			gpmc_t->clk_activation * 1000 + dev_t->t_rdyo);
+			gpmc_t->clk_activation + dev_t->t_rdyo);
 	/* shouldn't mux be kept as a whole for wr_data_mux_bus ?,
 	 * and in that case remember to handle we_on properly
 	 */
 	if (mux) {
 		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off * 1000 + dev_t->t_aavdh);
-		temp = max_t(u32, temp, (gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ns(dev_t->cyc_aavdh_we)) * 1000);
+			gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp) / 1000;
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
 	/* we_on */
 	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu) / 1000;
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
 	else
 		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
 
@@ -1007,24 +1001,24 @@ static int gpmc_calc_sync_write_timings(struct gpmc_timings *gpmc_t,
 	gpmc_t->wr_access = gpmc_t->access;
 
 	/* we_off */
-	temp = gpmc_t->we_on * 1000 + dev_t->t_wpl;
+	temp = gpmc_t->we_on + dev_t->t_wpl;
 	temp = max_t(u32, temp,
-			(gpmc_t->wr_access + gpmc_ticks_to_ns(1)) * 1000);
+			gpmc_t->wr_access + gpmc_ticks_to_ps(1));
 	temp = max_t(u32, temp,
-		(gpmc_t->we_on + gpmc_ticks_to_ns(dev_t->cyc_wpl)) * 1000);
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp) / 1000;
+		gpmc_t->we_on + gpmc_ticks_to_ps(dev_t->cyc_wpl));
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off * 1000 +
-							dev_t->t_wph) / 1000;
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+							dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = gpmc_round_ps_to_sync_clk(dev_t->t_cez_w, gpmc_t->sync_clk);
-	temp += gpmc_t->wr_access * 1000;
+	temp += gpmc_t->wr_access;
 	/* barter t_ce_rdyz with t_cez_w ? */
 	if (dev_t->t_ce_rdyz)
 		temp = max_t(u32, temp,
-				 gpmc_t->cs_wr_off * 1000 + dev_t->t_ce_rdyz);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+				 gpmc_t->cs_wr_off + dev_t->t_ce_rdyz);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
@@ -1038,35 +1032,33 @@ static int gpmc_calc_async_read_timings(struct gpmc_timings *gpmc_t,
 	/* adv_rd_off */
 	temp = dev_t->t_avdp_r;
 	if (mux)
-		temp = max_t(u32,
-			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
-	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp) / 1000;
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_rd_off = gpmc_round_ps_to_ticks(temp);
 
 	/* oe_on */
 	temp = dev_t->t_oeasu;
 	if (mux)
 		temp = max_t(u32, temp,
-			gpmc_t->adv_rd_off * 1000 + dev_t->t_aavdh);
-	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp) / 1000;
+			gpmc_t->adv_rd_off + dev_t->t_aavdh);
+	gpmc_t->oe_on = gpmc_round_ps_to_ticks(temp);
 
 	/* access */
 	temp = max_t(u32, dev_t->t_iaa, /* remove t_iaa in async ? */
-				gpmc_t->oe_on * 1000 + dev_t->t_oe);
+				gpmc_t->oe_on + dev_t->t_oe);
 	temp = max_t(u32, temp,
-				gpmc_t->cs_on * 1000 + dev_t->t_ce);
+				gpmc_t->cs_on + dev_t->t_ce);
 	temp = max_t(u32, temp,
-				gpmc_t->adv_on * 1000 + dev_t->t_aa);
-	gpmc_t->access = gpmc_round_ps_to_ticks(temp) / 1000;
+				gpmc_t->adv_on + dev_t->t_aa);
+	gpmc_t->access = gpmc_round_ps_to_ticks(temp);
 
-	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ns(1);
+	gpmc_t->oe_off = gpmc_t->access + gpmc_ticks_to_ps(1);
 	gpmc_t->cs_rd_off = gpmc_t->oe_off;
 
 	/* rd_cycle */
 	temp = max_t(u32, dev_t->t_rd_cycle,
-			gpmc_t->cs_rd_off * 1000 + dev_t->t_cez_r);
-	temp = max_t(u32, temp,
-			gpmc_t->oe_off * 1000 + dev_t->t_oez);
-	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+			gpmc_t->cs_rd_off + dev_t->t_cez_r);
+	temp = max_t(u32, temp, gpmc_t->oe_off + dev_t->t_oez);
+	gpmc_t->rd_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
@@ -1080,37 +1072,35 @@ static int gpmc_calc_async_write_timings(struct gpmc_timings *gpmc_t,
 	/* adv_wr_off */
 	temp = dev_t->t_avdp_w;
 	if (mux)
-		temp = max_t(u32,
-			(gpmc_t->adv_on + gpmc_ticks_to_ns(1)) * 1000, temp);
-	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp) / 1000;
+		temp = max_t(u32, gpmc_t->adv_on + gpmc_ticks_to_ps(1), temp);
+	gpmc_t->adv_wr_off = gpmc_round_ps_to_ticks(temp);
 
 	/* wr_data_mux_bus */
 	temp = dev_t->t_weasu;
 	if (mux) {
-		temp = max_t(u32, temp,
-			gpmc_t->adv_wr_off * 1000 + dev_t->t_aavdh);
-		temp = max_t(u32, temp, (gpmc_t->adv_wr_off +
-				gpmc_ticks_to_ns(dev_t->cyc_aavdh_we)) * 1000);
+		temp = max_t(u32, temp,	gpmc_t->adv_wr_off + dev_t->t_aavdh);
+		temp = max_t(u32, temp, gpmc_t->adv_wr_off +
+				gpmc_ticks_to_ps(dev_t->cyc_aavdh_we));
 	}
-	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp) / 1000;
+	gpmc_t->wr_data_mux_bus = gpmc_round_ps_to_ticks(temp);
 
 	/* we_on */
 	if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS)
-		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu) / 1000;
+		gpmc_t->we_on = gpmc_round_ps_to_ticks(dev_t->t_weasu);
 	else
 		gpmc_t->we_on = gpmc_t->wr_data_mux_bus;
 
 	/* we_off */
-	temp = gpmc_t->we_on * 1000 + dev_t->t_wpl;
-	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp) / 1000;
+	temp = gpmc_t->we_on + dev_t->t_wpl;
+	gpmc_t->we_off = gpmc_round_ps_to_ticks(temp);
 
-	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks((gpmc_t->we_off * 1000 +
-				dev_t->t_wph)) / 1000;
+	gpmc_t->cs_wr_off = gpmc_round_ps_to_ticks(gpmc_t->we_off +
+							dev_t->t_wph);
 
 	/* wr_cycle */
 	temp = max_t(u32, dev_t->t_wr_cycle,
-				gpmc_t->cs_wr_off * 1000 + dev_t->t_cez_w);
-	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp) / 1000;
+				gpmc_t->cs_wr_off + dev_t->t_cez_w);
+	gpmc_t->wr_cycle = gpmc_round_ps_to_ticks(temp);
 
 	return 0;
 }
@@ -1125,10 +1115,10 @@ static int gpmc_calc_sync_common_timings(struct gpmc_timings *gpmc_t,
 
 	gpmc_t->page_burst_access = gpmc_round_ps_to_sync_clk(
 					dev_t->t_bacc,
-					gpmc_t->sync_clk) / 1000;
+					gpmc_t->sync_clk);
 
 	temp = max_t(u32, dev_t->t_ces, dev_t->t_avds);
-	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp) / 1000;
+	gpmc_t->clk_activation = gpmc_round_ps_to_ticks(temp);
 
 	if (gpmc_calc_divider(gpmc_t->sync_clk) != 1)
 		return 0;
@@ -1151,14 +1141,14 @@ static int gpmc_calc_common_timings(struct gpmc_timings *gpmc_t,
 	u32 temp;
 
 	/* cs_on */
-	gpmc_t->cs_on = gpmc_round_ns_to_ticks(dev_t->t_ceasu / 1000);
+	gpmc_t->cs_on = gpmc_round_ps_to_ticks(dev_t->t_ceasu);
 
 	/* adv_on */
 	temp = dev_t->t_avdasu;
 	if (dev_t->t_ce_avd)
 		temp = max_t(u32, temp,
-				gpmc_t->cs_on * 1000 + dev_t->t_ce_avd);
-	gpmc_t->adv_on = gpmc_round_ns_to_ticks(temp / 1000);
+				gpmc_t->cs_on + dev_t->t_ce_avd);
+	gpmc_t->adv_on = gpmc_round_ps_to_ticks(temp);
 
 	if (dev_t->sync_write || dev_t->sync_read)
 		gpmc_calc_sync_common_timings(gpmc_t, dev_t);
arch/arm/plat-omap/include/plat/gpmc.h +20 -20
index e59a932..f1d1d2e 100644
@@ -116,38 +116,38 @@ struct gpmc_timings {
 	u32 sync_clk;
 
 	/* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
-	u16 cs_on;		/* Assertion time */
-	u16 cs_rd_off;		/* Read deassertion time */
-	u16 cs_wr_off;		/* Write deassertion time */
+	u32 cs_on;		/* Assertion time */
+	u32 cs_rd_off;		/* Read deassertion time */
+	u32 cs_wr_off;		/* Write deassertion time */
 
 	/* ADV signal timings corresponding to GPMC_CONFIG3 */
-	u16 adv_on;		/* Assertion time */
-	u16 adv_rd_off;		/* Read deassertion time */
-	u16 adv_wr_off;		/* Write deassertion time */
+	u32 adv_on;		/* Assertion time */
+	u32 adv_rd_off;		/* Read deassertion time */
+	u32 adv_wr_off;		/* Write deassertion time */
 
 	/* WE signals timings corresponding to GPMC_CONFIG4 */
-	u16 we_on;		/* WE assertion time */
-	u16 we_off;		/* WE deassertion time */
+	u32 we_on;		/* WE assertion time */
+	u32 we_off;		/* WE deassertion time */
 
 	/* OE signals timings corresponding to GPMC_CONFIG4 */
-	u16 oe_on;		/* OE assertion time */
-	u16 oe_off;		/* OE deassertion time */
+	u32 oe_on;		/* OE assertion time */
+	u32 oe_off;		/* OE deassertion time */
 
 	/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
-	u16 page_burst_access;	/* Multiple access word delay */
-	u16 access;		/* Start-cycle to first data valid delay */
-	u16 rd_cycle;		/* Total read cycle time */
-	u16 wr_cycle;		/* Total write cycle time */
+	u32 page_burst_access;	/* Multiple access word delay */
+	u32 access;		/* Start-cycle to first data valid delay */
+	u32 rd_cycle;		/* Total read cycle time */
+	u32 wr_cycle;		/* Total write cycle time */
 
-	u16 bus_turnaround;
-	u16 cycle2cycle_delay;
+	u32 bus_turnaround;
+	u32 cycle2cycle_delay;
 
-	u16 wait_monitoring;
-	u16 clk_activation;
+	u32 wait_monitoring;
+	u32 clk_activation;
 
 	/* The following are only on OMAP3430 */
-	u16 wr_access;		/* WRACCESSTIME */
-	u16 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
+	u32 wr_access;		/* WRACCESSTIME */
+	u32 wr_data_mux_bus;	/* WRDATAONADMUXBUS */
 
 	struct gpmc_bool_timings bool_timings;
 };
maintainer
#29 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Quoted 13 lines · Mohammed, Afzal

Hi Tony,

Quoted 10 lines · Afzal

* Mohammed, Afzal: Wednesday, September 12, 2012 3:20 PM

Quoted 2 lines

But some of the tusb async values is less by one. I need to get it right.

Reason has been identified. It was due to rounding error, no changes are required in the expressions. Moving completely to picoseconds resolves the issue.

Can you please try with the attached patch ?

Gave it a quick try and it seemed to work.. But when I tried rebasing my patches for the cbus to keep things working with the watchdog, I ran into multiple merge conflicts with current linux next and gave up.

Care to repost this series updated against current linux next?

I'm afraid I've pretty much lost track of all the patches and rather not start resolving the conflicts as I'm sure I'll break something else :)

Regards,

Tony

maintainer
#30 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Quoted 13 lines · Tony Lindgren
Quoted 12 lines · Mohammed, Afzal

Hi Tony,

Quoted 9 lines · Afzal

* Mohammed, Afzal: Wednesday, September 12, 2012 3:20 PM

Quoted 2 lines

But some of the tusb async values is less by one. I need to get it right.

Reason has been identified. It was due to rounding error, no changes are required in the expressions. Moving completely to picoseconds resolves the issue.

Quoted 6 lines
Quoted 1 line
Quoted 1 line

Can you please try with the attached patch ?

Gave it a quick try and it seemed to work.. But when I tried rebasing my patches for the cbus to keep things working with the watchdog, I ran into multiple merge conflicts with current linux next and gave up.

OK went back to my original branch without current linux next and with the new cbus + retu driver from Aaro applied. Confirmed it's now working on n800 tusb6010.

Quoted 6 lines

Care to repost this series updated against current linux next?

I'm afraid I've pretty much lost track of all the patches and rather not start resolving the conflicts as I'm sure I'll break something else :)

You should still repost the whole updated series against linux next.

Regards,

Tony

#31 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

Hi Tony,

Quoted 4 lines · Tony Lindgren
Quoted 2 lines · Tony Lindgren
Quoted 1 line
Quoted 1 line

Can you please try with the attached patch ?

Quoted 8 lines
Quoted 4 lines

Gave it a quick try and it seemed to work.. But when I tried rebasing my patches for the cbus to keep things working with the watchdog, I ran into multiple merge conflicts with current linux next and gave up.

OK went back to my original branch without current linux next and with the new cbus + retu driver from Aaro applied. Confirmed it's now working on n800 tusb6010.

Thanks for checking and confirming.

Quoted 9 lines
Quoted 6 lines

Care to repost this series updated against current linux next?

I'm afraid I've pretty much lost track of all the patches and rather not start resolving the conflicts as I'm sure I'll break something else :)

You should still repost the whole updated series against linux next.

New updated version - v7, based over linux next has been posted.

Regards
Afzal

#32 lore raw

PATCH v6 10/10 ARM: OMAP2+: tusb6010: generic timing calculation

In reply to Mohammed, Afzal

+ Rajendra

Hi

Quoted 1 line · Afzal

I tried to get an n800, but has been unsuccessful.

We took an n800 to TII a few years ago, hopefully you can find it. Cc'ing Rajendra who might know where it is.

- Paul

#33 lore raw

v6 cover OMAP-GPMC: generic time calc, prepare for driver

In reply to Afzal Mohammed

Hi Afzal,

Quoted 11 lines · Afzal Mohammed

This series provides a generic gpmc timing calculation routine. There were three peripherals (OneNAND, tusb6010, smc91x) using custom timing calculations, they are migrated to use the generic timing calculation.

Such a generic routine would help create a driver out of gpmc platform code, which would be peripheral agnostic and thus lead to DT finally. Input to generic timing calculation routine would be gpmc peripheral timings, output - translated timings that gpmc can understand. Later, to DT'ify, gpmc peripheral timings could be passed through DT. Input timings that has been used here are selected such that it represents those that are present in peripheral timing datasheets.

What I don't understand yet about this new approach is where the gpmc client code should live in. In order to probe the drivers via DT, each driver would need to call the gpmc support functions itself, right? Is the plan to obsolete helper functions like gpmc_nand_init() and move that functionality to the drivers?

I applied these patches locally and would like to help get the NAND controller on my AX33xx DT-driven board going. Let me know if I can do anything here.

Regards,
Daniel

#34 lore raw

v6 cover OMAP-GPMC: generic time calc, prepare for driver

Hi Daniel,

Quoted 11 lines · Daniel Mack
Quoted 7 lines

Such a generic routine would help create a driver out of gpmc platform code, which would be peripheral agnostic and thus lead to DT finally. Input to generic timing calculation routine would be gpmc peripheral timings, output - translated timings that gpmc can understand. Later, to DT'ify, gpmc peripheral timings could be passed through DT. Input timings that has been used here are selected such that it represents those that are present in peripheral timing datasheets.

What I don't understand yet about this new approach is where the gpmc client code should live in. In order to probe the drivers via DT, each driver would need to call the gpmc support functions itself, right? Is

By gpmc client code, if you are referring to helper functions in mach-omap2/gpmc-*, if things go as per plan, with DT, they will go away and gpmc driver would handle those based on the information from DT.

No change would be needed for client drivers like smc91x ethernet drivers, but NAND driver may need some change to live with DT as it is tightly coupled with GPMC.

Quoted 2 lines

the plan to obsolete helper functions like gpmc_nand_init() and move that functionality to the drivers?

Yes, plan is to obsolete the functions like gpmc_nand_init, those tasks would be handled by gpmc driver

Quoted 4 lines

I applied these patches locally and would like to help get the NAND controller on my AX33xx DT-driven board going. Let me know if I can do anything here.

Thanks for offering the help, will take liberty to ask you for help when required. BTW, do you have any OMAP family boards ?

Regards
Afzal

#35 lore raw

v6 cover OMAP-GPMC: generic time calc, prepare for driver

Quoted 10 lines · Afzal
Quoted 8 lines · Daniel Mack
Quoted 7 lines

Such a generic routine would help create a driver out of gpmc platform code, which would be peripheral agnostic and thus lead to DT finally. Input to generic timing calculation routine would be gpmc peripheral timings, output - translated timings that gpmc can understand. Later, to DT'ify, gpmc peripheral timings could be passed through DT. Input timings that has been used here are selected such that it represents those that are present in peripheral timing datasheets.

Quoted 7 lines
Quoted 3 lines

What I don't understand yet about this new approach is where the gpmc client code should live in. In order to probe the drivers via DT, each driver would need to call the gpmc support functions itself, right? Is

By gpmc client code, if you are referring to helper functions in mach-omap2/gpmc-*, if things go as per plan, with DT, they will go away and gpmc driver would handle those based on the information from DT.

So the GPMC driver is the one that is matched from DT, and the NAND driver will the be instanciated from the (generic) GPMC driver?

Quoted 3 lines

No change would be needed for client drivers like smc91x ethernet drivers, but NAND driver may need some change to live with DT as it is tightly coupled with GPMC.

NAND drivers also typically parse partition entries that are children of the DT node the are owning.

Quoted 7 lines
Quoted 2 lines

the plan to obsolete helper functions like gpmc_nand_init() and move that functionality to the drivers?

Yes, plan is to obsolete the functions like gpmc_nand_init, those tasks would be handled by gpmc driver

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

I applied these patches locally and would like to help get the NAND controller on my AX33xx DT-driven board going. Let me know if I can do anything here.

Thanks for offering the help, will take liberty to ask you for help when required. BTW, do you have any OMAP family boards ?

I do have a beaglboard xM, but the board I'm currently working with is a custom one based on an AM33xx.

Thanks,
Daniel

#36 lore raw

v6 cover OMAP-GPMC: generic time calc, prepare for driver

Hi Daniel,

Quoted 2 lines · Daniel Mack

So the GPMC driver is the one that is matched from DT, and the NAND driver will the be instanciated from the (generic) GPMC driver?

I think you were referring to nand device being instantiated from gpmc driver?, hence resulting in nand driver getting probed. What I have in mind is to represent peripherals connected to gpmc as childs of gpmc node. For devices like smsc911x, as they already have DT bindings, creating an of device for childs by parsing DT hopefully should relieve task of handling their platform data.

Similarly for nand, creating an of device is to be done by gpmc driver.

Once the bigger issue of timing is resolved, I am planning to implement DT as said above

Also for the existing boards on non-DT boot, plan is to keep the existing interface as such, with no change needed in board files.

Quoted 7 lines
Quoted 4 lines

No change would be needed for client drivers like smc91x ethernet drivers, but NAND driver may need some change to live with DT as it is tightly coupled with GPMC.

NAND drivers also typically parse partition entries that are children of the DT node the are owning.

Yes, in addition to the above, omap nand driver would need to determine a few gpmc specific like transfer mode.

Quoted 2 lines

I do have a beaglboard xM, but the board I'm currently working with is a custom one based on an AM33xx.

I was in need of a board like rx51, n800 that currently calculate gpmc timings at runtime to test the generic timing function, np, thanks again

Regards
Afzal