|
@@ -271,3 +271,124 @@ omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
|
|
}
|
|
}
|
|
|
|
|
|
static int gpmc_set_sync_mode(int cs, struct gpmc_timings *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 |
|
|
|
|
+ GPMC_CONFIG1_READMULTIPLE_SUPP |
|
|
|
|
+ (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
|
|
|
|
+ (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
|
|
|
|
+ (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
|
|
|
|
+ GPMC_CONFIG1_PAGE_LEN(2) |
|
|
|
|
+ (cpu_is_omap34xx() ? 0 :
|
|
|
|
+ (GPMC_CONFIG1_WAIT_READ_MON |
|
|
|
|
+ GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
|
|
|
|
+ GPMC_CONFIG1_DEVICESIZE_16 |
|
|
|
|
+ GPMC_CONFIG1_DEVICETYPE_NOR |
|
|
|
|
+ GPMC_CONFIG1_MUXADDDATA);
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ if (!freq) {
|
|
|
|
+ /* Very first call freq is not known */
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+ ret = omap2_onenand_setup_async(onenand_base);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(dev, "unable to set to async mode\n");
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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)
|
|
|
|
+{
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ gpmc_onenand_data = _onenand_data;
|
|
|
|
+ gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
|
|
|
|
+ gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;
|
|
|
|
+
|
|
|
|
+ if (cpu_is_omap24xx() &&
|
|
|
|
+ (gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
|
|
|
|
+ printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
|
|
|
|
+ gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
|
|
|
|
+ gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (cpu_is_omap34xx())
|
|
|
|
+ gpmc_onenand_data->flags |= ONENAND_IN_OMAP34XX;
|
|
|
|
+ else
|
|
|
|
+ gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;
|
|
|
|
+
|
|
|
|
+ err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
|
|
|
|
+ (unsigned long *)&gpmc_onenand_resource.start);
|
|
|
|
+ if (err < 0) {
|
|
|
|
+ pr_err("%s: Cannot request GPMC CS\n", __func__);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ gpmc_onenand_resource.end = gpmc_onenand_resource.start +
|
|
|
|
+ ONENAND_IO_SIZE - 1;
|
|
|
|
+
|
|
|
|
+ if (platform_device_register(&gpmc_onenand_device) < 0) {
|
|
|
|
+ pr_err("%s: Unable to register OneNAND device\n", __func__);
|
|
|
|
+ gpmc_cs_free(gpmc_onenand_data->cs);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+}
|