ARM: OMAP2+: Add function for configuring GPMC settings
authorJon Hunter <jon-hunter@ti.com>
Thu, 21 Feb 2013 21:25:23 +0000 (15:25 -0600)
committerJon Hunter <jon-hunter@ti.com>
Mon, 1 Apr 2013 19:53:41 +0000 (14:53 -0500)
The GPMC has various different configuration options such as bus-width,
synchronous or asychronous mode selection, burst mode options etc.
Currently, there is no common function for configuring these options and
various devices set these options by either programming the GPMC CONFIG1
register directly or by calling gpmc_cs_configure() to set some of the
options.

Add a new function for configuring all of the GPMC options. Having a common
function for configuring this options will simplify code and ease the
migration to device-tree.

Also add a new capability flag to detect devices that support the
address-address-data multiplexing mode.

Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Tested-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/gpmc.h

index 20747fbc686af7cdd12a3ab448e2537191696729..ee5d0e970c62eb81d2bea3c2f7e6e6d83329f791 100644 (file)
 
 #define        GPMC_HAS_WR_ACCESS              0x1
 #define        GPMC_HAS_WR_DATA_MUX_BUS        0x2
+#define        GPMC_HAS_MUX_AAD                0x4
 
 #define GPMC_NR_WAITPINS               4
 
@@ -1126,6 +1127,90 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
        return 0;
 }
 
+/**
+ * gpmc_cs_program_settings - programs non-timing related settings
+ * @cs:                GPMC chip-select to program
+ * @p:         pointer to GPMC settings structure
+ *
+ * Programs non-timing related settings for a GPMC chip-select, such as
+ * bus-width, burst configuration, etc. Function should be called once
+ * for each chip-select that is being used and must be called before
+ * calling gpmc_cs_set_timings() as timing parameters in the CONFIG1
+ * register will be initialised to zero by this function. Returns 0 on
+ * success and appropriate negative error code on failure.
+ */
+int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
+{
+       u32 config1;
+
+       if ((!p->device_width) || (p->device_width > GPMC_DEVWIDTH_16BIT)) {
+               pr_err("%s: invalid width %d!", __func__, p->device_width);
+               return -EINVAL;
+       }
+
+       /* Address-data multiplexing not supported for NAND devices */
+       if (p->device_nand && p->mux_add_data) {
+               pr_err("%s: invalid configuration!\n", __func__);
+               return -EINVAL;
+       }
+
+       if ((p->mux_add_data > GPMC_MUX_AD) ||
+           ((p->mux_add_data == GPMC_MUX_AAD) &&
+            !(gpmc_capability & GPMC_HAS_MUX_AAD))) {
+               pr_err("%s: invalid multiplex configuration!\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Page/burst mode supports lengths of 4, 8 and 16 bytes */
+       if (p->burst_read || p->burst_write) {
+               switch (p->burst_len) {
+               case GPMC_BURST_4:
+               case GPMC_BURST_8:
+               case GPMC_BURST_16:
+                       break;
+               default:
+                       pr_err("%s: invalid page/burst-length (%d)\n",
+                              __func__, p->burst_len);
+                       return -EINVAL;
+               }
+       }
+
+       if ((p->wait_on_read || p->wait_on_write) &&
+           (p->wait_pin > gpmc_nr_waitpins)) {
+               pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
+               return -EINVAL;
+       }
+
+       config1 = GPMC_CONFIG1_DEVICESIZE((p->device_width - 1));
+
+       if (p->sync_read)
+               config1 |= GPMC_CONFIG1_READTYPE_SYNC;
+       if (p->sync_write)
+               config1 |= GPMC_CONFIG1_WRITETYPE_SYNC;
+       if (p->wait_on_read)
+               config1 |= GPMC_CONFIG1_WAIT_READ_MON;
+       if (p->wait_on_write)
+               config1 |= GPMC_CONFIG1_WAIT_WRITE_MON;
+       if (p->wait_on_read || p->wait_on_write)
+               config1 |= GPMC_CONFIG1_WAIT_PIN_SEL(p->wait_pin);
+       if (p->device_nand)
+               config1 |= GPMC_CONFIG1_DEVICETYPE(GPMC_DEVICETYPE_NAND);
+       if (p->mux_add_data)
+               config1 |= GPMC_CONFIG1_MUXTYPE(p->mux_add_data);
+       if (p->burst_read)
+               config1 |= GPMC_CONFIG1_READMULTIPLE_SUPP;
+       if (p->burst_write)
+               config1 |= GPMC_CONFIG1_WRITEMULTIPLE_SUPP;
+       if (p->burst_read || p->burst_write) {
+               config1 |= GPMC_CONFIG1_PAGE_LEN(p->burst_len >> 3);
+               config1 |= p->burst_wrap ? GPMC_CONFIG1_WRAPBURST_SUPP : 0;
+       }
+
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, config1);
+
+       return 0;
+}
+
 #ifdef CONFIG_OF
 static struct of_device_id gpmc_dt_ids[] = {
        { .compatible = "ti,omap2420-gpmc" },
@@ -1372,8 +1457,23 @@ static int gpmc_probe(struct platform_device *pdev)
        gpmc_dev = &pdev->dev;
 
        l = gpmc_read_reg(GPMC_REVISION);
+
+       /*
+        * FIXME: Once device-tree migration is complete the below flags
+        * should be populated based upon the device-tree compatible
+        * string. For now just use the IP revision. OMAP3+ devices have
+        * the wr_access and wr_data_mux_bus register fields. OMAP4+
+        * devices support the addr-addr-data multiplex protocol.
+        *
+        * GPMC IP revisions:
+        * - OMAP24xx                   = 2.0
+        * - OMAP3xxx                   = 5.0
+        * - OMAP44xx/54xx/AM335x       = 6.0
+        */
        if (GPMC_REVISION_MAJOR(l) > 0x4)
                gpmc_capability = GPMC_HAS_WR_ACCESS | GPMC_HAS_WR_DATA_MUX_BUS;
+       if (GPMC_REVISION_MAJOR(l) > 0x5)
+               gpmc_capability |= GPMC_HAS_MUX_AAD;
        dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
                 GPMC_REVISION_MINOR(l));
 
index 39e4e04acdc92600c3ba119c7e131e7e945a009b..ce6ae218f41f59ea68c4cf4afe948d293203775f 100644 (file)
 #define GPMC_IRQ_FIFOEVENTENABLE       0x01
 #define GPMC_IRQ_COUNT_EVENT           0x02
 
+#define GPMC_BURST_4                   4       /* 4 word burst */
+#define GPMC_BURST_8                   8       /* 8 word burst */
+#define GPMC_BURST_16                  16      /* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT             1       /* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT            2       /* 16-bit device width */
 #define GPMC_MUX_AAD                   1       /* Addr-Addr-Data multiplex */
 #define GPMC_MUX_AD                    2       /* Addr-Data multiplex */
 
@@ -217,6 +222,7 @@ extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
 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_program_settings(int cs, struct gpmc_settings *p);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
 extern void omap3_gpmc_save_context(void);