@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/ioport.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -32,6 +33,7 @@
#include "soc.h"
#include "common.h"
+#include "control.h"
#include "omap_device.h"
#include "gpmc.h"
@@ -87,7 +89,6 @@
#define GPMC_MEM_START 0x00000000
#define GPMC_MEM_END 0x3FFFFFFF
-#define BOOT_ROM_SPACE 0x100000 /* 1MB */
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
#define GPMC_SECTION_SHIFT 28 /* 128 MB */
@@ -775,16 +776,11 @@ static void gpmc_mem_exit(void)
}
-static int gpmc_mem_init(void)
+static int gpmc_mem_init(u32 offset)
{
int cs, rc;
- unsigned long boot_rom_space = 0;
- /* never allocate the first page, to facilitate bug detection;
- * even if we didn't boot from ROM.
- */
- boot_rom_space = BOOT_ROM_SPACE;
- gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
+ gpmc_mem_root.start = GPMC_MEM_START + offset;
gpmc_mem_root.end = GPMC_MEM_END;
/* Reserve all regions that has been set up by bootloader */
@@ -1124,6 +1120,12 @@ static int gpmc_probe(struct platform_device *pdev)
int rc;
u32 l;
struct resource *res;
+ struct gpmc_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
+ return -ENODEV;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
@@ -1161,7 +1163,7 @@ static int gpmc_probe(struct platform_device *pdev)
dev_info(gpmc_dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
GPMC_REVISION_MINOR(l));
- rc = gpmc_mem_init();
+ rc = gpmc_mem_init(pdata->gpmc_rom_space);
if (IS_ERR_VALUE(rc)) {
clk_disable_unprepare(gpmc_l3_clk);
clk_put(gpmc_l3_clk);
@@ -1213,15 +1215,46 @@ static int __init omap_gpmc_init(void)
{
struct omap_hwmod *oh;
struct platform_device *pdev;
+ struct gpmc_platform_data *pdata;
char *oh_name = "gpmc";
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("%s: No memory for gpmc\n", __func__);
+ return -ENOMEM;
+ }
+
+ /*
+ * The first 1MB of GPMC address space is mapped to the internal
+ * ROM. OMAP2 devices are an exception to this where the first
+ * 1MB may be mapped to the GPMC. OMAP2 devices that boot from
+ * external memory devices, will map CS0 to the start of the
+ * GPMC address space (0x0). We can test this by checking the
+ * SYS_BOOT pins.
+ *
+ * OMAP2420 SYS_BOOT[3] = 1b, then GPMC CS0 is mapped to 0x0.
+ * OMAP2430 SYS_BOOT[2:1] = 00b, then GPMC CS0 is mapped to 0x0.
+ */
+ pdata->gpmc_rom_space = SZ_1M;
+
+ if (cpu_is_omap242x()) {
+ if (!(omap_ctrl_readl(OMAP24XX_CONTROL_STATUS) &
+ OMAP2_SYSBOOT_3_MASK))
+ pdata->gpmc_rom_space = 0;
+ } else if (cpu_is_omap243x()) {
+ if (!(omap_ctrl_readl(OMAP24XX_CONTROL_STATUS) &
+ (OMAP2_SYSBOOT_2_MASK | OMAP2_SYSBOOT_1_MASK)))
+ pdata->gpmc_rom_space = 0;
+ }
+
oh = omap_hwmod_lookup(oh_name);
if (!oh) {
pr_err("Could not look up %s\n", oh_name);
return -ENODEV;
}
- pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0, NULL, 0, 0);
+ pdev = omap_device_build(DEVICE_NAME, -1, oh, pdata, sizeof(*pdata),
+ NULL, 0, 0);
WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
@@ -189,6 +189,11 @@ struct gpmc_device_timings {
bool we_xdelay;
};
+/* GPMC platform data */
+struct gpmc_platform_data {
+ u32 gpmc_rom_space;
+};
+
extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
struct gpmc_device_timings *dev_t);