439 lines
11 KiB
C
439 lines
11 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <plat/dsp.h>
|
|
|
|
/* ----------------------------------- DSP/BIOS Bridge */
|
|
#include <dspbridge/dbdefs.h>
|
|
|
|
/* ----------------------------------- Platform Manager */
|
|
#include <dspbridge/dev.h>
|
|
#include <dspbridge/drv.h>
|
|
|
|
/* ----------------------------------- OS Adaptation Layer */
|
|
#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->dsp_ext_base_addr;
|
|
bool trace_read = false;
|
|
|
|
if (!ul_shm_base_virt) {
|
|
status = dev_get_symbol(dev_context->dev_obj,
|
|
SHMBASENAME, &ul_shm_base_virt);
|
|
}
|
|
|
|
/* Check if it is a read of Trace section */
|
|
if (!status && !ul_trace_sec_beg) {
|
|
status = dev_get_symbol(dev_context->dev_obj,
|
|
DSP_TRACESEC_BEG, &ul_trace_sec_beg);
|
|
}
|
|
|
|
if (!status && !ul_trace_sec_end) {
|
|
status = dev_get_symbol(dev_context->dev_obj,
|
|
DSP_TRACESEC_END, &ul_trace_sec_end);
|
|
}
|
|
|
|
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->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->dev_obj,
|
|
DYNEXTBASE, &ul_dyn_ext_base);
|
|
}
|
|
|
|
if (!status) {
|
|
status = dev_get_symbol(dev_context->dev_obj,
|
|
EXTBASE, &ul_ext_base);
|
|
}
|
|
|
|
if (!status) {
|
|
status = dev_get_symbol(dev_context->dev_obj,
|
|
EXTEND, &ul_ext_end);
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
|
|
if (ul_ext_end < ul_ext_base)
|
|
status = -EPERM;
|
|
|
|
if (!status) {
|
|
ul_tlb_base_virt =
|
|
dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE;
|
|
dw_ext_prog_virt_mem =
|
|
dev_context->atlb_entry[0].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->dsp_ext_base_addr =
|
|
dw_ext_prog_virt_mem;
|
|
|
|
/*
|
|
* This dsp_ext_base_addr will get cleared
|
|
* only when the board is stopped.
|
|
*/
|
|
if (!dev_context->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->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->dsp_start_add;
|
|
if (offset < base1) {
|
|
dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[2],
|
|
resources->mem_length[2]);
|
|
} else if (offset > base1 && offset < base2 + OMAP_DSP_MEM2_SIZE) {
|
|
dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[3],
|
|
resources->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->mem_base[4],
|
|
resources->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->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->dev_obj,
|
|
DSP_TRACESEC_BEG, &ul_trace_sec_beg);
|
|
if (!ret)
|
|
ret = dev_get_symbol(dev_context->dev_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->dsp_ext_base_addr);
|
|
dev_context->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->dev_obj,
|
|
SHMBASENAME, &ul_shm_base_virt);
|
|
if (dynamic_load) {
|
|
if (!ret) {
|
|
if (symbols_reloaded)
|
|
ret =
|
|
dev_get_symbol
|
|
(dev_context->dev_obj, DYNEXTBASE,
|
|
&ul_ext_base);
|
|
}
|
|
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->dev_obj, EXTEND,
|
|
&ul_ext_end);
|
|
}
|
|
} else {
|
|
if (symbols_reloaded) {
|
|
if (!ret)
|
|
ret =
|
|
dev_get_symbol
|
|
(dev_context->dev_obj, EXTBASE,
|
|
&ul_ext_base);
|
|
if (!ret)
|
|
ret =
|
|
dev_get_symbol
|
|
(dev_context->dev_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;
|
|
|
|
if (ul_ext_end < ul_ext_base)
|
|
ret = -EPERM;
|
|
|
|
if (!ret) {
|
|
ul_tlb_base_virt =
|
|
dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE;
|
|
|
|
if (symbols_reloaded) {
|
|
ret = dev_get_symbol
|
|
(dev_context->dev_obj,
|
|
DSP_TRACESEC_END, &shm0_end);
|
|
if (!ret) {
|
|
ret =
|
|
dev_get_symbol
|
|
(dev_context->dev_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].gpp_va;
|
|
} else {
|
|
dw_ext_prog_virt_mem = host_res->mem_base[1];
|
|
dw_ext_prog_virt_mem +=
|
|
(ul_ext_base - ul_dyn_ext_base);
|
|
}
|
|
|
|
dev_context->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->dsp_ext_base_addr;
|
|
/* This dsp_ext_base_addr will get cleared only when
|
|
* the board is stopped. */
|
|
if (!dev_context->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->dsp_ext_base_addr) {
|
|
MEM_UNMAP_LINEAR_ADDRESS((void *)
|
|
dev_context->dsp_ext_base_addr);
|
|
dev_context->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 omap_dsp_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->brd_state == BRD_DSP_HIBERNATION ||
|
|
dev_context->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->dmmu_base + 0x10);
|
|
|
|
dev_context->brd_state = BRD_RUNNING;
|
|
} else if (dev_context->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;
|
|
}
|