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 * Conversion to mempool API and ARM MMU section mapping
9 * by Paul Mundt <paul.mundt@nokia.com>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27 #include <linux/module.h>
28 #include <linux/init.h>
31 #include <linux/interrupt.h>
32 #include <linux/delay.h>
33 #include <linux/mempool.h>
34 #include <linux/clk.h>
35 #include <asm/uaccess.h>
38 #include <asm/pgalloc.h>
39 #include <asm/pgtable.h>
40 #include <asm/arch/tc.h>
41 #include <asm/arch/omapfb.h>
42 #include <asm/arch/dsp.h>
43 #include <asm/arch/mailbox.h>
44 #include <asm/arch/mmu.h>
45 #include "dsp_mbcmd.h"
49 #if defined(CONFIG_ARCH_OMAP1)
50 #include "../../mach-omap1/mmu.h"
51 #elif defined(CONFIG_ARCH_OMAP2)
52 #include "../../mach-omap2/mmu.h"
57 static struct mem_sync_struct mem_sync;
59 int dsp_mem_sync_inc(void)
61 if (dsp_mem_enable((void *)dspmem_base) < 0)
64 mem_sync.DARAM->ad_arm++;
66 mem_sync.SARAM->ad_arm++;
68 mem_sync.SDRAM->ad_arm++;
69 dsp_mem_disable((void *)dspmem_base);
75 * dsp_mem_sync_config() is called from mbox1 workqueue
77 int dsp_mem_sync_config(struct mem_sync_struct *sync)
79 size_t sync_seq_sz = sizeof(struct sync_seq);
81 #ifdef OLD_BINARY_SUPPORT
83 memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
87 if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
88 (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
89 (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
91 "omapdsp: mem_sync address validation failure!\n"
92 " mem_sync.DARAM = 0x%p,\n"
93 " mem_sync.SARAM = 0x%p,\n"
94 " mem_sync.SDRAM = 0x%p,\n",
95 sync->DARAM, sync->SARAM, sync->SDRAM);
99 memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
105 enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
107 void *ds = (void *)daram_base;
108 void *de = (void *)daram_base + daram_size;
109 void *ss = (void *)saram_base;
110 void *se = (void *)saram_base + saram_size;
113 if ((vadr >= ds) && (vadr < de)) {
115 return MEM_TYPE_CROSSING;
117 return MEM_TYPE_DARAM;
118 } else if ((vadr >= ss) && (vadr < se)) {
120 return MEM_TYPE_CROSSING;
122 return MEM_TYPE_SARAM;
124 down_read(&dsp_mmu.exmap_sem);
125 if (exmap_valid(&dsp_mmu, vadr, len))
126 ret = MEM_TYPE_EXTERN;
129 up_read(&dsp_mmu.exmap_sem);
134 int dsp_address_validate(void *p, size_t len, char *fmt, ...)
139 if (dsp_mem_type(p, len) > 0)
146 vsprintf(s, fmt, args);
149 "omapdsp: %s address(0x%p) and size(0x%x) is not valid!\n"
150 "(crossing different type of memories, or external memory\n"
151 "space where no actual memory is mapped)\n", s, p, len);
156 #ifdef CONFIG_OMAP_DSP_FBEXPORT
158 static inline unsigned long lineup_offset(unsigned long adr,
162 unsigned long newadr;
164 newadr = (adr & ~mask) | (ref & mask);
171 * fb update functions:
172 * fbupd_response() is executed by the workqueue.
173 * fbupd_cb() is called when fb update is done, in interrupt context.
174 * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
176 static void fbupd_response(struct work_struct *unused)
180 status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
184 /* FIXME: DSP is busy !! */
187 "DSP is busy when trying to send FBCTL:UPD response!\n");
190 static DECLARE_WORK(fbupd_response_work, fbupd_response);
192 static void fbupd_cb(void *arg)
194 schedule_work(&fbupd_response_work);
197 void mbox_fbctl_upd(void)
199 struct omapfb_update_window win;
200 volatile unsigned short *buf = ipbuf_sys_da->d;
202 if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
203 printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
211 release_ipbuf_pvt(ipbuf_sys_da);
215 "omapdsp: fbupd() called while HWA742 is not ready!\n");
218 omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
221 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
222 static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
223 unsigned long event, void *fbi)
225 pr_info("omapfb_notifier_cb(): event = %s\n",
226 (event == OMAPFB_EVENT_READY) ? "READY" :
227 (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
228 if (event == OMAPFB_EVENT_READY)
230 else if (event == OMAPFB_EVENT_DISABLED)
236 static int dsp_fbexport(dsp_long_t *dspadr)
238 dsp_long_t dspadr_actual;
239 unsigned long padr_sys, padr, fbsz_sys, fbsz;
242 pr_debug( "omapdsp: frame buffer export\n");
244 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
247 "omapdsp: frame buffer has been exported already!\n");
252 if (num_registered_fb == 0) {
253 pr_info("omapdsp: frame buffer not registered.\n");
256 if (num_registered_fb != 1) {
257 pr_info("omapdsp: %d frame buffers found. we use first one.\n",
260 padr_sys = registered_fb[0]->fix.smem_start;
261 fbsz_sys = registered_fb[0]->fix.smem_len;
264 "omapdsp: framebuffer doesn't seem to be configured "
265 "correctly! (size=0)\n");
270 * align padr and fbsz to 4kB boundary
271 * (should be noted to the user afterwards!)
273 padr = padr_sys & ~(SZ_4K-1);
274 fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1);
276 /* line up dspadr offset with padr */
278 (fbsz > SZ_1M) ? lineup_offset(*dspadr, padr, SZ_1M-1) :
279 (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) :
280 /* (fbsz > SZ_4KB) ? */ *dspadr;
281 if (dspadr_actual != *dspadr)
283 "omapdsp: actual dspadr for FBEXPORT = %08x\n",
285 *dspadr = dspadr_actual;
287 cnt = omap_mmu_exmap(&dsp_mmu, dspadr_actual, padr, fbsz,
290 printk(KERN_ERR "omapdsp: exmap failure.\n");
294 if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
296 " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
297 " !! screen base address or size is not aligned in 4kB: !!\n"
298 " !! actual screen adr = %08lx, size = %08lx !!\n"
299 " !! exporting adr = %08lx, size = %08lx !!\n"
300 " !! Make sure that the framebuffer is allocated with 4kB-order! !!\n"
301 " !! Otherwise DSP can corrupt the kernel memory. !!\n"
302 " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
303 padr_sys, fbsz_sys, padr, fbsz);
306 /* increase the DMA priority */
307 set_emiff_dma_prio(15);
309 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
310 omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
311 if (omapfb_nb == NULL) {
313 "omapdsp: failed to allocate memory for omapfb_nb!\n");
314 omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr);
318 status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
320 pr_info("omapfb_register_client(): failure(%d)\n", status);
326 void mbox_fbctl_upd(void) { }
329 /* dsp/mem fops: backward compatibility */
330 static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
333 return __omap_mmu_mem_read(&dsp_mmu, buf, *ppos, count);
336 static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
337 size_t count, loff_t *ppos)
339 return __omap_mmu_mem_write(&dsp_mmu,
340 (char __user *)buf, *ppos, count);
343 static int dsp_mem_ioctl(struct inode *inode, struct file *file,
344 unsigned int cmd, unsigned long arg)
346 struct omap_dsp_mapinfo mapinfo;
352 case MEM_IOCTL_MMUINIT:
353 if (dsp_mmu.exmap_tbl)
354 omap_mmu_unregister(&dsp_mmu);
355 return omap_mmu_register(&dsp_mmu);
357 case MEM_IOCTL_EXMAP:
358 if (copy_from_user(&mapinfo, (void __user *)arg,
361 return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr,
362 0, mapinfo.size, EXMAP_TYPE_MEM);
364 case MEM_IOCTL_EXUNMAP:
365 return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg);
367 case MEM_IOCTL_EXMAP_FLUSH:
368 omap_mmu_exmap_flush(&dsp_mmu);
370 #ifdef CONFIG_OMAP_DSP_FBEXPORT
371 case MEM_IOCTL_FBEXPORT:
372 if (copy_from_user(&dspadr, (void __user *)arg,
375 ret = dsp_fbexport(&dspadr);
376 if (copy_to_user((void __user *)arg, &dspadr,
381 case MEM_IOCTL_MMUITACK:
382 return dsp_mmu_itack();
384 case MEM_IOCTL_KMEM_RESERVE:
386 if (copy_from_user(&size, (void __user *)arg,
389 return omap_mmu_kmem_reserve(&dsp_mmu, size);
392 case MEM_IOCTL_KMEM_RELEASE:
393 omap_mmu_kmem_release();
401 struct file_operations dsp_mem_fops = {
402 .owner = THIS_MODULE,
403 .read = dsp_mem_read,
404 .write = dsp_mem_write,
405 .ioctl = dsp_mem_ioctl,
409 * DSP MMU interrupt handler
411 static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id)
413 disable_irq(omap_dsp->mmu_irq);
414 schedule_work(&mmu_int_work);
418 void dsp_mem_start(void)
420 dsp_register_mem_cb(intmem_enable, intmem_disable);
423 void dsp_mem_stop(void)
425 memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
426 dsp_unregister_mem_cb();
430 * later half of dsp memory initialization
432 void dsp_mem_late_init(void)
435 #ifdef CONFIG_ARCH_OMAP2
436 int i, dspmem_pg_count;
438 dspmem_pg_count = dspmem_size >> 12;
439 for (i = 0; i < dspmem_pg_count; i++) {
440 writel(i, DSP_IPI_INDEX);
441 writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY);
443 writel(1, DSP_IPI_ENABLE);
444 writel(IOMAP_VAL, DSP_IPI_IOMAP);
446 dsp_mmu.clk = dsp_fck_handle;
447 dsp_mmu.memclk = dsp_ick_handle;
448 #elif defined(CONFIG_ARCH_OMAP1)
449 dsp_mmu.clk = dsp_ck_handle;
450 dsp_mmu.memclk = api_ck_handle;
452 ret = omap_mmu_register(&dsp_mmu);
455 int __init dsp_mem_init(void)
459 * DSP MMU interrupt setup
461 ret = request_irq(omap_dsp->mmu_irq, dsp_mmu_interrupt, IRQF_DISABLED,
465 "failed to register DSP MMU interrupt: %d\n", ret);
469 /* MMU interrupt is not enabled until DSP runs */
470 disable_irq(omap_dsp->mmu_irq);
474 #ifdef CONFIG_ARCH_OMAP1
475 dsp_reset_idle_boot_base();
480 void dsp_mem_exit(void)
482 free_irq(omap_dsp->mmu_irq, NULL);
484 /* recover disable_depth */
485 enable_irq(omap_dsp->mmu_irq);
487 #ifdef CONFIG_ARCH_OMAP1
488 dsp_reset_idle_boot_base();
490 omap_mmu_unregister(&dsp_mmu);