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/err.h>
30 #include <linux/clk.h>
31 #include <linux/mutex.h>
32 #include <linux/interrupt.h>
34 #include <asm/tlbflush.h>
36 #include <asm/arch/dsp_common.h>
39 #ifdef CONFIG_ARCH_OMAP1
40 #include <asm/arch/tc.h>
43 #if defined(CONFIG_ARCH_OMAP1)
44 #define dsp_boot_config(mode) omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
46 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
47 #define dsp_boot_config(mode) writel((mode), DSP_IPI_DSPBOOTCONFIG)
50 struct omap_dsp *omap_dsp;
52 #if defined(CONFIG_ARCH_OMAP1)
53 struct clk *dsp_ck_handle;
54 struct clk *api_ck_handle;
55 #elif defined(CONFIG_ARCH_OMAP2)
56 struct clk *dsp_fck_handle;
57 struct clk *dsp_ick_handle;
59 dsp_long_t dspmem_base, dspmem_size,
60 daram_base, daram_size,
61 saram_base, saram_size;
63 static struct cpustat {
68 #ifdef CONFIG_ARCH_OMAP1
74 int (*mem_req_cb)(void);
75 void (*mem_rel_cb)(void);
78 .stat = CPUSTAT_RESET,
82 int dsp_set_rstvect(dsp_long_t adr)
84 unsigned long *dst_adr;
86 if (adr >= DSPSPACE_SIZE)
89 dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
91 *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
95 dsp_boot_config(DSP_BOOT_CONFIG_DIRECT);
100 dsp_long_t dsp_get_rstvect(void)
102 unsigned long *dst_adr;
104 dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
105 return ((*dst_adr & 0xffff) << 16) | (*dst_adr >> 16);
108 #ifdef CONFIG_ARCH_OMAP1
109 static void simple_load_code(unsigned char *src_c, u16 *dst, int len)
112 u16 *src = (u16 *)src_c;
115 /* len must be multiple of 2. */
120 for (i = 0; i < len_w; i++) {
122 *dst = ((*src & 0x00ff) << 8) |
123 ((*src & 0xff00) >> 8);
129 /* program size must be multiple of 2 */
130 #define GBL_IDLE_TEXT_SIZE 52
131 #define GBL_IDLE_TEXT_INIT { \
133 0x3c, 0x4a, /* 0x3c4a: MOV 0x4, AR2 */ \
134 0xf4, 0x41, 0xfc, 0xff, /* 0xf441fcff: AND 0xfcff, *AR2 */ \
136 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
137 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
138 0x9a, /* 0x9a: PORT */ \
139 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
140 0x9a, /* 0x9a: PORT */ \
141 /* *IER0 = 0, *IER1 = 0 */ \
142 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
143 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
144 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
145 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
146 /* *ICR = 0xffff */ \
147 0x3c, 0x1b, /* 0x3c1b: MOV 0x1, AR3 */ \
148 0xfb, 0x61, 0xff, 0xff, /* 0xfb61ffff: MOV 0xffff, *AR3 */ \
149 0x9a, /* 0x9a: PORT */ \
151 0xf5, 0x41, 0x03, 0x00, /* 0xf5410300: OR 0x0300, *AR2 */ \
152 /* idle and loop forever */ \
153 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
154 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
155 0x20, 0x20, 0x20, /* 0x20: NOP */ \
158 /* program size must be multiple of 2 */
159 #define CPU_IDLE_TEXT_SIZE 48
160 #define CPU_IDLE_TEXT_INIT(icrh, icrl) { \
162 0x3c, 0x4b, /* 0x3c4b: MOV 0x4, AR3 */ \
163 0xf4, 0x61, 0xfc, 0xff, /* 0xf461fcff: AND 0xfcff, *AR3 */ \
165 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
166 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
167 0x9a, /* 0x9a: PORT */ \
168 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
169 0x9a, /* 0x9a: PORT */ \
170 /* *IER0 = 0, *IER1 = 0 */ \
171 0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
172 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
173 0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
174 0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
175 /* set ICR = icr */ \
176 0x3c, 0x1b, /* 0x3c1b: MOV AR3 0x1 */ \
177 0xfb, 0x61, (icrh), (icrl), /* 0xfb61****: MOV *AR3, icr */ \
178 0x9a, /* 0x9a: PORT */ \
179 /* idle and loop forever */ \
180 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
181 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
182 0x20, 0x20, 0x20 /* 0x20: nop */ \
187 * Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
188 * This value is used before DSP Gateway driver is initialized.
189 * DSP Gateway driver will overwrite this value with other value,
190 * to avoid confliction with the user program.
192 static dsp_long_t idle_boot_base = DSP_BOOT_ADR_MPUI;
194 static void dsp_gbl_idle(void)
196 unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
199 clk_enable(api_ck_handle);
202 dsp_boot_config(DSP_BOOT_CONFIG_IDLE);
204 simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
206 if (idle_boot_base == DSP_BOOT_ADR_MPUI)
207 dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
209 dsp_set_rstvect(idle_boot_base);
212 udelay(100); /* to make things stable */
213 clk_disable(api_ck_handle);
216 static void dsp_cpu_idle(void)
219 unsigned char icrh, icrl;
222 clk_enable(api_ck_handle);
226 * DMA should not sleep for DARAM/SARAM access
227 * DPLL should not sleep while any other domain is active
229 icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA | DSPREG_ICR_DPLL);
231 icrl = icr_tmp & 0xff;
233 unsigned char idle_text[CPU_IDLE_TEXT_SIZE] = CPU_IDLE_TEXT_INIT(icrh, icrl);
234 simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
237 if (idle_boot_base == DSP_BOOT_ADR_MPUI)
238 dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
240 dsp_set_rstvect(idle_boot_base);
242 udelay(100); /* to make things stable */
243 clk_disable(api_ck_handle);
246 void dsp_set_idle_boot_base(dsp_long_t adr, size_t size)
248 if (adr == idle_boot_base)
250 idle_boot_base = adr;
251 if ((size < GBL_IDLE_TEXT_SIZE) ||
252 (size < CPU_IDLE_TEXT_SIZE)) {
254 "omapdsp: size for idle program is not enough!\n");
258 /* restart idle program with new base address */
259 if (cpustat.stat == CPUSTAT_GBL_IDLE)
261 if (cpustat.stat == CPUSTAT_CPU_IDLE)
265 void dsp_reset_idle_boot_base(void)
267 idle_boot_base = DSP_BOOT_ADR_MPUI;
270 void dsp_reset_idle_boot_base(void) { }
271 #endif /* CONFIG_ARCH_OMAP1 */
273 static int init_done;
275 static int omap_dsp_init(void)
277 mutex_init(&cpustat.lock);
280 #ifdef CONFIG_ARCH_OMAP15XX
281 if (cpu_is_omap15xx()) {
282 dspmem_base = OMAP1510_DSP_BASE;
283 dspmem_size = OMAP1510_DSP_SIZE;
284 daram_base = OMAP1510_DARAM_BASE;
285 daram_size = OMAP1510_DARAM_SIZE;
286 saram_base = OMAP1510_SARAM_BASE;
287 saram_size = OMAP1510_SARAM_SIZE;
290 #ifdef CONFIG_ARCH_OMAP16XX
291 if (cpu_is_omap16xx()) {
292 dspmem_base = OMAP16XX_DSP_BASE;
293 dspmem_size = OMAP16XX_DSP_SIZE;
294 daram_base = OMAP16XX_DARAM_BASE;
295 daram_size = OMAP16XX_DARAM_SIZE;
296 saram_base = OMAP16XX_SARAM_BASE;
297 saram_size = OMAP16XX_SARAM_SIZE;
300 #ifdef CONFIG_ARCH_OMAP24XX
301 if (cpu_is_omap24xx()) {
302 dspmem_base = DSP_MEM_24XX_VIRT;
303 dspmem_size = DSP_MEM_24XX_SIZE;
304 daram_base = OMAP24XX_DARAM_BASE;
305 daram_size = OMAP24XX_DARAM_SIZE;
306 saram_base = OMAP24XX_SARAM_BASE;
307 saram_size = OMAP24XX_SARAM_SIZE;
310 #ifdef CONFIG_ARCH_OMAP34XX
311 /* To be Revisited for 3430 */
312 if (cpu_is_omap34xx()) {
316 if (dspmem_size == 0) {
317 printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
321 #if defined(CONFIG_ARCH_OMAP1)
322 dsp_ck_handle = clk_get(NULL, "dsp_ck");
323 if (IS_ERR(dsp_ck_handle)) {
324 printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n");
325 return PTR_ERR(dsp_ck_handle);
328 api_ck_handle = clk_get(NULL, "api_ck");
329 if (IS_ERR(api_ck_handle)) {
330 printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
331 if (dsp_ck_handle != NULL)
332 clk_put(dsp_ck_handle);
333 return PTR_ERR(api_ck_handle);
336 /* This is needed for McBSP init, released in late_initcall */
337 clk_enable(api_ck_handle);
343 #elif defined(CONFIG_ARCH_OMAP2)
344 dsp_fck_handle = clk_get(NULL, "dsp_fck");
345 if (IS_ERR(dsp_fck_handle)) {
346 printk(KERN_ERR "omapdsp: could not acquire dsp_fck handle.\n");
347 return PTR_ERR(dsp_fck_handle);
350 # if defined(CONFIG_ARCH_OMAP2420)
351 dsp_ick_handle = clk_get(NULL, "dsp_ick");
352 # elif defined(CONFIG_ARCH_OMAP2430)
354 * 2430 has no separate switch for DSP ICLK, but this at least
355 * involves the minimal change to the rest of the code.
357 dsp_ick_handle = clk_get(NULL, "iva2_1_ick");
359 if (IS_ERR(dsp_ick_handle)) {
360 printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
361 if (dsp_fck_handle != NULL)
362 clk_put(dsp_fck_handle);
363 return PTR_ERR(dsp_ick_handle);
368 pr_info("omap_dsp_init() done\n");
372 #if defined(CONFIG_ARCH_OMAP1)
373 static int __dsp_late_init(void)
375 clk_disable(api_ck_handle);
378 late_initcall(__dsp_late_init);
381 static void dsp_cpustat_update(void)
386 if (cpustat.req == CPUSTAT_RUN) {
387 if (cpustat.stat < CPUSTAT_RUN) {
388 #if defined(CONFIG_ARCH_OMAP1)
390 clk_enable(api_ck_handle);
393 #elif defined(CONFIG_ARCH_OMAP2)
394 __dsp_core_disable();
398 cpustat.stat = CPUSTAT_RUN;
403 /* cpustat.req < CPUSTAT_RUN */
405 if (cpustat.stat == CPUSTAT_RUN) {
406 #ifdef CONFIG_ARCH_OMAP1
407 clk_disable(api_ck_handle);
411 #ifdef CONFIG_ARCH_OMAP1
413 * (1) when ARM wants DARAM access, MPUI should be SAM and
414 * DSP needs to be on.
415 * (2) if any bits of icr is masked, we can not enter global idle.
417 if ((cpustat.req == CPUSTAT_CPU_IDLE) ||
418 (cpustat.usecount.mem > 0) ||
419 (cpustat.usecount.mem_delayed > 0) ||
420 ((cpustat.usecount.mpui > 0) && (cpustat.icrmask != 0xffff))) {
421 if (cpustat.stat != CPUSTAT_CPU_IDLE) {
423 cpustat.stat = CPUSTAT_CPU_IDLE;
429 * when ARM only needs MPUI access, MPUI can be HOM and
432 if ((cpustat.req == CPUSTAT_GBL_IDLE) ||
433 (cpustat.usecount.mpui > 0)) {
434 if (cpustat.stat != CPUSTAT_GBL_IDLE) {
436 cpustat.stat = CPUSTAT_GBL_IDLE;
440 #endif /* CONFIG_ARCH_OMAP1 */
443 * no user, no request
445 if (cpustat.stat != CPUSTAT_RESET) {
446 #if defined(CONFIG_ARCH_OMAP1)
448 #elif defined(CONFIG_ARCH_OMAP2)
449 __dsp_core_disable();
451 cpustat.stat = CPUSTAT_RESET;
455 void dsp_cpustat_request(enum cpustat_e req)
457 mutex_lock(&cpustat.lock);
459 dsp_cpustat_update();
460 mutex_unlock(&cpustat.lock);
463 enum cpustat_e dsp_cpustat_get_stat(void)
468 u16 dsp_cpustat_get_icrmask(void)
470 return cpustat.icrmask;
473 void dsp_cpustat_set_icrmask(u16 mask)
475 mutex_lock(&cpustat.lock);
476 cpustat.icrmask = mask;
477 dsp_cpustat_update();
478 mutex_unlock(&cpustat.lock);
481 #ifdef CONFIG_ARCH_OMAP1
482 void omap_dsp_request_mpui(void)
484 mutex_lock(&cpustat.lock);
485 if (cpustat.usecount.mpui++ == 0)
486 dsp_cpustat_update();
487 mutex_unlock(&cpustat.lock);
490 void omap_dsp_release_mpui(void)
492 mutex_lock(&cpustat.lock);
493 if (cpustat.usecount.mpui-- == 0) {
495 "omapdsp: unbalanced mpui request/release detected.\n"
496 " cpustat.usecount.mpui is going to be "
497 "less than zero! ... fixed to be zero.\n");
498 cpustat.usecount.mpui = 0;
500 if (cpustat.usecount.mpui == 0)
501 dsp_cpustat_update();
502 mutex_unlock(&cpustat.lock);
505 int omap_dsp_request_mem(void)
509 mutex_lock(&cpustat.lock);
510 if ((cpustat.usecount.mem++ == 0) &&
511 (cpustat.usecount.mem_delayed == 0)) {
512 if (cpustat.mem_req_cb) {
513 if ((ret = cpustat.mem_req_cb()) < 0) {
514 cpustat.usecount.mem--;
518 dsp_cpustat_update();
521 mutex_unlock(&cpustat.lock);
527 * release_mem will be delayed.
529 static void do_release_mem(struct work_struct *dummy)
531 mutex_lock(&cpustat.lock);
532 cpustat.usecount.mem_delayed = 0;
533 if (cpustat.usecount.mem == 0) {
534 dsp_cpustat_update();
535 if (cpustat.mem_rel_cb)
536 cpustat.mem_rel_cb();
538 mutex_unlock(&cpustat.lock);
541 static DECLARE_DELAYED_WORK(mem_rel_work, do_release_mem);
543 int omap_dsp_release_mem(void)
545 mutex_lock(&cpustat.lock);
547 /* cancel previous release work */
548 cancel_delayed_work(&mem_rel_work);
549 cpustat.usecount.mem_delayed = 0;
551 if (cpustat.usecount.mem-- == 0) {
553 "omapdsp: unbalanced memory request/release detected.\n"
554 " cpustat.usecount.mem is going to be "
555 "less than zero! ... fixed to be zero.\n");
556 cpustat.usecount.mem = 0;
558 if (cpustat.usecount.mem == 0) {
559 cpustat.usecount.mem_delayed = 1;
560 schedule_delayed_work(&mem_rel_work, HZ);
563 mutex_unlock(&cpustat.lock);
568 void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
570 mutex_lock(&cpustat.lock);
572 cpustat.mem_req_cb = req_cb;
573 cpustat.mem_rel_cb = rel_cb;
576 * This function must be called while mem is enabled!
578 BUG_ON(cpustat.usecount.mem == 0);
580 mutex_unlock(&cpustat.lock);
583 void dsp_unregister_mem_cb(void)
585 mutex_lock(&cpustat.lock);
586 cpustat.mem_req_cb = NULL;
587 cpustat.mem_rel_cb = NULL;
588 mutex_unlock(&cpustat.lock);
591 void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)) { }
592 void dsp_unregister_mem_cb(void) { }
593 #endif /* CONFIG_ARCH_OMAP1 */
595 arch_initcall(omap_dsp_init);
597 #ifdef CONFIG_ARCH_OMAP1
598 EXPORT_SYMBOL(omap_dsp_request_mpui);
599 EXPORT_SYMBOL(omap_dsp_release_mpui);
600 EXPORT_SYMBOL(omap_dsp_request_mem);
601 EXPORT_SYMBOL(omap_dsp_release_mem);
602 #endif /* CONFIG_ARCH_OMAP1 */
604 #ifdef CONFIG_OMAP_DSP_MODULE
605 #if defined(CONFIG_ARCH_OMAP1)
606 EXPORT_SYMBOL(dsp_ck_handle);
607 EXPORT_SYMBOL(api_ck_handle);
608 #elif defined(CONFIG_ARCH_OMAP2)
609 EXPORT_SYMBOL(dsp_fck_handle);
610 EXPORT_SYMBOL(dsp_ick_handle);
612 EXPORT_SYMBOL(omap_dsp);
613 EXPORT_SYMBOL(dspmem_base);
614 EXPORT_SYMBOL(dspmem_size);
615 EXPORT_SYMBOL(daram_base);
616 EXPORT_SYMBOL(daram_size);
617 EXPORT_SYMBOL(saram_base);
618 EXPORT_SYMBOL(saram_size);
619 EXPORT_SYMBOL(dsp_set_rstvect);
620 EXPORT_SYMBOL(dsp_get_rstvect);
621 #ifdef CONFIG_ARCH_OMAP1
622 EXPORT_SYMBOL(dsp_set_idle_boot_base);
623 EXPORT_SYMBOL(dsp_reset_idle_boot_base);
624 #endif /* CONFIG_ARCH_OMAP1 */
625 EXPORT_SYMBOL(dsp_cpustat_request);
626 EXPORT_SYMBOL(dsp_cpustat_get_stat);
627 EXPORT_SYMBOL(dsp_cpustat_get_icrmask);
628 EXPORT_SYMBOL(dsp_cpustat_set_icrmask);
629 EXPORT_SYMBOL(dsp_register_mem_cb);
630 EXPORT_SYMBOL(dsp_unregister_mem_cb);
632 EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
633 EXPORT_SYMBOL(cpu_architecture);
634 EXPORT_SYMBOL(pmd_clear_bad);