2 * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
4 * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
6 * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 #include <linux/module.h>
25 #include <linux/init.h>
26 #include <linux/sched.h>
27 #include <linux/delay.h>
29 #include <linux/clk.h>
30 #include <linux/mutex.h>
31 #include <linux/interrupt.h>
33 #include <asm/tlbflush.h>
35 #ifdef CONFIG_ARCH_OMAP1
36 #include <asm/arch/tc.h>
38 #include "dsp_common.h"
40 #if defined(CONFIG_ARCH_OMAP1)
41 #define dsp_boot_config(mode) omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
42 #elif defined(CONFIG_ARCH_OMAP2)
43 #define dsp_boot_config(mode) writel((mode), DSP_IPI_DSPBOOTCONFIG)
46 #if defined(CONFIG_ARCH_OMAP1)
47 struct clk *dsp_ck_handle;
48 struct clk *api_ck_handle;
49 #elif defined(CONFIG_ARCH_OMAP2)
50 struct clk *dsp_fck_handle;
51 struct clk *dsp_ick_handle;
53 dsp_long_t dspmem_base, dspmem_size,
54 daram_base, daram_size,
55 saram_base, saram_size;
62 #ifdef CONFIG_ARCH_OMAP1
68 int (*mem_req_cb)(void);
69 void (*mem_rel_cb)(void);
72 .stat = CPUSTAT_RESET,
76 int dsp_set_rstvect(dsp_long_t adr)
78 unsigned long *dst_adr;
80 if (adr >= DSPSPACE_SIZE)
83 dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
85 *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
89 dsp_boot_config(DSP_BOOT_CONFIG_DIRECT);
94 dsp_long_t dsp_get_rstvect(void)
96 unsigned long *dst_adr;
98 dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
99 return ((*dst_adr & 0xffff) << 16) | (*dst_adr >> 16);
102 #ifdef CONFIG_ARCH_OMAP1
103 static void simple_load_code(unsigned char *src_c, u16 *dst, int len)
106 u16 *src = (u16 *)src_c;
109 /* len must be multiple of 2. */
114 for (i = 0; i < len_w; i++) {
116 *dst = ((*src & 0x00ff) << 8) |
117 ((*src & 0xff00) >> 8);
123 /* program size must be multiple of 2 */
124 #define GBL_IDLE_TEXT_SIZE 52
125 #define GBL_IDLE_TEXT_INIT { \
127 0x3c, 0x4a, /* 0x3c4a: MOV 0x4, AR2 */ \
128 0xf4, 0x41, 0xfc, 0xff, /* 0xf441fcff: AND 0xfcff, *AR2 */ \
130 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
131 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
132 0x9a, /* 0x9a: PORT */ \
133 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
134 0x9a, /* 0x9a: PORT */ \
135 /* *IER0 = 0, *IER1 = 0 */ \
136 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
137 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
138 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
139 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
140 /* *ICR = 0xffff */ \
141 0x3c, 0x1b, /* 0x3c1b: MOV 0x1, AR3 */ \
142 0xfb, 0x61, 0xff, 0xff, /* 0xfb61ffff: MOV 0xffff, *AR3 */ \
143 0x9a, /* 0x9a: PORT */ \
145 0xf5, 0x41, 0x03, 0x00, /* 0xf5410300: OR 0x0300, *AR2 */ \
146 /* idle and loop forever */ \
147 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
148 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
149 0x20, 0x20, 0x20, /* 0x20: NOP */ \
152 /* program size must be multiple of 2 */
153 #define CPU_IDLE_TEXT_SIZE 48
154 #define CPU_IDLE_TEXT_INIT(icrh, icrl) { \
156 0x3c, 0x4b, /* 0x3c4b: MOV 0x4, AR3 */ \
157 0xf4, 0x61, 0xfc, 0xff, /* 0xf461fcff: AND 0xfcff, *AR3 */ \
159 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
160 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
161 0x9a, /* 0x9a: PORT */ \
162 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
163 0x9a, /* 0x9a: PORT */ \
164 /* *IER0 = 0, *IER1 = 0 */ \
165 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
166 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
167 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
168 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
169 /* set ICR = icr */ \
170 0x3c, 0x1b, /* 0x3c1b: MOV AR3 0x1 */ \
171 0xfb, 0x61, (icrh), (icrl), /* 0xfb61****: MOV *AR3, icr */ \
172 0x9a, /* 0x9a: PORT */ \
173 /* idle and loop forever */ \
174 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
175 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
176 0x20, 0x20, 0x20 /* 0x20: nop */ \
181 * Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
182 * This value is used before DSP Gateway driver is initialized.
183 * DSP Gateway driver will overwrite this value with other value,
184 * to avoid confliction with the user program.
186 static dsp_long_t idle_boot_base = DSP_BOOT_ADR_MPUI;
188 static void dsp_gbl_idle(void)
190 unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
193 clk_enable(api_ck_handle);
196 dsp_boot_config(DSP_BOOT_CONFIG_IDLE);
198 simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
200 if (idle_boot_base == DSP_BOOT_ADR_MPUI)
201 dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
203 dsp_set_rstvect(idle_boot_base);
206 udelay(100); /* to make things stable */
207 clk_disable(api_ck_handle);
210 static void dsp_cpu_idle(void)
213 unsigned char icrh, icrl;
216 clk_enable(api_ck_handle);
220 * DMA should not sleep for DARAM/SARAM access
221 * DPLL should not sleep while any other domain is active
223 icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA | DSPREG_ICR_DPLL);
225 icrl = icr_tmp & 0xff;
227 unsigned char idle_text[CPU_IDLE_TEXT_SIZE] = CPU_IDLE_TEXT_INIT(icrh, icrl);
228 simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
231 if (idle_boot_base == DSP_BOOT_ADR_MPUI)
232 dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
234 dsp_set_rstvect(idle_boot_base);
236 udelay(100); /* to make things stable */
237 clk_disable(api_ck_handle);
240 void dsp_set_idle_boot_base(dsp_long_t adr, size_t size)
242 if (adr == idle_boot_base)
244 idle_boot_base = adr;
245 if ((size < GBL_IDLE_TEXT_SIZE) ||
246 (size < CPU_IDLE_TEXT_SIZE)) {
248 "omapdsp: size for idle program is not enough!\n");
252 /* restart idle program with new base address */
253 if (cpustat.stat == CPUSTAT_GBL_IDLE)
255 if (cpustat.stat == CPUSTAT_CPU_IDLE)
259 void dsp_reset_idle_boot_base(void)
261 idle_boot_base = DSP_BOOT_ADR_MPUI;
264 #endif /* CONFIG_ARCH_OMAP1 */
266 static int init_done;
268 static int __init omap_dsp_init(void)
270 mutex_init(&cpustat.lock);
273 #ifdef CONFIG_ARCH_OMAP15XX
274 if (cpu_is_omap1510()) {
275 dspmem_base = OMAP1510_DSP_BASE;
276 dspmem_size = OMAP1510_DSP_SIZE;
277 daram_base = OMAP1510_DARAM_BASE;
278 daram_size = OMAP1510_DARAM_SIZE;
279 saram_base = OMAP1510_SARAM_BASE;
280 saram_size = OMAP1510_SARAM_SIZE;
283 #ifdef CONFIG_ARCH_OMAP16XX
284 if (cpu_is_omap16xx()) {
285 dspmem_base = OMAP16XX_DSP_BASE;
286 dspmem_size = OMAP16XX_DSP_SIZE;
287 daram_base = OMAP16XX_DARAM_BASE;
288 daram_size = OMAP16XX_DARAM_SIZE;
289 saram_base = OMAP16XX_SARAM_BASE;
290 saram_size = OMAP16XX_SARAM_SIZE;
293 #ifdef CONFIG_ARCH_OMAP24XX
294 if (cpu_is_omap24xx()) {
295 dspmem_base = DSP_MEM_24XX_VIRT;
296 dspmem_size = DSP_MEM_24XX_SIZE;
297 daram_base = OMAP24XX_DARAM_BASE;
298 daram_size = OMAP24XX_DARAM_SIZE;
299 saram_base = OMAP24XX_SARAM_BASE;
300 saram_size = OMAP24XX_SARAM_SIZE;
303 if (dspmem_size == 0) {
304 printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
310 #if defined(CONFIG_ARCH_OMAP1)
311 dsp_ck_handle = clk_get(NULL, "dsp_ck");
312 if (IS_ERR(dsp_ck_handle)) {
313 printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n");
314 return PTR_ERR(dsp_ck_handle);
317 api_ck_handle = clk_get(NULL, "api_ck");
318 if (IS_ERR(api_ck_handle)) {
319 printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
320 return PTR_ERR(api_ck_handle);
323 /* This is needed for McBSP init, released in late_initcall */
324 clk_enable(api_ck_handle);
330 #elif defined(CONFIG_ARCH_OMAP2)
331 dsp_fck_handle = clk_get(NULL, "dsp_fck");
332 if (IS_ERR(dsp_fck_handle)) {
333 printk(KERN_ERR "omapdsp: could not acquire dsp_fck handle.\n");
334 return PTR_ERR(dsp_fck_handle);
337 dsp_ick_handle = clk_get(NULL, "dsp_ick");
338 if (IS_ERR(dsp_ick_handle)) {
339 printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
340 return PTR_ERR(dsp_ick_handle);
345 printk(KERN_INFO "omap_dsp_init() done\n");
349 #if defined(CONFIG_ARCH_OMAP1)
350 static int dsp_late_init(void)
352 clk_disable(api_ck_handle);
355 late_initcall(dsp_late_init);
358 static void dsp_cpustat_update(void)
363 if (cpustat.req == CPUSTAT_RUN) {
364 if (cpustat.stat < CPUSTAT_RUN) {
365 #if defined(CONFIG_ARCH_OMAP1)
367 clk_enable(api_ck_handle);
370 #elif defined(CONFIG_ARCH_OMAP2)
371 __dsp_core_disable();
375 cpustat.stat = CPUSTAT_RUN;
376 enable_irq(INT_DSP_MMU);
381 /* cpustat.req < CPUSTAT_RUN */
383 if (cpustat.stat == CPUSTAT_RUN) {
384 disable_irq(INT_DSP_MMU);
385 #ifdef CONFIG_ARCH_OMAP1
386 clk_disable(api_ck_handle);
390 #ifdef CONFIG_ARCH_OMAP1
392 * (1) when ARM wants DARAM access, MPUI should be SAM and
393 * DSP needs to be on.
394 * (2) if any bits of icr is masked, we can not enter global idle.
396 if ((cpustat.req == CPUSTAT_CPU_IDLE) ||
397 (cpustat.usecount.mem > 0) ||
398 (cpustat.usecount.mem_delayed > 0) ||
399 ((cpustat.usecount.mpui > 0) && (cpustat.icrmask != 0xffff))) {
400 if (cpustat.stat != CPUSTAT_CPU_IDLE) {
402 cpustat.stat = CPUSTAT_CPU_IDLE;
408 * when ARM only needs MPUI access, MPUI can be HOM and
411 if ((cpustat.req == CPUSTAT_GBL_IDLE) ||
412 (cpustat.usecount.mpui > 0)) {
413 if (cpustat.stat != CPUSTAT_GBL_IDLE) {
415 cpustat.stat = CPUSTAT_GBL_IDLE;
419 #endif /* CONFIG_ARCH_OMAP1 */
422 * no user, no request
424 if (cpustat.stat != CPUSTAT_RESET) {
425 #if defined(CONFIG_ARCH_OMAP1)
427 #elif defined(CONFIG_ARCH_OMAP2)
428 __dsp_core_disable();
430 cpustat.stat = CPUSTAT_RESET;
434 void dsp_cpustat_request(enum cpustat_e req)
436 mutex_lock(&cpustat.lock);
438 dsp_cpustat_update();
439 mutex_unlock(&cpustat.lock);
442 enum cpustat_e dsp_cpustat_get_stat(void)
447 u16 dsp_cpustat_get_icrmask(void)
449 return cpustat.icrmask;
452 void dsp_cpustat_set_icrmask(u16 mask)
454 mutex_lock(&cpustat.lock);
455 cpustat.icrmask = mask;
456 dsp_cpustat_update();
457 mutex_unlock(&cpustat.lock);
460 #ifdef CONFIG_ARCH_OMAP1
461 void omap_dsp_request_mpui(void)
463 mutex_lock(&cpustat.lock);
464 if (cpustat.usecount.mpui++ == 0)
465 dsp_cpustat_update();
466 mutex_unlock(&cpustat.lock);
469 void omap_dsp_release_mpui(void)
471 mutex_lock(&cpustat.lock);
472 if (cpustat.usecount.mpui-- == 0) {
474 "omapdsp: unbalanced mpui request/release detected.\n"
475 " cpustat.usecount.mpui is going to be "
476 "less than zero! ... fixed to be zero.\n");
477 cpustat.usecount.mpui = 0;
479 if (cpustat.usecount.mpui == 0)
480 dsp_cpustat_update();
481 mutex_unlock(&cpustat.lock);
484 int omap_dsp_request_mem(void)
488 mutex_lock(&cpustat.lock);
489 if ((cpustat.usecount.mem++ == 0) &&
490 (cpustat.usecount.mem_delayed == 0)) {
491 if (cpustat.mem_req_cb) {
492 if ((ret = cpustat.mem_req_cb()) < 0) {
493 cpustat.usecount.mem--;
497 dsp_cpustat_update();
500 mutex_unlock(&cpustat.lock);
506 * release_mem will be delayed.
508 static void do_release_mem(void)
510 mutex_lock(&cpustat.lock);
511 cpustat.usecount.mem_delayed = 0;
512 if (cpustat.usecount.mem == 0) {
513 dsp_cpustat_update();
514 if (cpustat.mem_rel_cb)
515 cpustat.mem_rel_cb();
517 mutex_unlock(&cpustat.lock);
520 static DECLARE_WORK(mem_rel_work, (void (*)(void *))do_release_mem, NULL);
522 int omap_dsp_release_mem(void)
524 mutex_lock(&cpustat.lock);
526 /* cancel previous release work */
527 cancel_delayed_work(&mem_rel_work);
528 cpustat.usecount.mem_delayed = 0;
530 if (cpustat.usecount.mem-- == 0) {
532 "omapdsp: unbalanced memory request/release detected.\n"
533 " cpustat.usecount.mem is going to be "
534 "less than zero! ... fixed to be zero.\n");
535 cpustat.usecount.mem = 0;
537 if (cpustat.usecount.mem == 0) {
538 cpustat.usecount.mem_delayed = 1;
539 schedule_delayed_work(&mem_rel_work, HZ);
542 mutex_unlock(&cpustat.lock);
547 void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
549 mutex_lock(&cpustat.lock);
551 cpustat.mem_req_cb = req_cb;
552 cpustat.mem_rel_cb = rel_cb;
555 * This function must be called while mem is enabled!
557 BUG_ON(cpustat.usecount.mem == 0);
559 mutex_unlock(&cpustat.lock);
562 void dsp_unregister_mem_cb(void)
564 mutex_lock(&cpustat.lock);
565 cpustat.mem_req_cb = NULL;
566 cpustat.mem_rel_cb = NULL;
567 mutex_unlock(&cpustat.lock);
569 #endif /* CONFIG_ARCH_OMAP1 */
572 * Audio power control function prototypes and defaults
573 * (To be overridden with board specific functions)
575 static void generic_audio_pwr_up_request(int stage)
577 printk(KERN_ERR "audio power-up request function is not defined.\n");
580 void (*omap_dsp_audio_pwr_up_request)(int stage) = generic_audio_pwr_up_request;
581 EXPORT_SYMBOL(omap_dsp_audio_pwr_up_request);
583 static void generic_audio_pwr_down_request(int stage)
585 printk(KERN_ERR "audio power-down request function is not defined.\n");
588 void (*omap_dsp_audio_pwr_down_request)(int stage) = generic_audio_pwr_down_request;
589 EXPORT_SYMBOL(omap_dsp_audio_pwr_down_request);
591 arch_initcall(omap_dsp_init);
593 #ifdef CONFIG_ARCH_OMAP1
594 EXPORT_SYMBOL(omap_dsp_request_mpui);
595 EXPORT_SYMBOL(omap_dsp_release_mpui);
596 EXPORT_SYMBOL(omap_dsp_request_mem);
597 EXPORT_SYMBOL(omap_dsp_release_mem);
598 #endif /* CONFIG_ARCH_OMAP1 */
600 #ifdef CONFIG_OMAP_DSP_MODULE
601 #if defined(CONFIG_ARCH_OMAP1)
602 EXPORT_SYMBOL(dsp_ck_handle);
603 EXPORT_SYMBOL(api_ck_handle);
604 #elif defined(CONFIG_ARCH_OMAP2)
605 EXPORT_SYMBOL(dsp_fck_handle);
606 EXPORT_SYMBOL(dsp_ick_handle);
608 EXPORT_SYMBOL(dspmem_base);
609 EXPORT_SYMBOL(dspmem_size);
610 EXPORT_SYMBOL(daram_base);
611 EXPORT_SYMBOL(daram_size);
612 EXPORT_SYMBOL(saram_base);
613 EXPORT_SYMBOL(saram_size);
614 EXPORT_SYMBOL(dsp_set_rstvect);
615 EXPORT_SYMBOL(dsp_get_rstvect);
616 #ifdef CONFIG_ARCH_OMAP1
617 EXPORT_SYMBOL(dsp_set_idle_boot_base);
618 EXPORT_SYMBOL(dsp_reset_idle_boot_base);
619 #endif /* CONFIG_ARCH_OMAP1 */
620 EXPORT_SYMBOL(dsp_cpustat_request);
621 EXPORT_SYMBOL(dsp_cpustat_get_stat);
622 EXPORT_SYMBOL(dsp_cpustat_get_icrmask);
623 EXPORT_SYMBOL(dsp_cpustat_set_icrmask);
624 #ifdef CONFIG_ARCH_OMAP1
625 EXPORT_SYMBOL(dsp_register_mem_cb);
626 EXPORT_SYMBOL(dsp_unregister_mem_cb);
627 #endif /* CONFIG_ARCH_OMAP1 */
629 EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
630 EXPORT_SYMBOL(cpu_architecture);
631 EXPORT_SYMBOL(pmd_clear_bad);