aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/tidspbridge/core/tiomap_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/tidspbridge/core/tiomap_io.c')
-rw-r--r--drivers/staging/tidspbridge/core/tiomap_io.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/drivers/staging/tidspbridge/core/tiomap_io.c b/drivers/staging/tidspbridge/core/tiomap_io.c
new file mode 100644
index 000000000000..190c028afe9b
--- /dev/null
+++ b/drivers/staging/tidspbridge/core/tiomap_io.c
@@ -0,0 +1,455 @@
+/*
+ * tiomap_io.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * Implementation for the io read/write routines.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- Platform Manager */
+#include <dspbridge/dev.h>
+#include <dspbridge/drv.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/cfg.h>
+#include <dspbridge/wdt.h>
+
+/* ----------------------------------- specific to this file */
+#include "_tiomap.h"
+#include "_tiomap_pwr.h"
+#include "tiomap_io.h"
+
+static u32 ul_ext_base;
+static u32 ul_ext_end;
+
+static u32 shm0_end;
+static u32 ul_dyn_ext_base;
+static u32 ul_trace_sec_beg;
+static u32 ul_trace_sec_end;
+static u32 ul_shm_base_virt;
+
+bool symbols_reloaded = true;
+
+/*
+ * ======== read_ext_dsp_data ========
+ * Copies DSP external memory buffers to the host side buffers.
+ */
+int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type)
+{
+ int status = 0;
+ struct bridge_dev_context *dev_context = dev_ctxt;
+ u32 offset;
+ u32 ul_tlb_base_virt = 0;
+ u32 ul_shm_offset_virt = 0;
+ u32 dw_ext_prog_virt_mem;
+ u32 dw_base_addr = dev_context->dw_dsp_ext_base_addr;
+ bool trace_read = false;
+
+ if (!ul_shm_base_virt) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ SHMBASENAME, &ul_shm_base_virt);
+ }
+ DBC_ASSERT(ul_shm_base_virt != 0);
+
+ /* Check if it is a read of Trace section */
+ if (!status && !ul_trace_sec_beg) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_BEG, &ul_trace_sec_beg);
+ }
+ DBC_ASSERT(ul_trace_sec_beg != 0);
+
+ if (!status && !ul_trace_sec_end) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_END, &ul_trace_sec_end);
+ }
+ DBC_ASSERT(ul_trace_sec_end != 0);
+
+ if (!status) {
+ if ((dsp_addr <= ul_trace_sec_end) &&
+ (dsp_addr >= ul_trace_sec_beg))
+ trace_read = true;
+ }
+
+ /* If reading from TRACE, force remap/unmap */
+ if (trace_read && dw_base_addr) {
+ dw_base_addr = 0;
+ dev_context->dw_dsp_ext_base_addr = 0;
+ }
+
+ if (!dw_base_addr) {
+ /* Initialize ul_ext_base and ul_ext_end */
+ ul_ext_base = 0;
+ ul_ext_end = 0;
+
+ /* Get DYNEXT_BEG, EXT_BEG and EXT_END. */
+ if (!status && !ul_dyn_ext_base) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ DYNEXTBASE, &ul_dyn_ext_base);
+ }
+ DBC_ASSERT(ul_dyn_ext_base != 0);
+
+ if (!status) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ EXTBASE, &ul_ext_base);
+ }
+ DBC_ASSERT(ul_ext_base != 0);
+
+ if (!status) {
+ status = dev_get_symbol(dev_context->hdev_obj,
+ EXTEND, &ul_ext_end);
+ }
+ DBC_ASSERT(ul_ext_end != 0);
+
+ /* Trace buffer is right after the shm SEG0,
+ * so set the base address to SHMBASE */
+ if (trace_read) {
+ ul_ext_base = ul_shm_base_virt;
+ ul_ext_end = ul_trace_sec_end;
+ }
+
+ DBC_ASSERT(ul_ext_end != 0);
+ DBC_ASSERT(ul_ext_end > ul_ext_base);
+
+ if (ul_ext_end < ul_ext_base)
+ status = -EPERM;
+
+ if (!status) {
+ ul_tlb_base_virt =
+ dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
+ DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
+ dw_ext_prog_virt_mem =
+ dev_context->atlb_entry[0].ul_gpp_va;
+
+ if (!trace_read) {
+ ul_shm_offset_virt =
+ ul_shm_base_virt - ul_tlb_base_virt;
+ ul_shm_offset_virt +=
+ PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base +
+ 1, HW_PAGE_SIZE64KB);
+ dw_ext_prog_virt_mem -= ul_shm_offset_virt;
+ dw_ext_prog_virt_mem +=
+ (ul_ext_base - ul_dyn_ext_base);
+ dev_context->dw_dsp_ext_base_addr =
+ dw_ext_prog_virt_mem;
+
+ /*
+ * This dw_dsp_ext_base_addr will get cleared
+ * only when the board is stopped.
+ */
+ if (!dev_context->dw_dsp_ext_base_addr)
+ status = -EPERM;
+ }
+
+ dw_base_addr = dw_ext_prog_virt_mem;
+ }
+ }
+
+ if (!dw_base_addr || !ul_ext_base || !ul_ext_end)
+ status = -EPERM;
+
+ offset = dsp_addr - ul_ext_base;
+
+ if (!status)
+ memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes);
+
+ return status;
+}
+
+/*
+ * ======== write_dsp_data ========
+ * purpose:
+ * Copies buffers to the DSP internal/external memory.
+ */
+int write_dsp_data(struct bridge_dev_context *dev_context,
+ u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes,
+ u32 mem_type)
+{
+ u32 offset;
+ u32 dw_base_addr = dev_context->dw_dsp_base_addr;
+ struct cfg_hostres *resources = dev_context->resources;
+ int status = 0;
+ u32 base1, base2, base3;
+ base1 = OMAP_DSP_MEM1_SIZE;
+ base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE;
+ base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE;
+
+ if (!resources)
+ return -EPERM;
+
+ offset = dsp_addr - dev_context->dw_dsp_start_add;
+ if (offset < base1) {
+ dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[2],
+ resources->dw_mem_length[2]);
+ } else if (offset > base1 && offset < base2 + OMAP_DSP_MEM2_SIZE) {
+ dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[3],
+ resources->dw_mem_length[3]);
+ offset = offset - base2;
+ } else if (offset >= base2 + OMAP_DSP_MEM2_SIZE &&
+ offset < base3 + OMAP_DSP_MEM3_SIZE) {
+ dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[4],
+ resources->dw_mem_length[4]);
+ offset = offset - base3;
+ } else {
+ return -EPERM;
+ }
+ if (ul_num_bytes)
+ memcpy((u8 *) (dw_base_addr + offset), host_buff, ul_num_bytes);
+ else
+ *((u32 *) host_buff) = dw_base_addr + offset;
+
+ return status;
+}
+
+/*
+ * ======== write_ext_dsp_data ========
+ * purpose:
+ * Copies buffers to the external memory.
+ *
+ */
+int write_ext_dsp_data(struct bridge_dev_context *dev_context,
+ u8 *host_buff, u32 dsp_addr,
+ u32 ul_num_bytes, u32 mem_type,
+ bool dynamic_load)
+{
+ u32 dw_base_addr = dev_context->dw_dsp_ext_base_addr;
+ u32 dw_offset = 0;
+ u8 temp_byte1, temp_byte2;
+ u8 remain_byte[4];
+ s32 i;
+ int ret = 0;
+ u32 dw_ext_prog_virt_mem;
+ u32 ul_tlb_base_virt = 0;
+ u32 ul_shm_offset_virt = 0;
+ struct cfg_hostres *host_res = dev_context->resources;
+ bool trace_load = false;
+ temp_byte1 = 0x0;
+ temp_byte2 = 0x0;
+
+ if (symbols_reloaded) {
+ /* Check if it is a load to Trace section */
+ ret = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_BEG, &ul_trace_sec_beg);
+ if (!ret)
+ ret = dev_get_symbol(dev_context->hdev_obj,
+ DSP_TRACESEC_END,
+ &ul_trace_sec_end);
+ }
+ if (!ret) {
+ if ((dsp_addr <= ul_trace_sec_end) &&
+ (dsp_addr >= ul_trace_sec_beg))
+ trace_load = true;
+ }
+
+ /* If dynamic, force remap/unmap */
+ if ((dynamic_load || trace_load) && dw_base_addr) {
+ dw_base_addr = 0;
+ MEM_UNMAP_LINEAR_ADDRESS((void *)
+ dev_context->dw_dsp_ext_base_addr);
+ dev_context->dw_dsp_ext_base_addr = 0x0;
+ }
+ if (!dw_base_addr) {
+ if (symbols_reloaded)
+ /* Get SHM_BEG EXT_BEG and EXT_END. */
+ ret = dev_get_symbol(dev_context->hdev_obj,
+ SHMBASENAME, &ul_shm_base_virt);
+ DBC_ASSERT(ul_shm_base_virt != 0);
+ if (dynamic_load) {
+ if (!ret) {
+ if (symbols_reloaded)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, DYNEXTBASE,
+ &ul_ext_base);
+ }
+ DBC_ASSERT(ul_ext_base != 0);
+ if (!ret) {
+ /* DR OMAPS00013235 : DLModules array may be
+ * in EXTMEM. It is expected that DYNEXTMEM and
+ * EXTMEM are contiguous, so checking for the
+ * upper bound at EXTEND should be Ok. */
+ if (symbols_reloaded)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, EXTEND,
+ &ul_ext_end);
+ }
+ } else {
+ if (symbols_reloaded) {
+ if (!ret)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, EXTBASE,
+ &ul_ext_base);
+ DBC_ASSERT(ul_ext_base != 0);
+ if (!ret)
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, EXTEND,
+ &ul_ext_end);
+ }
+ }
+ /* Trace buffer it right after the shm SEG0, so set the
+ * base address to SHMBASE */
+ if (trace_load)
+ ul_ext_base = ul_shm_base_virt;
+
+ DBC_ASSERT(ul_ext_end != 0);
+ DBC_ASSERT(ul_ext_end > ul_ext_base);
+ if (ul_ext_end < ul_ext_base)
+ ret = -EPERM;
+
+ if (!ret) {
+ ul_tlb_base_virt =
+ dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE;
+ DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt);
+
+ if (symbols_reloaded) {
+ ret = dev_get_symbol
+ (dev_context->hdev_obj,
+ DSP_TRACESEC_END, &shm0_end);
+ if (!ret) {
+ ret =
+ dev_get_symbol
+ (dev_context->hdev_obj, DYNEXTBASE,
+ &ul_dyn_ext_base);
+ }
+ }
+ ul_shm_offset_virt =
+ ul_shm_base_virt - ul_tlb_base_virt;
+ if (trace_load) {
+ dw_ext_prog_virt_mem =
+ dev_context->atlb_entry[0].ul_gpp_va;
+ } else {
+ dw_ext_prog_virt_mem = host_res->dw_mem_base[1];
+ dw_ext_prog_virt_mem +=
+ (ul_ext_base - ul_dyn_ext_base);
+ }
+
+ dev_context->dw_dsp_ext_base_addr =
+ (u32) MEM_LINEAR_ADDRESS((void *)
+ dw_ext_prog_virt_mem,
+ ul_ext_end - ul_ext_base);
+ dw_base_addr += dev_context->dw_dsp_ext_base_addr;
+ /* This dw_dsp_ext_base_addr will get cleared only when
+ * the board is stopped. */
+ if (!dev_context->dw_dsp_ext_base_addr)
+ ret = -EPERM;
+ }
+ }
+ if (!dw_base_addr || !ul_ext_base || !ul_ext_end)
+ ret = -EPERM;
+
+ if (!ret) {
+ for (i = 0; i < 4; i++)
+ remain_byte[i] = 0x0;
+
+ dw_offset = dsp_addr - ul_ext_base;
+ /* Also make sure the dsp_addr is < ul_ext_end */
+ if (dsp_addr > ul_ext_end || dw_offset > dsp_addr)
+ ret = -EPERM;
+ }
+ if (!ret) {
+ if (ul_num_bytes)
+ memcpy((u8 *) dw_base_addr + dw_offset, host_buff,
+ ul_num_bytes);
+ else
+ *((u32 *) host_buff) = dw_base_addr + dw_offset;
+ }
+ /* Unmap here to force remap for other Ext loads */
+ if ((dynamic_load || trace_load) && dev_context->dw_dsp_ext_base_addr) {
+ MEM_UNMAP_LINEAR_ADDRESS((void *)
+ dev_context->dw_dsp_ext_base_addr);
+ dev_context->dw_dsp_ext_base_addr = 0x0;
+ }
+ symbols_reloaded = false;
+ return ret;
+}
+
+int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
+{
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ u32 opplevel = 0;
+#endif
+ struct dspbridge_platform_data *pdata =
+ omap_dspbridge_dev->dev.platform_data;
+ struct cfg_hostres *resources = dev_context->resources;
+ int status = 0;
+ u32 temp;
+
+ if (!dev_context->mbox)
+ return 0;
+
+ if (!resources)
+ return -EPERM;
+
+ if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
+ dev_context->dw_brd_state == BRD_HIBERNATION) {
+#ifdef CONFIG_TIDSPBRIDGE_DVFS
+ if (pdata->dsp_get_opp)
+ opplevel = (*pdata->dsp_get_opp) ();
+ if (opplevel == VDD1_OPP1) {
+ if (pdata->dsp_set_min_opp)
+ (*pdata->dsp_set_min_opp) (VDD1_OPP2);
+ }
+#endif
+ /* Restart the peripheral clocks */
+ dsp_clock_enable_all(dev_context->dsp_per_clks);
+ dsp_wdt_enable(true);
+
+ /*
+ * 2:0 AUTO_IVA2_DPLL - Enabling IVA2 DPLL auto control
+ * in CM_AUTOIDLE_PLL_IVA2 register
+ */
+ (*pdata->dsp_cm_write)(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL);
+
+ /*
+ * 7:4 IVA2_DPLL_FREQSEL - IVA2 internal frq set to
+ * 0.75 MHz - 1.0 MHz
+ * 2:0 EN_IVA2_DPLL - Enable IVA2 DPLL in lock mode
+ */
+ (*pdata->dsp_cm_rmw_bits)(OMAP3430_IVA2_DPLL_FREQSEL_MASK |
+ OMAP3430_EN_IVA2_DPLL_MASK,
+ 0x3 << OMAP3430_IVA2_DPLL_FREQSEL_SHIFT |
+ 0x7 << OMAP3430_EN_IVA2_DPLL_SHIFT,
+ OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL);
+
+ /* Restore mailbox settings */
+ omap_mbox_restore_ctx(dev_context->mbox);
+
+ /* Access MMU SYS CONFIG register to generate a short wakeup */
+ temp = readl(resources->dw_dmmu_base + 0x10);
+
+ dev_context->dw_brd_state = BRD_RUNNING;
+ } else if (dev_context->dw_brd_state == BRD_RETENTION) {
+ /* Restart the peripheral clocks */
+ dsp_clock_enable_all(dev_context->dsp_per_clks);
+ }
+
+ status = omap_mbox_msg_send(dev_context->mbox, mb_val);
+
+ if (status) {
+ pr_err("omap_mbox_msg_send Fail and status = %d\n", status);
+ status = -EPERM;
+ }
+
+ return 0;
+}