18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Driver for MPC52xx processor BestComm peripheral controller 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Varma Electronics Oy, 78c2ecf20Sopenharmony_ci * ( by Andrey Volkov <avolkov@varma-el.com> ) 88c2ecf20Sopenharmony_ci * Copyright (C) 2003-2004 MontaVista, Software, Inc. 98c2ecf20Sopenharmony_ci * ( by Dale Farnsworth <dfarnsworth@mvista.com> ) 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 128c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 138c2ecf20Sopenharmony_ci * kind, whether express or implied. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/of.h> 208c2ecf20Sopenharmony_ci#include <linux/of_device.h> 218c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 228c2ecf20Sopenharmony_ci#include <asm/io.h> 238c2ecf20Sopenharmony_ci#include <asm/irq.h> 248c2ecf20Sopenharmony_ci#include <asm/mpc52xx.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/fsl/bestcomm/sram.h> 278c2ecf20Sopenharmony_ci#include <linux/fsl/bestcomm/bestcomm_priv.h> 288c2ecf20Sopenharmony_ci#include "linux/fsl/bestcomm/bestcomm.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define DRIVER_NAME "bestcomm-core" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* MPC5200 device tree match tables */ 338c2ecf20Sopenharmony_cistatic const struct of_device_id mpc52xx_sram_ids[] = { 348c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc5200-sram", }, 358c2ecf20Sopenharmony_ci { .compatible = "mpc5200-sram", }, 368c2ecf20Sopenharmony_ci {} 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct bcom_engine *bcom_eng = NULL; 418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* ======================================================================== */ 448c2ecf20Sopenharmony_ci/* Public and private API */ 458c2ecf20Sopenharmony_ci/* ======================================================================== */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Private API */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct bcom_task * 508c2ecf20Sopenharmony_cibcom_task_alloc(int bd_count, int bd_size, int priv_size) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci int i, tasknum = -1; 538c2ecf20Sopenharmony_ci struct bcom_task *tsk; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Don't try to do anything if bestcomm init failed */ 568c2ecf20Sopenharmony_ci if (!bcom_eng) 578c2ecf20Sopenharmony_ci return NULL; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Get and reserve a task num */ 608c2ecf20Sopenharmony_ci spin_lock(&bcom_eng->lock); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci for (i=0; i<BCOM_MAX_TASKS; i++) 638c2ecf20Sopenharmony_ci if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */ 648c2ecf20Sopenharmony_ci bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */ 658c2ecf20Sopenharmony_ci tasknum = i; 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci spin_unlock(&bcom_eng->lock); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (tasknum < 0) 728c2ecf20Sopenharmony_ci return NULL; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Allocate our structure */ 758c2ecf20Sopenharmony_ci tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL); 768c2ecf20Sopenharmony_ci if (!tsk) 778c2ecf20Sopenharmony_ci goto error; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci tsk->tasknum = tasknum; 808c2ecf20Sopenharmony_ci if (priv_size) 818c2ecf20Sopenharmony_ci tsk->priv = (void*)tsk + sizeof(struct bcom_task); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Get IRQ of that task */ 848c2ecf20Sopenharmony_ci tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum); 858c2ecf20Sopenharmony_ci if (!tsk->irq) 868c2ecf20Sopenharmony_ci goto error; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Init the BDs, if needed */ 898c2ecf20Sopenharmony_ci if (bd_count) { 908c2ecf20Sopenharmony_ci tsk->cookie = kmalloc_array(bd_count, sizeof(void *), 918c2ecf20Sopenharmony_ci GFP_KERNEL); 928c2ecf20Sopenharmony_ci if (!tsk->cookie) 938c2ecf20Sopenharmony_ci goto error; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa); 968c2ecf20Sopenharmony_ci if (!tsk->bd) 978c2ecf20Sopenharmony_ci goto error; 988c2ecf20Sopenharmony_ci memset_io(tsk->bd, 0x00, bd_count * bd_size); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci tsk->num_bd = bd_count; 1018c2ecf20Sopenharmony_ci tsk->bd_size = bd_size; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return tsk; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cierror: 1078c2ecf20Sopenharmony_ci if (tsk) { 1088c2ecf20Sopenharmony_ci if (tsk->irq) 1098c2ecf20Sopenharmony_ci irq_dispose_mapping(tsk->irq); 1108c2ecf20Sopenharmony_ci bcom_sram_free(tsk->bd); 1118c2ecf20Sopenharmony_ci kfree(tsk->cookie); 1128c2ecf20Sopenharmony_ci kfree(tsk); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci bcom_eng->tdt[tasknum].stop = 0; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return NULL; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_task_alloc); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_civoid 1228c2ecf20Sopenharmony_cibcom_task_free(struct bcom_task *tsk) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci /* Stop the task */ 1258c2ecf20Sopenharmony_ci bcom_disable_task(tsk->tasknum); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Clear TDT */ 1288c2ecf20Sopenharmony_ci bcom_eng->tdt[tsk->tasknum].start = 0; 1298c2ecf20Sopenharmony_ci bcom_eng->tdt[tsk->tasknum].stop = 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Free everything */ 1328c2ecf20Sopenharmony_ci irq_dispose_mapping(tsk->irq); 1338c2ecf20Sopenharmony_ci bcom_sram_free(tsk->bd); 1348c2ecf20Sopenharmony_ci kfree(tsk->cookie); 1358c2ecf20Sopenharmony_ci kfree(tsk); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_task_free); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciint 1408c2ecf20Sopenharmony_cibcom_load_image(int task, u32 *task_image) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct bcom_task_header *hdr = (struct bcom_task_header *)task_image; 1438c2ecf20Sopenharmony_ci struct bcom_tdt *tdt; 1448c2ecf20Sopenharmony_ci u32 *desc, *var, *inc; 1458c2ecf20Sopenharmony_ci u32 *desc_src, *var_src, *inc_src; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Safety checks */ 1488c2ecf20Sopenharmony_ci if (hdr->magic != BCOM_TASK_MAGIC) { 1498c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME 1508c2ecf20Sopenharmony_ci ": Trying to load invalid microcode\n"); 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if ((task < 0) || (task >= BCOM_MAX_TASKS)) { 1558c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME 1568c2ecf20Sopenharmony_ci ": Trying to load invalid task %d\n", task); 1578c2ecf20Sopenharmony_ci return -EINVAL; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Initial load or reload */ 1618c2ecf20Sopenharmony_ci tdt = &bcom_eng->tdt[task]; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (tdt->start) { 1648c2ecf20Sopenharmony_ci desc = bcom_task_desc(task); 1658c2ecf20Sopenharmony_ci if (hdr->desc_size != bcom_task_num_descs(task)) { 1668c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME 1678c2ecf20Sopenharmony_ci ": Trying to reload wrong task image " 1688c2ecf20Sopenharmony_ci "(%d size %d/%d)!\n", 1698c2ecf20Sopenharmony_ci task, 1708c2ecf20Sopenharmony_ci hdr->desc_size, 1718c2ecf20Sopenharmony_ci bcom_task_num_descs(task)); 1728c2ecf20Sopenharmony_ci return -EINVAL; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } else { 1758c2ecf20Sopenharmony_ci phys_addr_t start_pa; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa); 1788c2ecf20Sopenharmony_ci if (!desc) 1798c2ecf20Sopenharmony_ci return -ENOMEM; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci tdt->start = start_pa; 1828c2ecf20Sopenharmony_ci tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32)); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci var = bcom_task_var(task); 1868c2ecf20Sopenharmony_ci inc = bcom_task_inc(task); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Clear & copy */ 1898c2ecf20Sopenharmony_ci memset_io(var, 0x00, BCOM_VAR_SIZE); 1908c2ecf20Sopenharmony_ci memset_io(inc, 0x00, BCOM_INC_SIZE); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci desc_src = (u32 *)(hdr + 1); 1938c2ecf20Sopenharmony_ci var_src = desc_src + hdr->desc_size; 1948c2ecf20Sopenharmony_ci inc_src = var_src + hdr->var_size; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci memcpy_toio(desc, desc_src, hdr->desc_size * sizeof(u32)); 1978c2ecf20Sopenharmony_ci memcpy_toio(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32)); 1988c2ecf20Sopenharmony_ci memcpy_toio(inc, inc_src, hdr->inc_size * sizeof(u32)); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_load_image); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_civoid 2058c2ecf20Sopenharmony_cibcom_set_initiator(int task, int initiator) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci int i; 2088c2ecf20Sopenharmony_ci int num_descs; 2098c2ecf20Sopenharmony_ci u32 *desc; 2108c2ecf20Sopenharmony_ci int next_drd_has_initiator; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci bcom_set_tcr_initiator(task, initiator); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Just setting tcr is apparently not enough due to some problem */ 2158c2ecf20Sopenharmony_ci /* with it. So we just go thru all the microcode and replace in */ 2168c2ecf20Sopenharmony_ci /* the DRD directly */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci desc = bcom_task_desc(task); 2198c2ecf20Sopenharmony_ci next_drd_has_initiator = 1; 2208c2ecf20Sopenharmony_ci num_descs = bcom_task_num_descs(task); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci for (i=0; i<num_descs; i++, desc++) { 2238c2ecf20Sopenharmony_ci if (!bcom_desc_is_drd(*desc)) 2248c2ecf20Sopenharmony_ci continue; 2258c2ecf20Sopenharmony_ci if (next_drd_has_initiator) 2268c2ecf20Sopenharmony_ci if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS) 2278c2ecf20Sopenharmony_ci bcom_set_desc_initiator(desc, initiator); 2288c2ecf20Sopenharmony_ci next_drd_has_initiator = !bcom_drd_is_extended(*desc); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_set_initiator); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* Public API */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_civoid 2378c2ecf20Sopenharmony_cibcom_enable(struct bcom_task *tsk) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci bcom_enable_task(tsk->tasknum); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_enable); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_civoid 2448c2ecf20Sopenharmony_cibcom_disable(struct bcom_task *tsk) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci bcom_disable_task(tsk->tasknum); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_disable); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/* ======================================================================== */ 2528c2ecf20Sopenharmony_ci/* Engine init/cleanup */ 2538c2ecf20Sopenharmony_ci/* ======================================================================== */ 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* Function Descriptor table */ 2568c2ecf20Sopenharmony_ci/* this will need to be updated if Freescale changes their task code FDT */ 2578c2ecf20Sopenharmony_cistatic u32 fdt_ops[] = { 2588c2ecf20Sopenharmony_ci 0xa0045670, /* FDT[48] - load_acc() */ 2598c2ecf20Sopenharmony_ci 0x80045670, /* FDT[49] - unload_acc() */ 2608c2ecf20Sopenharmony_ci 0x21800000, /* FDT[50] - and() */ 2618c2ecf20Sopenharmony_ci 0x21e00000, /* FDT[51] - or() */ 2628c2ecf20Sopenharmony_ci 0x21500000, /* FDT[52] - xor() */ 2638c2ecf20Sopenharmony_ci 0x21400000, /* FDT[53] - andn() */ 2648c2ecf20Sopenharmony_ci 0x21500000, /* FDT[54] - not() */ 2658c2ecf20Sopenharmony_ci 0x20400000, /* FDT[55] - add() */ 2668c2ecf20Sopenharmony_ci 0x20500000, /* FDT[56] - sub() */ 2678c2ecf20Sopenharmony_ci 0x20800000, /* FDT[57] - lsh() */ 2688c2ecf20Sopenharmony_ci 0x20a00000, /* FDT[58] - rsh() */ 2698c2ecf20Sopenharmony_ci 0xc0170000, /* FDT[59] - crc8() */ 2708c2ecf20Sopenharmony_ci 0xc0145670, /* FDT[60] - crc16() */ 2718c2ecf20Sopenharmony_ci 0xc0345670, /* FDT[61] - crc32() */ 2728c2ecf20Sopenharmony_ci 0xa0076540, /* FDT[62] - endian32() */ 2738c2ecf20Sopenharmony_ci 0xa0000760, /* FDT[63] - endian16() */ 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int bcom_engine_init(void) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int task; 2808c2ecf20Sopenharmony_ci phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; 2818c2ecf20Sopenharmony_ci unsigned int tdt_size, ctx_size, var_size, fdt_size; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ 2848c2ecf20Sopenharmony_ci tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); 2858c2ecf20Sopenharmony_ci ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE; 2868c2ecf20Sopenharmony_ci var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE); 2878c2ecf20Sopenharmony_ci fdt_size = BCOM_FDT_SIZE; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa); 2908c2ecf20Sopenharmony_ci bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa); 2918c2ecf20Sopenharmony_ci bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa); 2928c2ecf20Sopenharmony_ci bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) { 2958c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n"); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->tdt); 2988c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->ctx); 2998c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->var); 3008c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->fdt); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return -ENOMEM; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci memset_io(bcom_eng->tdt, 0x00, tdt_size); 3068c2ecf20Sopenharmony_ci memset_io(bcom_eng->ctx, 0x00, ctx_size); 3078c2ecf20Sopenharmony_ci memset_io(bcom_eng->var, 0x00, var_size); 3088c2ecf20Sopenharmony_ci memset_io(bcom_eng->fdt, 0x00, fdt_size); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Copy the FDT for the EU#3 */ 3118c2ecf20Sopenharmony_ci memcpy_toio(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops)); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Initialize Task base structure */ 3148c2ecf20Sopenharmony_ci for (task=0; task<BCOM_MAX_TASKS; task++) 3158c2ecf20Sopenharmony_ci { 3168c2ecf20Sopenharmony_ci out_be16(&bcom_eng->regs->tcr[task], 0); 3178c2ecf20Sopenharmony_ci out_8(&bcom_eng->regs->ipr[task], 0); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci bcom_eng->tdt[task].context = ctx_pa; 3208c2ecf20Sopenharmony_ci bcom_eng->tdt[task].var = var_pa; 3218c2ecf20Sopenharmony_ci bcom_eng->tdt[task].fdt = fdt_pa; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE; 3248c2ecf20Sopenharmony_ci ctx_pa += BCOM_CTX_SIZE; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci out_be32(&bcom_eng->regs->taskBar, tdt_pa); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Init 'always' initiator */ 3308c2ecf20Sopenharmony_ci out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Disable COMM Bus Prefetch on the original 5200; it's broken */ 3338c2ecf20Sopenharmony_ci if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) 3348c2ecf20Sopenharmony_ci bcom_disable_prefetch(); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Init lock */ 3378c2ecf20Sopenharmony_ci spin_lock_init(&bcom_eng->lock); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void 3438c2ecf20Sopenharmony_cibcom_engine_cleanup(void) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int task; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Stop all tasks */ 3488c2ecf20Sopenharmony_ci for (task=0; task<BCOM_MAX_TASKS; task++) 3498c2ecf20Sopenharmony_ci { 3508c2ecf20Sopenharmony_ci out_be16(&bcom_eng->regs->tcr[task], 0); 3518c2ecf20Sopenharmony_ci out_8(&bcom_eng->regs->ipr[task], 0); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci out_be32(&bcom_eng->regs->taskBar, 0ul); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Release the SRAM zones */ 3578c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->tdt); 3588c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->ctx); 3598c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->var); 3608c2ecf20Sopenharmony_ci bcom_sram_free(bcom_eng->fdt); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/* ======================================================================== */ 3658c2ecf20Sopenharmony_ci/* OF platform driver */ 3668c2ecf20Sopenharmony_ci/* ======================================================================== */ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int mpc52xx_bcom_probe(struct platform_device *op) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct device_node *ofn_sram; 3718c2ecf20Sopenharmony_ci struct resource res_bcom; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci int rv; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Inform user we're ok so far */ 3768c2ecf20Sopenharmony_ci printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Get the bestcomm node */ 3798c2ecf20Sopenharmony_ci of_node_get(op->dev.of_node); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Prepare SRAM */ 3828c2ecf20Sopenharmony_ci ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids); 3838c2ecf20Sopenharmony_ci if (!ofn_sram) { 3848c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME ": " 3858c2ecf20Sopenharmony_ci "No SRAM found in device tree\n"); 3868c2ecf20Sopenharmony_ci rv = -ENODEV; 3878c2ecf20Sopenharmony_ci goto error_ofput; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci rv = bcom_sram_init(ofn_sram, DRIVER_NAME); 3908c2ecf20Sopenharmony_ci of_node_put(ofn_sram); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (rv) { 3938c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME ": " 3948c2ecf20Sopenharmony_ci "Error in SRAM init\n"); 3958c2ecf20Sopenharmony_ci goto error_ofput; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* Get a clean struct */ 3998c2ecf20Sopenharmony_ci bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL); 4008c2ecf20Sopenharmony_ci if (!bcom_eng) { 4018c2ecf20Sopenharmony_ci rv = -ENOMEM; 4028c2ecf20Sopenharmony_ci goto error_sramclean; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Save the node */ 4068c2ecf20Sopenharmony_ci bcom_eng->ofnode = op->dev.of_node; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Get, reserve & map io */ 4098c2ecf20Sopenharmony_ci if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) { 4108c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME ": " 4118c2ecf20Sopenharmony_ci "Can't get resource\n"); 4128c2ecf20Sopenharmony_ci rv = -EINVAL; 4138c2ecf20Sopenharmony_ci goto error_sramclean; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!request_mem_region(res_bcom.start, resource_size(&res_bcom), 4178c2ecf20Sopenharmony_ci DRIVER_NAME)) { 4188c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME ": " 4198c2ecf20Sopenharmony_ci "Can't request registers region\n"); 4208c2ecf20Sopenharmony_ci rv = -EBUSY; 4218c2ecf20Sopenharmony_ci goto error_sramclean; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci bcom_eng->regs_base = res_bcom.start; 4258c2ecf20Sopenharmony_ci bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma)); 4268c2ecf20Sopenharmony_ci if (!bcom_eng->regs) { 4278c2ecf20Sopenharmony_ci printk(KERN_ERR DRIVER_NAME ": " 4288c2ecf20Sopenharmony_ci "Can't map registers\n"); 4298c2ecf20Sopenharmony_ci rv = -ENOMEM; 4308c2ecf20Sopenharmony_ci goto error_release; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Now, do the real init */ 4348c2ecf20Sopenharmony_ci rv = bcom_engine_init(); 4358c2ecf20Sopenharmony_ci if (rv) 4368c2ecf20Sopenharmony_ci goto error_unmap; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Done ! */ 4398c2ecf20Sopenharmony_ci printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n", 4408c2ecf20Sopenharmony_ci (long)bcom_eng->regs_base); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Error path */ 4458c2ecf20Sopenharmony_cierror_unmap: 4468c2ecf20Sopenharmony_ci iounmap(bcom_eng->regs); 4478c2ecf20Sopenharmony_cierror_release: 4488c2ecf20Sopenharmony_ci release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma)); 4498c2ecf20Sopenharmony_cierror_sramclean: 4508c2ecf20Sopenharmony_ci kfree(bcom_eng); 4518c2ecf20Sopenharmony_ci bcom_sram_cleanup(); 4528c2ecf20Sopenharmony_cierror_ofput: 4538c2ecf20Sopenharmony_ci of_node_put(op->dev.of_node); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n"); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return rv; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int mpc52xx_bcom_remove(struct platform_device *op) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci /* Clean up the engine */ 4648c2ecf20Sopenharmony_ci bcom_engine_cleanup(); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Cleanup SRAM */ 4678c2ecf20Sopenharmony_ci bcom_sram_cleanup(); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Release regs */ 4708c2ecf20Sopenharmony_ci iounmap(bcom_eng->regs); 4718c2ecf20Sopenharmony_ci release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma)); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Release the node */ 4748c2ecf20Sopenharmony_ci of_node_put(bcom_eng->ofnode); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Release memory */ 4778c2ecf20Sopenharmony_ci kfree(bcom_eng); 4788c2ecf20Sopenharmony_ci bcom_eng = NULL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic const struct of_device_id mpc52xx_bcom_of_match[] = { 4848c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc5200-bestcomm", }, 4858c2ecf20Sopenharmony_ci { .compatible = "mpc5200-bestcomm", }, 4868c2ecf20Sopenharmony_ci {}, 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic struct platform_driver mpc52xx_bcom_of_platform_driver = { 4938c2ecf20Sopenharmony_ci .probe = mpc52xx_bcom_probe, 4948c2ecf20Sopenharmony_ci .remove = mpc52xx_bcom_remove, 4958c2ecf20Sopenharmony_ci .driver = { 4968c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 4978c2ecf20Sopenharmony_ci .of_match_table = mpc52xx_bcom_of_match, 4988c2ecf20Sopenharmony_ci }, 4998c2ecf20Sopenharmony_ci}; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/* ======================================================================== */ 5038c2ecf20Sopenharmony_ci/* Module */ 5048c2ecf20Sopenharmony_ci/* ======================================================================== */ 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int __init 5078c2ecf20Sopenharmony_cimpc52xx_bcom_init(void) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci return platform_driver_register(&mpc52xx_bcom_of_platform_driver); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void __exit 5138c2ecf20Sopenharmony_cimpc52xx_bcom_exit(void) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci platform_driver_unregister(&mpc52xx_bcom_of_platform_driver); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/* If we're not a module, we must make sure everything is setup before */ 5198c2ecf20Sopenharmony_ci/* anyone tries to use us ... that's why we use subsys_initcall instead */ 5208c2ecf20Sopenharmony_ci/* of module_init. */ 5218c2ecf20Sopenharmony_cisubsys_initcall(mpc52xx_bcom_init); 5228c2ecf20Sopenharmony_cimodule_exit(mpc52xx_bcom_exit); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); 5258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); 5268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); 5278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>"); 5288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5298c2ecf20Sopenharmony_ci 530