diff options
Diffstat (limited to 'drivers/dsp/syslink/procmgr')
-rwxr-xr-x | drivers/dsp/syslink/procmgr/Kbuild | 10 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/Kbuild | 10 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/dmm4430.c | 355 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/dmm4430.h | 50 | ||||
-rw-r--r-- | drivers/dsp/syslink/procmgr/proc4430/ducatienabler.c | 1332 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/hw_mmu.c | 643 | ||||
-rw-r--r-- | drivers/dsp/syslink/procmgr/proc4430/proc4430.c | 1021 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/proc4430.h | 147 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c | 400 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h | 169 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/procdefs.h | 203 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/processor.c | 398 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/processor.h | 84 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/procmgr.c | 957 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/procmgr_drv.c | 758 | ||||
-rwxr-xr-x | drivers/dsp/syslink/procmgr/procmgr_drvdefs.h | 541 |
16 files changed, 7078 insertions, 0 deletions
diff --git a/drivers/dsp/syslink/procmgr/Kbuild b/drivers/dsp/syslink/procmgr/Kbuild new file mode 100755 index 000000000000..58f6d3155250 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/Kbuild @@ -0,0 +1,10 @@ +libomap_syslink_proc = processor.o procmgr.o procmgr_drv.o + +obj-$(CONFIG_SYSLINK_PROC) += syslink_proc.o +syslink_proc-objs = $(libomap_syslink_proc) + +ccflags-y += -Wno-strict-prototypes + +#Header files +ccflags-y += -Iarch/arm/plat-omap/include/syslink + diff --git a/drivers/dsp/syslink/procmgr/proc4430/Kbuild b/drivers/dsp/syslink/procmgr/proc4430/Kbuild new file mode 100755 index 000000000000..f82f2e23f79a --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/Kbuild @@ -0,0 +1,10 @@ +libomap_proc4430 = proc4430.o proc4430_drv.o dmm4430.o \ + ducatienabler.o hw_mmu.o + +obj-$(CONFIG_SYSLINK_PROC) += syslink_proc4430.o +syslink_proc4430-objs = $(libomap_proc4430) + +ccflags-y += -Wno-strict-prototypes -DUSE_LEVEL_1_MACROS + +#Header files +ccflags-y += -Iarch/arm/plat-omap/include/syslink diff --git a/drivers/dsp/syslink/procmgr/proc4430/dmm4430.c b/drivers/dsp/syslink/procmgr/proc4430/dmm4430.c new file mode 100755 index 000000000000..d2ed9ece2245 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/dmm4430.c @@ -0,0 +1,355 @@ +/* + * dmm4430.c + * + * Syslink support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dmm.c ======== + * Purpose: + *The Dynamic Memory Manager (DMM) module manages the DSP Virtual address + *space that can be directly mapped to any MPU buffer or memory region + * + * Public Functions: + *dmm_create_tables + *dmm_create + *dmm_destroy + *dmm_exit + *dmm_init + *dmm_map_memory + *DMM_Reset + *dmm_reserve_memory + *dmm_unmap_memory + *dmm_unreserve_memory + * + * Private Functions: + *add_region + *create_region + *get_region + * get_free_region + * get_mapped_region + * + * Notes: + *Region: Generic memory entitiy having a start address and a size + *Chunk: Reserved region + * + *! + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/mutex.h> +#include <linux/vmalloc.h> +#include <asm/page.h> +#include "dmm4430.h" + + +#define DMM_ADDR_VIRTUAL(x, a) \ + do { \ + x = (((struct map_page *)(a) - p_virt_mapping_tbl) * PAGE_SIZE \ + + dyn_mem_map_begin);\ + } while (0) + +#define DMM_ADDR_TO_INDEX(i, a) \ + do { \ + i = (((a) - dyn_mem_map_begin) / PAGE_SIZE); \ + } while (0) + +struct map_page { + u32 region_size:31; + u32 b_reserved:1; +}; + +/* Create the free list */ +static struct map_page *p_virt_mapping_tbl; +static u32 i_freeregion; /* The index of free region */ +static u32 i_freesize; +static u32 table_size;/* The size of virtual and physical pages tables */ +static u32 dyn_mem_map_begin; +struct mutex *dmm_lock; + +static struct map_page *get_free_region(u32 size); +static struct map_page *get_mapped_region(u32 addr); + +/* ======== dmm_create_tables ======== + * Purpose: + *Create table to hold information of the virtual memory that is reserved + *for DSP. + */ +int dmm_create_tables(u32 addr, u32 size) +{ + int status = 0; + + dmm_delete_tables(); + if (WARN_ON(mutex_lock_interruptible(dmm_lock)) < 0) { + status = -EFAULT; + goto func_exit; + } + dyn_mem_map_begin = addr; + table_size = (size/PAGE_SIZE) + 1; + /* Create the free list */ + p_virt_mapping_tbl = (struct map_page *)vmalloc( + table_size*sizeof(struct map_page)); + if (WARN_ON(p_virt_mapping_tbl == NULL)) + status = -ENOMEM; + /* On successful allocation, + * all entries are zero ('free') */ + i_freeregion = 0; + i_freesize = table_size*PAGE_SIZE; + p_virt_mapping_tbl[0].region_size = table_size; + mutex_unlock(dmm_lock); + +func_exit: + return status; +} + +/* + * ======== dmm_create ======== + * Purpose: + *Create a dynamic memory manager object. + */ +int dmm_create(void) +{ + int status = 0; + dmm_lock = kmalloc(sizeof(struct mutex), GFP_KERNEL); + if (WARN_ON(dmm_lock == NULL)) { + status = -EFAULT; + goto func_exit; + } + mutex_init(dmm_lock); +func_exit: + return status; +} + +/* + * ======== dmm_destroy ======== + * Purpose: + *Release the communication memory manager resources. + */ +void dmm_destroy(void) +{ + dmm_delete_tables(); + kfree(dmm_lock); +} + + +/* + * ======== dmm_delete_tables ======== + * Purpose: + *Delete DMM Tables. + */ +void dmm_delete_tables(void) +{ + /* Delete all DMM tables */ + WARN_ON(mutex_lock_interruptible(dmm_lock)); + if (p_virt_mapping_tbl != NULL) { + vfree(p_virt_mapping_tbl); + p_virt_mapping_tbl = NULL; + } + mutex_unlock(dmm_lock); +} + +/* + * ======== dmm_init ======== + * Purpose: + *Initializes private state of DMM module. + */ +void dmm_init(void) +{ + p_virt_mapping_tbl = NULL ; + table_size = 0; + return; +} + +/* + * ======== dmm_reserve_memory ======== + * Purpose: + *Reserve a chunk of virtually contiguous DSP/IVA address space. + */ +int dmm_reserve_memory(u32 size, u32 *p_rsv_addr) +{ + int status = 0; + struct map_page *node; + u32 rsv_addr = 0; + u32 rsv_size = 0; + + if (WARN_ON(mutex_lock_interruptible(dmm_lock)) < 0) { + status = -EFAULT; + goto func_exit; + } + + /* Try to get a DSP chunk from the free list */ + node = get_free_region(size); + if (node != NULL) { + /* DSP chunk of given size is available. */ + DMM_ADDR_VIRTUAL(rsv_addr, node); + /* Calculate the number entries to use */ + rsv_size = size/PAGE_SIZE; + if (rsv_size < node->region_size) { + /* Mark remainder of free region */ + node[rsv_size].b_reserved = false; + node[rsv_size].region_size = + node->region_size - rsv_size; + } + /* get_region will return first fit chunk. But we only use what + is requested. */ + node->b_reserved = true; + node->region_size = rsv_size; + /* Return the chunk's starting address */ + *p_rsv_addr = rsv_addr; + } else + /*dSP chunk of given size is not available */ + status = -ENOMEM; + + mutex_unlock(dmm_lock); +func_exit: + return status; +} + + +/* + * ======== dmm_unreserve_memory ======== + * Purpose: + *Free a chunk of reserved DSP/IVA address space. + */ +int dmm_unreserve_memory(u32 rsv_addr, u32 *psize) +{ + struct map_page *chunk; + int status = 0; + + WARN_ON(mutex_lock_interruptible(dmm_lock)); + + /* Find the chunk containing the reserved address */ + chunk = get_mapped_region(rsv_addr); + if (chunk == NULL) + status = -ENXIO; + WARN_ON(status < 0); + if (status == 0) { + chunk->b_reserved = false; + *psize = chunk->region_size * PAGE_SIZE; + /* NOTE: We do NOT coalesce free regions here. + * Free regions are coalesced in get_region(), as it traverses + *the whole mapping table + */ + } + mutex_unlock(dmm_lock); + return status; +} + +/* + * ======== get_free_region ======== + * Purpose: + * Returns the requested free region + */ +static struct map_page *get_free_region(u32 size) +{ + struct map_page *curr_region = NULL; + u32 i = 0; + u32 region_size = 0; + u32 next_i = 0; + + if (p_virt_mapping_tbl == NULL) + return curr_region; + if (size > i_freesize) { + /* Find the largest free region + * (coalesce during the traversal) */ + while (i < table_size) { + region_size = p_virt_mapping_tbl[i].region_size; + next_i = i+region_size; + if (p_virt_mapping_tbl[i].b_reserved == false) { + /* Coalesce, if possible */ + if (next_i < table_size && + p_virt_mapping_tbl[next_i].b_reserved + == false) { + p_virt_mapping_tbl[i].region_size += + p_virt_mapping_tbl[next_i].region_size; + continue; + } + region_size *= PAGE_SIZE; + if (region_size > i_freesize) { + i_freeregion = i; + i_freesize = region_size; + } + } + i = next_i; + } + } + if (size <= i_freesize) { + curr_region = p_virt_mapping_tbl + i_freeregion; + i_freeregion += (size / PAGE_SIZE); + i_freesize -= size; + } + return curr_region; +} + +/* + * ======== get_mapped_region ======== + * Purpose: + * Returns the requestedmapped region + */ +static struct map_page *get_mapped_region(u32 addr) +{ + u32 i = 0; + struct map_page *curr_region = NULL; + + if (p_virt_mapping_tbl == NULL) + return curr_region; + + DMM_ADDR_TO_INDEX(i, addr); + if (i < table_size && (p_virt_mapping_tbl[i].b_reserved)) + curr_region = p_virt_mapping_tbl + i; + return curr_region; +} + +#ifdef DSP_DMM_DEBUG +int dmm_mem_map_dump(void) +{ + struct map_page *curNode = NULL; + u32 i; + u32 freemem = 0; + u32 bigsize = 0; + + WARN_ON(mutex_lock_interruptible(dmm_lock)); + + if (p_virt_mapping_tbl != NULL) { + for (i = 0; i < table_size; i += + p_virt_mapping_tbl[i].region_size) { + curNode = p_virt_mapping_tbl + i; + if (curNode->b_reserved == true) { + /*printk("RESERVED size = 0x%x, " + "Map size = 0x%x\n", + (curNode->region_size * PAGE_SIZE), + (curNode->b_mapped == false) ? 0 : + (curNode->mapped_size * PAGE_SIZE)); +*/ + } else { +/* printk("UNRESERVED size = 0x%x\n", + (curNode->region_size * PAGE_SIZE)); +*/ + freemem += (curNode->region_size * PAGE_SIZE); + if (curNode->region_size > bigsize) + bigsize = curNode->region_size; + } + } + } + printk(KERN_INFO "Total DSP VA FREE memory = %d Mbytes\n", + freemem/(1024*1024)); + printk(KERN_INFO "Total DSP VA USED memory= %d Mbytes \n", + (((table_size * PAGE_SIZE)-freemem))/(1024*1024)); + printk(KERN_INFO "DSP VA - Biggest FREE block = %d Mbytes \n\n", + (bigsize*PAGE_SIZE/(1024*1024))); + mutex_unlock(dmm_lock); + + return 0; +} +#endif diff --git a/drivers/dsp/syslink/procmgr/proc4430/dmm4430.h b/drivers/dsp/syslink/procmgr/proc4430/dmm4430.h new file mode 100755 index 000000000000..7d879f4fe123 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/dmm4430.h @@ -0,0 +1,50 @@ +/* + * dmm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dmm.h ======== + * Purpose: + *The Dynamic Memory Mapping(DMM) module manages the DSP Virtual address + *space that can be directly mapped to any MPU buffer or memory region + * + * Public Functions: + * + */ + +#ifndef DMM_4430_ +#define DMM_4430_ + +#include <linux/types.h> + +int dmm_reserve_memory(u32 size, u32 *p_rsv_addr); + +int dmm_unreserve_memory(u32 rsv_addr, u32 *psize); + +void dmm_destroy(void); + +void dmm_delete_tables(void); + +int dmm_create(void); + +void dmm_init(void); + +int dmm_create_tables(u32 addr, u32 size); + +#ifdef DSP_DMM_DEBUG +int dmm_mem_map_dump(void); +#endif +#endif/* DMM_4430_ */ diff --git a/drivers/dsp/syslink/procmgr/proc4430/ducatienabler.c b/drivers/dsp/syslink/procmgr/proc4430/ducatienabler.c new file mode 100644 index 000000000000..766005b56702 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/ducatienabler.c @@ -0,0 +1,1332 @@ +/* + * ducatienabler.c + * + * Syslink driver support for TI OMAP processors. + * + * Copyright (C) 2008-2009 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/gfp.h> +#include <linux/io.h> +#include <linux/module.h> +#include <asm/page.h> +#include <linux/kernel.h> +#include <linux/pagemap.h> + + +#include <linux/autoconf.h> +#include <asm/system.h> +#include <asm/atomic.h> +#include <linux/semaphore.h> +#include <linux/uaccess.h> +#include <asm/irq.h> +#include <linux/io.h> +#include <linux/syscalls.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/stddef.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/ctype.h> +#include <linux/mm.h> +#include <linux/device.h> +#include <linux/vmalloc.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/pagemap.h> +#include <asm/cacheflush.h> +#include <linux/dma-mapping.h> + +#include <syslink/ducatienabler.h> + + +#ifdef DEBUG_DUCATI_IPC +#define DPRINTK(fmt, args...) printk(KERN_INFO "%s: " fmt, __func__, ## args) +#else +#define DPRINTK(fmt, args...) +#endif + + +#define base_ducati_l2_mmuPhys 0x55082000 + +/* + * Macro to define the physical memory address for the + * Ducati Base image. The 74Mb memory is preallocated + * during the make menuconfig. + * + */ +/* #define DUCATI_BASEIMAGE_PHYSICAL_ADDRESS 0x87200000 */ +#define DUCATI_BASEIMAGE_PHYSICAL_ADDRESS 0x9CF00000 + +#define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT) + + +/* Attributes used to manage the DSP MMU page tables */ +struct pg_table_attrs { + struct sync_cs_object *hcs_object;/* Critical section object handle */ + u32 l1_base_pa; /* Physical address of the L1 PT */ + u32 l1_base_va; /* Virtual address of the L1 PT */ + u32 l1_size; /* Size of the L1 PT */ + u32 l1_tbl_alloc_pa; + /* Physical address of Allocated mem for L1 table. May not be aligned */ + u32 l1_tbl_alloc_va; + /* Virtual address of Allocated mem for L1 table. May not be aligned */ + u32 l1_tbl_alloc_sz; + /* Size of consistent memory allocated for L1 table. + * May not be aligned */ + u32 l2_base_pa; /* Physical address of the L2 PT */ + u32 l2_base_va; /* Virtual address of the L2 PT */ + u32 l2_size; /* Size of the L2 PT */ + u32 l2_tbl_alloc_pa; + /* Physical address of Allocated mem for L2 table. May not be aligned */ + u32 l2_tbl_alloc_va; + /* Virtual address of Allocated mem for L2 table. May not be aligned */ + u32 ls_tbl_alloc_sz; + /* Size of consistent memory allocated for L2 table. + * May not be aligned */ + u32 l2_num_pages; /* Number of allocated L2 PT */ + struct page_info *pg_info; +}; + +/* Attributes of L2 page tables for DSP MMU.*/ +struct page_info { + /* Number of valid PTEs in the L2 PT*/ + u32 num_entries; +}; + +enum pagetype { + SECTION = 0, + LARGE_PAGE = 1, + SMALL_PAGE = 2, + SUPER_SECTION = 3 +}; + +static struct pg_table_attrs *p_pt_attrs; +static u32 mmu_index_next; +static u32 base_ducati_l2_mmu; + +static u32 shm_phys_addr; +static u32 shm_virt_addr; + +static void bad_page_dump(u32 pa, struct page *pg) +{ + pr_emerg("DSPBRIDGE: MAP function: COUNT 0 FOR PA 0x%x\n", pa); + pr_emerg("Bad page state in process '%s'\n", current->comm); + BUG(); +} + +/*============================================ + * Print the DSP MMU Table Entries + */ +void dbg_print_ptes(bool ashow_inv_entries, bool ashow_repeat_entries) +{ + u32 pte_val; + u32 pte_size; + u32 last_sect = 0; + u32 this_sect = 0; + u32 cur_l1_entry; + u32 cur_l2_entry; + u32 pg_tbl_va; + u32 l1_base_va; + u32 l2_base_va = 0; + u32 l2_base_pa = 0; + + l1_base_va = p_pt_attrs->l1_base_va; + pg_tbl_va = l1_base_va; + + DPRINTK("\n*** Currently programmed PTEs : Max possible L1 Entries" + "[%d] ***\n", (p_pt_attrs->l1_size / sizeof(u32))); + + /* Walk all L1 entries, dump out info. Dive into L2 if necessary */ + for (cur_l1_entry = 0; cur_l1_entry < + (p_pt_attrs->l1_size / sizeof(u32)); cur_l1_entry++) { + /*pte_val = pL1PgTbl[cur_l1_entry];*/ + pte_val = *((u32 *)(pg_tbl_va + (cur_l1_entry * sizeof(u32)))); + pte_size = hw_mmu_pte_sizel1(pte_val); + + if (pte_size == HW_PAGE_SIZE_16MB) { + this_sect = hw_mmu_pte_phyaddr(pte_val, pte_size); + if (this_sect != last_sect) { + last_sect = this_sect; + DPRINTK("PTE L1 [16 MB] -> VA = " + "0x%x PA = 0x%x\n", + cur_l1_entry << 24, this_sect); + + } else if (ashow_repeat_entries != false) + DPRINTK(" {REPEAT}\n"); + } else if (pte_size == HW_PAGE_SIZE_1MB) { + this_sect = hw_mmu_pte_phyaddr(pte_val, pte_size); + if (this_sect != last_sect) { + + last_sect = this_sect; + + DPRINTK("PTE L1 [1 MB ] -> VA = " + "0x%x PA = 0x%x\n", + cur_l1_entry << 20, this_sect); + + } else if (ashow_repeat_entries != false) + DPRINTK(" {REPEAT}\n"); + + } else if (pte_size == HW_MMU_COARSE_PAGE_SIZE) { + /* Get the L2 data for this */ + DPRINTK("PTE L1 [L2 ] -> VA = " + "0x%x\n", cur_l1_entry << 20); + /* Get the L2 PA from the L1 PTE, and find corresponding L2 VA*/ + l2_base_pa = hw_mmu_pte_coarsel1(pte_val); + l2_base_va = l2_base_pa - p_pt_attrs->l2_base_pa + + p_pt_attrs->l2_base_va; + for (cur_l2_entry = 0; + cur_l2_entry < (HW_MMU_COARSE_PAGE_SIZE / sizeof(u32)); + cur_l2_entry++) { + pte_val = *((u32 *)(l2_base_va + + (cur_l2_entry * sizeof(u32)))); + pte_size = hw_mmu_pte_sizel2(pte_val); + if ((pte_size == HW_PAGE_SIZE_64KB) || + (pte_size == HW_PAGE_SIZE_4KB)) { + this_sect = hw_mmu_pte_phyaddr + (pte_val, pte_size); + if (this_sect != last_sect) { + last_sect = this_sect; + DPRINTK("PTE L2 [%s KB] ->" + "VA = 0x%x PA = 0x%x\n", + (pte_size == + HW_PAGE_SIZE_64KB) ? + "64" : "4", + ((cur_l1_entry << 20) + | (cur_l2_entry << 12)), + this_sect); + } else if (ashow_repeat_entries + != false) + + DPRINTK("{REPEAT}"); + } else if (ashow_inv_entries != false) { + + DPRINTK("PTE L2 [INVALID] -> VA = " + "0x%x", + ((cur_l1_entry << 20) | + (cur_l2_entry << 12))); + continue; + } + } + } else if (ashow_inv_entries != false) { + /* Entry is invalid (not set), skip it */ + DPRINTK("PTE L1 [INVALID] -> VA = 0x%x", + cur_l1_entry << 20); + continue; + } + } + /* Dump the TLB entries as well */ + DPRINTK("\n*** Currently programmed TLBs ***\n"); + hw_mmu_tlb_dump(base_ducati_l2_mmu, true); + DPRINTK("*** DSP MMU DUMP COMPLETED ***\n"); +} + +/*============================================ + * This function calculates PTE address (MPU virtual) to be updated + * It also manages the L2 page tables + */ +static int pte_set(u32 pa, u32 va, u32 size, struct hw_mmu_map_attrs_t *attrs) +{ + u32 i; + u32 pte_val; + u32 pte_addr_l1; + u32 pte_size; + u32 pg_tbl_va; /* Base address of the PT that will be updated */ + u32 l1_base_va; + /* Compiler warns that the next three variables might be used + * uninitialized in this function. Doesn't seem so. Working around, + * anyways. */ + u32 l2_base_va = 0; + u32 l2_base_pa = 0; + u32 l2_page_num = 0; + struct pg_table_attrs *pt = p_pt_attrs; + int status = 0; + DPRINTK("> pte_set ppg_table_attrs %x, pa %x, va %x, " + "size %x, attrs %x\n", (u32)pt, pa, va, size, (u32)attrs); + l1_base_va = pt->l1_base_va; + pg_tbl_va = l1_base_va; + if ((size == HW_PAGE_SIZE_64KB) || (size == HW_PAGE_SIZE_4KB)) { + /* Find whether the L1 PTE points to a valid L2 PT */ + pte_addr_l1 = hw_mmu_pte_addr_l1(l1_base_va, va); + if (pte_addr_l1 <= (pt->l1_base_va + pt->l1_size)) { + pte_val = *(u32 *)pte_addr_l1; + pte_size = hw_mmu_pte_sizel1(pte_val); + } else { + return -EINVAL; + } + /* FIX ME */ + /* TODO: ADD synchronication element*/ + /* sync_enter_cs(pt->hcs_object);*/ + if (pte_size == HW_MMU_COARSE_PAGE_SIZE) { + /* Get the L2 PA from the L1 PTE, and find + * corresponding L2 VA */ + l2_base_pa = hw_mmu_pte_coarsel1(pte_val); + l2_base_va = l2_base_pa - pt->l2_base_pa + + pt->l2_base_va; + l2_page_num = (l2_base_pa - pt->l2_base_pa) / + HW_MMU_COARSE_PAGE_SIZE; + } else if (pte_size == 0) { + /* L1 PTE is invalid. Allocate a L2 PT and + * point the L1 PTE to it */ + /* Find a free L2 PT. */ + for (i = 0; (i < pt->l2_num_pages) && + (pt->pg_info[i].num_entries != 0); i++) + ;; + if (i < pt->l2_num_pages) { + l2_page_num = i; + l2_base_pa = pt->l2_base_pa + (l2_page_num * + HW_MMU_COARSE_PAGE_SIZE); + l2_base_va = pt->l2_base_va + (l2_page_num * + HW_MMU_COARSE_PAGE_SIZE); + /* Endianness attributes are ignored for + * HW_MMU_COARSE_PAGE_SIZE */ + status = + hw_mmu_pte_set(l1_base_va, l2_base_pa, va, + HW_MMU_COARSE_PAGE_SIZE, attrs); + } else { + status = -ENOMEM; + } + } else { + /* Found valid L1 PTE of another size. + * Should not overwrite it. */ + status = -EINVAL; + } + if (status == 0) { + pg_tbl_va = l2_base_va; + if (size == HW_PAGE_SIZE_64KB) + pt->pg_info[l2_page_num].num_entries += 16; + else + pt->pg_info[l2_page_num].num_entries++; + + DPRINTK("L2 BaseVa %x, BasePa %x, " + "PageNum %x num_entries %x\n", l2_base_va, + l2_base_pa, l2_page_num, + pt->pg_info[l2_page_num].num_entries); + } +/* sync_leave_cs(pt->hcs_object);*/ + } + if (status == 0) { + DPRINTK("PTE pg_tbl_va %x, pa %x, va %x, size %x\n", + pg_tbl_va, pa, va, size); + DPRINTK("PTE endianism %x, element_size %x, " + "mixedSize %x\n", attrs->endianism, + attrs->element_size, attrs->mixedSize); + status = hw_mmu_pte_set(pg_tbl_va, pa, va, size, attrs); + if (status == RET_OK) + status = 0; + } + DPRINTK("< pte_set status %x\n", status); + return status; +} + + +/*============================================= + * This function calculates the optimum page-aligned addresses and sizes + * Caller must pass page-aligned values + */ +static int pte_update(u32 pa, u32 va, u32 size, + struct hw_mmu_map_attrs_t *map_attrs) +{ + u32 i; + u32 all_bits; + u32 pa_curr = pa; + u32 va_curr = va; + u32 num_bytes = size; + int status = 0; + u32 pg_size[] = {HW_PAGE_SIZE_16MB, HW_PAGE_SIZE_1MB, + HW_PAGE_SIZE_64KB, HW_PAGE_SIZE_4KB}; + DPRINTK("> pte_update pa %x, va %x, " + "size %x, map_attrs %x\n", pa, va, size, (u32)map_attrs); + while (num_bytes && (status == 0)) { + /* To find the max. page size with which both PA & VA are + * aligned */ + all_bits = pa_curr | va_curr; + DPRINTK("all_bits %x, pa_curr %x, va_curr %x, " + "num_bytes %x\n ", + all_bits, pa_curr, va_curr, num_bytes); + + for (i = 0; i < 4; i++) { + if ((num_bytes >= pg_size[i]) && ((all_bits & + (pg_size[i] - 1)) == 0)) { + DPRINTK("pg_size %x\n", pg_size[i]); + status = pte_set(pa_curr, + va_curr, pg_size[i], map_attrs); + pa_curr += pg_size[i]; + va_curr += pg_size[i]; + num_bytes -= pg_size[i]; + /* Don't try smaller sizes. Hopefully we have + * reached an address aligned to a bigger page + * size */ + break; + } + } + } + DPRINTK("< pte_update status %x num_bytes %x\n", status, num_bytes); + return status; +} + +/* + * ======== ducati_mem_unmap ======== + * Invalidate the PTEs for the DSP VA block to be unmapped. + * + * PTEs of a mapped memory block are contiguous in any page table + * So, instead of looking up the PTE address for every 4K block, + * we clear consecutive PTEs until we unmap all the bytes + */ +int ducati_mem_unmap(u32 da, u32 num_bytes) +{ + u32 L1_base_va; + u32 L2_base_va; + u32 L2_base_pa; + u32 L2_page_num; + u32 pte_val; + u32 pte_size; + u32 pte_count; + u32 pte_addr_l1; + u32 pte_addr_l2 = 0; + u32 rem_bytes; + u32 rem_bytes_l2; + u32 vaCurr; + struct page *pg = NULL; + int status = 0; + u32 temp; + u32 patemp = 0; + u32 pAddr; + u32 numof4Kpages = 0; + DPRINTK("> ducati_mem_unmap da 0x%x, " + "NumBytes 0x%x\n", da, num_bytes); + vaCurr = da; + rem_bytes = num_bytes; + rem_bytes_l2 = 0; + L1_base_va = p_pt_attrs->l1_base_va; + pte_addr_l1 = hw_mmu_pte_addr_l1(L1_base_va, vaCurr); + while (rem_bytes) { + u32 vaCurrOrig = vaCurr; + /* Find whether the L1 PTE points to a valid L2 PT */ + pte_addr_l1 = hw_mmu_pte_addr_l1(L1_base_va, vaCurr); + pte_val = *(u32 *)pte_addr_l1; + pte_size = hw_mmu_pte_sizel1(pte_val); + if (pte_size == HW_MMU_COARSE_PAGE_SIZE) { + /* + * Get the L2 PA from the L1 PTE, and find + * corresponding L2 VA + */ + L2_base_pa = hw_mmu_pte_coarsel1(pte_val); + L2_base_va = L2_base_pa - p_pt_attrs->l2_base_pa + + p_pt_attrs->l2_base_va; + L2_page_num = (L2_base_pa - p_pt_attrs->l2_base_pa) / + HW_MMU_COARSE_PAGE_SIZE; + /* + * Find the L2 PTE address from which we will start + * clearing, the number of PTEs to be cleared on this + * page, and the size of VA space that needs to be + * cleared on this L2 page + */ + pte_addr_l2 = hw_mmu_pte_addr_l2(L2_base_va, vaCurr); + pte_count = pte_addr_l2 & (HW_MMU_COARSE_PAGE_SIZE - 1); + pte_count = (HW_MMU_COARSE_PAGE_SIZE - pte_count) / + sizeof(u32); + if (rem_bytes < (pte_count * PAGE_SIZE)) + pte_count = rem_bytes / PAGE_SIZE; + + rem_bytes_l2 = pte_count * PAGE_SIZE; + DPRINTK("ducati_mem_unmap L2_base_pa %x, " + "L2_base_va %x pte_addr_l2 %x," + "rem_bytes_l2 %x\n", L2_base_pa, L2_base_va, + pte_addr_l2, rem_bytes_l2); + /* + * Unmap the VA space on this L2 PT. A quicker way + * would be to clear pte_count entries starting from + * pte_addr_l2. However, below code checks that we don't + * clear invalid entries or less than 64KB for a 64KB + * entry. Similar checking is done for L1 PTEs too + * below + */ + while (rem_bytes_l2) { + pte_val = *(u32 *)pte_addr_l2; + pte_size = hw_mmu_pte_sizel2(pte_val); + /* vaCurr aligned to pte_size? */ + if ((pte_size != 0) && (rem_bytes_l2 + >= pte_size) && + !(vaCurr & (pte_size - 1))) { + /* Collect Physical addresses from VA */ + pAddr = (pte_val & ~(pte_size - 1)); + if (pte_size == HW_PAGE_SIZE_64KB) + numof4Kpages = 16; + else + numof4Kpages = 1; + temp = 0; + while (temp++ < numof4Kpages) { + if (pfn_valid + (__phys_to_pfn + (patemp))) { + pg = phys_to_page + (pAddr); + if (page_count + (pg) < 1) { + bad_page_dump + (pAddr, pg); + } + SetPageDirty(pg); + page_cache_release(pg); + } + pAddr += HW_PAGE_SIZE_4KB; + } + if (hw_mmu_pte_clear(pte_addr_l2, + vaCurr, pte_size) == RET_OK) { + rem_bytes_l2 -= pte_size; + vaCurr += pte_size; + pte_addr_l2 += (pte_size >> 12) + * sizeof(u32); + } else { + status = -EFAULT; + goto EXIT_LOOP; + } + } else + status = -EFAULT; + } + if (rem_bytes_l2 != 0) { + status = -EFAULT; + goto EXIT_LOOP; + } + p_pt_attrs->pg_info[L2_page_num].num_entries -= + pte_count; + if (p_pt_attrs->pg_info[L2_page_num].num_entries + == 0) { + /* + * Clear the L1 PTE pointing to the + * L2 PT + */ + if (RET_OK != hw_mmu_pte_clear(L1_base_va, + vaCurrOrig, HW_MMU_COARSE_PAGE_SIZE)) { + status = -EFAULT; + goto EXIT_LOOP; + } + } + rem_bytes -= pte_count * PAGE_SIZE; + DPRINTK("ducati_mem_unmap L2_page_num %x, " + "num_entries %x, pte_count %x, status: 0x%x\n", + L2_page_num, + p_pt_attrs->pg_info[L2_page_num].num_entries, + pte_count, status); + } else + /* vaCurr aligned to pte_size? */ + /* pte_size = 1 MB or 16 MB */ + if ((pte_size != 0) && (rem_bytes >= pte_size) && + !(vaCurr & (pte_size - 1))) { + if (pte_size == HW_PAGE_SIZE_1MB) + numof4Kpages = 256; + else + numof4Kpages = 4096; + temp = 0; + /* Collect Physical addresses from VA */ + pAddr = (pte_val & ~(pte_size - 1)); + while (temp++ < numof4Kpages) { + pg = phys_to_page(pAddr); + if (page_count(pg) < 1) + bad_page_dump(pAddr, pg); + SetPageDirty(pg); + page_cache_release(pg); + pAddr += HW_PAGE_SIZE_4KB; + } + if (hw_mmu_pte_clear(L1_base_va, vaCurr, + pte_size) == RET_OK) { + rem_bytes -= pte_size; + vaCurr += pte_size; + } else { + status = -EFAULT; + goto EXIT_LOOP; + } + } else { + status = -EFAULT; + } + } + /* + * It is better to flush the TLB here, so that any stale old entries + * get flushed + */ +EXIT_LOOP: + hw_mmu_tlb_flushAll(base_ducati_l2_mmu); + DPRINTK("ducati_mem_unmap vaCurr %x, pte_addr_l1 %x " + "pte_addr_l2 %x\n", vaCurr, pte_addr_l1, pte_addr_l2); + DPRINTK("< ducati_mem_unmap status %x rem_bytes %x, " + "rem_bytes_l2 %x\n", status, rem_bytes, rem_bytes_l2); + return status; +} + + +/* + * ======== ducati_mem_virtToPhys ======== + * This funciton provides the translation from + * Remote virtual address to Physical address + */ + +inline u32 ducati_mem_virtToPhys(u32 da) +{ +#if 0 + /* FIXME: temp work around till L2MMU issue + * is resolved + */ + u32 *iopgd = iopgd_offset(ducati_iommu_ptr, da); + u32 phyaddress; + + if (*iopgd & IOPGD_TABLE) { + u32 *iopte = iopte_offset(iopgd, da); + if (*iopte & IOPTE_LARGE) { + phyaddress = *iopte & IOLARGE_MASK; + phyaddress |= (da & (IOLARGE_SIZE - 1)); + } else + phyaddress = (*iopte) & IOPAGE_MASK; + } else { + if ((*iopgd & IOPGD_SUPER) == IOPGD_SUPER) { + phyaddress = *iopgd & IOSUPER_MASK; + phyaddress |= (da & (IOSUPER_SIZE - 1)); + } else { + phyaddress = (*iopgd) & IOPGD_MASK; + phyaddress |= (da & (IOPGD_SIZE - 1)); + } + } +#endif + return da; +} + + +/* + * ======== user_va2pa ======== + * Purpose: + * This function walks through the Linux page tables to convert a userland + * virtual address to physical address + */ +u32 user_va2pa(struct mm_struct *mm, u32 address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + + pgd = pgd_offset(mm, address); + if (!(pgd_none(*pgd) || pgd_bad(*pgd))) { + pmd = pmd_offset(pgd, address); + if (!(pmd_none(*pmd) || pmd_bad(*pmd))) { + ptep = pte_offset_map(pmd, address); + if (ptep) { + pte = *ptep; + if (pte_present(pte)) + return pte & PAGE_MASK; + } + } + } + + return 0; +} + +/*============================================ + * This function maps MPU buffer to the DSP address space. It performs +* linear to physical address translation if required. It translates each +* page since linear addresses can be physically non-contiguous +* All address & size arguments are assumed to be page aligned (in proc.c) + * + */ +int ducati_mem_map(u32 mpu_addr, u32 ul_virt_addr, + u32 num_bytes, u32 map_attr) +{ + u32 attrs; + int status = 0; + struct hw_mmu_map_attrs_t hw_attrs; + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + struct task_struct *curr_task = current; + u32 write = 0; + u32 da = ul_virt_addr; + u32 pa = 0; + int pg_i = 0; + int pg_num = 0; + struct page *mappedPage, *pg; + int num_usr_pages = 0; + + DPRINTK("> WMD_BRD_MemMap pa %x, va %x, " + "size %x, map_attr %x\n", mpu_addr, ul_virt_addr, + num_bytes, map_attr); + if (num_bytes == 0) + return -EINVAL; + if (map_attr != 0) { + attrs = map_attr; + attrs |= DSP_MAPELEMSIZE32; + } else { + /* Assign default attributes */ + attrs = DSP_MAPVIRTUALADDR | DSP_MAPELEMSIZE32; + } + /* Take mapping properties */ + if (attrs & DSP_MAPBIGENDIAN) + hw_attrs.endianism = HW_BIG_ENDIAN; + else + hw_attrs.endianism = HW_LITTLE_ENDIAN; + + hw_attrs.mixedSize = (enum hw_mmu_mixed_size_t) + ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2); + /* Ignore element_size if mixedSize is enabled */ + if (hw_attrs.mixedSize == 0) { + if (attrs & DSP_MAPELEMSIZE8) { + /* Size is 8 bit */ + hw_attrs.element_size = HW_ELEM_SIZE_8BIT; + } else if (attrs & DSP_MAPELEMSIZE16) { + /* Size is 16 bit */ + hw_attrs.element_size = HW_ELEM_SIZE_16BIT; + } else if (attrs & DSP_MAPELEMSIZE32) { + /* Size is 32 bit */ + hw_attrs.element_size = HW_ELEM_SIZE_32BIT; + } else if (attrs & DSP_MAPELEMSIZE64) { + /* Size is 64 bit */ + hw_attrs.element_size = HW_ELEM_SIZE_64BIT; + } else { + /* Mixedsize isn't enabled, so size can't be + * zero here */ + DPRINTK("WMD_BRD_MemMap: MMU element size is zero\n"); + return -EINVAL; + } + } + /* + * Do OS-specific user-va to pa translation. + * Combine physically contiguous regions to reduce TLBs. + * Pass the translated pa to PteUpdate. + */ + if ((attrs & DSP_MAPPHYSICALADDR)) { + status = pte_update(mpu_addr, ul_virt_addr, num_bytes, + &hw_attrs); + goto func_cont; + } + /* + * Important Note: mpu_addr is mapped from user application process + * to current process - it must lie completely within the current + * virtual memory address space in order to be of use to us here! + */ + down_read(&mm->mmap_sem); + vma = find_vma(mm, mpu_addr); + /* + * It is observed that under some circumstances, the user buffer is + * spread across several VMAs. So loop through and check if the entire + * user buffer is covered + */ + while ((vma) && (mpu_addr + num_bytes > vma->vm_end)) { + /* jump to the next VMA region */ + vma = find_vma(mm, vma->vm_end + 1); + } + if (!vma) { + status = -EINVAL; + up_read(&mm->mmap_sem); + goto func_cont; + } + if (vma->vm_flags & VM_IO) { + num_usr_pages = num_bytes / PAGE_SIZE; + /* Get the physical addresses for user buffer */ + for (pg_i = 0; pg_i < num_usr_pages; pg_i++) { + pa = user_va2pa(mm, mpu_addr); + if (!pa) { + status = -EFAULT; + pr_err("DSPBRIDGE: VM_IO mapping physical" + "address is invalid\n"); + break; + } + if (pfn_valid(__phys_to_pfn(pa))) { + pg = phys_to_page(pa); + get_page(pg); + if (page_count(pg) < 1) { + pr_err("Bad page in VM_IO buffer\n"); + bad_page_dump(pa, pg); + } + } + status = pte_set(pa, da, HW_PAGE_SIZE_4KB, &hw_attrs); + if (WARN_ON(status < 0)) + break; + mpu_addr += HW_PAGE_SIZE_4KB; + da += HW_PAGE_SIZE_4KB; + } + } else { + num_usr_pages = num_bytes / PAGE_SIZE; + if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) + write = 1; + + for (pg_i = 0; pg_i < num_usr_pages; pg_i++) { + pg_num = get_user_pages(curr_task, mm, mpu_addr, 1, + write, 1, &mappedPage, NULL); + if (pg_num > 0) { + if (page_count(mappedPage) < 1) { + pr_err("Bad page count after doing" + "get_user_pages on" + "user buffer\n"); + bad_page_dump(page_to_phys(mappedPage), + mappedPage); + } + status = pte_set(page_to_phys(mappedPage), da, + HW_PAGE_SIZE_4KB, &hw_attrs); + if (WARN_ON(status < 0)) + break; + da += HW_PAGE_SIZE_4KB; + mpu_addr += HW_PAGE_SIZE_4KB; + } else { + pr_err("DSPBRIDGE: get_user_pages FAILED," + "MPU addr = 0x%x," + "vma->vm_flags = 0x%lx," + "get_user_pages Err" + "Value = %d, Buffer" + "size=0x%x\n", mpu_addr, + vma->vm_flags, pg_num, + num_bytes); + status = -EFAULT; + break; + } + } + } + up_read(&mm->mmap_sem); +func_cont: + /* Don't propogate Linux or HW status to upper layers */ + if (status < 0) { + /* + * Roll out the mapped pages incase it failed in middle of + * mapping + */ + if (pg_i) + ducati_mem_unmap(ul_virt_addr, (pg_i * PAGE_SIZE)); + } + /* In any case, flush the TLB + * This is called from here instead from pte_update to avoid unnecessary + * repetition while mapping non-contiguous physical regions of a virtual + * region */ + hw_mmu_tlb_flushAll(base_ducati_l2_mmu); + WARN_ON(status < 0); + DPRINTK("< WMD_BRD_MemMap status %x\n", status); + return status; +} + + /*========================================= + * Decides a TLB entry size + * + */ +static int get_mmu_entry_size(u32 phys_addr, u32 size, enum pagetype *size_tlb, + u32 *entry_size) +{ + int status = 0; + bool page_align_4kb = false; + bool page_align_64kb = false; + bool page_align_1mb = false; + bool page_align_16mb = false; + + /* First check the page alignment*/ + if ((phys_addr % PAGE_SIZE_4KB) == 0) + page_align_4kb = true; + if ((phys_addr % PAGE_SIZE_64KB) == 0) + page_align_64kb = true; + if ((phys_addr % PAGE_SIZE_1MB) == 0) + page_align_1mb = true; + if ((phys_addr % PAGE_SIZE_16MB) == 0) + page_align_16mb = true; + + if ((!page_align_64kb) && (!page_align_1mb) && (!page_align_4kb)) { + status = -EINVAL; + goto error_exit; + } + if (status == 0) { + /* Now decide the entry size */ + if (size >= PAGE_SIZE_16MB) { + if (page_align_16mb) { + *size_tlb = SUPER_SECTION; + *entry_size = PAGE_SIZE_16MB; + } else if (page_align_1mb) { + *size_tlb = SECTION; + *entry_size = PAGE_SIZE_1MB; + } else if (page_align_64kb) { + *size_tlb = LARGE_PAGE; + *entry_size = PAGE_SIZE_64KB; + } else if (page_align_4kb) { + *size_tlb = SMALL_PAGE; + *entry_size = PAGE_SIZE_4KB; + } else { + status = -EINVAL; + goto error_exit; + } + } else if (size >= PAGE_SIZE_1MB && size < PAGE_SIZE_16MB) { + if (page_align_1mb) { + *size_tlb = SECTION; + *entry_size = PAGE_SIZE_1MB; + } else if (page_align_64kb) { + *size_tlb = LARGE_PAGE; + *entry_size = PAGE_SIZE_64KB; + } else if (page_align_4kb) { + *size_tlb = SMALL_PAGE; + *entry_size = PAGE_SIZE_4KB; + } else { + status = -EINVAL; + goto error_exit; + } + } else if (size > PAGE_SIZE_4KB && + size < PAGE_SIZE_1MB) { + if (page_align_64kb) { + *size_tlb = LARGE_PAGE; + *entry_size = PAGE_SIZE_64KB; + } else if (page_align_4kb) { + *size_tlb = SMALL_PAGE; + *entry_size = PAGE_SIZE_4KB; + } else { + status = -EINVAL; + goto error_exit; + } + } else if (size == PAGE_SIZE_4KB) { + if (page_align_4kb) { + *size_tlb = SMALL_PAGE; + *entry_size = PAGE_SIZE_4KB; + } else { + status = -EINVAL; + goto error_exit; + } + } else { + status = -EINVAL; + goto error_exit; + } + } + DPRINTK("< GetMMUEntrySize status %x\n", status); + return 0; +error_exit: + DPRINTK("< GetMMUEntrySize FAILED !!!!!!\n"); + return status; +} + +/*========================================= + * Add DSP MMU entries corresponding to given MPU-Physical address + * and DSP-virtual address + */ +static int add_dsp_mmu_entry(u32 *phys_addr, u32 *dsp_addr, + u32 size) +{ + u32 mapped_size = 0; + enum pagetype size_tlb = SECTION; + u32 entry_size = 0; + int status = 0; + u32 page_size = HW_PAGE_SIZE_1MB; + struct hw_mmu_map_attrs_t map_attrs = { HW_LITTLE_ENDIAN, + HW_ELEM_SIZE_16BIT, + HW_MMU_CPUES }; + + DPRINTK("Entered add_dsp_mmu_entry phys_addr = " + "0x%x, dsp_addr = 0x%x,size = 0x%x\n", + *phys_addr, *dsp_addr, size); + + while ((mapped_size < size) && (status == 0)) { + status = get_mmu_entry_size(*phys_addr, + (size - mapped_size), &size_tlb, &entry_size); + + if (size_tlb == SUPER_SECTION) + page_size = HW_PAGE_SIZE_16MB; + + else if (size_tlb == SECTION) + page_size = HW_PAGE_SIZE_1MB; + + else if (size_tlb == LARGE_PAGE) + page_size = HW_PAGE_SIZE_64KB; + + else if (size_tlb == SMALL_PAGE) + page_size = HW_PAGE_SIZE_4KB; + if (status == 0) { + hw_mmu_tlb_add((base_ducati_l2_mmu), + *phys_addr, *dsp_addr, + page_size, mmu_index_next++, + &map_attrs, HW_SET, HW_SET); + mapped_size += entry_size; + *phys_addr += entry_size; + *dsp_addr += entry_size; + if (mmu_index_next > 32) { + status = -EINVAL; + break; + } + /* Lock the base counter*/ + hw_mmu_numlocked_set(base_ducati_l2_mmu, + mmu_index_next); + + hw_mmu_victim_numset(base_ducati_l2_mmu, + mmu_index_next); + } + } + DPRINTK("Exited add_dsp_mmu_entryphys_addr = \ + 0x%x, dsp_addr = 0x%x\n", + *phys_addr, *dsp_addr); + return status; + } + + +/*============================================= + * Add DSP MMU entries corresponding to given MPU-Physical address + * and DSP-virtual address + * + */ +#if 0 +static int add_entry_ext(u32 *phys_addr, u32 *dsp_addr, + u32 size) +{ + u32 mapped_size = 0; + enum pagetype size_tlb = SECTION; + u32 entry_size = 0; + int status = 0; + u32 page_size = HW_PAGE_SIZE_1MB; + u32 flags = 0; + + flags = (DSP_MAPELEMSIZE32 | DSP_MAPLITTLEENDIAN | + DSP_MAPPHYSICALADDR); + while ((mapped_size < size) && (status == 0)) { + + /* get_mmu_entry_size fills the size_tlb and entry_size + based on alignment and size of memory to map + to DSP - size */ + status = get_mmu_entry_size(*phys_addr, + (size - mapped_size), + &size_tlb, + &entry_size); + + if (size_tlb == SUPER_SECTION) + page_size = HW_PAGE_SIZE_16MB; + else if (size_tlb == SECTION) + page_size = HW_PAGE_SIZE_1MB; + else if (size_tlb == LARGE_PAGE) + page_size = HW_PAGE_SIZE_64KB; + else if (size_tlb == SMALL_PAGE) + page_size = HW_PAGE_SIZE_4KB; + + if (status == 0) { + + ducati_mem_map(*phys_addr, + *dsp_addr, page_size, flags); + mapped_size += entry_size; + *phys_addr += entry_size; + *dsp_addr += entry_size; + } + } + return status; +} +#endif +/*================================ + * Initialize the Ducati MMU. + */ +int ducati_mmu_init(u32 a_phy_addr) +{ + int ret_val = 0; + u32 ducati_mmu_linear_addr = base_ducati_l2_mmu; + u32 reg_value = 0; + u32 phys_addr = 0; + u32 num_l4_entries; + u32 i = 0; + u32 map_attrs; + u32 num_l3_mem_entries = 0; + u32 virt_addr = 0; +#if 0 + u32 tiler_mapbeg = 0; + u32 tiler_totalsize = 0; +#endif + + num_l4_entries = (sizeof(l4_map) / sizeof(struct mmu_entry)); + num_l3_mem_entries = sizeof(l3_memory_regions) / + sizeof(struct memory_entry); + + DPRINTK("\n Programming Ducati MMU using linear address [0x%x]", + ducati_mmu_linear_addr); + + /* Disable the MMU & TWL */ + hw_mmu_disable(base_ducati_l2_mmu); + hw_mmu_twl_disable(base_ducati_l2_mmu); + + mmu_index_next = 0; + phys_addr = a_phy_addr; + + printk(KERN_ALERT " Programming Ducati memory regions\n"); + printk(KERN_ALERT "=========================================\n"); + for (i = 0; i < num_l3_mem_entries; i++) { + + printk(KERN_ALERT "VA = [0x%x] of size [0x%x] at PA = [0x%x]\n", + l3_memory_regions[i].ul_virt_addr, + l3_memory_regions[i].ul_size, phys_addr); + +#if 0 + /* OMAP4430 original code */ + if (l3_memory_regions[i].ul_virt_addr == DUCATI_SHARED_IPC_ADDR) + shm_phys_addr = phys_addr; + */ +#endif + /* OMAP4430 SDC code */ + /* Adjust below logic if using cacheable shared memory */ + if (l3_memory_regions[i].ul_virt_addr == \ + DUCATI_MEM_IPC_HEAP0_ADDR) { + shm_phys_addr = phys_addr; + } + virt_addr = l3_memory_regions[i].ul_virt_addr; + ret_val = add_dsp_mmu_entry(&phys_addr, &virt_addr, + (l3_memory_regions[i].ul_size)); + + if (WARN_ON(ret_val < 0)) + goto error_exit; + } + +#if 0 + /* OMAP4430 original code */ + tiler_mapbeg = L3_TILER_VIEW0_ADDR; + tiler_totalsize = DUCATIVA_TILER_VIEW0_LEN; + phys_addr = L3_TILER_VIEW0_ADDR; + + printk(KERN_ALERT " Programming TILER memory region at " + "[VA = 0x%x] of size [0x%x] at [PA = 0x%x]\n", + tiler_mapbeg, tiler_totalsize, phys_addr); + ret_val = add_entry_ext(&phys_addr, &tiler_mapbeg, tiler_totalsize); + if (WARN_ON(ret_val < 0)) + goto error_exit; +#endif + + map_attrs = 0x00000000; + map_attrs |= DSP_MAPLITTLEENDIAN; + map_attrs |= DSP_MAPPHYSICALADDR; + map_attrs |= DSP_MAPELEMSIZE32; + printk(KERN_ALERT " Programming Ducati L4 peripherals\n"); + printk(KERN_ALERT "=========================================\n"); + for (i = 0; i < num_l4_entries; i++) { + printk(KERN_INFO "PA [0x%x] VA [0x%x] size [0x%x]\n", + l4_map[i].ul_phy_addr, l4_map[i].ul_virt_addr, + l4_map[i].ul_size); + virt_addr = l4_map[i].ul_virt_addr; + phys_addr = l4_map[i].ul_phy_addr; + ret_val = add_dsp_mmu_entry(&phys_addr, + &virt_addr, (l4_map[i].ul_size)); + if (WARN_ON(ret_val < 0)) { + + DPRINTK("**** Failed to map Peripheral ****"); + DPRINTK("Phys addr [0x%x] Virt addr [0x%x] size [0x%x]", + l4_map[i].ul_phy_addr, l4_map[i].ul_virt_addr, + l4_map[i].ul_size); + DPRINTK(" Status [0x%x]", ret_val); + goto error_exit; + } + } + + /* Set the TTB to point to the L1 page table's physical address */ + hw_mmu_ttbset(ducati_mmu_linear_addr, p_pt_attrs->l1_base_pa); + + /* Enable the TWL */ + hw_mmu_twl_enable(ducati_mmu_linear_addr); + + hw_mmu_enable(ducati_mmu_linear_addr); + + /* MMU Debug Statements */ + reg_value = *((REG u32 *)(ducati_mmu_linear_addr + 0x40)); + DPRINTK(" Ducati TWL Status [0x%x]\n", reg_value); + + reg_value = *((REG u32 *)(ducati_mmu_linear_addr + 0x4C)); + DPRINTK(" Ducati TTB Address [0x%x]\n", reg_value); + + reg_value = *((REG u32 *)(ducati_mmu_linear_addr + 0x44)); + DPRINTK(" Ducati MMU Status [0x%x]\n", reg_value); + + /* Dump the MMU Entries */ + dbg_print_ptes(false, false); + + return 0; +error_exit: + return ret_val; +} + + +/*======================================== + * This sets up the Ducati processor MMU Page tables + * + */ +int init_mmu_page_attribs(u32 l1_size, u32 l1_allign, u32 ls_num_of_pages) +{ + u32 pg_tbl_pa; + u32 pg_tbl_va; + u32 align_size; + int status = 0; + + base_ducati_l2_mmu = (u32)ioremap(base_ducati_l2_mmuPhys, 0x4000); + p_pt_attrs = kmalloc(sizeof(struct pg_table_attrs), GFP_ATOMIC); + if (p_pt_attrs) + memset(p_pt_attrs, 0, sizeof(struct pg_table_attrs)); + else { + status = -ENOMEM; + goto error_exit; + } + p_pt_attrs->l1_size = l1_size; + align_size = p_pt_attrs->l1_size; + /* Align sizes are expected to be power of 2 */ + /* we like to get aligned on L1 table size */ + pg_tbl_va = (u32)__get_dma_pages(GFP_KERNEL, + get_order(p_pt_attrs->l1_size)); + if (pg_tbl_va == (u32)NULL) { + DPRINTK("dma_alloc_coherent failed 0x%x\n", pg_tbl_va); + status = -ENOMEM; + goto error_exit; + } + pg_tbl_pa = __pa(pg_tbl_va); + /* Check if the PA is aligned for us */ + if ((pg_tbl_pa) & (align_size-1)) { + /* PA not aligned to page table size ,*/ + /* try with more allocation and align */ + free_pages(pg_tbl_va, get_order(p_pt_attrs->l1_size)); + /* we like to get aligned on L1 table size */ + pg_tbl_va = (u32)__get_dma_pages(GFP_KERNEL, + get_order(p_pt_attrs->l1_size * 2)); + if (pg_tbl_va == (u32)NULL) { + DPRINTK("__get_dma_pages failed 0x%x\n", pg_tbl_va); + status = -ENOMEM; + goto error_exit; + } + pg_tbl_pa = __pa(pg_tbl_va); + /* We should be able to get aligned table now */ + p_pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa; + p_pt_attrs->l1_tbl_alloc_va = pg_tbl_va; + p_pt_attrs->l1_tbl_alloc_sz = p_pt_attrs->l1_size * 2; + /* Align the PA to the next 'align' boundary */ + p_pt_attrs->l1_base_pa = ((pg_tbl_pa) + (align_size-1)) & + (~(align_size-1)); + p_pt_attrs->l1_base_va = pg_tbl_va + (p_pt_attrs->l1_base_pa - + pg_tbl_pa); + } else { + /* We got aligned PA, cool */ + p_pt_attrs->l1_tbl_alloc_pa = pg_tbl_pa; + p_pt_attrs->l1_tbl_alloc_va = pg_tbl_va; + p_pt_attrs->l1_tbl_alloc_sz = p_pt_attrs->l1_size; + p_pt_attrs->l1_base_pa = pg_tbl_pa; + p_pt_attrs->l1_base_va = pg_tbl_va; + } + if (p_pt_attrs->l1_base_va) + memset((u8 *)p_pt_attrs->l1_base_va, 0x00, p_pt_attrs->l1_size); + p_pt_attrs->l2_num_pages = ls_num_of_pages; + p_pt_attrs->l2_size = HW_MMU_COARSE_PAGE_SIZE * + p_pt_attrs->l2_num_pages; + align_size = 4; /* Make it u32 aligned */ + /* we like to get aligned on L1 table size */ + pg_tbl_va = (u32)__get_dma_pages(GFP_KERNEL, + get_order(p_pt_attrs->l2_size)); + if (pg_tbl_va == (u32)NULL) { + DPRINTK("dma_alloc_coherent failed 0x%x\n", pg_tbl_va); + status = -ENOMEM; + goto error_exit; + } + pg_tbl_pa = __pa(pg_tbl_va); + p_pt_attrs->l2_tbl_alloc_pa = pg_tbl_pa; + p_pt_attrs->l2_tbl_alloc_va = pg_tbl_va; + p_pt_attrs->ls_tbl_alloc_sz = p_pt_attrs->l2_size; + p_pt_attrs->l2_base_pa = pg_tbl_pa; + p_pt_attrs->l2_base_va = pg_tbl_va; + if (p_pt_attrs->l2_base_va) + memset((u8 *)p_pt_attrs->l2_base_va, 0x00, p_pt_attrs->l2_size); + + p_pt_attrs->pg_info = kmalloc(sizeof(struct page_info), GFP_ATOMIC); + if (p_pt_attrs->pg_info) + memset(p_pt_attrs->pg_info, 0, sizeof(struct page_info)); + else { + DPRINTK("memory allocation fails for p_pt_attrs->pg_info "); + status = -ENOMEM; + goto error_exit; + } + DPRINTK("L1 pa %x, va %x, size %x\n L2 pa %x, va " + "%x, size %x\n", p_pt_attrs->l1_base_pa, + p_pt_attrs->l1_base_va, p_pt_attrs->l1_size, + p_pt_attrs->l2_base_pa, p_pt_attrs->l2_base_va, + p_pt_attrs->l2_size); + DPRINTK("p_pt_attrs %x L2 NumPages %x pg_info %x\n", + (u32)p_pt_attrs, p_pt_attrs->l2_num_pages, + (u32)p_pt_attrs->pg_info); + return 0; +error_exit: + kfree(p_pt_attrs->pg_info); + if (p_pt_attrs->l1_base_va) { + free_pages(p_pt_attrs->l1_base_va, + get_order(p_pt_attrs->l1_tbl_alloc_sz)); + } + if (p_pt_attrs->l2_base_va) { + free_pages(p_pt_attrs->l2_base_va, + get_order(p_pt_attrs->ls_tbl_alloc_sz)); + } + WARN_ON(1); + printk(KERN_ALERT "init_mmu_page_attribs FAILED !!!!!\n"); + return status; +} + +/*======================================== + * This sets up the Ducati processor + * + */ +int ducati_setup(void) +{ + int ret_val = 0; + ret_val = init_mmu_page_attribs(0x8000, 14, 128); + if (WARN_ON(ret_val < 0)) + goto error_exit; + ret_val = ducati_mmu_init(DUCATI_BASEIMAGE_PHYSICAL_ADDRESS); + if (WARN_ON(ret_val < 0)) + goto error_exit; + return 0; +error_exit: + WARN_ON(1); + printk(KERN_ERR "DUCATI SETUP FAILED !!!!!\n"); + return ret_val; +} +EXPORT_SYMBOL(ducati_setup); + +/*============================================ + * De-Initialize the Ducati MMU and free the + * memory allocation for L1 and L2 pages + * + */ +void ducati_destroy(void) +{ + DPRINTK(" Freeing memory allocated in mmu_de_init\n"); + if (p_pt_attrs->l2_tbl_alloc_va) { + free_pages(p_pt_attrs->l2_tbl_alloc_va, + get_order(p_pt_attrs->ls_tbl_alloc_sz)); + } + if (p_pt_attrs->l1_tbl_alloc_va) { + free_pages(p_pt_attrs->l1_tbl_alloc_va, + get_order(p_pt_attrs->l1_tbl_alloc_sz)); + } + if (p_pt_attrs) + kfree((void *)p_pt_attrs); + iounmap((unsigned int *)base_ducati_l2_mmu); + return; +} +EXPORT_SYMBOL(ducati_destroy); + +/*============================================ + * Returns the ducati virtual address for IPC shared memory + * + */ +u32 get_ducati_virt_mem() +{ + /*shm_virt_addr = (u32)ioremap(shm_phys_addr, DUCATI_SHARED_IPC_LEN);*/ + shm_virt_addr = (u32)ioremap(shm_phys_addr, DUCATI_MEM_IPC_SHMEM_LEN); + return shm_virt_addr; +} +EXPORT_SYMBOL(get_ducati_virt_mem); + +/*============================================ + * Unmaps the ducati virtual address for IPC shared memory + * + */ +void unmap_ducati_virt_mem(u32 shm_virt_addr) +{ + iounmap((unsigned int *) shm_virt_addr); + return; +} +EXPORT_SYMBOL(unmap_ducati_virt_mem); diff --git a/drivers/dsp/syslink/procmgr/proc4430/hw_mmu.c b/drivers/dsp/syslink/procmgr/proc4430/hw_mmu.c new file mode 100755 index 000000000000..f2e4ccbe860f --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/hw_mmu.c @@ -0,0 +1,643 @@ +/* + * hw_mbox.c + * + * Syslink driver support for OMAP Processors. + * + * Copyright (C) 2008-2009 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +#include<linux/kernel.h> +#include<linux/module.h> + +#include <syslink/GlobalTypes.h> +#include <syslink/MMURegAcM.h> +#include <syslink/hw_defs.h> +#include <syslink/hw_mmu.h> + +#define MMU_BASE_VAL_MASK 0xFC00 +#define MMU_PAGE_MAX 3 +#define MMU_ELEMENTSIZE_MAX 3 +#define MMU_ADDR_MASK 0xFFFFF000 +#define MMU_TTB_MASK 0xFFFFC000 +#define MMU_SECTION_ADDR_MASK 0xFFF00000 +#define MMU_SSECTION_ADDR_MASK 0xFF000000 +#define MMU_PAGE_TABLE_MASK 0xFFFFFC00 +#define MMU_LARGE_PAGE_MASK 0xFFFF0000 +#define MMU_SMALL_PAGE_MASK 0xFFFFF000 + +#define MMU_LOAD_TLB 0x00000001 +#define NUM_TLB_ENTRIES 32 + + + +/* +* type: hw_mmu_pgsiz_t +* +* desc: Enumerated Type used to specify the MMU Page Size(SLSS) +* +* +*/ +enum hw_mmu_pgsiz_t { + HW_MMU_SECTION, + HW_MMU_LARGE_PAGE, + HW_MMU_SMALL_PAGE, + HW_MMU_SUPERSECTION + +}; + +/* +* function : mmu_flsh_entry +*/ + +static hw_status mmu_flsh_entry(const u32 base_address); + + /* +* function : mme_set_cam_entry +* +*/ + +static hw_status mme_set_cam_entry(const u32 base_address, + const u32 page_size, + const u32 preserve_bit, + const u32 valid_bit, + const u32 virt_addr_tag); + +/* +* function : mmu_set_ram_entry +*/ +static hw_status mmu_set_ram_entry(const u32 base_address, + const u32 physical_addr, + enum hw_endianism_t endianism, + enum hw_elemnt_siz_t element_size, + enum hw_mmu_mixed_size_t mixedSize); + +/* +* hw functions +* +*/ + +hw_status hw_mmu_enable(const u32 base_address) +{ + hw_status status = RET_OK; + + MMUMMU_CNTLMMUEnableWrite32(base_address, HW_SET); + + return status; +} +EXPORT_SYMBOL(hw_mmu_enable); + +hw_status hw_mmu_disable(const u32 base_address) +{ + hw_status status = RET_OK; + + MMUMMU_CNTLMMUEnableWrite32(base_address, HW_CLEAR); + + return status; +} +EXPORT_SYMBOL(hw_mmu_disable); + +hw_status hw_mmu_autoidle_en(const u32 base_address) +{ + hw_status status; + + status = mmu_sisconf_auto_idle_set32(base_address, HW_SET); + status = RET_OK; + return status; +} +EXPORT_SYMBOL(hw_mmu_autoidle_en); + +hw_status hw_mmu_nulck_set(const u32 base_address, u32 *num_lcked_entries) +{ + hw_status status = RET_OK; + + *num_lcked_entries = MMUMMU_LOCKBaseValueRead32(base_address); + + return status; +} +EXPORT_SYMBOL(hw_mmu_nulck_set); + + +hw_status hw_mmu_numlocked_set(const u32 base_address, u32 num_lcked_entries) +{ + hw_status status = RET_OK; + + MMUMMU_LOCKBaseValueWrite32(base_address, num_lcked_entries); + + return status; +} +EXPORT_SYMBOL(hw_mmu_numlocked_set); + + +hw_status hw_mmu_vctm_numget(const u32 base_address, u32 *vctm_entry_num) +{ + hw_status status = RET_OK; + + *vctm_entry_num = MMUMMU_LOCKCurrentVictimRead32(base_address); + + return status; +} +EXPORT_SYMBOL(hw_mmu_vctm_numget); + + +hw_status hw_mmu_victim_numset(const u32 base_address, u32 vctm_entry_num) +{ + hw_status status = RET_OK; + + mmu_lck_crnt_vctmwite32(base_address, vctm_entry_num); + + return status; +} +EXPORT_SYMBOL(hw_mmu_victim_numset); + +hw_status hw_mmu_tlb_flushAll(const u32 base_address) +{ + hw_status status = RET_OK; + + MMUMMU_GFLUSHGlobalFlushWrite32(base_address, HW_SET); + + return status; +} +EXPORT_SYMBOL(hw_mmu_tlb_flushAll); + +hw_status hw_mmu_eventack(const u32 base_address, u32 irq_mask) +{ + hw_status status = RET_OK; + + MMUMMU_IRQSTATUSWriteRegister32(base_address, irq_mask); + + return status; +} +EXPORT_SYMBOL(hw_mmu_eventack); + +hw_status hw_mmu_event_disable(const u32 base_address, u32 irq_mask) +{ + hw_status status = RET_OK; + u32 irqReg; + irqReg = MMUMMU_IRQENABLEReadRegister32(base_address); + + MMUMMU_IRQENABLEWriteRegister32(base_address, irqReg & ~irq_mask); + + return status; +} +EXPORT_SYMBOL(hw_mmu_event_disable); + +hw_status hw_mmu_event_enable(const u32 base_address, u32 irq_mask) +{ + hw_status status = RET_OK; + u32 irqReg; + + irqReg = MMUMMU_IRQENABLEReadRegister32(base_address); + + MMUMMU_IRQENABLEWriteRegister32(base_address, irqReg | irq_mask); + + return status; +} +EXPORT_SYMBOL(hw_mmu_event_enable); + +hw_status hw_mmu_event_status(const u32 base_address, u32 *irq_mask) +{ + hw_status status = RET_OK; + + *irq_mask = MMUMMU_IRQSTATUSReadRegister32(base_address); + + return status; +} +EXPORT_SYMBOL(hw_mmu_event_status); + +hw_status hw_mmu_flt_adr_rd(const u32 base_address, u32 *addr) +{ + hw_status status = RET_OK; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(base_address, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + /* read values from register */ + *addr = MMUMMU_FAULT_ADReadRegister32(base_address); + + return status; +} +EXPORT_SYMBOL(hw_mmu_flt_adr_rd); + + +hw_status hw_mmu_ttbset(const u32 base_address, u32 ttb_phys_addr) +{ + hw_status status = RET_OK; + u32 loadTTB; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(base_address, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + loadTTB = ttb_phys_addr & ~0x7FUL; + /* write values to register */ + MMUMMU_TTBWriteRegister32(base_address, loadTTB); + + return status; +} +EXPORT_SYMBOL(hw_mmu_ttbset); + +hw_status hw_mmu_twl_enable(const u32 base_address) +{ + hw_status status = RET_OK; + + MMUMMU_CNTLTWLEnableWrite32(base_address, HW_SET); + + return status; +} +EXPORT_SYMBOL(hw_mmu_twl_enable); + +hw_status hw_mmu_twl_disable(const u32 base_address) +{ + hw_status status = RET_OK; + + MMUMMU_CNTLTWLEnableWrite32(base_address, HW_CLEAR); + + return status; +} +EXPORT_SYMBOL(hw_mmu_twl_disable); + + +hw_status hw_mmu_tlb_flush(const u32 base_address, + u32 virtual_addr, + u32 page_size) +{ + hw_status status = RET_OK; + u32 virt_addr_tag; + enum hw_mmu_pgsiz_t pg_sizeBits; + + switch (page_size) { + case HW_PAGE_SIZE_4KB: + pg_sizeBits = HW_MMU_SMALL_PAGE; + break; + + case HW_PAGE_SIZE_64KB: + pg_sizeBits = HW_MMU_LARGE_PAGE; + break; + + case HW_PAGE_SIZE_1MB: + pg_sizeBits = HW_MMU_SECTION; + break; + + case HW_PAGE_SIZE_16MB: + pg_sizeBits = HW_MMU_SUPERSECTION; + break; + + default: + return RET_FAIL; + } + + /* Generate the 20-bit tag from virtual address */ + virt_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12); + + mme_set_cam_entry(base_address, pg_sizeBits, 0, 0, virt_addr_tag); + + mmu_flsh_entry(base_address); + + return status; +} +EXPORT_SYMBOL(hw_mmu_tlb_flush); + + +hw_status hw_mmu_tlb_add(const u32 base_address, + u32 physical_addr, + u32 virtual_addr, + u32 page_size, + u32 entryNum, + struct hw_mmu_map_attrs_t *map_attrs, + enum hw_set_clear_t preserve_bit, + enum hw_set_clear_t valid_bit) +{ + hw_status status = RET_OK; + u32 lockReg; + u32 virt_addr_tag; + enum hw_mmu_pgsiz_t mmu_pg_size; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(base_address, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(page_size, MMU_PAGE_MAX, RET_PARAM_OUT_OF_RANGE, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(map_attrs->element_size, + MMU_ELEMENTSIZE_MAX, RET_PARAM_OUT_OF_RANGE, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + switch (page_size) { + case HW_PAGE_SIZE_4KB: + mmu_pg_size = HW_MMU_SMALL_PAGE; + break; + + case HW_PAGE_SIZE_64KB: + mmu_pg_size = HW_MMU_LARGE_PAGE; + break; + + case HW_PAGE_SIZE_1MB: + mmu_pg_size = HW_MMU_SECTION; + break; + + case HW_PAGE_SIZE_16MB: + mmu_pg_size = HW_MMU_SUPERSECTION; + break; + + default: + return RET_FAIL; + } + + lockReg = mmu_lckread_reg_32(base_address); + + /* Generate the 20-bit tag from virtual address */ + virt_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12); + + /* Write the fields in the CAM Entry Register */ + mme_set_cam_entry(base_address, mmu_pg_size, preserve_bit, valid_bit, + virt_addr_tag); + + /* Write the different fields of the RAM Entry Register */ + /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit) */ + mmu_set_ram_entry(base_address, physical_addr, + map_attrs->endianism, map_attrs->element_size, map_attrs->mixedSize); + + /* Update the MMU Lock Register */ + /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1) */ + mmu_lck_crnt_vctmwite32(base_address, entryNum); + + /* Enable loading of an entry in TLB by writing 1 into LD_TLB_REG + register */ + mmu_ld_tlbwrt_reg32(base_address, MMU_LOAD_TLB); + + + mmu_lck_write_reg32(base_address, lockReg); + + return status; +} +EXPORT_SYMBOL(hw_mmu_tlb_add); + + + +hw_status hw_mmu_pte_set(const u32 pg_tbl_va, + u32 physical_addr, + u32 virtual_addr, + u32 page_size, + struct hw_mmu_map_attrs_t *map_attrs) +{ + hw_status status = RET_OK; + u32 pte_addr, pte_val; + long int num_entries = 1; + + switch (page_size) { + + case HW_PAGE_SIZE_4KB: + pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va, virtual_addr & + MMU_SMALL_PAGE_MASK); + pte_val = ((physical_addr & MMU_SMALL_PAGE_MASK) | + (map_attrs->endianism << 9) | + (map_attrs->element_size << 4) | + (map_attrs->mixedSize << 11) | 2 + ); + break; + + case HW_PAGE_SIZE_64KB: + num_entries = 16; + pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va, virtual_addr & + MMU_LARGE_PAGE_MASK); + pte_val = ((physical_addr & MMU_LARGE_PAGE_MASK) | + (map_attrs->endianism << 9) | + (map_attrs->element_size << 4) | + (map_attrs->mixedSize << 11) | 1 + ); + break; + + case HW_PAGE_SIZE_1MB: + pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va, virtual_addr & + MMU_SECTION_ADDR_MASK); + pte_val = ((((physical_addr & MMU_SECTION_ADDR_MASK) | + (map_attrs->endianism << 15) | + (map_attrs->element_size << 10) | + (map_attrs->mixedSize << 17)) & + ~0x40000) | 0x2 + ); + break; + + case HW_PAGE_SIZE_16MB: + num_entries = 16; + pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va, virtual_addr & + MMU_SSECTION_ADDR_MASK); + pte_val = (((physical_addr & MMU_SSECTION_ADDR_MASK) | + (map_attrs->endianism << 15) | + (map_attrs->element_size << 10) | + (map_attrs->mixedSize << 17) + ) | 0x40000 | 0x2 + ); + break; + + case HW_MMU_COARSE_PAGE_SIZE: + pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va, virtual_addr & + MMU_SECTION_ADDR_MASK); + pte_val = (physical_addr & MMU_PAGE_TABLE_MASK) | 1; + break; + + default: + return RET_FAIL; + } + + while (--num_entries >= 0) + ((u32 *)pte_addr)[num_entries] = pte_val; + + + return status; +} +EXPORT_SYMBOL(hw_mmu_pte_set); + +hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, + u32 virtual_addr, + u32 pg_size) +{ + hw_status status = RET_OK; + u32 pte_addr; + long int num_entries = 1; + + switch (pg_size) { + case HW_PAGE_SIZE_4KB: + pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va, + virtual_addr & MMU_SMALL_PAGE_MASK); + break; + + case HW_PAGE_SIZE_64KB: + num_entries = 16; + pte_addr = hw_mmu_pte_addr_l2(pg_tbl_va, + virtual_addr & MMU_LARGE_PAGE_MASK); + break; + + case HW_PAGE_SIZE_1MB: + case HW_MMU_COARSE_PAGE_SIZE: + pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va, + virtual_addr & MMU_SECTION_ADDR_MASK); + break; + + case HW_PAGE_SIZE_16MB: + num_entries = 16; + pte_addr = hw_mmu_pte_addr_l1(pg_tbl_va, + virtual_addr & MMU_SSECTION_ADDR_MASK); + break; + + default: + return RET_FAIL; + } + + while (--num_entries >= 0) + ((u32 *)pte_addr)[num_entries] = 0; + + return status; +} +EXPORT_SYMBOL(hw_mmu_pte_clear); + +/* +* function: mmu_flsh_entry +*/ +static hw_status mmu_flsh_entry(const u32 base_address) +{ + hw_status status = RET_OK; + u32 flushEntryData = 0x1; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(base_address, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + /* write values to register */ + MMUMMU_FLUSH_ENTRYWriteRegister32(base_address, flushEntryData); + + return status; +} +EXPORT_SYMBOL(mmu_flsh_entry); +/* +* function : mme_set_cam_entry +*/ +static hw_status mme_set_cam_entry(const u32 base_address, + const u32 page_size, + const u32 preserve_bit, + const u32 valid_bit, + const u32 virt_addr_tag) +{ + hw_status status = RET_OK; + u32 mmuCamReg; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(base_address, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + mmuCamReg = (virt_addr_tag << 12); + mmuCamReg = (mmuCamReg) | (page_size) | (valid_bit << 2) + | (preserve_bit << 3); + + /* write values to register */ + MMUMMU_CAMWriteRegister32(base_address, mmuCamReg); + + return status; +} +EXPORT_SYMBOL(mme_set_cam_entry); +/* +* function: mmu_set_ram_entry +*/ +static hw_status mmu_set_ram_entry(const u32 base_address, + const u32 physical_addr, + enum hw_endianism_t endianism, + enum hw_elemnt_siz_t element_size, + enum hw_mmu_mixed_size_t mixedSize) +{ + hw_status status = RET_OK; + u32 mmuRamReg; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(base_address, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(element_size, MMU_ELEMENTSIZE_MAX, + RET_PARAM_OUT_OF_RANGE, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + + mmuRamReg = (physical_addr & MMU_ADDR_MASK); + mmuRamReg = (mmuRamReg) | ((endianism << 9) | (element_size << 7) + | (mixedSize << 6)); + + /* write values to register */ + MMUMMU_RAMWriteRegister32(base_address, mmuRamReg); + + return status; + +} +EXPORT_SYMBOL(mmu_set_ram_entry); + +long hw_mmu_tlb_dump(const u32 base_address, bool shw_inv_entries) +{ + u32 i; + u32 lockSave; + u32 cam; + u32 ram; + + + /* Save off the lock register contents, + we'll restore it when we are done */ + + lockSave = mmu_lckread_reg_32(base_address); + + printk(KERN_INFO "TLB locked entries = %u, current victim = %u\n", + ((lockSave & MMU_MMU_LOCK_BaseValue_MASK) + >> MMU_MMU_LOCK_BaseValue_OFFSET), + ((lockSave & MMU_MMU_LOCK_CurrentVictim_MASK) + >> MMU_MMU_LOCK_CurrentVictim_OFFSET)); + printk(KERN_INFO "=============================================\n"); + for (i = 0; i < NUM_TLB_ENTRIES; i++) { + mmu_lck_crnt_vctmwite32(base_address, i); + cam = MMUMMU_CAMReadRegister32(base_address); + ram = MMUMMU_RAMReadRegister32(base_address); + + if ((cam & 0x4) != 0) { + printk(KERN_INFO "TLB Entry [0x%x]: VA = 0x%x" + "PA = 0x%x Protected = 0x%x\n)", + i, (cam & MMU_ADDR_MASK), (ram & MMU_ADDR_MASK), + (cam & 0x8) ? 1 : 0); + + } else if (shw_inv_entries != false) + printk(KERN_ALERT "TLB Entry [0x%x]: <INVALID>\n", i); + } + mmu_lck_write_reg32(base_address, lockSave); + return RET_OK; +} +EXPORT_SYMBOL(hw_mmu_tlb_dump); + +u32 hw_mmu_pte_phyaddr(u32 pte_val, u32 pte_size) +{ + u32 ret_val = 0; + + switch (pte_size) { + + case HW_PAGE_SIZE_4KB: + ret_val = pte_val & MMU_SMALL_PAGE_MASK; + break; + case HW_PAGE_SIZE_64KB: + ret_val = pte_val & MMU_LARGE_PAGE_MASK; + break; + + case HW_PAGE_SIZE_1MB: + ret_val = pte_val & MMU_SECTION_ADDR_MASK; + break; + case HW_PAGE_SIZE_16MB: + ret_val = pte_val & MMU_SSECTION_ADDR_MASK; + break; + default: + /* Invalid */ + break; + + } + + return ret_val; +} +EXPORT_SYMBOL(hw_mmu_pte_phyaddr); diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430.c b/drivers/dsp/syslink/procmgr/proc4430/proc4430.c new file mode 100644 index 000000000000..e752a7932c9e --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430.c @@ -0,0 +1,1021 @@ +/* + * proc4430.c + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/vmalloc.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/delay.h> + +/* Module level headers */ +#include "../procdefs.h" +#include "../processor.h" +#include <procmgr.h> +#include "../procmgr_drvdefs.h" +#include "proc4430.h" +#include "dmm4430.h" +#include <syslink/multiproc.h> +#include <syslink/ducatienabler.h> +#include <syslink/platform_mem.h> +#include <syslink/atomic_linux.h> + +#define DUCATI_DMM_START_ADDR 0xa0000000 +#define DUCATI_DMM_POOL_SIZE 0x6000000 + +#define SYS_M3 2 +#define APP_M3 3 +#define CORE_PRM_BASE OMAP2_L4_IO_ADDRESS(0x4a306700) +#define CORE_CM2_DUCATI_CLKSTCTRL OMAP2_L4_IO_ADDRESS(0x4A008900) +#define CORE_CM2_DUCATI_CLKCTRL OMAP2_L4_IO_ADDRESS(0x4A008920) +#define RM_MPU_M3_RSTCTRL_OFFSET 0x210 +#define RM_MPU_M3_RSTST_OFFSET 0x214 +#define RM_MPU_M3_RST1 0x1 +#define RM_MPU_M3_RST2 0x2 +#define RM_MPU_M3_RST3 0x4 + +#define OMAP4430PROC_MODULEID (u16) 0xbbec + +/* Macro to make a correct module magic number with refCount */ +#define OMAP4430PROC_MAKE_MAGICSTAMP(x) ((OMAP4430PROC_MODULEID << 12u) | (x)) + +/*OMAP4430 Module state object */ +struct proc4430_module_object { + u32 config_size; + /* Size of configuration structure */ + struct proc4430_config cfg; + /* OMAP4430 configuration structure */ + struct proc4430_config def_cfg; + /* Default module configuration */ + struct proc4430_params def_inst_params; + /* Default parameters for the OMAP4430 instances */ + void *proc_handles[MULTIPROC_MAXPROCESSORS]; + /* Processor handle array. */ + struct mutex *gate_handle; + /* void * of gate to be used for local thread safety */ + atomic_t ref_count; +}; + +/* + OMAP4430 instance object. + */ +struct proc4430_object { + struct proc4430_params params; + /* Instance parameters (configuration values) */ +}; + + +/* ================================= + * Globals + * ================================= + */ +/* + OMAP4430 state object variable + */ + +static struct proc4430_module_object proc4430_state = { + .config_size = sizeof(struct proc4430_config), + .gate_handle = NULL, + .def_inst_params.num_mem_entries = 0u, + .def_inst_params.mem_entries = NULL, + .def_inst_params.reset_vector_mem_entry = 0 +}; + + +/* ================================= + * APIs directly called by applications + * ================================= + */ +/* + * Function to get the default configuration for the OMAP4430 + * module. + * + * This function can be called by the application to get their + * configuration parameter to proc4430_setup filled in by the + * OMAP4430 module with the default parameters. If the user + * does not wish to make any change in the default parameters, this + * API is not required to be called. + */ +void proc4430_get_config(struct proc4430_config *cfg) +{ + BUG_ON(cfg == NULL); + memcpy(cfg, &(proc4430_state.def_cfg), + sizeof(struct proc4430_config)); +} +EXPORT_SYMBOL(proc4430_get_config); + +/* + * Function to setup the OMAP4430 module. + * + * This function sets up the OMAP4430 module. This function + * must be called before any other instance-level APIs can be + * invoked. + * Module-level configuration needs to be provided to this + * function. If the user wishes to change some specific config + * parameters, then proc4430_get_config can be called to get the + * configuration filled with the default values. After this, only + * the required configuration values can be changed. If the user + * does not wish to make any change in the default parameters, the + * application can simply call proc4430_setup with NULL + * parameters. The default parameters would get automatically used. + */ +int proc4430_setup(struct proc4430_config *cfg) +{ + int retval = 0; + struct proc4430_config tmp_cfg; + atomic_cmpmask_and_set(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(0)); + + if (atomic_inc_return(&proc4430_state.ref_count) != + OMAP4430PROC_MAKE_MAGICSTAMP(1)) { + return 1; + } + + if (cfg == NULL) { + proc4430_get_config(&tmp_cfg); + cfg = &tmp_cfg; + } + + dmm_create(); + dmm_create_tables(DUCATI_DMM_START_ADDR, DUCATI_DMM_POOL_SIZE); + + /* Create a default gate handle for local module protection. */ + proc4430_state.gate_handle = + kmalloc(sizeof(struct mutex), GFP_KERNEL); + if (proc4430_state.gate_handle == NULL) { + retval = -ENOMEM; + goto error; + } + + mutex_init(proc4430_state.gate_handle); + + /* Initialize the name to handles mapping array. */ + memset(&proc4430_state.proc_handles, 0, + (sizeof(void *) * MULTIPROC_MAXPROCESSORS)); + + /* Copy the user provided values into the state object. */ + memcpy(&proc4430_state.cfg, cfg, + sizeof(struct proc4430_config)); + + return 0; + +error: + atomic_dec_return(&proc4430_state.ref_count); + dmm_delete_tables(); + dmm_destroy(); + + return retval; +} +EXPORT_SYMBOL(proc4430_setup); + +/* + * Function to destroy the OMAP4430 module. + * + * Once this function is called, other OMAP4430 module APIs, + * except for the proc4430_get_config API cannot be called + * anymore. + */ +int proc4430_destroy(void) +{ + int retval = 0; + u16 i; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + retval = -ENODEV; + goto exit; + } + if (!(atomic_dec_return(&proc4430_state.ref_count) + == OMAP4430PROC_MAKE_MAGICSTAMP(0))) { + + retval = 1; + goto exit; + } + + /* Check if any OMAP4430 instances have not been + * deleted so far. If not,delete them. + */ + + for (i = 0; i < MULTIPROC_MAXPROCESSORS; i++) { + if (proc4430_state.proc_handles[i] == NULL) + continue; + proc4430_delete(&(proc4430_state.proc_handles[i])); + } + + /* Check if the gate_handle was created internally. */ + if (proc4430_state.gate_handle != NULL) { + mutex_destroy(proc4430_state.gate_handle); + kfree(proc4430_state.gate_handle); + } + +exit: + return retval; +} +EXPORT_SYMBOL(proc4430_destroy); + +/*================================================= + * Function to initialize the parameters for this Processor + * instance. + */ +void proc4430_params_init(void *handle, struct proc4430_params *params) +{ + struct proc4430_object *proc_object = (struct proc4430_object *)handle; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_params_init failed " + "Module not initialized"); + return; + } + + if (WARN_ON(params == NULL)) { + printk(KERN_ERR "proc4430_params_init failed " + "Argument of type proc4430_params * " + "is NULL"); + return; + } + + if (handle == NULL) + memcpy(params, &(proc4430_state.def_inst_params), + sizeof(struct proc4430_params)); + else + memcpy(params, &(proc_object->params), + sizeof(struct proc4430_params)); +} +EXPORT_SYMBOL(proc4430_params_init); + +/*=================================================== + *Function to create an instance of this Processor. + * + */ +void *proc4430_create(u16 proc_id, const struct proc4430_params *params) +{ + struct processor_object *handle = NULL; + struct proc4430_object *object = NULL; + + BUG_ON(!IS_VALID_PROCID(proc_id)); + BUG_ON(params == NULL); + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_create failed " + "Module not initialized"); + goto error; + } + + /* Enter critical section protection. */ + WARN_ON(mutex_lock_interruptible(proc4430_state.gate_handle)); + if (proc4430_state.proc_handles[proc_id] != NULL) { + handle = proc4430_state.proc_handles[proc_id]; + goto func_end; + } else { + handle = (struct processor_object *) + vmalloc(sizeof(struct processor_object)); + if (WARN_ON(handle == NULL)) + goto func_end; + + handle->proc_fxn_table.attach = &proc4430_attach; + handle->proc_fxn_table.detach = &proc4430_detach; + handle->proc_fxn_table.start = &proc4430_start; + handle->proc_fxn_table.stop = &proc4430_stop; + handle->proc_fxn_table.read = &proc4430_read; + handle->proc_fxn_table.write = &proc4430_write; + handle->proc_fxn_table.control = &proc4430_control; + handle->proc_fxn_table.translateAddr = + &proc4430_translate_addr; + handle->proc_fxn_table.map = &proc4430_map; + handle->proc_fxn_table.unmap = &proc4430_unmap; + handle->proc_fxn_table.procinfo = &proc4430_proc_info; + handle->proc_fxn_table.virt_to_phys = &proc4430_virt_to_phys; + handle->state = PROC_MGR_STATE_UNKNOWN; + handle->object = vmalloc(sizeof(struct proc4430_object)); + handle->proc_id = proc_id; + object = (struct proc4430_object *)handle->object; + if (params != NULL) { + /* Copy params into instance object. */ + memcpy(&(object->params), (void *)params, + sizeof(struct proc4430_params)); + } + if ((params != NULL) && (params->mem_entries != NULL) + && (params->num_mem_entries > 0)) { + /* Allocate memory for, and copy mem_entries table*/ + object->params.mem_entries = vmalloc(sizeof(struct + proc4430_mem_entry) * + params->num_mem_entries); + memcpy(object->params.mem_entries, + params->mem_entries, + (sizeof(struct proc4430_mem_entry) * + params->num_mem_entries)); + } + handle->boot_mode = PROC_MGR_BOOTMODE_NOLOAD; + /* Set the handle in the state object. */ + proc4430_state.proc_handles[proc_id] = handle; + } + +func_end: + mutex_unlock(proc4430_state.gate_handle); +error: + return (void *)handle; +} +EXPORT_SYMBOL(proc4430_create); + +/*================================================= + * Function to delete an instance of this Processor. + * + * The user provided pointer to the handle is reset after + * successful completion of this function. + * + */ +int proc4430_delete(void **handle_ptr) +{ + int retval = 0; + struct proc4430_object *object = NULL; + struct processor_object *handle; + + BUG_ON(handle_ptr == NULL); + BUG_ON(*handle_ptr == NULL); + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_delete failed " + "Module not initialized"); + return -ENODEV; + } + + handle = (struct processor_object *)(*handle_ptr); + BUG_ON(!IS_VALID_PROCID(handle->proc_id)); + /* Enter critical section protection. */ + WARN_ON(mutex_lock_interruptible(proc4430_state.gate_handle)); + /* Reset handle in PwrMgr handle array. */ + proc4430_state.proc_handles[handle->proc_id] = NULL; + /* Free memory used for the OMAP4430 object. */ + if (handle->object != NULL) { + object = (struct proc4430_object *)handle->object; + if (object->params.mem_entries != NULL) { + vfree(object->params.mem_entries); + object->params.mem_entries = NULL; + } + vfree(handle->object); + handle->object = NULL; + } + /* Free memory used for the Processor object. */ + vfree(handle); + *handle_ptr = NULL; + /* Leave critical section protection. */ + mutex_unlock(proc4430_state.gate_handle); + return retval; +} +EXPORT_SYMBOL(proc4430_delete); + +/*=================================================== + * Function to open a handle to an instance of this Processor. This + * function is called when access to the Processor is required from + * a different process. + */ +int proc4430_open(void **handle_ptr, u16 proc_id) +{ + int retval = 0; + + BUG_ON(handle_ptr == NULL); + BUG_ON(!IS_VALID_PROCID(proc_id)); + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_open failed " + "Module not initialized"); + return -ENODEV; + } + + /* Initialize return parameter handle. */ + *handle_ptr = NULL; + + /* Check if the PwrMgr exists and return the handle if found. */ + if (proc4430_state.proc_handles[proc_id] == NULL) { + retval = -ENODEV; + goto func_exit; + } else + *handle_ptr = proc4430_state.proc_handles[proc_id]; +func_exit: + return retval; +} +EXPORT_SYMBOL(proc4430_open); + +/*=============================================== + * Function to close a handle to an instance of this Processor. + * + */ +int proc4430_close(void *handle) +{ + int retval = 0; + + BUG_ON(handle == NULL); + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_close failed " + "Module not initialized"); + return -ENODEV; + } + + /* nothing to be done for now */ + return retval; +} +EXPORT_SYMBOL(proc4430_close); + +/* ================================= + * APIs called by Processor module (part of function table interface) + * ================================= + */ +/*================================ + * Function to initialize the slave processor + * + */ +int proc4430_attach(void *handle, struct processor_attach_params *params) +{ + int retval = 0; + + struct processor_object *proc_handle = NULL; + struct proc4430_object *object = NULL; + u32 map_count = 0; + u32 i; + memory_map_info map_info; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_attach failed" + "Module not initialized"); + return -ENODEV; + } + + if (WARN_ON(handle == NULL)) { + printk(KERN_ERR "proc4430_attach failed" + "Driver handle is NULL"); + return -EINVAL; + } + + if (WARN_ON(params == NULL)) { + printk(KERN_ERR "proc4430_attach failed" + "Argument processor_attach_params * is NULL"); + return -EINVAL; + } + + proc_handle = (struct processor_object *)handle; + + object = (struct proc4430_object *)proc_handle->object; + /* Return memory information in params. */ + for (i = 0; (i < object->params.num_mem_entries); i++) { + /* If the configured master virtual address is invalid, get the + * actual address by mapping the physical address into master + * kernel memory space. + */ + if ((object->params.mem_entries[i].master_virt_addr == (u32)-1) + && (object->params.mem_entries[i].shared == true)) { + map_info.src = object->params.mem_entries[i].phys_addr; + map_info.size = object->params.mem_entries[i].size; + map_info.is_cached = false; + retval = platform_mem_map(&map_info); + if (retval != 0) { + printk(KERN_ERR "proc4430_attach failed\n"); + return -EFAULT; + } + map_count++; + object->params.mem_entries[i].master_virt_addr = + map_info.dst; + params->mem_entries[i].addr + [PROC_MGR_ADDRTYPE_MASTERKNLVIRT] = + map_info.dst; + params->mem_entries[i].addr + [PROC_MGR_ADDRTYPE_SLAVEVIRT] = + (object->params.mem_entries[i].slave_virt_addr); + /* User virtual will be filled by user side. For now, + fill in the physical address so that it can be used + by mmap to remap this region into user-space */ + params->mem_entries[i].addr + [PROC_MGR_ADDRTYPE_MASTERUSRVIRT] = \ + object->params.mem_entries[i].phys_addr; + params->mem_entries[i].size = + object->params.mem_entries[i].size; + } + } + params->num_mem_entries = map_count; + return retval; +} + + +/*========================================== + * Function to detach from the Processor. + * + */ +int proc4430_detach(void *handle) +{ + struct processor_object *proc_handle = NULL; + struct proc4430_object *object = NULL; + u32 i; + memory_unmap_info unmap_info; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + + printk(KERN_ERR "proc4430_detach failed " + "Module not initialized"); + return -ENODEV; + } + + if (WARN_ON(handle == NULL)) { + printk(KERN_ERR "proc4430_detach failed " + "Argument Driverhandle is NULL"); + return -EINVAL; + } + + proc_handle = (struct processor_object *)handle; + object = (struct proc4430_object *)proc_handle->object; + for (i = 0; (i < object->params.num_mem_entries); i++) { + if ((object->params.mem_entries[i].master_virt_addr > 0) + && (object->params.mem_entries[i].shared == true)) { + unmap_info.addr = + object->params.mem_entries[i].master_virt_addr; + unmap_info.size = object->params.mem_entries[i].size; + platform_mem_unmap(&unmap_info); + object->params.mem_entries[i].master_virt_addr = + (u32)-1; + } + } + return 0; +} + +/*========================================== + * Function to start the slave processor + * + * Start the slave processor running from its entry point. + * Depending on the boot mode, this involves configuring the boot + * address and releasing the slave from reset. + * + */ +int proc4430_start(void *handle, u32 entry_pt, + struct processor_start_params *start_params) +{ + u32 reg; + int counter = 10; + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + + printk(KERN_ERR "proc4430_start failed " + "Module not initialized"); + return -ENODEV; + } + + /*FIXME: Remove handle and entry_pt if not used */ + if (WARN_ON(start_params == NULL)) { + printk(KERN_ERR "proc4430_start failed " + "Argument processor_start_params * is NULL"); + return -EINVAL; + } + switch (start_params->params->proc_id) { + case SYS_M3: + /* Module is managed automatically by HW */ + __raw_writel(0x01, CORE_CM2_DUCATI_CLKCTRL); + /* Enable the M3 clock */ + __raw_writel(0x02, CORE_CM2_DUCATI_CLKSTCTRL); + do { + reg = __raw_readl(CORE_CM2_DUCATI_CLKSTCTRL); + if (reg & 0x100) { + printk(KERN_INFO "M3 clock enabled:" + "CORE_CM2_DUCATI_CLKSTCTRL = 0x%x\n", reg); + break; + } + msleep(1); + } while (--counter); + if (counter == 0) { + printk(KERN_ERR "FAILED TO ENABLE DUCATI M3 CLOCK !\n"); + return -EFAULT; + } + /* De-assert RST 3 */ + __raw_writel(0x3, CORE_PRM_BASE + RM_MPU_M3_RSTCTRL_OFFSET); + ducati_setup(); + printk(KERN_INFO "De-assert RST1\n"); + __raw_writel(0x2, CORE_PRM_BASE + RM_MPU_M3_RSTCTRL_OFFSET); + return 0; + break; + case APP_M3: + __raw_writel(0x0, CORE_PRM_BASE + RM_MPU_M3_RSTCTRL_OFFSET); + printk(KERN_INFO "De-assert RST2\n"); + break; + default: + printk(KERN_ERR "proc4430_start: ERROR input\n"); + break; + } + return 0; +} + + +/* + * Function to stop the slave processor + * + * Stop the execution of the slave processor. Depending on the boot + * mode, this may result in placing the slave processor in reset. + * + * @param handle void * to the Processor instance + * + * @sa proc4430_start, OMAP3530_halResetCtrl + */ +int +proc4430_stop(void *handle, struct processor_stop_params *stop_params) +{ + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_stop failed " + "Module not initialized"); + return -ENODEV; + } + switch (stop_params->params->proc_id) { + case SYS_M3: + ducati_destroy(); + printk(KERN_INFO "Assert RST1 and RST2 and RST3\n"); + __raw_writel(0x7, CORE_PRM_BASE + RM_MPU_M3_RSTCTRL_OFFSET); + /* Disable the M3 clock */ + __raw_writel(0x01, CORE_CM2_DUCATI_CLKSTCTRL); + break; + case APP_M3: + printk(KERN_INFO "Assert RST2\n"); + __raw_writel(0x2, CORE_PRM_BASE + RM_MPU_M3_RSTCTRL_OFFSET); + break; + default: + printk(KERN_ERR "proc4430_stop: ERROR input\n"); + break; + } + return 0; +} + + +/*============================================== + * Function to read from the slave processor's memory. + * + * Read from the slave processor's memory and copy into the + * provided buffer. + */ +int proc4430_read(void *handle, u32 proc_addr, u32 *num_bytes, + void *buffer) +{ + int retval = 0; + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_read failed " + "Module not initialized"); + return -ENODEV; + } + + /* TODO */ + return retval; +} + + +/*============================================== + * Function to write into the slave processor's memory. + * + * Read from the provided buffer and copy into the slave + * processor's memory. + * + */ +int proc4430_write(void *handle, u32 proc_addr, u32 *num_bytes, + void *buffer) +{ + int retval = 0; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_write failed " + "Module not initialized"); + return -ENODEV; + } + + /* TODO */ + return retval; +} + + +/*========================================================= + * Function to perform device-dependent operations. + * + * Performs device-dependent control operations as exposed by this + * implementation of the Processor module. + */ +int proc4430_control(void *handle, int cmd, void *arg) +{ + int retval = 0; + + /*FIXME: Remove handle,etc if not used */ + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_control failed " + "Module not initialized"); + return -ENODEV; + } + + return retval; +} + + +/*===================================================== + * Function to translate between two types of address spaces. + * + * Translate between the specified address spaces. + */ +int proc4430_translate_addr(void *handle, + void **dst_addr, enum proc_mgr_addr_type dst_addr_type, + void *src_addr, enum proc_mgr_addr_type src_addr_type) +{ + int retval = 0; + struct processor_object *proc_handle = NULL; + struct proc4430_object *object = NULL; + struct proc4430_mem_entry *entry = NULL; + bool found = false; + u32 fm_addr_base = (u32)NULL; + u32 to_addr_base = (u32)NULL; + u32 i; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_translate_addr failed " + "Module not initialized"); + retval = -ENODEV; + goto error_exit; + } + + if (WARN_ON(handle == NULL)) { + retval = -EINVAL; + goto error_exit; + } + if (WARN_ON(dst_addr == NULL)) { + retval = -EINVAL; + goto error_exit; + } + if (WARN_ON(dst_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE)) { + retval = -EINVAL; + goto error_exit; + } + if (WARN_ON(src_addr == NULL)) { + retval = -EINVAL; + goto error_exit; + } + if (WARN_ON(src_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE)) { + retval = -EINVAL; + goto error_exit; + } + + proc_handle = (struct processor_object *)handle; + object = (struct proc4430_object *)proc_handle->object; + *dst_addr = NULL; + for (i = 0 ; i < object->params.num_mem_entries ; i++) { + entry = &(object->params.mem_entries[i]); + fm_addr_base = + (src_addr_type == PROC_MGR_ADDRTYPE_MASTERKNLVIRT) ? + entry->master_virt_addr : entry->slave_virt_addr; + to_addr_base = + (dst_addr_type == PROC_MGR_ADDRTYPE_MASTERKNLVIRT) ? + entry->master_virt_addr : entry->slave_virt_addr; + /* Determine whether which way to convert */ + if (((u32)src_addr < (fm_addr_base + entry->size)) && + ((u32)src_addr >= fm_addr_base)) { + found = true; + *dst_addr = (void *)(((u32)src_addr - fm_addr_base) + + to_addr_base); + break; + } + } + + /* This check must not be removed even with build optimize. */ + if (WARN_ON(found == false)) { + /*Failed to translate address. */ + retval = -ENXIO; + goto error_exit; + } + return 0; + +error_exit: + return retval; +} + + +/*================================================= + * Function to map slave address to host address space + * + * Map the provided slave address to master address space. This + * function also maps the specified address to slave MMU space. + */ +int proc4430_map(void *handle, u32 proc_addr, + u32 size, u32 *mapped_addr, u32 *mapped_size, u32 map_attribs) +{ + int retval = 0; + u32 da_align; + u32 da; + u32 va_align; + u32 size_align; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_map failed " + "Module not initialized"); + retval = -ENODEV; + goto error_exit; + } + + /*FIXME: Remove handle,etc if not used */ + + /* FIX ME: Temporary work around until the dynamic memory mapping + * for Tiler address space is available + */ + if ((map_attribs & DSP_MAPTILERADDR)) { + da_align = user_va2pa(current->mm, proc_addr); + *mapped_addr = (da_align | (proc_addr & (PAGE_SIZE - 1))); + printk(KERN_INFO "proc4430_map -tiler: user_va2pa: mapped_addr" + "= 0x%x\n", *mapped_addr); + return 0; + } + + /* Calculate the page-aligned PA, VA and size */ + va_align = PG_ALIGN_LOW(proc_addr, PAGE_SIZE); + size_align = PG_ALIGN_HIGH(size + (u32)proc_addr - va_align, PAGE_SIZE); + + dmm_reserve_memory(size_align, &da); + da_align = PG_ALIGN_LOW((u32)da, PAGE_SIZE); + retval = ducati_mem_map(va_align, da_align, size_align, map_attribs); + + /* Mapped address = MSB of DA | LSB of VA */ + *mapped_addr = (da_align | (proc_addr & (PAGE_SIZE - 1))); + +error_exit: + return retval; +} + +/*================================================= + * Function to unmap slave address to host address space + * + * UnMap the provided slave address to master address space. This + * function also unmaps the specified address to slave MMU space. + */ +int proc4430_unmap(void *handle, u32 mapped_addr) +{ + int da_align; + int ret_val = 0; + int size_align; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_map failed " + "Module not initialized"); + ret_val = -1; + goto error_exit; + } + + /*FIXME: Remove handle,etc if not used */ + + da_align = PG_ALIGN_LOW((u32)mapped_addr, PAGE_SIZE); + ret_val = dmm_unreserve_memory(da_align, &size_align); + if (WARN_ON(ret_val < 0)) + goto error_exit; + ret_val = ducati_mem_unmap(da_align, size_align); + if (WARN_ON(ret_val < 0)) + goto error_exit; + return 0; + +error_exit: + printk(KERN_WARNING "proc4430_unmap failed !!!!\n"); + return ret_val; +} + +/*================================================= + * Function to return list of translated mem entries + * + * This function takes the remote processor address as + * an input and returns the mapped Page entries in the + * buffer passed + */ +int proc4430_virt_to_phys(void *handle, u32 da, u32 *mapped_entries, + u32 num_of_entries) +{ + int da_align; + int i; + int ret_val = 0; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_virt_to_phys failed " + "Module not initialized"); + ret_val = -EFAULT; + goto error_exit; + } + + if (handle == NULL || mapped_entries == NULL || num_of_entries == 0) { + ret_val = -EFAULT; + goto error_exit; + } + da_align = PG_ALIGN_LOW((u32)da, PAGE_SIZE); + for (i = 0; i < num_of_entries; i++) { + mapped_entries[i] = ducati_mem_virtToPhys(da_align); + da_align += PAGE_SIZE; + } + return 0; + +error_exit: + printk(KERN_WARNING "proc4430_virtToPhys failed !!!!\n"); + return ret_val; +} + + +/*================================================= + * Function to return PROC4430 mem_entries info + * + */ +int proc4430_proc_info(void *handle, struct proc_mgr_proc_info *procinfo) +{ + struct processor_object *proc_handle = NULL; + struct proc4430_object *object = NULL; + struct proc4430_mem_entry *entry = NULL; + int i; + + if (atomic_cmpmask_and_lt(&proc4430_state.ref_count, + OMAP4430PROC_MAKE_MAGICSTAMP(0), + OMAP4430PROC_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc4430_proc_info failed " + "Module not initialized"); + goto error_exit; + } + + if (WARN_ON(handle == NULL)) + goto error_exit; + if (WARN_ON(procinfo == NULL)) + goto error_exit; + + proc_handle = (struct processor_object *)handle; + + object = (struct proc4430_object *)proc_handle->object; + + for (i = 0 ; i < object->params.num_mem_entries ; i++) { + entry = &(object->params.mem_entries[i]); + procinfo->mem_entries[i].addr[PROC_MGR_ADDRTYPE_MASTERKNLVIRT] + = entry->master_virt_addr; + procinfo->mem_entries[i].addr[PROC_MGR_ADDRTYPE_SLAVEVIRT] + = entry->slave_virt_addr; + procinfo->mem_entries[i].size = entry->size; + } + procinfo->num_mem_entries = object->params.num_mem_entries; + procinfo->boot_mode = proc_handle->boot_mode; + return 0; + +error_exit: + printk(KERN_WARNING "proc4430_proc_info failed !!!!\n"); + return -EFAULT; +} diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430.h b/drivers/dsp/syslink/procmgr/proc4430/proc4430.h new file mode 100755 index 000000000000..5903daeadaa3 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430.h @@ -0,0 +1,147 @@ +/* + * proc4430.h + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + + +#ifndef _SYSLINK_PROC_4430_H_ +#define _SYSLINK_PROC_4430_H_ + + +/* Module headers */ +#include <procmgr.h> +#include "../procdefs.h" +#include <linux/types.h> + +/* + Module configuration structure. + */ +struct proc4430_config { + struct mutex *gate_handle; + /* void * of gate to be used for local thread safety */ +}; + +/* + Memory entry for slave memory map configuration + */ +struct proc4430_mem_entry { + char name[PROCMGR_MAX_STRLEN]; + /* Name identifying the memory region. */ + u32 phys_addr; + /* Physical address of the memory region. */ + u32 slave_virt_addr; + /* Slave virtual address of the memory region. */ + u32 master_virt_addr; + /* Master virtual address of the memory region. If specified as -1, + * the master virtual address is assumed to be invalid, and shall be + * set internally within the Processor module. */ + u32 size; + /* Size (in bytes) of the memory region. */ + bool shared; + /* Flag indicating whether the memory region is shared between master + * and slave. */ +}; + +/* + Configuration parameters specific to this processor. + */ +struct proc4430_params { + int num_mem_entries; + /* Number of memory regions to be configured. */ + struct proc4430_mem_entry *mem_entries; + /* Array of information structures for memory regions + * to be configured. */ + u32 reset_vector_mem_entry; + /* Index of the memory entry within the mem_entries array, + * which is the resetVector memory region. */ +}; + + +/* Function to initialize the slave processor */ +int proc4430_attach(void *handle, struct processor_attach_params *params); + +/* Function to finalize the slave processor */ +int proc4430_detach(void *handle); + +/* Function to start the slave processor */ +int proc4430_start(void *handle, u32 entry_pt, + struct processor_start_params *params); + +/* Function to start the stop processor */ +int proc4430_stop(void *handle, + struct processor_stop_params *params); + +/* Function to read from the slave processor's memory. */ +int proc4430_read(void *handle, u32 proc_addr, u32 *num_bytes, + void *buffer); + +/* Function to write into the slave processor's memory. */ +int proc4430_write(void *handle, u32 proc_addr, u32 *num_bytes, + void *buffer); + +/* Function to perform device-dependent operations. */ +int proc4430_control(void *handle, int cmd, void *arg); + +/* Function to translate between two types of address spaces. */ +int proc4430_translate_addr(void *handle, void **dst_addr, + enum proc_mgr_addr_type dst_addr_type, + void *src_addr, enum proc_mgr_addr_type src_addr_type); + +/* Function to map slave address to host address space */ +int proc4430_map(void *handle, u32 proc_addr, u32 size, u32 *mapped_addr, + u32 *mapped_size, u32 map_attribs); + +/* Function to unmap the slave address to host address space */ +int proc4430_unmap(void *handle, u32 mapped_addr); + +/* Function to retrive physical address translations */ +int proc4430_virt_to_phys(void *handle, u32 da, u32 *mapped_entries, + u32 num_of_entries); + +/* ================================================= + * APIs + * ================================================= + */ + +/* Function to get the default configuration for the OMAP4430PROC module */ +void proc4430_get_config(struct proc4430_config *cfg); + +/* Function to setup the OMAP4430PROC module. */ +int proc4430_setup(struct proc4430_config *cfg); + +/* Function to destroy the OMAP4430PROC module. */ +int proc4430_destroy(void); + +/* Function to initialize the parameters for this processor instance. */ +void proc4430_params_init(void *handle, + struct proc4430_params *params); + +/* Function to create an instance of this processor. */ +void *proc4430_create(u16 proc_id, const struct proc4430_params *params); + +/* Function to delete an instance of this processor. */ +int proc4430_delete(void **handle_ptr); + +/* Function to open an instance of this processor. */ +int proc4430_open(void **handle_ptr, u16 proc_id); + +/* Function to close an instance of this processor. */ +int proc4430_close(void *handle); + +/* Function to get the proc info */ +int proc4430_proc_info(void *handle, struct proc_mgr_proc_info *procinfo); + +#endif diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c new file mode 100755 index 000000000000..92fc35b9e684 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c @@ -0,0 +1,400 @@ +/* + * proc4430_drv.c + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/autoconf.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> + + +/* Module headers */ +#include "proc4430.h" +#include "proc4430_drvdefs.h" + + + +/** ============================================================================ + * Macros and types + * ============================================================================ + */ +#define PROC4430_NAME "syslink-proc4430" + +static char *driver_name = PROC4430_NAME; + +static s32 driver_major; + +static s32 driver_minor; + +struct proc_4430_dev { + struct cdev cdev; +}; + +static struct proc_4430_dev *proc_4430_device; + +static struct class *proc_4430_class; + + + +/** ============================================================================ + * Forward declarations of internal functions + * ============================================================================ + */ +/* Linux driver function to open the driver object. */ +static int proc4430_drv_open(struct inode *inode, struct file *filp); + +/* Linux driver function to close the driver object. */ +static int proc4430_drv_release(struct inode *inode, struct file *filp); + +/* Linux driver function to invoke the APIs through ioctl. */ +static int proc4430_drv_ioctl(struct inode *inode, + struct file *filp, unsigned int cmd, + unsigned long args); + +/* Linux driver function to map memory regions to user space. */ +static int proc4430_drv_mmap(struct file *filp, + struct vm_area_struct *vma); + +/* Module initialization function for Linux driver. */ +static int __init proc4430_drv_initializeModule(void); + +/* Module finalization function for Linux driver. */ +static void __exit proc4430_drv_finalizeModule(void); + + + +/** ============================================================================ + * Globals + * ============================================================================ + */ + +/* + File operations table for PROC4430. + */ +static const struct file_operations proc_4430_fops = { + .open = proc4430_drv_open, + .release = proc4430_drv_release, + .ioctl = proc4430_drv_ioctl, + .mmap = proc4430_drv_mmap, +}; + +static int proc4430_drv_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int proc4430_drv_release(struct inode *inode, struct file *filp) +{ + return 0; +} + + +/* + Linux driver function to invoke the APIs through ioctl. + * + */ +static int proc4430_drv_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long args) +{ + int retval = 0; + struct proc_mgr_cmd_args *cmd_args = (struct proc_mgr_cmd_args *)args; + struct proc_mgr_cmd_args command_args; + + switch (cmd) { + case CMD_PROC4430_GETCONFIG: + { + struct proc4430_cmd_args_get_config *src_args = + (struct proc4430_cmd_args_get_config *)args; + struct proc4430_config cfg; + + /* copy_from_useris not needed for + * proc4430_get_config, since the + * user's config is not used. + */ + proc4430_get_config(&cfg); + + retval = copy_to_user((void *)(src_args->cfg), + (const void *)&cfg, + sizeof(struct proc4430_config)); + if (WARN_ON(retval < 0)) + goto func_exit; + } + break; + + case CMD_PROC4430_SETUP: + { + struct proc4430_cmd_args_setup *src_args = + (struct proc4430_cmd_args_setup *)args; + struct proc4430_config cfg; + + retval = copy_from_user((void *)&cfg, + (const void *)(src_args->cfg), + sizeof(struct proc4430_config)); + if (WARN_ON(retval < 0)) + goto func_exit; + proc4430_setup(&cfg); + } + break; + + case CMD_PROC4430_DESTROY: + { + proc4430_destroy(); + } + break; + + case CMD_PROC4430_PARAMS_INIT: + { + struct proc4430_cmd_args_params_init src_args; + struct proc4430_params params; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc4430_cmd_args_params_init)); + if (WARN_ON(retval < 0)) + goto func_exit; + proc4430_params_init(src_args.handle, ¶ms); + retval = copy_to_user((void *)(src_args.params), + (const void *) ¶ms, + sizeof(struct proc4430_params)); + if (WARN_ON(retval < 0)) + goto func_exit; + } + break; + + case CMD_PROC4430_CREATE: + { + struct proc4430_cmd_args_create src_args; + struct proc4430_params params; + struct proc4430_mem_entry *entries = NULL; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc4430_cmd_args_create)); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_from_user((void *) ¶ms, + (const void *)(src_args.params), + sizeof(struct proc4430_params)); + if (WARN_ON(retval < 0)) + goto func_exit; + /* Copy the contents of mem_entries from user-side */ + if (params.num_mem_entries) { + entries = vmalloc(params.num_mem_entries * \ + sizeof(struct proc4430_mem_entry)); + if (WARN_ON(!entries)) + goto func_exit; + retval = copy_from_user((void *) (entries), + (const void *)(params.mem_entries), + params.num_mem_entries * \ + sizeof(struct proc4430_mem_entry)); + if (WARN_ON(retval < 0)) { + vfree(entries); + goto func_exit; + } + params.mem_entries = entries; + } + src_args.handle = proc4430_create(src_args.proc_id, + ¶ms); + if (WARN_ON(src_args.handle == NULL)) + goto func_exit; + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc4430_cmd_args_create)); + /* Free the memory created */ + if (params.num_mem_entries) + vfree(entries); + } + break; + + case CMD_PROC4430_DELETE: + { + struct proc4430_cmd_args_delete src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc4430_cmd_args_delete)); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = proc4430_delete(&(src_args.handle)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROC4430_OPEN: + { + struct proc4430_cmd_args_open src_args; + + /*Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc4430_cmd_args_open)); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = proc4430_open(&(src_args.handle), + src_args.proc_id); + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc4430_cmd_args_open)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROC4430_CLOSE: + { + struct proc4430_cmd_args_close src_args; + + /*Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc4430_cmd_args_close)); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = proc4430_close(src_args.handle); + WARN_ON(retval < 0); + } + break; + + default: + { + printk(KERN_ERR "unsupported ioctl\n"); + } + break; + } +func_exit: + /* Set the status and copy the common args to user-side. */ + command_args.api_status = retval; + retval = copy_to_user((void *) cmd_args, + (const void *) &command_args, + sizeof(struct proc_mgr_cmd_args)); + WARN_ON(retval < 0); + return retval; +} + + +/* + Linux driver function to map memory regions to user space. + * + */ +static int proc4430_drv_mmap(struct file *filp, struct vm_area_struct *vma) +{ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_pfn_range(vma, + vma->vm_start, + vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + return -EAGAIN; + } + return 0; +} + + +/** ================================================================== + * Functions required for multiple .ko modules configuration + * ================================================================== + */ +/* + Module initialization function for Linux driver. + */ +static int __init proc4430_drv_initializeModule(void) +{ + dev_t dev = 0 ; + int retval; + + /* Display the version info and created date/time */ + printk(KERN_INFO "proc4430_drv_initializeModule\n"); + + if (driver_major) { + dev = MKDEV(driver_major, driver_minor); + retval = register_chrdev_region(dev, 1, driver_name); + } else { + retval = alloc_chrdev_region(&dev, driver_minor, 1, + driver_name); + driver_major = MAJOR(dev); + } + + proc_4430_device = kmalloc(sizeof(struct proc_4430_dev), GFP_KERNEL); + if (!proc_4430_device) { + retval = -ENOMEM; + unregister_chrdev_region(dev, 1); + goto exit; + } + memset(proc_4430_device, 0, sizeof(struct proc_4430_dev)); + cdev_init(&proc_4430_device->cdev, &proc_4430_fops); + proc_4430_device->cdev.owner = THIS_MODULE; + proc_4430_device->cdev.ops = &proc_4430_fops; + + retval = cdev_add(&proc_4430_device->cdev, dev, 1); + + if (retval) { + printk(KERN_ERR "Failed to add the syslink proc_4430 device \n"); + goto exit; + } + + /* udev support */ + proc_4430_class = class_create(THIS_MODULE, "syslink-proc4430"); + + if (IS_ERR(proc_4430_class)) { + printk(KERN_ERR "Error creating bridge class \n"); + goto exit; + } + device_create(proc_4430_class, NULL, MKDEV(driver_major, driver_minor), + NULL, PROC4430_NAME); +exit: + return 0; +} + +/* + function to finalize the driver module. + */ +static void __exit proc4430_drv_finalizeModule(void) +{ + dev_t devno = 0; + + /* FIX ME: THIS MIGHT NOT BE THE RIGHT PLACE TO CALL THE SETUP */ + proc4430_destroy(); + + devno = MKDEV(driver_major, driver_minor); + if (proc_4430_device) { + cdev_del(&proc_4430_device->cdev); + kfree(proc_4430_device); + } + unregister_chrdev_region(devno, 1); + if (proc_4430_class) { + /* remove the device from sysfs */ + device_destroy(proc_4430_class, MKDEV(driver_major, + driver_minor)); + class_destroy(proc_4430_class); + } + return; +} + +/* + Macro calls that indicate initialization and finalization functions + * to the kernel. + */ +MODULE_LICENSE("GPL v2"); +module_init(proc4430_drv_initializeModule); +module_exit(proc4430_drv_finalizeModule); diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h new file mode 100755 index 000000000000..4176d731f1d4 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h @@ -0,0 +1,169 @@ +/* + * proc4430_drvdefs.h + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#ifndef _SYSLINK_PROC4430_H +#define _SYSLINK_PROC4430_H + + +/* Module headers */ +#include "../procmgr_drvdefs.h" +#include "proc4430.h" + + +/* ---------------------------------------------------------------------------- + * IOCTL command IDs for OMAP4430PROC + * ---------------------------------------------------------------------------- + */ +/* + * Base command ID for OMAP4430PROC + */ +#define PROC4430_BASE_CMD 0x200 + +/* + * Command for PROC4430_getConfig + */ +#define CMD_PROC4430_GETCONFIG (PROC4430_BASE_CMD + 1) + +/* + * Command for PROC4430_setup + */ +#define CMD_PROC4430_SETUP (PROC4430_BASE_CMD + 2) + +/* + * Command for PROC4430_setup + */ +#define CMD_PROC4430_DESTROY (PROC4430_BASE_CMD + 3) + +/* + * Command for PROC4430_destroy + */ +#define CMD_PROC4430_PARAMS_INIT (PROC4430_BASE_CMD + 4) + +/* + * Command for PROC4430_create + */ +#define CMD_PROC4430_CREATE (PROC4430_BASE_CMD + 5) + +/* + * Command for PROC4430_delete + */ +#define CMD_PROC4430_DELETE (PROC4430_BASE_CMD + 6) + +/* + * Command for PROC4430_open + */ +#define CMD_PROC4430_OPEN (PROC4430_BASE_CMD + 7) + +/* + * Command for PROC4430_close + */ +#define CMD_PROC4430_CLOSE (PROC4430_BASE_CMD + 8) + + +/* --------------------------------------------------- + * Command arguments for OMAP4430PROC + * --------------------------------------------------- + */ +/* + * Command arguments for PROC4430_getConfig + */ +struct proc4430_cmd_args_get_config { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + struct proc4430_config *cfg; + /* Pointer to the OMAP4430PROC module configuration structure + * in which the default config is to be returned. */ +}; + +/* + * Command arguments for PROC4430_setup + */ +struct proc4430_cmd_args_setup { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + struct proc4430_config *cfg; + /* Optional OMAP4430PROC module configuration. If provided as NULL, + * default configuration is used. */ +}; + +/* + * Command arguments for PROC4430_destroy + */ +struct proc4430_cmd_args_destroy { + struct proc_mgr_cmd_args command_args; + /* Common command args */ +}; + +/* + * Command arguments for struct struct proc4430_params_init + */ +struct proc4430_cmd_args_params_init { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + void *handle; + /* void * to the processor instance. */ + struct proc4430_params *params; + /* Configuration parameters. */ +}; + +/* + * Command arguments for PROC4430_create + */ +struct proc4430_cmd_args_create { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + u16 proc_id; + /* Processor ID for which this processor instance is required. */ + struct proc4430_params *params; + /*Configuration parameters. */ + void *handle; + /* void * to the created processor instance. */ +}; + +/* + * Command arguments for PROC4430_delete + */ +struct proc4430_cmd_args_delete { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + void *handle; + /* Pointer to handle to the processor instance */ +}; + +/* + * Command arguments for PROC4430_open + */ +struct proc4430_cmd_args_open { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + u16 proc_id; + /* Processor ID addressed by this OMAP4430PROC instance. */ + void *handle; + /* Return parameter: void * to the processor instance */ +}; + +/* + * Command arguments for PROC4430_close + */ +struct proc4430_cmd_args_close { + struct proc_mgr_cmd_args command_args; + /* Common command args */ + void *handle; + /* void * to the processor instance */ +}; + +#endif diff --git a/drivers/dsp/syslink/procmgr/procdefs.h b/drivers/dsp/syslink/procmgr/procdefs.h new file mode 100755 index 000000000000..eb73626d27e1 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/procdefs.h @@ -0,0 +1,203 @@ +/* + * procdefs.h + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef SYSLINK_PROCDEFS_H +#define SYSLINK_PROCDEFS_H + +#include <linux/types.h> + +/* Module level headers */ +#include <procmgr.h> + + +/* ============================= + * Macros and types + * ============================= + */ +/* + * Enumerates the types of Endianism of slave processor. + */ +enum processor_endian{ + PROCESSOR_ENDIAN_DEFAULT = 0, + /* Default endianism (no conversion required) */ + PROCESSOR_ENDIAN_BIG = 1, + /* Big endian */ + PROCESSOR_ENDIAN_LITTLE = 2, + /* Little endian */ + PROCESSOR_ENDIAN_ENDVALUE = 3 + /* End delimiter indicating start of invalid values for this enum */ +}; + + +/* + * Configuration parameters for attaching to the slave Processor + */ +struct processor_attach_params { + struct proc_mgr_attach_params *params; + /* Common attach parameters for ProcMgr */ + u16 num_mem_entries; + /* Number of valid memory entries */ + struct proc_mgr_addr_info mem_entries[PROCMGR_MAX_MEMORY_REGIONS]; + /* Configuration of memory regions */ +}; + +/* + *Configuration parameters for starting the slave Processor + */ +struct processor_start_params { + struct proc_mgr_start_params *params; + /* Common start parameters for ProcMgr */ +}; + +/* + *Configuration parameters for stopping the slave Processor + */ +struct processor_stop_params { + struct proc_mgr_stop_params *params; + /* Common start parameters for ProcMgr */ +}; +/* + * Function pointer type for the function to attach to the processor. + */ +typedef int (*processor_attach_fxn) (void *handle, + struct processor_attach_params *params); + +/* + * Function pointer type for the function to detach from the + * procssor + */ +typedef int (*processor_detach_fxn) (void *handle); + +/* + * Function pointer type for the function to start the processor. + */ +typedef int (*processor_start_fxn) (void *handle, u32 entry_pt, + struct processor_start_params *params); + +/* + *Function pointer type for the function to stop the processor. + */ +typedef int (*processor_stop_fxn) (void *handle, + struct processor_stop_params *params); + +/* + * Function pointer type for the function to read from the slave + * processor's memory. + */ +typedef int (*processor_read_fxn) (void *handle, u32 proc_addr, + u32 *num_bytes, void *buffer); + +/* + *Function pointer type for the function to write into the slave + *processor's memory. + */ +typedef int (*processor_write_fxn) (void *handle, u32 proc_addr, + u32 *num_bytes, void *buffer); + +/* + *Function pointer type for the function to perform device-dependent + * operations. + */ +typedef int (*processor_control_fxn) (void *handle, int cmd, void *arg); + +/* + *Function pointer type for the function to translate between + * two types of address spaces. + */ +typedef int (*processor_translate_addr_fxn) (void *handle, void **dst_addr, + enum proc_mgr_addr_type dstAddrType, void *srcAddr, + enum proc_mgr_addr_type srcAddrType); + +/* + *Function pointer type for the function to map address to slave + * address space + */ +typedef int (*processor_map_fxn) (void *handle, u32 proc_addr, u32 size, + u32 *mapped_addr, u32 *mapped_size, u32 map_attribs); + +/* + *Function pointer type for the function to map address to slave + * address space + */ +typedef int (*processor_unmap_fxn) (void *handle, u32 mapped_addr); + +/* + *Function pointer type for the function that returns proc info + */ +typedef int (*processor_proc_info) (void *handle, + struct proc_mgr_proc_info *proc_info); + +/* + *Function pointer type for the function that returns proc info + */ +typedef int (*processor_virt_to_phys_fxn) (void *handle, u32 da, + u32 *mapped_entries, u32 num_of_entries); + + +/* ============================= + * Function table interface + * ============================= + */ +/* + *Function table interface for Processor. + */ +struct processor_fxn_table { + processor_attach_fxn attach; + /* Function to attach to the slave processor */ + processor_detach_fxn detach; + /* Function to detach from the slave processor */ + processor_start_fxn start; + /* Function to start the slave processor */ + processor_stop_fxn stop; + /* Function to stop the slave processor */ + processor_read_fxn read; + /* Function to read from the slave processor's memory */ + processor_write_fxn write; + /* Function to write into the slave processor's memory */ + processor_control_fxn control; + /* Function to perform device-dependent control function */ + processor_translate_addr_fxn translateAddr; + /* Function to translate between address ranges */ + processor_map_fxn map; + /* Function to map slave addresses to master address space */ + processor_unmap_fxn unmap; + /* Function to unmap slave addresses to master address space */ + processor_proc_info procinfo; + /* Function to convert Virtual to Physical pages */ + processor_virt_to_phys_fxn virt_to_phys; +}; + +/* ============================= + * Processor structure + * ============================= + */ +/* + * Generic Processor object. This object defines the handle type for all + * Processor operations. + */ +struct processor_object { + struct processor_fxn_table proc_fxn_table; + /* interface function table to plug into the generic Processor. */ + enum proc_mgr_state state; + /* State of the slave processor */ + enum proc_mgr_boot_mode boot_mode; + /* Boot mode for the slave processor. */ + void *object; + /* Pointer to Processor-specific object. */ + u16 proc_id; + /* Processor ID addressed by this Processor instance. */ +}; +#endif diff --git a/drivers/dsp/syslink/procmgr/processor.c b/drivers/dsp/syslink/procmgr/processor.c new file mode 100755 index 000000000000..4548d12ad967 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/processor.c @@ -0,0 +1,398 @@ +/* + * processor.c + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/types.h> +#include <linux/module.h> + +/* Module level headers */ +#include "procdefs.h" +#include "processor.h" + + + +/* ========================================= + * Functions called by ProcMgr + * ========================================= + */ +/* + * Function to attach to the Processor. + * + * This function calls into the specific Processor implementation + * to attach to it. + * This function is called from the ProcMgr attach function, and + * hence is used to perform any activities that may be required + * once the slave is powered up. + * Depending on the type of Processor, this function may or may not + * perform any activities. + */ +inline int processor_attach(void *handle, + struct processor_attach_params *params) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(params == NULL); + BUG_ON(proc_handle->proc_fxn_table.attach == NULL); + + proc_handle->boot_mode = params->params->boot_mode; + retval = proc_handle->proc_fxn_table.attach(handle, params); + + if (proc_handle->boot_mode == PROC_MGR_BOOTMODE_BOOT) + proc_handle->state = PROC_MGR_STATE_POWERED; + else if (proc_handle->boot_mode == PROC_MGR_BOOTMODE_NOLOAD) + proc_handle->state = PROC_MGR_STATE_LOADED; + else if (proc_handle->boot_mode == PROC_MGR_BOOTMODE_NOBOOT) + proc_handle->state = PROC_MGR_STATE_RUNNNING; + return retval; +} + + +/* + * Function to detach from the Processor. + * + * This function calls into the specific Processor implementation + * to detach from it. + * This function is called from the ProcMgr detach function, and + * hence is useful to perform any activities that may be required + * before the slave is powered down. + * Depending on the type of Processor, this function may or may not + * perform any activities. + */ +inline int processor_detach(void *handle) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(proc_handle->proc_fxn_table.detach == NULL); + + retval = proc_handle->proc_fxn_table.detach(handle); + /* For all boot modes, at the end of detach, the Processor is in + * unknown state. + */ + proc_handle->state = PROC_MGR_STATE_UNKNOWN; + return retval; +} + + +/* + * Function to start the processor. + * + * This function calls into the specific Processor implementation + * to start the slave processor running. + * This function starts the slave processor running, in most + * devices, by programming its entry point into the boot location + * of the slave processor and releasing it from reset. + * The handle specifies the specific Processor instance to be used. + * + * @param handle void * to the Processor object + * @param entryPt Entry point of the file loaded on the slave Processor + * + * @sa Processor_stop + */ +inline int processor_start(void *handle, u32 entry_pt, + struct processor_start_params *params) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + /* entryPt may be 0 for some devices. Cannot check for valid/invalid. */ + BUG_ON(params == NULL); + BUG_ON(proc_handle->proc_fxn_table.start == NULL); + retval = proc_handle->proc_fxn_table.start(handle, entry_pt, params); + + if ((proc_handle->boot_mode == PROC_MGR_BOOTMODE_BOOT) + || (proc_handle->boot_mode == PROC_MGR_BOOTMODE_NOLOAD)) + proc_handle->state = PROC_MGR_STATE_RUNNNING; + + return retval; +} + + +/* + * Function to stop the processor. + * + * This function calls into the specific Processor implementation + * to stop the slave processor. + * This function stops the slave processor running, in most + * devices, by placing it in reset. + * The handle specifies the specific Processor instance to be used. + */ +inline int processor_stop(void *handle, + struct processor_stop_params *params) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(proc_handle->proc_fxn_table.stop == NULL); + + retval = proc_handle->proc_fxn_table.stop(handle, params); + + if ((proc_handle->boot_mode == PROC_MGR_BOOTMODE_BOOT) + || (proc_handle->boot_mode == PROC_MGR_BOOTMODE_NOLOAD)) + proc_handle->state = PROC_MGR_STATE_RESET; + + return retval; +} + + +/* + * Function to read from the slave processor's memory. + * + * This function calls into the specific Processor implementation + * to read from the slave processor's memory. It reads from the + * specified address in the processor's address space and copies + * the required number of bytes into the specified buffer. + * It returns the number of bytes actually read in the num_bytes + * parameter. + * Depending on the processor implementation, it may result in + * reading from shared memory or across a peripheral physical + * connectivity. + * The handle specifies the specific Processor instance to be used. + */ +inline int processor_read(void *handle, u32 proc_addr, + u32 *num_bytes, void *buffer) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(proc_addr == 0); + BUG_ON(num_bytes == 0); + BUG_ON(buffer == NULL); + BUG_ON(proc_handle->proc_fxn_table.read == NULL); + + retval = proc_handle->proc_fxn_table.read(handle, proc_addr, + num_bytes, buffer); + return retval; +} + + +/* + * Function to write into the slave processor's memory. + * + * This function calls into the specific Processor implementation + * to write into the slave processor's memory. It writes into the + * specified address in the processor's address space and copies + * the required number of bytes from the specified buffer. + * It returns the number of bytes actually written in the num_bytes + * parameter. + * Depending on the processor implementation, it may result in + * writing into shared memory or across a peripheral physical + * connectivity. + * The handle specifies the specific Processor instance to be used. + */ +inline int processor_write(void *handle, u32 proc_addr, u32 *num_bytes, + void *buffer) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + BUG_ON(handle == NULL); + BUG_ON(proc_addr == 0); + BUG_ON(num_bytes == 0); + BUG_ON(buffer == NULL); + BUG_ON(proc_handle->proc_fxn_table.write == NULL); + + retval = proc_handle->proc_fxn_table.write(handle, proc_addr, + num_bytes, buffer); + return retval; +} + + +/* + * Function to get the current state of the slave Processor. + * + * This function gets the state of the slave processor as + * maintained on the master Processor state machine. It does not + * go to the slave processor to get its actual state at the time + * when this API is called. + */ +enum proc_mgr_state processor_get_state(void *handle) +{ + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + + return proc_handle->state; +} + + +/* + * Function to set the current state of the slave Processor + * to specified value. + * + * This function is used to set the state of the processor to the + * value as specified. This function may be used by external + * entities that affect the state of the slave processor, such as + * PwrMgr, error handler, or ProcMgr. + */ +void processor_set_state(void *handle, enum proc_mgr_state state) +{ + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + proc_handle->state = state; +} + + +/* + * Function to perform device-dependent operations. + * + * This function calls into the specific Processor implementation + * to perform device dependent control operations. The control + * operations supported by the device are exposed directly by the + * specific implementation of the Processor interface. These + * commands and their specific argument types are used with this + * function. + */ +inline int processor_control(void *handle, int cmd, void *arg) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(proc_handle->proc_fxn_table.control == NULL); + + retval = proc_handle->proc_fxn_table.control(handle, cmd, arg); + return retval; +} + + +/* + * Function to translate between two types of address spaces. + * + * This function translates addresses between two types of address + * spaces. The destination and source address types are indicated + * through parameters specified in this function. + */ +inline int processor_translate_addr(void *handle, void **dst_addr, + enum proc_mgr_addr_type dst_addr_type, void *src_addr, + enum proc_mgr_addr_type src_addr_type) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(dst_addr == NULL); + BUG_ON(src_addr == NULL); + BUG_ON(dst_addr_type >= PROC_MGR_ADDRTYPE_ENDVALUE); + BUG_ON(src_addr_type >= PROC_MGR_ADDRTYPE_ENDVALUE); + BUG_ON(proc_handle->proc_fxn_table.translateAddr == NULL); + + retval = proc_handle->proc_fxn_table.translateAddr(handle, + dst_addr, dst_addr_type, src_addr, src_addr_type); + return retval; +} + + +/* + * Function to map address to slave address space. + * + * This function maps the provided slave address to a host address + * and returns the mapped address and size. + */ +inline int processor_map(void *handle, u32 proc_addr, u32 size, + u32 *mapped_addr, u32 *mapped_size, u32 map_attribs) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + BUG_ON(handle == NULL); + BUG_ON(proc_addr == 0); + BUG_ON(size == 0); + BUG_ON(mapped_addr == NULL); + BUG_ON(mapped_size == NULL); + BUG_ON(proc_handle->proc_fxn_table.map == NULL); + + retval = proc_handle->proc_fxn_table.map(handle, proc_addr, + size, mapped_addr, mapped_size, map_attribs); + return retval; +} + +/* + * Function to unmap address to slave address space. + * + * This function unmap the provided slave address + */ +inline int processor_unmap(void *handle, u32 mapped_addr) +{ + int retval = 0; + struct processor_object *proc_handle = + (struct processor_object *)handle; + + retval = proc_handle->proc_fxn_table.unmap(handle, mapped_addr); + return retval; +} + +/* + * Function that registers for notification when the slave + * processor transitions to any of the states specified. + * + * This function allows the user application to register for + * changes in processor state and take actions accordingly. + + */ +inline int processor_register_notify(void *handle, proc_mgr_callback_fxn fxn, + void *args, enum proc_mgr_state state[]) +{ + int retval = 0; + + BUG_ON(handle == NULL); + BUG_ON(fxn == NULL); + + /* TODO: TBD: To be implemented. */ + return retval; +} + +/* + * Function that returns the proc instance mem info + */ +int processor_get_proc_info(void *handle, struct proc_mgr_proc_info *procinfo) +{ + struct processor_object *proc_handle = + (struct processor_object *)handle; + int retval; + retval = proc_handle->proc_fxn_table.procinfo(proc_handle, procinfo); + return retval; +} + +/* + * Function that returns the address translations + */ +int processor_virt_to_phys(void *handle, u32 da, u32 *mapped_entries, + u32 num_of_entries) +{ + struct processor_object *proc_handle = + (struct processor_object *)handle; + int retval; + retval = proc_handle->proc_fxn_table.virt_to_phys(handle, da, + mapped_entries, num_of_entries); + return retval; +} diff --git a/drivers/dsp/syslink/procmgr/processor.h b/drivers/dsp/syslink/procmgr/processor.h new file mode 100755 index 000000000000..b4f78581839e --- /dev/null +++ b/drivers/dsp/syslink/procmgr/processor.h @@ -0,0 +1,84 @@ +/* + * processor.h + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef SYSLINK_PROCESSOR_H_ +#define SYSLINK_PROCESSOR_H_ + +#include <linux/types.h> + +/* Module level headers */ +#include "procdefs.h" + +/* =================================== + * APIs + * =================================== + */ +/* Function to attach to the Processor. */ +int processor_attach(void *handle, struct processor_attach_params *params); + +/* Function to detach from the Processor. */ +int processor_detach(void *handle); + +/* Function to start the processor. */ +int processor_start(void *handle, u32 entry_pt, + struct processor_start_params *params); + +/* Function to stop the processor. */ +int processor_stop(void *handle, + struct processor_stop_params *params); + +/* Function to read from the slave processor's memory. */ +int processor_read(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer); + +/* Function to read write into the slave processor's memory. */ +int processor_write(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer); + +/* Function to get the current state of the slave Processor as maintained on + * the master Processor state machine. + */ +enum proc_mgr_state processor_get_state(void *handle); + +/* Function to set the current state of the slave Processor to specified value. + */ +void processor_set_state(void *handle, enum proc_mgr_state state); + +/* Function to perform device-dependent operations. */ +int processor_control(void *handle, int cmd, void *arg); + +/* Function to translate between two types of address spaces. */ +int processor_translate_addr(void *handle, void **dst_addr, + enum proc_mgr_addr_type dst_addr_type, void *src_addr, + enum proc_mgr_addr_type src_addr_type); + +/* Function to map address to slave address space */ +int processor_map(void *handle, u32 proc_addr, u32 size, u32 *mapped_addr, + u32 *mapped_size, u32 map_attribs); +/* Function to unmap address to slave address space */ +int processor_unmap(void *handle, u32 mapped_addr); + +/* Function that registers for notification when the slave processor + * transitions to any of the states specified. + */ +int processor_register_notify(void *handle, proc_mgr_callback_fxn fxn, + void *args, enum proc_mgr_state state[]); + +/* Function that returns the return value of specific processor info + */ +int processor_get_proc_info(void *handle, struct proc_mgr_proc_info *procinfo); + +int processor_virt_to_phys(void *handle, u32 da, u32 *mapped_entries, + u32 num_of_entries); +#endif diff --git a/drivers/dsp/syslink/procmgr/procmgr.c b/drivers/dsp/syslink/procmgr/procmgr.c new file mode 100755 index 000000000000..a7124c5b9028 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/procmgr.c @@ -0,0 +1,957 @@ +/* + * procmgr.c + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/vmalloc.h> +#include <asm/atomic.h> + +/* Module level headers */ +#include <procmgr.h> +#include "procdefs.h" +#include "processor.h" +#include <syslink/atomic_linux.h> + +/* ================================ + * Macros and types + * ================================ + */ +/*! @brief Macro to make a correct module magic number with refCount */ +#define PROCMGR_MAKE_MAGICSTAMP(x) ((PROCMGR_MODULEID << 12u) | (x)) + +/* + * ProcMgr Module state object + */ +struct proc_mgr_module_object { + atomic_t ref_count; + u32 config_size; + /* Size of configuration structure */ + struct proc_mgr_config cfg; + /* ProcMgr configuration structure */ + struct proc_mgr_config def_cfg; + /* Default module configuration */ + struct proc_mgr_params def_inst_params; + /* Default parameters for the ProcMgr instances */ + struct proc_mgr_attach_params def_attach_params; + /* Default parameters for the ProcMgr attach function */ + struct proc_mgr_start_params def_start_params; + /* Default parameters for the ProcMgr start function */ + struct proc_mgr_stop_params def_stop_params; + /* Default parameters for the ProcMgr stop function */ + struct mutex *gate_handle; + /* handle of gate to be used for local thread safety */ + void *proc_handles[MULTIPROC_MAXPROCESSORS]; + /* Array of handles of ProcMgr instances */ +}; + +/* + * ProcMgr instance object + */ +struct proc_mgr_object { + u16 proc_id; + /* Processor ID associated with this ProcMgr. */ + struct processor_object *proc_handle; + /* Processor ID of the processor being represented by this instance. */ + void *loader_handle; + /*!< Handle to the Loader object associated with this ProcMgr. */ + void *pwr_handle; + /*!< Handle to the PwrMgr object associated with this ProcMgr. */ + /*!< Processor ID of the processor being represented by this instance */ + struct proc_mgr_params params; + /* ProcMgr instance params structure */ + struct proc_mgr_attach_params attach_params; + /* ProcMgr attach params structure */ + struct proc_mgr_start_params start_params; + /* ProcMgr start params structure */ + struct proc_mgr_stop_params stop_params; + /* ProcMgr start params structure */ + u32 file_id; + /*!< File ID of the loaded static executable */ + u16 num_mem_entries; + /* Number of valid memory entries */ + struct proc_mgr_addr_info mem_entries[PROCMGR_MAX_MEMORY_REGIONS]; + /* Configuration of memory regions */ +}; + +struct proc_mgr_module_object proc_mgr_obj_state = { + .config_size = sizeof(struct proc_mgr_config), + .def_cfg.gate_handle = NULL, + .gate_handle = NULL, + .def_inst_params.proc_handle = NULL, + .def_attach_params.boot_mode = PROC_MGR_BOOTMODE_BOOT, + .def_start_params.proc_id = 0 +}; + + +/*====================================== + * Function to get the default configuration for the ProcMgr + * module. + * +* This function can be called by the application to get their +* configuration parameter to ProcMgr_setup filled in by the +* ProcMgr module with the default parameters. If the user does +* not wish to make any change in the default parameters, this API +* is not required to be called. + */ +void proc_mgr_get_config(struct proc_mgr_config *cfg) +{ + BUG_ON(cfg == NULL); + memcpy(cfg, &proc_mgr_obj_state.def_cfg, + sizeof(struct proc_mgr_config)); + return; +} +EXPORT_SYMBOL(proc_mgr_get_config); + +/* + * Function to setup the ProcMgr module. + * + *This function sets up the ProcMgr module. This function must + *be called before any other instance-level APIs can be invoked. + *Module-level configuration needs to be provided to this + *function. If the user wishes to change some specific config + *parameters, then ProcMgr_getConfig can be called to get the + *configuration filled with the default values. After this, only + *the required configuration values can be changed. If the user + *does not wish to make any change in the default parameters, the + *application can simply call ProcMgr_setup with NULL parameters. + *The default parameters would get automatically used. + */ +int proc_mgr_setup(struct proc_mgr_config *cfg) +{ + int retval = 0; + struct proc_mgr_config tmp_cfg; + + /* This sets the refCount variable is not initialized, upper 16 bits is + * written with module Id to ensure correctness of refCount variable. + */ + atomic_cmpmask_and_set(&proc_mgr_obj_state.ref_count, + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(0)); + + if (atomic_inc_return(&proc_mgr_obj_state.ref_count) + != PROCMGR_MAKE_MAGICSTAMP(1u)) + return 0; + if (cfg == NULL) { + proc_mgr_get_config(&tmp_cfg); + cfg = &tmp_cfg; + } + if (cfg->gate_handle != NULL) { + proc_mgr_obj_state.gate_handle = cfg->gate_handle; + } else { + /* User has not provided any gate handle, so create a + *default handle. + */ + proc_mgr_obj_state.gate_handle = kmalloc(sizeof(struct mutex), + GFP_KERNEL); + mutex_init(proc_mgr_obj_state.gate_handle); + } + memcpy(&proc_mgr_obj_state.cfg, cfg, sizeof(struct proc_mgr_config)); + /* Initialize the procHandles array. */ + memset(&proc_mgr_obj_state.proc_handles, 0, + (sizeof(void *) * MULTIPROC_MAXPROCESSORS)); + return retval; +} +EXPORT_SYMBOL(proc_mgr_setup); + +/*================================== + * Function to destroy the ProcMgr module. + * + * Once this function is called, other ProcMgr module APIs, except + * for the proc_mgr_get_config API cannot be called anymore. + */ +int proc_mgr_destroy(void) +{ + int retval = 0; + int i; + + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_destroy: Error - module not initialized\n"); + return -EFAULT; + } + if (atomic_dec_return(&proc_mgr_obj_state.ref_count) + == PROCMGR_MAKE_MAGICSTAMP(0)) { + + /* Check if any ProcMgr instances have not been deleted so far + *. If not,delete them + */ + for (i = 0 ; i < MULTIPROC_MAXPROCESSORS; i++) { + if (proc_mgr_obj_state.proc_handles[i] != NULL) + proc_mgr_delete + (&(proc_mgr_obj_state.proc_handles[i])); + } + + mutex_destroy(proc_mgr_obj_state.gate_handle); + kfree(proc_mgr_obj_state.gate_handle); + /* Decrease the refCount */ + atomic_set(&proc_mgr_obj_state.ref_count, + PROCMGR_MAKE_MAGICSTAMP(0)); + } + return retval;; +} +EXPORT_SYMBOL(proc_mgr_destroy); + +/*===================================== + * Function to initialize the parameters for the ProcMgr instance. + * + * This function can be called by the application to get their + * configuration parameter to ProcMgr_create filled in by the + * ProcMgr module with the default parameters. + */ +void proc_mgr_params_init(void *handle, struct proc_mgr_params *params) +{ + struct proc_mgr_object *proc_handle = (struct proc_mgr_object *)handle; + + if (WARN_ON(params == NULL)) + goto exit; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_params_init: Error - module not initialized\n"); + } + if (handle == NULL) { + memcpy(params, &(proc_mgr_obj_state.def_inst_params), + sizeof(struct proc_mgr_params)); + } else { + /* Return updated ProcMgr instance specific parameters. */ + memcpy(params, &(proc_handle->params), + sizeof(struct proc_mgr_params)); + } +exit: + return; +} +EXPORT_SYMBOL(proc_mgr_params_init); + +/*===================================== + * Function to create a ProcMgr object for a specific slave + * processor. + * + * This function creates an instance of the ProcMgr module and + * returns an instance handle, which is used to access the + * specified slave processor. The processor ID specified here is + * the ID of the slave processor as configured with the MultiProc + * module. + * Instance-level configuration needs to be provided to this + * function. If the user wishes to change some specific config + * parameters, then struct proc_mgr_params_init can be called to get the + * configuration filled with the default values. After this, only + * the required configuration values can be changed. For this + * API, the params argument is not optional, since the user needs + * to provide some essential values such as loader, PwrMgr and + * Processor instances to be used with this ProcMgr instance. + */ +void *proc_mgr_create(u16 proc_id, const struct proc_mgr_params *params) +{ + struct proc_mgr_object *handle = NULL; + + BUG_ON(!IS_VALID_PROCID(proc_id)); + BUG_ON(params == NULL); + BUG_ON(params->proc_handle == NULL); + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_create: Error - module not initialized\n"); + return NULL; + } + if (proc_mgr_obj_state.proc_handles[proc_id] != NULL) { + handle = proc_mgr_obj_state.proc_handles[proc_id]; + printk(KERN_WARNING "proc_mgr_create:" + "Processor already exists for specified" + "%d proc_id, handle = 0x%x\n", proc_id, (u32)handle); + return handle; + } + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + handle = (struct proc_mgr_object *) + vmalloc(sizeof(struct proc_mgr_object)); + BUG_ON(handle == NULL); + memset(handle, 0, sizeof(struct proc_mgr_object)); + memcpy(&(handle->params), params, sizeof(struct proc_mgr_params)); + handle->proc_id = proc_id; + handle->proc_handle = params->proc_handle; + handle->loader_handle = params->loader_handle; + handle->pwr_handle = params->pwr_handle; + proc_mgr_obj_state.proc_handles[proc_id] = handle; + mutex_unlock(proc_mgr_obj_state.gate_handle); + return handle; +} +EXPORT_SYMBOL(proc_mgr_create); + +/*=================================== + * Function to delete a ProcMgr object for a specific slave + * processor. + * + * Once this function is called, other ProcMgr instance level APIs + * that require the instance handle cannot be called. + * + */ +int +proc_mgr_delete(void **handle_ptr) +{ + int retval = 0; + struct proc_mgr_object *handle; + + BUG_ON(handle_ptr == NULL); + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_delete: Error - module not initialized\n"); + return -EFAULT; + } + + handle = (struct proc_mgr_object *)(*handle_ptr); + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + proc_mgr_obj_state.proc_handles[handle->proc_id] = NULL; + vfree(handle); + *handle_ptr = NULL; + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval; +} +EXPORT_SYMBOL(proc_mgr_delete); + +/*====================================== + * Function to open a handle to an existing ProcMgr object handling + * the proc_id. + * + * This function returns a handle to an existing ProcMgr instance + * created for this proc_id. It enables other entities to access + * and use this ProcMgr instance. + */ +int proc_mgr_open(void **handle_ptr, u16 proc_id) +{ + int retval = 0; + + BUG_ON(handle_ptr == NULL); + BUG_ON(!IS_VALID_PROCID(proc_id)); + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_open: Error - module not initialized\n"); + return -EFAULT; + } + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + *handle_ptr = proc_mgr_obj_state.proc_handles[proc_id]; + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval; +} +EXPORT_SYMBOL(proc_mgr_open); + +/*===================================== + * Function to close this handle to the ProcMgr instance. + * + * This function closes the handle to the ProcMgr instance + * obtained through proc_mgr_open call made earlier. + */ +int proc_mgr_close(void *handle) +{ + int retval = 0; + + BUG_ON(handle == NULL); + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_close: Error - module not initialized\n"); + return -EFAULT; + } + /* Nothing to be done for closing the handle. */ + return retval; +} +EXPORT_SYMBOL(proc_mgr_close); + +/*======================================== + * Function to initialize the parameters for the ProcMgr attach + * function. + * + * This function can be called by the application to get their + * configuration parameter to proc_mgr_attach filled in by the + * ProcMgr module with the default parameters. If the user does + * not wish to make any change in the default parameters, this API + * is not required to be called. + */ +void proc_mgr_get_attach_params(void *handle, + struct proc_mgr_attach_params *params) +{ + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + BUG_ON(params == NULL); + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_get_attach_params:" + "Error - module not initialized\n"); + } + if (handle == NULL) { + memcpy(params, &(proc_mgr_obj_state.def_attach_params), + sizeof(struct proc_mgr_attach_params)); + } else { + /* Return updated ProcMgr instance specific parameters. */ + memcpy(params, &(proc_mgr_handle->attach_params), + sizeof(struct proc_mgr_attach_params)); + } + return; +} +EXPORT_SYMBOL(proc_mgr_get_attach_params); + +/* + * Function to attach the client to the specified slave and also + * initialize the slave (if required). + * + * This function attaches to an instance of the ProcMgr module and + * performs any hardware initialization required to power up the + * slave device. This function also performs the required state + * transitions for this ProcMgr instance to ensure that the local + * object representing the slave device correctly indicates the + * state of the slave device. Depending on the slave boot mode + * being used, the slave may be powered up, in reset, or even + * running state. + * Configuration parameters need to be provided to this + * function. If the user wishes to change some specific config + * parameters, then proc_mgr_get_attach_params can be called to get + * the configuration filled with the default values. After this, + * only the required configuration values can be changed. If the + * user does not wish to make any change in the default parameters, + * the application can simply call proc_mgr_attach with NULL + * parameters. + * The default parameters would get automatically used. + */ +int proc_mgr_attach(void *handle, struct proc_mgr_attach_params *params) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + struct proc_mgr_attach_params tmp_params; + struct processor_attach_params proc_attach_params; + + if (params == NULL) { + proc_mgr_get_attach_params(handle, &tmp_params); + params = &tmp_params; + } + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_attach:" + "Error - module not initialized\n"); + return -EFAULT; + } + if (WARN_ON(handle == NULL)) { + retval = -EFAULT; + goto exit; + } + if (WARN_ON(params->boot_mode == PROC_MGR_BOOTMODE_ENDVALUE)) { + retval = -EINVAL; + goto exit; + } + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + /* Copy the user provided values into the instance object. */ + memcpy(&(proc_mgr_handle->attach_params), params, + sizeof(struct proc_mgr_attach_params)); + proc_attach_params.params = params; + proc_attach_params.num_mem_entries = 0; + /* Attach to the specified Processor instance. */ + retval = processor_attach(proc_mgr_handle->proc_handle, + &proc_attach_params); + proc_mgr_handle->num_mem_entries = proc_attach_params.num_mem_entries; + printk(KERN_INFO "proc_mgr_attach:proc_mgr_handle->num_mem_entries = %d\n", + proc_mgr_handle->num_mem_entries); + /* Store memory information in local object.*/ + memcpy(&(proc_mgr_handle->mem_entries), + &(proc_attach_params.mem_entries), + sizeof(proc_mgr_handle->mem_entries)); + mutex_unlock(proc_mgr_obj_state.gate_handle); +exit: + return retval; +} +EXPORT_SYMBOL(proc_mgr_attach); + +/*=================================== + * Function to detach the client from the specified slave and also + * finalze the slave (if required). + * + * This function detaches from an instance of the ProcMgr module + * and performs any hardware finalization required to power down + * the slave device. This function also performs the required state + * transitions for this ProcMgr instance to ensure that the local + * object representing the slave device correctly indicates the + * state of the slave device. Depending on the slave boot mode + * being used, the slave may be powered down, in reset, or left in + * its original state. +*/ +int proc_mgr_detach(void *handle) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_detach:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + /* Detach from the Processor. */ + retval = processor_detach(proc_mgr_handle->proc_handle); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval; +} +EXPORT_SYMBOL(proc_mgr_detach); + +/*=============================== + * Function to initialize the parameters for the ProcMgr start + * function. + * + * This function can be called by the application to get their + * configuration parameter to proc_mgr_start filled in by the + * ProcMgr module with the default parameters. If the user does + * not wish to make any change in the default parameters, this API + * is not required to be called. + * + */ +void proc_mgr_get_start_params(void *handle, + struct proc_mgr_start_params *params) +{ + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_get_start_params:" + "Error - module not initialized\n"); + } + BUG_ON(params == NULL); + + if (handle == NULL) { + memcpy(params, &(proc_mgr_obj_state.def_start_params), + sizeof(struct proc_mgr_start_params)); + } else { + /* Return updated ProcMgr instance specific parameters. */ + memcpy(params, &(proc_mgr_handle->start_params), + sizeof(struct proc_mgr_start_params)); + } + return; +} +EXPORT_SYMBOL(proc_mgr_get_start_params); + +/*========================================== + * Function to start the slave processor running. + * + * Function to start execution of the loaded code on the slave + * from the entry point specified in the slave executable loaded + * earlier by call to proc_mgr_load (). + * After successful completion of this function, the ProcMgr + * instance is expected to be in the proc_mgr_State_Running state. + */ +int proc_mgr_start(void *handle, u32 entry_point, + struct proc_mgr_start_params *params) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + struct proc_mgr_start_params tmp_params; + struct processor_start_params proc_params; + + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_start:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + + if (params == NULL) { + proc_mgr_get_start_params(handle, &tmp_params); + params = &tmp_params; + } + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + memcpy(&(proc_mgr_handle->start_params), params, + sizeof(struct proc_mgr_start_params)); + /* Start the slave processor running. */ + proc_params.params = params; + retval = processor_start(proc_mgr_handle->proc_handle, + entry_point, &proc_params); + + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_start); + +/*======================================== + * Function to stop the slave processor. + * + * Function to stop execution of the slave processor. + * Depending on the boot mode, after successful completion of this + * function, the ProcMgr instance may be in the proc_mgr_State_Reset + * state. + * + */ +int proc_mgr_stop(void *handle, struct proc_mgr_stop_params *params) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + struct processor_stop_params proc_params; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_stop:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + proc_params.params = params; + retval = processor_stop(proc_mgr_handle->proc_handle, + &proc_params); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_stop); + +/*=================================== + * Function to get the current state of the slave Processor. + * + * This function gets the state of the slave processor as + * maintained on the master Processor state machine. It does not + * go to the slave processor to get its actual state at the time + * when this API is called. + * + */ +enum proc_mgr_state proc_mgr_get_state(void *handle) +{ + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + enum proc_mgr_state state = PROC_MGR_STATE_UNKNOWN; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_get_state:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + state = processor_get_state(proc_mgr_handle->proc_handle); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return state; +} +EXPORT_SYMBOL(proc_mgr_get_state); + +/*================================================== + * Function to read from the slave processor's memory. + * + * This function reads from the specified address in the + * processor's address space and copies the required number of + * bytes into the specified buffer. + * It returns the number of bytes actually read in thenum_bytes + * parameter. + */ +int proc_mgr_read(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_read:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + BUG_ON(proc_addr == 0); + BUG_ON(num_bytes == NULL); + BUG_ON(buffer == NULL); + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + + retval = processor_read(proc_mgr_handle->proc_handle, proc_addr, + num_bytes, buffer); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval; +} +EXPORT_SYMBOL(proc_mgr_read); + +/* + * Function to write into the slave processor's memory. + * + * This function writes into the specified address in the + * processor's address space and copies the required number of + * bytes from the specified buffer. + * It returns the number of bytes actually written in thenum_bytes + * parameter. + */ +int proc_mgr_write(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_write:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(proc_addr == 0); + BUG_ON(num_bytes == NULL); + BUG_ON(buffer == NULL); + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + retval = processor_write(proc_mgr_handle->proc_handle, proc_addr, + num_bytes, buffer); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_write); + + +/*=================================== + * Function to perform device-dependent operations. + * + * This function performs control operations supported by the + * as exposed directly by the specific implementation of the + * Processor interface. These commands and their specific argument + * types are used with this function. + */ +int proc_mgr_control(void *handle, int cmd, void *arg) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle + = (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_control:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + /* Perform device-dependent control operation. */ + retval = processor_control(proc_mgr_handle->proc_handle, cmd, arg); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_control); + +/*======================================== + * Function to translate between two types of address spaces. + * + * This function translates addresses between two types of address + * spaces. The destination and source address types are indicated + * through parameters specified in this function. + */ +int proc_mgr_translate_addr(void *handle, void **dst_addr, + enum proc_mgr_addr_type dst_addr_type, void *src_addr, + enum proc_mgr_addr_type src_addr_type) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_translate_addr:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(dst_addr == NULL); + BUG_ON(handle == NULL); + BUG_ON(dst_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE); + BUG_ON(src_addr == NULL); + BUG_ON(src_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE); + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + /* Translate the address. */ + retval = processor_translate_addr(proc_mgr_handle->proc_handle, + dst_addr, dst_addr_type, src_addr, src_addr_type); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_translate_addr); + +/*============================================ + * Function to map address to slave address space. + * + * This function maps the provided slave address to a host address + * and returns the mapped address and size. + * + */ +int proc_mgr_map(void *handle, u32 proc_addr, u32 size, u32 *mapped_addr, + u32 *mapped_size, u32 map_attribs) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_map:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + BUG_ON(proc_addr == 0); + BUG_ON(mapped_addr == NULL); + BUG_ON(mapped_size == NULL); + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + + /* Map to host address space. */ + retval = processor_map(proc_mgr_handle->proc_handle, proc_addr, + size, mapped_addr, mapped_size, map_attribs); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_map); + +/*============================================ + * Function to unmap address to slave address space. + * + * This function unmaps the provided slave address to a host address + * + */ +int proc_mgr_unmap(void *handle, u32 mapped_addr) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_unmap:" + "Error - module not initialized\n"); + return -EFAULT; + } + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + + /* Map to host address space. */ + retval = processor_unmap(proc_mgr_handle->proc_handle, mapped_addr); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_unmap); + +/*================================= + * Function that registers for notification when the slave + * processor transitions to any of the states specified. + * + * This function allows the user application to register for + * changes in processor state and take actions accordingly. + * + */ +int proc_mgr_register_notify(void *handle, proc_mgr_callback_fxn fxn, + void *args, enum proc_mgr_state state[]) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle + = (struct proc_mgr_object *)handle; + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_register_notify:" + "Error - module not initialized\n"); + return -EFAULT; + } + BUG_ON(handle == NULL); + BUG_ON(fxn == NULL); + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + retval = processor_register_notify(proc_mgr_handle->proc_handle, fxn, + args, state); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval; +} +EXPORT_SYMBOL(proc_mgr_register_notify); + +/* + * Function that returns information about the characteristics of + * the slave processor. + */ +int proc_mgr_get_proc_info(void *handle, struct proc_mgr_proc_info *proc_info) +{ + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + struct processor_object *proc_handle; + + struct proc_mgr_proc_info proc_info_test; + + if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count), + PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1)) + == true) { + printk(KERN_ERR "proc_mgr_get_proc_info:" + "Error - module not initialized\n"); + return -EFAULT; + } + if (WARN_ON(handle == NULL)) + goto error_exit; + if (WARN_ON(proc_info == NULL)) + goto error_exit; + proc_handle = proc_mgr_handle->proc_handle; + if (WARN_ON(proc_handle == NULL)) + goto error_exit; + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + + processor_get_proc_info(proc_handle, &proc_info_test); + /* Return bootMode information. */ + proc_info->boot_mode = proc_mgr_handle->attach_params.boot_mode; + /* Return memory information. */ + proc_info->num_mem_entries = proc_mgr_handle->num_mem_entries; + memcpy(&(proc_info->mem_entries), + &(proc_mgr_handle->mem_entries), + sizeof(proc_mgr_handle->mem_entries)); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return 0; +error_exit: + return -EFAULT; +} +EXPORT_SYMBOL(proc_mgr_get_proc_info); + +/*============================================ + * Function to get virtual to physical address translations + * + * This function retrieves physical entries + * + */ +int proc_mgr_virt_to_phys(void *handle, u32 da, u32 *mapped_entries, + u32 num_of_entries) +{ + int retval = 0; + struct proc_mgr_object *proc_mgr_handle = + (struct proc_mgr_object *)handle; + + WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle)); + + /* Map to host address space. */ + retval = processor_virt_to_phys(proc_mgr_handle->proc_handle, da, + mapped_entries, num_of_entries); + WARN_ON(retval < 0); + mutex_unlock(proc_mgr_obj_state.gate_handle); + return retval;; +} +EXPORT_SYMBOL(proc_mgr_virt_to_phys); + diff --git a/drivers/dsp/syslink/procmgr/procmgr_drv.c b/drivers/dsp/syslink/procmgr/procmgr_drv.c new file mode 100755 index 000000000000..e35bb51259b6 --- /dev/null +++ b/drivers/dsp/syslink/procmgr/procmgr_drv.c @@ -0,0 +1,758 @@ +/* + * procmgr_drv.c + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#include <linux/autoconf.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> + +/* Module headers */ +#include <procmgr.h> +#include "procmgr_drvdefs.h" + +#define PROCMGR_NAME "syslink-procmgr" + +static char *driver_name = PROCMGR_NAME; + +static s32 driver_major; + +static s32 driver_minor; + +struct procmgr_dev { + struct cdev cdev; +}; + +struct platform_device *omap_proc_dev; +static struct platform_device *procmgr_pdev; +static struct procmgr_dev *procmgr_device; + +static struct class *proc_mgr_class; + + +/** ==================================== + * Forward declarations of internal functions + * ==================================== + */ +/* Linux driver function to open the driver object. */ +static int proc_mgr_drv_open(struct inode *inode, struct file *filp); + +/* Linux driver function to close the driver object. */ +static int proc_mgr_drv_release(struct inode *inode, struct file *filp); + +/* Linux driver function to invoke the APIs through ioctl. */ +static int proc_mgr_drv_ioctl(struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long args); + +/* Linux driver function to map memory regions to user space. */ +static int proc_mgr_drv_mmap(struct file *filp, struct vm_area_struct *vma); + +/* Module initialization function for Linux driver. */ +static int __init proc_mgr_drv_initialize_module(void); + +/* Module finalization function for Linux driver. */ +static void __exit proc_mgr_drv_finalize_module(void); + +/* Platform driver probe function */ +static int __devinit proc_mgr_probe(struct platform_device *pdev); + +/* Platform driver remove function */ +static int __devexit proc_mgr_remove(struct platform_device *pdev); + +/* + * name DriverOps + * + * desc Function to invoke the APIs through ioctl + * + */ +static const struct file_operations procmgr_fops = { + .open = proc_mgr_drv_open, + .ioctl = proc_mgr_drv_ioctl, + .release = proc_mgr_drv_release, + .mmap = proc_mgr_drv_mmap, +} ; + +/* Imtiaz changed places */ +static struct platform_driver procmgr_driver_ldm = { + .driver = { + .owner = THIS_MODULE, + .name = PROCMGR_NAME, + }, + .probe = proc_mgr_probe, + .remove = __devexit_p(proc_mgr_remove), + .shutdown = NULL, + .suspend = NULL, + .resume = NULL, +}; + +/* +* brief Linux specific function to open the driver. + */ +static int proc_mgr_drv_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +/* +* brief Linux driver function to close the driver object. + */ +static int proc_mgr_drv_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +/* +* Linux driver function to invoke the APIs through ioctl. + */ +static int proc_mgr_drv_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long args) +{ + int retval = 0; + struct proc_mgr_cmd_args *cmd_args = (struct proc_mgr_cmd_args *)args; + struct proc_mgr_cmd_args command_args; + + switch (cmd) { + case CMD_PROCMGR_GETCONFIG: + { + struct proc_mgr_cmd_args_get_config *src_args = + (struct proc_mgr_cmd_args_get_config *)args; + struct proc_mgr_config cfg; + + /* copy_from_user is not needed for proc_mgr_get_config, + * since the user's config is not used. + */ + proc_mgr_get_config(&cfg); + + retval = copy_to_user((void *)(src_args->cfg), + (const void *)&cfg, + sizeof(struct proc_mgr_config)); + + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_SETUP: + { + struct proc_mgr_cmd_args_setup *src_args = + (struct proc_mgr_cmd_args_setup *)args; + struct proc_mgr_config cfg; + + retval = copy_from_user((void *)&cfg, + (const void *)(src_args->cfg), + sizeof(struct proc_mgr_config)); + + /* This check is needed at run-time also since it + * depends on run environment. + * It must not be optimized out. + */ + if (WARN_ON(retval != 0)) + goto func_exit; + + retval = proc_mgr_setup(&cfg); + } + break; + + case CMD_PROCMGR_DESTROY: + { + retval = proc_mgr_destroy(); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_PARAMS_INIT: + { + struct proc_mgr_cmd_args_params_init src_args; + struct proc_mgr_params params; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_params_init)); + + if (WARN_ON(retval != 0)) + goto func_exit; + + proc_mgr_params_init(src_args.handle, ¶ms); + + /* Copy only the params to user-side */ + retval = copy_to_user((void *)(src_args.params), + (const void *)¶ms, + sizeof(struct proc_mgr_params)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_CREATE: + { + struct proc_mgr_cmd_args_create src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_create)); + + src_args.handle = proc_mgr_create(src_args.proc_id, + &(src_args.params)); + if (src_args.handle == NULL) { + retval = -EFAULT; + goto func_exit; + } + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_create)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_DELETE: + { + struct proc_mgr_cmd_args_delete src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_delete)); + if (WARN_ON(retval != 0)) + goto func_exit; + + retval = proc_mgr_delete(&(src_args.handle)); + } + break; + + case CMD_PROCMGR_OPEN: + { + struct proc_mgr_cmd_args_open src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_open)); + + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_open(&(src_args.handle), + src_args.proc_id); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = proc_mgr_get_proc_info(src_args.handle, + &(src_args.proc_info)); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_open)); + WARN_ON(retval); + } + break; + + case CMD_PROCMGR_CLOSE: + { + struct proc_mgr_cmd_args_close src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_close)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_close(&(src_args.handle)); + } + break; + + case CMD_PROCMGR_GETATTACHPARAMS: + { + struct proc_mgr_cmd_args_get_attach_params src_args; + struct proc_mgr_attach_params params; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_get_attach_params)); + if (WARN_ON(retval != 0)) + goto func_exit; + proc_mgr_get_attach_params(src_args.handle, ¶ms); + retval = copy_to_user((void *)(src_args.params), + (const void *)¶ms, + sizeof(struct proc_mgr_attach_params)); + WARN_ON(retval); + } + break; + + case CMD_PROCMGR_ATTACH: + { + struct proc_mgr_cmd_args_attach src_args; + struct proc_mgr_attach_params params; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_attach)); + if (WARN_ON(retval != 0)) + goto func_exit; + /* Copy params from user-side. */ + retval = copy_from_user((void *)¶ms, + (const void *)(src_args.params), + sizeof(struct proc_mgr_attach_params)); + retval = proc_mgr_attach(src_args.handle, ¶ms); + if (WARN_ON(retval < 0)) + goto func_exit; + /* Get memory information. */ + retval = proc_mgr_get_proc_info(src_args.handle, + &(src_args.proc_info)); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_attach)); + } + break; + + case CMD_PROCMGR_DETACH: + { + struct proc_mgr_cmd_args_detach src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_detach)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_detach(src_args.handle); + if (WARN_ON(retval < 0)) + goto func_exit; + } + break; + + case CMD_PROCMGR_GETSTARTPARAMS: + { + struct proc_mgr_cmd_args_get_start_params src_args; + struct proc_mgr_start_params params; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_get_start_params)); + if (WARN_ON(retval != 0)) + goto func_exit; + proc_mgr_get_start_params(src_args.handle, ¶ms); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(src_args.params), + (const void *)¶ms, + sizeof(struct proc_mgr_start_params)); + WARN_ON(retval); + } + break; + + case CMD_PROCMGR_START: + { + struct proc_mgr_cmd_args_start src_args; + struct proc_mgr_start_params params; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_start)); + /* Copy params from user-side. */ + retval = copy_from_user((void *)¶ms, + (const void *)(src_args.params), + sizeof(struct proc_mgr_start_params)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_start(src_args.handle, + src_args.entry_point, ¶ms); + + WARN_ON(retval); + } + break; + + case CMD_PROCMGR_STOP: + { + struct proc_mgr_cmd_args_stop src_args; + + struct proc_mgr_stop_params params; + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_stop)); + /* Copy params from user-side. */ + retval = copy_from_user((void *)¶ms, + (const void *)(src_args.params), + sizeof(struct proc_mgr_stop_params)); + + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_stop(src_args.handle, ¶ms); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_GETSTATE: + { + struct proc_mgr_cmd_args_get_state src_args; + enum proc_mgr_state procmgrstate; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_get_state)); + if (WARN_ON(retval != 0)) + goto func_exit; + procmgrstate = proc_mgr_get_state(src_args.handle); + src_args.proc_mgr_state = procmgrstate; + retval = copy_to_user((void *)(args), (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_get_state)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_READ: + { + struct proc_mgr_cmd_args_read src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_read)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_read(src_args.handle, + src_args.proc_addr, &(src_args.num_bytes), + src_args.buffer); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_read)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_WRITE: + { + struct proc_mgr_cmd_args_write src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_write)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_write(src_args.handle, + src_args.proc_addr, &(src_args.num_bytes), + src_args.buffer); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_write)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_CONTROL: + { + struct proc_mgr_cmd_args_control src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_control)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_control(src_args.handle, + src_args.cmd, src_args.arg); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_TRANSLATEADDR: + { + struct proc_mgr_cmd_args_translate_addr src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_translate_addr)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_translate_addr(src_args.handle, + &(src_args.dst_addr), src_args.dst_addr_type, + src_args.src_addr, src_args.src_addr_type); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), + (const void *)&src_args, sizeof + (struct proc_mgr_cmd_args_translate_addr)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_MAP: + { + struct proc_mgr_cmd_args_map src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_map)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_map(src_args.handle, + src_args.proc_addr, src_args.size, + &(src_args.mapped_addr), + &(src_args.mapped_size), + src_args.map_attribs); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), + (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_map)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_UNMAP: + { + struct proc_mgr_cmd_args_unmap src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_unmap)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_unmap(src_args.handle, + (src_args.mapped_addr)); + WARN_ON(retval < 0); + } + + case CMD_PROCMGR_REGISTERNOTIFY: + { + struct proc_mgr_cmd_args_register_notify src_args; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_register_notify)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_register_notify(src_args.handle, + src_args.callback_fxn, + src_args.args, src_args.state); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_GETPROCINFO: + { + struct proc_mgr_cmd_args_get_proc_info src_args; + struct proc_mgr_proc_info proc_info; + + /* Copy the full args from user-side. */ + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_get_proc_info)); + if (WARN_ON(retval != 0)) + goto func_exit; + retval = proc_mgr_get_proc_info + (src_args.handle, &proc_info); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(src_args.proc_info), + (const void *) &proc_info, + sizeof(struct proc_mgr_proc_info)); + WARN_ON(retval < 0); + } + break; + + case CMD_PROCMGR_GETVIRTTOPHYS: + { + struct proc_mgr_cmd_args_get_virt_to_phys src_args; + + retval = copy_from_user((void *)&src_args, + (const void *)(args), + sizeof(struct proc_mgr_cmd_args_get_virt_to_phys)); + retval = proc_mgr_virt_to_phys(src_args.handle, + src_args.da, (src_args.mem_entries), + src_args.num_of_entries); + if (WARN_ON(retval < 0)) + goto func_exit; + retval = copy_to_user((void *)(args), (const void *)&src_args, + sizeof(struct proc_mgr_cmd_args_get_virt_to_phys)); + WARN_ON(retval < 0); + } + break; + + default: + printk(KERN_ERR"PROC_MGR_DRV: WRONG IOCTL !!!!\n"); + BUG_ON(1); + break; + } +func_exit: + /* Set the retval and copy the common args to user-side. */ + command_args.api_status = retval; + retval = copy_to_user((void *)cmd_args, + (const void *)&command_args, sizeof(struct proc_mgr_cmd_args)); + + WARN_ON(retval < 0); + return retval; +} + + +/* + Driver function to map memory regions to user space. + */ +static int proc_mgr_drv_mmap(struct file *filp, struct vm_area_struct *vma) +{ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED; + + if (remap_pfn_range(vma, + vma->vm_start, + vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + return -EAGAIN; + } + return 0; +} + +static int __devinit proc_mgr_probe(struct platform_device *pdev) +{ + dev_t dev = 0 ; + int retval = -ENOMEM; + + /* Display the version info and created date/time */ + dev_dbg(&omap_proc_dev->dev, "Entering %s function\n\n", __func__); + + if (driver_major) { + dev = MKDEV(driver_major, driver_minor); + retval = register_chrdev_region(dev, 1, driver_name); + } else { + retval = alloc_chrdev_region(&dev, driver_minor, 1, + driver_name); + driver_major = MAJOR(dev); + } + + procmgr_device = kmalloc(sizeof(struct procmgr_dev), GFP_KERNEL); + if (!procmgr_device) { + retval = -ENOMEM; + unregister_chrdev_region(dev, 1); + goto exit; + } + memset(procmgr_device, 0, sizeof(struct procmgr_dev)); + cdev_init(&procmgr_device->cdev, &procmgr_fops); + procmgr_device->cdev.owner = THIS_MODULE; + procmgr_device->cdev.ops = &procmgr_fops; + + retval = cdev_add(&procmgr_device->cdev, dev, 1); + + if (retval) { + printk(KERN_ERR "Failed to add the syslink procmgr device \n"); + goto exit; + } + + /* udev support */ + proc_mgr_class = class_create(THIS_MODULE, "syslink-procmgr"); + + if (IS_ERR(proc_mgr_class)) { + printk(KERN_ERR "Error creating bridge class \n"); + goto exit; + } + device_create(proc_mgr_class, NULL, MKDEV(driver_major, driver_minor), + NULL, PROCMGR_NAME); + +exit: + dev_dbg(&omap_proc_dev->dev, "Leaving %s function\n\n", __func__); + return retval; +} + + +static int __devexit proc_mgr_remove(struct platform_device *pdev) +{ + dev_t devno = 0; + + dev_dbg(&omap_proc_dev->dev, "Entering %s function\n", __func__); + devno = MKDEV(driver_major, driver_minor); + if (procmgr_device) { + cdev_del(&procmgr_device->cdev); + kfree(procmgr_device); + } + unregister_chrdev_region(devno, 1); + if (proc_mgr_class) { + /* remove the device from sysfs */ + device_destroy(proc_mgr_class, MKDEV(driver_major, + driver_minor)); + class_destroy(proc_mgr_class); + } + dev_dbg(&omap_proc_dev->dev, "Entering %s function\n", __func__); + return 0; +} + +/* +* Module initialization function for Linux driver. + */ +static int __init proc_mgr_drv_initialize_module(void) +{ + int retval = -ENOMEM; + + procmgr_pdev = platform_device_alloc(PROCMGR_NAME, -1); + if (!procmgr_pdev) { + printk(KERN_ERR "%s:device allocation failed\n", __func__); + return -ENOMEM; + } + retval = platform_device_add(procmgr_pdev); + if (retval) + goto err_out; + + /*Saving the context for future use*/ + omap_proc_dev = procmgr_pdev; + + retval = platform_driver_register(&procmgr_driver_ldm); + if (!retval) + return retval; +err_out: + platform_device_put(procmgr_pdev); + return retval; +} + +/* +* driver function to finalize the driver module. + */ +static void __exit proc_mgr_drv_finalize_module(void) +{ + + dev_dbg(&omap_proc_dev->dev, "Entering %s function\n", __func__); + platform_device_unregister(procmgr_pdev); + platform_driver_unregister(&procmgr_driver_ldm); + dev_dbg(&omap_proc_dev->dev, "Leaving %s function\n", __func__); +} + +/* +* brief Macro calls that indicate initialization and finalization functions + * to the kernel. + */ +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Mugdha Kamoolkar"); +module_init(proc_mgr_drv_initialize_module); +module_exit(proc_mgr_drv_finalize_module); diff --git a/drivers/dsp/syslink/procmgr/procmgr_drvdefs.h b/drivers/dsp/syslink/procmgr/procmgr_drvdefs.h new file mode 100755 index 000000000000..2be14bf7a20e --- /dev/null +++ b/drivers/dsp/syslink/procmgr/procmgr_drvdefs.h @@ -0,0 +1,541 @@ +/* + * procmgr_drvdefs.h + * + * Syslink driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#ifndef SYSLINK_PROCMGR_DRVDEFS_H +#define SYSLINK_PROCMGR_DRVDEFS_H + +#include <linux/types.h> + +/* Module headers */ +#include <procmgr.h> + + +/* ================================= + * Macros and types + * ================================= + */ +/* + * Base structure for ProcMgr command args. This needs to be the first + * field in all command args structures. + */ +struct proc_mgr_cmd_args { + int api_status; + /*Status of the API being called. */ +}; + +/* -------------------------------------- + * IOCTL command IDs for ProcMgr + * --------------------------------------- + */ +/* + * Base command ID for ProcMgr + */ +#define PROCMGR_BASE_CMD 0x100 + +/* + * Command for ProcMgr_getConfig + */ +#define CMD_PROCMGR_GETCONFIG (PROCMGR_BASE_CMD + 1) + +/* + * Command for ProcMgr_setup + */ +#define CMD_PROCMGR_SETUP (PROCMGR_BASE_CMD + 2) + +/* + * Command for ProcMgr_setup + */ +#define CMD_PROCMGR_DESTROY (PROCMGR_BASE_CMD + 3) + +/* + * Command for ProcMgr_destroy + */ +#define CMD_PROCMGR_PARAMS_INIT (PROCMGR_BASE_CMD + 4) + +/* + * Command for ProcMgr_create + */ +#define CMD_PROCMGR_CREATE (PROCMGR_BASE_CMD + 5) + +/* + * Command for ProcMgr_delete + */ +#define CMD_PROCMGR_DELETE (PROCMGR_BASE_CMD + 6) + +/* + * Command for ProcMgr_open + */ +#define CMD_PROCMGR_OPEN (PROCMGR_BASE_CMD + 7) + +/* + * Command for ProcMgr_close + */ +#define CMD_PROCMGR_CLOSE (PROCMGR_BASE_CMD + 8) + +/* + * Command for ProcMgr_getAttachParams + */ +#define CMD_PROCMGR_GETATTACHPARAMS (PROCMGR_BASE_CMD + 9) + +/* + * Command for ProcMgr_attach + */ +#define CMD_PROCMGR_ATTACH (PROCMGR_BASE_CMD + 10) + +/* + * Command for ProcMgr_detach + */ +#define CMD_PROCMGR_DETACH (PROCMGR_BASE_CMD + 11) + +/* + * Command for ProcMgr_load + */ +#define CMD_PROCMGR_LOAD (PROCMGR_BASE_CMD + 12) + +/* + * Command for ProcMgr_unload + */ +#define CMD_PROCMGR_UNLOAD (PROCMGR_BASE_CMD + 13) + +/* + * Command for ProcMgr_getStartParams + */ +#define CMD_PROCMGR_GETSTARTPARAMS (PROCMGR_BASE_CMD + 14) + +/* + * Command for ProcMgr_start + */ +#define CMD_PROCMGR_START (PROCMGR_BASE_CMD + 15) + +/* + * Command for ProcMgr_stop + */ +#define CMD_PROCMGR_STOP (PROCMGR_BASE_CMD + 16) + +/* + * Command for ProcMgr_getState + */ +#define CMD_PROCMGR_GETSTATE (PROCMGR_BASE_CMD + 17) + +/* + * Command for ProcMgr_read + */ +#define CMD_PROCMGR_READ (PROCMGR_BASE_CMD + 18) + +/* + * Command for ProcMgr_write + */ +#define CMD_PROCMGR_WRITE (PROCMGR_BASE_CMD + 19) + +/* + * Command for ProcMgr_control + */ +#define CMD_PROCMGR_CONTROL (PROCMGR_BASE_CMD + 20) + +/* + * Command for ProcMgr_translateAddr + */ +#define CMD_PROCMGR_TRANSLATEADDR (PROCMGR_BASE_CMD + 22) + +/* + * Command for ProcMgr_getSymbolAddress + */ +#define CMD_PROCMGR_GETSYMBOLADDRESS (PROCMGR_BASE_CMD + 23) + +/* + * Command for ProcMgr_map + */ +#define CMD_PROCMGR_MAP (PROCMGR_BASE_CMD + 24) + +/* + * Command for ProcMgr_registerNotify + */ +#define CMD_PROCMGR_REGISTERNOTIFY (PROCMGR_BASE_CMD + 25) + +/* + * Command for ProcMgr_getProcInfo + */ +#define CMD_PROCMGR_GETPROCINFO (PROCMGR_BASE_CMD + 26) + +/* + * Command for ProcMgr_unmap + */ +#define CMD_PROCMGR_UNMAP (PROCMGR_BASE_CMD + 27) + +/* + * Command for ProcMgr_getVirtToPhysPages + */ +#define CMD_PROCMGR_GETVIRTTOPHYS (PROCMGR_BASE_CMD + 28) + + + + +/* ---------------------------------------------------------------------------- + * Command arguments for ProcMgr + * ---------------------------------------------------------------------------- + */ +/* + * Command arguments for ProcMgr_getConfig + */ +struct proc_mgr_cmd_args_get_config { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + struct proc_mgr_config *cfg; + /*Pointer to the ProcMgr module configuration structure in which the + default config is to be returned. */ +}; + +/* + * Command arguments for ProcMgr_setup + */ +struct proc_mgr_cmd_args_setup { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + struct proc_mgr_config *cfg; + /*Optional ProcMgr module configuration. If provided as NULL, default + configuration is used. */ +}; + +/* + * Command arguments for ProcMgr_destroy + */ +struct proc_mgr_cmd_args_destroy { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ +}; + +/* + * Command arguments for ProcMgr_Params_init + */ +struct proc_mgr_cmd_args_params_init { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object. */ + struct proc_mgr_params *params; + /*Pointer to the ProcMgr instance params structure in which the default + params is to be returned. */ +}; + +/* + * Command arguments for ProcMgr_create + */ +struct proc_mgr_cmd_args_create { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + u16 proc_id; + /*Processor ID represented by this ProcMgr instance */ + struct proc_mgr_params params; + /*ProcMgr instance configuration parameters. */ + void *handle; + /*Handle to the created ProcMgr object */ +}; + +/* + * Command arguments for ProcMgr_delete + */ +struct proc_mgr_cmd_args_delete{ + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Pointer to Handle to the ProcMgr object */ +}; + +/* + * Command arguments for ProcMgr_open + */ +struct proc_mgr_cmd_args_open { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + u16 proc_id; + /*Processor ID represented by this ProcMgr instance */ + void *handle; + /*Handle to the opened ProcMgr object. */ + struct proc_mgr_proc_info proc_info; + /*Processor information. */ +}; + +/* + * Command arguments for ProcMgr_close + */ +struct proc_mgr_cmd_args_close{ + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + struct proc_mgr_proc_info proc_info; + /*Processor information. */ +}; + +/* + * Command arguments for ProcMgr_getAttachParams + */ +struct proc_mgr_cmd_args_get_attach_params{ + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object. */ + struct proc_mgr_attach_params *params; + /*Pointer to the ProcMgr attach params structure in which the default + params is to be returned. */ +}; + +/* + * Command arguments for ProcMgr_attach + */ +struct proc_mgr_cmd_args_attach { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object. */ + struct proc_mgr_attach_params *params; + /*Optional ProcMgr attach parameters. */ + struct proc_mgr_proc_info proc_info; + /*Processor information. */ +}; + +/* + * Command arguments for ProcMgr_detach + */ +struct proc_mgr_cmd_args_detach { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + struct proc_mgr_proc_info proc_info; + /*Processor information. */ +}; + + +/* + * Command arguments for ProcMgr_getStartParams + */ +struct proc_mgr_cmd_args_get_start_params { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Entry point for the image*/ + u32 entry_point; + /*Handle to the ProcMgr object */ + struct proc_mgr_start_params *params; + /*Pointer to the ProcMgr start params structure in which the default + params is to be returned. */ +}; + +/* + * Command arguments for ProcMgr_start + */ +struct proc_mgr_cmd_args_start { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Entry point for the image*/ + u32 entry_point; + /*Handle to the ProcMgr object */ + struct proc_mgr_start_params *params; + /*Optional ProcMgr start parameters. */ +}; + +/* + * Command arguments for ProcMgr_stop + */ +struct proc_mgr_cmd_args_stop { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + struct proc_mgr_stop_params *params; + /*Optional ProcMgr stop parameters. */ +}; + +/* + * Command arguments for ProcMgr_getState + */ +struct proc_mgr_cmd_args_get_state { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /* Handle to the ProcMgr object */ + enum proc_mgr_state proc_mgr_state; + /*Current state of the ProcMgr object. */ +}; + +/* + * Command arguments for ProcMgr_read + */ +struct proc_mgr_cmd_args_read { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + u32 proc_addr; + /*Address in space processor's address space of the memory region to + read from. */ + u32 num_bytes; + /*IN/OUT parameter. As an IN-parameter, it takes in the number of bytes + to be read. When the function returns, this parameter contains the + number of bytes actually read. */ + void *buffer; + /*User-provided buffer in which the slave processor's memory contents + are to be copied. */ +}; + +/* + * Command arguments for ProcMgr_write + */ +struct proc_mgr_cmd_args_write { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + u32 proc_addr; + /*Address in space processor's address space of the memory region to + write into. */ + u32 num_bytes; + /*IN/OUT parameter. As an IN-parameter, it takes in the number of bytes + to be written. When the function returns, this parameter contains the + number of bytes actually written. */ + void *buffer; + /*User-provided buffer from which the data is to be written into the + slave processor's memory. */ +}; + +/* + * Command arguments for ProcMgr_control + */ +struct proc_mgr_cmd_args_control { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + int cmd; + /*Device specific processor command */ + void *arg; + /*Arguments specific to the type of command. */ +}; + +/* + * Command arguments for ProcMgr_translateAddr + */ +struct proc_mgr_cmd_args_translate_addr { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + void *dst_addr; + /*Return parameter: Pointer to receive the translated address. */ + enum proc_mgr_addr_type dst_addr_type; + /*Destination address type requested */ + void *src_addr; + /*Source address in the source address space */ + enum proc_mgr_addr_type src_addr_type; + /*Source address type */ +}; + +/* + * Command arguments for ProcMgr_getSymbolAddress + */ +struct proc_mgr_cmd_args_get_symbol_address { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + u32 file_id; + /*ID of the file received from the load function */ + char *symbol_name; + /*Name of the symbol */ + u32 sym_value; + /*Return parameter: Symbol address */ +}; + +/* + * Command arguments for ProcMgr_map + */ +struct proc_mgr_cmd_args_map { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + u32 proc_addr; + /*Slave address to be mapped */ + u32 size; + /*Size (in bytes) of region to be mapped */ + u32 mapped_addr; + /*Return parameter: Mapped address in host address space */ + u32 mapped_size; + /*Return parameter: Mapped size */ + u32 map_attribs; + /*Type of mapping. */ +}; + +/* + * Command arguments for ProcMgr_map + */ +struct proc_mgr_cmd_args_unmap { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + u32 mapped_addr; + /* Mapped address in host address space */ +}; + +/* + * Command arguments for ProcMgr_registerNotify + */ +struct proc_mgr_cmd_args_register_notify { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + int (*callback_fxn)(u16 proc_id, void *handle, + enum proc_mgr_state from_state, enum proc_mgr_state to_state); + /*Handling function to be registered. */ + void *args; + /*Optional arguments associated with the handler fxn. */ + enum proc_mgr_state state[]; + /*Array of target states for which registration is required. */ +}; + +/* + * Command arguments for ProcMgr_getProcInfo + */ +struct proc_mgr_cmd_args_get_proc_info { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + /*Handle to the ProcMgr object */ + struct proc_mgr_proc_info *proc_info; + /*Pointer to the ProcInfo object to be populated. */ +}; + +/* + * Command arguments for ProcMgr_virtToPhys + */ +struct proc_mgr_cmd_args_get_virt_to_phys { + struct proc_mgr_cmd_args commond_args; + /*Common command args */ + void *handle; + u32 da; + /* mem entries buffer */ + u32 *mem_entries; + /* number of entries */ + u32 num_of_entries; +}; + +#endif + |