diff options
Diffstat (limited to 'drivers/staging/tidspbridge/core/tiomap_io.c')
-rw-r--r-- | drivers/staging/tidspbridge/core/tiomap_io.c | 455 |
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; +} |