From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from nommos.sslcatacombnetworking.com (nommos.sslcatacombnetworking.com [67.18.224.114]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTP id 8B5ADDDEC1 for ; Wed, 16 May 2007 07:38:55 +1000 (EST) In-Reply-To: <11790019234031-git-send-email-tnt@246tNt.com> References: <11790019171838-git-send-email-tnt@246tNt.com> <11790019223299-git-send-email-tnt@246tNt.com> <11790019223880-git-send-email-tnt@246tNt.com> <11790019223925-git-send-email-tnt@246tNt.com> <11790019234031-git-send-email-tnt@246tNt.com> Mime-Version: 1.0 (Apple Message framework v752.2) Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed Message-Id: <781A28BA-63E5-41C4-93F7-B5C004F526AD@kernel.crashing.org> From: Kumar Gala Subject: Re: [PATCH 4/9] powerpc: BestComm core support for Freescale MPC5200 Date: Tue, 15 May 2007 16:37:53 -0500 To: Sylvain Munaut Cc: Linux PPC dev ML List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , On May 12, 2007, at 3:31 PM, Sylvain Munaut wrote: > This patch adds support for the core of the BestComm API > for the Freescale MPC5200(b). The BestComm engine is a > microcode-controlled / tasks-based DMA used by several > of the onchip devices. > > Setting up the tasks / memory allocation and all common > low level functions are handled by this patch. > The specifics details of each tasks and their microcode > are split-out in separate patches. > > This is not the official API, but a much cleaner one. Can you give more detail about how the API works. > Signed-off-by: Sylvain Munaut > --- > arch/powerpc/platforms/Kconfig | 2 + > arch/powerpc/sysdev/Makefile | 1 + > arch/powerpc/sysdev/bestcomm/Kconfig | 18 + > arch/powerpc/sysdev/bestcomm/Makefile | 8 + > arch/powerpc/sysdev/bestcomm/bestcomm.c | 600 +++++++++++++++ > +++++++++++ > arch/powerpc/sysdev/bestcomm/bestcomm.h | 136 ++++++ > arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | 325 ++++++++++++++ > arch/powerpc/sysdev/bestcomm/sram.c | 180 ++++++++ > arch/powerpc/sysdev/bestcomm/sram.h | 54 +++ > 9 files changed, 1324 insertions(+), 0 deletions(-) > create mode 100644 arch/powerpc/sysdev/bestcomm/Kconfig > create mode 100644 arch/powerpc/sysdev/bestcomm/Makefile > create mode 100644 arch/powerpc/sysdev/bestcomm/bestcomm.c > create mode 100644 arch/powerpc/sysdev/bestcomm/bestcomm.h > create mode 100644 arch/powerpc/sysdev/bestcomm/bestcomm_priv.h > create mode 100644 arch/powerpc/sysdev/bestcomm/sram.c > create mode 100644 arch/powerpc/sysdev/bestcomm/sram.h > > diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/ > platforms/Kconfig > index 8432f56..fc170a3 100644 > --- a/arch/powerpc/platforms/Kconfig > +++ b/arch/powerpc/platforms/Kconfig > @@ -259,4 +259,6 @@ config CPM2 > you wish to build a kernel for a machine with a CPM2 coprocessor > on it (826x, 827x, 8560). > > +source "arch/powerpc/sysdev/bestcomm/Kconfig" > + > endmenu > diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/ > Makefile > index c3ce0bd..89074f8 100644 > --- a/arch/powerpc/sysdev/Makefile > +++ b/arch/powerpc/sysdev/Makefile > @@ -16,6 +16,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o > obj-$(CONFIG_FSL_PCIE) += fsl_pcie.o > obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o > obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ > +obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ > mv64x60-$(CONFIG_PCI) += mv64x60_pci.o > obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o > > diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/ > sysdev/bestcomm/Kconfig > new file mode 100644 > index 0000000..3366e24 > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/Kconfig > @@ -0,0 +1,18 @@ > +# > +# Kconfig options for Bestcomm > +# > + > +config PPC_BESTCOMM > + tristate "Bestcomm DMA engine support" > + depends on PPC_MPC52xx > + default n > + select PPC_LIB_RHEAP > + help > + BestComm is the name of the communication coprocessor found > + on the Freescale MPC5200 family of processor. It's usage is > + optionnal for some drivers (like ATA), but required for > + others (like FEC). > + > + If you want to use drivers that require DMA operations, > + answer Y or M. Otherwise say N. > + > diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/ > sysdev/bestcomm/Makefile > new file mode 100644 > index 0000000..a24aa06 > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/Makefile > @@ -0,0 +1,8 @@ > +# > +# Makefile for BestComm & co > +# > + > +bestcomm-core-objs := bestcomm.o sram.o > + > +obj-$(CONFIG_PPC_BESTCOMM) += bestcomm-core.o Any reason why sram isn't on the ojb-$(CONFIG_PPC_BESTCOMM) line? > + > diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/ > sysdev/bestcomm/bestcomm.c > new file mode 100644 > index 0000000..0063a1e > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c > @@ -0,0 +1,600 @@ > +/* > + * Driver for MPC52xx processor BestComm peripheral controller > + * > + * > + * Copyright (C) 2006-2007 Sylvain Munaut > + * Copyright (C) 2005 Varma Electronics Oy, > + * ( by Andrey Volkov el.com> ) > + * Copyright (C) 2003-2004 MontaVista, Software, Inc. > + * ( by Dale Farnsworth > ) > + * > + * This file is licensed under the terms of the GNU General Public > License > + * version 2. This program is licensed "as is" without any > warranty of any > + * kind, whether express or implied. > + */ > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#include "sram.h" > +#include "bestcomm_priv.h" > +#include "bestcomm.h" > + > +#define DRIVER_NAME "bestcomm-core" > + > + > +struct bcom_engine *bcom = NULL; > + > + > +/* > ====================================================================== > == */ > +/* Public and private > API */ > +/* > ====================================================================== > == */ > + > +/* Debug Dump */ > + > +#define BCOM_DPRINTK(a,b...) printk(KERN_DEBUG DRIVER_NAME ": " a, > ## b) We have dev_dbg and dev_printk can we not use them? > + > +void > +bcom_dump_status(void) > +{ > + int i; > + struct mpc52xx_sdma __iomem *r = bcom->regs; > + > + BCOM_DPRINTK("BestComm status dump (pa=%08lx, va=%p)\n", > + bcom->regs_base, bcom->regs); > + BCOM_DPRINTK(" taskBar = %08x\n", in_be32(&r->taskBar)); > + BCOM_DPRINTK(" currentPointer = %08x\n", in_be32(&r- > >currentPointer)); > + BCOM_DPRINTK(" endPointer = %08x\n", in_be32(&r->endPointer)); > + BCOM_DPRINTK(" variablePointer = %08x\n", in_be32(&r- > >variablePointer)); > + BCOM_DPRINTK(" IntVect1 = %08x\n", (u32)in_8(&r->IntVect1)); > + BCOM_DPRINTK(" IntVect2 = %08x\n", (u32)in_8(&r->IntVect2)); > + BCOM_DPRINTK(" PtdCntrl = %08hx\n", in_be16(&r->PtdCntrl)); > + BCOM_DPRINTK(" IntPend = %08x\n", in_be32(&r->IntPend)); > + BCOM_DPRINTK(" IntMask = %08x\n", in_be32(&r->IntMask)); > + > + BCOM_DPRINTK(" TCR dump :\n"); > + > + for (i=0; i<16; i++) { > + printk("%s%04hx%s", > + (i&0x7) == 0x0 ? KERN_DEBUG "\t" : "", > + in_be16(&r->tcr[i]), > + (i&0x7) == 0x7 ? "\n" : " "); > + } > + > + BCOM_DPRINTK(" IPR dump :\n"); > + > + for (i=0; i<32; i++) { > + printk("%s%02x%s", > + (i&0x7) == 0x0 ? KERN_DEBUG "\t" : "", > + (u32)in_8(&r->ipr[i]), > + (i&0x7) == 0x7 ? "\n" : " "); > + } > + > + BCOM_DPRINTK(" cReqSelect = %08x\n", in_be32(&r->cReqSelect)); > + BCOM_DPRINTK(" task_size0 = %08x\n", in_be32(&r->task_size0)); > + BCOM_DPRINTK(" task_size1 = %08x\n", in_be32(&r->task_size1)); > + BCOM_DPRINTK(" MDEDebug = %08x\n", in_be32(&r->MDEDebug)); > + BCOM_DPRINTK(" ADSDebug = %08x\n", in_be32(&r->ADSDebug)); > + BCOM_DPRINTK(" Value1 = %08x\n", in_be32(&r->Value1)); > + BCOM_DPRINTK(" Value2 = %08x\n", in_be32(&r->Value2)); > + BCOM_DPRINTK(" Control = %08x\n", in_be32(&r->Control)); > + BCOM_DPRINTK(" Status = %08x\n", in_be32(&r->Status)); > + BCOM_DPRINTK(" PTDDebug = %08x\n", in_be32(&r->PTDDebug)); > +} > + > +void > +bcom_dump_task(int task) > +{ > + int i; > + u32 *p; > + struct bcom_tdt *tdt = &bcom->tdt[task]; > + > + BCOM_DPRINTK("Task dump %d\n", task); > + BCOM_DPRINTK(" tcr = %04hx\n", bcom->regs->tcr[task]); > + BCOM_DPRINTK(" tdt = %p\n", &bcom->tdt[task]); > + BCOM_DPRINTK(" tdt->start = %08x\n", tdt->start); > + BCOM_DPRINTK(" tdt->stop = %08x\n", tdt->stop); > + BCOM_DPRINTK(" tdt->var = %08x\n", tdt->var); > + BCOM_DPRINTK(" tdt->fdt = %08x\n", tdt->fdt); > + BCOM_DPRINTK(" tdt->status = %08x\n", tdt->exec_status); > + BCOM_DPRINTK(" tdt->mvtp = %08x\n", tdt->mvtp); > + BCOM_DPRINTK(" tdt->context = %08x\n", tdt->context); > + BCOM_DPRINTK(" tdt->litbase = %08x\n", tdt->litbase); > + > + BCOM_DPRINTK(" code :\n"); > + > + p = bcom_task_desc(task); > + for (i=0; i + printk(KERN_DEBUG "\t%p %08x\n", &p[i], p[i]); > + > + BCOM_DPRINTK(" var/inc :\n"); > + > + p = bcom_task_var(task); > + for (i=0; i + printk(KERN_DEBUG "\t%p %08x\n", &p[i], p[i]); > +} > + > +void > +bcom_dump_bdring(struct bcom_task *tsk) > +{ > + int i, j; > + > + BCOM_DPRINTK("BD ring dump %d\n", tsk->tasknum); > + > + for (i=0; inum_bd; i++) { > + BCOM_DPRINTK(" BD[%02d] :\n", i); > + BCOM_DPRINTK(" cookie : %p\n", tsk->cookie[i]); > + BCOM_DPRINTK(" status : %08x\n", tsk->bd[i].status); > + for (j=0; j<(tsk->bd_size/sizeof(u32))-1; j++) > + BCOM_DPRINTK(" data[%02d] : %08x\n", > + j, tsk->bd[i].data[j]); > + } > +} > + > + Would all bcom_dump_status(), bcom_dump_task(), bcom_dump_bdring be better using debugfs? At minimum there should be a Kconfig option to enable bestcomm debug that enables this code. > +/* Private API */ > + What's private about it? It would probably be good for the API functions to have DocBook style comments. See something like drivers/rapidio/rio.c for an example. > +struct bcom_task * > +bcom_task_alloc(int bd_count, int bd_size, int priv_size) > +{ > + int i, tasknum = -1; > + struct bcom_task *tsk; > + > + /* Get and reserve a task num */ > + spin_lock(&bcom->lock); > + > + for (i=0; i + if (!bcom->tdt[i].stop) { /* we use stop as a marker */ > + bcom->tdt[i].stop = 0xfffffffful; /* dummy addr */ > + tasknum = i; > + break; > + } > + > + spin_unlock(&bcom->lock); > + > + if (tasknum < 0) > + return NULL; > + > + /* Allocate our structure */ > + tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL); > + if (!tsk) > + goto error; > + > + tsk->tasknum = tasknum; > + if (priv_size) > + tsk->priv = (void*)tsk + sizeof(struct bcom_task); > + > + /* Get IRQ of that task */ > + tsk->irq = irq_of_parse_and_map(bcom->ofnode, tsk->tasknum); > + if (tsk->irq == NO_IRQ) > + goto error; > + > + /* Init the BDs, if needed */ > + if (bd_count) { > + tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL); > + if (!tsk->cookie) > + goto error; > + > + tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa); > + if (!tsk->bd) > + goto error; > + memset(tsk->bd, 0x00, bd_count * bd_size); > + > + tsk->num_bd = bd_count; > + tsk->bd_size = bd_size; > + } > + > + return tsk; > + > +error: > + if (tsk) { > + if (tsk->irq != NO_IRQ) > + irq_dispose_mapping(tsk->irq); > + bcom_sram_free(tsk->bd); > + kfree(tsk->cookie); > + kfree(tsk); > + } > + > + bcom->tdt[tasknum].stop = 0; > + > + return NULL; > +} > + > +void > +bcom_task_release(struct bcom_task *tsk) bcom_task_free() to match alloc/free semantics? > +{ > + /* Stop the task */ > + bcom_disable_task(tsk->tasknum); > + > + /* Clear TDT */ > + bcom->tdt[tsk->tasknum].start = 0; > + bcom->tdt[tsk->tasknum].stop = 0; > + > + /* Free everything */ > + irq_dispose_mapping(tsk->irq); > + bcom_sram_free(tsk->bd); > + kfree(tsk->cookie); > + kfree(tsk); > +} > + > +int > +bcom_load_image(int task, u32 *task_image) > +{ > + struct bcom_task_header *hdr = (struct bcom_task_header *) > task_image; > + struct bcom_tdt *tdt; > + u32 *desc, *var, *inc; > + u32 *desc_src, *var_src, *inc_src; > + > + /* Safety checks */ > + if (hdr->magic != BCOM_TASK_MAGIC) { > + printk(KERN_ERR DRIVER_NAME > + ": Trying to load invalid microcode\n"); > + return -EINVAL; > + } > + > + if ((task < 0) || (task >= BCOM_MAX_TASKS)) { > + printk(KERN_ERR DRIVER_NAME > + ": Trying to load invalid task %d\n", task); > + return -EINVAL; > + } > + > + /* Initial load or reload */ > + tdt = &bcom->tdt[task]; > + > + if (tdt->start) { > + desc = bcom_task_desc(task); > + if (hdr->desc_size != bcom_task_num_descs(task)) { > + printk(KERN_ERR DRIVER_NAME > + ": Trying to reload wrong task image " > + "(%d size %d/%d)!\n", > + task, > + hdr->desc_size, > + bcom_task_num_descs(task)); > + return -EINVAL; > + } > + } else { > + phys_addr_t start_pa; > + > + desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa); > + if (!desc) > + return -ENOMEM; > + > + tdt->start = start_pa; > + tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32)); > + } > + > + var = bcom_task_var(task); > + inc = bcom_task_inc(task); > + > + /* Clear & copy */ > + memset(var, 0x00, BCOM_VAR_SIZE); > + memset(inc, 0x00, BCOM_INC_SIZE); > + > + desc_src = (u32 *)(hdr + 1); > + var_src = desc_src + hdr->desc_size; > + inc_src = var_src + hdr->var_size; > + > + memcpy(desc, desc_src, hdr->desc_size * sizeof(u32)); > + memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32)); > + memcpy(inc, inc_src, hdr->inc_size * sizeof(u32)); > + > + return 0; > +} > + > +void > +bcom_set_initiator(int task, int initiator) > +{ > + int i; > + int num_descs; > + u32 *desc; > + int next_drd_has_initiator; > + > + bcom_set_tcr_initiator(task, initiator); > + > + /* Just setting tcr is apparently not enough due to some problem */ > + /* with it. So we just go thru all the microcode and replace in */ > + /* the DRD directly */ > + > + desc = bcom_task_desc(task); > + next_drd_has_initiator = 1; > + num_descs = bcom_task_num_descs(task); > + > + for (i=0; i + if (!bcom_desc_is_drd(*desc)) > + continue; > + if (next_drd_has_initiator) > + if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS) > + bcom_set_desc_initiator(desc, initiator); > + next_drd_has_initiator = !bcom_drd_is_extended(*desc); > + } > +} > + > + > +/* Public API */ > + What's public about these? > +void > +bcom_enable(struct bcom_task *tsk) > +{ > + bcom_enable_task(tsk->tasknum); > +} > + > +void > +bcom_disable(struct bcom_task *tsk) > +{ > + bcom_disable_task(tsk->tasknum); > +} > + > + > +/* > ====================================================================== > == */ > +/* Engine init/ > cleanup */ > +/* > ====================================================================== > == */ > + > +/* Function Descriptor table */ > +/* this will need to be updated if Freescale changes their task > code FDT */ > +static u32 fdt_ops[] = { > + 0xa0045670, /* FDT[48] - load_acc() */ > + 0x80045670, /* FDT[49] - unload_acc() */ > + 0x21800000, /* FDT[50] - and() */ > + 0x21e00000, /* FDT[51] - or() */ > + 0x21500000, /* FDT[52] - xor() */ > + 0x21400000, /* FDT[53] - andn() */ > + 0x21500000, /* FDT[54] - not() */ > + 0x20400000, /* FDT[55] - add() */ > + 0x20500000, /* FDT[56] - sub() */ > + 0x20800000, /* FDT[57] - lsh() */ > + 0x20a00000, /* FDT[58] - rsh() */ > + 0xc0170000, /* FDT[59] - crc8() */ > + 0xc0145670, /* FDT[60] - crc16() */ > + 0xc0345670, /* FDT[61] - crc32() */ > + 0xa0076540, /* FDT[62] - endian32() */ > + 0xa0000760, /* FDT[63] - endian16() */ > +}; > + > + > +static int __devinit > +bcom_engine_init(void) > +{ > + int task; > + phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; > + unsigned int tdt_size, ctx_size, var_size, fdt_size; > + > + /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/ > incs */ > + tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); > + ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE; > + var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE); > + fdt_size = BCOM_FDT_SIZE; > + > + bcom->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa); > + bcom->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa); > + bcom->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa); > + bcom->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa); > + > + if (!bcom->tdt || !bcom->ctx || !bcom->var || !bcom->fdt) { > + printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n"); > + > + bcom_sram_free(bcom->tdt); > + bcom_sram_free(bcom->ctx); > + bcom_sram_free(bcom->var); > + bcom_sram_free(bcom->fdt); > + > + return -ENOMEM; > + } > + > + memset(bcom->tdt, 0x00, tdt_size); > + memset(bcom->ctx, 0x00, ctx_size); > + memset(bcom->var, 0x00, var_size); > + memset(bcom->fdt, 0x00, fdt_size); > + > + /* Copy the FDT for the EU#3 */ > + memcpy(&bcom->fdt[48], fdt_ops, sizeof(fdt_ops)); > + > + /* Initialize Task base structure */ > + for (task=0; task + { > + out_be16(&bcom->regs->tcr[task], 0); > + out_8(&bcom->regs->ipr[task], 0); > + > + bcom->tdt[task].context = ctx_pa; > + bcom->tdt[task].var = var_pa; > + bcom->tdt[task].fdt = fdt_pa; > + > + var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE; > + ctx_pa += BCOM_CTX_SIZE; > + } > + > + out_be32(&bcom->regs->taskBar, tdt_pa); > + > + /* Init 'always' initiator */ > + out_8(&bcom->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); > + > + /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ > + /* FIXME: This should be done on 5200 and not 5200B ... */ > + out_be16(&bcom->regs->PtdCntrl, in_be16(&bcom->regs->PtdCntrl) | 1); > + > + /* Init lock */ > + spin_lock_init(&bcom->lock); > + > + return 0; > +} > + > +static void > +bcom_engine_cleanup(void) > +{ > + int task; > + > + /* Stop all tasks */ > + for (task=0; task + { > + out_be16(&bcom->regs->tcr[task], 0); > + out_8(&bcom->regs->ipr[task], 0); > + } > + > + out_be32(&bcom->regs->taskBar, 0ul); > + > + /* Release the SRAM zones */ > + bcom_sram_free(bcom->tdt); > + bcom_sram_free(bcom->ctx); > + bcom_sram_free(bcom->var); > + bcom_sram_free(bcom->fdt); > +} > + > + > +/* > ====================================================================== > == */ > +/* System/Module init & > cleanup */ > +/* > ====================================================================== > == */ > + > +static int __init > +mpc52xx_bcom_init(void) > +{ > + struct device_node *ofn_bcom, *ofn_sram; > + struct resource res_bcom; > + > + int rv; > + > + /* Find the bestcomm node. If none, fails 'silently' since > + * we may just be on another platform */ > + ofn_bcom = of_find_compatible_node( > + NULL, "dma-controller", "mpc5200-bestcomm"); > + if (!ofn_bcom) > + return -ENODEV; > + > + /* Inform user we're ok so far */ > + printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); > + > + /* Prepare SRAM */ > + ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram"); > + if (!ofn_sram) { > + printk(KERN_ERR DRIVER_NAME ": " > + "No SRAM found in device tree\n"); > + rv = -ENODEV; > + goto error_ofput; > + } > + > + rv = bcom_sram_init(ofn_sram, DRIVER_NAME); > + > + of_node_put(ofn_sram); > + > + if (rv) { > + printk(KERN_ERR DRIVER_NAME ": " > + "Error in SRAM init\n"); > + goto error_ofput; > + } > + > + /* Get a clean struct */ > + bcom = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL); > + if (!bcom) { > + printk(KERN_ERR DRIVER_NAME ": " > + "Can't allocate state structure\n"); > + rv = -ENOMEM; > + goto error_sramclean; > + } > + > + /* Save the node */ > + bcom->ofnode = ofn_bcom; > + > + /* Get, reserve & map io */ > + if (of_address_to_resource(bcom->ofnode, 0, &res_bcom)) { > + printk(KERN_ERR DRIVER_NAME ": " > + "Can't get resource\n"); > + rv = -EINVAL; > + goto error_sramclean; > + } > + > + if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma), > + DRIVER_NAME)) { > + printk(KERN_ERR DRIVER_NAME ": " > + "Can't request registers region\n"); > + rv = -EBUSY; > + goto error_sramclean; > + } > + > + bcom->regs_base = res_bcom.start; > + bcom->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma)); > + if (!bcom->regs) { > + printk(KERN_ERR DRIVER_NAME ": " > + "Can't map registers\n"); > + rv = -ENOMEM; > + goto error_release; > + } > + > + /* Now, do the real init */ > + rv = bcom_engine_init(); > + if (rv) > + goto error_unmap; > + > + /* Done ! */ > + printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n", > + bcom->regs_base); > + > + return 0; > + > + /* Error path */ > +error_unmap: > + iounmap(bcom->regs); > +error_release: > + release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma)); > +error_sramclean: > + bcom_sram_cleanup(); > +error_ofput: > + of_node_put(bcom->ofnode); > + > + printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n"); > + > + return rv; > +} > + > +static void __exit > +mpc52xx_bcom_exit(void) > +{ > + /* Clean up the engine */ > + bcom_engine_cleanup(); > + > + /* Cleanup SRAM */ > + bcom_sram_cleanup(); > + > + /* Release regs */ > + iounmap(bcom->regs); > + release_mem_region(bcom->regs_base, sizeof(struct mpc52xx_sdma)); > + > + /* Release the node */ > + of_node_put(bcom->ofnode); > + > + /* Release memory */ > + kfree(bcom); > +} > + > +#ifdef MODULE > +module_init(mpc52xx_bcom_init); > +module_exit(mpc52xx_bcom_exit); > +#endif > + > +/* If we're not a module, we must make sure everything is setup > before anyone */ > +/* tries to use us ... */ > +#ifndef MODULE > +subsys_initcall(mpc52xx_bcom_init); > +#endif > + > +MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); > +MODULE_AUTHOR("Sylvain Munaut "); > +MODULE_AUTHOR("Andrey Volkov "); > +MODULE_AUTHOR("Dale Farnsworth "); > +MODULE_LICENSE("GPL v2"); > + > + > +EXPORT_SYMBOL(bcom); > +EXPORT_SYMBOL(bcom_dump_status); > +EXPORT_SYMBOL(bcom_dump_task); > +EXPORT_SYMBOL(bcom_dump_bdring); > +EXPORT_SYMBOL(bcom_task_alloc); > +EXPORT_SYMBOL(bcom_task_release); > +EXPORT_SYMBOL(bcom_load_image); > +EXPORT_SYMBOL(bcom_set_initiator); > +EXPORT_SYMBOL(bcom_enable); > +EXPORT_SYMBOL(bcom_disable); > + > diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/ > sysdev/bestcomm/bestcomm.h > new file mode 100644 > index 0000000..eac3eec > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h > @@ -0,0 +1,136 @@ > +/* > + * Public header for the MPC52xx processor BestComm driver > + * > + * > + * Copyright (C) 2006 Sylvain Munaut > + * Copyright (C) 2005 Varma Electronics Oy, > + * ( by Andrey Volkov el.com> ) > + * Copyright (C) 2003-2004 MontaVista, Software, Inc. > + * ( by Dale Farnsworth > ) > + * > + * This file is licensed under the terms of the GNU General Public > License > + * version 2. This program is licensed "as is" without any > warranty of any > + * kind, whether express or implied. > + */ > + > +#ifndef __BESTCOMM_H__ > +#define __BESTCOMM_H__ > + > +struct bcom_bd; /* defined later on ... */ > + > + > +/* > ====================================================================== > == */ > +/* Generic task > managment */ > +/* > ====================================================================== > == */ > + > +struct bcom_task { > + unsigned int tasknum; > + unsigned int flags; > + int irq; > + > + struct bcom_bd *bd; > + phys_addr_t bd_pa; > + void **cookie; > + unsigned short index; > + unsigned short outdex; > + unsigned int num_bd; > + unsigned int bd_size; > + > + void* priv; > +}; > + > +#define BCOM_FLAGS_NONE 0x00000000ul > +#define BCOM_FLAGS_ENABLE_TASK (1ul << 0) > + > + > +extern void bcom_enable(struct bcom_task *tsk); > +extern void bcom_disable(struct bcom_task *tsk); > + > +static inline int > +bcom_get_task_irq(struct bcom_task *tsk) { > + return tsk->irq; > +} > + > + > +/* Debug dumps */ > +extern void bcom_dump_status(void); > +extern void bcom_dump_task(int task); > +extern void bcom_dump_bdring(struct bcom_task *tsk); > + > + > +/* > ====================================================================== > == */ > +/* BD based tasks > helpers */ > +/* > ====================================================================== > == */ > + > +struct bcom_bd { > + u32 status; > + u32 data[1]; /* variable, but at least 1 */ > +}; > + > +#define BCOM_BD_READY 0x40000000ul > + > +static inline int /* user shouldn't use this ! */ > +_bcom_next_index(struct bcom_task *tsk) > +{ > + return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1; > +} > + > +static inline int /* user shouldn't use this ! */ > +_bcom_next_outdex(struct bcom_task *tsk) > +{ > + return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1; > +} > + > +static inline int > +bcom_queue_empty(struct bcom_task *tsk) > +{ > + return tsk->index == tsk->outdex; > +} > + > +static inline int > +bcom_queue_full(struct bcom_task *tsk) > +{ > + return tsk->outdex == _bcom_next_index(tsk); > +} > + > +static inline int > +bcom_buffer_done(struct bcom_task *tsk) > +{ > + if (bcom_queue_empty(tsk)) > + return 0; > + return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); > +} > + > +static inline struct bcom_bd * > +bcom_prepare_next_buffer(struct bcom_task *tsk) > +{ > + tsk->bd[tsk->index].status = 0; /* cleanup last status */ > + return &tsk->bd[tsk->index]; > +} > + > +static inline void > +bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) > +{ > + tsk->cookie[tsk->index] = cookie; > + mb(); /* ensure the bd is really up-to-date */ > + tsk->bd[tsk->index].status |= BCOM_BD_READY; > + tsk->index = _bcom_next_index(tsk); > + if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) > + bcom_enable(tsk); > +} > + > +static inline void * > +bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct > bcom_bd **p_bd) > +{ > + void *cookie = tsk->cookie[tsk->outdex]; > + if (p_status) > + *p_status = tsk->bd[tsk->outdex].status; > + if (p_bd) > + *p_bd = &tsk->bd[tsk->outdex]; > + tsk->outdex = _bcom_next_outdex(tsk); > + return cookie; > +} > + > + > +#endif /* __BESTCOMM_H__ */ > + > diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/ > powerpc/sysdev/bestcomm/bestcomm_priv.h > new file mode 100644 > index 0000000..d43b00a > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h > @@ -0,0 +1,325 @@ > +/* > + * Private header for the MPC52xx processor BestComm driver > + * > + * > + * Copyright (C) 2006 Sylvain Munaut > + * Copyright (C) 2005 Varma Electronics Oy, > + * ( by Andrey Volkov el.com> ) > + * Copyright (C) 2003-2004 MontaVista, Software, Inc. > + * ( by Dale Farnsworth > ) > + * > + * This file is licensed under the terms of the GNU General Public > License > + * version 2. This program is licensed "as is" without any > warranty of any > + * kind, whether express or implied. > + */ > + > +#ifndef __BESTCOMM_PRIV_H__ > +#define __BESTCOMM_PRIV_H__ > + > +#include > +#include > +#include > +#include > + > +#include "sram.h" > + > + > +/* > ====================================================================== > == */ > +/* Engine related > stuff */ > +/* > ====================================================================== > == */ > + > +/* Zones sizes and needed alignments */ > +#define BCOM_MAX_TASKS 16 > +#define BCOM_MAX_VAR 24 > +#define BCOM_MAX_INC 8 > +#define BCOM_MAX_FDT 64 > +#define BCOM_MAX_CTX 20 > +#define BCOM_CTX_SIZE (BCOM_MAX_CTX * sizeof(u32)) > +#define BCOM_CTX_ALIGN 0x100 > +#define BCOM_VAR_SIZE (BCOM_MAX_VAR * sizeof(u32)) > +#define BCOM_INC_SIZE (BCOM_MAX_INC * sizeof(u32)) > +#define BCOM_VAR_ALIGN 0x80 > +#define BCOM_FDT_SIZE (BCOM_MAX_FDT * sizeof(u32)) > +#define BCOM_FDT_ALIGN 0x100 > + > +/* Task Descriptor Table Entry */ > +struct bcom_tdt { > + u32 start; > + u32 stop; > + u32 var; > + u32 fdt; > + u32 exec_status; /* used internally by BestComm engine */ > + u32 mvtp; /* used internally by BestComm engine */ > + u32 context; > + u32 litbase; > +}; > + > +/* This holds all info needed globaly to handle the engine */ > +struct bcom_engine { > + struct device_node *ofnode; > + struct mpc52xx_sdma __iomem *regs; > + phys_addr_t regs_base; > + > + struct bcom_tdt *tdt; > + u32 *ctx; > + u32 *var; > + u32 *fdt; > + > + spinlock_t lock; > +}; > + > +extern struct bcom_engine *bcom; > + > + > +/* > ====================================================================== > == */ > +/* Tasks related > stuff */ > +/* > ====================================================================== > == */ > + > +/* Tasks image header */ > +#define BCOM_TASK_MAGIC 0x4243544B /* 'BCTK' */ > + > +struct bcom_task_header { > + u32 magic; > + u8 desc_size; /* the size fields */ > + u8 var_size; /* are given in number */ > + u8 inc_size; /* of 32-bits words */ > + u8 first_var; > + u8 reserved[8]; > +}; > + > +/* Descriptors stucture & co */ > +#define BCOM_DESC_NOP 0x000001f8 > +#define BCOM_LCD_MASK 0x80000000 > +#define BCOM_DRD_EXTENDED 0x40000000 > +#define BCOM_DRD_INITIATOR_SHIFT 21 > + > +/* Tasks pragma */ > +#define BCOM_PRAGMA_BIT_RSV 7 /* reserved pragma bit */ > +#define BCOM_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when > possible, */ > + /* 1=iter end */ > +#define BCOM_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */ > + /* task enable */ > +#define BCOM_PRAGMA_BIT_PACK 4 /* pack data enable */ > +#define BCOM_PRAGMA_BIT_INTEGER 3 /* data alignment */ > + /* 0=frac(msb), 1=int(lsb) */ > +#define BCOM_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */ > +#define BCOM_PRAGMA_BIT_CW 1 /* write line buffer enable */ > +#define BCOM_PRAGMA_BIT_RL 0 /* read line buffer enable */ > + > + /* Looks like XLB speculative read generates XLB errors when a > buffer > + * is at the end of the physical memory. i.e. when accessing the > + * lasts words, the engine tries to prefetch the next but there > is no > + * next ... > + */ > +#define BCOM_STD_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \ > + (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \ > + (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \ > + (0 << BCOM_PRAGMA_BIT_PACK) | \ > + (0 << BCOM_PRAGMA_BIT_INTEGER) | \ > + (0 << BCOM_PRAGMA_BIT_SPECREAD) | \ > + (1 << BCOM_PRAGMA_BIT_CW) | \ > + (1 << BCOM_PRAGMA_BIT_RL)) > + > +#define BCOM_PCI_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \ > + (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \ > + (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \ > + (0 << BCOM_PRAGMA_BIT_PACK) | \ > + (1 << BCOM_PRAGMA_BIT_INTEGER) | \ > + (0 << BCOM_PRAGMA_BIT_SPECREAD) | \ > + (1 << BCOM_PRAGMA_BIT_CW) | \ > + (1 << BCOM_PRAGMA_BIT_RL)) > + > +#define BCOM_ATA_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_CRC16_DP_0_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_CRC16_DP_1_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_FEC_RX_BD_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_FEC_TX_BD_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_DP_0_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_DP_1_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_DP_2_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_DP_3_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_DP_BD_0_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_DP_BD_1_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_RX_BD_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_TX_BD_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_GEN_LPC_PRAGMA BCOM_STD_PRAGMA > +#define BCOM_PCI_RX_PRAGMA BCOM_PCI_PRAGMA > +#define BCOM_PCI_TX_PRAGMA BCOM_PCI_PRAGMA > + > +/* Initiators number */ > +#define BCOM_INITIATOR_ALWAYS 0 > +#define BCOM_INITIATOR_SCTMR_0 1 > +#define BCOM_INITIATOR_SCTMR_1 2 > +#define BCOM_INITIATOR_FEC_RX 3 > +#define BCOM_INITIATOR_FEC_TX 4 > +#define BCOM_INITIATOR_ATA_RX 5 > +#define BCOM_INITIATOR_ATA_TX 6 > +#define BCOM_INITIATOR_SCPCI_RX 7 > +#define BCOM_INITIATOR_SCPCI_TX 8 > +#define BCOM_INITIATOR_PSC3_RX 9 > +#define BCOM_INITIATOR_PSC3_TX 10 > +#define BCOM_INITIATOR_PSC2_RX 11 > +#define BCOM_INITIATOR_PSC2_TX 12 > +#define BCOM_INITIATOR_PSC1_RX 13 > +#define BCOM_INITIATOR_PSC1_TX 14 > +#define BCOM_INITIATOR_SCTMR_2 15 > +#define BCOM_INITIATOR_SCLPC 16 > +#define BCOM_INITIATOR_PSC5_RX 17 > +#define BCOM_INITIATOR_PSC5_TX 18 > +#define BCOM_INITIATOR_PSC4_RX 19 > +#define BCOM_INITIATOR_PSC4_TX 20 > +#define BCOM_INITIATOR_I2C2_RX 21 > +#define BCOM_INITIATOR_I2C2_TX 22 > +#define BCOM_INITIATOR_I2C1_RX 23 > +#define BCOM_INITIATOR_I2C1_TX 24 > +#define BCOM_INITIATOR_PSC6_RX 25 > +#define BCOM_INITIATOR_PSC6_TX 26 > +#define BCOM_INITIATOR_IRDA_RX 25 > +#define BCOM_INITIATOR_IRDA_TX 26 > +#define BCOM_INITIATOR_SCTMR_3 27 > +#define BCOM_INITIATOR_SCTMR_4 28 > +#define BCOM_INITIATOR_SCTMR_5 29 > +#define BCOM_INITIATOR_SCTMR_6 30 > +#define BCOM_INITIATOR_SCTMR_7 31 > + > +/* Initiators priorities */ > +#define BCOM_IPR_ALWAYS 7 > +#define BCOM_IPR_SCTMR_0 2 > +#define BCOM_IPR_SCTMR_1 2 > +#define BCOM_IPR_FEC_RX 6 > +#define BCOM_IPR_FEC_TX 5 > +#define BCOM_IPR_ATA_RX 4 > +#define BCOM_IPR_ATA_TX 3 > +#define BCOM_IPR_SCPCI_RX 2 > +#define BCOM_IPR_SCPCI_TX 2 > +#define BCOM_IPR_PSC3_RX 2 > +#define BCOM_IPR_PSC3_TX 2 > +#define BCOM_IPR_PSC2_RX 2 > +#define BCOM_IPR_PSC2_TX 2 > +#define BCOM_IPR_PSC1_RX 2 > +#define BCOM_IPR_PSC1_TX 2 > +#define BCOM_IPR_SCTMR_2 2 > +#define BCOM_IPR_SCLPC 2 > +#define BCOM_IPR_PSC5_RX 2 > +#define BCOM_IPR_PSC5_TX 2 > +#define BCOM_IPR_PSC4_RX 2 > +#define BCOM_IPR_PSC4_TX 2 > +#define BCOM_IPR_I2C2_RX 2 > +#define BCOM_IPR_I2C2_TX 2 > +#define BCOM_IPR_I2C1_RX 2 > +#define BCOM_IPR_I2C1_TX 2 > +#define BCOM_IPR_PSC6_RX 2 > +#define BCOM_IPR_PSC6_TX 2 > +#define BCOM_IPR_IRDA_RX 2 > +#define BCOM_IPR_IRDA_TX 2 > +#define BCOM_IPR_SCTMR_3 2 > +#define BCOM_IPR_SCTMR_4 2 > +#define BCOM_IPR_SCTMR_5 2 > +#define BCOM_IPR_SCTMR_6 2 > +#define BCOM_IPR_SCTMR_7 2 > + > + > +/* > ====================================================================== > == */ > +/* > API > */ > +/* > ====================================================================== > == */ > + > +extern struct bcom_task *bcom_task_alloc(int bd_count, int > bd_size, int priv_size); > +extern void bcom_task_release(struct bcom_task *tsk); > + > +extern int bcom_load_image(int task, u32 *task_image); > +extern void bcom_set_initiator(int task, int initiator); > + > + > +#define TASK_ENABLE 0x8000 > + > +static inline void > +bcom_enable_task(int task) > +{ > + u16 reg; > + reg = in_be16(&bcom->regs->tcr[task]); > + out_be16(&bcom->regs->tcr[task], reg | TASK_ENABLE); > +} > + > +static inline void > +bcom_disable_task(int task) > +{ > + u16 reg = in_be16(&bcom->regs->tcr[task]); > + out_be16(&bcom->regs->tcr[task], reg & ~TASK_ENABLE); > +} > + > + > +static inline u32 * > +bcom_task_desc(int task) > +{ > + return bcom_sram_pa2va(bcom->tdt[task].start); > +} > + > +static inline int > +bcom_task_num_descs(int task) > +{ > + return (bcom->tdt[task].stop - bcom->tdt[task].start)/sizeof(u32) > + 1; > +} > + > +static inline u32 * > +bcom_task_var(int task) > +{ > + return bcom_sram_pa2va(bcom->tdt[task].var); > +} > + > +static inline u32 * > +bcom_task_inc(int task) > +{ > + return &bcom_task_var(task)[BCOM_MAX_VAR]; > +} > + > + > +static inline int > +bcom_drd_is_extended(u32 desc) > +{ > + return (desc) & BCOM_DRD_EXTENDED; > +} > + > +static inline int > +bcom_desc_is_drd(u32 desc) > +{ > + return !(desc & BCOM_LCD_MASK) && desc != BCOM_DESC_NOP; > +} > + > +static inline int > +bcom_desc_initiator(u32 desc) > +{ > + return (desc >> BCOM_DRD_INITIATOR_SHIFT) & 0x1f; > +} > + > +static inline void > +bcom_set_desc_initiator(u32 *desc, int initiator) > +{ > + *desc = (*desc & ~(0x1f << BCOM_DRD_INITIATOR_SHIFT)) | > + ((initiator & 0x1f) << BCOM_DRD_INITIATOR_SHIFT); > +} > + > + > +static inline void > +bcom_set_task_pragma(int task, int pragma) > +{ > + u32 *fdt = &bcom->tdt[task].fdt; > + *fdt = (*fdt & ~0xff) | pragma; > +} > + > +static inline void > +bcom_set_task_auto_start(int task, int next_task) > +{ > + u16 __iomem *tcr = &bcom->regs->tcr[task]; > + out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task); > +} > + > +static inline void > +bcom_set_tcr_initiator(int task, int initiator) > +{ > + u16 __iomem *tcr = &bcom->regs->tcr[task]; > + out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8)); > +} > + > + > +#endif /* __BESTCOMM_PRIV_H__ */ > + > diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/ > sysdev/bestcomm/sram.c > new file mode 100644 > index 0000000..4f69127 > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/sram.c > @@ -0,0 +1,180 @@ > +/* > + * Simple memory allocator for on-board SRAM > + * > + * > + * Maintainer : Sylvain Munaut > + * > + * Copyright (C) 2005 Sylvain Munaut > + * > + * This file is licensed under the terms of the GNU General Public > License > + * version 2. This program is licensed "as is" without any > warranty of any > + * kind, whether express or implied. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "sram.h" > + > + > +/* Struct keeping our 'state' */ > +struct bcom_sram *bcom_sram = NULL; > + > + > +/* > ====================================================================== > == */ > +/* Public > API */ > +/* > ====================================================================== > == */ > +/* DO NOT USE in interrupts, if needed in irq handler, we should > use the > + _irqsave version of the spin_locks */ > + > +int bcom_sram_init(struct device_node *sram_node, char *owner) > +{ > + int rv; > + const u32 *regaddr_p; > + u64 regaddr64, size64; > + unsigned int psize; > + > + /* Create our state struct */ > + if (bcom_sram) { > + printk(KERN_ERR "%s: bcom_sram_init: " > + "Already initialiwed !\n", owner); > + return -EBUSY; > + } > + > + bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL); > + if (!bcom_sram) { > + printk(KERN_ERR "%s: bcom_sram_init: " > + "Couldn't allocate internal state !\n", owner); > + return -ENOMEM; > + } > + > + /* Get address and size of the sram */ > + regaddr_p = of_get_address(sram_node, 0, &size64, NULL); > + if (!regaddr_p) { > + printk(KERN_ERR "%s: bcom_sram_init: " > + "Invalid device node !\n", owner); > + rv = -EINVAL; > + goto error_free; > + } > + > + regaddr64 = of_translate_address(sram_node, regaddr_p); > + > + bcom_sram->base_phys = (phys_addr_t) regaddr64; > + bcom_sram->size = (unsigned int) size64; > + > + /* Request region */ > + if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, > owner)) { > + printk(KERN_ERR "%s: bcom_sram_init: " > + "Couln't request region !\n", owner); > + rv = -EBUSY; > + goto error_free; > + } > + > + /* Map SRAM */ > + /* sram is not really __iomem */ > + bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, > bcom_sram->size); > + > + if (!bcom_sram->base_virt) { > + printk(KERN_ERR "%s: bcom_sram_init: " > + "Map error SRAM zone 0x%08lx (0x%0x)!\n", > + owner, bcom_sram->base_phys, bcom_sram->size ); > + rv = -ENOMEM; > + goto error_release; > + } > + > + /* Create an rheap (defaults to 32 bits word alignment) */ > + bcom_sram->rh = rh_create(4); > + > + /* Attach the free zones */ > +#if 0 > + /* Currently disabled ... for future use only */ > + reg_addr_p = of_get_property(sram_node, "available", &psize); > +#else > + regaddr_p = NULL; > + psize = 0; > +#endif > + > + if (!regaddr_p || !psize) { > + /* Attach the whole zone */ > + rh_attach_region(bcom_sram->rh, 0, bcom_sram->size); > + } else { > + /* Attach each zone independently */ > + while (psize >= 2 * sizeof(u32)) { > + phys_addr_t zbase = of_translate_address(sram_node, regaddr_p); > + rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, > regaddr_p[1]); > + regaddr_p += 2; > + psize -= 2 * sizeof(u32); > + } > + } > + > + /* Init our spinlock */ > + spin_lock_init(&bcom_sram->lock); > + > + return 0; > + > +error_release: > + release_mem_region(bcom_sram->base_phys, bcom_sram->size); > +error_free: > + kfree(bcom_sram); > + bcom_sram = NULL; > + > + return rv; > +} > + > +void bcom_sram_cleanup(void) > +{ > + /* Free resources */ > + if (bcom_sram) { > + rh_destroy(bcom_sram->rh); > + iounmap((void __iomem *)bcom_sram->base_virt); > + release_mem_region(bcom_sram->base_phys, bcom_sram->size); > + kfree(bcom_sram); > + bcom_sram = NULL; > + } > +} > + > +void* bcom_sram_alloc(int size, int align, phys_addr_t *phys) > +{ > + unsigned long offset; > + > + spin_lock(&bcom_sram->lock); > + offset = rh_alloc_align(bcom_sram->rh, size, align, NULL); > + spin_unlock(&bcom_sram->lock); > + > + if (IS_ERR_VALUE(offset)) > + return NULL; > + > + *phys = bcom_sram->base_phys + offset; > + return bcom_sram->base_virt + offset; > +} > + > +void bcom_sram_free(void *ptr) > +{ > + unsigned long offset; > + > + if (!ptr) > + return; > + > + offset = ptr - bcom_sram->base_virt; > + > + spin_lock(&bcom_sram->lock); > + rh_free(bcom_sram->rh, offset); > + spin_unlock(&bcom_sram->lock); > +} > + > + > +EXPORT_SYMBOL(bcom_sram); > + > +EXPORT_SYMBOL(bcom_sram_init); > +EXPORT_SYMBOL(bcom_sram_cleanup); > +EXPORT_SYMBOL(bcom_sram_alloc); > +EXPORT_SYMBOL(bcom_sram_free); > + > diff --git a/arch/powerpc/sysdev/bestcomm/sram.h b/arch/powerpc/ > sysdev/bestcomm/sram.h > new file mode 100644 > index 0000000..b6d6689 > --- /dev/null > +++ b/arch/powerpc/sysdev/bestcomm/sram.h > @@ -0,0 +1,54 @@ > +/* > + * Handling of a sram zone for bestcomm > + * > + * > + * Copyright (C) 2007 Sylvain Munaut > + * > + * This file is licensed under the terms of the GNU General Public > License > + * version 2. This program is licensed "as is" without any > warranty of any > + * kind, whether express or implied. > + */ > + > +#ifndef __BESTCOMM_SRAM_H__ > +#define __BESTCOMM_SRAM_H__ > + > +#include > +#include > +#include > + > + > +/* Structure used internally */ > + /* The internals are here for the inline functions > + * sake, certainly not for the user to mess with ! > + */ > +struct bcom_sram { > + phys_addr_t base_phys; > + void *base_virt; > + unsigned int size; > + rh_info_t *rh; > + spinlock_t lock; > +}; > + > +extern struct bcom_sram *bcom_sram; > + > + > +/* Public API */ > +extern int bcom_sram_init(struct device_node *sram_node, char > *owner); > +extern void bcom_sram_cleanup(void); > + > +extern void* bcom_sram_alloc(int size, int align, phys_addr_t *phys); > +extern void bcom_sram_free(void *ptr); > + > +static inline phys_addr_t bcom_sram_va2pa(void *va) { > + return bcom_sram->base_phys + > + (unsigned long)(va - bcom_sram->base_virt); > +} > + > +static inline void *bcom_sram_pa2va(phys_addr_t pa) { > + return bcom_sram->base_virt + > + (unsigned long)(pa - bcom_sram->base_phys); > +} > + > + > +#endif /* __BESTCOMM_SRAM_H__ */ > + > -- > 1.5.1.2 > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev