|
@@ -756,3 +756,94 @@ static int gpmc_free_irq(void)
|
|
|
irq_set_chip(gpmc_client_irq[i].irq, &no_irq_chip);
|
|
|
irq_modify_status(gpmc_client_irq[i].irq, 0, 0);
|
|
|
}
|
|
|
+
|
|
|
+ irq_free_descs(gpmc_irq_start, GPMC_NR_IRQ);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void gpmc_mem_exit(void)
|
|
|
+{
|
|
|
+ int cs;
|
|
|
+
|
|
|
+ for (cs = 0; cs < GPMC_CS_NUM; cs++) {
|
|
|
+ if (!gpmc_cs_mem_enabled(cs))
|
|
|
+ continue;
|
|
|
+ gpmc_cs_delete_mem(cs);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static int gpmc_mem_init(void)
|
|
|
+{
|
|
|
+ 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;
|
|
|
+ /* In apollon the CS0 is mapped as 0x0000 0000 */
|
|
|
+ if (machine_is_omap_apollon())
|
|
|
+ boot_rom_space = 0;
|
|
|
+ gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
|
|
|
+ gpmc_mem_root.end = GPMC_MEM_END;
|
|
|
+
|
|
|
+ /* Reserve all regions that has been set up by bootloader */
|
|
|
+ for (cs = 0; cs < GPMC_CS_NUM; cs++) {
|
|
|
+ u32 base, size;
|
|
|
+
|
|
|
+ if (!gpmc_cs_mem_enabled(cs))
|
|
|
+ continue;
|
|
|
+ gpmc_cs_get_memconf(cs, &base, &size);
|
|
|
+ rc = gpmc_cs_insert_mem(cs, base, size);
|
|
|
+ if (IS_ERR_VALUE(rc)) {
|
|
|
+ while (--cs >= 0)
|
|
|
+ if (gpmc_cs_mem_enabled(cs))
|
|
|
+ gpmc_cs_delete_mem(cs);
|
|
|
+ return rc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+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);
|
|
|
+}
|
|
|
+
|
|
|
+/* XXX: 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;
|
|
|
+ /* XXX: mux check required ? */
|
|
|
+ if (mux) {
|
|
|
+ /* XXX: t_avdp not to be required for sync, only added for tusb
|
|
|
+ * this indirectly necessitates requirement of t_avdp_r and
|
|
|
+ * t_avdp_w instead of having a single t_avdp
|
|
|
+ */
|
|
|
+ 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);
|
|
|
+
|
|
|
+ /* oe_on */
|
|
|
+ temp = dev_t->t_oeasu; /* XXX: remove this ? */
|
|
|
+ if (mux) {
|
|
|
+ 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);
|