[PATCH 4/9] powerpc: BestComm core support for Freescale MPC5200
Kumar Gala
galak at kernel.crashing.org
Wed May 16 07:37:53 EST 2007
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 <tnt at 246tNt.com>
> ---
> 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 <tnt at 246tNt.com>
> + * Copyright (C) 2005 Varma Electronics Oy,
> + * ( by Andrey Volkov <avolkov at varma-
> el.com> )
> + * Copyright (C) 2003-2004 MontaVista, Software, Inc.
> + * ( by Dale Farnsworth
> <dfarnsworth at mvista.com> )
> + *
> + * 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 <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +
> +#include <asm/io.h>
> +#include <asm/irq.h>
> +#include <asm/prom.h>
> +#include <asm/mpc52xx.h>
> +
> +#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<bcom_task_num_descs(task); 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<BCOM_MAX_VAR+BCOM_MAX_INC; 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; i<tsk->num_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<BCOM_MAX_TASKS; 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<num_descs; i++, desc++) {
> + 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<BCOM_MAX_TASKS; 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<BCOM_MAX_TASKS; 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 <tnt at 246tNt.com>");
> +MODULE_AUTHOR("Andrey Volkov <avolkov at varma-el.com>");
> +MODULE_AUTHOR("Dale Farnsworth <dfarnsworth at mvista.com>");
> +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 <tnt at 246tNt.com>
> + * Copyright (C) 2005 Varma Electronics Oy,
> + * ( by Andrey Volkov <avolkov at varma-
> el.com> )
> + * Copyright (C) 2003-2004 MontaVista, Software, Inc.
> + * ( by Dale Farnsworth
> <dfarnsworth at mvista.com> )
> + *
> + * 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 <tnt at 246tNt.com>
> + * Copyright (C) 2005 Varma Electronics Oy,
> + * ( by Andrey Volkov <avolkov at varma-
> el.com> )
> + * Copyright (C) 2003-2004 MontaVista, Software, Inc.
> + * ( by Dale Farnsworth
> <dfarnsworth at mvista.com> )
> + *
> + * 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 <linux/spinlock.h>
> +#include <asm/io.h>
> +#include <asm/prom.h>
> +#include <asm/mpc52xx.h>
> +
> +#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 <tnt at 246tNt.com>
> + *
> + * Copyright (C) 2005 Sylvain Munaut <tnt at 246tNt.com>
> + *
> + * 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 <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/string.h>
> +#include <linux/ioport.h>
> +
> +#include <asm/io.h>
> +#include <asm/mmu.h>
> +#include <asm/prom.h>
> +
> +#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 <tnt at 246tNt.com>
> + *
> + * 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 <asm/rheap.h>
> +#include <asm/mmu.h>
> +#include <linux/spinlock.h>
> +
> +
> +/* 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 at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list