1/* 2 * tiomap_io.c 3 * 4 * DSP-BIOS Bridge driver support functions for TI OMAP processors. 5 * 6 * Implementation for the io read/write routines. 7 * 8 * Copyright (C) 2005-2006 Texas Instruments, Inc. 9 * 10 * This package is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 */ 18 19/* ----------------------------------- DSP/BIOS Bridge */ 20#include <dspbridge/dbdefs.h> 21 22/* ----------------------------------- Trace & Debug */ 23#include <dspbridge/dbc.h> 24 25/* ----------------------------------- Platform Manager */ 26#include <dspbridge/dev.h> 27#include <dspbridge/drv.h> 28 29/* ----------------------------------- OS Adaptation Layer */ 30#include <dspbridge/cfg.h> 31#include <dspbridge/wdt.h> 32 33/* ----------------------------------- specific to this file */ 34#include "_tiomap.h" 35#include "_tiomap_pwr.h" 36#include "tiomap_io.h" 37 38static u32 ul_ext_base; 39static u32 ul_ext_end; 40 41static u32 shm0_end; 42static u32 ul_dyn_ext_base; 43static u32 ul_trace_sec_beg; 44static u32 ul_trace_sec_end; 45static u32 ul_shm_base_virt; 46 47bool symbols_reloaded = true; 48 49/* 50 * ======== read_ext_dsp_data ======== 51 * Copies DSP external memory buffers to the host side buffers. 52 */ 53int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt, 54 u8 *host_buff, u32 dsp_addr, 55 u32 ul_num_bytes, u32 mem_type) 56{ 57 int status = 0; 58 struct bridge_dev_context *dev_context = dev_ctxt; 59 u32 offset; 60 u32 ul_tlb_base_virt = 0; 61 u32 ul_shm_offset_virt = 0; 62 u32 dw_ext_prog_virt_mem; 63 u32 dw_base_addr = dev_context->dw_dsp_ext_base_addr; 64 bool trace_read = false; 65 66 if (!ul_shm_base_virt) { 67 status = dev_get_symbol(dev_context->hdev_obj, 68 SHMBASENAME, &ul_shm_base_virt); 69 } 70 DBC_ASSERT(ul_shm_base_virt != 0); 71 72 /* Check if it is a read of Trace section */ 73 if (!status && !ul_trace_sec_beg) { 74 status = dev_get_symbol(dev_context->hdev_obj, 75 DSP_TRACESEC_BEG, &ul_trace_sec_beg); 76 } 77 DBC_ASSERT(ul_trace_sec_beg != 0); 78 79 if (!status && !ul_trace_sec_end) { 80 status = dev_get_symbol(dev_context->hdev_obj, 81 DSP_TRACESEC_END, &ul_trace_sec_end); 82 } 83 DBC_ASSERT(ul_trace_sec_end != 0); 84 85 if (!status) { 86 if ((dsp_addr <= ul_trace_sec_end) && 87 (dsp_addr >= ul_trace_sec_beg)) 88 trace_read = true; 89 } 90 91 /* If reading from TRACE, force remap/unmap */ 92 if (trace_read && dw_base_addr) { 93 dw_base_addr = 0; 94 dev_context->dw_dsp_ext_base_addr = 0; 95 } 96 97 if (!dw_base_addr) { 98 /* Initialize ul_ext_base and ul_ext_end */ 99 ul_ext_base = 0; 100 ul_ext_end = 0; 101 102 /* Get DYNEXT_BEG, EXT_BEG and EXT_END. */ 103 if (!status && !ul_dyn_ext_base) { 104 status = dev_get_symbol(dev_context->hdev_obj, 105 DYNEXTBASE, &ul_dyn_ext_base); 106 } 107 DBC_ASSERT(ul_dyn_ext_base != 0); 108 109 if (!status) { 110 status = dev_get_symbol(dev_context->hdev_obj, 111 EXTBASE, &ul_ext_base); 112 } 113 DBC_ASSERT(ul_ext_base != 0); 114 115 if (!status) { 116 status = dev_get_symbol(dev_context->hdev_obj, 117 EXTEND, &ul_ext_end); 118 } 119 DBC_ASSERT(ul_ext_end != 0); 120 121 /* Trace buffer is right after the shm SEG0, 122 * so set the base address to SHMBASE */ 123 if (trace_read) { 124 ul_ext_base = ul_shm_base_virt; 125 ul_ext_end = ul_trace_sec_end; 126 } 127 128 DBC_ASSERT(ul_ext_end != 0); 129 DBC_ASSERT(ul_ext_end > ul_ext_base); 130 131 if (ul_ext_end < ul_ext_base) 132 status = -EPERM; 133 134 if (!status) { 135 ul_tlb_base_virt = 136 dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE; 137 DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt); 138 dw_ext_prog_virt_mem = 139 dev_context->atlb_entry[0].ul_gpp_va; 140 141 if (!trace_read) { 142 ul_shm_offset_virt = 143 ul_shm_base_virt - ul_tlb_base_virt; 144 ul_shm_offset_virt += 145 PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base + 146 1, HW_PAGE_SIZE64KB); 147 dw_ext_prog_virt_mem -= ul_shm_offset_virt; 148 dw_ext_prog_virt_mem += 149 (ul_ext_base - ul_dyn_ext_base); 150 dev_context->dw_dsp_ext_base_addr = 151 dw_ext_prog_virt_mem; 152 153 /* 154 * This dw_dsp_ext_base_addr will get cleared 155 * only when the board is stopped. 156 */ 157 if (!dev_context->dw_dsp_ext_base_addr) 158 status = -EPERM; 159 } 160 161 dw_base_addr = dw_ext_prog_virt_mem; 162 } 163 } 164 165 if (!dw_base_addr || !ul_ext_base || !ul_ext_end) 166 status = -EPERM; 167 168 offset = dsp_addr - ul_ext_base; 169 170 if (!status) 171 memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes); 172 173 return status; 174} 175 176/* 177 * ======== write_dsp_data ======== 178 * purpose: 179 * Copies buffers to the DSP internal/external memory. 180 */ 181int write_dsp_data(struct bridge_dev_context *dev_context, 182 u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes, 183 u32 mem_type) 184{ 185 u32 offset; 186 u32 dw_base_addr = dev_context->dw_dsp_base_addr; 187 struct cfg_hostres *resources = dev_context->resources; 188 int status = 0; 189 u32 base1, base2, base3; 190 base1 = OMAP_DSP_MEM1_SIZE; 191 base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE; 192 base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE; 193 194 if (!resources) 195 return -EPERM; 196 197 offset = dsp_addr - dev_context->dw_dsp_start_add; 198 if (offset < base1) { 199 dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[2], 200 resources->dw_mem_length[2]); 201 } else if (offset > base1 && offset < base2 + OMAP_DSP_MEM2_SIZE) { 202 dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[3], 203 resources->dw_mem_length[3]); 204 offset = offset - base2; 205 } else if (offset >= base2 + OMAP_DSP_MEM2_SIZE && 206 offset < base3 + OMAP_DSP_MEM3_SIZE) { 207 dw_base_addr = MEM_LINEAR_ADDRESS(resources->dw_mem_base[4], 208 resources->dw_mem_length[4]); 209 offset = offset - base3; 210 } else { 211 return -EPERM; 212 } 213 if (ul_num_bytes) 214 memcpy((u8 *) (dw_base_addr + offset), host_buff, ul_num_bytes); 215 else 216 *((u32 *) host_buff) = dw_base_addr + offset; 217 218 return status; 219} 220 221/* 222 * ======== write_ext_dsp_data ======== 223 * purpose: 224 * Copies buffers to the external memory. 225 * 226 */ 227int write_ext_dsp_data(struct bridge_dev_context *dev_context, 228 u8 *host_buff, u32 dsp_addr, 229 u32 ul_num_bytes, u32 mem_type, 230 bool dynamic_load) 231{ 232 u32 dw_base_addr = dev_context->dw_dsp_ext_base_addr; 233 u32 dw_offset = 0; 234 u8 temp_byte1, temp_byte2; 235 u8 remain_byte[4]; 236 s32 i; 237 int ret = 0; 238 u32 dw_ext_prog_virt_mem; 239 u32 ul_tlb_base_virt = 0; 240 u32 ul_shm_offset_virt = 0; 241 struct cfg_hostres *host_res = dev_context->resources; 242 bool trace_load = false; 243 temp_byte1 = 0x0; 244 temp_byte2 = 0x0; 245 246 if (symbols_reloaded) { 247 /* Check if it is a load to Trace section */ 248 ret = dev_get_symbol(dev_context->hdev_obj, 249 DSP_TRACESEC_BEG, &ul_trace_sec_beg); 250 if (!ret) 251 ret = dev_get_symbol(dev_context->hdev_obj, 252 DSP_TRACESEC_END, 253 &ul_trace_sec_end); 254 } 255 if (!ret) { 256 if ((dsp_addr <= ul_trace_sec_end) && 257 (dsp_addr >= ul_trace_sec_beg)) 258 trace_load = true; 259 } 260 261 /* If dynamic, force remap/unmap */ 262 if ((dynamic_load || trace_load) && dw_base_addr) { 263 dw_base_addr = 0; 264 MEM_UNMAP_LINEAR_ADDRESS((void *) 265 dev_context->dw_dsp_ext_base_addr); 266 dev_context->dw_dsp_ext_base_addr = 0x0; 267 } 268 if (!dw_base_addr) { 269 if (symbols_reloaded) 270 /* Get SHM_BEG EXT_BEG and EXT_END. */ 271 ret = dev_get_symbol(dev_context->hdev_obj, 272 SHMBASENAME, &ul_shm_base_virt); 273 DBC_ASSERT(ul_shm_base_virt != 0); 274 if (dynamic_load) { 275 if (!ret) { 276 if (symbols_reloaded) 277 ret = 278 dev_get_symbol 279 (dev_context->hdev_obj, DYNEXTBASE, 280 &ul_ext_base); 281 } 282 DBC_ASSERT(ul_ext_base != 0); 283 if (!ret) { 284 /* DR OMAPS00013235 : DLModules array may be 285 * in EXTMEM. It is expected that DYNEXTMEM and 286 * EXTMEM are contiguous, so checking for the 287 * upper bound at EXTEND should be Ok. */ 288 if (symbols_reloaded) 289 ret = 290 dev_get_symbol 291 (dev_context->hdev_obj, EXTEND, 292 &ul_ext_end); 293 } 294 } else { 295 if (symbols_reloaded) { 296 if (!ret) 297 ret = 298 dev_get_symbol 299 (dev_context->hdev_obj, EXTBASE, 300 &ul_ext_base); 301 DBC_ASSERT(ul_ext_base != 0); 302 if (!ret) 303 ret = 304 dev_get_symbol 305 (dev_context->hdev_obj, EXTEND, 306 &ul_ext_end); 307 } 308 } 309 /* Trace buffer it right after the shm SEG0, so set the 310 * base address to SHMBASE */ 311 if (trace_load) 312 ul_ext_base = ul_shm_base_virt; 313 314 DBC_ASSERT(ul_ext_end != 0); 315 DBC_ASSERT(ul_ext_end > ul_ext_base); 316 if (ul_ext_end < ul_ext_base) 317 ret = -EPERM; 318 319 if (!ret) { 320 ul_tlb_base_virt = 321 dev_context->atlb_entry[0].ul_dsp_va * DSPWORDSIZE; 322 DBC_ASSERT(ul_tlb_base_virt <= ul_shm_base_virt); 323 324 if (symbols_reloaded) { 325 ret = dev_get_symbol 326 (dev_context->hdev_obj, 327 DSP_TRACESEC_END, &shm0_end); 328 if (!ret) { 329 ret = 330 dev_get_symbol 331 (dev_context->hdev_obj, DYNEXTBASE, 332 &ul_dyn_ext_base); 333 } 334 } 335 ul_shm_offset_virt = 336 ul_shm_base_virt - ul_tlb_base_virt; 337 if (trace_load) { 338 dw_ext_prog_virt_mem = 339 dev_context->atlb_entry[0].ul_gpp_va; 340 } else { 341 dw_ext_prog_virt_mem = host_res->dw_mem_base[1]; 342 dw_ext_prog_virt_mem += 343 (ul_ext_base - ul_dyn_ext_base); 344 } 345 346 dev_context->dw_dsp_ext_base_addr = 347 (u32) MEM_LINEAR_ADDRESS((void *) 348 dw_ext_prog_virt_mem, 349 ul_ext_end - ul_ext_base); 350 dw_base_addr += dev_context->dw_dsp_ext_base_addr; 351 /* This dw_dsp_ext_base_addr will get cleared only when 352 * the board is stopped. */ 353 if (!dev_context->dw_dsp_ext_base_addr) 354 ret = -EPERM; 355 } 356 } 357 if (!dw_base_addr || !ul_ext_base || !ul_ext_end) 358 ret = -EPERM; 359 360 if (!ret) { 361 for (i = 0; i < 4; i++) 362 remain_byte[i] = 0x0; 363 364 dw_offset = dsp_addr - ul_ext_base; 365 /* Also make sure the dsp_addr is < ul_ext_end */ 366 if (dsp_addr > ul_ext_end || dw_offset > dsp_addr) 367 ret = -EPERM; 368 } 369 if (!ret) { 370 if (ul_num_bytes) 371 memcpy((u8 *) dw_base_addr + dw_offset, host_buff, 372 ul_num_bytes); 373 else 374 *((u32 *) host_buff) = dw_base_addr + dw_offset; 375 } 376 /* Unmap here to force remap for other Ext loads */ 377 if ((dynamic_load || trace_load) && dev_context->dw_dsp_ext_base_addr) { 378 MEM_UNMAP_LINEAR_ADDRESS((void *) 379 dev_context->dw_dsp_ext_base_addr); 380 dev_context->dw_dsp_ext_base_addr = 0x0; 381 } 382 symbols_reloaded = false; 383 return ret; 384} 385 386int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val) 387{ 388#ifdef CONFIG_TIDSPBRIDGE_DVFS 389 u32 opplevel = 0; 390#endif 391 struct dspbridge_platform_data *pdata = 392 omap_dspbridge_dev->dev.platform_data; 393 struct cfg_hostres *resources = dev_context->resources; 394 int status = 0; 395 u32 temp; 396 397 if (!dev_context->mbox) 398 return 0; 399 400 if (!resources) 401 return -EPERM; 402 403 if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION || 404 dev_context->dw_brd_state == BRD_HIBERNATION) { 405#ifdef CONFIG_TIDSPBRIDGE_DVFS 406 if (pdata->dsp_get_opp) 407 opplevel = (*pdata->dsp_get_opp) (); 408 if (opplevel == VDD1_OPP1) { 409 if (pdata->dsp_set_min_opp) 410 (*pdata->dsp_set_min_opp) (VDD1_OPP2); 411 } 412#endif 413 /* Restart the peripheral clocks */ 414 dsp_clock_enable_all(dev_context->dsp_per_clks); 415 dsp_wdt_enable(true); 416 417 /* 418 * 2:0 AUTO_IVA2_DPLL - Enabling IVA2 DPLL auto control 419 * in CM_AUTOIDLE_PLL_IVA2 register 420 */ 421 (*pdata->dsp_cm_write)(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT, 422 OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL); 423 424 /* 425 * 7:4 IVA2_DPLL_FREQSEL - IVA2 internal frq set to 426 * 0.75 MHz - 1.0 MHz 427 * 2:0 EN_IVA2_DPLL - Enable IVA2 DPLL in lock mode 428 */ 429 (*pdata->dsp_cm_rmw_bits)(OMAP3430_IVA2_DPLL_FREQSEL_MASK | 430 OMAP3430_EN_IVA2_DPLL_MASK, 431 0x3 << OMAP3430_IVA2_DPLL_FREQSEL_SHIFT | 432 0x7 << OMAP3430_EN_IVA2_DPLL_SHIFT, 433 OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL); 434 435 /* Restore mailbox settings */ 436 omap_mbox_restore_ctx(dev_context->mbox); 437 438 /* Access MMU SYS CONFIG register to generate a short wakeup */ 439 temp = readl(resources->dw_dmmu_base + 0x10); 440 441 dev_context->dw_brd_state = BRD_RUNNING; 442 } else if (dev_context->dw_brd_state == BRD_RETENTION) { 443 /* Restart the peripheral clocks */ 444 dsp_clock_enable_all(dev_context->dsp_per_clks); 445 } 446 447 status = omap_mbox_msg_send(dev_context->mbox, mb_val); 448 449 if (status) { 450 pr_err("omap_mbox_msg_send Fail and status = %d\n", status); 451 status = -EPERM; 452 } 453 454 return 0; 455} 456