From: Hiroshi DOYU Date: Tue, 20 Feb 2007 12:18:12 +0000 (+0530) Subject: ARM: OMAP: Adapt to new MMU framework X-Git-Tag: v2.6.21-omap1~99 X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=c4ff7b01c0f4977c002ed1f5360ce1d255ed95c8;p=linux-2.6-omap-h63xx.git ARM: OMAP: Adapt to new MMU framework - Taken from maemo.org N800 kernel package. - Change dsp related code to adapt MMU framework. Signed-off-by: Trilok Soni Signed-off-by: Hiroshi DOYU --- diff --git a/arch/arm/plat-omap/dsp/dsp.h b/arch/arm/plat-omap/dsp/dsp.h index 353565941ea..ae8df3e1ec2 100644 --- a/arch/arm/plat-omap/dsp/dsp.h +++ b/arch/arm/plat-omap/dsp/dsp.h @@ -23,6 +23,7 @@ #include "hardware_dsp.h" #include "dsp_common.h" +#include /* * MAJOR device number: !! allocated arbitrary !! @@ -199,8 +200,6 @@ extern int dsp_mem_sync_inc(void); extern int dsp_mem_sync_config(struct mem_sync_struct *sync); extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len); extern int dsp_address_validate(void *p, size_t len, char *fmt, ...); -extern int dsp_mem_enable(void *adr); -extern void dsp_mem_disable(void *adr); #ifdef CONFIG_ARCH_OMAP1 extern void dsp_mem_usecount_clear(void); #endif @@ -238,3 +237,8 @@ extern const struct cmdinfo *cmdinfo[]; extern char *subcmd_name(struct mbcmd *mb); extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir); + +extern struct omap_mmu dsp_mmu; + +#define dsp_mem_enable(addr) omap_mmu_mem_enable(&dsp_mmu, (addr)) +#define dsp_mem_disable(addr) omap_mmu_mem_disable(&dsp_mmu, (addr)) diff --git a/arch/arm/plat-omap/dsp/dsp_common.c b/arch/arm/plat-omap/dsp/dsp_common.c index b998509cd57..2f3117e31b2 100644 --- a/arch/arm/plat-omap/dsp/dsp_common.c +++ b/arch/arm/plat-omap/dsp/dsp_common.c @@ -568,6 +568,9 @@ void dsp_unregister_mem_cb(void) cpustat.mem_rel_cb = NULL; mutex_unlock(&cpustat.lock); } +#else +void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)) { } +void dsp_unregister_mem_cb(void) { } #endif /* CONFIG_ARCH_OMAP1 */ arch_initcall(omap_dsp_init); diff --git a/arch/arm/plat-omap/dsp/dsp_common.h b/arch/arm/plat-omap/dsp/dsp_common.h index 872d838f420..cad42995b06 100644 --- a/arch/arm/plat-omap/dsp/dsp_common.h +++ b/arch/arm/plat-omap/dsp/dsp_common.h @@ -141,10 +141,8 @@ void dsp_cpustat_request(enum cpustat_e req); enum cpustat_e dsp_cpustat_get_stat(void); u16 dsp_cpustat_get_icrmask(void); void dsp_cpustat_set_icrmask(u16 mask); -#ifdef CONFIG_ARCH_OMAP1 void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)); void dsp_unregister_mem_cb(void); -#endif #if defined(CONFIG_ARCH_OMAP1) static inline void dsp_clk_autoidle(void) {} diff --git a/arch/arm/plat-omap/dsp/dsp_ctl.c b/arch/arm/plat-omap/dsp/dsp_ctl.c index 91be986b935..5fea6258303 100644 --- a/arch/arm/plat-omap/dsp/dsp_ctl.c +++ b/arch/arm/plat-omap/dsp/dsp_ctl.c @@ -34,11 +34,11 @@ #include #include #include +#include #include "hardware_dsp.h" #include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" -#include "ioctl.h" enum dsp_space_e { SPACE_MEM, diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c index 8442a960c37..f994e99f0c7 100644 --- a/arch/arm/plat-omap/dsp/dsp_mem.c +++ b/arch/arm/plat-omap/dsp/dsp_mem.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -40,311 +39,23 @@ #include #include #include +#include #include -#include -#include "uaccess_dsp.h" +#include #include "dsp_mbcmd.h" #include "dsp.h" -#include "ioctl.h" #include "ipbuf.h" -#ifdef CONFIG_ARCH_OMAP2 -#define IOMAP_VAL 0x3f -#endif - -#define SZ_1KB 0x400 -#define SZ_4KB 0x1000 -#define SZ_64KB 0x10000 -#define SZ_1MB 0x100000 -#define SZ_16MB 0x1000000 -#define is_aligned(adr,align) (!((adr)&((align)-1))) -#define ORDER_4KB (12 - PAGE_SHIFT) -#define ORDER_64KB (16 - PAGE_SHIFT) -#define ORDER_1MB (20 - PAGE_SHIFT) - -/* - * absorb DSP MMU register size and location difference - */ -#if defined(CONFIG_ARCH_OMAP1) -typedef u16 dsp_mmu_reg_t; -#define dsp_mmu_read_reg(a) omap_readw(a) -#define dsp_mmu_write_reg(v,a) omap_writew(v,a) -#elif defined(CONFIG_ARCH_OMAP2) -typedef u32 dsp_mmu_reg_t; -#define dsp_mmu_read_reg(a) readl(a) -#define dsp_mmu_write_reg(v,a) writel(v,a) -#define dsp_ipi_read_reg(a) readl(a) -#define dsp_ipi_write_reg(v,a) writel(v,a) -#endif - -#if defined(CONFIG_ARCH_OMAP1) - -#define dsp_mmu_enable() \ - do { \ - dsp_mmu_write_reg(DSP_MMU_CNTL_MMU_EN | DSP_MMU_CNTL_RESET_SW, \ - DSP_MMU_CNTL); \ - } while(0) -#define dsp_mmu_disable() \ - do { \ - dsp_mmu_write_reg(0, DSP_MMU_CNTL); \ - } while(0) -#define __dsp_mmu_itack() \ - do { \ - dsp_mmu_write_reg(DSP_MMU_IT_ACK_IT_ACK, DSP_MMU_IT_ACK); \ - } while(0) - -#elif defined(CONFIG_ARCH_OMAP2) - -#define dsp_mmu_enable() \ - do { \ - dsp_mmu_write_reg(DSP_MMU_CNTL_MMUENABLE, DSP_MMU_CNTL); \ - } while(0) -#define dsp_mmu_disable() \ - do { \ - dsp_mmu_write_reg(0, DSP_MMU_CNTL); \ - } while(0) -#define dsp_mmu_reset() \ - do { \ - dsp_mmu_write_reg(dsp_mmu_read_reg(DSP_MMU_SYSCONFIG) | \ - DSP_MMU_SYSCONFIG_SOFTRESET, \ - DSP_MMU_SYSCONFIG); \ - } while(0) - -#endif /* CONFIG_ARCH_OMAP2 */ - -#define dsp_mmu_flush() \ - do { \ - dsp_mmu_write_reg(DSP_MMU_FLUSH_ENTRY_FLUSH_ENTRY, \ - DSP_MMU_FLUSH_ENTRY); \ - } while(0) -#define __dsp_mmu_gflush() \ - do { \ - dsp_mmu_write_reg(DSP_MMU_GFLUSH_GFLUSH, DSP_MMU_GFLUSH); \ - } while(0) - -/* - * absorb register name difference - */ -#ifdef CONFIG_ARCH_OMAP1 -#define DSP_MMU_CAM_P DSP_MMU_CAM_L_P -#define DSP_MMU_CAM_V DSP_MMU_CAM_L_V -#define DSP_MMU_CAM_PAGESIZE_MASK DSP_MMU_CAM_L_PAGESIZE_MASK -#define DSP_MMU_CAM_PAGESIZE_1MB DSP_MMU_CAM_L_PAGESIZE_1MB -#define DSP_MMU_CAM_PAGESIZE_64KB DSP_MMU_CAM_L_PAGESIZE_64KB -#define DSP_MMU_CAM_PAGESIZE_4KB DSP_MMU_CAM_L_PAGESIZE_4KB -#define DSP_MMU_CAM_PAGESIZE_1KB DSP_MMU_CAM_L_PAGESIZE_1KB -#endif /* CONFIG_ARCH_OMAP1 */ - -/* - * OMAP1 EMIFF access - */ -#ifdef CONFIG_ARCH_OMAP1 -#define EMIF_PRIO_LB_MASK 0x0000f000 -#define EMIF_PRIO_LB_SHIFT 12 -#define EMIF_PRIO_DMA_MASK 0x00000f00 -#define EMIF_PRIO_DMA_SHIFT 8 -#define EMIF_PRIO_DSP_MASK 0x00000070 -#define EMIF_PRIO_DSP_SHIFT 4 -#define EMIF_PRIO_MPU_MASK 0x00000007 -#define EMIF_PRIO_MPU_SHIFT 0 -#define set_emiff_dma_prio(prio) \ - do { \ - omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \ - ~EMIF_PRIO_DMA_MASK) | \ - ((prio) << EMIF_PRIO_DMA_SHIFT), \ - OMAP_TC_OCPT1_PRIOR); \ - } while(0) -#endif /* CONFIG_ARCH_OMAP1 */ - -enum exmap_type_e { - EXMAP_TYPE_MEM, - EXMAP_TYPE_FB -}; - -struct exmap_tbl_entry { - unsigned int valid:1; - unsigned int prsvd:1; /* preserved */ - int usecount; /* reference count by mmap */ - enum exmap_type_e type; - void *buf; /* virtual address of the buffer, - * i.e. 0xc0000000 - */ - void *vadr; /* DSP shadow space, - * i.e. 0xe0000000 - 0xe0ffffff */ - unsigned int order; - struct { - int prev; - int next; - } link; /* grouping */ -}; - -#define INIT_EXMAP_TBL_ENTRY(ent,b,v,typ,od) \ - do {\ - (ent)->buf = (b); \ - (ent)->vadr = (v); \ - (ent)->valid = 1; \ - (ent)->prsvd = 0; \ - (ent)->usecount = 0; \ - (ent)->type = (typ); \ - (ent)->order = (od); \ - (ent)->link.next = -1; \ - (ent)->link.prev = -1; \ - } while (0) - -#define INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(ent,b,v) \ - do {\ - (ent)->buf = (b); \ - (ent)->vadr = (v); \ - (ent)->valid = 1; \ - (ent)->prsvd = 1; \ - (ent)->usecount = 0; \ - (ent)->type = EXMAP_TYPE_MEM; \ - (ent)->order = 0; \ - (ent)->link.next = -1; \ - (ent)->link.prev = -1; \ - } while (0) - -#define DSP_MMU_TLB_LINES 32 -static struct exmap_tbl_entry exmap_tbl[DSP_MMU_TLB_LINES]; -static int exmap_preserved_cnt; -static DECLARE_RWSEM(exmap_sem); - -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL -static struct omapfb_notifier_block *omapfb_nb; -static int omapfb_ready; -#endif - -struct cam_ram_regset { -#if defined(CONFIG_ARCH_OMAP1) - dsp_mmu_reg_t cam_h; - dsp_mmu_reg_t cam_l; - dsp_mmu_reg_t ram_h; - dsp_mmu_reg_t ram_l; -#elif defined(CONFIG_ARCH_OMAP2) - dsp_mmu_reg_t cam; - dsp_mmu_reg_t ram; -#endif -}; - -struct tlb_entry { - dsp_long_t va; - unsigned long pa; - dsp_mmu_reg_t pgsz, prsvd, valid; -#if defined(CONFIG_ARCH_OMAP1) - dsp_mmu_reg_t ap; -#elif defined(CONFIG_ARCH_OMAP2) - dsp_mmu_reg_t endian, elsz, mixed; -#endif -}; - -#if defined(CONFIG_ARCH_OMAP1) -#define INIT_TLB_ENTRY(ent,v,p,ps) \ - do { \ - (ent)->va = (v); \ - (ent)->pa = (p); \ - (ent)->pgsz = (ps); \ - (ent)->prsvd = 0; \ - (ent)->ap = DSP_MMU_RAM_L_AP_FA; \ - } while (0) -#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \ - do { \ - (ent)->va = (v); \ - (ent)->pa = (p); \ - (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \ - (ent)->prsvd = DSP_MMU_CAM_P; \ - (ent)->ap = DSP_MMU_RAM_L_AP_FA; \ - } while (0) -#elif defined(CONFIG_ARCH_OMAP2) -#define INIT_TLB_ENTRY(ent,v,p,ps) \ - do { \ - (ent)->va = (v); \ - (ent)->pa = (p); \ - (ent)->pgsz = (ps); \ - (ent)->prsvd = 0; \ - (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \ - (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \ - (ent)->mixed = 0; \ - } while (0) -#define INIT_TLB_ENTRY_4KB_PRESERVED(ent,v,p) \ - do { \ - (ent)->va = (v); \ - (ent)->pa = (p); \ - (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \ - (ent)->prsvd = DSP_MMU_CAM_P; \ - (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \ - (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_16; \ - (ent)->mixed = 0; \ - } while (0) -#define INIT_TLB_ENTRY_4KB_ES32_PRESERVED(ent,v,p) \ - do { \ - (ent)->va = (v); \ - (ent)->pa = (p); \ - (ent)->pgsz = DSP_MMU_CAM_PAGESIZE_4KB; \ - (ent)->prsvd = DSP_MMU_CAM_P; \ - (ent)->endian = DSP_MMU_RAM_ENDIANNESS_LITTLE; \ - (ent)->elsz = DSP_MMU_RAM_ELEMENTSIZE_32; \ - (ent)->mixed = 0; \ - } while (0) -#endif - #if defined(CONFIG_ARCH_OMAP1) -#define cam_ram_valid(cr) ((cr).cam_l & DSP_MMU_CAM_V) +#include "../../mach-omap1/mmu.h" #elif defined(CONFIG_ARCH_OMAP2) -#define cam_ram_valid(cr) ((cr).cam & DSP_MMU_CAM_V) +#include "../../mach-omap2/mmu.h" #endif -struct tlb_lock { - int base; - int victim; -}; - -static int dsp_exunmap(dsp_long_t dspadr); +#include "mmu.h" -static void *dspvect_page; -static u32 dsp_fault_adr; static struct mem_sync_struct mem_sync; -static ssize_t mmu_show(struct device *dev, struct device_attribute *attr, - char *buf); -static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, - char *buf); -static ssize_t mempool_show(struct device *dev, struct device_attribute *attr, - char *buf); - -static struct device_attribute dev_attr_mmu = __ATTR_RO(mmu); -static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap); -static struct device_attribute dev_attr_mempool = __ATTR_RO(mempool); - -/* - * special mempool function: - * hope this goes to mm/mempool.c - */ -static void *mempool_alloc_from_pool(mempool_t *pool, gfp_t gfp_mask) -{ - unsigned long flags; - - spin_lock_irqsave(&pool->lock, flags); - if (likely(pool->curr_nr)) { - void *element = pool->elements[--pool->curr_nr]; - spin_unlock_irqrestore(&pool->lock, flags); - return element; - } - spin_unlock_irqrestore(&pool->lock, flags); - - return mempool_alloc(pool, gfp_mask); -} - -static __inline__ unsigned long lineup_offset(unsigned long adr, - unsigned long ref, - unsigned long mask) -{ - unsigned long newadr; - - newadr = (adr & ~mask) | (ref & mask); - if (newadr < adr) - newadr += mask + 1; - return newadr; -} - int dsp_mem_sync_inc(void) { if (dsp_mem_enable((void *)dspmem_base) < 0) @@ -356,6 +67,7 @@ int dsp_mem_sync_inc(void) if (mem_sync.SDRAM) mem_sync.SDRAM->ad_arm++; dsp_mem_disable((void *)dspmem_base); + return 0; } @@ -373,1636 +85,88 @@ int dsp_mem_sync_config(struct mem_sync_struct *sync) } #endif if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) || - (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) || - (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) { - printk(KERN_ERR - "omapdsp: mem_sync address validation failure!\n" - " mem_sync.DARAM = 0x%p,\n" - " mem_sync.SARAM = 0x%p,\n" - " mem_sync.SDRAM = 0x%p,\n", - sync->DARAM, sync->SARAM, sync->SDRAM); - return -1; - } - memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct)); - return 0; -} - -static mempool_t *kmem_pool_1M; -static mempool_t *kmem_pool_64K; - -static void *dsp_pool_alloc(unsigned int __nocast gfp, void *order) -{ - return (void *)__get_dma_pages(gfp, (unsigned int)order); -} - -static void dsp_pool_free(void *buf, void *order) -{ - free_pages((unsigned long)buf, (unsigned int)order); -} - -static void dsp_kmem_release(void) -{ - if (kmem_pool_64K) { - mempool_destroy(kmem_pool_64K); - kmem_pool_64K = NULL; - } - - if (kmem_pool_1M) { - mempool_destroy(kmem_pool_1M); - kmem_pool_1M = NULL; - } -} - -static int dsp_kmem_reserve(unsigned long size) -{ - unsigned long len = size; - - /* alignment check */ - if (!is_aligned(size, SZ_64KB)) { - printk(KERN_ERR - "omapdsp: size(0x%lx) is not multiple of 64KB.\n", size); - return -EINVAL; - } - - if (size > DSPSPACE_SIZE) { - printk(KERN_ERR - "omapdsp: size(0x%lx) is larger than DSP memory space " - "size (0x%x.\n", size, DSPSPACE_SIZE); - return -EINVAL; - } - - if (size >= SZ_1MB) { - int nr = size >> 20; - - if (likely(!kmem_pool_1M)) - kmem_pool_1M = mempool_create(nr, - dsp_pool_alloc, - dsp_pool_free, - (void *)ORDER_1MB); - else - mempool_resize(kmem_pool_1M, kmem_pool_1M->min_nr + nr, - GFP_KERNEL); - - size &= ~(0xf << 20); - } - - if (size >= SZ_64KB) { - int nr = size >> 16; - - if (likely(!kmem_pool_64K)) - kmem_pool_64K = mempool_create(nr, - dsp_pool_alloc, - dsp_pool_free, - (void *)ORDER_64KB); - else - mempool_resize(kmem_pool_64K, - kmem_pool_64K->min_nr + nr, GFP_KERNEL); - - size &= ~(0xf << 16); - } - - if (size) - len -= size; - - return len; -} - -static void dsp_mem_free_pages(unsigned long buf, unsigned int order) -{ - struct page *page, *ps, *pe; - - ps = virt_to_page(buf); - pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order))); - - for (page = ps; page < pe; page++) - ClearPageReserved(page); - - if ((order == ORDER_64KB) && likely(kmem_pool_64K)) - mempool_free((void *)buf, kmem_pool_64K); - else if ((order == ORDER_1MB) && likely(kmem_pool_1M)) - mempool_free((void *)buf, kmem_pool_1M); - else - free_pages(buf, order); -} - -static inline void -exmap_alloc_pte(unsigned long virt, unsigned long phys, pgprot_t prot) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - pgd = pgd_offset_k(virt); - pud = pud_offset(pgd, virt); - pmd = pmd_offset(pud, virt); - - if (pmd_none(*pmd)) { - pte = pte_alloc_one_kernel(&init_mm, 0); - if (!pte) - return; - - /* note: two PMDs will be set */ - pmd_populate_kernel(&init_mm, pmd, pte); - } - - pte = pte_offset_kernel(pmd, virt); - set_pte_ext(pte, pfn_pte(phys >> PAGE_SHIFT, prot), 0); -} - -#if 0 -static inline int -exmap_alloc_sect(unsigned long virt, unsigned long phys, int prot) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - - pgd = pgd_offset_k(virt); - pud = pud_alloc(&init_mm, pgd, virt); - pmd = pmd_alloc(&init_mm, pud, virt); - - if (virt & (1 << 20)) - pmd++; - - if (!pmd_none(*pmd)) - /* No good, fall back on smaller mappings. */ - return -EINVAL; - - *pmd = __pmd(phys | prot); - flush_pmd_entry(pmd); - - return 0; -} -#endif - -/* - * ARM MMU operations - */ -static int exmap_set_armmmu(unsigned long virt, unsigned long phys, - unsigned long size) -{ - long off; - pgprot_t prot_pte; - int prot_sect; - - printk(KERN_DEBUG - "omapdsp: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n", - virt, phys, size); - - prot_pte = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | - L_PTE_DIRTY | L_PTE_WRITE); - - prot_sect = PMD_TYPE_SECT | PMD_SECT_UNCACHED | - PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO); - - if (cpu_architecture() <= CPU_ARCH_ARMv5) - prot_sect |= PMD_BIT4; - - off = phys - virt; - - while ((virt & 0xfffff || (virt + off) & 0xfffff) && size >= PAGE_SIZE) { - exmap_alloc_pte(virt, virt + off, prot_pte); - - virt += PAGE_SIZE; - size -= PAGE_SIZE; - } - - /* XXX: Not yet.. confuses dspfb -- PFM. */ -#if 0 - while (size >= (PGDIR_SIZE / 2)) { - if (exmap_alloc_sect(virt, virt + off, prot_sect) < 0) - break; - - virt += (PGDIR_SIZE / 2); - size -= (PGDIR_SIZE / 2); - } -#endif - - while (size >= PAGE_SIZE) { - exmap_alloc_pte(virt, virt + off, prot_pte); - - virt += PAGE_SIZE; - size -= PAGE_SIZE; - } - - BUG_ON(size); - - return 0; -} - - /* XXX: T.Kobayashi - * A process can have old mappings. if we want to clear a pmd, - * we need to do it for all proceeses that use the old mapping. - */ -#if 0 -static inline void -exmap_clear_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end) -{ - pte_t *pte; - - pte = pte_offset_map(pmd, addr); - do { - if (pte_none(*pte)) - continue; - - pte_clear(&init_mm, addr, pte); - } while (pte++, addr += PAGE_SIZE, addr != end); - - pte_unmap(pte - 1); -} - -static inline void -exmap_clear_pmd_range(pud_t *pud, unsigned long addr, unsigned long end) -{ - pmd_t *pmd; - unsigned long next; - - pmd = pmd_offset(pud, addr); - do { - next = pmd_addr_end(addr, end); - - if (addr & (1 << 20)) - pmd++; - - if ((pmd_val(*pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) { - *pmd = __pmd(0); - clean_pmd_entry(pmd); - continue; - } - - if (pmd_none_or_clear_bad(pmd)) - continue; - - exmap_clear_pte_range(pmd, addr, next); - } while (pmd++, addr = next, addr != end); -} - -static inline void -exmap_clear_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end) -{ - pud_t *pud; - unsigned long next; - - pud = pud_offset(pgd, addr); - do { - next = pud_addr_end(addr, end); - if (pud_none_or_clear_bad(pud)) - continue; - - exmap_clear_pmd_range(pud, addr, next); - } while (pud++, addr = next, addr != end); -} -#endif - -static void exmap_clear_armmmu(unsigned long virt, unsigned long size) -{ -#if 0 - unsigned long next, end; - pgd_t *pgd; - - printk(KERN_DEBUG - "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n", - virt, size); - - pgd = pgd_offset_k(virt); - end = virt + size; - do { - next = pgd_addr_end(virt, end); - if (pgd_none_or_clear_bad(pgd)) - continue; - - exmap_clear_pud_range(pgd, virt, next); - } while (pgd++, virt = next, virt != end); -#else - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - printk(KERN_DEBUG - "omapdsp: unmapping in ARM MMU, v=%#010lx, sz=%#lx\n", - virt, size); - - while (size >= PAGE_SIZE) { - pgd = pgd_offset_k(virt); - pud = pud_offset(pgd, virt); - pmd = pmd_offset(pud, virt); - pte = pte_offset_kernel(pmd, virt); - - pte_clear(&init_mm, virt, pte); - size -= PAGE_SIZE; - virt += PAGE_SIZE; - } - - BUG_ON(size); -#endif -} - -static int exmap_valid(void *vadr, size_t len) -{ - /* exmap_sem should be held before calling this function */ - int i; - -start: - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - void *mapadr; - unsigned long mapsize; - struct exmap_tbl_entry *ent = &exmap_tbl[i]; - - if (!ent->valid) - continue; - mapadr = (void *)ent->vadr; - mapsize = 1 << (ent->order + PAGE_SHIFT); - if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) { - if (vadr + len <= mapadr + mapsize) { - /* this map covers whole address. */ - return 1; - } else { - /* - * this map covers partially. - * check rest portion. - */ - len -= mapadr + mapsize - vadr; - vadr = mapadr + mapsize; - goto start; - } - } - } - - return 0; -} - -enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len) -{ - void *ds = (void *)daram_base; - void *de = (void *)daram_base + daram_size; - void *ss = (void *)saram_base; - void *se = (void *)saram_base + saram_size; - int ret; - - if ((vadr >= ds) && (vadr < de)) { - if (vadr + len > de) - return MEM_TYPE_CROSSING; - else - return MEM_TYPE_DARAM; - } else if ((vadr >= ss) && (vadr < se)) { - if (vadr + len > se) - return MEM_TYPE_CROSSING; - else - return MEM_TYPE_SARAM; - } else { - down_read(&exmap_sem); - if (exmap_valid(vadr, len)) - ret = MEM_TYPE_EXTERN; - else - ret = MEM_TYPE_NONE; - up_read(&exmap_sem); - return ret; - } -} - -int dsp_address_validate(void *p, size_t len, char *fmt, ...) -{ - if (dsp_mem_type(p, len) <= 0) { - if (fmt != NULL) { - char s[64]; - va_list args; - - va_start(args, fmt); - vsprintf(s, fmt, args); - va_end(args); - printk(KERN_ERR - "omapdsp: %s address(0x%p) and size(0x%x) is " - "not valid!\n" - " (crossing different type of memories, or \n" - " external memory space where no " - "actual memory is mapped)\n", - s, p, len); - } - return -1; - } - - return 0; -} - -/* - * exmap_use(), unuse(): - * when the mapped area is exported to user space with mmap, - * the usecount is incremented. - * while the usecount > 0, that area can't be released. - */ -void exmap_use(void *vadr, size_t len) -{ - int i; - - down_write(&exmap_sem); - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - void *mapadr; - unsigned long mapsize; - struct exmap_tbl_entry *ent = &exmap_tbl[i]; - - if (!ent->valid) - continue; - mapadr = (void *)ent->vadr; - mapsize = 1 << (ent->order + PAGE_SHIFT); - if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) - ent->usecount++; - } - up_write(&exmap_sem); -} - -void exmap_unuse(void *vadr, size_t len) -{ - int i; - - down_write(&exmap_sem); - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - void *mapadr; - unsigned long mapsize; - struct exmap_tbl_entry *ent = &exmap_tbl[i]; - - if (!ent->valid) - continue; - mapadr = (void *)ent->vadr; - mapsize = 1 << (ent->order + PAGE_SHIFT); - if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) - ent->usecount--; - } - up_write(&exmap_sem); -} - -/* - * dsp_virt_to_phys() - * returns physical address, and sets len to valid length - */ -unsigned long dsp_virt_to_phys(void *vadr, size_t *len) -{ - int i; - - if (is_dsp_internal_mem(vadr)) { - /* DSRAM or SARAM */ - *len = dspmem_base + dspmem_size - (unsigned long)vadr; - return (unsigned long)vadr; - } - - /* EXRAM */ - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - void *mapadr; - unsigned long mapsize; - struct exmap_tbl_entry *ent = &exmap_tbl[i]; - - if (!ent->valid) - continue; - mapadr = (void *)ent->vadr; - mapsize = 1 << (ent->order + PAGE_SHIFT); - if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) { - *len = mapadr + mapsize - vadr; - return __pa(ent->buf) + vadr - mapadr; - } - } - - /* valid mapping not found */ - return 0; -} - -/* - * DSP MMU operations - */ -#ifdef CONFIG_ARCH_OMAP1 -static dsp_mmu_reg_t get_cam_l_va_mask(dsp_mmu_reg_t pgsz) -{ - switch (pgsz) { - case DSP_MMU_CAM_PAGESIZE_1MB: - return DSP_MMU_CAM_L_VA_TAG_L1_MASK | - DSP_MMU_CAM_L_VA_TAG_L2_MASK_1MB; - case DSP_MMU_CAM_PAGESIZE_64KB: - return DSP_MMU_CAM_L_VA_TAG_L1_MASK | - DSP_MMU_CAM_L_VA_TAG_L2_MASK_64KB; - case DSP_MMU_CAM_PAGESIZE_4KB: - return DSP_MMU_CAM_L_VA_TAG_L1_MASK | - DSP_MMU_CAM_L_VA_TAG_L2_MASK_4KB; - case DSP_MMU_CAM_PAGESIZE_1KB: - return DSP_MMU_CAM_L_VA_TAG_L1_MASK | - DSP_MMU_CAM_L_VA_TAG_L2_MASK_1KB; - } - return 0; -} -#endif /* CONFIG_ARCH_OMAP1 */ - -#if defined(CONFIG_ARCH_OMAP1) -#define get_cam_va_mask(pgsz) \ - ((u32)DSP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \ - (u32)get_cam_l_va_mask(pgsz) << 6) -#elif defined(CONFIG_ARCH_OMAP2) -#define get_cam_va_mask(pgsz) \ - ((pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \ - (pgsz == DSP_MMU_CAM_PAGESIZE_1MB) ? 0xfff00000 : \ - (pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \ - (pgsz == DSP_MMU_CAM_PAGESIZE_4KB) ? 0xfffff000 : 0) -#endif /* CONFIG_ARCH_OMAP2 */ - -static void get_tlb_lock(struct tlb_lock *tlb_lock) -{ - dsp_mmu_reg_t lock = dsp_mmu_read_reg(DSP_MMU_LOCK); - - tlb_lock->base = (lock & DSP_MMU_LOCK_BASE_MASK) >> - DSP_MMU_LOCK_BASE_SHIFT; - tlb_lock->victim = (lock & DSP_MMU_LOCK_VICTIM_MASK) >> - DSP_MMU_LOCK_VICTIM_SHIFT; -} - -static void set_tlb_lock(struct tlb_lock *tlb_lock) -{ - dsp_mmu_write_reg((tlb_lock->base << DSP_MMU_LOCK_BASE_SHIFT) | - (tlb_lock->victim << DSP_MMU_LOCK_VICTIM_SHIFT), - DSP_MMU_LOCK); -} - -static void __read_tlb(struct tlb_lock *tlb_lock, struct cam_ram_regset *cr) -{ - /* set victim */ - set_tlb_lock(tlb_lock); - -#if defined(CONFIG_ARCH_OMAP1) - /* read a TLB entry */ - dsp_mmu_write_reg(DSP_MMU_LD_TLB_RD, DSP_MMU_LD_TLB); - - cr->cam_h = dsp_mmu_read_reg(DSP_MMU_READ_CAM_H); - cr->cam_l = dsp_mmu_read_reg(DSP_MMU_READ_CAM_L); - cr->ram_h = dsp_mmu_read_reg(DSP_MMU_READ_RAM_H); - cr->ram_l = dsp_mmu_read_reg(DSP_MMU_READ_RAM_L); -#elif defined(CONFIG_ARCH_OMAP2) - cr->cam = dsp_mmu_read_reg(DSP_MMU_READ_CAM); - cr->ram = dsp_mmu_read_reg(DSP_MMU_READ_RAM); -#endif -} - -static void __load_tlb(struct cam_ram_regset *cr) -{ -#if defined(CONFIG_ARCH_OMAP1) - dsp_mmu_write_reg(cr->cam_h, DSP_MMU_CAM_H); - dsp_mmu_write_reg(cr->cam_l, DSP_MMU_CAM_L); - dsp_mmu_write_reg(cr->ram_h, DSP_MMU_RAM_H); - dsp_mmu_write_reg(cr->ram_l, DSP_MMU_RAM_L); -#elif defined(CONFIG_ARCH_OMAP2) - dsp_mmu_write_reg(cr->cam | DSP_MMU_CAM_V, DSP_MMU_CAM); - dsp_mmu_write_reg(cr->ram, DSP_MMU_RAM); -#endif - - /* flush the entry */ - dsp_mmu_flush(); - - /* load a TLB entry */ - dsp_mmu_write_reg(DSP_MMU_LD_TLB_LD, DSP_MMU_LD_TLB); -} - -static int dsp_mmu_load_tlb(struct tlb_entry *tlb_ent) -{ - struct tlb_lock tlb_lock; - struct cam_ram_regset cr; - -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(dsp_ck_handle); - omap_dsp_request_mem(); -#endif - - get_tlb_lock(&tlb_lock); - for (tlb_lock.victim = 0; - tlb_lock.victim < tlb_lock.base; - tlb_lock.victim++) { - struct cam_ram_regset tmp_cr; - - /* read a TLB entry */ - __read_tlb(&tlb_lock, &tmp_cr); - if (!cam_ram_valid(tmp_cr)) - goto found_victim; - } - set_tlb_lock(&tlb_lock); - -found_victim: - /* The last (31st) entry cannot be locked? */ - if (tlb_lock.victim == 31) { - printk(KERN_ERR "omapdsp: TLB is full.\n"); - return -EBUSY; - } - - if (tlb_ent->va & ~get_cam_va_mask(tlb_ent->pgsz)) { - printk(KERN_ERR - "omapdsp: mapping vadr (0x%06x) is not " - "aligned boundary\n", tlb_ent->va); - return -EINVAL; - } - -#if defined(CONFIG_ARCH_OMAP1) - cr.cam_h = tlb_ent->va >> 22; - cr.cam_l = (tlb_ent->va >> 6 & get_cam_l_va_mask(tlb_ent->pgsz)) | - tlb_ent->prsvd | tlb_ent->pgsz; - cr.ram_h = tlb_ent->pa >> 16; - cr.ram_l = (tlb_ent->pa & DSP_MMU_RAM_L_RAM_LSB_MASK) | tlb_ent->ap; -#elif defined(CONFIG_ARCH_OMAP2) - cr.cam = (tlb_ent->va & DSP_MMU_CAM_VATAG_MASK) | - tlb_ent->prsvd | tlb_ent->pgsz; - cr.ram = tlb_ent->pa | tlb_ent->endian | tlb_ent->elsz; -#endif - __load_tlb(&cr); - - /* update lock base */ - if (tlb_lock.victim == tlb_lock.base) - tlb_lock.base++; - tlb_lock.victim = tlb_lock.base; - set_tlb_lock(&tlb_lock); - -#ifdef CONFIG_ARCH_OMAP1 - omap_dsp_release_mem(); - clk_disable(dsp_ck_handle); -#endif - return 0; -} - -static int dsp_mmu_clear_tlb(dsp_long_t vadr) -{ - struct tlb_lock tlb_lock; - int i; - int max_valid = 0; - -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(dsp_ck_handle); - omap_dsp_request_mem(); -#endif - - get_tlb_lock(&tlb_lock); - for (i = 0; i < tlb_lock.base; i++) { - struct cam_ram_regset cr; - dsp_long_t cam_va; - dsp_mmu_reg_t pgsz; - - /* read a TLB entry */ - tlb_lock.victim = i; - __read_tlb(&tlb_lock, &cr); - if (!cam_ram_valid(cr)) - continue; - -#if defined(CONFIG_ARCH_OMAP1) - pgsz = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK; - cam_va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 | - (u32)(cr.cam_l & get_cam_l_va_mask(pgsz)) << 6; -#elif defined(CONFIG_ARCH_OMAP2) - pgsz = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK; - cam_va = cr.cam & get_cam_va_mask(pgsz); -#endif - - if (cam_va == vadr) - /* flush the entry */ - dsp_mmu_flush(); - else - max_valid = i; - } - - /* set new lock base */ - tlb_lock.base = max_valid + 1; - tlb_lock.victim = max_valid + 1; - set_tlb_lock(&tlb_lock); - -#ifdef CONFIG_ARCH_OMAP1 - omap_dsp_release_mem(); - clk_disable(dsp_ck_handle); -#endif - return 0; -} - -static void dsp_mmu_gflush(void) -{ - struct tlb_lock tlb_lock; - -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(dsp_ck_handle); - omap_dsp_request_mem(); -#endif - - __dsp_mmu_gflush(); - tlb_lock.base = exmap_preserved_cnt; - tlb_lock.victim = exmap_preserved_cnt; - set_tlb_lock(&tlb_lock); - -#ifdef CONFIG_ARCH_OMAP1 - omap_dsp_release_mem(); - clk_disable(dsp_ck_handle); -#endif -} - -/* - * dsp_exmap() - * - * MEM_IOCTL_EXMAP ioctl calls this function with padr=0. - * In this case, the buffer for DSP is allocated in this routine, - * then it is mapped. - * On the other hand, for example - frame buffer sharing, calls - * this function with padr set. It means some known address space - * pointed with padr is going to be shared with DSP. - */ -static int dsp_exmap(dsp_long_t dspadr, unsigned long padr, unsigned long size, - enum exmap_type_e type) -{ - dsp_mmu_reg_t pgsz; - void *buf; - unsigned int order = 0; - unsigned long unit; - int prev = -1; - dsp_long_t _dspadr = dspadr; - unsigned long _padr = padr; - void *_vadr = dspbyte_to_virt(dspadr); - unsigned long _size = size; - struct tlb_entry tlb_ent; - struct exmap_tbl_entry *exmap_ent; - int status; - int idx; - int i; - -#define MINIMUM_PAGESZ SZ_4KB - /* - * alignment check - */ - if (!is_aligned(size, MINIMUM_PAGESZ)) { - printk(KERN_ERR - "omapdsp: size(0x%lx) is not multiple of 4KB.\n", size); - return -EINVAL; - } - if (!is_aligned(dspadr, MINIMUM_PAGESZ)) { - printk(KERN_ERR - "omapdsp: DSP address(0x%x) is not aligned.\n", dspadr); - return -EINVAL; - } - if (!is_aligned(padr, MINIMUM_PAGESZ)) { - printk(KERN_ERR - "omapdsp: physical address(0x%lx) is not aligned.\n", - padr); - return -EINVAL; - } - - /* address validity check */ - if ((dspadr < dspmem_size) || - (dspadr >= DSPSPACE_SIZE) || - ((dspadr + size > DSP_INIT_PAGE) && - (dspadr < DSP_INIT_PAGE + PAGE_SIZE))) { - printk(KERN_ERR - "omapdsp: illegal address/size for dsp_exmap().\n"); - return -EINVAL; - } - - down_write(&exmap_sem); - - /* overlap check */ - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - unsigned long mapsize; - struct exmap_tbl_entry *tmp_ent = &exmap_tbl[i]; - - if (!tmp_ent->valid) - continue; - mapsize = 1 << (tmp_ent->order + PAGE_SHIFT); - if ((_vadr + size > tmp_ent->vadr) && - (_vadr < tmp_ent->vadr + mapsize)) { - printk(KERN_ERR "omapdsp: exmap page overlap!\n"); - up_write(&exmap_sem); - return -EINVAL; - } - } - -start: - buf = NULL; - /* Are there any free TLB lines? */ - for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) { - if (!exmap_tbl[idx].valid) - goto found_free; - } - printk(KERN_ERR "omapdsp: DSP TLB is full.\n"); - status = -EBUSY; - goto fail; - -found_free: - exmap_ent = &exmap_tbl[idx]; - - /* - * we don't use - * 1KB mapping in OMAP1, - * 16MB mapping in OMAP2. - */ - if ((_size >= SZ_1MB) && - (is_aligned(_padr, SZ_1MB) || (padr == 0)) && - is_aligned(_dspadr, SZ_1MB)) { - unit = SZ_1MB; - pgsz = DSP_MMU_CAM_PAGESIZE_1MB; - } else if ((_size >= SZ_64KB) && - (is_aligned(_padr, SZ_64KB) || (padr == 0)) && - is_aligned(_dspadr, SZ_64KB)) { - unit = SZ_64KB; - pgsz = DSP_MMU_CAM_PAGESIZE_64KB; - } else { - unit = SZ_4KB; - pgsz = DSP_MMU_CAM_PAGESIZE_4KB; - } - - order = get_order(unit); - - /* buffer allocation */ - if (type == EXMAP_TYPE_MEM) { - struct page *page, *ps, *pe; - - if ((order == ORDER_1MB) && likely(kmem_pool_1M)) - buf = mempool_alloc_from_pool(kmem_pool_1M, GFP_KERNEL); - else if ((order == ORDER_64KB) && likely(kmem_pool_64K)) - buf = mempool_alloc_from_pool(kmem_pool_64K,GFP_KERNEL); - else { - buf = (void *)__get_dma_pages(GFP_KERNEL, order); - if (buf == NULL) { - status = -ENOMEM; - goto fail; - } - } - - /* mark the pages as reserved; this is needed for mmap */ - ps = virt_to_page(buf); - pe = virt_to_page(buf + unit); - - for (page = ps; page < pe; page++) - SetPageReserved(page); - - _padr = __pa(buf); - } - - /* - * mapping for ARM MMU: - * we should not access to the allocated memory through 'buf' - * since this area should not be cashed. - */ - status = exmap_set_armmmu((unsigned long)_vadr, _padr, unit); - if (status < 0) - goto fail; - - /* loading DSP TLB entry */ - INIT_TLB_ENTRY(&tlb_ent, _dspadr, _padr, pgsz); - status = dsp_mmu_load_tlb(&tlb_ent); - if (status < 0) { - exmap_clear_armmmu((unsigned long)_vadr, unit); - goto fail; - } - - INIT_EXMAP_TBL_ENTRY(exmap_ent, buf, _vadr, type, order); - exmap_ent->link.prev = prev; - if (prev >= 0) - exmap_tbl[prev].link.next = idx; - - if ((_size -= unit) == 0) { /* normal completion */ - up_write(&exmap_sem); - return size; - } - - _dspadr += unit; - _vadr += unit; - _padr = padr ? _padr + unit : 0; - prev = idx; - goto start; - -fail: - up_write(&exmap_sem); - if (buf) - dsp_mem_free_pages((unsigned long)buf, order); - dsp_exunmap(dspadr); - return status; -} - -static unsigned long unmap_free_arm(struct exmap_tbl_entry *ent) -{ - unsigned long size; - - /* clearing ARM MMU */ - size = 1 << (ent->order + PAGE_SHIFT); - exmap_clear_armmmu((unsigned long)ent->vadr, size); - - /* freeing allocated memory */ - if (ent->type == EXMAP_TYPE_MEM) { - dsp_mem_free_pages((unsigned long)ent->buf, ent->order); - printk(KERN_DEBUG - "omapdsp: freeing 0x%lx bytes @ adr 0x%8p\n", - size, ent->buf); - } -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL - else if (ent->type == EXMAP_TYPE_FB) { - int status; - if (omapfb_nb) { - status = omapfb_unregister_client(omapfb_nb); - if (!status) - printk("omapfb_unregister_client(): " - "success\n"); - else - printk("omapfb_runegister_client(): " - "failure(%d)\n", status); - kfree(omapfb_nb); - omapfb_nb = NULL; - omapfb_ready = 0; - } - } -#endif - - return size; -} - -static int dsp_exunmap(dsp_long_t dspadr) -{ - void *vadr; - unsigned long size; - int total = 0; - struct exmap_tbl_entry *ent; - int idx; - - vadr = dspbyte_to_virt(dspadr); - down_write(&exmap_sem); - for (idx = 0; idx < DSP_MMU_TLB_LINES; idx++) { - ent = &exmap_tbl[idx]; - if ((!ent->valid) || ent->prsvd) - continue; - if (ent->vadr == vadr) - goto found_map; - } - up_write(&exmap_sem); - printk(KERN_WARNING - "omapdsp: address %06x not found in exmap_tbl.\n", dspadr); - return -EINVAL; - -found_map: - if (ent->usecount > 0) { - printk(KERN_ERR - "omapdsp: exmap reference count is not 0.\n" - " idx=%d, vadr=%p, order=%d, usecount=%d\n", - idx, ent->vadr, ent->order, ent->usecount); - up_write(&exmap_sem); - return -EINVAL; - } - /* clearing DSP TLB entry */ - dsp_mmu_clear_tlb(dspadr); - - /* clear ARM MMU and free buffer */ - size = unmap_free_arm(ent); - ent->valid = 0; - total += size; - - /* we don't free PTEs */ - - /* flush TLB */ - flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size); - - if ((idx = ent->link.next) < 0) - goto up_out; /* normal completion */ - ent = &exmap_tbl[idx]; - dspadr += size; - vadr += size; - if (ent->vadr == vadr) - goto found_map; /* continue */ - - printk(KERN_ERR - "omapdsp: illegal exmap_tbl grouping!\n" - "expected vadr = %p, exmap_tbl[%d].vadr = %p\n", - vadr, idx, ent->vadr); - up_write(&exmap_sem); - return -EINVAL; - -up_out: - up_write(&exmap_sem); - return total; -} - -static void exmap_flush(void) -{ - struct exmap_tbl_entry *ent; - int i; - - down_write(&exmap_sem); - - /* clearing DSP TLB entry */ - dsp_mmu_gflush(); - - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - ent = &exmap_tbl[i]; - if (ent->valid && (!ent->prsvd)) { - unmap_free_arm(ent); - ent->valid = 0; - } - } - - /* flush TLB */ - flush_tlb_kernel_range(dspmem_base + dspmem_size, - dspmem_base + DSPSPACE_SIZE); - up_write(&exmap_sem); -} - -#ifdef CONFIG_OMAP_DSP_FBEXPORT -#ifndef CONFIG_FB -#error You configured OMAP_DSP_FBEXPORT, but FB was not configured! -#endif /* CONFIG_FB */ - -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL -static int omapfb_notifier_cb(struct notifier_block *omapfb_nb, - unsigned long event, void *fbi) -{ - /* XXX */ - printk("omapfb_notifier_cb(): event = %s\n", - (event == OMAPFB_EVENT_READY) ? "READY" : - (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown"); - if (event == OMAPFB_EVENT_READY) - omapfb_ready = 1; - else if (event == OMAPFB_EVENT_DISABLED) - omapfb_ready = 0; - return 0; -} -#endif - -static int dsp_fbexport(dsp_long_t *dspadr) -{ - dsp_long_t dspadr_actual; - unsigned long padr_sys, padr, fbsz_sys, fbsz; - int cnt; -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL - int status; -#endif - - printk(KERN_DEBUG "omapdsp: frame buffer export\n"); - -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL - if (omapfb_nb) { - printk(KERN_WARNING - "omapdsp: frame buffer has been exported already!\n"); - return -EBUSY; - } -#endif - - if (num_registered_fb == 0) { - printk(KERN_INFO "omapdsp: frame buffer not registered.\n"); - return -EINVAL; - } - if (num_registered_fb != 1) { - printk(KERN_INFO - "omapdsp: %d frame buffers found. we use first one.\n", - num_registered_fb); - } - padr_sys = registered_fb[0]->fix.smem_start; - fbsz_sys = registered_fb[0]->fix.smem_len; - if (fbsz_sys == 0) { - printk(KERN_ERR - "omapdsp: framebuffer doesn't seem to be configured " - "correctly! (size=0)\n"); - return -EINVAL; - } - - /* - * align padr and fbsz to 4kB boundary - * (should be noted to the user afterwards!) - */ - padr = padr_sys & ~(SZ_4KB-1); - fbsz = (fbsz_sys + padr_sys - padr + SZ_4KB-1) & ~(SZ_4KB-1); - - /* line up dspadr offset with padr */ - dspadr_actual = - (fbsz > SZ_1MB) ? lineup_offset(*dspadr, padr, SZ_1MB-1) : - (fbsz > SZ_64KB) ? lineup_offset(*dspadr, padr, SZ_64KB-1) : - /* (fbsz > SZ_4KB) ? */ *dspadr; - if (dspadr_actual != *dspadr) - printk(KERN_DEBUG - "omapdsp: actual dspadr for FBEXPORT = %08x\n", - dspadr_actual); - *dspadr = dspadr_actual; - - cnt = dsp_exmap(dspadr_actual, padr, fbsz, EXMAP_TYPE_FB); - if (cnt < 0) { - printk(KERN_ERR "omapdsp: exmap failure.\n"); - return cnt; - } - - if ((padr != padr_sys) || (fbsz != fbsz_sys)) { - printk(KERN_WARNING -" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" -" !! screen base address or size is not aligned in 4kB: !!\n" -" !! actual screen adr = %08lx, size = %08lx !!\n" -" !! exporting adr = %08lx, size = %08lx !!\n" -" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n" -" !! Otherwise DSP can corrupt the kernel memory. !!\n" -" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", - padr_sys, fbsz_sys, padr, fbsz); - } - -#ifdef CONFIG_ARCH_OMAP1 - /* increase the DMA priority */ - set_emiff_dma_prio(15); -#endif - -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL - omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL); - if (omapfb_nb == NULL) { - printk(KERN_ERR - "omapdsp: failed to allocate memory for omapfb_nb!\n"); - dsp_exunmap(dspadr_actual); - return -ENOMEM; - } - status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL); - if (!status) - printk("omapfb_register_client(): success\n"); - else - printk("omapfb_register_client(): failure(%d)\n", status); -#endif - - return cnt; -} - -#else /* CONFIG_OMAP_DSP_FBEXPORT */ - -static int dsp_fbexport(dsp_long_t *dspadr) -{ - printk(KERN_ERR "omapdsp: FBEXPORT function is not enabled.\n"); - return -EINVAL; -} - -#endif /* CONFIG_OMAP_DSP_FBEXPORT */ - -static void exmap_setup_preserved_mem_page(void *buf, dsp_long_t dspadr, - int exmap_idx) -{ - unsigned long phys; - void *virt; - struct tlb_entry tlb_ent; - - phys = __pa(buf); - virt = dspbyte_to_virt(dspadr); - exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); - INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], buf, virt); - INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, dspadr, phys); - dsp_mmu_load_tlb(&tlb_ent); -} - -static void exmap_clear_mem_page(dsp_long_t dspadr) -{ - void *virt; - - virt = dspbyte_to_virt(dspadr); - exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE); - /* DSP MMU is shutting down. not handled here. */ -} - -#ifdef CONFIG_ARCH_OMAP2 -static void exmap_setup_iomap_page(unsigned long phys, unsigned long dsp_io_adr, - int exmap_idx) -{ - dsp_long_t dspadr; - void *virt; - struct tlb_entry tlb_ent; - - dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1); - virt = dspbyte_to_virt(dspadr); - exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); - INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(&exmap_tbl[exmap_idx], NULL, virt); - INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys); - dsp_mmu_load_tlb(&tlb_ent); -} - -static void exmap_clear_iomap_page(unsigned long dsp_io_adr) -{ - dsp_long_t dspadr; - void *virt; - - dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1); - virt = dspbyte_to_virt(dspadr); - exmap_clear_armmmu((unsigned long)virt, PAGE_SIZE); - /* DSP MMU is shutting down. not handled here. */ -} -#endif /* CONFIG_ARCH_OMAP2 */ - -#define OMAP2420_GPT5_BASE (L4_24XX_BASE + 0x7c000) -#define OMAP2420_GPT6_BASE (L4_24XX_BASE + 0x7e000) -#define OMAP2420_GPT7_BASE (L4_24XX_BASE + 0x80000) -#define OMAP2420_GPT8_BASE (L4_24XX_BASE + 0x82000) -#define OMAP24XX_EAC_BASE (L4_24XX_BASE + 0x90000) - -static int exmap_setup_preserved_entries(void) -{ - int n = 0; - - exmap_setup_preserved_mem_page(dspvect_page, DSP_INIT_PAGE, n++); -#ifdef CONFIG_ARCH_OMAP2 - exmap_setup_iomap_page(OMAP24XX_PRCM_BASE, 0x7000, n++); -#ifdef CONFIG_ARCH_OMAP2420 - exmap_setup_iomap_page(OMAP2420_GPT5_BASE, 0xe000, n++); - exmap_setup_iomap_page(OMAP2420_GPT6_BASE, 0xe800, n++); - exmap_setup_iomap_page(OMAP2420_GPT7_BASE, 0xf000, n++); - exmap_setup_iomap_page(OMAP2420_GPT8_BASE, 0xf800, n++); -#endif /* CONFIG_ARCH_OMAP2420 */ - exmap_setup_iomap_page(OMAP24XX_EAC_BASE, 0x10000, n++); - exmap_setup_iomap_page(OMAP24XX_MAILBOX_BASE, 0x11000, n++); -#endif /* CONFIG_ARCH_OMAP2 */ - - return n; -} - -static void exmap_clear_preserved_entries(void) -{ - exmap_clear_mem_page(DSP_INIT_PAGE); -#ifdef CONFIG_ARCH_OMAP2 - exmap_clear_iomap_page(0x7000); /* PRCM */ -#ifdef CONFIG_ARCH_OMAP2420 - exmap_clear_iomap_page(0xe000); /* GPT5 */ - exmap_clear_iomap_page(0xe800); /* GPT6 */ - exmap_clear_iomap_page(0xf000); /* GPT7 */ - exmap_clear_iomap_page(0xf800); /* GPT8 */ -#endif /* CONFIG_ARCH_OMAP2420 */ - exmap_clear_iomap_page(0x10000); /* EAC */ - exmap_clear_iomap_page(0x11000); /* MAILBOX */ -#endif /* CONFIG_ARCH_OMAP2 */ -} - -#ifdef CONFIG_ARCH_OMAP1 -static int dsp_mmu_itack(void) -{ - unsigned long dspadr; - - printk(KERN_INFO "omapdsp: sending DSP MMU interrupt ack.\n"); - if (!dsp_err_isset(ERRCODE_MMU)) { - printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n"); - return -EINVAL; - } - dspadr = dsp_fault_adr & ~(SZ_4K-1); - dsp_exmap(dspadr, 0, SZ_4K, EXMAP_TYPE_MEM); /* FIXME: reserve TLB entry for this */ - printk(KERN_INFO "omapdsp: falling into recovery runlevel...\n"); - dsp_set_runlevel(RUNLEVEL_RECOVERY); - __dsp_mmu_itack(); - udelay(100); - dsp_exunmap(dspadr); - dsp_err_clear(ERRCODE_MMU); - return 0; -} -#endif /* CONFIG_ARCH_OMAP1 */ - -#ifdef CONFIG_ARCH_OMAP2 -#define MMU_IRQ_MASK \ - (DSP_MMU_IRQ_MULTIHITFAULT | \ - DSP_MMU_IRQ_TABLEWALKFAULT | \ - DSP_MMU_IRQ_EMUMISS | \ - DSP_MMU_IRQ_TRANSLATIONFAULT | \ - DSP_MMU_IRQ_TLBMISS) -#endif - -static int is_mmu_init; - -static void dsp_mmu_init(void) -{ - struct tlb_lock tlb_lock; - -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(dsp_ck_handle); - omap_dsp_request_mem(); -#endif - down_write(&exmap_sem); - -#if defined(CONFIG_ARCH_OMAP1) - dsp_mmu_disable(); /* clear all */ - udelay(100); -#elif defined(CONFIG_ARCH_OMAP2) - dsp_mmu_reset(); -#endif - dsp_mmu_enable(); - - /* DSP TLB initialization */ - tlb_lock.base = 0; - tlb_lock.victim = 0; - set_tlb_lock(&tlb_lock); - - exmap_preserved_cnt = exmap_setup_preserved_entries(); - -#ifdef CONFIG_ARCH_OMAP2 - /* MMU IRQ mask setup */ - dsp_mmu_write_reg(MMU_IRQ_MASK, DSP_MMU_IRQENABLE); -#endif - - up_write(&exmap_sem); -#ifdef CONFIG_ARCH_OMAP1 - omap_dsp_release_mem(); - clk_disable(dsp_ck_handle); -#endif - - is_mmu_init = 1; -} - -static void dsp_mmu_shutdown(void) -{ - if (is_mmu_init) { - exmap_flush(); - exmap_clear_preserved_entries(); - dsp_mmu_disable(); - } -} - -#ifdef CONFIG_ARCH_OMAP1 -/* - * intmem_enable() / disable(): - * if the address is in DSP internal memories, - * we send PM mailbox commands so that DSP DMA domain won't go in idle - * when ARM is accessing to those memories. - */ -static int intmem_enable(void) -{ - int ret = 0; - - if (dsp_cfgstat_get_stat() == CFGSTAT_READY) - ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA); - - return ret; -} - -static void intmem_disable(void) { - if (dsp_cfgstat_get_stat() == CFGSTAT_READY) - mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA); -} -#endif /* CONFIG_ARCH_OMAP1 */ - -/* - * dsp_mem_enable() / disable() - */ -#ifdef CONFIG_ARCH_OMAP1 -int intmem_usecount; -#endif - -int dsp_mem_enable(void *adr) -{ - int ret = 0; - - if (is_dsp_internal_mem(adr)) { -#ifdef CONFIG_ARCH_OMAP1 - if (intmem_usecount++ == 0) - ret = omap_dsp_request_mem(); -#endif - } else - down_read(&exmap_sem); - - return ret; -} - -void dsp_mem_disable(void *adr) -{ - if (is_dsp_internal_mem(adr)) { -#ifdef CONFIG_ARCH_OMAP1 - if (--intmem_usecount == 0) - omap_dsp_release_mem(); -#endif - } else - up_read(&exmap_sem); -} - -/* for safety */ -#ifdef CONFIG_ARCH_OMAP1 -void dsp_mem_usecount_clear(void) -{ - if (intmem_usecount != 0) { - printk(KERN_WARNING - "omapdsp: unbalanced memory request/release detected.\n" - " intmem_usecount is not zero at where " - "it should be! ... fixed to be zero.\n"); - intmem_usecount = 0; - omap_dsp_release_mem(); - } -} -#endif /* CONFIG_ARCH_OMAP1 */ - -/* - * dsp_mem file operations - */ -static loff_t dsp_mem_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t ret; - - mutex_lock(&file->f_dentry->d_inode->i_mutex); - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - break; - default: - ret = -EINVAL; - } - mutex_unlock(&file->f_dentry->d_inode->i_mutex); - return ret; -} - -static ssize_t intmem_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned long p = *ppos; - void *vadr = dspbyte_to_virt(p); - ssize_t size = dspmem_size; - ssize_t read; - - if (p >= size) - return 0; -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(api_ck_handle); -#endif - read = count; - if (count > size - p) - read = size - p; - if (copy_to_user(buf, vadr, read)) { - read = -EFAULT; - goto out; - } - *ppos += read; -out: -#ifdef CONFIG_ARCH_OMAP1 - clk_disable(api_ck_handle); -#endif - return read; -} - -static ssize_t exmem_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned long p = *ppos; - void *vadr = dspbyte_to_virt(p); - - if (!exmap_valid(vadr, count)) { - printk(KERN_ERR - "omapdsp: DSP address %08lx / size %08x " - "is not valid!\n", p, count); - return -EFAULT; - } - if (count > DSPSPACE_SIZE - p) - count = DSPSPACE_SIZE - p; - if (copy_to_user(buf, vadr, count)) - return -EFAULT; - *ppos += count; - - return count; -} - -static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - int ret; - void *vadr = dspbyte_to_virt(*(unsigned long *)ppos); - - if (dsp_mem_enable(vadr) < 0) - return -EBUSY; - if (is_dspbyte_internal_mem(*ppos)) - ret = intmem_read(file, buf, count, ppos); - else - ret = exmem_read(file, buf, count, ppos); - dsp_mem_disable(vadr); - - return ret; -} - -static ssize_t intmem_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - void *vadr = dspbyte_to_virt(p); - ssize_t size = dspmem_size; - ssize_t written; - - if (p >= size) - return 0; -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(api_ck_handle); -#endif - written = count; - if (count > size - p) - written = size - p; - if (copy_from_user(vadr, buf, written)) { - written = -EFAULT; - goto out; - } - *ppos += written; -out: -#ifdef CONFIG_ARCH_OMAP1 - clk_disable(api_ck_handle); -#endif - return written; -} - -static ssize_t exmem_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - void *vadr = dspbyte_to_virt(p); - - if (!exmap_valid(vadr, count)) { + (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) || + (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) { printk(KERN_ERR - "omapdsp: DSP address %08lx / size %08x " - "is not valid!\n", p, count); - return -EFAULT; + "omapdsp: mem_sync address validation failure!\n" + " mem_sync.DARAM = 0x%p,\n" + " mem_sync.SARAM = 0x%p,\n" + " mem_sync.SDRAM = 0x%p,\n", + sync->DARAM, sync->SARAM, sync->SDRAM); + return -1; } - if (count > DSPSPACE_SIZE - p) - count = DSPSPACE_SIZE - p; - if (copy_from_user(vadr, buf, count)) - return -EFAULT; - *ppos += count; - return count; + memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct)); + + return 0; } -static ssize_t dsp_mem_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) + +enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len) { + void *ds = (void *)daram_base; + void *de = (void *)daram_base + daram_size; + void *ss = (void *)saram_base; + void *se = (void *)saram_base + saram_size; int ret; - void *vadr = dspbyte_to_virt(*(unsigned long *)ppos); - - if (dsp_mem_enable(vadr) < 0) - return -EBUSY; - if (is_dspbyte_internal_mem(*ppos)) - ret = intmem_write(file, buf, count, ppos); - else - ret = exmem_write(file, buf, count, ppos); - dsp_mem_disable(vadr); - return ret; + if ((vadr >= ds) && (vadr < de)) { + if (vadr + len > de) + return MEM_TYPE_CROSSING; + else + return MEM_TYPE_DARAM; + } else if ((vadr >= ss) && (vadr < se)) { + if (vadr + len > se) + return MEM_TYPE_CROSSING; + else + return MEM_TYPE_SARAM; + } else { + down_read(&dsp_mmu.exmap_sem); + if (exmap_valid(&dsp_mmu, vadr, len)) + ret = MEM_TYPE_EXTERN; + else + ret = MEM_TYPE_NONE; + up_read(&dsp_mmu.exmap_sem); + return ret; + } } -static int dsp_mem_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +int dsp_address_validate(void *p, size_t len, char *fmt, ...) { - switch (cmd) { - case MEM_IOCTL_MMUINIT: - dsp_mmu_init(); - return 0; - - case MEM_IOCTL_EXMAP: - { - struct omap_dsp_mapinfo mapinfo; - if (copy_from_user(&mapinfo, (void __user *)arg, - sizeof(mapinfo))) - return -EFAULT; - return dsp_exmap(mapinfo.dspadr, 0, mapinfo.size, - EXMAP_TYPE_MEM); - } - - case MEM_IOCTL_EXUNMAP: - return dsp_exunmap((unsigned long)arg); + char s[64]; + va_list args; - case MEM_IOCTL_EXMAP_FLUSH: - exmap_flush(); + if (dsp_mem_type(p, len) > 0) return 0; - case MEM_IOCTL_FBEXPORT: - { - dsp_long_t dspadr; - int ret; - if (copy_from_user(&dspadr, (void __user *)arg, - sizeof(dsp_long_t))) - return -EFAULT; - ret = dsp_fbexport(&dspadr); - if (copy_to_user((void __user *)arg, &dspadr, - sizeof(dsp_long_t))) - return -EFAULT; - return ret; - } - -#ifdef CONFIG_ARCH_OMAP1 - case MEM_IOCTL_MMUITACK: - return dsp_mmu_itack(); -#endif - - case MEM_IOCTL_KMEM_RESERVE: - { - __u32 size; - if (copy_from_user(&size, (void __user *)arg, - sizeof(__u32))) - return -EFAULT; - return dsp_kmem_reserve(size); - } - - case MEM_IOCTL_KMEM_RELEASE: - dsp_kmem_release(); - return 0; + if (fmt == NULL) + goto out; - default: - return -ENOIOCTLCMD; - } + va_start(args, fmt); + vsprintf(s, fmt, args); + va_end(args); + printk(KERN_ERR + "omapdsp: %s address(0x%p) and size(0x%x) is not valid!\n" + "(crossing different type of memories, or external memory\n" + "space where no actual memory is mapped)\n", s, p, len); + out: + return -1; } -static int dsp_mem_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* - * FIXME - */ - return -ENOSYS; -} +#ifdef CONFIG_OMAP_DSP_FBEXPORT -static int dsp_mem_open(struct inode *inode, struct file *file) +static inline unsigned long lineup_offset(unsigned long adr, + unsigned long ref, + unsigned long mask) { - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; + unsigned long newadr; - return 0; + newadr = (adr & ~mask) | (ref & mask); + if (newadr < adr) + newadr += mask + 1; + return newadr; } -#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL /* * fb update functions: * fbupd_response() is executed by the workqueue. @@ -2014,12 +178,13 @@ static void fbupd_response(struct work_struct *unused) int status; status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD); - if (status < 0) { - /* FIXME: DSP is busy !! */ - printk(KERN_ERR - "omapdsp: DSP is busy when trying to send FBCTL:UPD " - "response!\n"); - } + if (status == 0) + return; + + /* FIXME: DSP is busy !! */ + printk(KERN_ERR + "omapdsp:" + "DSP is busy when trying to send FBCTL:UPD response!\n"); } static DECLARE_WORK(fbupd_response_work, fbupd_response); @@ -2034,7 +199,6 @@ void mbox_fbctl_upd(void) struct omapfb_update_window win; volatile unsigned short *buf = ipbuf_sys_da->d; - /* FIXME: try count sometimes exceeds 1000. */ if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) { printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n"); return; @@ -2051,377 +215,199 @@ void mbox_fbctl_upd(void) "omapdsp: fbupd() called while HWA742 is not ready!\n"); return; } - //printk("calling omapfb_update_window_async()\n"); omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL); } -#else /* CONFIG_FB_OMAP_LCDC_EXTERNAL */ - -void mbox_fbctl_upd(void) +#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL +static int omapfb_notifier_cb(struct notifier_block *omapfb_nb, + unsigned long event, void *fbi) { + pr_info("omapfb_notifier_cb(): event = %s\n", + (event == OMAPFB_EVENT_READY) ? "READY" : + (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown"); + if (event == OMAPFB_EVENT_READY) + omapfb_ready = 1; + else if (event == OMAPFB_EVENT_DISABLED) + omapfb_ready = 0; + return 0; } -#endif /* CONFIG_FB_OMAP_LCDC_EXTERNAL */ - -/* - * sysfs files - */ +#endif -/* mmu */ -static ssize_t mmu_show(struct device *dev, struct device_attribute *attr, - char *buf) +static int dsp_fbexport(dsp_long_t *dspadr) { - int len; - struct tlb_lock tlb_lock_org; - int i; - -#ifdef CONFIG_ARCH_OMAP1 - clk_enable(dsp_ck_handle); - omap_dsp_request_mem(); -#endif - down_read(&exmap_sem); + dsp_long_t dspadr_actual; + unsigned long padr_sys, padr, fbsz_sys, fbsz; + int cnt, status; - get_tlb_lock(&tlb_lock_org); + pr_debug( "omapdsp: frame buffer export\n"); -#if defined(CONFIG_ARCH_OMAP1) - len = sprintf(buf, "P: preserved, V: valid\n" - "ety P V size cam_va ram_pa ap\n"); - /* 00: P V 4KB 0x300000 0x10171800 FA */ -#elif defined(CONFIG_ARCH_OMAP2) - len = sprintf(buf, "P: preserved, V: valid\n" - "B: big endian, L:little endian, " - "M: mixed page attribute\n" - "ety P V size cam_va ram_pa E ES M\n"); - /* 00: P V 4KB 0x300000 0x10171800 B 16 M */ +#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL + if (omapfb_nb) { + printk(KERN_WARNING + "omapdsp: frame buffer has been exported already!\n"); + return -EBUSY; + } #endif - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - struct cam_ram_regset cr; - struct tlb_lock tlb_lock_tmp; - struct tlb_entry ent; -#if defined(CONFIG_ARCH_OMAP1) - char *pgsz_str, *ap_str; -#elif defined(CONFIG_ARCH_OMAP2) - char *pgsz_str, *elsz_str; -#endif + if (num_registered_fb == 0) { + pr_info("omapdsp: frame buffer not registered.\n"); + return -EINVAL; + } + if (num_registered_fb != 1) { + pr_info("omapdsp: %d frame buffers found. we use first one.\n", + num_registered_fb); + } + padr_sys = registered_fb[0]->fix.smem_start; + fbsz_sys = registered_fb[0]->fix.smem_len; + if (fbsz_sys == 0) { + printk(KERN_ERR + "omapdsp: framebuffer doesn't seem to be configured " + "correctly! (size=0)\n"); + return -EINVAL; + } + + /* + * align padr and fbsz to 4kB boundary + * (should be noted to the user afterwards!) + */ + padr = padr_sys & ~(SZ_4K-1); + fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1); - /* read a TLB entry */ - tlb_lock_tmp.base = tlb_lock_org.base; - tlb_lock_tmp.victim = i; - __read_tlb(&tlb_lock_tmp, &cr); + /* line up dspadr offset with padr */ + dspadr_actual = + (fbsz > SZ_1M) ? lineup_offset(*dspadr, padr, SZ_1M-1) : + (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) : + /* (fbsz > SZ_4KB) ? */ *dspadr; + if (dspadr_actual != *dspadr) + pr_debug( + "omapdsp: actual dspadr for FBEXPORT = %08x\n", + dspadr_actual); + *dspadr = dspadr_actual; -#if defined(CONFIG_ARCH_OMAP1) - ent.pgsz = cr.cam_l & DSP_MMU_CAM_PAGESIZE_MASK; - ent.prsvd = cr.cam_l & DSP_MMU_CAM_P; - ent.valid = cr.cam_l & DSP_MMU_CAM_V; - ent.ap = cr.ram_l & DSP_MMU_RAM_L_AP_MASK; - ent.va = (u32)(cr.cam_h & DSP_MMU_CAM_H_VA_TAG_H_MASK) << 22 | - (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6; - ent.pa = (unsigned long)cr.ram_h << 16 | - (cr.ram_l & DSP_MMU_RAM_L_RAM_LSB_MASK); - - pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB) ? " 1MB": - (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB": - (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB) ? " 4KB": - (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1KB) ? " 1KB": - " ???"; - ap_str = (ent.ap == DSP_MMU_RAM_L_AP_RO) ? "RO": - (ent.ap == DSP_MMU_RAM_L_AP_FA) ? "FA": - (ent.ap == DSP_MMU_RAM_L_AP_NA) ? "NA": - "??"; -#elif defined(CONFIG_ARCH_OMAP2) - ent.pgsz = cr.cam & DSP_MMU_CAM_PAGESIZE_MASK; - ent.prsvd = cr.cam & DSP_MMU_CAM_P; - ent.valid = cr.cam & DSP_MMU_CAM_V; - ent.va = cr.cam & DSP_MMU_CAM_VATAG_MASK; - ent.endian = cr.ram & DSP_MMU_RAM_ENDIANNESS; - ent.elsz = cr.ram & DSP_MMU_RAM_ELEMENTSIZE_MASK; - ent.pa = cr.ram & DSP_MMU_RAM_PADDR_MASK; - ent.mixed = cr.ram & DSP_MMU_RAM_MIXED; - - pgsz_str = (ent.pgsz == DSP_MMU_CAM_PAGESIZE_16MB) ? "64MB": - (ent.pgsz == DSP_MMU_CAM_PAGESIZE_1MB) ? " 1MB": - (ent.pgsz == DSP_MMU_CAM_PAGESIZE_64KB) ? "64KB": - (ent.pgsz == DSP_MMU_CAM_PAGESIZE_4KB) ? " 4KB": - " ???"; - elsz_str = (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_8) ? " 8": - (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_16) ? "16": - (ent.elsz == DSP_MMU_RAM_ELEMENTSIZE_32) ? "32": - "??"; -#endif + cnt = omap_mmu_exmap(&dsp_mmu, dspadr_actual, padr, fbsz, + EXMAP_TYPE_FB); + if (cnt < 0) { + printk(KERN_ERR "omapdsp: exmap failure.\n"); + return cnt; + } - if (i == tlb_lock_org.base) - len += sprintf(buf + len, "lock base = %d\n", - tlb_lock_org.base); - if (i == tlb_lock_org.victim) - len += sprintf(buf + len, "victim = %d\n", - tlb_lock_org.victim); -#if defined(CONFIG_ARCH_OMAP1) - len += sprintf(buf + len, - /* 00: P V 4KB 0x300000 0x10171800 FA */ - "%02d: %c %c %s 0x%06x 0x%08lx %s\n", - i, - ent.prsvd ? 'P' : ' ', - ent.valid ? 'V' : ' ', - pgsz_str, ent.va, ent.pa, ap_str); -#elif defined(CONFIG_ARCH_OMAP2) - len += sprintf(buf + len, - /* 00: P V 4KB 0x300000 0x10171800 B 16 M */ - "%02d: %c %c %s 0x%06x 0x%08lx %c %s %c\n", - i, - ent.prsvd ? 'P' : ' ', - ent.valid ? 'V' : ' ', - pgsz_str, ent.va, ent.pa, - ent.endian ? 'B' : 'L', - elsz_str, - ent.mixed ? 'M' : ' '); -#endif /* CONFIG_ARCH_OMAP2 */ + if ((padr != padr_sys) || (fbsz != fbsz_sys)) { + printk(KERN_WARNING +" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" +" !! screen base address or size is not aligned in 4kB: !!\n" +" !! actual screen adr = %08lx, size = %08lx !!\n" +" !! exporting adr = %08lx, size = %08lx !!\n" +" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n" +" !! Otherwise DSP can corrupt the kernel memory. !!\n" +" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", + padr_sys, fbsz_sys, padr, fbsz); } - /* restore victim entry */ - set_tlb_lock(&tlb_lock_org); + /* increase the DMA priority */ + set_emiff_dma_prio(15); - up_read(&exmap_sem); -#ifdef CONFIG_ARCH_OMAP1 - omap_dsp_release_mem(); - clk_disable(dsp_ck_handle); +#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL + omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL); + if (omapfb_nb == NULL) { + printk(KERN_ERR + "omapdsp: failed to allocate memory for omapfb_nb!\n"); + omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr); + return -ENOMEM; + } + + status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL); + if (status) + pr_info("omapfb_register_client(): failure(%d)\n", status); #endif - return len; + + return cnt; } +#else +void mbox_fbctl_upd(void) { } +#endif -/* exmap */ -static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, - char *buf) +/* dsp/mem fops: backward compatibility */ +static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) { - int len; - int i; - - down_read(&exmap_sem); - len = sprintf(buf, " dspadr size buf size uc\n"); - /* 0x300000 0x123000 0xc0171000 0x100000 0*/ - for (i = 0; i < DSP_MMU_TLB_LINES; i++) { - struct exmap_tbl_entry *ent = &exmap_tbl[i]; - void *vadr; - unsigned long size; - enum exmap_type_e type; - int idx; - - /* find a top of link */ - if (!ent->valid || (ent->link.prev >= 0)) - continue; - - vadr = ent->vadr; - type = ent->type; - size = 0; - idx = i; - do { - ent = &exmap_tbl[idx]; - size += PAGE_SIZE << ent->order; - } while ((idx = ent->link.next) >= 0); - - len += sprintf(buf + len, "0x%06x %#8lx", - virt_to_dspbyte(vadr), size); - - if (type == EXMAP_TYPE_FB) { - len += sprintf(buf + len, " framebuf\n"); - } else { - len += sprintf(buf + len, "\n"); - idx = i; - do { - ent = &exmap_tbl[idx]; - len += sprintf(buf + len, - /* 0xc0171000 0x100000 0*/ - "%19s0x%8p %#8lx %2d\n", - "", ent->buf, - PAGE_SIZE << ent->order, - ent->usecount); - } while ((idx = ent->link.next) >= 0); - } - } - - up_read(&exmap_sem); - return len; + return __omap_mmu_mem_read(&dsp_mmu, buf, *ppos, count); } -/* mempool */ -static ssize_t mempool_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t dsp_mem_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { - int min_nr_1M = 0, curr_nr_1M = 0; - int min_nr_64K = 0, curr_nr_64K = 0; - int total = 0; - - if (likely(kmem_pool_1M)) { - min_nr_1M = kmem_pool_1M->min_nr; - curr_nr_1M = kmem_pool_1M->curr_nr; - total += min_nr_1M * SZ_1MB; - } - if (likely(kmem_pool_64K)) { - min_nr_64K = kmem_pool_64K->min_nr; - curr_nr_64K = kmem_pool_64K->curr_nr; - total += min_nr_64K * SZ_64KB; - } - - return sprintf(buf, - "0x%x\n" - "1M buffer: %d (%d free)\n" - "64K buffer: %d (%d free)\n", - total, min_nr_1M, curr_nr_1M, min_nr_64K, curr_nr_64K); + return __omap_mmu_mem_write(&dsp_mmu, + (char __user *)buf, *ppos, count); } -/* - * workqueue for mmu int - */ -#ifdef CONFIG_ARCH_OMAP1 -/* - * MMU fault mask: - * We ignore prefetch err. - */ -#define MMUFAULT_MASK \ - (DSP_MMU_FAULT_ST_PERM |\ - DSP_MMU_FAULT_ST_TLB_MISS |\ - DSP_MMU_FAULT_ST_TRANS) -#endif /* CONFIG_ARCH_OMAP1 */ - -static void do_mmu_int(struct work_struct *unused) +static int dsp_mem_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { -#if defined(CONFIG_ARCH_OMAP1) - - dsp_mmu_reg_t status; - dsp_mmu_reg_t adh, adl; - dsp_mmu_reg_t dp; - - status = dsp_mmu_read_reg(DSP_MMU_FAULT_ST); - adh = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_H); - adl = dsp_mmu_read_reg(DSP_MMU_FAULT_AD_L); - dp = adh & DSP_MMU_FAULT_AD_H_DP; - dsp_fault_adr = MK32(adh & DSP_MMU_FAULT_AD_H_ADR_MASK, adl); - - /* if the fault is masked, nothing to do */ - if ((status & MMUFAULT_MASK) == 0) { - printk(KERN_DEBUG "DSP MMU interrupt, but ignoring.\n"); - /* - * note: in OMAP1710, - * when CACHE + DMA domain gets out of idle in DSP, - * MMU interrupt occurs but DSP_MMU_FAULT_ST is not set. - * in this case, we just ignore the interrupt. - */ - if (status) { - printk(KERN_DEBUG "%s%s%s%s\n", - (status & DSP_MMU_FAULT_ST_PREF)? - " (prefetch err)" : "", - (status & DSP_MMU_FAULT_ST_PERM)? - " (permission fault)" : "", - (status & DSP_MMU_FAULT_ST_TLB_MISS)? - " (TLB miss)" : "", - (status & DSP_MMU_FAULT_ST_TRANS) ? - " (translation fault)": ""); - printk(KERN_DEBUG "fault address = %#08x\n", - dsp_fault_adr); - } - enable_irq(omap_dsp->mmu_irq); - return; - } + struct omap_dsp_mapinfo mapinfo; + dsp_long_t dspadr; + int ret; + __u32 size; -#elif defined(CONFIG_ARCH_OMAP2) + switch (cmd) { + case MEM_IOCTL_MMUINIT: + if (dsp_mmu.exmap_tbl) + omap_mmu_unregister(&dsp_mmu); + return omap_mmu_register(&dsp_mmu); - dsp_mmu_reg_t status; + case MEM_IOCTL_EXMAP: + if (copy_from_user(&mapinfo, (void __user *)arg, + sizeof(mapinfo))) + return -EFAULT; + return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr, + 0, mapinfo.size, EXMAP_TYPE_MEM); - status = dsp_mmu_read_reg(DSP_MMU_IRQSTATUS); - dsp_fault_adr = dsp_mmu_read_reg(DSP_MMU_FAULT_AD); + case MEM_IOCTL_EXUNMAP: + return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg); -#endif /* CONFIG_ARCH_OMAP2 */ + case MEM_IOCTL_EXMAP_FLUSH: + omap_mmu_exmap_flush(&dsp_mmu); + return 0; +#ifdef CONFIG_OMAP_DSP_FBEXPORT + case MEM_IOCTL_FBEXPORT: + if (copy_from_user(&dspadr, (void __user *)arg, + sizeof(dsp_long_t))) + return -EFAULT; + ret = dsp_fbexport(&dspadr); + if (copy_to_user((void __user *)arg, &dspadr, + sizeof(dsp_long_t))) + return -EFAULT; + return ret; +#endif + case MEM_IOCTL_MMUITACK: + return dsp_mmu_itack(); - printk(KERN_INFO "DSP MMU interrupt!\n"); + case MEM_IOCTL_KMEM_RESERVE: -#if defined(CONFIG_ARCH_OMAP1) + if (copy_from_user(&size, (void __user *)arg, + sizeof(__u32))) + return -EFAULT; + return omap_mmu_kmem_reserve(&dsp_mmu, size); - printk(KERN_INFO "%s%s%s%s\n", - (status & DSP_MMU_FAULT_ST_PREF)? - (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PREF)? - " prefetch err": - " (prefetch err)": - "", - (status & DSP_MMU_FAULT_ST_PERM)? - (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PERM)? - " permission fault": - " (permission fault)": - "", - (status & DSP_MMU_FAULT_ST_TLB_MISS)? - (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TLB_MISS)? - " TLB miss": - " (TLB miss)": - "", - (status & DSP_MMU_FAULT_ST_TRANS)? - (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TRANS)? - " translation fault": - " (translation fault)": - ""); -#elif defined(CONFIG_ARCH_OMAP2) + case MEM_IOCTL_KMEM_RELEASE: + omap_mmu_kmem_release(); + return 0; - printk(KERN_INFO "%s%s%s%s%s\n", - (status & DSP_MMU_IRQ_MULTIHITFAULT)? - (MMU_IRQ_MASK & DSP_MMU_IRQ_MULTIHITFAULT)? - " multi hit": - " (multi hit)": - "", - (status & DSP_MMU_IRQ_TABLEWALKFAULT)? - (MMU_IRQ_MASK & DSP_MMU_IRQ_TABLEWALKFAULT)? - " table walk fault": - " (table walk fault)": - "", - (status & DSP_MMU_IRQ_EMUMISS)? - (MMU_IRQ_MASK & DSP_MMU_IRQ_EMUMISS)? - " EMU miss": - " (EMU miss)": - "", - (status & DSP_MMU_IRQ_TRANSLATIONFAULT)? - (MMU_IRQ_MASK & DSP_MMU_IRQ_TRANSLATIONFAULT)? - " translation fault": - " (translation fault)": - "", - (status & DSP_MMU_IRQ_TLBMISS)? - (MMU_IRQ_MASK & DSP_MMU_IRQ_TLBMISS)? - " TLB miss": - " (TLB miss)": - ""); - -#endif /* CONFIG_ARCH_OMAP2 */ - - printk(KERN_INFO "fault address = %#08x\n", dsp_fault_adr); - - if (dsp_cfgstat_get_stat() == CFGSTAT_READY) - dsp_err_set(ERRCODE_MMU, (unsigned long)dsp_fault_adr); - else { -#ifdef CONFIG_ARCH_OMAP1 - __dsp_mmu_itack(); -#endif - printk(KERN_INFO "Resetting DSP...\n"); - dsp_cpustat_request(CPUSTAT_RESET); - /* - * if we enable followings, semaphore lock should be avoided. - * - printk(KERN_INFO "Flushing DSP MMU...\n"); - exmap_flush(); - dsp_mmu_init(); - */ + default: + return -ENOIOCTLCMD; } - -#ifdef CONFIG_ARCH_OMAP2 - dsp_mmu_disable(); - dsp_mmu_write_reg(status, DSP_MMU_IRQSTATUS); - dsp_mmu_enable(); -#endif - - enable_irq(omap_dsp->mmu_irq); } -static DECLARE_WORK(mmu_int_work, do_mmu_int); +struct file_operations dsp_mem_fops = { + .owner = THIS_MODULE, + .read = dsp_mem_read, + .write = dsp_mem_write, + .ioctl = dsp_mem_ioctl, +}; /* * DSP MMU interrupt handler */ - static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id) { disable_irq(omap_dsp->mmu_irq); @@ -2429,32 +415,15 @@ static irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * - */ -struct file_operations dsp_mem_fops = { - .owner = THIS_MODULE, - .llseek = dsp_mem_lseek, - .read = dsp_mem_read, - .write = dsp_mem_write, - .ioctl = dsp_mem_ioctl, - .mmap = dsp_mem_mmap, - .open = dsp_mem_open, -}; - void dsp_mem_start(void) { -#ifdef CONFIG_ARCH_OMAP1 dsp_register_mem_cb(intmem_enable, intmem_disable); -#endif } void dsp_mem_stop(void) { memset(&mem_sync, 0, sizeof(struct mem_sync_struct)); -#ifdef CONFIG_ARCH_OMAP1 dsp_unregister_mem_cb(); -#endif } /* @@ -2462,65 +431,55 @@ void dsp_mem_stop(void) */ void dsp_mem_late_init(void) { + int ret = 0; #ifdef CONFIG_ARCH_OMAP2 - int i; - int dspmem_pg_count; + int i, dspmem_pg_count; dspmem_pg_count = dspmem_size >> 12; for (i = 0; i < dspmem_pg_count; i++) { - dsp_ipi_write_reg(i, DSP_IPI_INDEX); - dsp_ipi_write_reg(DSP_IPI_ENTRY_ELMSIZEVALUE_16, - DSP_IPI_ENTRY); + writel(i, DSP_IPI_INDEX); + writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY); } - dsp_ipi_write_reg(1, DSP_IPI_ENABLE); - dsp_ipi_write_reg(IOMAP_VAL, DSP_IPI_IOMAP); + writel(1, DSP_IPI_ENABLE); + writel(IOMAP_VAL, DSP_IPI_IOMAP); + + dsp_mmu.clk = dsp_fck_handle; + dsp_mmu.memclk = dsp_ick_handle; +#elif defined(CONFIG_ARCH_OMAP1) + dsp_mmu.clk = dsp_ck_handle; + dsp_mmu.memclk = api_ck_handle; #endif - dsp_mmu_init(); + ret = omap_mmu_register(&dsp_mmu); } -static char devid_mmu; - int __init dsp_mem_init(void) { - int i, ret; - - for (i = 0; i < DSP_MMU_TLB_LINES; i++) - exmap_tbl[i].valid = 0; - - dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0); - if (dspvect_page == NULL) { - printk(KERN_ERR - "omapdsp: failed to allocate memory " - "for dsp vector table\n"); - return -ENOMEM; - } - + int ret; /* * DSP MMU interrupt setup */ ret = request_irq(omap_dsp->mmu_irq, dsp_mmu_interrupt, IRQF_DISABLED, - "dsp_mmu", &devid_mmu); + "dsp_mmu", NULL); if (ret) { printk(KERN_ERR "failed to register DSP MMU interrupt: %d\n", ret); - return ret; + goto fail; } /* MMU interrupt is not enabled until DSP runs */ disable_irq(omap_dsp->mmu_irq); - ret = device_create_file(omap_dsp->dev, &dev_attr_mmu); - ret |= device_create_file(omap_dsp->dev, &dev_attr_exmap); - ret |= device_create_file(omap_dsp->dev, &dev_attr_mempool); - if (ret) - printk(KERN_ERR "device_create_file failed: %d\n", ret); - return 0; + fail: +#ifdef CONFIG_ARCH_OMAP1 + dsp_reset_idle_boot_base(); +#endif + return ret; } void dsp_mem_exit(void) { - free_irq(omap_dsp->mmu_irq, &devid_mmu); + free_irq(omap_dsp->mmu_irq, NULL); /* recover disable_depth */ enable_irq(omap_dsp->mmu_irq); @@ -2528,15 +487,5 @@ void dsp_mem_exit(void) #ifdef CONFIG_ARCH_OMAP1 dsp_reset_idle_boot_base(); #endif - dsp_mmu_shutdown(); - dsp_kmem_release(); - - if (dspvect_page != NULL) { - free_page((unsigned long)dspvect_page); - dspvect_page = NULL; - } - - device_remove_file(omap_dsp->dev, &dev_attr_mmu); - device_remove_file(omap_dsp->dev, &dev_attr_exmap); - device_remove_file(omap_dsp->dev, &dev_attr_mempool); + omap_mmu_unregister(&dsp_mmu); } diff --git a/arch/arm/plat-omap/dsp/mmu.h b/arch/arm/plat-omap/dsp/mmu.h new file mode 100644 index 00000000000..ab9953ab9ec --- /dev/null +++ b/arch/arm/plat-omap/dsp/mmu.h @@ -0,0 +1,277 @@ +#ifndef __PLAT_OMAP_DSP_MMU_H +#define __PLAT_OMAP_DSP_MMU_H + +#ifdef CONFIG_ARCH_OMAP1 + +#ifdef CONFIG_ARCH_OMAP15XX +struct omap_mmu dsp_mmu = { + .name = "dsp", + .type = OMAP_MMU_DSP, + .base = OMAP15XX_DSP_START, + .membase = OMAP15XX_DSP_BASE, + .memsize = OMAP15XX_DSP_SIZE, + .nr_tlb_entries = 32, + .addrspace = 24, + .ops = &omap1_mmu_ops, +}; +#endif +#ifdef CONFIG_ARCH_OMAP16XX +struct omap_mmu dsp_mmu = { + .name = "dsp", + .type = OMAP_MMU_DSP, + .base = OMAP16XX_DSP_START, + .membase = OMAP16XX_DSP_BASE, + .memsize = OMAP16XX_DSP_SIZE, + .nr_tlb_entries = 32, + .addrspace = 24, + .ops = &omap1_mmu_ops, +}; +#endif +#else /* OMAP2 */ +struct omap_mmu dsp_mmu = { + .name = "dsp", + .type = OMAP_MMU_DSP, + .base = DSP_MMU_24XX_VIRT, + .membase = DSP_MEM_24XX_VIRT, + .memsize = DSP_MEM_24XX_SIZE, + .nr_tlb_entries = 32, + .addrspace = 24, + .ops = &omap2_mmu_ops, +}; + +#define IOMAP_VAL 0x3f +#endif + +static u32 dsp_fault_adr; + +#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL +static struct omapfb_notifier_block *omapfb_nb; +static int omapfb_ready; +#endif + +/* + * OMAP1 EMIFF access + */ +#ifdef CONFIG_ARCH_OMAP1 +#define EMIF_PRIO_LB_MASK 0x0000f000 +#define EMIF_PRIO_LB_SHIFT 12 +#define EMIF_PRIO_DMA_MASK 0x00000f00 +#define EMIF_PRIO_DMA_SHIFT 8 +#define EMIF_PRIO_DSP_MASK 0x00000070 +#define EMIF_PRIO_DSP_SHIFT 4 +#define EMIF_PRIO_MPU_MASK 0x00000007 +#define EMIF_PRIO_MPU_SHIFT 0 +#define set_emiff_dma_prio(prio) \ + do { \ + omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \ + ~EMIF_PRIO_DMA_MASK) | \ + ((prio) << EMIF_PRIO_DMA_SHIFT), \ + OMAP_TC_OCPT1_PRIOR); \ + } while(0) +#else +#define set_emiff_dma_prio(prio) do { } while (0) +#endif /* CONFIG_ARCH_OMAP1 */ + +/* + * workqueue for mmu int + */ +#ifdef CONFIG_ARCH_OMAP1 +/* + * MMU fault mask: + * We ignore prefetch err. + */ +#define MMUFAULT_MASK \ + (DSP_MMU_FAULT_ST_PERM |\ + DSP_MMU_FAULT_ST_TLB_MISS |\ + DSP_MMU_FAULT_ST_TRANS) + +static void do_mmu_int(struct work_struct *unused) +{ + unsigned long status; + unsigned long adh, adl; + unsigned long dp; + + status = omap_mmu_read_reg(&dsp_mmu, DSP_MMU_FAULT_ST); + adh = omap_mmu_read_reg(&dsp_mmu, DSP_MMU_FAULT_AD_H); + adl = omap_mmu_read_reg(&dsp_mmu, DSP_MMU_FAULT_AD_L); + dp = adh & DSP_MMU_FAULT_AD_H_DP; + dsp_fault_adr = MK32(adh & DSP_MMU_FAULT_AD_H_ADR_MASK, adl); + + /* if the fault is masked, nothing to do */ + if ((status & MMUFAULT_MASK) == 0) { + pr_debug( "DSP MMU interrupt, but ignoring.\n"); + /* + * note: in OMAP1710, + * when CACHE + DMA domain gets out of idle in DSP, + * MMU interrupt occurs but DSP_MMU_FAULT_ST is not set. + * in this case, we just ignore the interrupt. + */ + if (status) { + pr_debug( "%s%s%s%s\n", + (status & DSP_MMU_FAULT_ST_PREF)? + " (prefetch err)" : "", + (status & DSP_MMU_FAULT_ST_PERM)? + " (permission fault)" : "", + (status & DSP_MMU_FAULT_ST_TLB_MISS)? + " (TLB miss)" : "", + (status & DSP_MMU_FAULT_ST_TRANS) ? + " (translation fault)": ""); + pr_debug( "fault address = %#08x\n", dsp_fault_adr); + } + enable_irq(omap_dsp->mmu_irq); + return; + } + + + pr_info("%s%s%s%s\n", + (status & DSP_MMU_FAULT_ST_PREF)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PREF)? + " prefetch err": + " (prefetch err)": + "", + (status & DSP_MMU_FAULT_ST_PERM)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_PERM)? + " permission fault": + " (permission fault)": + "", + (status & DSP_MMU_FAULT_ST_TLB_MISS)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TLB_MISS)? + " TLB miss": + " (TLB miss)": + "", + (status & DSP_MMU_FAULT_ST_TRANS)? + (MMUFAULT_MASK & DSP_MMU_FAULT_ST_TRANS)? + " translation fault": + " (translation fault)": + ""); + + pr_info("fault address = %#08x\n", dsp_fault_adr); + + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) + dsp_err_set(ERRCODE_MMU, (unsigned long)dsp_fault_adr); + else { + __dsp_mmu_itack(&dsp_mmu); + + pr_info("Resetting DSP...\n"); + dsp_cpustat_request(CPUSTAT_RESET); + /* + * if we enable followings, semaphore lock should be avoided. + * + pr_info("Flushing DSP MMU...\n"); + exmap_flush(); + dsp_mmu_init(); + */ + } + + enable_irq(omap_dsp->mmu_irq); +} +#elif defined(CONFIG_ARCH_OMAP2) +static void do_mmu_int(struct work_struct *unused) +{ + unsigned long status; + + status = omap_mmu_read_reg(&dsp_mmu, DSP_MMU_IRQSTATUS); + dsp_fault_adr = omap_mmu_read_reg(&dsp_mmu, DSP_MMU_FAULT_AD); + +#define MMU_IRQ_MASK \ + (DSP_MMU_IRQ_MULTIHITFAULT | \ + DSP_MMU_IRQ_TABLEWALKFAULT | \ + DSP_MMU_IRQ_EMUMISS | \ + DSP_MMU_IRQ_TRANSLATIONFAULT | \ + DSP_MMU_IRQ_TLBMISS) + + pr_info("%s%s%s%s%s\n", + (status & DSP_MMU_IRQ_MULTIHITFAULT)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_MULTIHITFAULT)? + " multi hit": + " (multi hit)": + "", + (status & DSP_MMU_IRQ_TABLEWALKFAULT)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_TABLEWALKFAULT)? + " table walk fault": + " (table walk fault)": + "", + (status & DSP_MMU_IRQ_EMUMISS)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_EMUMISS)? + " EMU miss": + " (EMU miss)": + "", + (status & DSP_MMU_IRQ_TRANSLATIONFAULT)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_TRANSLATIONFAULT)? + " translation fault": + " (translation fault)": + "", + (status & DSP_MMU_IRQ_TLBMISS)? + (MMU_IRQ_MASK & DSP_MMU_IRQ_TLBMISS)? + " TLB miss": + " (TLB miss)": + ""); + + pr_info("fault address = %#08x\n", dsp_fault_adr); + + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) + dsp_err_set(ERRCODE_MMU, (unsigned long)dsp_fault_adr); + else { + pr_info("Resetting DSP...\n"); + dsp_cpustat_request(CPUSTAT_RESET); + } + + omap_mmu_disable(&dsp_mmu); + omap_mmu_write_reg(&dsp_mmu, status, DSP_MMU_IRQSTATUS); + omap_mmu_enable(&dsp_mmu, 0); + + enable_irq(omap_dsp->mmu_irq); +} +#endif + +static DECLARE_WORK(mmu_int_work, do_mmu_int); + +#ifdef CONFIG_ARCH_OMAP1 +static int dsp_mmu_itack(void) +{ + unsigned long dspadr; + + pr_info("omapdsp: sending DSP MMU interrupt ack.\n"); + if (!dsp_err_isset(ERRCODE_MMU)) { + printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n"); + return -EINVAL; + } + dspadr = dsp_fault_adr & ~(SZ_4K-1); + /* FIXME: reserve TLB entry for this */ + omap_mmu_exmap(&dsp_mmu, dspadr, 0, SZ_4K, EXMAP_TYPE_MEM); + pr_info("omapdsp: falling into recovery runlevel...\n"); + dsp_set_runlevel(RUNLEVEL_RECOVERY); + __dsp_mmu_itack(&dsp_mmu); + udelay(100); + omap_mmu_exunmap(&dsp_mmu, dspadr); + dsp_err_clear(ERRCODE_MMU); + return 0; +} + +/* + * intmem_enable() / disable(): + * if the address is in DSP internal memories, + * we send PM mailbox commands so that DSP DMA domain won't go in idle + * when ARM is accessing to those memories. + */ +static int intmem_enable(void) +{ + int ret = 0; + + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) + ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA); + + return ret; +} + +static void intmem_disable(void) { + if (dsp_cfgstat_get_stat() == CFGSTAT_READY) + mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA); +} +#else +static int intmem_enable(void) { return 0; } +static void intmem_disable(void) { } +static int dsp_mmu_itack(void) { return 0; } +#endif + +#endif /* __PLAT_OMAP_DSP_MMU_H */ diff --git a/arch/arm/plat-omap/dsp/task.c b/arch/arm/plat-omap/dsp/task.c index 10eee909805..25c69efde0b 100644 --- a/arch/arm/plat-omap/dsp/task.c +++ b/arch/arm/plat-omap/dsp/task.c @@ -36,13 +36,13 @@ #include #include #include +#include #include "uaccess_dsp.h" #include "dsp_mbcmd.h" #include "dsp.h" #include "ipbuf.h" #include "fifo.h" #include "proclist.h" -#include "ioctl.h" #define is_aligned(adr,align) (!((adr)&((align)-1))) @@ -1358,7 +1358,7 @@ static void dsp_task_mmap_open(struct vm_area_struct *vma) BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED)); task = dev->task; - exmap_use(task->map_base, len); + omap_mmu_exmap_use(&dsp_mmu, task->map_base, len); } static void dsp_task_mmap_close(struct vm_area_struct *vma) @@ -1369,7 +1369,7 @@ static void dsp_task_mmap_close(struct vm_area_struct *vma) BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED)); task = dev->task; - exmap_unuse(task->map_base, len); + omap_mmu_exmap_unuse(&dsp_mmu, task->map_base, len); } /** @@ -1416,7 +1416,7 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) tmp_vmadr = vma->vm_start; tmp_vadr = task->map_base + off; do { - tmp_padr = dsp_virt_to_phys(tmp_vadr, &tmp_len); + tmp_padr = omap_mmu_virt_to_phys(&dsp_mmu, tmp_vadr, &tmp_len); if (tmp_padr == 0) { printk(KERN_ERR "omapdsp: task %s: illegal address " @@ -1449,7 +1449,7 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &dsp_task_vm_ops; vma->vm_private_data = dev; - exmap_use(task->map_base, vma->vm_end - vma->vm_start); + omap_mmu_exmap_use(&dsp_mmu, task->map_base, vma->vm_end - vma->vm_start); unlock_out: devstate_read_unlock(dev); diff --git a/arch/arm/plat-omap/dsp/ioctl.h b/include/asm-arm/arch-omap/dsp.h similarity index 92% rename from arch/arm/plat-omap/dsp/ioctl.h rename to include/asm-arm/arch-omap/dsp.h index 27e8358238e..ae71eb80483 100644 --- a/arch/arm/plat-omap/dsp/ioctl.h +++ b/include/asm-arm/arch-omap/dsp.h @@ -21,6 +21,9 @@ * */ +#ifndef __ARCH_OMAP_DSP_H +#define __ARCH_OMAP_DSP_H + /* * for /dev/dspctl/ctl */ @@ -55,18 +58,18 @@ #define DSPCTL_IOCTL_MBSEND 99 struct omap_dsp_mailbox_cmd { - __u16 cmd; - __u16 data; + __u16 cmd; + __u16 data; }; struct omap_dsp_reginfo { - __u16 adr; - __u16 val; + __u16 adr; + __u16 val; }; struct omap_dsp_varinfo { - __u8 varid; - __u16 val[0]; + __u8 varid; + __u16 val[0]; }; /* @@ -86,16 +89,14 @@ struct omap_dsp_varinfo { #define MEM_IOCTL_EXUNMAP 2 #define MEM_IOCTL_EXMAP_FLUSH 3 #define MEM_IOCTL_FBEXPORT 5 -#ifdef CONFIG_ARCH_OMAP1 #define MEM_IOCTL_MMUITACK 7 -#endif #define MEM_IOCTL_MMUINIT 9 #define MEM_IOCTL_KMEM_RESERVE 11 #define MEM_IOCTL_KMEM_RELEASE 12 struct omap_dsp_mapinfo { - __u32 dspadr; - __u32 size; + __u32 dspadr; + __u32 size; }; /* @@ -108,8 +109,10 @@ struct omap_dsp_mapinfo { #define TWCH_IOCTL_TKILL 13 struct omap_dsp_taddinfo { - __u8 minor; - __u32 taskadr; + __u8 minor; + __u32 taskadr; }; #define TADD_ABORTADR 0xffffffff + +#endif /* __ARCH_OMAP_DSP_H */