diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-10-09 21:33:03 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-10-09 21:33:03 +0100 |
commit | b1add0480a95b6ceaece5caf6c50614771eae9b2 (patch) | |
tree | 06f969f37bd0f51d9ebcccdb3e3ae983edaad889 /arch | |
parent | 3f30a09a612bac2b531a206c2a58a292dd7ff182 (diff) | |
parent | 58a85f465fb16a918a869eba05addb8f78d9e064 (diff) |
Merge branch 'for-rmk' of git://pasiphae.extern.pengutronix.de/git/imx/linux-2.6.git
Merge branch 'imx-devel' into devel
Diffstat (limited to 'arch')
27 files changed, 1270 insertions, 115 deletions
diff --git a/arch/arm/mach-imx/include/mach/irqs.h b/arch/arm/mach-imx/include/mach/irqs.h index eb8d5bd05d5..67812c5ac1f 100644 --- a/arch/arm/mach-imx/include/mach/irqs.h +++ b/arch/arm/mach-imx/include/mach/irqs.h @@ -111,6 +111,11 @@ /* decode irq number to use with IMR(x), ISR(x) and friends */ #define IRQ_TO_REG(irq) ((irq - IMX_IRQS) >> 5) +/* all normal IRQs can be FIQs */ +#define FIQ_START 0 +/* switch betwean IRQ and FIQ */ +extern int imx_set_irq_fiq(unsigned int irq, unsigned int type); + #define NR_IRQS (IRQ_GPIOD(32) + 1) #define IRQ_GPIO(x) #endif diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c index 232e3b9f880..531b95deadc 100644 --- a/arch/arm/mach-imx/irq.c +++ b/arch/arm/mach-imx/irq.c @@ -36,10 +36,7 @@ /* * * We simply use the ENABLE DISABLE registers inside of the IMX - * to turn on/off specific interrupts. FIXME- We should - * also add support for the accelerated interrupt controller - * by putting offets to irq jump code in the appropriate - * places. + * to turn on/off specific interrupts. * */ @@ -102,6 +99,28 @@ imx_unmask_irq(unsigned int irq) __raw_writel(irq, IMX_AITC_INTENNUM); } +#ifdef CONFIG_FIQ +int imx_set_irq_fiq(unsigned int irq, unsigned int type) +{ + unsigned int irqt; + + if (irq >= IMX_IRQS) + return -EINVAL; + + if (irq < IMX_IRQS / 2) { + irqt = __raw_readl(IMX_AITC_INTTYPEL) & ~(1 << irq); + __raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEL); + } else { + irq -= IMX_IRQS / 2; + irqt = __raw_readl(IMX_AITC_INTTYPEH) & ~(1 << irq); + __raw_writel(irqt | (!!type << irq), IMX_AITC_INTTYPEH); + } + + return 0; +} +EXPORT_SYMBOL(imx_set_irq_fiq); +#endif /* CONFIG_FIQ */ + static int imx_gpio_irq_type(unsigned int _irq, unsigned int type) { @@ -284,4 +303,9 @@ imx_init_irq(void) /* Release masking of interrupts according to priority */ __raw_writel(-1, IMX_AITC_NIMASK); + +#ifdef CONFIG_FIQ + /* Initialize FIQ */ + init_FIQ(); +#endif } diff --git a/arch/arm/mach-mx2/devices.h b/arch/arm/mach-mx2/devices.h new file mode 100644 index 00000000000..c77a4b8f73b --- /dev/null +++ b/arch/arm/mach-mx2/devices.h @@ -0,0 +1,15 @@ + +extern struct platform_device mxc_gpt1; +extern struct platform_device mxc_gpt2; +extern struct platform_device mxc_gpt3; +extern struct platform_device mxc_gpt4; +extern struct platform_device mxc_gpt5; +extern struct platform_device mxc_wdt; +extern struct platform_device mxc_irda_device; +extern struct platform_device mxc_uart_device0; +extern struct platform_device mxc_uart_device1; +extern struct platform_device mxc_uart_device2; +extern struct platform_device mxc_uart_device3; +extern struct platform_device mxc_uart_device4; +extern struct platform_device mxc_uart_device5; + diff --git a/arch/arm/mach-mx2/mx27ads.c b/arch/arm/mach-mx2/mx27ads.c index 4ce56ef4d8d..56e22d3ca07 100644 --- a/arch/arm/mach-mx2/mx27ads.c +++ b/arch/arm/mach-mx2/mx27ads.c @@ -34,6 +34,8 @@ #include <mach/iomux-mx1-mx2.h> #include <mach/board-mx27ads.h> +#include "devices.h" + /* ADS's NOR flash */ static struct physmap_flash_data mx27ads_flash_data = { .width = 2, @@ -251,12 +253,14 @@ static struct imxuart_platform_data uart_pdata[] = { static void __init mx27ads_board_init(void) { - int i; - gpio_fec_active(); - for (i = 0; i < 6; i++) - imx_init_uart(i, &uart_pdata[i]); + mxc_register_device(&mxc_uart_device0, &uart_pdata[0]); + mxc_register_device(&mxc_uart_device1, &uart_pdata[1]); + mxc_register_device(&mxc_uart_device2, &uart_pdata[2]); + mxc_register_device(&mxc_uart_device3, &uart_pdata[3]); + mxc_register_device(&mxc_uart_device4, &uart_pdata[4]); + mxc_register_device(&mxc_uart_device5, &uart_pdata[5]); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); } diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c index 1028f453cfc..7f55746e259 100644 --- a/arch/arm/mach-mx2/pcm038.c +++ b/arch/arm/mach-mx2/pcm038.c @@ -28,6 +28,8 @@ #include <mach/imx-uart.h> #include <mach/board-pcm038.h> +#include "devices.h" + /* * Phytec's phyCORE-i.MX27 comes with 32MiB flash, * 16 bit width @@ -170,11 +172,11 @@ static struct platform_device *platform_devices[] __initdata = { static void __init pcm038_init(void) { - int i; gpio_fec_active(); - for (i = 0; i < 3; i++) - imx_init_uart(i, &uart_pdata[i]); + mxc_register_device(&mxc_uart_device0, &uart_pdata[0]); + mxc_register_device(&mxc_uart_device1, &uart_pdata[1]); + mxc_register_device(&mxc_uart_device2, &uart_pdata[2]); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); diff --git a/arch/arm/mach-mx2/serial.c b/arch/arm/mach-mx2/serial.c index e31fd44f794..16debc296da 100644 --- a/arch/arm/mach-mx2/serial.c +++ b/arch/arm/mach-mx2/serial.c @@ -35,7 +35,7 @@ static struct resource uart0[] = { }, }; -static struct platform_device mxc_uart_device0 = { +struct platform_device mxc_uart_device0 = { .name = "imx-uart", .id = 0, .resource = uart0, @@ -54,7 +54,7 @@ static struct resource uart1[] = { }, }; -static struct platform_device mxc_uart_device1 = { +struct platform_device mxc_uart_device1 = { .name = "imx-uart", .id = 1, .resource = uart1, @@ -73,7 +73,7 @@ static struct resource uart2[] = { }, }; -static struct platform_device mxc_uart_device2 = { +struct platform_device mxc_uart_device2 = { .name = "imx-uart", .id = 2, .resource = uart2, @@ -92,7 +92,7 @@ static struct resource uart3[] = { }, }; -static struct platform_device mxc_uart_device3 = { +struct platform_device mxc_uart_device3 = { .name = "imx-uart", .id = 3, .resource = uart3, @@ -111,7 +111,7 @@ static struct resource uart4[] = { }, }; -static struct platform_device mxc_uart_device4 = { +struct platform_device mxc_uart_device4 = { .name = "imx-uart", .id = 4, .resource = uart4, @@ -130,48 +130,9 @@ static struct resource uart5[] = { }, }; -static struct platform_device mxc_uart_device5 = { +struct platform_device mxc_uart_device5 = { .name = "imx-uart", .id = 5, .resource = uart5, .num_resources = ARRAY_SIZE(uart5), }; - -/* - * Register only those UARTs that physically exists - */ -int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata) -{ - switch (uart_no) { - case 0: - mxc_uart_device0.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device0); - break; - case 1: - mxc_uart_device1.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device1); - break; -#ifndef CONFIG_MXC_IRDA - case 2: - mxc_uart_device2.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device2); - break; -#endif - case 3: - mxc_uart_device3.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device3); - break; - case 4: - mxc_uart_device4.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device4); - break; - case 5: - mxc_uart_device5.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device5); - break; - default: - return -ENODEV; - } - - return 0; -} diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c index e08c6a8ac56..a6bdcc07f3c 100644 --- a/arch/arm/mach-mx3/devices.c +++ b/arch/arm/mach-mx3/devices.c @@ -36,7 +36,7 @@ static struct resource uart0[] = { }, }; -static struct platform_device mxc_uart_device0 = { +struct platform_device mxc_uart_device0 = { .name = "imx-uart", .id = 0, .resource = uart0, @@ -55,7 +55,7 @@ static struct resource uart1[] = { }, }; -static struct platform_device mxc_uart_device1 = { +struct platform_device mxc_uart_device1 = { .name = "imx-uart", .id = 1, .resource = uart1, @@ -74,7 +74,7 @@ static struct resource uart2[] = { }, }; -static struct platform_device mxc_uart_device2 = { +struct platform_device mxc_uart_device2 = { .name = "imx-uart", .id = 2, .resource = uart2, @@ -93,7 +93,7 @@ static struct resource uart3[] = { }, }; -static struct platform_device mxc_uart_device3 = { +struct platform_device mxc_uart_device3 = { .name = "imx-uart", .id = 3, .resource = uart3, @@ -112,46 +112,13 @@ static struct resource uart4[] = { }, }; -static struct platform_device mxc_uart_device4 = { +struct platform_device mxc_uart_device4 = { .name = "imx-uart", .id = 4, .resource = uart4, .num_resources = ARRAY_SIZE(uart4), }; -/* - * Register only those UARTs that physically exist - */ -int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata) -{ - switch (uart_no) { - case 0: - mxc_uart_device0.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device0); - break; - case 1: - mxc_uart_device1.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device1); - break; - case 2: - mxc_uart_device2.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device2); - break; - case 3: - mxc_uart_device3.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device3); - break; - case 4: - mxc_uart_device4.dev.platform_data = pdata; - platform_device_register(&mxc_uart_device4); - break; - default: - return -ENODEV; - } - - return 0; -} - /* GPIO port description */ static struct mxc_gpio_port imx_gpio_ports[] = { [0] = { diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h new file mode 100644 index 00000000000..4dc03f9e600 --- /dev/null +++ b/arch/arm/mach-mx3/devices.h @@ -0,0 +1,6 @@ + +extern struct platform_device mxc_uart_device0; +extern struct platform_device mxc_uart_device1; +extern struct platform_device mxc_uart_device2; +extern struct platform_device mxc_uart_device3; +extern struct platform_device mxc_uart_device4; diff --git a/arch/arm/mach-mx3/iomux.c b/arch/arm/mach-mx3/iomux.c index 3dda1fe23cb..6e664be8cc1 100644 --- a/arch/arm/mach-mx3/iomux.c +++ b/arch/arm/mach-mx3/iomux.c @@ -43,7 +43,8 @@ static DEFINE_SPINLOCK(gpio_mux_lock); */ int mxc_iomux_mode(unsigned int pin_mode) { - u32 reg, field, l, mode, ret = 0; + u32 field, l, mode, ret = 0; + void __iomem *reg; reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK); field = pin_mode & 0x3; @@ -70,7 +71,8 @@ EXPORT_SYMBOL(mxc_iomux_mode); */ void mxc_iomux_set_pad(enum iomux_pins pin, u32 config) { - u32 reg, field, l; + u32 field, l; + void __iomem *reg; reg = IOMUXSW_PAD_CTL + (pin + 2) / 3; field = (pin + 2) % 3; diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c index 0cd90a9667c..1be4a390c63 100644 --- a/arch/arm/mach-mx3/mx31ads.c +++ b/arch/arm/mach-mx3/mx31ads.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/clk.h> #include <linux/serial_8250.h> +#include <linux/irq.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -31,6 +32,8 @@ #include <asm/mach/map.h> #include <mach/common.h> #include <mach/board-mx31ads.h> +#include <mach/imx-uart.h> +#include <mach/iomux-mx3.h> /*! * @file mx31ads.c @@ -84,6 +87,108 @@ static inline int mxc_init_extuart(void) } #endif +#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE) +static struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static inline void mxc_init_imx_uart(void) +{ + mxc_iomux_mode(MX31_PIN_CTS1__CTS1); + mxc_iomux_mode(MX31_PIN_RTS1__RTS1); + mxc_iomux_mode(MX31_PIN_TXD1__TXD1); + mxc_iomux_mode(MX31_PIN_RXD1__RXD1); + + mxc_register_device(&mxc_uart_device0, &uart_pdata); +} +#else /* !SERIAL_IMX */ +static inline void mxc_init_imx_uart(void) +{ +} +#endif /* !SERIAL_IMX */ + +static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc) +{ + u32 imr_val; + u32 int_valid; + u32 expio_irq; + + imr_val = __raw_readw(PBC_INTMASK_SET_REG); + int_valid = __raw_readw(PBC_INTSTATUS_REG) & imr_val; + + expio_irq = MXC_EXP_IO_BASE; + for (; int_valid != 0; int_valid >>= 1, expio_irq++) { + if ((int_valid & 1) == 0) + continue; + + generic_handle_irq(expio_irq); + } +} + +/* + * Disable an expio pin's interrupt by setting the bit in the imr. + * @param irq an expio virtual irq number + */ +static void expio_mask_irq(u32 irq) +{ + u32 expio = MXC_IRQ_TO_EXPIO(irq); + /* mask the interrupt */ + __raw_writew(1 << expio, PBC_INTMASK_CLEAR_REG); + __raw_readw(PBC_INTMASK_CLEAR_REG); +} + +/* + * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr. + * @param irq an expanded io virtual irq number + */ +static void expio_ack_irq(u32 irq) +{ + u32 expio = MXC_IRQ_TO_EXPIO(irq); + /* clear the interrupt status */ + __raw_writew(1 << expio, PBC_INTSTATUS_REG); +} + +/* + * Enable a expio pin's interrupt by clearing the bit in the imr. + * @param irq a expio virtual irq number + */ +static void expio_unmask_irq(u32 irq) +{ + u32 expio = MXC_IRQ_TO_EXPIO(irq); + /* unmask the interrupt */ + __raw_writew(1 << expio, PBC_INTMASK_SET_REG); +} + +static struct irq_chip expio_irq_chip = { + .ack = expio_ack_irq, + .mask = expio_mask_irq, + .unmask = expio_unmask_irq, +}; + +static void __init mx31ads_init_expio(void) +{ + int i; + + printk(KERN_INFO "MX31ADS EXPIO(CPLD) hardware\n"); + + /* + * Configure INT line as GPIO input + */ + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO)); + + /* disable the interrupt and clear the status */ + __raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG); + __raw_writew(0xFFFF, PBC_INTSTATUS_REG); + for (i = MXC_EXP_IO_BASE; i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES); + i++) { + set_irq_chip(i, &expio_irq_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_HIGH); + set_irq_chained_handler(EXPIO_PARENT_INT, mx31ads_expio_irq_handler); +} + /*! * This structure defines static mappings for the i.MX31ADS board. */ @@ -120,12 +225,19 @@ void __init mx31ads_map_io(void) iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc)); } +void __init mx31ads_init_irq(void) +{ + mxc_init_irq(); + mx31ads_init_expio(); +} + /*! * Board specific initialization. */ static void __init mxc_board_init(void) { mxc_init_extuart(); + mxc_init_imx_uart(); } static void __init mx31ads_timer_init(void) @@ -148,7 +260,7 @@ MACHINE_START(MX31ADS, "Freescale MX31ADS") .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc, .boot_params = PHYS_OFFSET + 0x100, .map_io = mx31ads_map_io, - .init_irq = mxc_init_irq, + .init_irq = mx31ads_init_irq, .init_machine = mxc_board_init, .timer = &mx31ads_timer, MACHINE_END diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c index 0a152ed15a8..03374f9e000 100644 --- a/arch/arm/mach-mx3/pcm037.c +++ b/arch/arm/mach-mx3/pcm037.c @@ -33,6 +33,8 @@ #include <mach/iomux-mx3.h> #include <mach/board-pcm037.h> +#include "devices.h" + static struct physmap_flash_data pcm037_flash_data = { .width = 2, }; @@ -73,12 +75,12 @@ static void __init mxc_board_init(void) mxc_iomux_mode(MX31_PIN_TXD1__TXD1); mxc_iomux_mode(MX31_PIN_RXD1__RXD1); - imx_init_uart(0, &uart_pdata); + mxc_register_device(&mxc_uart_device0, &uart_pdata); mxc_iomux_mode(MX31_PIN_CSPI3_MOSI__RXD3); mxc_iomux_mode(MX31_PIN_CSPI3_MISO__TXD3); - imx_init_uart(2, &uart_pdata); + mxc_register_device(&mxc_uart_device2, &uart_pdata); } /* diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index e14eaad11dd..b2a7e3fad11 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -23,4 +23,15 @@ source "arch/arm/mach-mx3/Kconfig" endmenu +config MXC_IRQ_PRIOR + bool "Use IRQ priority" + depends on ARCH_MXC + help + Select this if you want to use prioritized IRQ handling. + This feature prevents higher priority ISR to be interrupted + by lower priority IRQ even IRQF_DISABLED flag is not set. + This may be useful in embedded applications, where are strong + requirements for timing. + Say N here, unless you have a specialized requirement. + endif diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index db66e9ae841..067556f7c91 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -3,6 +3,6 @@ # # Common support -obj-y := irq.o clock.o gpio.o time.o +obj-y := irq.o clock.o gpio.o time.o devices.o -obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o +obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o diff --git a/arch/arm/plat-mxc/devices.c b/arch/arm/plat-mxc/devices.c new file mode 100644 index 00000000000..c66748267c4 --- /dev/null +++ b/arch/arm/plat-mxc/devices.c @@ -0,0 +1,36 @@ +/* + * Copyright 2008 Sascha Hauer, kernel@pengutronix.de + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> + +int __init mxc_register_device(struct platform_device *pdev, void *data) +{ + int ret; + + pdev->dev.platform_data = data; + + ret = platform_device_register(pdev); + if (ret) + pr_debug("Unable to register platform device '%s': %d\n", + pdev->name, ret); + + return ret; +} + diff --git a/arch/arm/plat-mxc/dma-mx1-mx2.c b/arch/arm/plat-mxc/dma-mx1-mx2.c new file mode 100644 index 00000000000..b296f19fd89 --- /dev/null +++ b/arch/arm/plat-mxc/dma-mx1-mx2.c @@ -0,0 +1,840 @@ +/* + * linux/arch/arm/plat-mxc/dma-mx1-mx2.c + * + * i.MX DMA registration and IRQ dispatching + * + * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de> + * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/scatterlist.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <mach/hardware.h> +#include <asm/dma.h> +#include <mach/dma-mx1-mx2.h> + +#define DMA_DCR 0x00 /* Control Register */ +#define DMA_DISR 0x04 /* Interrupt status Register */ +#define DMA_DIMR 0x08 /* Interrupt mask Register */ +#define DMA_DBTOSR 0x0c /* Burst timeout status Register */ +#define DMA_DRTOSR 0x10 /* Request timeout Register */ +#define DMA_DSESR 0x14 /* Transfer Error Status Register */ +#define DMA_DBOSR 0x18 /* Buffer overflow status Register */ +#define DMA_DBTOCR 0x1c /* Burst timeout control Register */ +#define DMA_WSRA 0x40 /* W-Size Register A */ +#define DMA_XSRA 0x44 /* X-Size Register A */ +#define DMA_YSRA 0x48 /* Y-Size Register A */ +#define DMA_WSRB 0x4c /* W-Size Register B */ +#define DMA_XSRB 0x50 /* X-Size Register B */ +#define DMA_YSRB 0x54 /* Y-Size Register B */ +#define DMA_SAR(x) (0x80 + ((x) << 6)) /* Source Address Registers */ +#define DMA_DAR(x) (0x84 + ((x) << 6)) /* Destination Address Registers */ +#define DMA_CNTR(x) (0x88 + ((x) << 6)) /* Count Registers */ +#define DMA_CCR(x) (0x8c + ((x) << 6)) /* Control Registers */ +#define DMA_RSSR(x) (0x90 + ((x) << 6)) /* Request source select Registers */ +#define DMA_BLR(x) (0x94 + ((x) << 6)) /* Burst length Registers */ +#define DMA_RTOR(x) (0x98 + ((x) << 6)) /* Request timeout Registers */ +#define DMA_BUCR(x) (0x98 + ((x) << 6)) /* Bus Utilization Registers */ +#define DMA_CCNR(x) (0x9C + ((x) << 6)) /* Channel counter Registers */ + +#define DCR_DRST (1<<1) +#define DCR_DEN (1<<0) +#define DBTOCR_EN (1<<15) +#define DBTOCR_CNT(x) ((x) & 0x7fff) +#define CNTR_CNT(x) ((x) & 0xffffff) +#define CCR_ACRPT (1<<14) +#define CCR_DMOD_LINEAR (0x0 << 12) +#define CCR_DMOD_2D (0x1 << 12) +#define CCR_DMOD_FIFO (0x2 << 12) +#define CCR_DMOD_EOBFIFO (0x3 << 12) +#define CCR_SMOD_LINEAR (0x0 << 10) +#define CCR_SMOD_2D (0x1 << 10) +#define CCR_SMOD_FIFO (0x2 << 10) +#define CCR_SMOD_EOBFIFO (0x3 << 10) +#define CCR_MDIR_DEC (1<<9) +#define CCR_MSEL_B (1<<8) +#define CCR_DSIZ_32 (0x0 << 6) +#define CCR_DSIZ_8 (0x1 << 6) +#define CCR_DSIZ_16 (0x2 << 6) +#define CCR_SSIZ_32 (0x0 << 4) +#define CCR_SSIZ_8 (0x1 << 4) +#define CCR_SSIZ_16 (0x2 << 4) +#define CCR_REN (1<<3) +#define CCR_RPT (1<<2) +#define CCR_FRC (1<<1) +#define CCR_CEN (1<<0) +#define RTOR_EN (1<<15) +#define RTOR_CLK (1<<14) +#define RTOR_PSC (1<<13) + +/* + * struct imx_dma_channel - i.MX specific DMA extension + * @name: name specified by DMA client + * @irq_handler: client callback for end of transfer + * @err_handler: client callback for error condition + * @data: clients context data for callbacks + * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE + * @sg: pointer to the actual read/written chunk for scatter-gather emulation + * @resbytes: total residual number of bytes to transfer + * (it can be lower or same as sum of SG mapped chunk sizes) + * @sgcount: number of chunks to be read/written + * + * Structure is used for IMX DMA processing. It would be probably good + * @struct dma_struct in the future for external interfacing and use + * @struct imx_dma_channel only as extension to it. + */ + +struct imx_dma_channel { + const char *name; + void (*irq_handler) (int, void *); + void (*err_handler) (int, void *, int errcode); + void (*prog_handler) (int, void *, struct scatterlist *); + void *data; + dmamode_t dma_mode; + struct scatterlist *sg; + unsigned int resbytes; + int dma_num; + + int in_use; + + u32 ccr_from_device; + u32 ccr_to_device; + + struct timer_list watchdog; + + int hw_chaining; +}; + +static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; + +static struct clk *dma_clk; + +static int imx_dma_hw_chain(struct imx_dma_channel *imxdma) +{ + if (cpu_is_mx27()) + return imxdma->hw_chaining; + else + return 0; +} + + +/* + * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation + */ +static inline int imx_dma_sg_next(int channel, struct scatterlist *sg) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long now; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return 0; + } + + now = min(imxdma->resbytes, sg->length); + imxdma->resbytes -= now; + + if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) + __raw_writel(sg->dma_address, DMA_BASE + DMA_DAR(channel)); + else + __raw_writel(sg->dma_address, DMA_BASE + DMA_SAR(channel)); + + __raw_writel(now, DMA_BASE + DMA_CNTR(channel)); + + pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, " + "size 0x%08x\n", channel, + __raw_readl(DMA_BASE + DMA_DAR(channel)), + __raw_readl(DMA_BASE + DMA_SAR(channel)), + __raw_readl(DMA_BASE + DMA_CNTR(channel))); + + return now; +} + +/** + * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from + * device transfer + * + * @channel: i.MX DMA channel number + * @dma_address: the DMA/physical memory address of the linear data block + * to transfer + * @dma_length: length of the data block in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_single(int channel, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + dmamode_t dmamode) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + imxdma->sg = NULL; + imxdma->dma_mode = dmamode; + + if (!dma_address) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", + channel); + return -EINVAL; + } + + if (!dma_length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", + channel); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d " + "dev_addr=0x%08x for read\n", + channel, __func__, (unsigned int)dma_address, + dma_length, dev_addr); + + __raw_writel(dev_addr, DMA_BASE + DMA_SAR(channel)); + __raw_ |