[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <8628FE4E7912BF47A96AE7DD7BAC0AADCB25AE17C5@SJEXCHCCR02.corp.ad.broadcom.com>
Date: Fri, 26 Jun 2009 16:29:44 -0700
From: "Leo (Hao) Chen" <leochen@...adcom.com>
To: "linux-arm-kernel@...ts.arm.linux.org.uk"
<linux-arm-kernel@...ts.arm.linux.org.uk>,
"Linux Kernel" <linux-kernel@...r.kernel.org>
cc: "Leo (Hao) Chen" <leochen@...adcom.com>
Subject: [PATCH v1 3/6][ARM] new ARM SoC support: BCMRing
Hi,
This is the third patch. This big patch contains the core arch code in arch/arm/mach-bcmring directory.
Header files in arch/arm/mach-bcmring/include/mach are included as well.
>From 8c38c714343f1cc203c55db8fd28505b1ec4f914 Mon Sep 17 00:00:00 2001
From: Leo Chen <leochen@...adcom.com>
Date: Fri, 26 Jun 2009 15:46:41 -0700
Subject: [PATCH 3/6] add bcmring arch core code and header files
---
arch/arm/mach-bcmring/Kconfig | 40 +
arch/arm/mach-bcmring/Makefile | 10 +
arch/arm/mach-bcmring/Makefile.boot | 6 +
arch/arm/mach-bcmring/arch.c | 184 ++
arch/arm/mach-bcmring/clock.c | 229 ++
arch/arm/mach-bcmring/clock.h | 33 +
arch/arm/mach-bcmring/core.c | 358 +++
arch/arm/mach-bcmring/core.h | 75 +
arch/arm/mach-bcmring/dma.c | 3022 ++++++++++++++++++++
arch/arm/mach-bcmring/early_printk.c | 105 +
arch/arm/mach-bcmring/include/cfg_global.h | 16 +
arch/arm/mach-bcmring/include/cfg_global_defines.h | 54 +
arch/arm/mach-bcmring/include/mach/clkdev.h | 7 +
arch/arm/mach-bcmring/include/mach/dma.h | 894 ++++++
arch/arm/mach-bcmring/include/mach/entry-macro.S | 94 +
arch/arm/mach-bcmring/include/mach/hardware.h | 65 +
arch/arm/mach-bcmring/include/mach/io.h | 61 +
arch/arm/mach-bcmring/include/mach/irqs.h | 139 +
arch/arm/mach-bcmring/include/mach/memory.h | 47 +
.../mach-bcmring/include/mach/memory_settings.h | 69 +
arch/arm/mach-bcmring/include/mach/reg_nand.h | 65 +
arch/arm/mach-bcmring/include/mach/reg_umi.h | 149 +
arch/arm/mach-bcmring/include/mach/system.h | 75 +
arch/arm/mach-bcmring/include/mach/timer.h | 87 +
arch/arm/mach-bcmring/include/mach/timex.h | 25 +
arch/arm/mach-bcmring/include/mach/uncompress.h | 53 +
arch/arm/mach-bcmring/include/mach/vmalloc.h | 32 +
arch/arm/mach-bcmring/irq.c | 154 +
arch/arm/mach-bcmring/mm.c | 102 +
arch/arm/mach-bcmring/timer.c | 66 +
30 files changed, 6316 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-bcmring/Kconfig
create mode 100644 arch/arm/mach-bcmring/Makefile
create mode 100644 arch/arm/mach-bcmring/Makefile.boot
create mode 100644 arch/arm/mach-bcmring/arch.c
create mode 100644 arch/arm/mach-bcmring/clock.c
create mode 100644 arch/arm/mach-bcmring/clock.h
create mode 100644 arch/arm/mach-bcmring/core.c
create mode 100644 arch/arm/mach-bcmring/core.h
create mode 100644 arch/arm/mach-bcmring/dma.c
create mode 100644 arch/arm/mach-bcmring/early_printk.c
create mode 100644 arch/arm/mach-bcmring/include/cfg_global.h
create mode 100644 arch/arm/mach-bcmring/include/cfg_global_defines.h
create mode 100644 arch/arm/mach-bcmring/include/mach/clkdev.h
create mode 100644 arch/arm/mach-bcmring/include/mach/dma.h
create mode 100644 arch/arm/mach-bcmring/include/mach/entry-macro.S
create mode 100644 arch/arm/mach-bcmring/include/mach/hardware.h
create mode 100644 arch/arm/mach-bcmring/include/mach/io.h
create mode 100644 arch/arm/mach-bcmring/include/mach/irqs.h
create mode 100644 arch/arm/mach-bcmring/include/mach/memory.h
create mode 100644 arch/arm/mach-bcmring/include/mach/memory_settings.h
create mode 100644 arch/arm/mach-bcmring/include/mach/reg_nand.h
create mode 100644 arch/arm/mach-bcmring/include/mach/reg_umi.h
create mode 100644 arch/arm/mach-bcmring/include/mach/system.h
create mode 100644 arch/arm/mach-bcmring/include/mach/timer.h
create mode 100644 arch/arm/mach-bcmring/include/mach/timex.h
create mode 100644 arch/arm/mach-bcmring/include/mach/uncompress.h
create mode 100644 arch/arm/mach-bcmring/include/mach/vmalloc.h
create mode 100644 arch/arm/mach-bcmring/irq.c
create mode 100644 arch/arm/mach-bcmring/mm.c
create mode 100644 arch/arm/mach-bcmring/timer.c
diff --git a/arch/arm/mach-bcmring/Kconfig b/arch/arm/mach-bcmring/Kconfig
new file mode 100644
index 0000000..45053c8
--- /dev/null
+++ b/arch/arm/mach-bcmring/Kconfig
@@ -0,0 +1,40 @@
+choice
+ prompt "Processor selection in BCMRING family of devices"
+ depends on ARCH_BCMRING
+ default ARCH_BCM11107
+
+config ARCH_FPGA11107
+ bool "FPGA11107"
+
+config ARCH_BCM11107
+ bool "BCM11107"
+endchoice
+
+menu "BCMRING Options"
+ depends on ARCH_BCMRING
+
+config BCM_ZRELADDR
+ hex "Compressed ZREL ADDR"
+
+config BCM_EARLY_PRINTK
+ bool "Enable early console printk"
+ default n
+ help
+ Enable console printk very early in boot process.
+
+choice
+ prompt "Serial port for early printk and jtag"
+ depends on BCM_EARLY_PRINTK || BCM_DEBUG_PAUSE_JTAG
+ default BCM_EARLY_CONSOLE_UARTA
+
+config BCM_EARLY_CONSOLE_UARTA
+ bool "UART A - Early Console"
+
+config BCM_EARLY_CONSOLE_UARTB
+ bool "UART B - Early Console"
+
+endchoice
+
+endmenu
+
+# source "drivers/char/bcmring/Kconfig"
diff --git a/arch/arm/mach-bcmring/Makefile b/arch/arm/mach-bcmring/Makefile
new file mode 100644
index 0000000..853f6a5
--- /dev/null
+++ b/arch/arm/mach-bcmring/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y := arch.o mm.o irq.o clock.o core.o timer.o dma.o
+obj-y += csp/
+
+obj-$(CONFIG_BCM_EARLY_PRINTK) += early_printk.o
diff --git a/arch/arm/mach-bcmring/Makefile.boot b/arch/arm/mach-bcmring/Makefile.boot
new file mode 100644
index 0000000..fb53b28
--- /dev/null
+++ b/arch/arm/mach-bcmring/Makefile.boot
@@ -0,0 +1,6 @@
+# Address where decompressor will be written and eventually executed.
+#
+# default to SDRAM
+zreladdr-y := $(CONFIG_BCM_ZRELADDR)
+params_phys-y := 0x00000800
+
diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
new file mode 100644
index 0000000..ed4beb0
--- /dev/null
+++ b/arch/arm/mach-bcmring/arch.c
@@ -0,0 +1,184 @@
+/*****************************************************************************
+* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/time.h>
+
+#include <asm/mach/arch.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/csp/mm_io.h>
+#include <mach/csp/chipcHw_def.h>
+#include <mach/csp/chipcHw_inline.h>
+
+#include <cfg_global.h>
+
+#include "core.h"
+
+HW_DECLARE_SPINLOCK(Arch)
+HW_DECLARE_SPINLOCK(Gpio)
+
+#if defined( CONFIG_DEBUG_SPINLOCK )
+EXPORT_SYMBOL(gGpioRegLock);
+#endif
+
+/* FIXME: temporary solution */
+#define BCM_SYSCTL_REBOOT_WARM 1
+#define CTL_BCM_REBOOT 112
+
+/* sysctl */
+int gArchWarmReboot = 0; // do a warm reboot on hard reset
+
+static struct ctl_table_header *gSysCtlHeader;
+
+static struct ctl_table gSysCtlReboot[] = {
+ {
+ .ctl_name = BCM_SYSCTL_REBOOT_WARM,
+ .procname = "warm",
+ .data = &gArchWarmReboot,
+ .maxlen = sizeof( int ),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+ {}
+};
+static struct ctl_table gSysCtl[] = {
+ {
+ .ctl_name = CTL_BCM_REBOOT,
+ .procname = "reboot",
+ .mode = 0555,
+ .child = gSysCtlReboot
+ },
+ {}
+};
+
+extern void bcmring_map_io(void);
+extern void bcmring_init_irq(void);
+extern void bcmring_init_timer(void);
+
+static struct platform_device nand_device = {
+ .name = "bcm-nand",
+ .id = -1,
+};
+
+static struct platform_device *devices[] __initdata =
+{
+ &nand_device,
+};
+
+/****************************************************************************
+*
+* Called from the customize_machine function in arch/arm/kernel/setup.c
+*
+* The customize_machine function is tagged as an arch_initcall
+* (see include/linux/init.h for the order that the various init sections
+* are called in.
+*
+*****************************************************************************/
+static void __init bcmring_init_machine( void )
+{
+
+ gSysCtlHeader = register_sysctl_table(gSysCtl);
+
+ /* Enable spread spectrum */
+ chipcHw_enableSpreadSpectrum ( );
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+
+ bcmring_amba_init();
+
+ dma_init();
+}
+
+/****************************************************************************
+*
+* Called from setup_arch (in arch/arm/kernel/setup.c) to fixup any tags
+* passed in by the boot loader.
+*
+*****************************************************************************/
+
+static void __init bcmring_fixup
+(
+ struct machine_desc *desc,
+ struct tag *t,
+ char **cmdline,
+ struct meminfo *mi
+)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+ printk(KERN_NOTICE "bcmring_fixup\n");
+ t->hdr.tag = ATAG_CORE;
+ t->hdr.size = tag_size(tag_core);
+ t->u.core.flags = 0;
+ t->u.core.pagesize = PAGE_SIZE;
+ t->u.core.rootdev = 31 << 8 | 0;
+ t = tag_next(t);
+
+ t->hdr.tag = ATAG_MEM;
+ t->hdr.size = tag_size(tag_mem32);
+ t->u.mem.start = CFG_GLOBAL_RAM_BASE;
+ t->u.mem.size = CFG_GLOBAL_RAM_SIZE;
+
+ t = tag_next(t);
+
+ t->hdr.tag = ATAG_NONE;
+ t->hdr.size = 0;
+#endif
+}
+
+/****************************************************************************
+*
+* Timer related information. bcmring_init_timer is called from
+* time_init (in arch/arm/kernel/time.c).
+*
+*****************************************************************************/
+
+static struct sys_timer bcmring_timer =
+{
+ .init = bcmring_init_timer,
+};
+
+/****************************************************************************
+*
+* Machine Description
+*
+*****************************************************************************/
+
+MACHINE_START(BCMRING, "BCMRING")
+ /* Maintainer: Broadcom Corporation */
+ .phys_io = IO_START,
+ .io_pg_offst = (IO_BASE >> 18) & 0xfffc,
+ .fixup = bcmring_fixup,
+ .map_io = bcmring_map_io,
+ .init_irq = bcmring_init_irq,
+ .timer = &bcmring_timer,
+ .init_machine = bcmring_init_machine
+MACHINE_END
+
diff --git a/arch/arm/mach-bcmring/clock.c b/arch/arm/mach-bcmring/clock.c
new file mode 100644
index 0000000..924d47d
--- /dev/null
+++ b/arch/arm/mach-bcmring/clock.c
@@ -0,0 +1,229 @@
+/*****************************************************************************
+* Copyright 2001 - 2009 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <mach/csp/hw_cfg.h>
+#include <mach/csp/chipcHw_def.h>
+#include <mach/csp/chipcHw_reg.h>
+#include <mach/csp/chipcHw_inline.h>
+
+#include <asm/clkdev.h>
+
+#include "clock.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY)
+#define clk_is_pll1(x) ((x)->type & CLK_TYPE_PLL1)
+#define clk_is_pll2(x) ((x)->type & CLK_TYPE_PLL2)
+#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE)
+#define clk_is_bypassable(x) ((x)->type & CLK_TYPE_BYPASSABLE)
+
+#define clk_is_using_xtal(x) ((x)->mode & CLK_MODE_XTAL)
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static void __clk_enable(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ /* enable parent clock first */
+ if (clk->parent)
+ __clk_enable(clk->parent);
+
+ if (clk->use_cnt++ == 0) {
+ if (clk_is_pll1(clk)) { /* PLL1 */
+ chipcHw_pll1Enable(clk->rate_hz, 0);
+ } else if (clk_is_pll2(clk)) { /* PLL2 */
+ chipcHw_pll2Enable(clk->rate_hz);
+ } else if (clk_is_using_xtal(clk)) { /* source is crystal */
+ if (!clk_is_primary(clk)) {
+ chipcHw_bypassClockEnable(clk->csp_id);
+ }
+ } else { /* source is PLL */
+ chipcHw_setClockEnable(clk->csp_id);
+ }
+ }
+}
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (!clk)
+ return -EINVAL;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ __clk_enable(clk);
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+static void __clk_disable(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ BUG_ON(clk->use_cnt == 0);
+
+ if (--clk->use_cnt == 0) {
+ if (clk_is_pll1(clk)) { /* PLL1 */
+ chipcHw_pll1Disable();
+ } else if (clk_is_pll2(clk)) { /* PLL2 */
+ chipcHw_pll2Disable();
+ } else if (clk_is_using_xtal(clk)) { /* source is crystal */
+ if (!clk_is_primary(clk)) {
+ chipcHw_bypassClockDisable(clk->csp_id);
+ }
+ } else { /* source is PLL */
+ chipcHw_setClockDisable(clk->csp_id);
+ }
+ }
+
+ if (clk->parent)
+ __clk_disable(clk->parent);
+}
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (!clk)
+ return;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clk_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk->rate_hz;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long flags;
+ unsigned long actual;
+ unsigned long rate_hz;
+
+ if (!clk)
+ return -EINVAL;
+
+ if (!clk_is_programmable(clk))
+ return -EINVAL;
+
+ if (clk->use_cnt)
+ return -EBUSY;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ actual = clk->parent->rate_hz;
+ rate_hz = MIN(actual, rate);
+ rate_hz = chipcHw_setClockFrequency(clk->csp_id, rate_hz);
+ clk->rate_hz = rate_hz;
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return rate_hz;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long flags;
+ unsigned long actual;
+ unsigned long rate_hz;
+
+ if (!clk)
+ return -EINVAL;
+
+ if (!clk_is_programmable(clk))
+ return -EINVAL;
+
+ if (clk->use_cnt)
+ return -EBUSY;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ actual = clk->parent->rate_hz;
+ rate_hz = MIN(actual, rate);
+ rate_hz = chipcHw_setClockFrequency(clk->csp_id, rate_hz);
+ clk->rate_hz = rate_hz;
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (!clk)
+ return NULL;
+
+ return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ unsigned long flags;
+ struct clk *old_parent;
+
+ if (!clk || !parent)
+ return -EINVAL;
+
+ if (!clk_is_primary(parent) || !clk_is_bypassable(clk))
+ return -EINVAL;
+
+ /* if more than one user, parent is not allowed */
+ if (clk->use_cnt > 1)
+ return -EBUSY;
+
+ if (clk->parent == parent)
+ return 0;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ old_parent = clk->parent;
+ clk->parent = parent;
+ if (clk_is_using_xtal(parent))
+ clk->mode |= CLK_MODE_XTAL;
+ else
+ clk->mode &= (~CLK_MODE_XTAL);
+
+ /* if clock is active */
+ if (clk->use_cnt != 0) {
+ clk->use_cnt--;
+ /* enable clock with the new parent */
+ __clk_enable(clk);
+ /* disable the old parent */
+ __clk_disable(old_parent);
+ }
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
diff --git a/arch/arm/mach-bcmring/clock.h b/arch/arm/mach-bcmring/clock.h
new file mode 100644
index 0000000..7280774
--- /dev/null
+++ b/arch/arm/mach-bcmring/clock.h
@@ -0,0 +1,33 @@
+/*****************************************************************************
+* Copyright 2001 - 2009 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+#include <mach/csp/chipcHw_def.h>
+
+#define CLK_TYPE_PRIMARY 1 /* primary clock must NOT have a parent */
+#define CLK_TYPE_PLL1 2 /* PPL1 */
+#define CLK_TYPE_PLL2 4 /* PPL2 */
+#define CLK_TYPE_PROGRAMMABLE 8 /* programmable clock rate */
+#define CLK_TYPE_BYPASSABLE 16 /* parent can be changed */
+
+#define CLK_MODE_XTAL 1 /* clock source is from crystal */
+
+struct clk {
+ const char *name; /* clock name */
+ unsigned int type; /* clock type */
+ unsigned int mode; /* current mode */
+ volatile int use_bypass; /* indicate if it's in bypass mode */
+ chipcHw_CLOCK_e csp_id; /* clock ID for CSP CHIPC */
+ unsigned long rate_hz; /* clock rate in Hz */
+ unsigned int use_cnt; /* usage count */
+ struct clk *parent; /* parent clock */
+};
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
new file mode 100644
index 0000000..c582409
--- /dev/null
+++ b/arch/arm/mach-bcmring/core.c
@@ -0,0 +1,358 @@
+/*
+ * derived from linux/arch/arm/mach-versatile/core.c
+ * linux/arch/arm/mach-bcmring/core.c
+ *
+ * Copyright (C) 1999 - 2003 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* Portions copyright Broadcom 2008 */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/amba/bus.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+#include <mach/system.h>
+#include <mach/hardware.h>
+#include <asm/clkdev.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware/arm_timer.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+
+#include <cfg_global.h>
+
+#include "core.h"
+#include "clock.h"
+
+#include <csp/secHw.h>
+#include <mach/csp/secHw_def.h>
+#include <mach/csp/chipcHw_inline.h>
+#include <mach/csp/tmrHw_reg.h>
+
+/* DevChip Primecells */
+AMBA_DEVICE(uartA, "dev:f1", UARTA, NULL, SZ_4K);
+AMBA_DEVICE(uartB, "dev:f2", UARTB, NULL, SZ_4K);
+
+static struct clk pll1_clk = {
+ .name = "PLL1",
+ .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL1,
+ .rate_hz = 2000000000,
+ .use_cnt = 7,
+};
+
+static struct clk uart_clk = {
+ .name = "UART",
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .csp_id = chipcHw_CLOCK_UART,
+ .rate_hz = HW_CFG_UART_CLK_HZ,
+ .parent = &pll1_clk,
+};
+
+static struct clk_lookup lookups[] = {
+ { /* UART0 */
+ .dev_id = "dev:f1",
+ .clk = &uart_clk,
+ }, { /* UART1 */
+ .dev_id = "dev:f2",
+ .clk = &uart_clk,
+ }
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+ &uartA_device,
+ &uartB_device,
+};
+
+void __init bcmring_amba_init(void)
+{
+ int i;
+ u32 bus_clock;
+
+// Linux is run initially in non-secure mode. Secure peripherals
+// generate FIQ, and must be handled in secure mode. Until we have
+// a linux security monitor implementation, keep everything in
+// non-secure mode.
+ chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_SPU);
+ secHw_setUnsecure ( secHw_BLK_MASK_CHIP_CONTROL |
+ secHw_BLK_MASK_KEY_SCAN |
+ secHw_BLK_MASK_TOUCH_SCREEN |
+ secHw_BLK_MASK_UART0 |
+ secHw_BLK_MASK_UART1 |
+ secHw_BLK_MASK_WATCHDOG |
+ secHw_BLK_MASK_SPUM |
+ secHw_BLK_MASK_DDR2 |
+ secHw_BLK_MASK_SPU |
+ secHw_BLK_MASK_PKA |
+ secHw_BLK_MASK_RNG |
+ secHw_BLK_MASK_RTC |
+ secHw_BLK_MASK_OTP |
+ secHw_BLK_MASK_BOOT |
+ secHw_BLK_MASK_MPU |
+ secHw_BLK_MASK_TZCTRL |
+ secHw_BLK_MASK_INTR );
+
+
+ // Only the devices attached to the AMBA bus are enabled just before the bus is
+ // scanned and the drivers are loaded. The clocks need to be on for the AMBA bus
+ // driver to access these blocks. The bus is probed, and the drivers are loaded.
+ // FIXME Need to remove enable of PIF once CLCD clock enable used properly in FPGA.
+ bus_clock = chipcHw_REG_BUS_CLOCK_GE
+ | chipcHw_REG_BUS_CLOCK_SDIO0
+ | chipcHw_REG_BUS_CLOCK_SDIO1;
+
+
+ chipcHw_busInterfaceClockEnable ( bus_clock );
+
+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+ struct amba_device *d = amba_devs[i];
+ amba_device_register(d, &iomem_resource);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
+}
+
+/*
+ * Where is the timer (VA)?
+ */
+#define TIMER0_VA_BASE MM_IO_BASE_TMR
+#define TIMER1_VA_BASE (MM_IO_BASE_TMR + 0x20)
+#define TIMER2_VA_BASE (MM_IO_BASE_TMR + 0x40)
+#define TIMER3_VA_BASE (MM_IO_BASE_TMR + 0x60)
+
+// Timer 0 - 25 MHz, Timer3 at bus clock rate, typically 150-166 MHz
+#if defined(CONFIG_ARCH_FPGA11107)
+// fpga cpu/bus are currently 30 times slower so scale frequency as well to
+// slow down Linux's sense of time
+#define TIMER0_FREQUENCY_MHZ (tmrHw_LOW_FREQUENCY_MHZ * 30)
+#define TIMER1_FREQUENCY_MHZ (tmrHw_LOW_FREQUENCY_MHZ * 30)
+#define TIMER3_FREQUENCY_MHZ (tmrHw_HIGH_FREQUENCY_MHZ * 30)
+#define TIMER3_FREQUENCY_KHZ (tmrHw_HIGH_FREQUENCY_HZ / 1000 * 30)
+#else
+#define TIMER0_FREQUENCY_MHZ tmrHw_LOW_FREQUENCY_MHZ
+#define TIMER1_FREQUENCY_MHZ tmrHw_LOW_FREQUENCY_MHZ
+#define TIMER3_FREQUENCY_MHZ tmrHw_HIGH_FREQUENCY_MHZ
+#define TIMER3_FREQUENCY_KHZ (tmrHw_HIGH_FREQUENCY_HZ / 1000)
+#endif
+
+#define TICKS_PER_uSEC TIMER0_FREQUENCY_MHZ
+
+/*
+ * These are useconds NOT ticks.
+ *
+ */
+ #define mSEC_1 1000
+ #define mSEC_5 (mSEC_1 * 5)
+ #define mSEC_10 (mSEC_1 * 10)
+ #define mSEC_25 (mSEC_1 * 25)
+ #define SEC_1 (mSEC_1 * 1000)
+
+/*
+ * How long is the timer interval?
+ */
+#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
+#if TIMER_INTERVAL >= 0x100000
+#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
+#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
+#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
+#elif TIMER_INTERVAL >= 0x10000
+#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
+#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
+#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
+#else
+#define TIMER_RELOAD (TIMER_INTERVAL)
+#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
+#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
+#endif
+
+static void timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
+{
+ unsigned long ctrl;
+
+ switch(mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
+
+ ctrl = TIMER_CTRL_PERIODIC;
+ ctrl |= TIMER_DIVISOR | TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* period set, and timer enabled in 'next_event' hook */
+ ctrl = TIMER_CTRL_ONESHOT;
+ ctrl |= TIMER_DIVISOR | TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ ctrl = 0;
+ }
+
+ writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
+}
+
+static int timer_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
+
+ writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
+
+ return 0;
+}
+
+static struct clock_event_device timer0_clockevent = {
+ .name = "timer0",
+ .shift = 32,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = timer_set_mode,
+ .set_next_event = timer_set_next_event,
+};
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t bcmring_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &timer0_clockevent;
+
+ writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction bcmring_timer_irq = {
+ .name = "bcmring Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = bcmring_timer_interrupt,
+};
+
+static cycle_t bcmring_get_cycles_timer1(void)
+{
+ return ~readl(TIMER1_VA_BASE + TIMER_VALUE);
+}
+
+static cycle_t bcmring_get_cycles_timer3(void)
+{
+ return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
+}
+
+static struct clocksource clocksource_bcmring_timer1 = {
+ .name = "timer1",
+ .rating = 200,
+ .read = bcmring_get_cycles_timer1,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct clocksource clocksource_bcmring_timer3 = {
+ .name = "timer3",
+ .rating = 100,
+ .read = bcmring_get_cycles_timer3,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init bcmring_clocksource_init(void)
+{
+ /* setup timer1 as free-running clocksource */
+ writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+ writel(0xffffffff, TIMER1_VA_BASE + TIMER_LOAD);
+ writel(0xffffffff, TIMER1_VA_BASE + TIMER_VALUE);
+ writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+ TIMER1_VA_BASE + TIMER_CTRL);
+
+ clocksource_bcmring_timer1.mult =
+ clocksource_khz2mult(TIMER1_FREQUENCY_MHZ * 1000, clocksource_bcmring_timer1.shift);
+ clocksource_register(&clocksource_bcmring_timer1);
+
+ /* setup timer3 as free-running clocksource */
+ writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+ writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
+ writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
+ writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+ TIMER3_VA_BASE + TIMER_CTRL);
+
+ clocksource_bcmring_timer3.mult =
+ clocksource_khz2mult(TIMER3_FREQUENCY_KHZ, clocksource_bcmring_timer3.shift);
+ clocksource_register(&clocksource_bcmring_timer3);
+
+ return 0;
+}
+
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+void __init bcmring_init_timer(void)
+{
+ printk(KERN_INFO"bcmring_init_timer\n");
+#if defined(CONFIG_BCM_SVN_REVISION)
+ printk(KERN_INFO"SVN Revision: "CONFIG_BCM_SVN_REVISION"\n");
+#endif
+ /*
+ * Initialise to a known state (all timers off)
+ */
+ writel(0, TIMER0_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER2_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+
+ /*
+ * Make irqs happen for the system timer
+ */
+ setup_irq(IRQ_TIMER0, &bcmring_timer_irq);
+
+ bcmring_clocksource_init();
+
+ timer0_clockevent.mult =
+ div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
+ timer0_clockevent.max_delta_ns =
+ clockevent_delta2ns(0xffffffff, &timer0_clockevent);
+ timer0_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xf, &timer0_clockevent);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27)
+ timer0_clockevent.cpumask = cpumask_of(0);
+#else
+ timer0_clockevent.cpumask = cpumask_of_cpu(0);
+#endif
+ clockevents_register_device(&timer0_clockevent);
+}
+
+struct sys_timer bcmring_timer = {
+ .init = bcmring_init_timer,
+};
+
diff --git a/arch/arm/mach-bcmring/core.h b/arch/arm/mach-bcmring/core.h
new file mode 100644
index 0000000..afc7b70
--- /dev/null
+++ b/arch/arm/mach-bcmring/core.h
@@ -0,0 +1,75 @@
+/*
+ * linux/arch/arm/mach-versatile/core.h
+ *
+ * Copyright (C) 2004 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* Portions copyright Broadcom 2008 */
+#ifndef __ASM_ARCH_BCMRING_H
+#define __ASM_ARCH_BCMRING_H
+
+#include <linux/version.h>
+#include <linux/amba/bus.h>
+#include <mach/csp/mm_addr.h>
+
+void __init bcmring_amba_init(void);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+
+#define AMBA_DEVICE(name,busid,base,plat,size) \
+static struct amba_device name##_device = { \
+ .dev = { \
+ .coherent_dma_mask = ~0, \
+ .bus_id = busid, \
+ .platform_data = plat \
+ }, \
+ .res = { \
+ .start = MM_ADDR_IO_##base, \
+ .end = MM_ADDR_IO_##base + (size) - 1, \
+ .flags = IORESOURCE_MEM \
+ }, \
+ .dma_mask = ~0, \
+ .irq = { \
+ IRQ_##base \
+ } \
+ /* .dma = base##_DMA,*/ \
+}
+
+#else
+
+#define AMBA_DEVICE(name,initname,base,plat,size) \
+static struct amba_device name##_device = { \
+ .dev = { \
+ .coherent_dma_mask = ~0, \
+ .init_name = initname, \
+ .platform_data = plat \
+ }, \
+ .res = { \
+ .start = MM_ADDR_IO_##base, \
+ .end = MM_ADDR_IO_##base + (size) - 1, \
+ .flags = IORESOURCE_MEM \
+ }, \
+ .dma_mask = ~0, \
+ .irq = { \
+ IRQ_##base \
+ } \
+ /* .dma = base##_DMA,*/ \
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-bcmring/dma.c b/arch/arm/mach-bcmring/dma.c
new file mode 100644
index 0000000..a144514
--- /dev/null
+++ b/arch/arm/mach-bcmring/dma.c
@@ -0,0 +1,3022 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+/****************************************************************************/
+/**
+* @file dma.c
+*
+* @brief Implements the DMA interface.
+*/
+/****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/proc_fs.h>
+
+#include <mach/timer.h>
+
+#include <linux/mm.h>
+#include <linux/pfn.h>
+#include <asm/atomic.h>
+#include <mach/dma.h>
+
+#ifdef CONFIG_BCM_KNLLOG_IRQ
+#include <linux/broadcom/knllog.h>
+// knllog needs ability to get module and channel from handle
+// csp driver should provide api to get this information
+#include <mach/csp/dmacHw_priv.h>
+#endif
+
+// I don't quite understand why dc4 fails when this is set to 1 and DMA is enabled
+// especially since dc4 doesn't use kmalloc'd memory.
+
+#define ALLOW_MAP_OF_KMALLOC_MEMORY 0
+
+/* ---- Public Variables ------------------------------------------------- */
+
+/* ---- Private Constants and Types -------------------------------------- */
+
+#define MAKE_HANDLE( controllerIdx, channelIdx ) (( (controllerIdx) << 4 ) | (channelIdx) )
+
+#define CONTROLLER_FROM_HANDLE( handle ) (( (handle) >> 4 ) & 0x0f )
+#define CHANNEL_FROM_HANDLE( handle ) ( (handle) & 0x0f )
+
+#define DMA_MAP_DEBUG 0
+
+#if DMA_MAP_DEBUG
+# define DMA_MAP_PRINT( fmt, args... ) printk( "%s: " fmt, __func__, ## args )
+#else
+# define DMA_MAP_PRINT( fmt, args... )
+#endif
+
+/* ---- Private Variables ------------------------------------------------ */
+
+static DMA_Global_t gDMA;
+static struct proc_dir_entry *gDmaDir;
+
+static atomic_t gDmaStatMemTypeKmalloc = ATOMIC_INIT( 0 );
+static atomic_t gDmaStatMemTypeVmalloc = ATOMIC_INIT( 0 );
+static atomic_t gDmaStatMemTypeUser = ATOMIC_INIT( 0 );
+static atomic_t gDmaStatMemTypeCoherent = ATOMIC_INIT( 0 );
+
+
+DMA_DeviceAttribute_t DMA_gDeviceAttribute[ DMA_NUM_DEVICE_ENTRIES ] =
+{
+ [DMA_DEVICE_MEM_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "mem-to-mem",
+ .config =
+ {
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_MEM,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+
+ },
+ },
+ [DMA_DEVICE_VPM_MEM_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_IS_DEDICATED | DMA_DEVICE_FLAG_NO_ISR,
+ .name = "vpm",
+ .dedicatedController = 0,
+ .dedicatedChannel = 0,
+ /* reserve DMA0:0 for VPM */
+ },
+ [DMA_DEVICE_NAND_MEM_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "nand",
+ .config =
+ {
+ .srcPeripheralPort = 0,
+ .dstPeripheralPort = 0,
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_6,
+ },
+ },
+ [DMA_DEVICE_PIF_MEM_TO_DEV] = /* PIF TX */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1
+ | DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO
+ | DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST | DMA_DEVICE_FLAG_PORT_PER_DMAC,
+ .name = "pif_tx",
+ .dmacPort = { 14, 5 },
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ //.dstPeripheralPort = 5 or 14
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ .maxDataPerBlock = 16256,
+ },
+ },
+ [DMA_DEVICE_PIF_DEV_TO_MEM] = /* PIF RX */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1
+ | DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO
+ //| DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST
+ | DMA_DEVICE_FLAG_PORT_PER_DMAC,
+ .name = "pif_rx",
+ .dmacPort = { 14, 5 },
+ .config =
+ {
+ //.srcPeripheralPort = 5 or 14
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ .maxDataPerBlock = 16256,
+ },
+ },
+ [DMA_DEVICE_I2S0_DEV_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "i2s0_rx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: I2S0 */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_16,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_0,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_I2S0_MEM_TO_DEV] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "i2s0_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 1, /* DST: I2S0 */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_16,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_0,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_I2S1_DEV_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "i2s1_rx",
+ .config =
+ {
+ .srcPeripheralPort = 2, /* SRC: I2S1 */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_16,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_0,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_I2S1_MEM_TO_DEV] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "i2s1_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 3, /* DST: I2S1 */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_16,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_0,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_ESW_MEM_TO_DEV] = /* ESW TX */
+ {
+ .name = "esw_tx",
+ .flags = DMA_DEVICE_FLAG_IS_DEDICATED,
+ .dedicatedController = 1,
+ .dedicatedChannel = 3,
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 1, /* DST: ESW (MTP) */
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_DISABLE,
+ // DMAx_AHB_SSTATARy
+ .srcStatusRegisterAddress = 0x00000000,
+ // DMAx_AHB_DSTATARy
+ .dstStatusRegisterAddress = 0x30490010,
+ // DMAx_AHB_CFGy
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ // DMAx_AHB_CTLy
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_0,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ },
+ },
+ [DMA_DEVICE_ESW_DEV_TO_MEM] = /* ESW RX */
+ {
+ .name = "esw_rx",
+ .flags = DMA_DEVICE_FLAG_IS_DEDICATED,
+ .dedicatedController = 1,
+ .dedicatedChannel = 2,
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: ESW (PTM) */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_DISABLE,
+ // DMAx_AHB_SSTATARy
+ .srcStatusRegisterAddress = 0x30480010,
+ // DMAx_AHB_DSTATARy
+ .dstStatusRegisterAddress = 0x00000000,
+ // DMAx_AHB_CFGy
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ // DMAx_AHB_CTLy
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_0,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ },
+ },
+ [DMA_DEVICE_APM_CODEC_A_DEV_TO_MEM] = /* APM Codec A Ingress */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "apm_a_rx",
+ .config =
+ {
+ .srcPeripheralPort = 2, /* SRC: Codec A Ingress FIFO */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_APM_CODEC_A_MEM_TO_DEV] = /* APM Codec A Egress */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "apm_a_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 3, /* DST: Codec A Egress FIFO */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_APM_CODEC_B_DEV_TO_MEM] = /* APM Codec B Ingress */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "apm_b_rx",
+ .config =
+ {
+ .srcPeripheralPort = 4, /* SRC: Codec B Ingress FIFO */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_APM_CODEC_B_MEM_TO_DEV] = /* APM Codec B Egress */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "apm_b_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 5, /* DST: Codec B Egress FIFO */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_APM_CODEC_C_DEV_TO_MEM] = /* APM Codec C Ingress */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "apm_c_rx",
+ .config =
+ {
+ .srcPeripheralPort = 4, /* SRC: Codec C Ingress FIFO */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_APM_PCM0_DEV_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "pcm0_rx",
+ .config =
+ {
+ .srcPeripheralPort = 12, /* SRC: PCM0 */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_APM_PCM0_MEM_TO_DEV] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0,
+ .name = "pcm0_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 13, /* DST: PCM0 */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_APM_PCM1_DEV_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "pcm1_rx",
+ .config =
+ {
+ .srcPeripheralPort = 14, /* SRC: PCM1 */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_4,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_CONTINUOUS,
+ },
+ },
+ [DMA_DEVICE_APM_PCM1_MEM_TO_DEV] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "pcm1_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 15, /* DST: PCM1 */
+ .srcStatusRegisterAddress = 0,
+ .dstStatusRegisterAddress = 0,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_4,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_SPUM_DEV_TO_MEM] = /* SPUM RX */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "spum_rx",
+ .config =
+ {
+ .srcPeripheralPort = 6, /* SRC: Codec A Ingress FIFO */
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ /* Busrt size **MUST** be 16 for SPUM to work */
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_16,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_16,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ /* on the RX side, SPU needs to be the flow controller */
+ .flowControler = dmacHw_FLOW_CONTROL_PERIPHERAL,
+ },
+ },
+ [DMA_DEVICE_SPUM_MEM_TO_DEV] = /* SPUM TX */
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "spum_tx",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .dstPeripheralPort = 7, /* DST: SPUM */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .blockTransferInterrupt = dmacHw_INTERRUPT_DISABLE,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_32,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_32,
+ /* Busrt size **MUST** be 16 for SPUM to work */
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_16,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_16,
+ .transferMode = dmacHw_TRANSFER_MODE_PERREQUEST,
+ },
+ },
+ [DMA_DEVICE_MEM_TO_VRAM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "mem-to-vram",
+ .config =
+ {
+ .srcPeripheralPort = 0, /* SRC: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_1,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_2,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ },
+ },
+ [DMA_DEVICE_VRAM_TO_MEM] =
+ {
+ .flags = DMA_DEVICE_FLAG_ON_DMA0 | DMA_DEVICE_FLAG_ON_DMA1,
+ .name = "vram-to-mem",
+ .config =
+ {
+ .dstPeripheralPort = 0, /* DST: memory */
+ .srcStatusRegisterAddress = 0x00000000,
+ .dstStatusRegisterAddress = 0x00000000,
+ .srcUpdate = dmacHw_SRC_ADDRESS_UPDATE_MODE_INC,
+ .dstUpdate = dmacHw_DST_ADDRESS_UPDATE_MODE_INC,
+ .transferType = dmacHw_TRANSFER_TYPE_MEM_TO_MEM,
+ .srcMasterInterface = dmacHw_SRC_MASTER_INTERFACE_2,
+ .dstMasterInterface = dmacHw_DST_MASTER_INTERFACE_1,
+ .completeTransferInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .errorInterrupt = dmacHw_INTERRUPT_ENABLE,
+ .channelPriority = dmacHw_CHANNEL_PRIORITY_7,
+ .srcMaxTransactionWidth = dmacHw_SRC_TRANSACTION_WIDTH_64,
+ .dstMaxTransactionWidth = dmacHw_DST_TRANSACTION_WIDTH_64,
+ .srcMaxBurstWidth = dmacHw_SRC_BURST_WIDTH_8,
+ .dstMaxBurstWidth = dmacHw_DST_BURST_WIDTH_8,
+ },
+ },
+};
+
+EXPORT_SYMBOL( DMA_gDeviceAttribute ); // primarily for dma-test.c
+
+/* ---- Private Function Prototypes -------------------------------------- */
+
+/* ---- Functions ------------------------------------------------------- */
+
+/****************************************************************************/
+/**
+* Displays information for /proc/dma/mem-type
+*/
+/****************************************************************************/
+
+static int dma_proc_read_mem_type( char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len += sprintf( buf + len, "dma_map_mem statistics\n" );
+ len += sprintf( buf + len, "coherent: %d\n", atomic_read( &gDmaStatMemTypeCoherent ));
+ len += sprintf( buf + len, "kmalloc: %d\n", atomic_read( &gDmaStatMemTypeKmalloc ));
+ len += sprintf( buf + len, "vmalloc: %d\n", atomic_read( &gDmaStatMemTypeVmalloc ));
+ len += sprintf( buf + len, "user: %d\n", atomic_read( &gDmaStatMemTypeUser ));
+
+ return len;
+}
+
+/****************************************************************************/
+/**
+* Displays information for /proc/dma/channels
+*/
+/****************************************************************************/
+
+static int dma_proc_read_channels( char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+ int controllerIdx;
+ int channelIdx;
+ int limit = count - 200;
+ int len = 0;
+ DMA_Channel_t *channel;
+
+ if ( down_interruptible( &gDMA.lock ) < 0 )
+ {
+ return -ERESTARTSYS;
+ }
+
+ for ( controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS; controllerIdx++ )
+ {
+ for ( channelIdx = 0; channelIdx < DMA_NUM_CHANNELS; channelIdx++ )
+ {
+ if ( len >= limit )
+ {
+ break;
+ }
+
+ channel = &gDMA.controller[ controllerIdx ].channel[ channelIdx ];
+
+ len += sprintf( buf + len, "%d:%d ", controllerIdx, channelIdx );
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED ) != 0 )
+ {
+ len += sprintf( buf + len, "Dedicated for %s ", DMA_gDeviceAttribute[ channel->devType ].name );
+ }
+ else
+ {
+ len += sprintf( buf + len, "Shared " );
+ }
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_NO_ISR ) != 0 )
+ {
+ len += sprintf( buf + len, "No ISR " );
+ }
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_LARGE_FIFO ) != 0 )
+ {
+ len += sprintf( buf + len, "Fifo: 128 " );
+ }
+ else
+ {
+ len += sprintf( buf + len, "Fifo: 64 " );
+ }
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_IN_USE ) != 0 )
+ {
+ len += sprintf( buf + len, "InUse by %s", DMA_gDeviceAttribute[ channel->devType ].name );
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+ len += sprintf( buf + len, " (%s:%d)", channel->fileName, channel->lineNum );
+#endif
+ }
+ else
+ {
+ len += sprintf( buf + len, "Avail " );
+ }
+
+ if ( channel->lastDevType != DMA_DEVICE_NONE )
+ {
+ len += sprintf( buf + len, "Last use: %s ", DMA_gDeviceAttribute[ channel->lastDevType ].name );
+ }
+
+ len += sprintf( buf + len, "\n" );
+ }
+ }
+ up( &gDMA.lock );
+ *eof = 1;
+
+ return len;
+}
+
+/****************************************************************************/
+/**
+* Displays information for /proc/dma/devices
+*/
+/****************************************************************************/
+
+static int dma_proc_read_devices( char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+ int limit = count - 200;
+ int len = 0;
+ int devIdx;
+
+ if ( down_interruptible( &gDMA.lock ) < 0 )
+ {
+ return -ERESTARTSYS;
+ }
+
+ for ( devIdx = 0; devIdx < DMA_NUM_DEVICE_ENTRIES; devIdx++ )
+ {
+ DMA_DeviceAttribute_t *devAttr = &DMA_gDeviceAttribute[ devIdx ];
+
+ if ( devAttr->name == NULL )
+ {
+ continue;
+ }
+
+ if ( len >= limit )
+ {
+ break;
+ }
+
+ len += sprintf( buf + len, "%-12s ", devAttr->name );
+
+ if (( devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED ) != 0 )
+ {
+ len += sprintf( buf + len, "Dedicated %d:%d ", devAttr->dedicatedController, devAttr->dedicatedChannel );
+ }
+ else
+ {
+ len += sprintf( buf + len, "Shared DMA:" );
+ if (( devAttr->flags & DMA_DEVICE_FLAG_ON_DMA0 ) != 0 )
+ {
+ len += sprintf( buf + len, "0" );
+ }
+ if (( devAttr->flags & DMA_DEVICE_FLAG_ON_DMA1 ) != 0 )
+ {
+ len += sprintf( buf + len, "1" );
+ }
+ len += sprintf( buf + len, " " );
+ }
+ if (( devAttr->flags & DMA_DEVICE_FLAG_NO_ISR ) != 0 )
+ {
+ len += sprintf( buf + len, "NoISR " );
+ }
+ if (( devAttr->flags & DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO ) != 0 )
+ {
+ len += sprintf( buf + len, "Allow-128 " );
+ }
+
+ len += sprintf( buf + len, "Xfer #: %Lu Ticks: %Lu Bytes: %Lu DescLen: %u\n",
+ devAttr->numTransfers,
+ devAttr->transferTicks,
+ devAttr->transferBytes,
+ devAttr->ring.bytesAllocated );
+
+ }
+
+ up( &gDMA.lock );
+ *eof = 1;
+
+ return len;
+}
+
+/****************************************************************************/
+/**
+* Determines if a DMA_Device_t is "valid".
+*
+* @return
+* TRUE - dma device is valid
+* FALSE - dma device isn't valid
+*/
+/****************************************************************************/
+
+static inline int IsDeviceValid( DMA_Device_t device )
+{
+ return ( device >= 0 ) && ( device < DMA_NUM_DEVICE_ENTRIES );
+}
+
+/****************************************************************************/
+/**
+* Translates a DMA handle into a pointer to a channel.
+*
+* @return
+* non-NULL - pointer to DMA_Channel_t
+* NULL - DMA Handle was invalid
+*/
+/****************************************************************************/
+
+static inline DMA_Channel_t *HandleToChannel( DMA_Handle_t handle )
+{
+ int controllerIdx;
+ int channelIdx;
+
+ controllerIdx = CONTROLLER_FROM_HANDLE( handle );
+ channelIdx = CHANNEL_FROM_HANDLE( handle );
+
+ if (( controllerIdx > DMA_NUM_CONTROLLERS ) || ( channelIdx > DMA_NUM_CHANNELS ))
+ {
+ return NULL;
+ }
+ return &gDMA.controller[ controllerIdx ].channel[ channelIdx ];
+}
+
+/****************************************************************************/
+/**
+* Interrupt handler which is called to process DMA interrupts.
+*/
+/****************************************************************************/
+
+static irqreturn_t dma_interrupt_handler( int irq, void *dev_id )
+{
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+ int irqStatus;
+
+ channel = (DMA_Channel_t *)dev_id;
+
+ // Figure out why we were called, and knock down the interrupt
+
+ irqStatus = dmacHw_getInterruptStatus( channel->dmacHwHandle );
+ dmacHw_clearInterrupt( channel->dmacHwHandle );
+
+ if (( channel->devType < 0 ) || ( channel->devType > DMA_NUM_DEVICE_ENTRIES ))
+ {
+ printk( KERN_ERR "dma_interrupt_handler: Invalid devType: %d\n", channel->devType );
+ return IRQ_NONE;
+ }
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+
+#ifdef CONFIG_BCM_KNLLOG_IRQ
+ if (gKnllogIrqSchedEnable & KNLLOG_DMA)
+ {
+ dmacHw_CBLK_t* pCblk = dmacHw_HANDLE_TO_CBLK ( channel->dmacHwHandle );
+ KNLLOG("tstop [%s %u:%u:%u devType=%u bytes=%u]\n",
+ devAttr->name,
+ pCblk->module,
+ pCblk->channel,
+ devAttr->config.channelPriority>>dmacHw_REG_CFG_LO_CH_PRIORITY_SHIFT,
+ channel->devType,
+ devAttr->numBytes);
+ }
+#endif
+
+ // Update stats
+
+ if (( irqStatus & dmacHw_INTERRUPT_STATUS_TRANS ) != 0 )
+ {
+ devAttr->transferTicks += ( timer_get_tick_count() - devAttr->transferStartTime );
+ }
+
+ if (( irqStatus & dmacHw_INTERRUPT_STATUS_ERROR ) != 0 )
+ {
+ printk( KERN_ERR "dma_interrupt_handler: devType :%d DMA error (%s)\n", channel->devType, devAttr->name );
+ }
+ else
+ {
+ devAttr->numTransfers++;
+ devAttr->transferBytes += devAttr->numBytes;
+ }
+
+ // Call any installed handler
+
+ if ( devAttr->devHandler != NULL )
+ {
+ devAttr->devHandler( channel->devType, irqStatus, devAttr->userData );
+ }
+
+ return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+/**
+* Allocates memory to hold a descriptor ring. The descriptor ring then
+* needs to be populated by making one or more calls to
+* dna_add_descriptors.
+*
+* The returned descriptor ring will be automatically initialized.
+*
+* @return
+* 0 Descriptor ring was allocated successfully
+* -EINVAL Invalid parameters passed in
+* -ENOMEM Unable to allocate memory for the desired number of descriptors.
+*/
+/****************************************************************************/
+
+int dma_alloc_descriptor_ring
+(
+ DMA_DescriptorRing_t *ring, ///< Descriptor ring to populate
+ int numDescriptors ///< Number of descriptors that need to be allocated.
+)
+{
+ size_t bytesToAlloc = dmacHw_descriptorLen( numDescriptors );
+
+ if (( ring == NULL ) || ( numDescriptors <= 0 ))
+ {
+ return -EINVAL;
+ }
+
+ ring->physAddr = 0;
+ ring->descriptorsAllocated = 0;
+ ring->bytesAllocated = 0;
+
+ if (( ring->virtAddr = dma_alloc_writecombine( NULL,
+ bytesToAlloc,
+ &ring->physAddr,
+ GFP_KERNEL )) == NULL )
+ {
+ return -ENOMEM;
+ }
+
+ ring->bytesAllocated = bytesToAlloc;
+ ring->descriptorsAllocated = numDescriptors;
+
+ return dma_init_descriptor_ring( ring, numDescriptors );
+}
+EXPORT_SYMBOL( dma_alloc_descriptor_ring );
+
+/****************************************************************************/
+/**
+* Releases the memory which was previously allocated for a descriptor ring.
+*/
+/****************************************************************************/
+
+void dma_free_descriptor_ring
+(
+ DMA_DescriptorRing_t *ring ///< Descriptor to release
+)
+{
+ if ( ring->virtAddr != NULL )
+ {
+ dma_free_writecombine( NULL,
+ ring->bytesAllocated,
+ ring->virtAddr,
+ ring->physAddr );
+ }
+
+ ring->bytesAllocated = 0;
+ ring->descriptorsAllocated = 0;
+ ring->virtAddr = NULL;
+ ring->physAddr = 0;
+}
+EXPORT_SYMBOL( dma_free_descriptor_ring );
+
+/****************************************************************************/
+/**
+* Initializes a descriptor ring, so that descriptors can be added to it.
+* Once a descriptor ring has been allocated, it may be reinitialized for
+* use with additional/different regions of memory.
+*
+* Note that if 7 descriptors are allocated, it's perfectly acceptable to
+* initialize the ring with a smaller number of descriptors. The amount
+* of memory allocated for the descriptor ring will not be reduced, and
+* the descriptor ring may be reinitialized later
+*
+* @return
+* 0 Descriptor ring was initialized successfully
+* -ENOMEM The descriptor which was passed in has insufficient space
+* to hold the desired number of descriptors.
+*/
+/****************************************************************************/
+
+int dma_init_descriptor_ring
+(
+ DMA_DescriptorRing_t *ring, ///< Descriptor ring to initialize
+ int numDescriptors ///< Number of descriptors to initialize.
+)
+{
+ if ( ring->virtAddr == NULL )
+ {
+ return -EINVAL;
+ }
+ if ( dmacHw_initDescriptor( ring->virtAddr,
+ ring->physAddr,
+ ring->bytesAllocated,
+ numDescriptors ) < 0 )
+ {
+ printk( KERN_ERR "dma_init_descriptor_ring: dmacHw_initDescriptor failed\n" );
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_init_descriptor_ring );
+
+/****************************************************************************/
+/**
+* Determines the number of descriptors which would be required for a
+* transfer of the indicated memory region.
+*
+* This function also needs to know which DMA device this transfer will
+* be destined for, so that the appropriate DMA configuration can be retrieved.
+* DMA parameters such as transfer width, and whether this is a memory-to-memory
+* or memory-to-peripheral, etc can all affect the actual number of descriptors
+* required.
+*
+* @return
+* > 0 Returns the number of descriptors required for the indicated transfer
+* -ENODEV - Device handed in is invalid.
+* -EINVAL Invalid parameters
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_calculate_descriptor_count
+(
+ DMA_Device_t device, ///< DMA Device that this will be associated with
+ dma_addr_t srcData, ///< Place to get data to write to device
+ dma_addr_t dstData, ///< Pointer to device data address
+ size_t numBytes ///< Number of bytes to transfer to the device
+)
+{
+ int numDescriptors;
+ DMA_DeviceAttribute_t *devAttr;
+
+ if ( !IsDeviceValid( device ))
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ device ];
+
+ if (( numDescriptors = dmacHw_calculateDescriptorCount( &devAttr->config,
+ (void *)srcData,
+ (void *)dstData,
+ numBytes )) < 0 )
+ {
+ printk( KERN_ERR "dma_calculate_descriptor_count: dmacHw_calculateDescriptorCount failed\n" );
+ return -EINVAL;
+ }
+
+ return numDescriptors;
+}
+EXPORT_SYMBOL( dma_calculate_descriptor_count );
+
+/****************************************************************************/
+/**
+* Adds a region of memory to the descriptor ring. Note that it may take
+* multiple descriptors for each region of memory. It is the callers
+* responsibility to allocate a sufficiently large descriptor ring.
+*
+* @return
+* 0 Descriptors were added successfully
+* -ENODEV Device handed in is invalid.
+* -EINVAL Invalid parameters
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_add_descriptors
+(
+ DMA_DescriptorRing_t *ring, ///< Descriptor ring to add descriptors to
+ DMA_Device_t device, ///< DMA Device that descriptors are for
+ dma_addr_t srcData, ///< Place to get data (memory or device)
+ dma_addr_t dstData, ///< Place to put data (memory or device)
+ size_t numBytes ///< Number of bytes to transfer to the device
+)
+{
+ int rc;
+ DMA_DeviceAttribute_t *devAttr;
+
+ if ( !IsDeviceValid( device ))
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ device ];
+
+ rc = dmacHw_setDataDescriptor( &devAttr->config,
+ ring->virtAddr,
+ (void *)srcData,
+ (void *)dstData,
+ numBytes );
+ if ( rc < 0 )
+ {
+ printk( KERN_ERR "dma_add_descriptors: dmacHw_setDataDescriptor failed with code: %d\n", rc );
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_add_descriptors );
+
+/****************************************************************************/
+/**
+* Sets the descriptor ring associated with a device.
+*
+* Once set, the descriptor ring will be associated with the device, even
+* across channel request/free calls. Passing in a NULL descriptor ring
+* will release any descriptor ring currently associated with the device.
+*
+* Note: If you call dma_transfer, or one of the other dma_alloc_ functions
+* the descriptor ring may be released and reallocated.
+*
+* Note: This function will release the descriptor memory for any current
+* descriptor ring associated with this device.
+*
+* @return
+* 0 Descriptors were added successfully
+* -ENODEV Device handed in is invalid.
+*/
+/****************************************************************************/
+
+int dma_set_device_descriptor_ring
+(
+ DMA_Device_t device, ///< Device to update the descriptor ring for.
+ DMA_DescriptorRing_t *ring ///< Descriptor ring to add descriptors to
+)
+{
+ DMA_DeviceAttribute_t *devAttr;
+
+ if ( !IsDeviceValid( device ))
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ device ];
+
+ // Free the previously allocated descriptor ring
+
+ dma_free_descriptor_ring( &devAttr->ring );
+
+ if ( ring != NULL )
+ {
+ // Copy in the new one
+
+ devAttr->ring = *ring;
+ }
+
+ // Set things up so that if dma_transfer is called then this descriptor
+ // ring will get freed.
+
+ devAttr->prevSrcData = 0;
+ devAttr->prevDstData = 0;
+ devAttr->prevNumBytes = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_set_device_descriptor_ring );
+
+/****************************************************************************/
+/**
+* Retrieves the descriptor ring associated with a device.
+*
+* @return
+* 0 Descriptors were added successfully
+* -ENODEV Device handed in is invalid.
+*/
+/****************************************************************************/
+
+int dma_get_device_descriptor_ring
+(
+ DMA_Device_t device, ///< Device to retrieve the descriptor ring for.
+ DMA_DescriptorRing_t *ring ///< Place to store retrieved ring
+)
+{
+ DMA_DeviceAttribute_t *devAttr;
+
+ memset( ring, 0, sizeof( *ring ));
+
+ if ( !IsDeviceValid( device ))
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ device ];
+
+ *ring = devAttr->ring;
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_get_device_descriptor_ring );
+
+/****************************************************************************/
+/**
+* Configures a DMA channel.
+*
+* @return
+* >= 0 - Initialization was successfull.
+*
+* -EBUSY - Device is currently being used.
+* -ENODEV - Device handed in is invalid.
+*/
+/****************************************************************************/
+
+static int ConfigChannel( DMA_Handle_t handle )
+{
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+ int controllerIdx;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+ controllerIdx = CONTROLLER_FROM_HANDLE( handle );
+
+ if (( devAttr->flags & DMA_DEVICE_FLAG_PORT_PER_DMAC ) != 0 )
+ {
+ if ( devAttr->config.transferType == dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL )
+ {
+ devAttr->config.dstPeripheralPort = devAttr->dmacPort[ controllerIdx ];
+ }
+ else
+ if ( devAttr->config.transferType == dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM )
+ {
+ devAttr->config.srcPeripheralPort = devAttr->dmacPort[ controllerIdx ];
+ }
+ }
+
+ if ( dmacHw_configChannel( channel->dmacHwHandle, &devAttr->config ) != 0 )
+ {
+ printk( KERN_ERR "ConfigChannel: dmacHw_configChannel failed\n" );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/**
+* Intializes all of the data structures associated with the DMA.
+* @return
+* >= 0 - Initialization was successfull.
+*
+* -EBUSY - Device is currently being used.
+* -ENODEV - Device handed in is invalid.
+*/
+/****************************************************************************/
+
+int dma_init( void )
+{
+ int rc = 0;
+ int controllerIdx;
+ int channelIdx;
+ DMA_Device_t devIdx;
+ DMA_Channel_t *channel;
+ DMA_Handle_t dedicatedHandle;
+
+ memset( &gDMA, 0, sizeof( gDMA ));
+
+ init_MUTEX_LOCKED( &gDMA.lock );
+ init_waitqueue_head( &gDMA.freeChannelQ );
+
+ // Initialize the Hardware
+
+ dmacHw_initDma();
+
+ // Start off by marking all of the DMA channels as shared.
+
+ for ( controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS; controllerIdx++ )
+ {
+ for ( channelIdx = 0; channelIdx < DMA_NUM_CHANNELS; channelIdx++ )
+ {
+ channel = &gDMA.controller[ controllerIdx ].channel[ channelIdx ];
+
+ channel->flags = 0;
+ channel->devType = DMA_DEVICE_NONE;
+ channel->lastDevType = DMA_DEVICE_NONE;
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+ channel->fileName = "";
+ channel->lineNum = 0;
+#endif
+
+ channel->dmacHwHandle = dmacHw_getChannelHandle( dmacHw_MAKE_CHANNEL_ID( controllerIdx, channelIdx ));
+ dmacHw_initChannel( channel->dmacHwHandle );
+ }
+ }
+
+ // Record any special attributes that channels may have
+
+ gDMA.controller[0].channel[0].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
+ gDMA.controller[0].channel[1].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
+ gDMA.controller[1].channel[0].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
+ gDMA.controller[1].channel[1].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
+
+ // Now walk through and record the dedicated channels.
+
+ for ( devIdx = 0; devIdx < DMA_NUM_DEVICE_ENTRIES; devIdx++ )
+ {
+ DMA_DeviceAttribute_t *devAttr = &DMA_gDeviceAttribute[ devIdx ];
+
+ if ((( devAttr->flags & DMA_DEVICE_FLAG_NO_ISR ) != 0 )
+ && (( devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED ) == 0 ))
+ {
+ printk( KERN_ERR "DMA Device: %s Can only request NO_ISR for dedicated devices\n", devAttr->name );
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (( devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED ) != 0 )
+ {
+ // This is a dedicated device. Mark the channel as being reserved.
+
+ if ( devAttr->dedicatedController >= DMA_NUM_CONTROLLERS )
+ {
+ printk( KERN_ERR "DMA Device: %s DMA Controller %d is out of range\n",
+ devAttr->name, devAttr->dedicatedController );
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if ( devAttr->dedicatedChannel >= DMA_NUM_CHANNELS )
+ {
+ printk( KERN_ERR "DMA Device: %s DMA Channel %d is out of range\n",
+ devAttr->name, devAttr->dedicatedChannel );
+ rc = -EINVAL;
+ goto out;
+ }
+
+ dedicatedHandle = MAKE_HANDLE( devAttr->dedicatedController, devAttr->dedicatedChannel );
+ channel = HandleToChannel( dedicatedHandle );
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED ) != 0 )
+ {
+ printk( "DMA Device: %s attempting to use same DMA Controller:Channel (%d:%d) as %s\n",
+ devAttr->name, devAttr->dedicatedController, devAttr->dedicatedChannel,
+ DMA_gDeviceAttribute[ channel->devType ].name );
+ rc = -EBUSY;
+ goto out;
+ }
+
+ channel->flags |= DMA_CHANNEL_FLAG_IS_DEDICATED;
+ channel->devType = devIdx;
+
+ if ( devAttr->flags & DMA_DEVICE_FLAG_NO_ISR )
+ {
+ channel->flags |= DMA_CHANNEL_FLAG_NO_ISR;
+ }
+
+ // For dedicated channels, we can go ahead and configure the DMA channel now
+ // as well.
+
+ ConfigChannel( dedicatedHandle );
+ }
+ }
+
+ // Go through and register the interrupt handlers
+
+ for ( controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS; controllerIdx++ )
+ {
+ for ( channelIdx = 0; channelIdx < DMA_NUM_CHANNELS; channelIdx++ )
+ {
+ channel = &gDMA.controller[ controllerIdx ].channel[ channelIdx ];
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_NO_ISR ) == 0 )
+ {
+ snprintf( channel->name, sizeof( channel->name ), "dma %d:%d %s", controllerIdx, channelIdx,
+ channel->devType == DMA_DEVICE_NONE ? "" : DMA_gDeviceAttribute[ channel->devType ].name );
+
+ if (( rc = request_irq( IRQ_DMA0C0 + ( controllerIdx * DMA_NUM_CHANNELS ) + channelIdx,
+ dma_interrupt_handler,
+ IRQF_DISABLED, channel->name, channel )) != 0 )
+ {
+ printk( KERN_ERR "request_irq for IRQ_DMA%dC%d failed\n", controllerIdx, channelIdx );
+ }
+ }
+ }
+ }
+
+ // Create /proc/dma/channels and /proc/dma/devices
+
+ gDmaDir = create_proc_entry( "dma", S_IFDIR | S_IRUGO | S_IXUGO, NULL );
+
+ if ( gDmaDir == NULL )
+ {
+ printk( KERN_ERR "Unable to create /proc/dma\n" );
+ }
+ else
+ {
+ create_proc_read_entry( "channels", 0, gDmaDir, dma_proc_read_channels, NULL );
+ create_proc_read_entry( "devices", 0, gDmaDir, dma_proc_read_devices, NULL );
+ create_proc_read_entry( "mem-type", 0, gDmaDir, dma_proc_read_mem_type, NULL );
+ }
+
+out:
+
+ up( &gDMA.lock );
+
+ return rc;
+}
+
+/****************************************************************************/
+/**
+* Reserves a channel for use with @a dev. If the device is setup to use
+* a shared channel, then this function will block until a free channel
+* becomes available.
+*
+* @return
+* >= 0 - A valid DMA Handle.
+* -EBUSY - Device is currently being used.
+* -ENODEV - Device handed in is invalid.
+*/
+/****************************************************************************/
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+DMA_Handle_t dma_request_channel_dbg
+(
+ DMA_Device_t dev,
+ const char *fileName,
+ int lineNum
+)
+#else
+DMA_Handle_t dma_request_channel
+(
+ DMA_Device_t dev
+)
+#endif
+{
+ DMA_Handle_t handle;
+ DMA_DeviceAttribute_t *devAttr;
+ DMA_Channel_t *channel;
+ int controllerIdx;
+ int controllerIdx2;
+ int channelIdx;
+
+ if ( down_interruptible( &gDMA.lock ) < 0 )
+ {
+ return -ERESTARTSYS;
+ }
+
+ if (( dev < 0 ) || ( dev >= DMA_NUM_DEVICE_ENTRIES ))
+ {
+ handle = -ENODEV;
+ goto out;
+ }
+ devAttr = &DMA_gDeviceAttribute[ dev ];
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+ {
+ char *s;
+
+ if (( s = strrchr( fileName, '/' )) != NULL )
+ {
+ fileName = s+1;
+ }
+ }
+#endif
+ if (( devAttr->flags & DMA_DEVICE_FLAG_IN_USE ) != 0 )
+ {
+ // This device has already been requested and not been freed
+
+ printk( KERN_ERR "%s: device %s is already requested\n", __func__, devAttr->name );
+ handle = -EBUSY;
+ goto out;
+ }
+
+ if (( devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED ) != 0 )
+ {
+ // This device has a dedicated channel.
+
+ channel = &gDMA.controller[ devAttr->dedicatedController ].channel[ devAttr->dedicatedChannel ];
+ if (( channel->flags & DMA_CHANNEL_FLAG_IN_USE ) != 0 )
+ {
+ handle = -EBUSY;
+ goto out;
+ }
+
+ channel->flags |= DMA_CHANNEL_FLAG_IN_USE;
+ devAttr->flags |= DMA_DEVICE_FLAG_IN_USE;
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+ channel->fileName = fileName;
+ channel->lineNum = lineNum;
+#endif
+ handle = MAKE_HANDLE( devAttr->dedicatedController, devAttr->dedicatedChannel );
+ goto out;
+ }
+
+ // This device needs to use one of the shared channels.
+
+ handle = DMA_INVALID_HANDLE;
+ while ( handle == DMA_INVALID_HANDLE )
+ {
+ // Scan through the shared channels and see if one is available
+
+ for ( controllerIdx2 = 0; controllerIdx2 < DMA_NUM_CONTROLLERS; controllerIdx2++ )
+ {
+ // Check to see if we should try on controller 1 first.
+
+ controllerIdx = controllerIdx2;
+ if (( devAttr->flags & DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST ) != 0 )
+ {
+ controllerIdx = 1 - controllerIdx;
+ }
+
+ // See if the device is available on the controller being tested
+
+ if (( devAttr->flags & ( DMA_DEVICE_FLAG_ON_DMA0 << controllerIdx )) != 0 )
+ {
+ for ( channelIdx = 0; channelIdx < DMA_NUM_CHANNELS; channelIdx++ )
+ {
+ channel = &gDMA.controller[ controllerIdx ].channel[ channelIdx ];
+
+ if ((( channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED ) == 0 )
+ && (( channel->flags & DMA_CHANNEL_FLAG_IN_USE ) == 0 ))
+ {
+ if ((( channel->flags & DMA_CHANNEL_FLAG_LARGE_FIFO ) != 0 )
+ && (( devAttr->flags & DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO ) == 0 ))
+ {
+ // This channel is a large fifo - don't tie it up
+ // with devices that we don't want using it.
+
+ continue;
+ }
+
+ channel->flags |= DMA_CHANNEL_FLAG_IN_USE;
+ channel->devType = dev;
+ devAttr->flags |= DMA_DEVICE_FLAG_IN_USE;
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+ channel->fileName = fileName;
+ channel->lineNum = lineNum;
+#endif
+ handle = MAKE_HANDLE( controllerIdx, channelIdx );
+
+ // Now that we've reserved the channel - we can go ahead and configure it
+
+
+ if ( ConfigChannel( handle ) != 0 )
+ {
+ handle = -EIO;
+ printk( KERN_ERR "dma_request_channel: ConfigChannel failed\n" );
+ }
+ goto out;
+ }
+ }
+ }
+ }
+
+ // No channels are currently available. Let's wait for one to free up.
+
+ {
+ DEFINE_WAIT( wait );
+
+ prepare_to_wait( &gDMA.freeChannelQ, &wait, TASK_INTERRUPTIBLE );
+ up( &gDMA.lock );
+ schedule();
+ finish_wait( &gDMA.freeChannelQ, &wait );
+
+ if (signal_pending(current))
+ {
+ // We don't currently hold gDMA.lock, so we return directly
+
+ return -ERESTARTSYS;
+ }
+ }
+
+ if ( down_interruptible( &gDMA.lock ))
+ {
+ return -ERESTARTSYS;
+ }
+ }
+
+out:
+ up( &gDMA.lock );
+
+ return handle;
+}
+
+// Create both _dbg and non _dbg functions for modules.
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+#undef dma_request_channel
+DMA_Handle_t dma_request_channel
+(
+ DMA_Device_t dev
+)
+{
+ return dma_request_channel_dbg( dev, __FILE__, __LINE__ );
+}
+
+EXPORT_SYMBOL( dma_request_channel_dbg );
+#endif
+EXPORT_SYMBOL( dma_request_channel );
+
+/****************************************************************************/
+/**
+* Frees a previously allocated DMA Handle.
+*/
+/****************************************************************************/
+
+int dma_free_channel
+(
+ DMA_Handle_t handle ///< DMA handle.
+)
+{
+ int rc = 0;
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+
+ if ( down_interruptible( &gDMA.lock ) < 0 )
+ {
+ return -ERESTARTSYS;
+ }
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+
+ if (( channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED ) == 0 )
+ {
+ channel->lastDevType = channel->devType;
+ channel->devType = DMA_DEVICE_NONE;
+ }
+ channel->flags &= ~DMA_CHANNEL_FLAG_IN_USE;
+ devAttr->flags &= ~DMA_DEVICE_FLAG_IN_USE;
+
+out:
+ up( &gDMA.lock );
+
+ wake_up_interruptible( &gDMA.freeChannelQ );
+
+ return rc;
+}
+EXPORT_SYMBOL( dma_free_channel );
+
+/****************************************************************************/
+/**
+* Determines if a given device has been configured as using a shared
+* channel.
+*
+* @return
+* 0 Device uses a dedicated channel
+* > zero Device uses a shared channel
+* < zero Error code
+*/
+/****************************************************************************/
+
+int dma_device_is_channel_shared
+(
+ DMA_Device_t device ///< Device to check.
+)
+{
+ DMA_DeviceAttribute_t *devAttr;
+
+ if ( !IsDeviceValid( device ))
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ device ];
+
+ return (( devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED ) == 0 );
+}
+EXPORT_SYMBOL( dma_device_is_channel_shared );
+
+/****************************************************************************/
+/**
+* Allocates buffers for the descriptors. This is normally done automatically
+* but needs to be done explicitly when initiating a dma from interrupt
+* context.
+*
+* @return
+* 0 Descriptors were allocated successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_alloc_descriptors
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dmacHw_TRANSFER_TYPE_e transferType, ///< Type of transfer being performed
+ dma_addr_t srcData, ///< Place to get data to write to device
+ dma_addr_t dstData, ///< Pointer to device data address
+ size_t numBytes ///< Number of bytes to transfer to the device
+)
+{
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+ int numDescriptors;
+ size_t ringBytesRequired;
+ int rc = 0;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+
+ if ( devAttr->config.transferType != transferType )
+ {
+ return -EINVAL;
+ }
+
+ // Figure out how many descriptors we need.
+
+ //printk( "srcData: 0x%08x dstData: 0x%08x, numBytes: %d\n",
+ // srcData, dstData, numBytes );
+
+ if (( numDescriptors = dmacHw_calculateDescriptorCount( &devAttr->config,
+ (void *)srcData,
+ (void *)dstData,
+ numBytes )) < 0 )
+ {
+ printk( KERN_ERR "%s: dmacHw_calculateDescriptorCount failed\n", __func__ );
+ return -EINVAL;
+ }
+
+ // Check to see if we can reuse the existing descriptor ring, or if we need to allocate
+ // a new one.
+
+ ringBytesRequired = dmacHw_descriptorLen( numDescriptors );
+
+ //printk( "ringBytesRequired: %d\n", ringBytesRequired );
+
+ if ( ringBytesRequired > devAttr->ring.bytesAllocated )
+ {
+ // Make sure that this code path is never taken from interrupt context.
+ // It's OK for an interrupt to initiate a DMA transfer, but the descriptor
+ // allocation needs to have already been done.
+
+ might_sleep();
+
+ // Free the old descriptor ring and allocate a new one.
+
+ dma_free_descriptor_ring( &devAttr->ring );
+
+ // And allocate a new one.
+
+ if (( rc = dma_alloc_descriptor_ring( &devAttr->ring, numDescriptors )) < 0 )
+ {
+ printk( KERN_ERR "%s: dma_alloc_descriptor_ring( %d ) failed\n", __func__, numDescriptors );
+ return rc;
+ }
+ // Setup the descriptor for this transfer
+
+ if ( dmacHw_initDescriptor( devAttr->ring.virtAddr,
+ devAttr->ring.physAddr,
+ devAttr->ring.bytesAllocated,
+ numDescriptors ) < 0 )
+ {
+ printk( KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__ );
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ // We've already got enough ring buffer allocated. All we need to do is reset
+ // any control information, just in case the previous DMA was stopped.
+
+ dmacHw_resetDescriptorControl( devAttr->ring.virtAddr );
+ }
+
+ // dma_alloc/free both set the prevSrc/DstData to 0. If they happen to be the same
+ // as last time, then we don't need to call setDataDescriptor again.
+
+ if ( dmacHw_setDataDescriptor( &devAttr->config,
+ devAttr->ring.virtAddr,
+ (void *)srcData,
+ (void *)dstData,
+ numBytes ) < 0 )
+ {
+ printk( KERN_ERR "%s: dmacHw_setDataDescriptor failed\n", __func__ );
+ return -EINVAL;
+ }
+
+ // Remember the critical information for this transfer so that we can eliminate
+ // another call to dma_alloc_descriptors if the caller reuses the same buffers
+
+ devAttr->prevSrcData = srcData;
+ devAttr->prevDstData = dstData;
+ devAttr->prevNumBytes = numBytes;
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_alloc_descriptors );
+
+/****************************************************************************/
+/**
+* Allocates and sets up descriptors for a double buffered circular buffer.
+*
+* This is primarily intended to be used for things like the ingress samples
+* from a microphone.
+*
+* @return
+* > 0 Number of descriptors actually allocated.
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_alloc_double_dst_descriptors
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dma_addr_t srcData, ///< Physical address of source data
+ dma_addr_t dstData1, ///< Physical address of first destination buffer
+ dma_addr_t dstData2, ///< Physical address of second destination buffer
+ size_t numBytes ///< Number of bytes in each destination buffer
+)
+{
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+ int numDst1Descriptors;
+ int numDst2Descriptors;
+ int numDescriptors;
+ size_t ringBytesRequired;
+ int rc = 0;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+
+ // Figure out how many descriptors we need.
+
+ //printk( "srcData: 0x%08x dstData: 0x%08x, numBytes: %d\n",
+ // srcData, dstData, numBytes );
+
+ if (( numDst1Descriptors = dmacHw_calculateDescriptorCount( &devAttr->config,
+ (void *)srcData,
+ (void *)dstData1,
+ numBytes )) < 0 )
+ {
+ return -EINVAL;
+ }
+ if (( numDst2Descriptors = dmacHw_calculateDescriptorCount( &devAttr->config,
+ (void *)srcData,
+ (void *)dstData2,
+ numBytes )) < 0 )
+ {
+ return -EINVAL;
+ }
+ numDescriptors = numDst1Descriptors + numDst2Descriptors;
+ //printk( "numDescriptors: %d\n", numDescriptors );
+
+ // Check to see if we can reuse the existing descriptor ring, or if we need to allocate
+ // a new one.
+
+ ringBytesRequired = dmacHw_descriptorLen( numDescriptors );
+
+ //printk( "ringBytesRequired: %d\n", ringBytesRequired );
+
+ if ( ringBytesRequired > devAttr->ring.bytesAllocated )
+ {
+ // Make sure that this code path is never taken from interrupt context.
+ // It's OK for an interrupt to initiate a DMA transfer, but the descriptor
+ // allocation needs to have already been done.
+
+ might_sleep();
+
+ // Free the old descriptor ring and allocate a new one.
+
+ dma_free_descriptor_ring( &devAttr->ring );
+
+ // And allocate a new one.
+
+ if (( rc = dma_alloc_descriptor_ring( &devAttr->ring, numDescriptors )) < 0 )
+ {
+ printk( KERN_ERR "%s: dma_alloc_descriptor_ring( %d ) failed\n", __func__, ringBytesRequired );
+ return rc;
+ }
+ }
+
+ // Setup the descriptor for this transfer. Since this function is used with
+ // CONTINUOUS DMA operations, we need to reinitialize every time, otherwise
+ // setDataDescriptor will keep trying to append onto the end.
+
+ if ( dmacHw_initDescriptor( devAttr->ring.virtAddr,
+ devAttr->ring.physAddr,
+ devAttr->ring.bytesAllocated,
+ numDescriptors ) < 0 )
+ {
+ printk( KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__ );
+ return -EINVAL;
+ }
+
+ // dma_alloc/free both set the prevSrc/DstData to 0. If they happen to be the same
+ // as last time, then we don't need to call setDataDescriptor again.
+
+ if ( dmacHw_setDataDescriptor( &devAttr->config,
+ devAttr->ring.virtAddr,
+ (void *)srcData,
+ (void *)dstData1,
+ numBytes ) < 0 )
+ {
+ printk( KERN_ERR "%s: dmacHw_setDataDescriptor 1 failed\n", __func__ );
+ return -EINVAL;
+ }
+ if ( dmacHw_setDataDescriptor( &devAttr->config,
+ devAttr->ring.virtAddr,
+ (void *)srcData,
+ (void *)dstData2,
+ numBytes ) < 0 )
+ {
+ printk( KERN_ERR "%s: dmacHw_setDataDescriptor 2 failed\n", __func__ );
+ return -EINVAL;
+ }
+
+ // You should use dma_start_transfer rather than dma_transfer_xxx so we don't
+ // try to make the 'prev' variables right.
+
+ devAttr->prevSrcData = 0;
+ devAttr->prevDstData = 0;
+ devAttr->prevNumBytes = 0;
+
+ return numDescriptors;
+}
+EXPORT_SYMBOL( dma_alloc_double_dst_descriptors );
+
+/****************************************************************************/
+/**
+* Initiates a transfer when the descriptors have already been setup.
+*
+* This is a special case, and normally, the dma_transfer_xxx functions should
+* be used.
+*
+* @return
+* 0 Transfer was started successfully
+* -ENODEV Invalid handle
+*/
+/****************************************************************************/
+
+int dma_start_transfer( DMA_Handle_t handle )
+{
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+
+ dmacHw_initiateTransfer( channel->dmacHwHandle, &devAttr->config, devAttr->ring.virtAddr );
+
+ // Since we got this far, everything went successfully
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_start_transfer );
+
+/****************************************************************************/
+/**
+* Stops a previously started DMA transfer.
+*
+* @return
+* 0 Transfer was stopped successfully
+* -ENODEV Invalid handle
+*/
+/****************************************************************************/
+
+int dma_stop_transfer( DMA_Handle_t handle )
+{
+ DMA_Channel_t *channel;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+
+ dmacHw_stopTransfer( channel->dmacHwHandle );
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_stop_transfer );
+
+/****************************************************************************/
+/**
+* Waits for a DMA to complete by polling. This function is only intended
+* to be used for testing. Interrupts should be used for most DMA operations.
+*/
+/****************************************************************************/
+
+int dma_wait_transfer_done( DMA_Handle_t handle )
+{
+ DMA_Channel_t *channel;
+ dmacHw_TRANSFER_STATUS_e status;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+
+ while (( status = dmacHw_transferCompleted( channel->dmacHwHandle )) == dmacHw_TRANSFER_STATUS_BUSY )
+ {
+ ;
+ }
+
+ if ( status == dmacHw_TRANSFER_STATUS_ERROR )
+ {
+ printk( KERN_ERR "%s: DMA transfer failed\n", __func__ );
+ return -EIO;
+ }
+ return 0;
+}
+EXPORT_SYMBOL( dma_wait_transfer_done );
+
+/****************************************************************************/
+/**
+* Initiates a DMA, allocating the descriptors as required.
+*
+* @return
+* 0 Transfer was started successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _DEV_TO_MEM and not _MEM_TO_DEV)
+*/
+/****************************************************************************/
+
+int dma_transfer
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dmacHw_TRANSFER_TYPE_e transferType, ///< Type of transfer being performed
+ dma_addr_t srcData, ///< Place to get data to write to device
+ dma_addr_t dstData, ///< Pointer to device data address
+ size_t numBytes ///< Number of bytes to transfer to the device
+)
+{
+ DMA_Channel_t *channel;
+ DMA_DeviceAttribute_t *devAttr;
+ int rc = 0;
+
+ if (( channel = HandleToChannel( handle )) == NULL )
+ {
+ return -ENODEV;
+ }
+
+ devAttr = &DMA_gDeviceAttribute[ channel->devType ];
+
+ if ( devAttr->config.transferType != transferType )
+ {
+ return -EINVAL;
+ }
+
+ // We keep track of the information about the previous request for this
+ // device, and if the attributes match, then we can use the descriptors we setup
+ // the last time, and not have to reinitialize everything.
+
+#if 0
+ if (( numBytes != devAttr->prevNumBytes )
+ || ( srcData != devAttr->prevSrcData )
+ || ( dstData != devAttr->prevDstData ))
+#endif
+ {
+ if (( rc = dma_alloc_descriptors( handle, transferType, srcData, dstData, numBytes )) != 0 )
+ {
+ return rc;
+ }
+ }
+
+ // And kick off the transfer
+
+ devAttr->numBytes = numBytes;
+ devAttr->transferStartTime = timer_get_tick_count();
+
+#ifdef CONFIG_BCM_KNLLOG_IRQ
+ if (gKnllogIrqSchedEnable & KNLLOG_DMA)
+ {
+ dmacHw_CBLK_t* pCblk = dmacHw_HANDLE_TO_CBLK ( channel->dmacHwHandle );
+ KNLLOG("tstart [%s %u:%u:%u devType=%u bytes=%u]\n",
+ devAttr->name,
+ pCblk->module,
+ pCblk->channel,
+ devAttr->config.channelPriority>>dmacHw_REG_CFG_LO_CH_PRIORITY_SHIFT,
+ channel->devType,
+ devAttr->numBytes);
+ }
+#endif
+ dmacHw_initiateTransfer( channel->dmacHwHandle, &devAttr->config, devAttr->ring.virtAddr );
+
+ // Since we got this far, everything went successfully
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_transfer );
+
+/****************************************************************************/
+/**
+* Set the callback function which will be called when a transfer completes.
+* If a NULL callback function is set, then no callback will occur.
+*
+* @note @a devHandler will be called from IRQ context.
+*
+* @return
+* 0 - Success
+* -ENODEV - Device handed in is invalid.
+*/
+/****************************************************************************/
+
+int dma_set_device_handler
+(
+ DMA_Device_t dev, ///< Device to set the callback for.
+ DMA_DeviceHandler_t devHandler, ///< Function to call when the DMA completes
+ void *userData ///< Pointer which will be passed to devHandler.
+)
+{
+ DMA_DeviceAttribute_t *devAttr;
+ unsigned long flags;
+
+ if ( !IsDeviceValid( dev ))
+ {
+ return -ENODEV;
+ }
+ devAttr = &DMA_gDeviceAttribute[ dev ];
+
+ local_irq_save( flags);
+
+ devAttr->userData = userData;
+ devAttr->devHandler = devHandler;
+
+ local_irq_restore( flags );
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_set_device_handler );
+
+/****************************************************************************/
+/**
+* Initializes a memory mapping structure
+*/
+/****************************************************************************/
+
+int dma_init_mem_map( DMA_MemMap_t *memMap )
+{
+ memset( memMap, 0, sizeof( *memMap ));
+
+ init_MUTEX( &memMap->lock );
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_init_mem_map );
+
+/****************************************************************************/
+/**
+* Releases any memory currently being held by a memory mapping structure.
+*/
+/****************************************************************************/
+
+int dma_term_mem_map( DMA_MemMap_t *memMap )
+{
+ down( &memMap->lock ); // Just being paranoid
+
+ // Free up any allocated memory
+
+ //...
+
+ up( &memMap->lock );
+ memset( memMap, 0, sizeof( *memMap ));
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_term_mem_map );
+
+#if 0
+/****************************************************************************/
+/**
+* Helper function which maps in a vmalloc'd reagion of memory
+*
+* @return
+*/
+/****************************************************************************/
+
+static int dma_map_mem_vmalloc( DMA_MemMap_t *memMap, uint8_t *mem, size_t count, enum dma_data_direction dir )
+{
+ int numPages;
+ size_t bytesRemaining;
+ DMA_Segment_t *segment;
+ DMA_Segment_t *endSegment;
+
+ numPages = ( count + offset + PAGE_SIZE - 1 ) >> PAGE_SHIFT;
+
+ // Run through the pages and figure out the physical address for each page, and amalgamate
+ // pages which are next to each other.
+
+ if ( numPages > memMap->numSegmentsAllocated )
+ {
+ kfree( memMap->segment );
+ if (( memMap->segment = kmalloc( numPages * sizeof( memMap->segment[0] ), GFP_KERNEL )) == NULL )
+ {
+ return -ENOMEM;
+ }
+ memMap->numSegmentsAllocated = numPages;
+ }
+
+ segment = memMap->segment;
+
+ // Setup the first segment (which may not start at te beginning of a page)
+
+ segment->physAddr = ( vmalloc_to_pfn( mem ) << PAGE_SHIFT ) + offset;
+ segment->numBytes = PAGE_SIZE - offset;
+ if ( segment->numBytes > count )
+ {
+ segment->numBytes = count;
+ }
+ bytesRemaining = count - segment->numBytes;
+ dma_sync_single_for_cpu( NULL, segment->physAddr, segment->numBytes, dir );
+
+ mem += segment->numBytes;
+
+ // Setup the remaining segments (which all start at a page boundary)
+
+ while ( bytesRemaining > 0 )
+ {
+ dma_addr_t physAddr = ( vmalloc_to_pfn( mem ) << PAGE_SHIFT );
+ size_t bytesThisTime = bytesRemaining;
+
+ if ( bytesThisTime > PAGE_SIZE )
+ {
+ bytesThisTime = PAGE_SIZE;
+ }
+
+ dma_sync_single_for_cpu( NULL, physAddr, bytesThisTime, dir );
+
+ if ( physAddr == ( segment->physAddr + segment->numBytes ))
+ {
+ segment->numBytes += bytesThisTime;
+ }
+ else
+ {
+ segment++;
+
+ segment->physAddr = physAddr;
+ segment->numBytes = bytesThisTime;
+ }
+ bytesRemaining -= bytesThisTime;
+ mem += bytesThisTime;
+ }
+ segment++;
+ endSegment = segment;
+
+ memMap->numSegmentsUsed = endSegment - memMap->segment;
+
+ return 0;
+}
+#endif
+
+/****************************************************************************/
+/**
+* Looks at a memory address and categorizes it.
+*
+* @return One of the values from the DMA_MemType_t enumeration.
+*/
+/****************************************************************************/
+
+DMA_MemType_t dma_mem_type( void *addr )
+{
+ unsigned long addrVal = (unsigned long)addr;
+
+ if ( addrVal >= VMALLOC_END )
+ {
+ // NOTE: DMA virtual memory space starts at 0xFFxxxxxx
+
+ // dma_alloc_xxx pages are physically and virtually contiguous
+
+ return DMA_MEM_TYPE_DMA;
+ }
+
+ // Technically, we could add one more classification. Addresses between VMALLOC_END
+ // and the beginning of the DMA virtual address could be considered to be I/O space.
+ // Right now, nobody cares about this particular classification, so we ignore it.
+
+ if ( is_vmalloc_addr( addr ))
+ {
+ // Address comes from the vmalloc'd region. Pages are virtually
+ // contiguous but NOT physically contiguous
+
+ return DMA_MEM_TYPE_VMALLOC;
+ }
+
+ if ( addrVal >= PAGE_OFFSET )
+ {
+ // PAGE_OFFSET is typically 0xC0000000
+
+ // kmalloc'd pages are physically contiguous
+
+ return DMA_MEM_TYPE_KMALLOC;
+ }
+
+ return DMA_MEM_TYPE_USER;
+}
+EXPORT_SYMBOL( dma_mem_type );
+
+/****************************************************************************/
+/**
+* Looks at a memory address and determines if we support DMA'ing to/from
+* that type of memory.
+*
+* @return boolean -
+* return value != 0 means dma supported
+* return value == 0 means dma not supported
+*/
+/****************************************************************************/
+
+int dma_mem_supports_dma( void *addr )
+{
+ DMA_MemType_t memType = dma_mem_type( addr );
+
+ return ( memType == DMA_MEM_TYPE_DMA )
+#if ALLOW_MAP_OF_KMALLOC_MEMORY
+ || ( memType == DMA_MEM_TYPE_KMALLOC )
+#endif
+ || ( memType == DMA_MEM_TYPE_USER )
+ ;
+}
+EXPORT_SYMBOL( dma_mem_supports_dma );
+
+/****************************************************************************/
+/**
+* Maps in a memory region such that it can be used for performing a DMA.
+*
+* @return
+*/
+/****************************************************************************/
+
+int dma_map_start
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ enum dma_data_direction dir ///< Direction that the mapping will be going
+)
+{
+ int rc;
+
+ down( &memMap->lock );
+
+ DMA_MAP_PRINT( "memMap: %p\n", memMap );
+
+ if ( memMap->inUse )
+ {
+ printk( KERN_ERR "%s: memory map %p is already being used\n", __func__, memMap );
+ rc = -EBUSY;
+ goto out;
+ }
+
+ memMap->inUse = 1;
+ memMap->dir = dir;
+ memMap->numRegionsUsed = 0;
+
+ rc = 0;
+
+out:
+
+ DMA_MAP_PRINT( "returning %d", rc );
+
+ up( &memMap->lock );
+
+ return rc;
+}
+EXPORT_SYMBOL( dma_map_start );
+
+/****************************************************************************/
+/**
+* Adds a segment of memory to a memory map. Each segment is both
+* physically and virtually contiguous.
+*
+* @return 0 on success, error code otherwise.
+*/
+/****************************************************************************/
+
+static int dma_map_add_segment
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ DMA_Region_t *region, ///< Region that the segment belongs to
+ void *virtAddr, ///< Virtual address of the segment being added
+ dma_addr_t physAddr, ///< Physical address of the segment being added
+ size_t numBytes ///< Number of bytes of the segment being added
+)
+{
+ DMA_Segment_t *segment;
+
+ DMA_MAP_PRINT( "memMap:%p va:%p pa:0x%x #:%d\n", memMap, virtAddr, physAddr, numBytes );
+
+ // Sanity check
+
+ if (( (unsigned long)virtAddr < (unsigned long)region->virtAddr )
+ || ( ((unsigned long)virtAddr + numBytes )) > ((unsigned long)region->virtAddr + region->numBytes ))
+ {
+ printk( KERN_ERR "%s: virtAddr %p is outside region @ %p len: %d\n", __func__, virtAddr, region->virtAddr, region->numBytes );
+ return -EINVAL;
+ }
+
+ if ( region->numSegmentsUsed > 0 )
+ {
+ // Check to see if this segment is physically contiguous with the previous one
+
+ segment = ®ion->segment[ region->numSegmentsUsed - 1 ];
+
+ if (( segment->physAddr + segment->numBytes ) == physAddr )
+ {
+ // It is - just add on to the end
+
+ DMA_MAP_PRINT( "appending %d bytes to last segment\n", numBytes );
+
+ segment->numBytes += numBytes;
+
+ return 0;
+ }
+ }
+
+ // Reallocate to hold more segments, if required.
+
+ if ( region->numSegmentsUsed >= region->numSegmentsAllocated )
+ {
+ DMA_Segment_t *newSegment;
+ size_t oldSize = region->numSegmentsAllocated * sizeof( *newSegment );
+ int newAlloc = region->numSegmentsAllocated + 4;
+ size_t newSize = newAlloc * sizeof( *newSegment );
+
+ if (( newSegment = kmalloc( newSize, GFP_KERNEL )) == NULL )
+ {
+ return -ENOMEM;
+ }
+ memcpy( newSegment, region->segment, oldSize );
+ memset( &((uint8_t *)newSegment)[ oldSize ], 0, newSize - oldSize );
+ kfree( region->segment );
+
+ region->numSegmentsAllocated = newAlloc;
+ region->segment = newSegment;
+ }
+
+ segment = ®ion->segment[ region->numSegmentsUsed ];
+ region->numSegmentsUsed++;
+
+ segment->virtAddr = virtAddr;
+ segment->physAddr = physAddr;
+ segment->numBytes = numBytes;
+
+ DMA_MAP_PRINT( "returning success\n" );
+
+ return 0;
+}
+
+/****************************************************************************/
+/**
+* Adds a region of memory to a memory map. Each region is virtually
+* contiguous, but not necessarily physically contiguous.
+*
+* @return 0 on success, error code otherwise.
+*/
+/****************************************************************************/
+
+int dma_map_add_region
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ void *mem, ///< Virtual address that we want to get a map of
+ size_t numBytes ///< Number of bytes being mapped
+)
+{
+ unsigned long addr = (unsigned long)mem;
+ unsigned int offset;
+ int rc = 0;
+ DMA_Region_t *region;
+ dma_addr_t physAddr;
+
+ down( &memMap->lock );
+
+ DMA_MAP_PRINT( "memMap:%p va:%p #:%d\n", memMap, mem, numBytes );
+
+ if ( !memMap->inUse )
+ {
+ printk( KERN_ERR "%s: Make sure you call dma_map_start first\n", __func__ );
+ rc = -EINVAL;
+ goto out;
+ }
+
+ // Reallocate to hold more regions.
+
+ if ( memMap->numRegionsUsed >= memMap->numRegionsAllocated )
+ {
+ DMA_Region_t *newRegion;
+ size_t oldSize = memMap->numRegionsAllocated * sizeof( *newRegion );
+ int newAlloc = memMap->numRegionsAllocated + 4;
+ size_t newSize = newAlloc * sizeof( *newRegion );
+
+ if (( newRegion = kmalloc( newSize, GFP_KERNEL )) == NULL )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy( newRegion, memMap->region, oldSize );
+ memset( &((uint8_t *)newRegion)[ oldSize ], 0, newSize - oldSize );
+
+ kfree( memMap->region );
+
+ memMap->numRegionsAllocated = newAlloc;
+ memMap->region = newRegion;
+ }
+
+ region = &memMap->region[ memMap->numRegionsUsed ];
+ memMap->numRegionsUsed++;
+
+ offset = addr & ~PAGE_MASK;
+
+ region->memType = dma_mem_type( mem );
+ region->virtAddr = mem;
+ region->numBytes = numBytes;
+ region->numSegmentsUsed = 0;
+ region->numLockedPages = 0;
+ region->lockedPages = NULL;
+
+ switch ( region->memType )
+ {
+ case DMA_MEM_TYPE_VMALLOC:
+ {
+ atomic_inc( &gDmaStatMemTypeVmalloc );
+
+ // printk( KERN_ERR "%s: vmalloc'd pages are not supported\n", __func__ );
+
+ // vmalloc'd pages are not physically contiguous
+
+ rc = -EINVAL;
+ break;
+ }
+
+ case DMA_MEM_TYPE_KMALLOC:
+ {
+ atomic_inc( &gDmaStatMemTypeKmalloc );
+
+ // kmalloc'd pages are physically contiguous, so they'll have exactly
+ // one segment
+
+ #if ALLOW_MAP_OF_KMALLOC_MEMORY
+ physAddr = dma_map_single( NULL, mem, numBytes, memMap->dir );
+ rc = dma_map_add_segment( memMap, region, mem, physAddr, numBytes );
+ #else
+ rc = -EINVAL;
+ #endif
+ break;
+ }
+
+ case DMA_MEM_TYPE_DMA:
+ {
+ // dma_alloc_xxx pages are physically contiguous
+
+ atomic_inc( &gDmaStatMemTypeCoherent );
+
+ physAddr = ( vmalloc_to_pfn( mem ) << PAGE_SHIFT ) + offset;
+
+ dma_sync_single_for_cpu( NULL, physAddr, numBytes, memMap->dir );
+ rc = dma_map_add_segment( memMap, region, mem, physAddr, numBytes);
+ break;
+ }
+
+ case DMA_MEM_TYPE_USER:
+ {
+ size_t firstPageOffset;
+ size_t firstPageSize;
+ struct page **pages;
+ struct task_struct *userTask;
+
+ atomic_inc( &gDmaStatMemTypeUser );
+
+#if 1
+ // If the pages are user pages, then the dma_mem_map_set_user_task function
+ // must have been previously called.
+
+ if ( memMap->userTask == NULL )
+ {
+ printk( KERN_ERR "%s: must call dma_mem_map_set_user_task when using user-mode memory\n", __func__ );
+ return -EINVAL;
+ }
+
+ // User pages need to be locked.
+
+ firstPageOffset = (unsigned long)region->virtAddr & ( PAGE_SIZE - 1 );
+ firstPageSize = PAGE_SIZE - firstPageOffset;
+
+ region->numLockedPages = ( firstPageOffset
+ + region->numBytes + PAGE_SIZE - 1 ) / PAGE_SIZE;
+ pages = kmalloc( region->numLockedPages * sizeof( struct page * ), GFP_KERNEL );
+
+ if ( pages == NULL )
+ {
+ region->numLockedPages = 0;
+ return -ENOMEM;
+ }
+
+ userTask = memMap->userTask;
+
+ down_read( &userTask->mm->mmap_sem );
+ rc = get_user_pages( userTask, // task
+ userTask->mm, // mm
+ (unsigned long)region->virtAddr, // start
+ region->numLockedPages, // len
+ memMap->dir == DMA_FROM_DEVICE, // write
+ 0, // force
+ pages, // pages (array of pointers to page)
+ NULL ); // vmas
+ up_read( &userTask->mm->mmap_sem );
+
+ if ( rc != region->numLockedPages )
+ {
+ kfree( pages );
+ region->numLockedPages = 0;
+
+ if ( rc >= 0 )
+ {
+ rc = -EINVAL;
+ }
+ }
+ else
+ {
+ uint8_t *virtAddr = region->virtAddr;
+ size_t bytesRemaining;
+ int pageIdx;
+
+ rc = 0; // Since get_user_pages returns +ve number
+
+ region->lockedPages = pages;
+
+ // We've locked the user pages. Now we need to walk them and figure
+ // out the physical addresses.
+
+ // The first page may be partial
+
+ dma_map_add_segment( memMap,
+ region,
+ virtAddr,
+ PFN_PHYS( page_to_pfn( pages[0] )) + firstPageOffset,
+ firstPageSize );
+
+ virtAddr += firstPageSize;
+ bytesRemaining = region->numBytes - firstPageSize;
+
+ for ( pageIdx = 1; pageIdx < region->numLockedPages; pageIdx++ )
+ {
+ size_t bytesThisPage = ( bytesRemaining > PAGE_SIZE ? PAGE_SIZE : bytesRemaining );
+
+ DMA_MAP_PRINT( "pageIdx:%d pages[pageIdx]=%p pfn=%u phys=%u\n",
+ pageIdx,
+ pages[pageIdx],
+ page_to_pfn( pages[pageIdx] ),
+ PFN_PHYS( page_to_pfn( pages[pageIdx] )));
+
+ dma_map_add_segment( memMap,
+ region,
+ virtAddr,
+ PFN_PHYS( page_to_pfn( pages[pageIdx] )),
+ bytesThisPage );
+
+ virtAddr += bytesThisPage;
+ bytesRemaining -= bytesThisPage;
+ }
+ }
+#else
+ printk( KERN_ERR "%s: User mode pages are not yet supported\n", __func__ );
+
+ // user pages are not physically contiguous
+
+ rc = -EINVAL;
+#endif
+ break;
+ }
+
+ default:
+ {
+ printk( KERN_ERR "%s: Unsupported memory type: %d\n", __func__, region->memType );
+
+ rc = -EINVAL;
+ break;
+ }
+ }
+
+ if ( rc != 0 )
+ {
+ memMap->numRegionsUsed--;
+ }
+
+out:
+
+ DMA_MAP_PRINT( "returning %d\n", rc );
+
+ up( &memMap->lock );
+
+ return rc;
+}
+EXPORT_SYMBOL( dma_map_add_segment );
+
+/****************************************************************************/
+/**
+* Maps in a memory region such that it can be used for performing a DMA.
+*
+* @return 0 on success, error code otherwise.
+*/
+/****************************************************************************/
+
+int dma_map_mem
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ void *mem, ///< Virtual address that we want to get a map of
+ size_t numBytes, ///< Number of bytes being mapped
+ enum dma_data_direction dir ///< Direction that the mapping will be going
+)
+{
+ int rc;
+
+ if (( rc = dma_map_start( memMap, dir )) == 0 )
+ {
+ if (( rc = dma_map_add_region( memMap, mem, numBytes )) < 0 )
+ {
+ // Since the add fails, this function will fail, and the caller won't
+ // call unmap, so we need to do it here.
+
+ dma_unmap( memMap, 0 );
+ }
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL( dma_map_mem );
+
+/****************************************************************************/
+/**
+* Setup a descriptor ring for a given memory map.
+*
+* It is assumed that the descriptor ring has already been initialized, and
+* this routine will only reallocate a new descriptor ring if the existing
+* one is too small.
+*
+* @return 0 on success, error code otherwise.
+*/
+/****************************************************************************/
+
+int dma_map_create_descriptor_ring
+(
+ DMA_Device_t dev, ///< DMA device (where the ring is stored)
+ DMA_MemMap_t *memMap, ///< Memory map that will be used
+ dma_addr_t devPhysAddr ///< Physical address of device
+)
+{
+ int rc;
+ int numDescriptors;
+ DMA_DeviceAttribute_t *devAttr;
+ DMA_Region_t *region;
+ DMA_Segment_t *segment;
+ dma_addr_t srcPhysAddr;
+ dma_addr_t dstPhysAddr;
+ int regionIdx;
+ int segmentIdx;
+
+ devAttr = &DMA_gDeviceAttribute[ dev ];
+
+ down( &memMap->lock );
+
+ // Figure out how many descriptors we need
+
+ numDescriptors = 0;
+ for ( regionIdx = 0; regionIdx < memMap->numRegionsUsed; regionIdx++ )
+ {
+ region = &memMap->region[ regionIdx ];
+
+ for ( segmentIdx = 0; segmentIdx < region->numSegmentsUsed; segmentIdx++ )
+ {
+ segment = ®ion->segment[segmentIdx];
+
+ if ( memMap->dir == DMA_TO_DEVICE )
+ {
+ srcPhysAddr = segment->physAddr;
+ dstPhysAddr = devPhysAddr;
+ }
+ else
+ {
+ srcPhysAddr = devPhysAddr;
+ dstPhysAddr = segment->physAddr;
+ }
+
+ if (( rc = dma_calculate_descriptor_count( dev, srcPhysAddr, dstPhysAddr, segment->numBytes )) < 0 )
+ {
+ printk( KERN_ERR "%s: dma_calculate_descriptor_count failed: %d\n", __func__, rc );
+ goto out;
+ }
+ numDescriptors += rc;
+ }
+ }
+
+ // Adjust the size of the ring, if it isn't big enough
+
+ if ( numDescriptors > devAttr->ring.descriptorsAllocated )
+ {
+ dma_free_descriptor_ring( &devAttr->ring );
+ if (( rc = dma_alloc_descriptor_ring( &devAttr->ring, numDescriptors )) < 0 )
+ {
+ printk( KERN_ERR "%s: dma_alloc_descriptor_ring failed: %d\n", __func__, rc );
+ goto out;
+ }
+ }
+ else
+ {
+ if (( rc = dma_init_descriptor_ring( &devAttr->ring, numDescriptors )) < 0 )
+ {
+ printk( KERN_ERR "%s: dma_init_descriptor_ring failed: %d\n", __func__, rc );
+ goto out;
+ }
+ }
+
+ // Populate the descriptors
+
+ for ( regionIdx = 0; regionIdx < memMap->numRegionsUsed; regionIdx++ )
+ {
+ region = &memMap->region[ regionIdx ];
+
+ for ( segmentIdx = 0; segmentIdx < region->numSegmentsUsed; segmentIdx++ )
+ {
+ segment = ®ion->segment[ segmentIdx ];
+
+ if ( memMap->dir == DMA_TO_DEVICE )
+ {
+ srcPhysAddr = segment->physAddr;
+ dstPhysAddr = devPhysAddr;
+ }
+ else
+ {
+ srcPhysAddr = devPhysAddr;
+ dstPhysAddr = segment->physAddr;
+ }
+
+ if (( rc = dma_add_descriptors( &devAttr->ring, dev, srcPhysAddr, dstPhysAddr, segment->numBytes )) < 0 )
+ {
+ printk( KERN_ERR "%s: dma_add_descriptors failed: %d\n", __func__, rc );
+ goto out;
+ }
+ }
+ }
+
+ rc = 0;
+
+out:
+
+ up( &memMap->lock );
+ return rc;
+}
+EXPORT_SYMBOL( dma_map_create_descriptor_ring );
+
+/****************************************************************************/
+/**
+* Maps in a memory region such that it can be used for performing a DMA.
+*
+* @return
+*/
+/****************************************************************************/
+
+int dma_unmap
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ int dirtied ///< non-zero if any of the pages were modified
+)
+{
+ int regionIdx;
+ int segmentIdx;
+ DMA_Region_t *region;
+ DMA_Segment_t *segment;
+
+ for ( regionIdx = 0; regionIdx < memMap->numRegionsUsed; regionIdx++ )
+ {
+ region = &memMap->region[ regionIdx ];
+
+ for ( segmentIdx = 0; segmentIdx < region->numSegmentsUsed; segmentIdx++ )
+ {
+ segment = ®ion->segment[ segmentIdx ];
+
+ switch ( region->memType )
+ {
+ case DMA_MEM_TYPE_VMALLOC:
+ {
+ printk( KERN_ERR "%s: vmalloc'd pages are not yet supported\n", __func__ );
+ return -EINVAL;
+ }
+
+ case DMA_MEM_TYPE_KMALLOC:
+ {
+ #if ALLOW_MAP_OF_KMALLOC_MEMORY
+ dma_unmap_single( NULL, segment->physAddr, segment->numBytes, memMap->dir );
+ #endif
+ break;
+ }
+
+ case DMA_MEM_TYPE_DMA:
+ {
+ dma_sync_single_for_cpu( NULL, segment->physAddr, segment->numBytes, memMap->dir );
+ break;
+ }
+
+ case DMA_MEM_TYPE_USER:
+ {
+ // Nothing to do here.
+
+ break;
+ }
+
+ default:
+ {
+ printk( KERN_ERR "%s: Unsupported memory type: %d\n", __func__, region->memType );
+ return -EINVAL;
+ }
+ }
+
+ segment->virtAddr = NULL;
+ segment->physAddr = 0;
+ segment->numBytes = 0;
+ }
+
+ if ( region->numLockedPages > 0 )
+ {
+ int pageIdx;
+
+ // Some user pages were locked. We need to go and unlock them now.
+
+ for ( pageIdx = 0; pageIdx < region->numLockedPages; pageIdx++ )
+ {
+ struct page *page = region->lockedPages[ pageIdx ];
+
+ if ( memMap->dir == DMA_FROM_DEVICE )
+ {
+ SetPageDirty( page );
+ }
+ page_cache_release( page );
+ }
+ kfree( region->lockedPages );
+ region->numLockedPages = 0;
+ region->lockedPages = NULL;
+ }
+
+ region->memType = DMA_MEM_TYPE_NONE;
+ region->virtAddr = NULL;
+ region->numBytes = 0;
+ region->numSegmentsUsed = 0;
+ }
+ memMap->userTask = NULL;
+ memMap->numRegionsUsed = 0;
+ memMap->inUse = 0;
+
+ up( &memMap->lock );
+
+ return 0;
+}
+EXPORT_SYMBOL( dma_unmap );
+
diff --git a/arch/arm/mach-bcmring/early_printk.c b/arch/arm/mach-bcmring/early_printk.c
new file mode 100644
index 0000000..88954e3
--- /dev/null
+++ b/arch/arm/mach-bcmring/early_printk.c
@@ -0,0 +1,105 @@
+/*****************************************************************************
+* Copyright 2005 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+#if defined( CONFIG_BCM_EARLY_PRINTK ) || defined( CONFIG_KGDB )
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <linux/console.h>
+#include <linux/init.h>
+#include <csp/uartHw.h>
+
+/* ---- External Variable Declarations ----------------------------------- */
+/* ---- External Function Prototypes ------------------------------------- */
+
+/* ---- Public Variables ------------------------------------------------- */
+/* ---- Private Constants and Types -------------------------------------- */
+#if defined( CONFIG_BCM_EARLY_CONSOLE_UARTA )
+#define EARLY_PRINTK_UART_NUM 0
+#endif
+#if defined( CONFIG_BCM_EARLY_CONSOLE_UARTB )
+#define EARLY_PRINTK_UART_NUM 1
+#endif
+
+/* ---- Private Variables ------------------------------------------------ */
+static int bcm_early_console_enabled = 0;
+
+/* ---- Private Function Prototypes -------------------------------------- */
+/* ==== Public Functions ================================================= */
+
+static int __init bcm_early_console_setup( struct console *co, char *options )
+{
+ /* Initialize the UART to 115K, 8N1 */
+ uartHw_Init( EARLY_PRINTK_UART_NUM, 115200 );
+
+ return 0;
+}
+
+static void bcm_early_console_putc( char ch )
+{
+ /* Put the character in the TX Fifo of the UART */
+ uartHw_TxFifoPut( EARLY_PRINTK_UART_NUM, ch );
+}
+
+static void bcm_early_console_write( struct console *co, const char *s, u_int count )
+{
+ /*
+ ** Write the characters out the UART, adding \r where necessary .
+ ** At end, wait for fifo to be idle so all characters are out UART before continuing.
+ */
+ if ( bcm_early_console_enabled )
+ {
+ while ( count > 0 )
+ {
+ if ( *s == '\n' )
+ {
+ bcm_early_console_putc( '\r' );
+ }
+ bcm_early_console_putc( *s );
+
+ s++;
+ count--;
+ }
+ uartHw_TxWaitIdle( EARLY_PRINTK_UART_NUM );
+ }
+}
+
+static struct console bcm_early_console =
+{
+ name: "econ",
+ write: bcm_early_console_write,
+ setup: bcm_early_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void bcm_install_early_console( void )
+{
+ bcm_early_console_enabled = 1;
+ register_console( &bcm_early_console );
+}
+
+void bcm_uninstall_early_console( void )
+{
+ /*
+ ** We don't call unregister here, because we get get enabled when
+ ** KGDB is used. KGDB registers it's own console and since we register
+ ** first the notion of "preferred" console gets lost.
+ */
+ bcm_early_console_enabled = 0;
+}
+
+#endif
+
diff --git a/arch/arm/mach-bcmring/include/cfg_global.h b/arch/arm/mach-bcmring/include/cfg_global.h
new file mode 100644
index 0000000..c71ed0a
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/cfg_global.h
@@ -0,0 +1,16 @@
+#ifndef _CFG_GLOBAL_H_
+#define _CFG_GLOBAL_H_
+
+#include <cfg_global_defines.h>
+
+#define CFG_GLOBAL_CHIP BCM11107
+#define CFG_GLOBAL_CHIP_FAMILY CFG_GLOBAL_CHIP_FAMILY_BCMRING
+#define CFG_GLOBAL_CHIP_REV 0xA0
+#define CFG_GLOBAL_CPU ARM11
+#define CFG_GLOBAL_CPU_ENDIAN le
+#define CFG_GLOBAL_RAM_SIZE 0x10000000
+#define CFG_GLOBAL_RAM_BASE 0x00000000
+#define CFG_GLOBAL_RAM_RESERVED_SIZE 0x000000
+#define CFG_GLOBAL_RTLSIM_SUPPORT 1
+
+#endif /* _CFG_GLOBAL_H_ */
diff --git a/arch/arm/mach-bcmring/include/cfg_global_defines.h b/arch/arm/mach-bcmring/include/cfg_global_defines.h
new file mode 100644
index 0000000..dbc04d0
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/cfg_global_defines.h
@@ -0,0 +1,54 @@
+/*****************************************************************************
+* Copyright 2006 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+#ifndef CFG_GLOBAL_DEFINES_H
+#define CFG_GLOBAL_DEFINES_H
+
+/* CPU */
+#define ARMEB 1
+#define MIPS32 2
+#define ARM9 3
+#define ARM11 4
+
+/* CHIP */
+#define BCM1103 1
+
+#define BCM1191 4
+#define BCM2153 5
+#define BCM2820 6
+
+#define BCM2826 8
+#define FPGA11107 9
+#define BCM11107 10
+#define BCM11109 11
+#define BCM11170 12
+#define BCM11110 13
+#define BCM11211 14
+
+/* CFG_GLOBAL_CHIP_FAMILY types */
+#define CFG_GLOBAL_CHIP_FAMILY_NONE 0
+#define CFG_GLOBAL_CHIP_FAMILY_BCM116X 2
+#define CFG_GLOBAL_CHIP_FAMILY_BCMRING 4
+#define CFG_GLOBAL_CHIP_FAMILY_BCM1103 8
+
+/* CFG_GLOBAL_ROOT_FILE_SYSTEM */
+#define JFFS2_RFS 1
+#define CRAMFS_RFS 2
+#define INITRAMFS 3
+
+#define IMAGE_HEADER_SIZE_CHECKSUM 4
+#endif
+
diff --git a/arch/arm/mach-bcmring/include/mach/clkdev.h b/arch/arm/mach-bcmring/include/mach/clkdev.h
new file mode 100644
index 0000000..04b37a8
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/clkdev.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-bcmring/include/mach/dma.h b/arch/arm/mach-bcmring/include/mach/dma.h
new file mode 100644
index 0000000..e1fd27e
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/dma.h
@@ -0,0 +1,894 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+/****************************************************************************/
+/**
+* @file dma.h
+*
+* @brief API definitions for the linux DMA interface.
+*/
+/****************************************************************************/
+
+#if !defined( ASM_ARM_ARCH_BCMRING_DMA_H )
+#define ASM_ARM_ARCH_BCMRING_DMA_H
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/semaphore.h>
+#include <csp/dmacHw.h>
+#include <mach/timer.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+// If DMA_DEBUG_TRACK_RESERVATION is set to a non-zero value, then the filename
+// and line number of the reservation request will be recorded in the channel table
+
+#define DMA_DEBUG_TRACK_RESERVATION 1
+
+#define DMA_NUM_CONTROLLERS 2
+#define DMA_NUM_CHANNELS 8 // per controller
+
+typedef enum
+{
+ DMA_DEVICE_MEM_TO_MEM, // For memory to memory transfers
+ DMA_DEVICE_I2S0_DEV_TO_MEM,
+ DMA_DEVICE_I2S0_MEM_TO_DEV,
+ DMA_DEVICE_I2S1_DEV_TO_MEM,
+ DMA_DEVICE_I2S1_MEM_TO_DEV,
+ DMA_DEVICE_APM_CODEC_A_DEV_TO_MEM,
+ DMA_DEVICE_APM_CODEC_A_MEM_TO_DEV,
+ DMA_DEVICE_APM_CODEC_B_DEV_TO_MEM,
+ DMA_DEVICE_APM_CODEC_B_MEM_TO_DEV,
+ DMA_DEVICE_APM_CODEC_C_DEV_TO_MEM, // Additional mic input for beam-forming
+ DMA_DEVICE_APM_PCM0_DEV_TO_MEM,
+ DMA_DEVICE_APM_PCM0_MEM_TO_DEV,
+ DMA_DEVICE_APM_PCM1_DEV_TO_MEM,
+ DMA_DEVICE_APM_PCM1_MEM_TO_DEV,
+ DMA_DEVICE_SPUM_DEV_TO_MEM,
+ DMA_DEVICE_SPUM_MEM_TO_DEV,
+ DMA_DEVICE_SPIH_DEV_TO_MEM,
+ DMA_DEVICE_SPIH_MEM_TO_DEV,
+ DMA_DEVICE_UART_A_DEV_TO_MEM,
+ DMA_DEVICE_UART_A_MEM_TO_DEV,
+ DMA_DEVICE_UART_B_DEV_TO_MEM,
+ DMA_DEVICE_UART_B_MEM_TO_DEV,
+ DMA_DEVICE_PIF_MEM_TO_DEV,
+ DMA_DEVICE_PIF_DEV_TO_MEM,
+ DMA_DEVICE_ESW_DEV_TO_MEM,
+ DMA_DEVICE_ESW_MEM_TO_DEV,
+ DMA_DEVICE_VPM_MEM_TO_MEM,
+ DMA_DEVICE_CLCD_MEM_TO_MEM,
+ DMA_DEVICE_NAND_MEM_TO_MEM,
+ DMA_DEVICE_MEM_TO_VRAM,
+ DMA_DEVICE_VRAM_TO_MEM,
+
+ // Add new entries before this line.
+
+ DMA_NUM_DEVICE_ENTRIES,
+ DMA_DEVICE_NONE = 0xff, // Special value to indicate that no device is currently assigned.
+
+} DMA_Device_t;
+
+/****************************************************************************
+*
+* The DMA_Handle_t is the primary object used by callers of the API.
+*
+*****************************************************************************/
+
+#define DMA_INVALID_HANDLE ((DMA_Handle_t) -1)
+
+typedef int DMA_Handle_t;
+
+/****************************************************************************
+*
+* The DMA_DescriptorRing_t contains a ring of descriptors which is used
+* to point to regions of memory.
+*
+*****************************************************************************/
+
+typedef struct
+{
+ void *virtAddr; ///< Virtual Address of the descriptor ring
+ dma_addr_t physAddr; ///< Physical address of the descriptor ring
+ int descriptorsAllocated; ///< Number of descriptors allocated in the descriptor ring
+ size_t bytesAllocated; ///< Number of bytes allocated in the descriptor ring
+
+} DMA_DescriptorRing_t;
+
+/****************************************************************************
+*
+* The DMA_MemType_t and DMA_MemMap_t are helper structures used to setup
+* DMA chains from a variety of memory sources.
+*
+*****************************************************************************/
+
+#define DMA_MEM_MAP_MIN_SIZE 4096 // Pages less than this size are better
+ // off not being DMA'd.
+
+typedef enum
+{
+ DMA_MEM_TYPE_NONE, // Not a valid setting
+ DMA_MEM_TYPE_VMALLOC, // Memory came from vmalloc call
+ DMA_MEM_TYPE_KMALLOC, // Memory came from kmalloc call
+ DMA_MEM_TYPE_DMA, // Memory came from dma_alloc_xxx call
+ DMA_MEM_TYPE_USER, // Memory came from user space.
+
+} DMA_MemType_t;
+
+// A segment represents a physically and virtually contiguous chunk of memory.
+// i.e. each segment can be DMA'd
+//
+// A user of the DMA code will add memory regions. Each region may need to be
+// represented by one or more segments.
+
+typedef struct
+{
+ void *virtAddr; // Virtual address used for this segment
+ dma_addr_t physAddr; // Physical address this segment maps to
+ size_t numBytes; // Size of the segment, in bytes
+
+} DMA_Segment_t;
+
+// A region represents a virtually contiguous chunk of memory, which may be
+// made up of multiple segments.
+
+typedef struct
+{
+ DMA_MemType_t memType;
+ void *virtAddr;
+ size_t numBytes;
+
+ // Each region (virtually contiguous) consists of one or more segments. Each
+ // segment is virtually and physically contiguous.
+
+ int numSegmentsUsed;
+ int numSegmentsAllocated;
+ DMA_Segment_t *segment;
+
+ // When a region corresponds to user memory, we need to lock all of the pages
+ // down before we can figure out the physical addresses. The lockedPage array contains
+ // the pages that were locked, and which subsequently need to be unlocked once the
+ // memory is unmapped.
+
+ unsigned numLockedPages;
+ struct page **lockedPages;
+
+} DMA_Region_t;
+
+typedef struct
+{
+ int inUse; // Is this mapping currently being used?
+ struct semaphore lock; // Acquired when using this structure
+ enum dma_data_direction dir; // Direction this transfer is intended for
+
+ // In the event that we're mapping user memory, we need to know which task
+ // the memory is for, so that we can obtain the correct mm locks.
+
+ struct task_struct *userTask;
+
+ int numRegionsUsed;
+ int numRegionsAllocated;
+ DMA_Region_t *region;
+
+} DMA_MemMap_t;
+
+/****************************************************************************
+*
+* The DMA_DeviceAttribute_t contains information which describes a
+* particular DMA device (or peripheral).
+*
+* It is anticipated that the arrary of DMA_DeviceAttribute_t's will be
+* statically initialized.
+*
+*****************************************************************************/
+
+// The device handler is called whenever a DMA operation completes. The reaon
+// for it to be called will be a bitmask with one or more of the following bits
+// set.
+
+#define DMA_HANDLER_REASON_BLOCK_COMPLETE dmacHw_INTERRUPT_STATUS_BLOCK
+#define DMA_HANDLER_REASON_TRANSFER_COMPLETE dmacHw_INTERRUPT_STATUS_TRANS
+#define DMA_HANDLER_REASON_ERROR dmacHw_INTERRUPT_STATUS_ERROR
+
+typedef void (*DMA_DeviceHandler_t)( DMA_Device_t dev, int reason, void *userData );
+
+#define DMA_DEVICE_FLAG_ON_DMA0 0x00000001
+#define DMA_DEVICE_FLAG_ON_DMA1 0x00000002
+#define DMA_DEVICE_FLAG_PORT_PER_DMAC 0x00000004 // If set, it means that the port used on DMAC0 is different from the port used on DMAC1
+#define DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST 0x00000008 // If set, allocate from DMA1 before allocating from DMA0
+#define DMA_DEVICE_FLAG_IS_DEDICATED 0x00000100
+#define DMA_DEVICE_FLAG_NO_ISR 0x00000200
+#define DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO 0x00000400
+#define DMA_DEVICE_FLAG_IN_USE 0x00000800 // If set, device is in use on a channel
+
+// Note: Some DMA devices can be used from multiple DMA Controllers. The bitmask is used to
+// determine which DMA controllers a given device can be used from, and the interface
+// array determeines the actual interface number to use for a given controller.
+
+typedef struct
+{
+ uint32_t flags; // Bitmask of DMA_DEVICE_FLAG_xxx constants
+ uint8_t dedicatedController;// Controller number to use if DMA_DEVICE_FLAG_IS_DEDICATED is set.
+ uint8_t dedicatedChannel; // Channel number to use if DMA_DEVICE_FLAG_IS_DEDICATED is set.
+ const char *name; // Will show up in the /proc entry
+
+ uint32_t dmacPort[DMA_NUM_CONTROLLERS]; // Specifies the port number when DMA_DEVICE_FLAG_PORT_PER_DMAC flag is set
+
+ dmacHw_CONFIG_t config; // Configuration to use when DMA'ing using this device
+
+ void *userData; // Passed to the devHandler
+ DMA_DeviceHandler_t devHandler; // Called when DMA operations finish.
+
+ timer_tick_count_t transferStartTime;// Time the current transfer was started
+
+ // The following statistical information will be collected and presented in a proc entry.
+ // Note: With a contiuous bandwidth of 1 Gb/sec, it would take 584 years to overflow
+ // a 64 bit counter.
+
+ uint64_t numTransfers; // Number of DMA transfers performed
+ uint64_t transferTicks; // Total time spent doing DMA transfers (measured in timer_tick_count_t's)
+ uint64_t transferBytes; // Total bytes transferred
+ uint32_t timesBlocked; // Number of times a channel was unavailable
+ uint32_t numBytes; // Last transfer size
+
+ // It's not possible to free memory which is allocated for the descriptors from within
+ // the ISR. So make the presumption that a given device will tend to use the
+ // same sized buffers over and over again, and we keep them around.
+
+ DMA_DescriptorRing_t ring; // Ring of descriptors allocated for this device
+
+ // We stash away some of the information from the previous transfer. If back-to-back
+ // transfers are performed from the same buffer, then we don't have to keep re-initializing
+ // the descriptor buffers.
+
+ uint32_t prevNumBytes;
+ dma_addr_t prevSrcData;
+ dma_addr_t prevDstData;
+
+} DMA_DeviceAttribute_t;
+
+
+/****************************************************************************
+*
+* DMA_Channel_t, DMA_Controller_t, and DMA_State_t are really internal
+* data structures and don't belong in this header file, but are included
+* merely for discussion.
+*
+* By the time this is implemented, these structures will be moved out into
+* the appropriate C source file instead.
+*
+*****************************************************************************/
+
+/****************************************************************************
+*
+* The DMA_Channel_t contains state information about each DMA channel. Some
+* of the channels are dedicated. Non-dedicated channels are shared
+* amongst the other devices.
+*
+*****************************************************************************/
+
+#define DMA_CHANNEL_FLAG_IN_USE 0x00000001
+#define DMA_CHANNEL_FLAG_IS_DEDICATED 0x00000002
+#define DMA_CHANNEL_FLAG_NO_ISR 0x00000004
+#define DMA_CHANNEL_FLAG_LARGE_FIFO 0x00000008
+
+typedef struct
+{
+ uint32_t flags; // bitmask of DMA_CHANNEL_FLAG_xxx constants
+ DMA_Device_t devType; // Device this channel is currently reserved for
+ DMA_Device_t lastDevType;// Device type that used this previously
+ char name[ 20 ]; // Name passed onto request_irq
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+ const char *fileName; // Place where channel reservation took place
+ int lineNum; // Place where channel reservation took place
+#endif
+ dmacHw_HANDLE_t dmacHwHandle; // low level channel handle.
+
+} DMA_Channel_t;
+
+/****************************************************************************
+*
+* The DMA_Controller_t contains state information about each DMA controller.
+*
+* The freeChannelQ is stored in the controller data structure rather than
+* the channel data structure since several of the devices are accessible
+* from multiple controllers, and there is no way to know which controller
+* will become available first.
+*
+*****************************************************************************/
+
+typedef struct
+{
+ DMA_Channel_t channel[ DMA_NUM_CHANNELS ];
+
+} DMA_Controller_t;
+
+/****************************************************************************
+*
+* The DMA_Global_t contains all of the global state information used by
+* the DMA code.
+*
+* Callers which need to allocate a shared channel will be queued up
+* on the freeChannelQ until a channel becomes available.
+*
+*****************************************************************************/
+
+typedef struct
+{
+ struct semaphore lock; // acquired when manipulating table entries
+ wait_queue_head_t freeChannelQ;
+
+ DMA_Controller_t controller[ DMA_NUM_CONTROLLERS ];
+
+} DMA_Global_t;
+
+/* ---- Variable Externs ------------------------------------------------- */
+
+extern DMA_DeviceAttribute_t DMA_gDeviceAttribute[ DMA_NUM_DEVICE_ENTRIES ];
+
+/* ---- Function Prototypes ---------------------------------------------- */
+
+#if defined( __KERNEL__ )
+
+/****************************************************************************/
+/**
+* Initializes the DMA module.
+*
+* @return
+* 0 - Success
+* < 0 - Error
+*/
+/****************************************************************************/
+
+int dma_init( void );
+
+#if ( DMA_DEBUG_TRACK_RESERVATION )
+DMA_Handle_t dma_request_channel_dbg( DMA_Device_t dev, const char *fileName, int lineNum );
+#define dma_request_channel( dev ) dma_request_channel_dbg( dev, __FILE__, __LINE__ )
+#else
+
+/****************************************************************************/
+/**
+* Reserves a channel for use with @a dev. If the device is setup to use
+* a shared channel, then this function will block until a free channel
+* becomes available.
+*
+* @return
+* >= 0 - A valid DMA Handle.
+* -EBUSY - Device is currently being used.
+* -ENODEV - Device handed in is invalid.
+*/
+/****************************************************************************/
+
+DMA_Handle_t dma_request_channel
+(
+ DMA_Device_t dev ///< Device to use with the allocated channel.
+);
+#endif
+
+/****************************************************************************/
+/**
+* Frees a previously allocated DMA Handle.
+*
+* @return
+* 0 - DMA Handle was released successfully.
+* -EINVAL - Invalid DMA handle
+*/
+/****************************************************************************/
+
+int dma_free_channel
+(
+ DMA_Handle_t channel ///< DMA handle.
+);
+
+/****************************************************************************/
+/**
+* Determines if a given device has been configured as using a shared
+* channel.
+*
+* @return boolean
+* 0 Device uses a dedicated channel
+* non-zero Device uses a shared channel
+*/
+/****************************************************************************/
+
+int dma_device_is_channel_shared
+(
+ DMA_Device_t dev ///< Device to check.
+);
+
+/****************************************************************************/
+/**
+* Allocates memory to hold a descriptor ring. The descriptor ring then
+* needs to be populated by making one or more calls to
+* dna_add_descriptors.
+*
+* The returned descriptor ring will be automatically initialized.
+*
+* @return
+* 0 Descriptor ring was allocated successfully
+* -ENOMEM Unable to allocate memory for the desired number of descriptors.
+*/
+/****************************************************************************/
+
+int dma_alloc_descriptor_ring
+(
+ DMA_DescriptorRing_t *ring, ///< Descriptor ring to populate
+ int numDescriptors ///< Number of descriptors that need to be allocated.
+);
+
+/****************************************************************************/
+/**
+* Releases the memory which was previously allocated for a descriptor ring.
+*/
+/****************************************************************************/
+
+void dma_free_descriptor_ring
+(
+ DMA_DescriptorRing_t *ring ///< Descriptor to release
+);
+
+/****************************************************************************/
+/**
+* Initializes a descriptor ring, so that descriptors can be added to it.
+* Once a descriptor ring has been allocated, it may be reinitialized for
+* use with additional/different regions of memory.
+*
+* Note that if 7 descriptors are allocated, it's perfectly acceptable to
+* initialize the ring with a smaller number of descriptors. The amount
+* of memory allocated for the descriptor ring will not be reduced, and
+* the descriptor ring may be reinitialized later
+*
+* @return
+* 0 Descriptor ring was initialized successfully
+* -ENOMEM The descriptor which was passed in has insufficient space
+* to hold the desired number of descriptors.
+*/
+/****************************************************************************/
+
+int dma_init_descriptor_ring
+(
+ DMA_DescriptorRing_t *ring, ///< Descriptor ring to initialize
+ int numDescriptors ///< Number of descriptors to initialize.
+);
+
+/****************************************************************************/
+/**
+* Determines the number of descriptors which would be required for a
+* transfer of the indicated memory region.
+*
+* This function also needs to know which DMA device this transfer will
+* be destined for, so that the appropriate DMA configuration can be retrieved.
+* DMA parameters such as transfer width, and whether this is a memory-to-memory
+* or memory-to-peripheral, etc can all affect the actual number of descriptors
+* required.
+*
+* @return
+* > 0 Returns the number of descriptors required for the indicated transfer
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_calculate_descriptor_count
+(
+ DMA_Device_t device, ///< DMA Device that this will be associated with
+ dma_addr_t srcData, ///< Place to get data to write to device
+ dma_addr_t dstData, ///< Pointer to device data address
+ size_t numBytes ///< Number of bytes to transfer to the device
+);
+
+/****************************************************************************/
+/**
+* Adds a region of memory to the descriptor ring. Note that it may take
+* multiple descriptors for each region of memory. It is the callers
+* responsibility to allocate a sufficiently large descriptor ring.
+*
+* @return
+* 0 Descriptors were added successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_add_descriptors
+(
+ DMA_DescriptorRing_t *ring, ///< Descriptor ring to add descriptors to
+ DMA_Device_t device, ///< DMA Device that descriptors are for
+ dma_addr_t srcData, ///< Place to get data (memory or device)
+ dma_addr_t dstData, ///< Place to put data (memory or device)
+ size_t numBytes ///< Number of bytes to transfer to the device
+);
+
+/****************************************************************************/
+/**
+* Sets the descriptor ring associated with a device.
+*
+* Once set, the descriptor ring will be associated with the device, even
+* across channel request/free calls. Passing in a NULL descriptor ring
+* will release any descriptor ring currently associated with the device.
+*
+* Note: If you call dma_transfer, or one of the other dma_alloc_ functions
+* the descriptor ring may be released and reallocated.
+*
+* Note: This function will release the descriptor memory for any current
+* descriptor ring associated with this device.
+*/
+/****************************************************************************/
+
+int dma_set_device_descriptor_ring
+(
+ DMA_Device_t device, ///< Device to update the descriptor ring for.
+ DMA_DescriptorRing_t *ring ///< Descriptor ring to add descriptors to
+);
+
+/****************************************************************************/
+/**
+* Retrieves the descriptor ring associated with a device.
+*/
+/****************************************************************************/
+
+int dma_get_device_descriptor_ring
+(
+ DMA_Device_t device, ///< Device to retrieve the descriptor ring for.
+ DMA_DescriptorRing_t *ring ///< Place to store retrieved ring
+);
+
+/****************************************************************************/
+/**
+* Allocates buffers for the descriptors. This is normally done automatically
+* but needs to be done explicitly when initiating a dma from interrupt
+* context.
+*
+* @return
+* 0 Descriptors were allocated successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_alloc_descriptors
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dmacHw_TRANSFER_TYPE_e transferType, ///< Type of transfer being performed
+ dma_addr_t srcData, ///< Place to get data to write to device
+ dma_addr_t dstData, ///< Pointer to device data address
+ size_t numBytes ///< Number of bytes to transfer to the device
+);
+
+/****************************************************************************/
+/**
+* Allocates and sets up descriptors for a double buffered circular buffer.
+*
+* This is primarily intended to be used for things like the ingress samples
+* from a microphone.
+*
+* @return
+* > 0 Number of descriptors actually allocated.
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+* -ENOMEM Memory exhausted
+*/
+/****************************************************************************/
+
+int dma_alloc_double_dst_descriptors
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dma_addr_t srcData, ///< Physical address of source data
+ dma_addr_t dstData1, ///< Physical address of first destination buffer
+ dma_addr_t dstData2, ///< Physical address of second destination buffer
+ size_t numBytes ///< Number of bytes in each destination buffer
+);
+
+/****************************************************************************/
+/**
+* Initializes a DMA_MemMap_t data structure
+*/
+/****************************************************************************/
+
+int dma_init_mem_map
+(
+ DMA_MemMap_t *memMap ///< Stores state information about the map
+);
+
+/****************************************************************************/
+/**
+* Releases any memory currently being held by a memory mapping structure.
+*/
+/****************************************************************************/
+
+int dma_term_mem_map
+(
+ DMA_MemMap_t *memMap ///< Stores state information about the map
+);
+
+/****************************************************************************/
+/**
+* Looks at a memory address and categorizes it.
+*
+* @return One of the values from the DMA_MemType_t enumeration.
+*/
+/****************************************************************************/
+
+DMA_MemType_t dma_mem_type( void *addr );
+
+/****************************************************************************/
+/**
+* Sets the process (aka userTask) associated with a mem map. This is
+* required if user-mode segments will be added to the mapping.
+*/
+/****************************************************************************/
+
+static inline void dma_mem_map_set_user_task( DMA_MemMap_t *memMap, struct task_struct *task )
+{
+ memMap->userTask = task;
+}
+
+/****************************************************************************/
+/**
+* Looks at a memory address and determines if we support DMA'ing to/from
+* that type of memory.
+*
+* @return boolean -
+* return value != 0 means dma supported
+* return value == 0 means dma not supported
+*/
+/****************************************************************************/
+
+int dma_mem_supports_dma( void *addr );
+
+/****************************************************************************/
+/**
+* Initializes a memory map for use. Since this function acquires a
+* sempaphore within the memory map, it is VERY important that dma_unmap
+* be called when you're finished using the map.
+*/
+/****************************************************************************/
+
+int dma_map_start
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ enum dma_data_direction dir ///< Direction that the mapping will be going
+);
+
+/****************************************************************************/
+/**
+* Adds a segment of memory to a memory map.
+*
+* @return 0 on success, error code otherwise.
+*/
+/****************************************************************************/
+
+int dma_map_add_region
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ void *mem, ///< Virtual address that we want to get a map of
+ size_t numBytes ///< Number of bytes being mapped
+);
+
+/****************************************************************************/
+/**
+* Creates a descriptor ring from a memory mapping.
+*
+* @return 0 on sucess, error code otherwise.
+*/
+/****************************************************************************/
+
+int dma_map_create_descriptor_ring
+(
+ DMA_Device_t dev, ///< DMA device (where the ring is stored)
+ DMA_MemMap_t *memMap, ///< Memory map that will be used
+ dma_addr_t devPhysAddr ///< Physical address of device
+);
+
+/****************************************************************************/
+/**
+* Maps in a memory region such that it can be used for performing a DMA.
+*
+* @return
+*/
+/****************************************************************************/
+
+int dma_map_mem
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ void *addr, ///< Virtual address that we want to get a map of
+ size_t count, ///< Number of bytes being mapped
+ enum dma_data_direction dir ///< Direction that the mapping will be going
+);
+
+/****************************************************************************/
+/**
+* Maps in a memory region such that it can be used for performing a DMA.
+*
+* @return
+*/
+/****************************************************************************/
+
+int dma_unmap
+(
+ DMA_MemMap_t *memMap, ///< Stores state information about the map
+ int dirtied ///< non-zero if any of the pages were modified
+);
+
+/****************************************************************************/
+/**
+* Initiates a transfer when the descriptors have already been setup.
+*
+* This is a special case, and normally, the dma_transfer_xxx functions should
+* be used.
+*
+* @return
+* 0 Transfer was started successfully
+* -ENODEV Invalid handle
+*/
+/****************************************************************************/
+
+int dma_start_transfer( DMA_Handle_t handle );
+
+/****************************************************************************/
+/**
+* Stops a previously started DMA transfer.
+*
+* @return
+* 0 Transfer was stopped successfully
+* -ENODEV Invalid handle
+*/
+/****************************************************************************/
+
+int dma_stop_transfer( DMA_Handle_t handle );
+
+/****************************************************************************/
+/**
+* Waits for a DMA to complete by polling. This function is only intended
+* to be used for testing. Interrupts should be used for most DMA operations.
+*/
+/****************************************************************************/
+
+int dma_wait_transfer_done( DMA_Handle_t handle );
+
+/****************************************************************************/
+/**
+* Initiates a DMA transfer
+*
+* @return
+* 0 Transfer was started successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+*/
+/****************************************************************************/
+
+int dma_transfer
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dmacHw_TRANSFER_TYPE_e transferType, ///< Type of transfer being performed
+ dma_addr_t srcData, ///< Place to get data to write to device
+ dma_addr_t dstData, ///< Pointer to device data address
+ size_t numBytes ///< Number of bytes to transfer to the device
+);
+
+/****************************************************************************/
+/**
+* Initiates a transfer from memory to a device.
+*
+* @return
+* 0 Transfer was started successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _DEV_TO_MEM and not _MEM_TO_DEV)
+*/
+/****************************************************************************/
+
+static inline int dma_transfer_to_device
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dma_addr_t srcData, ///< Place to get data to write to device (physical address)
+ dma_addr_t dstData, ///< Pointer to device data address (physical address)
+ size_t numBytes ///< Number of bytes to transfer to the device
+)
+{
+ return dma_transfer( handle,
+ dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
+ srcData,
+ dstData,
+ numBytes );
+}
+
+/****************************************************************************/
+/**
+* Initiates a transfer from a device to memory.
+*
+* @return
+* 0 Transfer was started successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
+*/
+/****************************************************************************/
+
+static inline int dma_transfer_from_device
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dma_addr_t srcData, ///< Pointer to the device data address (physical address)
+ dma_addr_t dstData, ///< Place to store data retrieved from the device (physical address)
+ size_t numBytes ///< Number of bytes to retrieve from the device
+)
+{
+ return dma_transfer( handle,
+ dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
+ srcData,
+ dstData,
+ numBytes );
+}
+
+/****************************************************************************/
+/**
+* Initiates a memory to memory transfer.
+*
+* @return
+* 0 Transfer was started successfully
+* -EINVAL Invalid device type for this kind of transfer
+* (i.e. the device wasn't DMA_DEVICE_MEM_TO_MEM)
+*/
+/****************************************************************************/
+
+static inline int dma_transfer_mem_to_mem
+(
+ DMA_Handle_t handle, ///< DMA Handle
+ dma_addr_t srcData, ///< Place to transfer data from (physical address)
+ dma_addr_t dstData, ///< Place to transfer data to (physical address)
+ size_t numBytes ///< Number of bytes to transfer
+)
+{
+ return dma_transfer( handle,
+ dmacHw_TRANSFER_TYPE_MEM_TO_MEM,
+ srcData,
+ dstData,
+ numBytes );
+}
+
+/****************************************************************************/
+/**
+* Set the callback function which will be called when a transfer completes.
+* If a NULL callback function is set, then no callback will occur.
+*
+* @note @a devHandler will be called from IRQ context.
+*
+* @return
+* 0 - Success
+* -ENODEV - Device handed in is invalid.
+*/
+/****************************************************************************/
+
+int dma_set_device_handler
+(
+ DMA_Device_t dev, ///< Device to set the callback for.
+ DMA_DeviceHandler_t devHandler, ///< Function to call when the DMA completes
+ void *userData ///< Pointer which will be passed to devHandler.
+);
+
+#endif
+
+#endif /* ASM_ARM_ARCH_BCMRING_DMA_H */
+
diff --git a/arch/arm/mach-bcmring/include/mach/entry-macro.S b/arch/arm/mach-bcmring/include/mach/entry-macro.S
new file mode 100644
index 0000000..6201bb0
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/entry-macro.S
@@ -0,0 +1,94 @@
+/*****************************************************************************
+* Copyright 2006 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+/*
+ *
+ * Low-level IRQ helper macros for BCM116X-based platforms
+ *
+ * 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 <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/csp/mm_io.h>
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \base, =(MM_IO_BASE_INTC0)
+ ldr \irqstat, [\base, #0] @ get status
+ ldr \irqnr, [\base, #0x10] @ mask with enable register
+ ands \irqstat, \irqstat, \irqnr
+ mov \irqnr, #IRQ_INTC0_START
+ cmp \irqstat, #0
+ bne 1001f
+
+ ldr \base, =(MM_IO_BASE_INTC1)
+ ldr \irqstat, [\base, #0] @ get status
+ ldr \irqnr, [\base, #0x10] @ mask with enable register
+ ands \irqstat, \irqstat, \irqnr
+ mov \irqnr, #IRQ_INTC1_START
+ cmp \irqstat, #0
+ bne 1001f
+
+ ldr \base, =(MM_IO_BASE_SINTC)
+ ldr \irqstat, [\base, #0] @ get status
+ ldr \irqnr, [\base, #0x10] @ mask with enable register
+ ands \irqstat, \irqstat, \irqnr
+ mov \irqnr, #0xffffffff @ code meaning no interrupt bits set
+ cmp \irqstat, #0
+ beq 1002f
+
+ mov \irqnr, #IRQ_SINTC_START @ something is set, so fixup return value
+
+1001:
+ movs \tmp, \irqstat, lsl #16
+ movne \irqstat, \tmp
+ addeq \irqnr, \irqnr, #16
+
+ movs \tmp, \irqstat, lsl #8
+ movne \irqstat, \tmp
+ addeq \irqnr, \irqnr, #8
+
+ movs \tmp, \irqstat, lsl #4
+ movne \irqstat, \tmp
+ addeq \irqnr, \irqnr, #4
+
+ movs \tmp, \irqstat, lsl #2
+ movne \irqstat, \tmp
+ addeq \irqnr, \irqnr, #2
+
+ movs \tmp, \irqstat, lsl #1
+ addeq \irqnr, \irqnr, #1
+ orrs \base, \base, #1
+
+1002: @ irqnr will be set to 0xffffffff if no irq bits are set
+ .endm
+
+
+ .macro get_irqnr_preamble, base, tmp
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ .macro irq_prio_table
+ .endm
+
+
diff --git a/arch/arm/mach-bcmring/include/mach/hardware.h b/arch/arm/mach-bcmring/include/mach/hardware.h
new file mode 100644
index 0000000..65f853b
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/hardware.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * This file contains the hardware definitions of the BCM116X.
+ *
+ * Copyright (C) 1999 ARM Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#include <mach/memory.h>
+#include <cfg_global.h>
+#include <mach/csp/mm_io.h>
+
+/* Hardware addresses of major areas.
+ * *_START is the physical address
+ * *_SIZE is the size of the region
+ * *_BASE is the virtual address
+ */
+#define RAM_START PHYS_OFFSET
+
+//#define RAM_SIZE SZ_32M
+#define RAM_SIZE (CFG_GLOBAL_RAM_SIZE-CFG_GLOBAL_RAM_SIZE_RESERVED)
+#define RAM_BASE PAGE_OFFSET
+
+#define pcibios_assign_all_busses() 1
+
+// Macros to make managing spinlocks a bit more controlled in terms of naming.
+// See reg_gpio.h, reg_irq.h, arch.c, gpio.c for example usage.
+#if defined( __KERNEL__ )
+#define HW_DECLARE_SPINLOCK(name) spinlock_t g##name##RegLock = SPIN_LOCK_UNLOCKED;
+#define HW_EXTERN_SPINLOCK(name) extern spinlock_t g##name##RegLock;
+#define HW_IRQ_SAVE(name, val) spin_lock_irqsave(&g##name##RegLock,(val))
+#define HW_IRQ_RESTORE(name, val) spin_unlock_irqrestore(&g##name##RegLock,(val))
+#else
+#define HW_DECLARE_SPINLOCK(name)
+#define HW_EXTERN_SPINLOCK(name)
+#define HW_IRQ_SAVE(name, val) {(void)(name);(void)(val);}
+#define HW_IRQ_RESTORE(name, val) {(void)(name);(void)(val);}
+#endif
+
+#define IO_START MM_IO_START
+#define IO_BASE MM_IO_BASE
+#ifndef HW_IO_PHYS_TO_VIRT
+#define HW_IO_PHYS_TO_VIRT MM_IO_PHYS_TO_VIRT
+#endif
+#define HW_IO_VIRT_TO_PHYS MM_IO_VIRT_TO_PHYS
+
+
+#endif
+
diff --git a/arch/arm/mach-bcmring/include/mach/io.h b/arch/arm/mach-bcmring/include/mach/io.h
new file mode 100644
index 0000000..d3513b9
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/io.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#include <mach/hardware.h>
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a) ((void __iomem *)HW_IO_PHYS_TO_VIRT(a))
+
+// Do not enable mem_pci for a big endian arm architecture or unexpected byteswaps will
+// happen in readw/writew etc.
+//#define __mem_pci(a) ((unsigned long)(a))
+
+//#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a))
+
+
+#define readb(c) __raw_readb(c)
+#define readw(c) __raw_readw(c)
+#define readl(c) __raw_readl(c)
+#define readb_relaxed(addr) readb(addr)
+#define readw_relaxed(addr) readw(addr)
+#define readl_relaxed(addr) readl(addr)
+
+#define readsb(p,d,l) __raw_readsb(p,d,l)
+#define readsw(p,d,l) __raw_readsw(p,d,l)
+#define readsl(p,d,l) __raw_readsl(p,d,l)
+
+#define writeb(v,c) __raw_writeb(v,c)
+#define writew(v,c) __raw_writew(v,c)
+#define writel(v,c) __raw_writel(v,c)
+
+#define writesb(p,d,l) __raw_writesb(p,d,l)
+#define writesw(p,d,l) __raw_writesw(p,d,l)
+#define writesl(p,d,l) __raw_writesl(p,d,l)
+
+#define memset_io(c,v,l) _memset_io((c),(v),(l))
+#define memcpy_fromio(a,c,l) _memcpy_fromio((a),(c),(l))
+#define memcpy_toio(c,a,l) _memcpy_toio((c),(a),(l))
+
+#define eth_io_copy_and_sum(s,c,l,b) \
+ eth_copy_and_sum((s),(c),(l),(b))
+
+#endif
diff --git a/arch/arm/mach-bcmring/include/mach/irqs.h b/arch/arm/mach-bcmring/include/mach/irqs.h
new file mode 100644
index 0000000..0bb97be
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/irqs.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2007 Broadcom
+ * Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined( ARCH_BCMRING_IRQS_H )
+#define ARCH_BCMRING_IRQS_H
+
+// INTC0 - interrupt controller 0
+#define IRQ_INTC0_START 0
+#define IRQ_DMA0C0 0 // DMA0 channel 0 interrupt
+#define IRQ_DMA0C1 1 // DMA0 channel 1 interrupt
+#define IRQ_DMA0C2 2 // DMA0 channel 2 interrupt
+#define IRQ_DMA0C3 3 // DMA0 channel 3 interrupt
+#define IRQ_DMA0C4 4 // DMA0 channel 4 interrupt
+#define IRQ_DMA0C5 5 // DMA0 channel 5 interrupt
+#define IRQ_DMA0C6 6 // DMA0 channel 6 interrupt
+#define IRQ_DMA0C7 7 // DMA0 channel 7 interrupt
+#define IRQ_DMA1C0 8 // DMA1 channel 0 interrupt
+#define IRQ_DMA1C1 9 // DMA1 channel 1 interrupt
+#define IRQ_DMA1C2 10 // DMA1 channel 2 interrupt
+#define IRQ_DMA1C3 11 // DMA1 channel 3 interrupt
+#define IRQ_DMA1C4 12 // DMA1 channel 4 interrupt
+#define IRQ_DMA1C5 13 // DMA1 channel 5 interrupt
+#define IRQ_DMA1C6 14 // DMA1 channel 6 interrupt
+#define IRQ_DMA1C7 15 // DMA1 channel 7 interrupt
+#define IRQ_VPM 16 // Voice process module interrupt
+#define IRQ_USBHD2 17 // USB host2/device2 interrupt
+#define IRQ_USBH1 18 // USB1 host interrupt
+#define IRQ_USBD 19 // USB device interrupt
+#define IRQ_SDIOH0 20 // SDIO0 host interrupt
+#define IRQ_SDIOH1 21 // SDIO1 host interrupt
+#define IRQ_TIMER0 22 // Timer0 interrupt
+#define IRQ_TIMER1 23 // Timer1 interrupt
+#define IRQ_TIMER2 24 // Timer2 interrupt
+#define IRQ_TIMER3 25 // Timer3 interrupt
+#define IRQ_SPIH 26 // SPI host interrupt
+#define IRQ_ESW 27 // Ethernet switch interrupt
+#define IRQ_APM 28 // Audio process module interrupt
+#define IRQ_GE 29 // Graphic engine interrupt
+#define IRQ_CLCD 30 // LCD Controller interrupt
+#define IRQ_PIF 31 // Peripheral interface interrupt
+#define IRQ_INTC0_END 31
+
+// INTC1 - interrupt controller 1
+#define IRQ_INTC1_START 32
+#define IRQ_GPIO0 32 // 0 GPIO bit 31//0 combined interrupt
+#define IRQ_GPIO1 33 // 1 GPIO bit 64//32 combined interrupt
+#define IRQ_I2S0 34 // 2 I2S0 interrupt
+#define IRQ_I2S1 35 // 3 I2S1 interrupt
+#define IRQ_I2CH 36 // 4 I2C host interrupt
+#define IRQ_I2CS 37 // 5 I2C slave interrupt
+#define IRQ_SPIS 38 // 6 SPI slave interrupt
+#define IRQ_GPHY 39 // 7 Gigabit Phy interrupt
+#define IRQ_FLASHC 40 // 8 Flash controller interrupt
+#define IRQ_COMMTX 41 // 9 ARM DDC transmit interrupt
+#define IRQ_COMMRX 42 // 10 ARM DDC receive interrupt
+#define IRQ_PMUIRQ 43 // 11 ARM performance monitor interrupt
+#define IRQ_UARTB 44 // 12 UARTB
+#define IRQ_WATCHDOG 45 // 13 Watchdog timer interrupt
+#define IRQ_UARTA 46 // 14 UARTA
+#define IRQ_TSC 47 // 15 Touch screen controller interrupt
+#define IRQ_KEYC 48 // 16 Key pad controller interrupt
+#define IRQ_DMPU 49 // 17 DDR2 memory partition interrupt
+#define IRQ_VMPU 50 // 18 VRAM memory partition interrupt
+#define IRQ_FMPU 51 // 19 Flash memory parition unit interrupt
+#define IRQ_RNG 52 // 20 Random number generator interrupt
+#define IRQ_RTC0 53 // 21 Real time clock periodic interrupt
+#define IRQ_RTC1 54 // 22 Real time clock one-shot interrupt
+#define IRQ_SPUM 55 // 23 Secure process module interrupt
+#define IRQ_VDEC 56 // 24 Hantro video decoder interrupt
+#define IRQ_RTC2 57 // 25 Real time clock tamper interrupt
+#define IRQ_DDRP 58 // 26 DDR Panic interrupt
+#define IRQ_INTC1_END 58
+
+// SINTC secure int controller
+#define IRQ_SINTC_START 59
+#define IRQ_SEC_WATCHDOG 59 // 0 Watchdog timer interrupt
+#define IRQ_SEC_UARTA 60 // 1 UARTA interrupt
+#define IRQ_SEC_TSC 61 // 2 Touch screen controller interrupt
+#define IRQ_SEC_KEYC 62 // 3 Key pad controller interrupt
+#define IRQ_SEC_DMPU 63 // 4 DDR2 memory partition interrupt
+#define IRQ_SEC_VMPU 64 // 5 VRAM memory partition interrupt
+#define IRQ_SEC_FMPU 65 // 6 Flash memory parition unit interrupt
+#define IRQ_SEC_RNG 66 // 7 Random number generator interrupt
+#define IRQ_SEC_RTC0 67 // 8 Real time clock periodic interrupt
+#define IRQ_SEC_RTC1 68 // 9 Real time clock one-shot interrupt
+#define IRQ_SEC_SPUM 69 // 10 Secure process module interrupt
+#define IRQ_SEC_TIMER0 70 // 11 Secure timer0 interrupt
+#define IRQ_SEC_TIMER1 71 // 12 Secure timer1 interrupt
+#define IRQ_SEC_TIMER2 72 // 13 Secure timer2 interrupt
+#define IRQ_SEC_TIMER3 73 // 14 Secure timer3 interrupt
+#define IRQ_SEC_RTC2 74 // 15 Real time clock tamper interrupt
+
+#define IRQ_SINTC_END 74
+
+// Note: there are 3 INTC registers of 32 bits each. So internal IRQs could go from 0-95
+// Since IRQs are typically viewed in decimal, we start the gpio based IRQs off at 100
+// to make the mapping easy for humans to decipher.
+
+#define IRQ_GPIO_0 100
+
+#define NUM_INTERNAL_IRQS (IRQ_SINTC_END+1)
+
+
+// I couldn't get the gpioHw_reg.h file to be included cleanly, so I hardcoded it
+//#define NUM_GPIO_IRQS GPIOHW_TOTAL_NUM_PINS
+#define NUM_GPIO_IRQS 62
+
+#define NR_IRQS (IRQ_GPIO_0 + NUM_GPIO_IRQS)
+
+#define IRQ_UNKNOWN -1
+
+
+// Tune these bits to preclude noisy or unsupported interrupt sources as required.
+#define IRQ_INTC0_VALID_MASK 0xffffffff
+#define IRQ_INTC1_VALID_MASK 0x07ffffff
+#define IRQ_SINTC_VALID_MASK 0x0000ffff
+
+
+#define gpio_to_irq( gpio ) ((gpio) + IRQ_GPIO_0 )
+#define irq_to_gpio( irq ) ((irq) - IRQ_GPIO_0 )
+
+#endif // ARCH_BCMRING_IRQS_H
+
diff --git a/arch/arm/mach-bcmring/include/mach/memory.h b/arch/arm/mach-bcmring/include/mach/memory.h
new file mode 100644
index 0000000..3e35fc1
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/memory.h
@@ -0,0 +1,47 @@
+/*****************************************************************************
+* Copyright 2005 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#include <cfg_global.h>
+
+/*
+ * Physical vs virtual RAM address space conversion. These are
+ * private definitions which should NOT be used outside memory.h
+ * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
+ */
+
+#define PHYS_OFFSET CFG_GLOBAL_RAM_BASE
+
+/*
+ * Maximum DMA memory allowed is 14M
+ */
+#define CONSISTENT_DMA_SIZE (SZ_16M - SZ_2M)
+
+/*
+ * DEPRECATED: See include/asm/memory.h
+ *
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ * address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ * to an address that the kernel can use.
+ */
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff --git a/arch/arm/mach-bcmring/include/mach/memory_settings.h b/arch/arm/mach-bcmring/include/mach/memory_settings.h
new file mode 100644
index 0000000..cee1a6c
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/memory_settings.h
@@ -0,0 +1,69 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#ifndef MEMORY_SETTINGS_H
+#define MEMORY_SETTINGS_H
+
+// ---- Include Files ----------------------------------------
+// ---- Constants and Types ----------------------------------
+
+// Memory devices
+//
+/* NAND Flash timing for 166 MHz setting */
+#define HW_CFG_NAND_tBTA ( 5 << 16 ) /* Bus turnaround cycle (n) 0-7 (30 ns) */
+#define HW_CFG_NAND_tWP ( 4 << 11 ) /* Write pulse width cycle (n+1) 0-31 (25 ns) */
+#define HW_CFG_NAND_tWR ( 1 << 9 ) /* Write recovery cycle (n+1) 0-3 (10 ns) */
+#define HW_CFG_NAND_tAS ( 0 << 7 ) /* Write address setup cycle (n+1) 0-3 ( 0 ns) */
+#define HW_CFG_NAND_tOE ( 3 << 5 ) /* Output enable delay cycle (n) 0-3 (15 ns) */
+#define HW_CFG_NAND_tRC ( 7 << 0 ) /* Read access cycle (n+2) 0-31 (50 ns) */
+
+#define HW_CFG_NAND_TCR ( HW_CFG_NAND_tBTA \
+ | HW_CFG_NAND_tWP \
+ | HW_CFG_NAND_tWR \
+ | HW_CFG_NAND_tAS \
+ | HW_CFG_NAND_tOE \
+ | HW_CFG_NAND_tRC )
+
+/* NOR Flash timing for 166 MHz setting */
+#define HW_CFG_NOR_TPRC_TWLC ( 0 << 19 ) /* Page read access cycle / Burst write latency (n+2 / n+1) (max 25ns) */
+#define HW_CFG_NOR_TBTA ( 0 << 16 ) /* Bus turnaround cycle (n) (DNA) */
+#define HW_CFG_NOR_TWP ( 6 << 11 ) /* Write pulse width cycle (n+1) (35ns) */
+#define HW_CFG_NOR_TWR ( 0 << 9 ) /* Write recovery cycle (n+1) (0ns) */
+#define HW_CFG_NOR_TAS ( 0 << 7 ) /* Write address setup cycle (n+1) (0ns) */
+#define HW_CFG_NOR_TOE ( 0 << 5 ) /* Output enable delay cycle (n) (max 25ns) */
+#define HW_CFG_NOR_TRC_TLC ( 0x10 << 0 ) /* Read access cycle / Burst read latency (n+2 / n+1) (100ns) */
+
+#define HW_CFG_FLASH0_TCR ( HW_CFG_NOR_TPRC_TWLC \
+ | HW_CFG_NOR_TBTA \
+ | HW_CFG_NOR_TWP \
+ | HW_CFG_NOR_TWR \
+ | HW_CFG_NOR_TAS \
+ | HW_CFG_NOR_TOE \
+ | HW_CFG_NOR_TRC_TLC )
+#define HW_CFG_FLASH1_TCR HW_CFG_FLASH0_TCR
+#define HW_CFG_FLASH2_TCR HW_CFG_FLASH0_TCR
+
+// SDRAM Settings
+//
+// #define HW_CFG_SDRAM_CAS_LATENCY 5 // Default 5, Values [3..6]
+// #define HW_CFG_SDRAM_CHIP_SELECT_CNT 1 // Default 1, Vaules [1..2]
+// #define HW_CFG_SDRAM_SPEED_GRADE 667 // Default 667, Values [400,533,667,800]
+// #define HW_CFG_SDRAM_WIDTH_BITS 16 // Default 16, Vaules [8,16]
+//
+#define HW_CFG_SDRAM_SIZE_BYTES 0x10000000 // Total memory, not per device size
+
+// ---- Variable Externs -------------------------------------
+// ---- Function Prototypes ----------------------------------
+
+#endif /* MEMORY_SETTINGS_H */
diff --git a/arch/arm/mach-bcmring/include/mach/reg_nand.h b/arch/arm/mach-bcmring/include/mach/reg_nand.h
new file mode 100644
index 0000000..e7853cc
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/reg_nand.h
@@ -0,0 +1,65 @@
+/*****************************************************************************
+* Copyright 2001 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+
+/*
+*
+*****************************************************************************
+*
+* REG_NAND.h
+*
+* PURPOSE:
+*
+* This file contains definitions for the nand registers:
+*
+* NOTES:
+*
+*****************************************************************************/
+
+
+#if !defined( __ASM_ARCH_REG_NAND_H )
+#define __ASM_ARCH_REG_NAND_H
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <csp/reg.h>
+#include <mach/reg_umi.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+#define HW_NAND_BASE MM_IO_BASE_NAND // NAND Flash
+
+// DMA accesses by the bootstrap need hard nonvirtual addresses
+#define REG_NAND_CMD __REG16( HW_NAND_BASE + 0 )
+#define REG_NAND_ADDR __REG16( HW_NAND_BASE + 4 )
+
+#define REG_NAND_PHYS_DATA16 (HW_NAND_BASE + 8)
+#define REG_NAND_PHYS_DATA8 (HW_NAND_BASE + 8)
+#define REG_NAND_DATA16 __REG16( REG_NAND_PHYS_DATA16 )
+#define REG_NAND_DATA8 __REG8 ( REG_NAND_PHYS_DATA8 )
+
+/* use appropriate offset to make sure it start at the 1K boundary */
+#define REG_NAND_PHYS_DATA_DMA (HW_NAND_BASE + 0x400)
+#define REG_NAND_DATA_DMA __REG32( REG_NAND_PHYS_DATA_DMA )
+
+/* Linux DMA requires physical address of the data register */
+#define REG_NAND_DATA16_PADDR HW_IO_VIRT_TO_PHYS( REG_NAND_PHYS_DATA16 )
+#define REG_NAND_DATA8_PADDR HW_IO_VIRT_TO_PHYS( REG_NAND_PHYS_DATA8 )
+#define REG_NAND_DATA_PADDR HW_IO_VIRT_TO_PHYS( REG_NAND_PHYS_DATA_DMA )
+
+#define NAND_BUS_16BIT() ( 0 )
+#define NAND_BUS_8BIT() ( !NAND_BUS_16BIT() )
+
+#endif
diff --git a/arch/arm/mach-bcmring/include/mach/reg_umi.h b/arch/arm/mach-bcmring/include/mach/reg_umi.h
new file mode 100644
index 0000000..8d0820e
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/reg_umi.h
@@ -0,0 +1,149 @@
+/*****************************************************************************
+* Copyright 2005 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+
+/*
+*
+*****************************************************************************
+*
+* REG_UMI.h
+*
+* PURPOSE:
+*
+* This file contains definitions for the nand registers:
+*
+* NOTES:
+*
+*****************************************************************************/
+
+
+#if !defined( __ASM_ARCH_REG_UMI_H )
+#define __ASM_ARCH_REG_UMI_H
+
+/* ---- Include Files ---------------------------------------------------- */
+#include <csp/reg.h>
+#include <mach/csp/mm_io.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+#define HW_UMI_BASE MM_IO_BASE_UMI // Unified Memory Interface Ctrl Register
+
+#define REG_UMI_FLASH0_TCR __REG32( HW_UMI_BASE + 0x00 ) // Flash bank 0 timing and control register
+#define REG_UMI_FLASH1_TCR __REG32( HW_UMI_BASE + 0x04 ) // Flash bank 1 timing and control register
+#define REG_UMI_FLASH2_TCR __REG32( HW_UMI_BASE + 0x08 ) // Flash bank 2 timing and control register
+#define REG_UMI_MMD_ICR __REG32( HW_UMI_BASE + 0x0c ) // MMD interface and control register
+#define REG_UMI_NAND_TCR __REG32( HW_UMI_BASE + 0x18 ) // NAND timing and control register
+#define REG_UMI_NAND_RCSR __REG32( HW_UMI_BASE + 0x1c ) // NAND ready/chip select register
+#define REG_UMI_NAND_ECC_CSR __REG32( HW_UMI_BASE + 0x20 ) // NAND ECC control & status register
+#define REG_UMI_NAND_ECC_DATA __REG32( HW_UMI_BASE + 0x24 ) // NAND ECC data register XXB2B1B0
+#define REG_UMI_BCH_N __REG32( HW_UMI_BASE + 0x40 ) // BCH ECC Parameter N
+#define REG_UMI_BCH_K __REG32( HW_UMI_BASE + 0x44 ) // BCH ECC Parameter T
+#define REG_UMI_BCH_T __REG32( HW_UMI_BASE + 0x48 ) // BCH ECC Parameter K
+#define REG_UMI_BCH_CTRL_STATUS __REG32( HW_UMI_BASE + 0x4C ) // BCH ECC Contro Status
+#define REG_UMI_BCH_WR_ECC_0 __REG32( HW_UMI_BASE + 0x50 ) // BCH WR ECC 31:0
+#define REG_UMI_BCH_WR_ECC_1 __REG32( HW_UMI_BASE + 0x54 ) // BCH WR ECC 63:32
+#define REG_UMI_BCH_WR_ECC_2 __REG32( HW_UMI_BASE + 0x58 ) // BCH WR ECC 95:64
+#define REG_UMI_BCH_WR_ECC_3 __REG32( HW_UMI_BASE + 0x5c ) // BCH WR ECC 127:96
+#define REG_UMI_BCH_WR_ECC_4 __REG32( HW_UMI_BASE + 0x60 ) // BCH WR ECC 155:128
+#define REG_UMI_BCH_RD_ERR_LOC_1_0 __REG32( HW_UMI_BASE + 0x64 ) // BCH Read Error Location 1,0
+#define REG_UMI_BCH_RD_ERR_LOC_3_2 __REG32( HW_UMI_BASE + 0x68 ) // BCH Read Error Location 3,2
+#define REG_UMI_BCH_RD_ERR_LOC_5_4 __REG32( HW_UMI_BASE + 0x6c ) // BCH Read Error Location 5,4
+#define REG_UMI_BCH_RD_ERR_LOC_7_6 __REG32( HW_UMI_BASE + 0x70 ) // BCH Read Error Location 7,6
+#define REG_UMI_BCH_RD_ERR_LOC_9_8 __REG32( HW_UMI_BASE + 0x74 ) // BCH Read Error Location 9,8
+#define REG_UMI_BCH_RD_ERR_LOC_B_A __REG32( HW_UMI_BASE + 0x78 ) // BCH Read Error Location 11,10
+
+// REG_UMI_FLASH0/1/2_TCR, REG_UMI_SRAM0/1_TCR bits
+#define REG_UMI_TCR_WAITEN 0x80000000 // Enable wait pin during burst write or read
+#define REG_UMI_TCR_LOWFREQ 0x40000000 // Enable mem ctrlr to work iwth ext mem of lower freq than AHB clk
+#define REG_UMI_TCR_MEMTYPE_SYNCWRITE 0x20000000 // 1=synch write, 0=async write
+#define REG_UMI_TCR_MEMTYPE_SYNCREAD 0x10000000 // 1=synch read, 0=async read
+#define REG_UMI_TCR_MEMTYPE_PAGEREAD 0x08000000 // 1=page mode read, 0=normal mode read
+#define REG_UMI_TCR_MEMTYPE_PGSZ_MASK 0x07000000 // page size/burst size (wrap only)
+#define REG_UMI_TCR_MEMTYPE_PGSZ_4 0x00000000 // 4 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_8 0x01000000 // 8 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_16 0x02000000 // 16 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_32 0x03000000 // 32 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_64 0x04000000 // 64 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_128 0x05000000 // 128 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_256 0x06000000 // 256 word
+#define REG_UMI_TCR_MEMTYPE_PGSZ_512 0x07000000 // 512 word
+#define REG_UMI_TCR_TPRC_TWLC_MASK 0x00f80000 // Page read access cycle / Burst write latency (n+2 / n+1)
+#define REG_UMI_TCR_TBTA_MASK 0x00070000 // Bus turnaround cycle (n)
+#define REG_UMI_TCR_TWP_MASK 0x0000f800 // Write pulse width cycle (n+1)
+#define REG_UMI_TCR_TWR_MASK 0x00000600 // Write recovery cycle (n+1)
+#define REG_UMI_TCR_TAS_MASK 0x00000180 // Write address setup cycle (n+1)
+#define REG_UMI_TCR_TOE_MASK 0x00000060 // Output enable delay cycle (n)
+#define REG_UMI_TCR_TRC_TLC_MASK 0x0000001f // Read access cycle / Burst read latency (n+2 / n+1)
+
+
+// REG_UMI_MMD_ICR bits
+#define REG_UMI_MMD_ICR_FLASH_WP 0x8000 // Flash write protection pin control
+#define REG_UMI_MMD_ICR_XHCS 0x4000 // Extend hold time for sram0, sram1 csn (39 MHz operation)
+#define REG_UMI_MMD_ICR_SDRAM2EN 0x2000 // Enable SDRAM 2 interface control
+#define REG_UMI_MMD_ICR_INST512 0x1000 // Enable merge of flash banks 0/1 to 512 MBit bank
+#define REG_UMI_MMD_ICR_DATA512 0x0800 // Enable merge of flash banks 1/2 to 512 MBit bank
+#define REG_UMI_MMD_ICR_SDRAMEN 0x0400 // Enable SDRAM interface control
+#define REG_UMI_MMD_ICR_WAITPOL 0x0200 // Polarity of busy state of Burst Wait Signal
+#define REG_UMI_MMD_ICR_BCLKSTOP 0x0100 // Enable burst clock stopped when not accessing external burst flash/sram
+#define REG_UMI_MMD_ICR_PERI1EN 0x0080 // Enable the peri1_csn to replace flash1_csn in 512 Mb flash mode
+#define REG_UMI_MMD_ICR_PERI2EN 0x0040 // Enable the peri2_csn to replace sdram_csn
+#define REG_UMI_MMD_ICR_PERI3EN 0x0020 // Enable the peri3_csn to replace sdram2_csn
+#define REG_UMI_MMD_ICR_MRSB1 0x0010 // Enable sram bank1 for H/W controlled MRS
+#define REG_UMI_MMD_ICR_MRSB0 0x0008 // Enable sram bank0 for H/W controlled MRS
+#define REG_UMI_MMD_ICR_MRSPOL 0x0004 // Polarity for assert3ed state of H/W controlled MRS
+#define REG_UMI_MMD_ICR_MRSMODE 0x0002 // 0: S/W controllable ZZ/MRS/CRE/P-Mode pin
+ // 1: H/W controlled ZZ/MRS/CRE/P-Mode, same timing as CS
+#define REG_UMI_MMD_ICR_MRSSTATE 0x0001 // MRS state for S/W controlled mode
+
+// REG_UMI_NAND_TCR bits
+#define REG_UMI_NAND_TCR_CS_SWCTRL 0x80000000 // Enable software to control CS
+#define REG_UMI_NAND_TCR_WORD16 0x40000000 // 16-bit nand wordsize if set
+#define REG_UMI_NAND_TCR_TBTA_MASK 0x00070000 // Bus turnaround cycle (n)
+#define REG_UMI_NAND_TCR_TWP_MASK 0x0000f800 // Write pulse width cycle (n+1)
+#define REG_UMI_NAND_TCR_TWR_MASK 0x00000600 // Write recovery cycle (n+1)
+#define REG_UMI_NAND_TCR_TAS_MASK 0x00000180 // Write address setup cycle (n+1)
+#define REG_UMI_NAND_TCR_TOE_MASK 0x00000060 // Output enable delay cycle (n)
+#define REG_UMI_NAND_TCR_TRC_TLC_MASK 0x0000001f // Read access cycle (n+2)
+
+// REG_UMI_NAND_RCSR bits
+#define REG_UMI_NAND_RCSR_RDY 0x02 // Status: Ready=1, Busy=0
+#define REG_UMI_NAND_RCSR_CS_ASSERTED 0x01 // Keep CS asserted during operation
+
+// REG_UMI_NAND_ECC_CSR bits
+#define REG_UMI_NAND_ECC_CSR_NANDINT 0x80000000 // Interrupt status - read-only
+#define REG_UMI_NAND_ECC_CSR_ECCINT_RAW 0x00800000 // Read: Status of ECC done, Write: clear ECC interrupt
+#define REG_UMI_NAND_ECC_CSR_RBINT_RAW 0x00400000 // Read: Status of R/B, Write: clear R/B interrupt
+#define REG_UMI_NAND_ECC_CSR_ECCINT_ENABLE 0x00008000 // 1 = Enable ECC Interrupt
+#define REG_UMI_NAND_ECC_CSR_RBINT_ENABLE 0x00004000 // 1 = Assert interrupt at rising edge of R/B_
+#define REG_UMI_NAND_ECC_CSR_256BYTE 0x00000080 // Calculate ECC by 0=512 bytes, 1=256 bytes
+#define REG_UMI_NAND_ECC_CSR_ECC_ENABLE 0x00000001 // Enable ECC in hardware
+
+// REG_UMI_BCH_CTRL_STATUS bits
+#define REG_UMI_BCH_CTRL_STATUS_NB_CORR_ERROR 0x00F00000 // Indicate Number of correctable errors detected
+#define REG_UMI_BCH_CTRL_STATUS_UNCORR_ERR 0x00080000 // Indicate Errors detected during read but uncorrectable
+#define REG_UMI_BCH_CTRL_STATUS_CORR_ERR 0x00040000 // Indicate Errors detected during read and are correctable
+#define REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID 0x00020000 // Flag indicates BCH's ECC status of read process are valid
+#define REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID 0x00010000 // Flag indicates BCH's ECC status of write process are valid
+#define REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC 0x00000010 // Pause ECC calculation
+#define REG_UMI_BCH_CTRL_STATUS_INT_EN 0x00000004 // Enable Interrupt
+#define REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN 0x00000002 // Enable ECC during read
+#define REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN 0x00000001 // Enable ECC during write
+#define REG_UMI_BCH_ERR_LOC_MASK 0x00001FFF // Mask for location
+#define REG_UMI_BCH_ERR_LOC_BYTE 0x00000007 // location within a byte
+#define REG_UMI_BCH_ERR_LOC_WORD 0x00000018 // location within a word
+#define REG_UMI_BCH_ERR_LOC_PAGE 0x00001FE0 // location within a page (512 byte)
+#define REG_UMI_BCH_ERR_LOC_ADDR(index) ( __REG32( HW_UMI_BASE + 0x64 + (index / 2)*4 ) >> ( (index % 2) * 16 ) )
+#endif
diff --git a/arch/arm/mach-bcmring/include/mach/system.h b/arch/arm/mach-bcmring/include/mach/system.h
new file mode 100644
index 0000000..0698744
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/system.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <mach/csp/chipcHw_inline.h>
+
+#if defined( CONFIG_BCM_IDLE_PROFILER_SUPPORT )
+#include <linux/broadcom/idle_prof.h>
+#include <mach/timer.h>
+#endif
+
+extern int gArchWarmReboot;
+
+static inline void arch_idle(void)
+{
+#if defined( CONFIG_BCM_IDLE_PROFILER_SUPPORT )
+ u32 idle_enter, idle_leave;
+
+ idle_enter = timer_get_tick_count();
+#endif
+ cpu_do_idle();
+#if defined( CONFIG_BCM_IDLE_PROFILER_SUPPORT )
+ idle_leave = timer_get_tick_count();
+ idle_count += (idle_leave - idle_enter);
+#endif
+}
+
+static inline void arch_reset(char mode, char *cmd)
+{
+ printk("arch_reset:%c %x\n", mode, gArchWarmReboot);
+
+ if (mode == 'h')
+ {
+ /* Reboot configured in proc entry */
+ if (gArchWarmReboot)
+ {
+ printk("warm reset\n");
+ /* Issue Warm reset (do not reset ethernet switch, keep alive) */
+ chipcHw_reset(chipcHw_REG_SOFT_RESET_CHIP_WARM);
+ }
+ else
+ {
+ /* Force reset of everything */
+ printk("force reset\n");
+ chipcHw_reset(chipcHw_REG_SOFT_RESET_CHIP_SOFT);
+ }
+ }
+ else
+ {
+ /* Force reset of everything */
+ printk("force reset\n");
+ chipcHw_reset(chipcHw_REG_SOFT_RESET_CHIP_SOFT);
+ }
+}
+
+#endif
+
diff --git a/arch/arm/mach-bcmring/include/mach/timer.h b/arch/arm/mach-bcmring/include/mach/timer.h
new file mode 100644
index 0000000..780d9aa
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/timer.h
@@ -0,0 +1,87 @@
+/*****************************************************************************
+* Copyright 2004 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+
+/*
+*
+*****************************************************************************
+*
+* timer.h
+*
+* PURPOSE:
+*
+*
+*
+* NOTES:
+*
+*****************************************************************************/
+
+
+#if !defined( BCM_LINUX_TIMER_H )
+#define BCM_LINUX_TIMER_H
+
+#if defined( __KERNEL__ )
+
+/* ---- Include Files ---------------------------------------------------- */
+/* ---- Constants and Types ---------------------------------------------- */
+
+typedef unsigned int timer_tick_count_t;
+typedef unsigned int timer_tick_rate_t;
+typedef unsigned int timer_msec_t;
+
+
+/* ---- Variable Externs ------------------------------------------------- */
+/* ---- Function Prototypes ---------------------------------------------- */
+
+
+/****************************************************************************
+*
+* timer_get_tick_count
+*
+*
+***************************************************************************/
+timer_tick_count_t timer_get_tick_count( void );
+
+
+/****************************************************************************
+*
+* timer_get_tick_rate
+*
+*
+***************************************************************************/
+timer_tick_rate_t timer_get_tick_rate( void );
+
+
+/****************************************************************************
+*
+* timer_get_msec
+*
+*
+***************************************************************************/
+timer_msec_t timer_get_msec( void );
+
+
+/****************************************************************************
+*
+* timer_ticks_to_msec
+*
+*
+***************************************************************************/
+timer_msec_t timer_ticks_to_msec( timer_tick_count_t ticks );
+
+
+#endif /* __KERNEL__ */
+#endif /* BCM_LINUX_TIMER_H */
diff --git a/arch/arm/mach-bcmring/include/mach/timex.h b/arch/arm/mach-bcmring/include/mach/timex.h
new file mode 100644
index 0000000..cf006df
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/timex.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * Integrator architecture timex specifications
+ *
+ * Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Specifies the number of ticks per second
+ */
+#define CLOCK_TICK_RATE 100000 //REG_SMT_TICKS_PER_SEC
diff --git a/arch/arm/mach-bcmring/include/mach/uncompress.h b/arch/arm/mach-bcmring/include/mach/uncompress.h
new file mode 100644
index 0000000..0c008db
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/uncompress.h
@@ -0,0 +1,53 @@
+/*****************************************************************************
+* Copyright 2005 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+// The piggy build defines __KERNEL__ but can't actually
+// work with kernel code in general, especially the static inline functions.
+// -Dstatic= is set for the misc.c compile, and this causes unnecessary includes
+// of "static inline" functions (just "inline" are included by mistake).
+// So we have to be careful to not call much kernel code from the piggy build.
+// We want the simplified REG_LOCAL_IRQ_SAVE/RESTORE macros from reg.h for
+// this reason and also because piggy doesn't need protection since it is
+// effectively single threaded boot code.
+// uartHw.h below includes uartHw_inline.h which includes reg.h which brings
+// in too much kernel code for piggy unless we define STANDALONE.
+#define STANDALONE
+
+/*
+ * Map IO 1 to 1 with physical addresses.
+ * Do not move this below the include of mm_io.h
+ */
+#undef MM_IO_PHYS_TO_VIRT
+#define MM_IO_PHYS_TO_VIRT(x) (x)
+#include <mach/csp/mm_io.h>
+#include <csp/uartHw.h>
+
+/*
+ * This does not append a newline
+ */
+static inline void putc(int c)
+{
+ /* Send out UARTA */
+ uartHw_TxFifoPut( 0, c );
+}
+
+static inline void flush(void)
+{
+ /* Flush UARTA */
+ uartHw_TxWaitIdle( 0 );
+}
+
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
+
diff --git a/arch/arm/mach-bcmring/include/mach/vmalloc.h b/arch/arm/mach-bcmring/include/mach/vmalloc.h
new file mode 100644
index 0000000..58c2a93
--- /dev/null
+++ b/arch/arm/mach-bcmring/include/mach/vmalloc.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (C) 2000 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+/* We have a range of 0xC0000000 to 0xDFFFFFFF minus the VMALLOC and high_memory area available for virtual memory */
+#define VMALLOC_END (PAGE_OFFSET + 0x1F000000)
diff --git a/arch/arm/mach-bcmring/irq.c b/arch/arm/mach-bcmring/irq.c
new file mode 100644
index 0000000..8a07287
--- /dev/null
+++ b/arch/arm/mach-bcmring/irq.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/stddef.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+#include <mach/csp/intcHw_reg.h>
+#include <mach/csp/mm_io.h>
+// #include <mach/reg_gpio.h> // for brcm_init_gpio prototype
+
+
+static void bcmring_mask_irq0(unsigned int irq)
+{
+ writel(1 << (irq - IRQ_INTC0_START), MM_IO_BASE_INTC0 + INTCHW_INTENCLEAR);
+}
+static void bcmring_unmask_irq0(unsigned int irq)
+{
+ writel(1 << (irq - IRQ_INTC0_START), MM_IO_BASE_INTC0 + INTCHW_INTENABLE);
+}
+static void bcmring_mask_irq1(unsigned int irq)
+{
+ writel(1 << (irq - IRQ_INTC1_START), MM_IO_BASE_INTC1 + INTCHW_INTENCLEAR);
+}
+static void bcmring_unmask_irq1(unsigned int irq)
+{
+ writel(1 << (irq - IRQ_INTC1_START), MM_IO_BASE_INTC1 + INTCHW_INTENABLE);
+}
+static void bcmring_mask_irq2(unsigned int irq)
+{
+ writel(1 << (irq - IRQ_SINTC_START), MM_IO_BASE_SINTC + INTCHW_INTENCLEAR);
+}
+static void bcmring_unmask_irq2(unsigned int irq)
+{
+ writel(1 << (irq - IRQ_SINTC_START), MM_IO_BASE_SINTC + INTCHW_INTENABLE);
+}
+
+static struct irq_chip bcmring_irq0_chip = {
+ .typename = "ARM-INTC0",
+ .ack = bcmring_mask_irq0,
+ .mask = bcmring_mask_irq0, /* mask a specific interrupt, blocking its delivery. */
+ .unmask = bcmring_unmask_irq0, /* unmaks an interrupt */
+};
+
+static struct irq_chip bcmring_irq1_chip = {
+ .typename = "ARM-INTC1",
+ .ack = bcmring_mask_irq1,
+ .mask = bcmring_mask_irq1,
+ .unmask = bcmring_unmask_irq1,
+};
+
+static struct irq_chip bcmring_irq2_chip = {
+ .typename = "ARM-SINTC",
+ .ack = bcmring_mask_irq2,
+ .mask = bcmring_mask_irq2,
+ .unmask = bcmring_unmask_irq2,
+};
+
+
+static void vic_init(void __iomem *base, struct irq_chip *chip, unsigned int irq_start, unsigned int vic_sources)
+{
+ unsigned int i;
+ for ( i = 0; i < 32; i++ )
+ {
+ unsigned int irq = irq_start + i;
+ set_irq_chip( irq, chip );
+ set_irq_chip_data(irq, base);
+
+ if (vic_sources & (1 << i))
+ {
+ set_irq_handler( irq, handle_level_irq );
+ set_irq_flags( irq, IRQF_VALID | IRQF_PROBE );
+ }
+ }
+ writel(0, base + INTCHW_INTSELECT);
+ writel(0, base + INTCHW_INTENABLE);
+ writel(~0, base + INTCHW_INTENCLEAR);
+ writel(0, base + INTCHW_IRQSTATUS);
+ writel(~0, base + INTCHW_SOFTINTCLEAR);
+
+#if 0
+
+ // FUTURE - we may want to enable the auto vector
+ // functionality some day and this means that we
+ // could write an interrupt number into the address
+ // registers, and get_irqnr_and_base could use
+ // that information.
+
+ /*
+ * Make sure we clear all existing interrupts
+ */
+ writel(0, base + INTCHW_ADDRESS);
+ for (i = 0; i < 36; i++)
+ {
+ unsigned int value = readl(base + INTCHW_ADDRESS);
+ writel(value, base + INTCHW_ADDRESS);
+ }
+
+ // Instead of vector addresses, store the irq number (from 0) in the address
+ // registers, and when an irq happens, read the number from the sole address
+ // register that tells us the source of the interrupt. This avoids complicated
+ // code in the low level assember macro get_irqnr_and base.
+ for (i = 0; i < 32; i++)
+ {
+ void __iomem *reg = base + INTCHW_VECTADDR0 + (i * 4);
+ writel(i, reg);
+ }
+#endif
+}
+
+
+void __init bcmring_init_irq( void )
+{
+ vic_init((void __iomem *)MM_IO_BASE_INTC0, &bcmring_irq0_chip, IRQ_INTC0_START, IRQ_INTC0_VALID_MASK);
+ vic_init((void __iomem *)MM_IO_BASE_INTC1, &bcmring_irq1_chip, IRQ_INTC1_START, IRQ_INTC1_VALID_MASK);
+ vic_init((void __iomem *)MM_IO_BASE_SINTC, &bcmring_irq2_chip, IRQ_SINTC_START, IRQ_SINTC_VALID_MASK);
+
+ // special cases
+ if (INTCHW_INTC1_GPIO0 & IRQ_INTC1_VALID_MASK)
+ {
+ set_irq_handler( IRQ_GPIO0, handle_simple_irq );
+ }
+ if (INTCHW_INTC1_GPIO1 & IRQ_INTC1_VALID_MASK)
+ {
+ set_irq_handler( IRQ_GPIO1, handle_simple_irq );
+ }
+
+#if defined( CONFIG_HAVE_GPIO_LIB )
+ brcm_init_gpio();
+#endif
+}
+
diff --git a/arch/arm/mach-bcmring/mm.c b/arch/arm/mach-bcmring/mm.c
new file mode 100644
index 0000000..c417544
--- /dev/null
+++ b/arch/arm/mach-bcmring/mm.c
@@ -0,0 +1,102 @@
+/*****************************************************************************
+* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+#include <asm/pgalloc.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <mach/hardware.h>
+#include <mach/csp/mm_io.h>
+
+#define IO_DESC(va, sz) { .virtual = va, \
+ .pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
+ .length = sz, \
+ .type = MT_DEVICE }
+
+#define MEM_DESC(va, sz) { .virtual = va, \
+ .pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
+ .length = sz, \
+ .type = MT_MEMORY }
+
+static struct map_desc bcmring_io_desc[] __initdata =
+{
+ IO_DESC( MM_IO_BASE_NAND, SZ_64K ), // phys:0x28000000-0x28000FFF virt:0xE8000000-0xE8000FFF size:0x00010000
+ IO_DESC( MM_IO_BASE_UMI, SZ_64K ), // phys:0x2C000000-0x2C000FFF virt:0xEC000000-0xEC000FFF size:0x00010000
+
+ IO_DESC( MM_IO_BASE_BROM, SZ_64K ), // phys:0x30000000-0x3000FFFF virt:0xF3000000-0xF300FFFF size:0x00010000
+ MEM_DESC( MM_IO_BASE_ARAM, SZ_1M ), // phys:0x31000000-0x31FFFFFF virt:0xF3100000-0xF31FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_DMA0, SZ_1M ), // phys:0x32000000-0x32FFFFFF virt:0xF3200000-0xF32FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_DMA1, SZ_1M ), // phys:0x33000000-0x33FFFFFF virt:0xF3300000-0xF33FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_ESW, SZ_1M ), // phys:0x34000000-0x34FFFFFF virt:0xF3400000-0xF34FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_CLCD, SZ_1M ), // phys:0x35000000-0x35FFFFFF virt:0xF3500000-0xF35FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_APM, SZ_1M ), // phys:0x36000000-0x36FFFFFF virt:0xF3600000-0xF36FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_SPUM, SZ_1M ), // phys:0x37000000-0x37FFFFFF virt:0xF3700000-0xF37FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_VPM_PROG, SZ_1M ), // phys:0x38000000-0x38FFFFFF virt:0xF3800000-0xF38FFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_VPM_DATA, SZ_1M ), // phys:0x3A000000-0x3AFFFFFF virt:0xF3A00000-0xF3AFFFFF size:0x01000000
+
+ IO_DESC( MM_IO_BASE_VRAM, SZ_64K ), // phys:0x40000000-0x4000FFFF virt:0xF4000000-0xF400FFFF size:0x00010000
+ IO_DESC( MM_IO_BASE_CHIPC, SZ_16M ), // phys:0x80000000-0x80FFFFFF virt:0xF8000000-0xF8FFFFFF size:0x01000000
+ IO_DESC( MM_IO_BASE_VPM_EXTMEM_RSVD,
+ SZ_16M ), // phys:0x0F000000-0x0FFFFFFF virt:0xF0000000-0xF0FFFFFF size:0x01000000
+};
+
+void __init bcmring_map_io( void )
+{
+
+ iotable_init( bcmring_io_desc, ARRAY_SIZE( bcmring_io_desc ));
+
+#if defined( CONFIG_BCM_EARLY_PRINTK )
+ {
+ /*
+ * Now that the I/O space has been setup, we can install our
+ * "early" console device.
+ */
+
+ extern void bcm_install_early_console( void );
+
+ /*
+ * We need to call flush_tlb_all before printing will actually work.
+ * (I'm not sure exactly why). This is done by paging_init
+ * after map_io is called, but because we're in map_io we need to do
+ * it if we're going to get already buffered stuff to be printed.
+ */
+
+ flush_tlb_all();
+
+ /*
+ * Install a console, so that we can get early printk's to work before
+ * interrupts are enabled.
+ */
+
+ bcm_install_early_console();
+ }
+#endif
+}
+
diff --git a/arch/arm/mach-bcmring/timer.c b/arch/arm/mach-bcmring/timer.c
new file mode 100644
index 0000000..bea7f4b
--- /dev/null
+++ b/arch/arm/mach-bcmring/timer.c
@@ -0,0 +1,66 @@
+/*****************************************************************************
+* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+
+
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <csp/tmrHw.h>
+
+#include <mach/timer.h>
+// The core.c file initializes timers 1 and 3 as a linux clocksource.
+// The real time clock should probably be the real linux clocksource.
+// In the meantime, this file should agree with core.c as to the
+// profiling timer. If the clocksource is moved to rtc later, then
+// we can init the profiling timer here instead.
+
+// Timer 1 provides 25MHz resolution syncrhonized to scheduling and APM timing
+// Timer 3 provides bus freqeuncy sychronized to ACLK, but spread spectrum will
+// affect synchronization with scheduling and APM timing.
+
+#define PROF_TIMER 1
+
+timer_tick_rate_t timer_get_tick_rate(void)
+{
+ return tmrHw_getCountRate(PROF_TIMER);
+}
+
+timer_tick_count_t timer_get_tick_count(void)
+{
+ return tmrHw_GetCurrentCount(PROF_TIMER); // change downcounter to upcounter
+}
+
+timer_msec_t timer_ticks_to_msec(timer_tick_count_t ticks)
+{
+ static int tickRateMsec = 0;
+
+ if ( tickRateMsec == 0 )
+ {
+ tickRateMsec = timer_get_tick_rate() / 1000;
+ }
+
+ return ( ticks / tickRateMsec );
+}
+
+timer_msec_t timer_get_msec(void)
+{
+ return timer_ticks_to_msec(timer_get_tick_count());
+}
+
+EXPORT_SYMBOL(timer_get_tick_count);
+EXPORT_SYMBOL(timer_ticks_to_msec);
+EXPORT_SYMBOL(timer_get_tick_rate);
+EXPORT_SYMBOL(timer_get_msec);
--
1.6.0.6
Leo Hao Chen
Software Engineer
Broadcom Canada Inc.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists