From cdde68e3a7d4cbf4701005ab6032366e76009419 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 19 Oct 2009 14:43:19 -0500 Subject: ENGR00117389 Port 5.0.0 release to 2.6.31 This is i.MX BSP 5.0.0 release ported to 2.6.31 Signed-off-by: Rob Herring Signed-off-by: Alan Tull Signed-off-by: Xinyu Chen --- arch/arm/plat-mxc/Kconfig | 127 +- arch/arm/plat-mxc/Makefile | 52 +- arch/arm/plat-mxc/clock.c | 335 ++- arch/arm/plat-mxc/cpu_common.c | 84 + arch/arm/plat-mxc/cpufreq.c | 347 +++ arch/arm/plat-mxc/dma_mx2.c | 1316 +++++++++ arch/arm/plat-mxc/dptc.c | 621 +++++ arch/arm/plat-mxc/dvfs_core.c | 802 ++++++ arch/arm/plat-mxc/entry-pm.S | 315 +++ arch/arm/plat-mxc/gpio.c | 175 +- arch/arm/plat-mxc/include/mach/arc_otg.h | 343 +++ arch/arm/plat-mxc/include/mach/audio_controls.h | 220 ++ arch/arm/plat-mxc/include/mach/clock.h | 19 +- arch/arm/plat-mxc/include/mach/common.h | 12 +- arch/arm/plat-mxc/include/mach/dma.h | 293 ++ arch/arm/plat-mxc/include/mach/dptc.h | 186 ++ arch/arm/plat-mxc/include/mach/dvfs_dptc_struct.h | 169 ++ arch/arm/plat-mxc/include/mach/entry-macro.S | 33 +- arch/arm/plat-mxc/include/mach/fsl_usb.h | 86 + arch/arm/plat-mxc/include/mach/fsl_usb_gadget.h | 40 + arch/arm/plat-mxc/include/mach/gpio.h | 3 + arch/arm/plat-mxc/include/mach/hardware.h | 64 +- arch/arm/plat-mxc/include/mach/hw_events.h | 65 + arch/arm/plat-mxc/include/mach/io.h | 42 +- arch/arm/plat-mxc/include/mach/irqs.h | 34 +- arch/arm/plat-mxc/include/mach/memory.h | 49 +- arch/arm/plat-mxc/include/mach/mmc.h | 17 + arch/arm/plat-mxc/include/mach/mtd-xip.h | 30 +- arch/arm/plat-mxc/include/mach/mx25.h | 462 ++++ arch/arm/plat-mxc/include/mach/mx2_dma.h | 261 ++ arch/arm/plat-mxc/include/mach/mx31.h | 95 + arch/arm/plat-mxc/include/mach/mx35.h | 127 + arch/arm/plat-mxc/include/mach/mx37.h | 474 ++++ arch/arm/plat-mxc/include/mach/mx3x.h | 45 +- arch/arm/plat-mxc/include/mach/mx51.h | 511 ++++ arch/arm/plat-mxc/include/mach/mxc.h | 570 +++- arch/arm/plat-mxc/include/mach/mxc_dptc.h | 111 + arch/arm/plat-mxc/include/mach/mxc_dvfs.h | 51 + arch/arm/plat-mxc/include/mach/mxc_edid.h | 33 + arch/arm/plat-mxc/include/mach/mxc_gpc.h | 74 + arch/arm/plat-mxc/include/mach/mxc_pm.h | 252 ++ arch/arm/plat-mxc/include/mach/mxc_scc.h | 45 + arch/arm/plat-mxc/include/mach/mxc_timer.h | 157 ++ arch/arm/plat-mxc/include/mach/mxc_uart.h | 275 ++ arch/arm/plat-mxc/include/mach/mxc_vpu.h | 94 + arch/arm/plat-mxc/include/mach/pcmcia.h | 218 ++ arch/arm/plat-mxc/include/mach/pmic_audio.h | 2315 ++++++++++++++++ arch/arm/plat-mxc/include/mach/pmic_convity.h | 873 ++++++ arch/arm/plat-mxc/include/mach/pmic_power.h | 1358 ++++++++++ arch/arm/plat-mxc/include/mach/sdma.h | 561 ++++ arch/arm/plat-mxc/include/mach/spba.h | 66 + arch/arm/plat-mxc/include/mach/system.h | 7 +- arch/arm/plat-mxc/include/mach/timex.h | 8 +- arch/arm/plat-mxc/include/mach/uncompress.h | 2 + arch/arm/plat-mxc/io.c | 41 + arch/arm/plat-mxc/irq.c | 146 +- arch/arm/plat-mxc/isp1301xc.c | 290 ++ arch/arm/plat-mxc/isp1504xc.c | 279 ++ arch/arm/plat-mxc/leds.c | 111 + arch/arm/plat-mxc/mc13783_xc.c | 299 +++ arch/arm/plat-mxc/pwm.c | 26 +- arch/arm/plat-mxc/sdma/Makefile | 18 + arch/arm/plat-mxc/sdma/dma_sdma.c | 697 +++++ arch/arm/plat-mxc/sdma/iapi/Makefile | 5 + arch/arm/plat-mxc/sdma/iapi/include/epm.h | 187 ++ arch/arm/plat-mxc/sdma/iapi/include/iapi.h | 49 + arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h | 128 + arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h | 136 + arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h | 78 + arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h | 50 + arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h | 60 + arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h | 52 + .../arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h | 41 + arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h | 96 + arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h | 426 +++ arch/arm/plat-mxc/sdma/iapi/src/Makefile | 18 + arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c | 110 + arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c | 2798 ++++++++++++++++++++ arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c | 149 ++ arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c | 79 + arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c | 518 ++++ arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c | 623 +++++ arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c | 52 + arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c | 64 + arch/arm/plat-mxc/sdma/sdma.c | 1481 +++++++++++ arch/arm/plat-mxc/sdma/sdma_malloc.c | 387 +++ arch/arm/plat-mxc/serialxc.c | 64 + arch/arm/plat-mxc/snoop.c | 133 + arch/arm/plat-mxc/spba.c | 133 + arch/arm/plat-mxc/time.c | 30 +- arch/arm/plat-mxc/tzic.c | 181 ++ arch/arm/plat-mxc/usb_common.c | 860 ++++++ arch/arm/plat-mxc/utmixc.c | 106 + arch/arm/plat-mxc/wdog.c | 68 + 94 files changed, 25875 insertions(+), 118 deletions(-) create mode 100644 arch/arm/plat-mxc/cpu_common.c create mode 100644 arch/arm/plat-mxc/cpufreq.c create mode 100644 arch/arm/plat-mxc/dma_mx2.c create mode 100644 arch/arm/plat-mxc/dptc.c create mode 100644 arch/arm/plat-mxc/dvfs_core.c create mode 100644 arch/arm/plat-mxc/entry-pm.S create mode 100644 arch/arm/plat-mxc/include/mach/arc_otg.h create mode 100644 arch/arm/plat-mxc/include/mach/audio_controls.h create mode 100644 arch/arm/plat-mxc/include/mach/dma.h create mode 100644 arch/arm/plat-mxc/include/mach/dptc.h create mode 100644 arch/arm/plat-mxc/include/mach/dvfs_dptc_struct.h create mode 100644 arch/arm/plat-mxc/include/mach/fsl_usb.h create mode 100644 arch/arm/plat-mxc/include/mach/fsl_usb_gadget.h create mode 100644 arch/arm/plat-mxc/include/mach/hw_events.h create mode 100644 arch/arm/plat-mxc/include/mach/mx25.h create mode 100644 arch/arm/plat-mxc/include/mach/mx2_dma.h create mode 100644 arch/arm/plat-mxc/include/mach/mx37.h create mode 100644 arch/arm/plat-mxc/include/mach/mx51.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_dptc.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_dvfs.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_edid.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_gpc.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_pm.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_scc.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_timer.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_uart.h create mode 100644 arch/arm/plat-mxc/include/mach/mxc_vpu.h create mode 100644 arch/arm/plat-mxc/include/mach/pcmcia.h create mode 100644 arch/arm/plat-mxc/include/mach/pmic_audio.h create mode 100644 arch/arm/plat-mxc/include/mach/pmic_convity.h create mode 100644 arch/arm/plat-mxc/include/mach/pmic_power.h create mode 100644 arch/arm/plat-mxc/include/mach/sdma.h create mode 100644 arch/arm/plat-mxc/include/mach/spba.h create mode 100644 arch/arm/plat-mxc/io.c create mode 100644 arch/arm/plat-mxc/isp1301xc.c create mode 100644 arch/arm/plat-mxc/isp1504xc.c create mode 100644 arch/arm/plat-mxc/leds.c create mode 100644 arch/arm/plat-mxc/mc13783_xc.c create mode 100644 arch/arm/plat-mxc/sdma/Makefile create mode 100644 arch/arm/plat-mxc/sdma/dma_sdma.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/Makefile create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/epm.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapi.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/Makefile create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c create mode 100644 arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c create mode 100644 arch/arm/plat-mxc/sdma/sdma.c create mode 100644 arch/arm/plat-mxc/sdma/sdma_malloc.c create mode 100644 arch/arm/plat-mxc/serialxc.c create mode 100644 arch/arm/plat-mxc/snoop.c create mode 100644 arch/arm/plat-mxc/spba.c create mode 100644 arch/arm/plat-mxc/tzic.c create mode 100644 arch/arm/plat-mxc/usb_common.c create mode 100644 arch/arm/plat-mxc/utmixc.c create mode 100644 arch/arm/plat-mxc/wdog.c (limited to 'arch/arm/plat-mxc') diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 8986b7412235..e09407b66a5e 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -22,9 +22,30 @@ config ARCH_MX2 config ARCH_MX3 bool "MX3-based" select CPU_V6 - select COMMON_CLKDEV +# select COMMON_CLKDEV + help + This enables support for systems based on the Freescale i.MX31 and i.MX32 + +config ARCH_MX25 + bool "MX25-based" + select MX25_OPTIONS + help + This enables support for systems based on the Freescale i.MX25 + +config ARCH_MX35 + bool "MX35-based" + help + This enables support for systems based on Freescale i.MX35 + +config ARCH_MX37 + bool "MX37-based" help - This enables support for systems based on the Freescale i.MX3 family + This enables support for systems based on Freescale i.MX37 + +config ARCH_MX51 + bool "MX51-based" + help + This enables support for systems based on Freescale i.MX51 endchoice @@ -32,8 +53,106 @@ source "arch/arm/mach-mx1/Kconfig" source "arch/arm/mach-mx2/Kconfig" source "arch/arm/mach-mx3/Kconfig" +source "arch/arm/mach-mx25/Kconfig" +source "arch/arm/mach-mx35/Kconfig" +source "arch/arm/mach-mx37/Kconfig" +source "arch/arm/mach-mx51/Kconfig" + endmenu +config MXC_TZIC + bool + depends on ARCH_MXC + +config MXC_DSP_BRINGUP + bool + depends on ARCH_MXC + +config ARCH_HAS_EVTMON + bool + depends on ARCH_MXC + +config MXC_EMMA + bool + depends on ARCH_MXC + +config MXC_FB_IRAM + bool + depends on ARCH_MXC + +config DMA_ZONE_SIZE + int "DMA memory zone size" + range 0 64 + default 24 + help + This is the size in MB for the DMA zone. The DMA zone is used for + dedicated memory for large contiguous video buffers + +# set iff we need the 1504 transceiver code +config ISP1504_MXC + bool + select ISP1504_MXC_OTG if USB_GADGET && USB_EHCI_HCD && USB_OTG + default y if USB_EHCI_FSL_1504 || USB_GADGET_FSL_1504 + +config ISP1504_MXC_OTG + tristate + help + Support for USB OTG pin detect using the ISP1504 transceiver on MXC platforms. + +# set iff we need the UTMI transceiver code +config UTMI_MXC + bool + select UTMI_MXC_OTG if ARCH_MX25 && USB_GADGET && USB_EHCI_HCD && USB_OTG + default y if USB_EHCI_FSL_UTMI || USB_GADGET_FSL_UTMI + depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX37 || ARCH_MX51 + +config UTMI_MXC_OTG + tristate + help + Support for USB OTG pin detect using the UTMI transceiver on MXC platforms. + +# set iff we need the 1301 transceiver code +config ISP1301_MXC + bool + default y if USB_EHCI_FSL_1301 || USB_GADGET_FSL_1301 + select I2C_MXC + +# set iff we need the mx13783 transceiver code +config MC13783_MXC + bool + default y if USB_EHCI_FSL_MC13783 || USB_GADGET_FSL_MC13783 + select SPI_MXC + +choice + prompt "Select serial USB transceiver mode" + depends on ISP1301_MXC || MC13783_MXC + default MXC_USB_SU6 + +config MXC_USB_SU6 + bool "Single Ended Unidirectional Mode" + help + If you say yes to this option, the serial tranceiver operates in SU6 mode. + This option will work for either the Freescale MC13783 or Philips ISP1301 + transceiver. + +config MXC_USB_SB3 + bool "Single Ended Bidirectional Mode" + help + If you say yes to this option, the serial tranceiver operates in SB3 mode. + Not recommended for the Freescale MC13783. + +config MXC_USB_DU6 + bool "Differential Unidirectional Mode" + help + If you say yes to this option, the serial tranceiver operates in DU6 mode. + +config MXC_USB_DB4 + bool "Differential Bidirectional Mode" + help + If you say yes to this option, the serial tranceiver operates in DB4 mode. + +endchoice + config MXC_IRQ_PRIOR bool "Use IRQ priority" depends on ARCH_MXC @@ -56,6 +175,10 @@ config ARCH_HAS_RNGA bool depends on ARCH_MXC +config ARCH_HAS_RNGC + bool + depends on ARCH_MXC + config ARCH_MXC_IOMUX_V3 bool endif diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index e3212c8ff421..56da7aa5d278 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -3,9 +3,59 @@ # # Common support -obj-y := irq.o clock.o gpio.o time.o devices.o cpu.o system.o +obj-y := cpu.o cpu_common.o gpio.o clock.o wdog.o snoop.o io.o time.o obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o obj-$(CONFIG_MXC_PWM) += pwm.o + +ifneq ($(CONFIG_ARCH_MX27),y) +obj-y += spba.o sdma/ +endif + +ifeq ($(CONFIG_MXC_TZIC),y) +obj-y += tzic.o +else +obj-y += irq.o +endif + +obj-$(CONFIG_ARCH_MX27) += dma_mx2.o usb_common.o +obj-$(CONFIG_ARCH_MX3) += dptc.o usb_common.o entry-pm.o +obj-$(CONFIG_ARCH_MX35) += usb_common.o serialxc.o +obj-$(CONFIG_ARCH_MX37) += usb_common.o utmixc.o dptc.o dvfs_core.o +obj-$(CONFIG_ARCH_MX51) += usb_common.o utmixc.o dvfs_core.o + +# LEDs support +obj-$(CONFIG_LEDS) += leds.o + +# CPU FREQ support +obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o + +# USB support +obj-$(CONFIG_ISP1504_MXC) += isp1504xc.o +obj-$(CONFIG_ISP1301_MXC) += isp1301xc.o +obj-$(CONFIG_MC13783_MXC) += mc13783_xc.o + +# obj-$(CONFIG_USB_EHCI_FSL_UTMI) += utmixc.o +ifneq ($(strip $(CONFIG_USB_EHCI_FSL_UTMI) $(CONFIG_USB_GADGET_FSL_UTMI)),) +obj-y += utmixc.o +endif + +ifneq ($(CONFIG_USB_EHCI_ARC_H1)$(CONFIG_USB_EHCI_ARC_H2),) +ifneq ($(CONFIG_ARCH_MX51),y) +obj-y += serialxc.o +else +obj-y += isp1504xc.o +endif +endif + +ifneq ($(CONFIG_ARCH_MX25)$(CONFIG_USB),) +obj-y += usb_common.o +endif + +ifeq ($(CONFIG_ARCH_MX25),y) +ifneq ($(CONFIG_USB_EHCI_ARC_H2),) +obj-y += serialxc.o +endif +endif diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 92e13566cd4f..4ba52f106bfb 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -4,7 +4,7 @@ * Copyright (C) 2004 - 2005 Nokia corporation * Written by Tuukka Tikkanen * Modified for omap shared clock framework by Tony Lindgren - * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -25,6 +25,7 @@ /* #define DEBUG */ #include +#include #include #include #include @@ -35,13 +36,27 @@ #include #include #include +#include #include #include #include +#if (defined(CONFIG_ARCH_MX51) || defined(CONFIG_ARCH_MX37)) +extern int dvfs_core_is_active; +extern int lp_high_freq; +extern int lp_med_freq; +extern void dvfs_core_set_bus_freq(void); +#else +int dvfs_core_is_active; +void dvfs_core_set_bus_freq(void) +{ +}; +#endif + static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clockfw_lock); /*------------------------------------------------------------------------- * Standard clock functions defined in include/linux/clk.h @@ -119,14 +134,16 @@ EXPORT_SYMBOL(clk_get); static void __clk_disable(struct clk *clk) { - if (clk == NULL || IS_ERR(clk)) + if (clk == NULL || IS_ERR(clk) || !clk->usecount) return; - __clk_disable(clk->parent); - __clk_disable(clk->secondary); + if (!(--clk->usecount)) { + if (clk->disable) + clk->disable(clk); - if (!(--clk->usecount) && clk->disable) - clk->disable(clk); + __clk_disable(clk->parent); + __clk_disable(clk->secondary); + } } static int __clk_enable(struct clk *clk) @@ -134,12 +151,13 @@ static int __clk_enable(struct clk *clk) if (clk == NULL || IS_ERR(clk)) return -EINVAL; - __clk_enable(clk->parent); - __clk_enable(clk->secondary); - - if (clk->usecount++ == 0 && clk->enable) - clk->enable(clk); + if (clk->usecount++ == 0) { + __clk_enable(clk->parent); + __clk_enable(clk->secondary); + if (clk->enable) + clk->enable(clk); + } return 0; } @@ -148,15 +166,36 @@ static int __clk_enable(struct clk *clk) */ int clk_enable(struct clk *clk) { + unsigned long flags; int ret = 0; if (clk == NULL || IS_ERR(clk)) return -EINVAL; - mutex_lock(&clocks_mutex); + spin_lock_irqsave(&clockfw_lock, flags); + ret = __clk_enable(clk); - mutex_unlock(&clocks_mutex); + spin_unlock_irqrestore(&clockfw_lock, flags); + + if ((clk->flags & CPU_FREQ_TRIG_UPDATE) + && (clk_get_usecount(clk) == 1)) { +#if defined(CONFIG_CPU_FREQ) + if (dvfs_core_is_active) + dvfs_core_set_bus_freq(); +#if (defined(CONFIG_ARCH_MX51) || defined(CONFIG_ARCH_MX37)) + else if ((lp_high_freq == 0 && lp_med_freq == 0) || + (lp_high_freq == 1) || + (lp_high_freq == 0 && lp_med_freq == 1)) +#else + else +#endif + cpufreq_update_policy(0); +#else + if (dvfs_core_is_active) + dvfs_core_set_bus_freq(); +#endif + } return ret; } EXPORT_SYMBOL(clk_enable); @@ -167,15 +206,56 @@ EXPORT_SYMBOL(clk_enable); */ void clk_disable(struct clk *clk) { + unsigned long flags; + if (clk == NULL || IS_ERR(clk)) return; - mutex_lock(&clocks_mutex); + spin_lock_irqsave(&clockfw_lock, flags); + __clk_disable(clk); - mutex_unlock(&clocks_mutex); + + spin_unlock_irqrestore(&clockfw_lock, flags); + + if ((clk->flags & CPU_FREQ_TRIG_UPDATE) + && (clk_get_usecount(clk) == 0)) { +#if defined(CONFIG_CPU_FREQ) + if (dvfs_core_is_active) + dvfs_core_set_bus_freq(); +#if (defined(CONFIG_ARCH_MX51) || defined(CONFIG_ARCH_MX37)) + else if (lp_high_freq == 0) +#else + else +#endif + cpufreq_update_policy(0); +#else + if (dvfs_core_is_active) + dvfs_core_set_bus_freq(); +#endif + } } + EXPORT_SYMBOL(clk_disable); +/*! + * @brief Function to get the usage count for the requested clock. + * + * This function returns the reference count for the clock. + * + * @param clk Handle to clock to disable. + * + * @return Returns the usage count for the requested clock. + */ +int clk_get_usecount(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return 0; + + return clk->usecount; +} + +EXPORT_SYMBOL(clk_get_usecount); + /* Retrieve the *current* clock rate. If the clock itself * does not provide a special calculation routine, ask * its parent and so on, until one is able to return @@ -186,10 +266,7 @@ unsigned long clk_get_rate(struct clk *clk) if (clk == NULL || IS_ERR(clk)) return 0UL; - if (clk->get_rate) - return clk->get_rate(clk); - - return clk_get_rate(clk->parent); + return clk->rate; } EXPORT_SYMBOL(clk_get_rate); @@ -216,19 +293,48 @@ long clk_round_rate(struct clk *clk, unsigned long rate) } EXPORT_SYMBOL(clk_round_rate); +/* Propagate rate to children */ +void propagate_rate(struct clk *tclk) +{ + struct clk *clkp; + + if (tclk == NULL || IS_ERR(tclk)) + return; + + pr_debug("mxc clock: finding children of %s-%d\n", tclk->name, + tclk->id); + list_for_each_entry(clkp, &clocks, node) { + if (likely(clkp->parent != tclk)) + continue; + pr_debug("mxc clock: %s-%d: recalculating rate: old = %lu, ", + clkp->name, clkp->id, clkp->rate); + if (likely((u32) clkp->recalc)) + clkp->recalc(clkp); + else + clkp->rate = tclk->rate; + pr_debug("new = %lu\n", clkp->rate); + propagate_rate(clkp); + } +} + /* Set the clock to the requested clock rate. The rate must * match a supported rate exactly based on what clk_round_rate returns */ int clk_set_rate(struct clk *clk, unsigned long rate) { + unsigned long flags; int ret = -EINVAL; if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0) return ret; - mutex_lock(&clocks_mutex); + spin_lock_irqsave(&clockfw_lock, flags); + ret = clk->set_rate(clk, rate); - mutex_unlock(&clocks_mutex); + if (unlikely((ret == 0) && (clk->flags & RATE_PROPAGATES))) + propagate_rate(clk); + + spin_unlock_irqrestore(&clockfw_lock, flags); return ret; } @@ -237,17 +343,35 @@ EXPORT_SYMBOL(clk_set_rate); /* Set the clock's parent to another clock source */ int clk_set_parent(struct clk *clk, struct clk *parent) { + unsigned long flags; int ret = -EINVAL; + struct clk *prev_parent = clk->parent; if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent) || clk->set_parent == NULL) return ret; - mutex_lock(&clocks_mutex); + if (clk->usecount != 0) { + clk_enable(parent); + } + + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->set_parent(clk, parent); - if (ret == 0) + if (ret == 0) { clk->parent = parent; - mutex_unlock(&clocks_mutex); + if (clk->recalc) { + clk->recalc(clk); + } else { + clk->rate = parent->rate; + } + if (unlikely(clk->flags & RATE_PROPAGATES)) + propagate_rate(clk); + } + spin_unlock_irqrestore(&clockfw_lock, flags); + + if (clk->usecount != 0) { + clk_disable(prev_parent); + } return ret; } @@ -295,43 +419,164 @@ void clk_unregister(struct clk *clk) EXPORT_SYMBOL(clk_unregister); #ifdef CONFIG_PROC_FS -static int mxc_clock_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) + +static void *mxc_proc_clocks_seq_start(struct seq_file *file, loff_t *index) { - struct clk *clkp; - char *p = page; - int len; + unsigned int i; + unsigned int name_length; + unsigned int longest_length = 0; + struct clk *current_clock = 0; + struct clk *clock; + + /* Examine the clock list. */ + + i = 0; + + list_for_each_entry(clock, &clocks, node) { + if (i++ == *index) + current_clock = clock; + name_length = strlen(clock->name); + if (name_length > longest_length) + longest_length = name_length; + } - list_for_each_entry(clkp, &clocks, node) { - p += sprintf(p, "%s-%d:\t\t%lu, %d", clkp->name, clkp->id, - clk_get_rate(clkp), clkp->usecount); - if (clkp->parent) - p += sprintf(p, ", %s-%d\n", clkp->parent->name, - clkp->parent->id); - else - p += sprintf(p, "\n"); + /* Check if we found the indicated clock. */ + + if (!current_clock) + return NULL; + + /* Stash the length of the longest clock name for later use. */ + + file->private = (void *) longest_length; + + /* Return success. */ + + return current_clock; +} + +static void *mxc_proc_clocks_seq_next(struct seq_file *file, void *data, + loff_t *index) +{ + struct clk *current_clock = (struct clk *) data; + + /* Check for nonsense. */ + + if (!current_clock) + return NULL; + + /* Check if the current clock is the last. */ + + if (list_is_last(¤t_clock->node, &clocks)) + return NULL; + + /* Move to the next clock structure. */ + + current_clock = list_entry(current_clock->node.next, + typeof(*current_clock), node); + + (*index)++; + + /* Return the new current clock. */ + + return current_clock; + +} + +static void mxc_proc_clocks_seq_stop(struct seq_file *file, void *data) +{ +} + +static int mxc_proc_clocks_seq_show(struct seq_file *file, void *data) +{ + int result; + struct clk *clock = (struct clk *) data; + struct clk *parent = clock->parent; + unsigned int longest_length = (unsigned int) file->private; + unsigned long range_divisor; + const char *range_units; + + if (clock->rate >= 1000000) { + range_divisor = 1000000; + range_units = "MHz"; + } else if (clock->rate >= 1000) { + range_divisor = 1000; + range_units = "KHz"; + } else { + range_divisor = 1; + range_units = "Hz"; } - len = (p - page) - off; - if (len < 0) - len = 0; + if (parent) + result = seq_printf(file, + "%s-%-d%*s %s-%-d%*s %c%c%c%c%c%c %3d", + clock->name, + clock->id, + longest_length - strlen(clock->name), "", + parent->name, + parent->id, + longest_length - strlen(parent->name), "", + (clock->flags & RATE_PROPAGATES) ? 'P' : '_', + (clock->flags & ALWAYS_ENABLED) ? 'A' : '_', + (clock->flags & RATE_FIXED) ? 'F' : '_', + (clock->flags & CPU_FREQ_TRIG_UPDATE) ? 'T' : '_', + (clock->flags & AHB_HIGH_SET_POINT) ? 'H' : '_', + (clock->flags & AHB_MED_SET_POINT) ? 'M' : '_', + clock->usecount); + else + result = seq_printf(file, + "%s-%-d%*s %*s %c%c%c%c%c%c %3d", + clock->name, + clock->id, + longest_length - strlen(clock->name), "", + longest_length + 2, "", + (clock->flags & RATE_PROPAGATES) ? 'P' : '_', + (clock->flags & ALWAYS_ENABLED) ? 'A' : '_', + (clock->flags & RATE_FIXED) ? 'F' : '_', + (clock->flags & CPU_FREQ_TRIG_UPDATE) ? 'T' : '_', + (clock->flags & AHB_HIGH_SET_POINT) ? 'H' : '_', + (clock->flags & AHB_MED_SET_POINT) ? 'M' : '_', + clock->usecount); + + if (result) + return result; + + result = seq_printf(file, " %10lu (%lu%s)\n", + clock->rate, + clock->rate / range_divisor, range_units); + + return result; + +} - *eof = (len <= count) ? 1 : 0; - *start = page + off; +static const struct seq_operations mxc_proc_clocks_seq_ops = { + .start = mxc_proc_clocks_seq_start, + .next = mxc_proc_clocks_seq_next, + .stop = mxc_proc_clocks_seq_stop, + .show = mxc_proc_clocks_seq_show +}; - return len; +static int mxc_proc_clocks_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &mxc_proc_clocks_seq_ops); } +static const struct file_operations mxc_proc_clocks_ops = { + .open = mxc_proc_clocks_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static int __init mxc_setup_proc_entry(void) { struct proc_dir_entry *res; - res = create_proc_read_entry("cpu/clocks", 0, NULL, - mxc_clock_read_proc, NULL); + res = create_proc_entry("cpu/clocks", 0, NULL); if (!res) { printk(KERN_ERR "Failed to create proc/cpu/clocks\n"); return -ENOMEM; } + res->proc_fops = &mxc_proc_clocks_ops; return 0; } diff --git a/arch/arm/plat-mxc/cpu_common.c b/arch/arm/plat-mxc/cpu_common.c new file mode 100644 index 000000000000..07e92e17289a --- /dev/null +++ b/arch/arm/plat-mxc/cpu_common.c @@ -0,0 +1,84 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include + +extern int mxc_early_serial_console_init(char *); + +/*! + * @file plat-mxc/cpu_common.c + * + * @brief This file contains the common CPU initialization code. + * + * @ingroup MSL_MX31 MSL_MXC91321 + */ + +static void __init system_rev_setup(char **p) +{ + system_rev = simple_strtoul(*p, NULL, 16); +} + +__early_param("system_rev=", system_rev_setup); + +int mxc_jtag_enabled; /* OFF: 0 (default), ON: 1 */ + +/* + * Here are the JTAG options from the command line. By default JTAG + * is OFF which means JTAG is not connected and WFI is enabled + * + * "on" -- JTAG is connected, so WFI is disabled + * "off" -- JTAG is disconnected, so WFI is enabled + */ + +static void __init jtag_wfi_setup(char **p) +{ + if (memcmp(*p, "on", 2) == 0) { + mxc_jtag_enabled = 1; + *p += 2; + } else if (memcmp(*p, "off", 3) == 0) { + mxc_jtag_enabled = 0; + *p += 3; + } +} + +__early_param("jtag=", jtag_wfi_setup); + +void __init mxc_cpu_common_init(void) +{ + mxc_set_cpu_type((((system_rev >> 20) & 0xF) * 10) + ((system_rev >> 16) & 0xF)); + pr_info("CPU is %s%x Revision %u.%u\n", + (mxc_cpu() < 0x100) ? "i.MX" : "MXC", + mxc_cpu(), mxc_cpu_rev_major(), mxc_cpu_rev_minor()); +} + +/** + * early_console_setup - setup debugging console + * + * Consoles started here require little enough setup that we can start using + * them very early in the boot process, either right after the machine + * vector initialization, or even before if the drivers can detect their hw. + * + * Returns non-zero if a console couldn't be setup. + * This function is developed based on + * early_console_setup function as defined in arch/ia64/kernel/setup.c + */ +void __init early_console_setup(char *cmdline) +{ +#ifdef CONFIG_SERIAL_MXC_CONSOLE + mxc_early_serial_console_init(cmdline); +#endif +} diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c new file mode 100644 index 000000000000..bc3d1c97526c --- /dev/null +++ b/arch/arm/plat-mxc/cpufreq.c @@ -0,0 +1,347 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file cpufreq.c + * + * @brief A driver for the Freescale Semiconductor i.MXC CPUfreq module. + * + * The CPUFREQ driver is for controling CPU frequency. It allows you to change + * the CPU clock speed on the fly. + * + * @ingroup PM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int cpu_freq_khz_min; +int cpu_freq_khz_max; +int arm_lpm_clk; +int arm_normal_clk; +int cpufreq_suspended; + +static struct clk *cpu_clk; +static struct regulator *gp_regulator; +static struct cpu_wp *cpu_wp_tbl; +static struct cpufreq_frequency_table imx_freq_table[4]; +extern int low_bus_freq_mode; +extern int high_bus_freq_mode; +extern int dvfs_core_is_active; +extern int cpu_wp_nr; +extern char *gp_reg_id; + +extern int set_low_bus_freq(void); +extern int set_high_bus_freq(int high_bus_speed); +extern int low_freq_bus_used(void); + +#ifdef CONFIG_ARCH_MX51 +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +#endif + +static int set_cpu_freq(int freq) +{ + int ret = 0; + int org_cpu_rate; + int gp_volt = 0; + int i; + + org_cpu_rate = clk_get_rate(cpu_clk); + + if (org_cpu_rate == freq) + return ret; + + for (i = 0; i < cpu_wp_nr; i++) { + if (freq == cpu_wp_tbl[i].cpu_rate) + gp_volt = cpu_wp_tbl[i].cpu_voltage; + } + + if (gp_volt == 0) + return ret; + + /*Set the voltage for the GP domain. */ + if (freq > org_cpu_rate) { + ret = regulator_set_voltage(gp_regulator, gp_volt, gp_volt); + if (ret < 0) { + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n"); + return ret; + } + } + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + printk(KERN_DEBUG "cannot set CPU clock rate\n"); + return ret; + } + + if (freq < org_cpu_rate) { + ret = regulator_set_voltage(gp_regulator, gp_volt, gp_volt); + if (ret < 0) { + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n"); + return ret; + } + } + + return ret; +} + +static int mxc_verify_speed(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -EINVAL; + + return cpufreq_frequency_table_verify(policy, imx_freq_table); +} + +static unsigned int mxc_get_speed(unsigned int cpu) +{ + if (cpu) + return 0; + + return clk_get_rate(cpu_clk) / 1000; +} + +static int calc_frequency_khz(int target, unsigned int relation) +{ + int i; + + if ((target * 1000) == clk_get_rate(cpu_clk)) + return target; + + if (relation == CPUFREQ_RELATION_H) { + for (i = cpu_wp_nr - 1; i >= 0; i--) { + if (imx_freq_table[i].frequency <= target) + return imx_freq_table[i].frequency; + } + } else if (relation == CPUFREQ_RELATION_L) { + for (i = 0; i < cpu_wp_nr; i++) { + if (imx_freq_table[i].frequency >= target) + return imx_freq_table[i].frequency; + } + } + printk(KERN_ERR "Error: No valid cpufreq relation\n"); + return cpu_freq_khz_max; +} + +static int mxc_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + int freq_Hz; + int low_freq_bus_ready = 0; + int ret = 0; + + if (cpufreq_suspended) + return 0; + + if (dvfs_core_is_active) { + target_freq = clk_get_rate(cpu_clk) / 1000; + freq_Hz = calc_frequency_khz(target_freq, relation) * 1000; + if (freq_Hz == arm_lpm_clk) + freqs.old = cpu_wp_tbl[cpu_wp_nr - 2].cpu_rate / 1000; + else + freqs.old = arm_lpm_clk / 1000; + + freqs.new = freq_Hz / 1000; + freqs.cpu = 0; + freqs.flags = 0; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return ret; + } + /* + * Some governors do not respects CPU and policy lower limits + * which leads to bad things (division by zero etc), ensure + * that such things do not happen. + */ + if (target_freq < policy->cpuinfo.min_freq) + target_freq = policy->cpuinfo.min_freq; + + if (target_freq < policy->min) + target_freq = policy->min; + + freq_Hz = calc_frequency_khz(target_freq, relation) * 1000; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = freq_Hz / 1000; + freqs.cpu = 0; + freqs.flags = 0; + low_freq_bus_ready = low_freq_bus_used(); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (!dvfs_core_is_active) { + if ((freq_Hz == arm_lpm_clk) && (!low_bus_freq_mode) + && (low_freq_bus_ready)) { + if (freqs.old != freqs.new) + ret = set_cpu_freq(freq_Hz); + set_low_bus_freq(); + + } else { + set_high_bus_freq(0); + ret = set_cpu_freq(freq_Hz); + } + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return ret; +} + +static int __init mxc_cpufreq_driver_init(struct cpufreq_policy *policy) +{ + int ret; + int i; + + printk(KERN_INFO "i.MXC CPU frequency driver\n"); + + if (policy->cpu != 0) + return -EINVAL; + + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_ERR "%s: failed to get cpu clock\n", __func__); + return PTR_ERR(cpu_clk); + } + + gp_regulator = regulator_get(NULL, gp_reg_id); + if (IS_ERR(gp_regulator)) { + clk_put(cpu_clk); + printk(KERN_ERR "%s: failed to get gp regulator\n", __func__); + return PTR_ERR(gp_regulator); + } + + /* Set the current working point. */ + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + + cpu_freq_khz_min = cpu_wp_tbl[0].cpu_rate / 1000; + cpu_freq_khz_max = cpu_wp_tbl[0].cpu_rate / 1000; + + for (i = 0; i < cpu_wp_nr; i++) { + imx_freq_table[cpu_wp_nr - 1 - i].index = cpu_wp_nr - i; + imx_freq_table[cpu_wp_nr - 1 - i].frequency = + cpu_wp_tbl[i].cpu_rate / 1000; + + if ((cpu_wp_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min) + cpu_freq_khz_min = cpu_wp_tbl[i].cpu_rate / 1000; + + if ((cpu_wp_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max) + cpu_freq_khz_max = cpu_wp_tbl[i].cpu_rate / 1000; + } + + imx_freq_table[i].index = 0; + imx_freq_table[i].frequency = CPUFREQ_TABLE_END; + + policy->cur = clk_get_rate(cpu_clk) / 1000; + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min; + policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max; + + arm_lpm_clk = cpu_freq_khz_min * 1000; + arm_normal_clk = cpu_freq_khz_max * 1000; + + /* Manual states, that PLL stabilizes in two CLK32 periods */ + policy->cpuinfo.transition_latency = 10; + + ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); + + if (ret < 0) { + clk_put(cpu_clk); + regulator_put(gp_regulator); + printk(KERN_ERR "%s: failed to register i.MXC CPUfreq\n", + __func__); + return ret; + } + + cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu); + return 0; +} + +static int mxc_cpufreq_suspend(struct cpufreq_policy *policy, + pm_message_t state) +{ + struct cpufreq_freqs freqs; + int ret = 0; + cpufreq_suspended = 1; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = arm_normal_clk / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + if (clk_get_rate(cpu_clk) != arm_normal_clk) { + set_high_bus_freq(1); + ret = set_cpu_freq(arm_normal_clk); + } + return ret; +} + +static int mxc_cpufreq_resume(struct cpufreq_policy *policy) +{ + cpufreq_suspended = 0; + return 0; +} + +static int mxc_cpufreq_driver_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + + /* Reset CPU to 665MHz */ + if (!dvfs_core_is_active) + set_cpu_freq(arm_normal_clk); + if (!high_bus_freq_mode) + set_high_bus_freq(1); + + clk_put(cpu_clk); + regulator_put(gp_regulator); + return 0; +} + +static struct cpufreq_driver mxc_driver = { + .flags = CPUFREQ_STICKY, + .verify = mxc_verify_speed, + .target = mxc_set_target, + .get = mxc_get_speed, + .init = mxc_cpufreq_driver_init, + .exit = mxc_cpufreq_driver_exit, + .suspend = mxc_cpufreq_suspend, + .resume = mxc_cpufreq_resume, + .name = "imx", +}; + +static int __devinit mxc_cpufreq_init(void) +{ + return cpufreq_register_driver(&mxc_driver); +} + +static void mxc_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&mxc_driver); +} + +module_init(mxc_cpufreq_init); +module_exit(mxc_cpufreq_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("CPUfreq driver for i.MX"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/dma_mx2.c b/arch/arm/plat-mxc/dma_mx2.c new file mode 100644 index 000000000000..5a7e93b31d57 --- /dev/null +++ b/arch/arm/plat-mxc/dma_mx2.c @@ -0,0 +1,1316 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* Front-end to the DMA handling. This handles the allocation/freeing + * of DMA channels, and provides a unified interface to the machines + * DMA facilities. + */ + +/*! + * @file plat-mxc/dma_mx2.c + * @brief This file contains functions for DMA API + * + * @ingroup DMA_MX27 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +/* commented temperily for mx27 compilation +#define DMA_PM +*/ +#ifdef DMA_PM +#include +#include +struct apmc_user *dma_apmc_user; +struct pm_dev *dma_pm; +#define DMA_PMST_RESUME 0 +#define DMA_PMST_STANDBY 1 +#define DMA_PMST_SUSPEND 2 +static unsigned int dma_pm_status = DMA_PMST_RESUME; +#endif + +/*! + * This variable is used to controll the clock of DMA. + * It counts the number of actived channels + */ +static atomic_t g_dma_actived = ATOMIC_INIT(0); + +/*! + * This variable point a proc file which contains the information + * of DMA channels + */ +static struct proc_dir_entry *g_proc_dir; + +/*! + * The dma channels + */ +static mxc_dma_channel_t g_dma_channels[MAX_DMA_CHANNELS]; +static mx2_dma_priv_t g_dma_privates[MXC_DMA_CHANNELS]; +static mx2_dma_bd_t g_dma_bd_table[MXC_DMA_CHANNELS][MAX_BD_SIZE]; + +static DEFINE_SPINLOCK(dma_list_lock); + +static struct clk *dma_clk; + +/*!@brief flush buffer descriptor ring*/ +#define flush_dma_bd(private) \ + { \ + atomic_set(&(private->bd_used), 0); \ + private->bd_rd = private->bd_wr;\ + } + +/*!@brief get next buffer discriptor */ +#define next_dma_bd(private) \ + ({ \ + int bd_next = (private->bd_rd+1)%MAX_BD_SIZE; \ + (bd_next == private->bd_wr) ? NULL: private->bd_ring+bd_next;\ + }) + +static inline int consume_dma_bd(mxc_dma_channel_t * dma, int error); +/*! + *@brief allocate a dma channel. + * + *@param idx Requested channel NO. + * @li MXC_INVLAID_CHANNEL System allocates a free channel which is not statically allocated. + * @li Others User requests a specific channel + *@return @li MXC_INVLAID_CHANNEL Failure + * @li Others Success + */ +static inline int get_dma_channel(int idx) +{ + int i; + mxc_dma_channel_t *p; + + if ((idx >= MAX_DMA_CHANNELS) && (idx != MXC_DMA_DYNAMIC_CHANNEL)) { + return -1; + } + if (idx != MXC_DMA_DYNAMIC_CHANNEL) { + p = g_dma_channels + idx; + BUG_ON(p->dynamic != 0); + if (xchg(&p->lock, 1) != 0) { + return -1; + } + return idx; + } + + p = g_dma_channels; + for (i = 0; (i < MAX_DMA_CHANNELS); i++, p++) { + if (p->dynamic && (xchg(&p->lock, 1) == 0)) { + return i; + } + } + return -1; +} + +/*! + *@brief release a dma channel. + * + *@param idx channel number + *@return none; + */ +static inline void put_dma_channel(int idx) +{ + mxc_dma_channel_t *p; + + if ((idx < MAX_DMA_CHANNELS) && (idx >= 0)) { + p = g_dma_channels + idx; + (void)xchg(&p->lock, 0); + } +} + +/*! + *@brief Get dma list for /proc/dma + */ +static int mxc_get_dma_list(char *buf) +{ + mxc_dma_channel_t *dma; + char *p = buf; + int i; + + for (i = 0, dma = g_dma_channels; i < MAX_DMA_CHANNELS; i++, dma++) { + if (dma->lock) { + p += sprintf(p, "dma channel %2d: %s\n", i, + dma->dev_name ? dma->dev_name : "unknown"); + } else { + p += sprintf(p, "dma channel %2d: unused\n", i); + } + } + + return p - buf; +} + +/*!@brief save the mask of dma interrupts*/ +#define save_dma_interrupt(flags) \ + flags = __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DIMR) + +/*!@brief restore the mask of dma interrupts*/ +#define restore_dma_interrupt(flags) \ + __raw_writel(flags, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DIMR) + +/*!@brief disable interrupt of dma channel*/ +static inline void mask_dma_interrupt(int channel) +{ + unsigned long reg; + save_dma_interrupt(reg); + reg |= 1 << channel; /*mask interrupt; */ + restore_dma_interrupt(reg); +} + +/*!@brief enable interrupt of dma channel */ +static inline void unmask_dma_interrupt(int channel) +{ + unsigned long reg; + save_dma_interrupt(reg); + reg &= ~(1 << channel); /*unmask interrupt; */ + restore_dma_interrupt(reg); +} + +/*!@brief get interrupt event of dma channel */ +static unsigned long inline __get_dma_interrupt(int channel) +{ + unsigned long mode; + mode = 0; + if (__raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DISR) & (1 << channel)) + mode |= DMA_DONE; + + if (__raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBTOSR) & + (1 << channel)) + mode |= DMA_BURST_TIMEOUT; + if (__raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DSESR) & (1 << channel)) + mode |= DMA_TRANSFER_ERROR; + + if (__raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBOSR) & (1 << channel)) + mode |= DMA_BUFFER_OVERFLOW; + if (__raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DRTOSR) & + (1 << channel)) + mode |= DMA_REQUEST_TIMEOUT; + return mode; +} + +/*! + *@brief clean all event of dma interrupt and return the valid event. + */ +static unsigned long inline __clear_dma_interrupt(int channel) +{ + unsigned long mode; + mode = __get_dma_interrupt(channel); + __raw_writel(1 << channel, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DISR); + __raw_writel(1 << channel, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBTOSR); + __raw_writel(1 << channel, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DRTOSR); + __raw_writel(1 << channel, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DSESR); + __raw_writel(1 << channel, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBOSR); + + return mode; +} + +/*!@brief This function enables dma clocks without lock */ +static void inline __enable_dma_clk(void) +{ + unsigned long reg; + clk_enable(dma_clk); + reg = __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DCR); + reg |= 0x1; + __raw_writel(reg, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DCR); +} + +/*!@brief This function disables dma clocks without lock */ +static void inline __disable_dma_clk(void) +{ + unsigned long reg; + reg = __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DCR); + reg &= ~0x1; + __raw_writel(reg, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DCR); + clk_disable(dma_clk); +} + +/*!@brief This function enables dma clocks with lock */ +static void inline enable_dma_clk(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_list_lock, flags); + if (atomic_read(&g_dma_actived) == 0) { + __enable_dma_clk(); + } + spin_unlock_irqrestore(&dma_list_lock, flags); + return; +} + +/*!@brief This function disables dma clocks without locked */ +static void inline disable_dma_clk(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_list_lock, flags); + if (atomic_read(&g_dma_actived) == 0) { + __disable_dma_clk(); + } + spin_unlock_irqrestore(&dma_list_lock, flags); + return; +} + +/*!@brief select a buffer to transfer and + * setup dma channel for current transfer + */ +static void setup_dmac(mxc_dma_channel_t * dma) +{ + mx2_dma_priv_t *priv = (mx2_dma_priv_t *) dma->private; + dma_regs_t *dma_base = (dma_regs_t *) (priv->dma_base); + mx2_dma_bd_t *p, *q; + unsigned long ctrl_val; + + if (dma->active == 0) { + printk(KERN_ERR + "dma channel %d is not enabled, when receiving this channel 's interrupt\n", + dma->channel); + return; + } + if (atomic_read(&(priv->bd_used)) <= 0) { + printk(KERN_ERR "dma channel %d is empty\n", dma->channel); + dma->active = 0; + atomic_dec(&g_dma_actived); + return; + } + /* BUSY: transfering + * PEND: Wait for set to DMAC. + * s1: no transfering: + * set first(one BUSY). if there are more than one tranfer. set second &repeat is enabled(two BUSY). + * + * s2: transfering & just on transfer + * one BUSY. set the tranesfer and set repeat bit(two BUSY) + * s3: transfering & repeat has set + * has two BUSY. + */ + p = priv->bd_ring + priv->bd_rd; + q = next_dma_bd(priv); + if (!(p->state & DMA_BD_ST_BUSY)) { + /*NOTICE:: This is first buffer or dma chain does not support chain-buffer. So CEN must clear & set again */ + ctrl_val = + __raw_readl(&(dma_base->Ctl)) & + (~(DMA_CTL_ACRPT | DMA_CTL_RPT | DMA_CTL_CEN)); + __raw_writel(ctrl_val, &(dma_base->Ctl)); + if (p->mode != dma->mode) { + dma->mode = p->mode; /* bi-dir channel do mode change */ + if (dma->mode == MXC_DMA_MODE_READ) { + DMA_CTL_SET_SMOD(ctrl_val, + priv->dma_info->sourceType); + DMA_CTL_SET_SSIZ(ctrl_val, + priv->dma_info->sourcePort); + DMA_CTL_SET_DMOD(ctrl_val, + priv->dma_info->destType); + DMA_CTL_SET_DSIZ(ctrl_val, + priv->dma_info->destPort); + } else { + DMA_CTL_SET_SMOD(ctrl_val, + priv->dma_info->destType); + DMA_CTL_SET_SSIZ(ctrl_val, + priv->dma_info->destPort); + DMA_CTL_SET_DMOD(ctrl_val, + priv->dma_info->sourceType); + DMA_CTL_SET_DSIZ(ctrl_val, + priv->dma_info->sourcePort); + } + } + __raw_writel(p->src_addr, &(dma_base->SourceAddr)); + __raw_writel(p->dst_addr, &(dma_base->DestAddr)); + __raw_writel(p->count, &(dma_base->Count)); + p->state |= DMA_BD_ST_BUSY; + p->state &= ~(DMA_BD_ST_PEND); + ctrl_val |= DMA_CTL_CEN; + __raw_writel(ctrl_val, &(dma_base->Ctl)); + if (q && priv->dma_chaining) { /*DO chain-buffer */ + __raw_writel(q->src_addr, &(dma_base->SourceAddr)); + __raw_writel(q->dst_addr, &(dma_base->DestAddr)); + __raw_writel(q->count, &(dma_base->Count)); + q->state |= DMA_BD_ST_BUSY; + q->state &= ~(DMA_BD_ST_PEND); + ctrl_val |= DMA_CTL_ACRPT | DMA_CTL_RPT | DMA_CTL_CEN; + __raw_writel(ctrl_val, &(dma_base->Ctl)); + } + } else { /* Just dma channel which supports dma buffer can run to there */ + BUG_ON(!priv->dma_chaining); + if (q) { /* p is tranfering, then q must be set into dma controller */ + /*WARNING:: [1] dangerous area begin. + * If the p is completed during MCU run in this erea, the dma channel is crashed. + */ + __raw_writel(q->src_addr, &(dma_base->SourceAddr)); + __raw_writel(q->dst_addr, &(dma_base->DestAddr)); + __raw_writel(q->count, &(dma_base->Count)); + /*WARNING:: [2] dangerous area end */ + ctrl_val = + __raw_readl(&(dma_base->Ctl)) | (DMA_CTL_ACRPT | + DMA_CTL_RPT | + DMA_CTL_CEN); + __raw_writel(ctrl_val, &(dma_base->Ctl)); + + /* WARNING:: This is workaround and it is dangerous: + * the judgement is not safety. + */ + if (!__get_dma_interrupt(dma->channel)) { + q->state |= DMA_BD_ST_BUSY; + q->state &= ~(DMA_BD_ST_PEND); + } else { + /*Waiting re-enable is in ISR */ + printk(KERN_ERR + "Warning:: The privous transfer is completed. Maybe the chain buffer is stopped."); + } + } else { /* Last buffer is transfering: just clear RPT bit */ + ctrl_val = + __raw_readl(&(dma_base->Ctl)) & + (~(DMA_CTL_ACRPT | DMA_CTL_RPT)); + __raw_writel(ctrl_val, &(dma_base->Ctl)); + } + } +} + +/*! + * @brief interrupt handler of dma channel + */ +static irqreturn_t dma_irq_handler(int irq, void *dev_id) +{ + mxc_dma_channel_t *dma = (mxc_dma_channel_t *) dev_id; + mx2_dma_priv_t *priv = (mx2_dma_priv_t *) (dma ? dma->private : NULL); + dma_regs_t *dma_base; + int state, error = MXC_DMA_DONE; + + BUG_ON(priv == NULL); + + dma_base = (dma_regs_t *) priv->dma_base; + + state = __clear_dma_interrupt(dma->channel); + + priv->trans_bytes += dma_base->transferd; + if (state != DMA_DONE) { + if (state & DMA_REQUEST_TIMEOUT) { + error = MXC_DMA_REQUEST_TIMEOUT; + } else { + error = MXC_DMA_TRANSFER_ERROR; + } + } + if (consume_dma_bd(dma, error)) { + disable_dma_clk(); + if (dma->cb_fn) { + dma->cb_fn(dma->cb_args, error, priv->trans_bytes); + } + priv->trans_bytes = 0; + } else { + disable_dma_clk(); + } + return IRQ_HANDLED; +} + +/*! + *@brief Set DMA channel parameters + * + *@param dma Requested channel NO. + *@param dma_info Channel configuration + *@return @li 0 Success + * @li others Failure + */ +static int setup_dma_channel(mxc_dma_channel_t * dma, mx2_dma_info_t * dma_info) +{ + mx2_dma_priv_t *priv = (mx2_dma_priv_t *) (dma ? dma->private : NULL); + dma_regs_t *dma_base; + unsigned long reg; + + if (!dma_info || !priv) { + return -1; + } + + if (dma_info->sourceType > 3) { + return -1; + } + if (dma_info->destType > 3) { + return -1; + } + if (dma_info->destPort > 3) { + return -1; + } + if (dma_info->sourcePort > 3) { + return -1; + } + if (dma_info->M2D_Valid) { + /*add for second dma */ + if (dma_info->W < dma_info->X) { + return -1; + } + } + + priv->dma_chaining = dma_info->dma_chaining; + priv->ren = dma_info->ren; + + if (dma_info->sourceType != DMA_TYPE_FIFO + && dma_info->destType != DMA_TYPE_FIFO) { + if (dma_info->ren) { + printk(KERN_INFO + "Warning:request enable just affect source or destination port is FIFO !\n"); + priv->ren = 0; + } + } + + if (dma_info->M2D_Valid) { + if (dma_info->msel) { + __raw_writel(dma_info->W, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_WSRB); + __raw_writel(dma_info->X, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_XSRB); + __raw_writel(dma_info->Y, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_YSRB); + + } else { + __raw_writel(dma_info->W, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_WSRA); + __raw_writel(dma_info->X, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_XSRA); + __raw_writel(dma_info->Y, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_YSRA); + } + } + + dma_base = (dma_regs_t *) (priv->dma_base); + + __raw_writel(dma_info->burstLength, &(dma_base->BurstLength)); + __raw_writel(dma_info->request, &(dma_base->RequestSource)); + + if (dma_info->ren) { + reg = dma_info->busuntils & 0x1FFFF; + if (dma_info->rto_en) { + reg |= 0xE000; + } + __raw_writel(reg, &(dma_base->BusUtilt)); + } else { + __raw_writel(dma_info->busuntils, &(dma_base->BusUtilt)); + } + + reg = __raw_readl(&(dma_base->Ctl)) & (~(DMA_CTL_ACRPT | DMA_CTL_RPT)); + + if (dma_info->dir) { + reg |= DMA_CTL_MDIR; + } else { + reg &= ~DMA_CTL_MDIR; + } + + if (priv->ren) { + reg |= DMA_CTL_REN; + } else { + reg &= ~DMA_CTL_REN; + } + + if ((dma_info->M2D_Valid) && (dma_info->msel)) { + reg |= DMA_CTL_MSEL; + } else { + reg &= ~DMA_CTL_MSEL; + } + + if (dma_info->mode) { + DMA_CTL_SET_SMOD(reg, dma_info->destType); + DMA_CTL_SET_SSIZ(reg, dma_info->destPort); + DMA_CTL_SET_DMOD(reg, dma_info->sourceType); + DMA_CTL_SET_DSIZ(reg, dma_info->sourcePort); + } else { + DMA_CTL_SET_SMOD(reg, dma_info->sourceType); + DMA_CTL_SET_SSIZ(reg, dma_info->sourcePort); + DMA_CTL_SET_DMOD(reg, dma_info->destType); + DMA_CTL_SET_DSIZ(reg, dma_info->destPort); + } + + __raw_writel(reg, &(dma_base->Ctl)); + + __clear_dma_interrupt(dma->channel); + unmask_dma_interrupt(dma->channel); + + disable_dma_clk(); + return 0; +} + +/*!@brief setup interrupt and setup dma channel by dma parameter */ +static inline int __init_dma_channel(mxc_dma_channel_t * chan, + mx2_dma_info_t * dma_info) +{ + mx2_dma_priv_t *dma_private = (mx2_dma_priv_t *) chan->private; + dma_regs_t *dma_base; + int ret; + + mask_dma_interrupt(chan->channel); + ret = + request_irq(dma_private->dma_irq, dma_irq_handler, + IRQF_DISABLED | IRQF_SHARED, chan->dev_name, + (void *)chan); + if (ret) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel\n", + chan->dev_name, dma_private->dma_irq); + return ret; + } + + enable_dma_clk(); + + dma_base = (dma_regs_t *) (dma_private->dma_base); + __raw_writel(0, &(dma_base->Ctl)); + + ret = 0; + if ((ret = setup_dma_channel(chan, dma_info))) { + free_irq(dma_private->dma_irq, (void *)chan); + } + disable_dma_clk(); + return 0; +} + +/*!@brief initialize buffer descriptor ring.*/ +static inline void init_dma_bd(mx2_dma_priv_t * private) +{ + int i; + mx2_dma_bd_t *pbd; + private->bd_rd = private->bd_wr = 0; + atomic_set(&(private->bd_used), 0); + for (i = 0, pbd = private->bd_ring; i < MAX_BD_SIZE; i++, pbd++) { + pbd->state = 0; + } +} + +/*!@brief add dma buffer into buffer descriptor ring */ +static inline int fill_dma_bd(mxc_dma_channel_t * dma, + mxc_dma_requestbuf_t * buf, int num, + mxc_dma_mode_t mode) +{ + int i, wr; + unsigned long flags, mask; + mx2_dma_priv_t *priv = dma->private; + mx2_dma_bd_t *p, *q; + + if ((atomic_read(&(priv->bd_used)) + num) > MAX_BD_SIZE) { + return -EBUSY; + } + + for (i = 0; i < num; i++) { + wr = priv->bd_wr; + p = priv->bd_ring + wr; + p->mode = mode; + p->count = buf[i].num_of_bytes; + p->src_addr = buf[i].src_addr; + p->dst_addr = buf[i].dst_addr; + if (i == num - 1) { + p->state = DMA_BD_ST_LAST | DMA_BD_ST_PEND; + } else { + p->state = DMA_BD_ST_PEND; + } + priv->bd_wr = (wr + 1) % MAX_BD_SIZE; + atomic_inc(&(priv->bd_used)); + + if (atomic_read(&(priv->bd_used)) != 2) + continue; + /* Disable interrupt of this channel */ + local_irq_save(flags); + local_irq_disable(); + save_dma_interrupt(mask); + mask_dma_interrupt(dma->channel); + local_irq_restore(flags); + /*TODO :: + * If channel is transfering and supports chain_buffer, + * when the new buffer is 2st buffer , repeat must be enabled + */ + if (priv->dma_chaining && dma->active) { + q = priv->bd_ring + priv->bd_rd; + if (q && (q->state & DMA_BD_ST_BUSY)) { + if (atomic_read(&(priv->bd_used)) == 2) { + setup_dmac(dma); + } + } + } + restore_dma_interrupt(mask); + } + return 0; +} + +/*!@brief add sg-list into buffer descriptor ring */ +static inline int fill_dma_bd_by_sg(mxc_dma_channel_t * dma, + struct scatterlist *sg, int num, + int real_bytes, mxc_dma_mode_t mode) +{ + int i, wr, total_bytes = real_bytes; + unsigned long flags, mask; + mx2_dma_priv_t *priv = dma->private; + mx2_dma_bd_t *p, *q; + if ((atomic_read(&(priv->bd_used)) + num) > MAX_BD_SIZE) { + return -EBUSY; + } + + for (i = 0; i < num && ((real_bytes <= 0) || (total_bytes > 0)); i++) { + wr = priv->bd_wr; + p = priv->bd_ring + wr; + p->mode = mode; + if (real_bytes > 0) { + if (sg[i].length >= total_bytes) { + p->count = total_bytes; + } else { + p->count = sg[i].length; + } + total_bytes -= p->count; + } else { + p->count = sg[i].length; + } + if (mode == MXC_DMA_MODE_READ) { + p->src_addr = priv->dma_info->per_address; + p->dst_addr = sg[i].dma_address; + } else { + p->dst_addr = priv->dma_info->per_address; + p->src_addr = sg[i].dma_address; + } + if ((i == num - 1) || ((real_bytes > 0) && (total_bytes == 0))) { + p->state = DMA_BD_ST_LAST | DMA_BD_ST_PEND; + } else { + p->state = DMA_BD_ST_PEND; + } + priv->bd_wr = (wr + 1) % MAX_BD_SIZE; + atomic_inc(&(priv->bd_used)); + + if (atomic_read(&(priv->bd_used)) != 2) + continue; + /* Disable interrupt of this channel */ + local_irq_save(flags); + local_irq_disable(); + save_dma_interrupt(mask); + mask_dma_interrupt(dma->channel); + local_irq_restore(flags); + /*TODO :: + * If channel is transfering and supports chain_buffer, + * when the new buffer is 2st buffer , repeat must be enabled + */ + if (priv->dma_chaining && dma->active) { + q = next_dma_bd(priv); + if (q && (q->state & DMA_BD_ST_BUSY)) { + if ((atomic_read(&(priv->bd_used))) == 2) { + setup_dmac(dma); + } + } + } + restore_dma_interrupt(mask); + } + return 0; +} + +/*!@brief select next buffer descripter to transfer. + * return 1: need call call-back function. 0: Not need call call-back. + * it just is called in ISR + */ +static inline int consume_dma_bd(mxc_dma_channel_t * dma, int error) +{ + mx2_dma_priv_t *priv = dma->private; + mx2_dma_bd_t *p; + int notify = 0; + if (priv == NULL) { + printk(KERN_ERR + "request dma channel %d which is not initialize completed.!\n", + dma->channel); + return 1; + } + if (error != MXC_DMA_DONE) { + for (p = priv->bd_ring + priv->bd_rd; + atomic_read(&(priv->bd_used)) > 0;) { + priv->bd_rd = (priv->bd_rd + 1) % MAX_BD_SIZE; + atomic_dec(&(priv->bd_used)); + if (p->state & DMA_BD_ST_LAST) { + p->state = 0; + break; + } + p->state = 0; + } + notify = 1; + } else { + p = priv->bd_ring + priv->bd_rd; + priv->bd_rd = (priv->bd_rd + 1) % MAX_BD_SIZE; + atomic_dec(&(priv->bd_used)); + notify = (p->state & DMA_BD_ST_LAST) == DMA_BD_ST_LAST; + } + if (atomic_read(&(priv->bd_used)) <= 0) { + dma->active = 0; + atomic_dec(&g_dma_actived); + } else { + setup_dmac(dma); + } + return notify; +} + +/*! + * This function is generally called by the driver at open time. + * The DMA driver would do any initialization steps that is required + * to get the channel ready for data transfer. + * + * @param channel_id a pre-defined id. The peripheral driver would specify + * the id associated with its peripheral. This would be + * used by the DMA driver to identify the peripheral + * requesting DMA and do the necessary setup on the + * channel associated with the particular peripheral. + * The DMA driver could use static or dynamic DMA channel + * allocation. + * @param dev_name module name or device name + * @return returns a negative number on error if request for a DMA channel did not + * succeed, returns the channel number to be used on success. + */ +int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name, + struct dma_channel_info *info) +{ + mxc_dma_channel_t *dma; + mx2_dma_priv_t *dma_private = NULL; + mx2_dma_info_t *dma_info = mxc_dma_get_info(channel_id); + int index; + int ret; + + if (dma_info == NULL) { + return -EINVAL; + } + + if ((index = get_dma_channel(dma_info->dma_chan)) < 0) { + return -ENODEV; + } + + dma = g_dma_channels + index; + dma_private = (mx2_dma_priv_t *) dma->private; + if (dma_private == NULL) { + printk(KERN_ERR + "request dma channel %d which is not initialize completed.!\n", + index); + ret = -EFAULT; + goto exit; + } + + dma->active = 0; + dma_private->dma_info = NULL; + dma->cb_fn = NULL; + dma->cb_args = NULL; + dma->dev_name = dev_name; + dma->mode = dma_info->mode ? MXC_DMA_MODE_WRITE : MXC_DMA_MODE_READ; + init_dma_bd(dma_private); + + if (!(ret = __init_dma_channel(dma, dma_info))) { + dma_private->dma_info = dma_info; + return index; + } + exit: + put_dma_channel(index); + return ret; +} + +/*! + * This function is generally called by the driver at close time. The DMA + * driver would do any cleanup associated with this channel. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_free(int channel_num) +{ + mxc_dma_channel_t *dma; + mx2_dma_priv_t *dma_private; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + dma = g_dma_channels + channel_num; + dma_private = (mx2_dma_priv_t *) dma->private; + if (dma_private == NULL) { + printk(KERN_ERR + "Free dma %d which is not completed initialization \n", + channel_num); + return -EFAULT; + } + if (dma->lock) { + if (dma->active) { /*Channel is busy */ + mxc_dma_disable(channel_num); + } + + dma_private = (mx2_dma_priv_t *) dma->private; + + enable_dma_clk(); + mask_dma_interrupt(channel_num); + disable_dma_clk(); + + free_irq(dma_private->dma_irq, (void *)dma); + put_dma_channel(channel_num); + } + return 0; +} + +/*! + * This function would just configure the buffers specified by the user into + * dma channel. The caller must call mxc_dma_enable to start this transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param dma_buf an array of physical addresses to the user defined + * buffers. The caller must guarantee the dma_buf is + * available until the transfer is completed. + * @param num_buf number of buffers in the array + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not be + * added with DMA for transfer. On Success, it returns 0 + */ +int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf, int num_buf, + mxc_dma_mode_t mode) +{ + mxc_dma_channel_t *dma; + mx2_dma_priv_t *dma_private; + + if ((dma_buf == NULL) || (num_buf < 1)) { + return -EINVAL; + } + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + dma = g_dma_channels + channel_num; + dma_private = (mx2_dma_priv_t *) dma->private; + if (dma_private == NULL) { + printk(KERN_ERR + "config dma %d which is not completed initialization \n", + channel_num); + return -EFAULT; + } + + if (dma->lock == 0) { + return -ENODEV; + } + + /*TODO: dma chainning can not support on bi-dir channel */ + if (dma_private->dma_chaining && (dma->mode != mode)) { + return -EINVAL; + } + + /*TODO: fill dma buffer into driver . + * If driver is no enought buffer to save them , it will return -EBUSY + */ + if (fill_dma_bd(dma, dma_buf, num_buf, mode)) { + return -EBUSY; + } + + return 0; +} + +/*! + * This function would just configure the scatterlist specified by the + * user into dma channel. This is a slight variation of mxc_dma_config(), + * it is provided for the convenience of drivers that have a scatterlist + * passed into them. It is the calling driver's responsibility to have the + * correct physical address filled in the "dma_address" field of the + * scatterlist. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param sg a scatterlist of buffers. The caller must guarantee + * the dma_buf is available until the transfer is + * completed. + * @param num_buf number of buffers in the array + * @param num_of_bytes total number of bytes to transfer. If set to 0, this + * would imply to use the length field of the scatterlist + * for each DMA transfer. Else it would calculate the size + * for each DMA transfer. + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not + * be added with DMA for transfer. On Success, it returns 0 + */ +int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, mxc_dma_mode_t mode) +{ + mxc_dma_channel_t *dma; + mx2_dma_priv_t *dma_private; + + if ((sg == NULL) || (num_buf < 1) || (num_of_bytes < 0)) { + return -EINVAL; + } + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + dma = g_dma_channels + channel_num; + dma_private = (mx2_dma_priv_t *) dma->private; + if (dma_private == NULL) { + printk(KERN_ERR + "config_sg dma %d which is not completed initialization \n", + channel_num); + return -EFAULT; + } + + if (dma->lock == 0) { + return -ENODEV; + } + + /*TODO: dma chainning can not support on bi-dir channel */ + if (dma_private->dma_chaining && (dma->mode != mode)) { + return -EINVAL; + } + + /*TODO: fill dma buffer into driver . + * If driver is no enought buffer to save them , it will return -EBUSY + */ + if (fill_dma_bd_by_sg(dma, sg, num_buf, num_of_bytes, mode)) { + return -EBUSY; + } + return 0; +} + +/*! + * This function is provided if the driver would like to set/change its + * callback function. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param callback a callback function to provide notification on transfer + * completion, user could specify NULL if he does not wish + * to be notified + * @param arg an argument that gets passed in to the callback + * function, used by the user to do any driver specific + * operations. + * @return this function returns an error if the callback could not be set + * for the channel + */ +int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback, + void *arg) +{ + mxc_dma_channel_t *dma; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + dma = g_dma_channels + channel_num; + + if (!dma->lock) { + return -ENODEV; + } + + if (dma->active) { + return -EBUSY; + } + dma->cb_fn = callback; + dma->cb_args = arg; + return 0; + +} + +/*! + * This stops the DMA channel and any ongoing transfers. Subsequent use of + * mxc_dma_enable() will restart the channel and restart the transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_disable(int channel_num) +{ + mxc_dma_channel_t *dma; + mx2_dma_priv_t *priv; + unsigned long ctrl_val; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + dma = g_dma_channels + channel_num; + + if (dma->lock == 0) { + return -EINVAL; + } + + if (!dma->active) { + return -EINVAL; + } + + priv = (mx2_dma_priv_t *) dma->private; + if (priv == NULL) { + printk(KERN_ERR "disable a uncompleted dma channel %d\n", + channel_num); + return -EFAULT; + } + + dma->active = 0; + enable_dma_clk(); + + __clear_dma_interrupt(channel_num); + ctrl_val = + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_CCR(channel_num)); + ctrl_val &= ~DMA_CTL_CEN; /* clear CEN bit */ + __raw_writel(ctrl_val, + IO_ADDRESS(DMA_BASE_ADDR) + DMA_CCR(channel_num)); + disable_dma_clk(); + atomic_dec(&g_dma_actived); + + /*TODO: Clear all request buffers */ + flush_dma_bd(priv); + return 0; +} + +/*! + * This starts DMA transfer. Or it restarts DMA on a stopped channel + * previously stopped with mxc_dma_disable(). + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_enable(int channel_num) +{ + mxc_dma_channel_t *dma; + mx2_dma_priv_t *priv; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + dma = g_dma_channels + channel_num; + + if (dma->lock == 0) { + return -EINVAL; + } + + priv = (mx2_dma_priv_t *) dma->private; + if (priv == NULL) { + printk(KERN_ERR "enable a uncompleted dma channel %d\n", + channel_num); + return -EFAULT; + } + + if (dma->active) { + return 0; + } + dma->active = 1; + priv->trans_bytes = 0; + + enable_dma_clk(); + + atomic_inc(&g_dma_actived); + __clear_dma_interrupt(channel_num); + + setup_dmac(dma); + disable_dma_clk(); + return 0; +} + +/*! +*@brief Dump DMA registers +* +*@param channel Requested channel NO. +*@return none +*/ + +void mxc_dump_dma_register(int channel) +{ + mxc_dma_channel_t *dma = &g_dma_channels[channel]; + mx2_dma_priv_t *priv = (mx2_dma_priv_t *) dma->private; + dma_regs_t *dma_base; + + printk(KERN_INFO "======== Dump dma channel %d \n", channel); + if ((unsigned)channel >= MXC_DMA_CHANNELS) { + printk(KERN_INFO "Channel number is invalid \n"); + return; + } + if (!dma->lock) { + printk(KERN_INFO "Channel is not allocated \n"); + return; + } + + printk(KERN_INFO "g_dma_actived = %d\n", atomic_read(&g_dma_actived)); + + enable_dma_clk(); + dma_base = (dma_regs_t *) (priv->dma_base); + printk(KERN_INFO "DMA COMMON REGISTER\n"); + printk(KERN_INFO "DMA CONTROL DMA_DCR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DCR)); + printk(KERN_INFO "DMA Interrupt status DMA_DISR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DISR)); + printk(KERN_INFO "DMA Interrupt Mask DMA_DIMR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DIMR)); + printk(KERN_INFO "DMA Burst Time Out DMA_DBTOSR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBTOSR)); + printk(KERN_INFO "DMA request Time Out DMA_DRTOSR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DRTOSR)); + printk(KERN_INFO "DMA Transfer Error DMA_DSESR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DSESR)); + printk(KERN_INFO "DMA DMA_Overflow DMA_DBOSR: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBOSR)); + printk(KERN_INFO "DMA Burst Time OutCtl DMA_BurstTOCtl: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_DBTOCR)); + + printk(KERN_INFO "DMA 2D X size: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_XSRA)); + printk(KERN_INFO "DMA 2D Y size: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_YSRA)); + printk(KERN_INFO "DMA 2D Z size: %08x\n", + __raw_readl(IO_ADDRESS(DMA_BASE_ADDR) + DMA_WSRA)); + + printk(KERN_INFO "DMA Chan %2d Sourc SourceAddr: %08x\n", channel, + __raw_readl(&(dma_base->SourceAddr))); + printk(KERN_INFO "DMA Chan %2d dest DestAddr: %08x\n", channel, + __raw_readl(&(dma_base->DestAddr))); + printk(KERN_INFO "DMA Chan %2d count Count: %08x\n", channel, + __raw_readl(&(dma_base->Count))); + printk(KERN_INFO "DMA Chan %2d Ctl Ctl: %08x\n", channel, + __raw_readl(&(dma_base->Ctl))); + printk(KERN_INFO "DMA Chan %2d request RequestSource: %08x\n", + channel, __raw_readl(&(dma_base->RequestSource))); + printk(KERN_INFO "DMA Chan %2d burstL BurstLength: %08x\n", channel, + __raw_readl(&(dma_base->BurstLength))); + printk(KERN_INFO "DMA Chan %2d requestTO ReqTimeout: %08x\n", channel, + __raw_readl(&(dma_base->ReqTimeout))); + printk(KERN_INFO "DMA Chan %2d BusUtilt BusUtilt: %08x\n", channel, + __raw_readl(&(dma_base->BusUtilt))); + + disable_dma_clk(); +} + +#ifdef DMA_PM + +static int channel_in_use(void) +{ + int i; + for (i = 0; i < MXC_DMA_CHANNELS; i++) { + if (dma_chan[i].lock) + return 1; + } + return 0; +} + +int mxc_dma_pm_standby(void) +{ + unsigned long reg; + if (dma_pm_status == DMA_PMST_STANDBY) + return 0; + + if (!channel_in_use()) { + /*Disable DMA */ + __disable_dma_clk(); + dma_pm_status = DMA_PMST_STANDBY; + return 0; + } + return -1; +} + +int mxc_dma_pm_resume(void) +{ + unsigned long reg; + if (dma_pm_status == DMA_PMST_RESUME) + return 0; + + /*Enable HCLK_DMA and DMA(ipg clock) */ + dma_pm_status = DMA_PMST_RESUME; + return 0; +} + +int mxc_dma_pm_suspend(void) +{ + unsigned long reg; + if (dma_pm_status == DMA_PMST_SUSPEND) + return 0; + + if (!channel_in_use()) { + /*Disable DMA */ + __disable_dma_clk(); + dma_pm_status = DMA_PMST_SUSPEND; + return 0; + } + return -1; +} + +int mxc_dma_pm_handler(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + int ret = 0; + switch (rqst) { + /*APM doesn't send PM_STANDBY and PM_STANDBY_RESUME request now. */ + case PM_SUSPEND: + ret = dma_pm_suspend(); + break; + case PM_RESUME: + ret = dma_pm_resume(); + break; + } + return ret; +} + +#endif /*DMA_PM */ + +int __init mxc_dma_init(void) +{ + int i; + mxc_dma_channel_t *dma = g_dma_channels; + mx2_dma_priv_t *private = g_dma_privates; + + memset(dma, 0, sizeof(mxc_dma_channel_t) * MXC_DMA_CHANNELS); + for (i = 0; i < MXC_DMA_CHANNELS; i++, dma++, private++) { + dma->channel = i; + dma->private = private; + private->dma_base = + (unsigned int)(IO_ADDRESS(DMA_BASE_ADDR + DMA_CH_BASE(i))); + private->dma_irq = i + MXC_DMA_INTR_0; /*Dma channel interrupt number */ + private->bd_ring = &g_dma_bd_table[i][0]; + } + + mxc_dma_load_info(g_dma_channels); + + dma_clk = clk_get(NULL, "dma_clk"); + clk_enable(dma_clk); + + __raw_writel(0x2, IO_ADDRESS(DMA_BASE_ADDR) + DMA_DCR); /*reset DMA; */ + + disable_dma_clk(); + + /*use module init because create_proc after init_dma */ + g_proc_dir = create_proc_entry("dma", 0, NULL); + g_proc_dir->read_proc = (read_proc_t *) mxc_get_dma_list; + g_proc_dir->data = NULL; + +#ifdef DMA_PM + /* Register the device with power management. */ + dma_pm = pm_register(PM_DMA_DEV, PM_SYS_UNKNOWN, dma_pm_handler); +#endif + + return 0; +} + +arch_initcall(mxc_dma_init); + +EXPORT_SYMBOL(mxc_dma_request_ext); +EXPORT_SYMBOL(mxc_dma_free); +EXPORT_SYMBOL(mxc_dma_callback_set); +EXPORT_SYMBOL(mxc_dma_enable); +EXPORT_SYMBOL(mxc_dma_disable); +EXPORT_SYMBOL(mxc_dma_config); +EXPORT_SYMBOL(mxc_dma_sg_config); +EXPORT_SYMBOL(mxc_dump_dma_register); diff --git a/arch/arm/plat-mxc/dptc.c b/arch/arm/plat-mxc/dptc.c new file mode 100644 index 000000000000..6b7f5599909e --- /dev/null +++ b/arch/arm/plat-mxc/dptc.c @@ -0,0 +1,621 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file dptc.c + * + * @brief Driver for the Freescale Semiconductor MXC DPTC module. + * + * The DPTC driver is designed to control the MXC DPTC hardware. + * hardware. Upon initialization, the DPTC driver initializes the DPTC hardware + * sets up driver nodes attaches to the DPTC interrupt and initializes internal + * data structures. When the DPTC interrupt occurs the driver checks the cause + * of the interrupt (lower frequency, increase frequency or emergency) and changes + * the CPU voltage according to translation table that is loaded into the driver. + * The driver read method is used to read the log buffer. + * Driver ioctls are used to change driver parameters and enable/disable the + * DVFS operation. + * + * @ingroup PM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +enum { + DPTC_PTVAI_NOCHANGE = 0x0, + DPTC_PTVAI_DECREASE, + DPTC_PTVAI_INCREASE, + DPTC_PTVAI_EMERG, +}; + +struct device *dev_data0; +struct device *dev_data1; + +/*! + * In case the MXC device has multiple DPTC modules, this structure is used to + * store information specific to each DPTC module. + */ +struct dptc_device { + /* DPTC delayed work */ + struct delayed_work dptc_work; + /* DPTC spinlock */ + spinlock_t lock; + /* DPTC regulator */ + struct regulator *dptc_reg; + /* DPTC clock */ + struct clk *dptc_clk; + /* DPTC is active flag */ + int dptc_is_active; + /* turbo mode active flag */ + int turbo_mode_active; + /* DPTC current working point */ + int curr_wp; + /* DPTC vai bits */ + u32 ptvai; + /* The interrupt number used by the DPTC device */ + int irq; + /* DPTC platform data pointer */ + struct mxc_dptc_data *dptc_platform_data; +}; + +static void update_dptc_wp(struct dptc_device *drv_data, u32 wp) +{ + struct mxc_dptc_data *dptc_data = drv_data->dptc_platform_data; + int voltage_uV; + int ret = 0; + + voltage_uV = dptc_data->dptc_wp_allfreq[wp].voltage * 1000; + + __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr0, + dptc_data->dcvr0_reg_addr); + __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr1, + dptc_data->dcvr0_reg_addr + 0x4); + __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr2, + dptc_data->dcvr0_reg_addr + 0x8); + __raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr3, + dptc_data->dcvr0_reg_addr + 0xC); + + /* Set the voltage */ + ret = regulator_set_voltage(drv_data->dptc_reg, voltage_uV, voltage_uV); + if (ret < 0) + printk(KERN_DEBUG "COULD NOT SET VOLTAGE!!!!!\n"); + + pr_debug("dcvr0-3: 0x%x, 0x%x, 0x%x, 0x%x; vol: %d\n", + dptc_data->dptc_wp_allfreq[wp].dcvr0, + dptc_data->dptc_wp_allfreq[wp].dcvr1, + dptc_data->dptc_wp_allfreq[wp].dcvr2, + dptc_data->dptc_wp_allfreq[wp].dcvr3, + dptc_data->dptc_wp_allfreq[wp].voltage); +} + +static irqreturn_t dptc_irq(int irq, void *dev_id) +{ + struct device *dev = dev_id; + struct dptc_device *drv_data = dev->driver_data; + struct mxc_dptc_data *dptc_data = dev->platform_data; + u32 dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + u32 gpc_cntr = __raw_readl(dptc_data->gpc_cntr_reg_addr); + + gpc_cntr = (gpc_cntr & dptc_data->dptccr); + + if (gpc_cntr) { + drv_data->ptvai = + (dptccr & dptc_data->vai_mask) >> dptc_data->vai_offset; + pr_debug("dptc_irq: vai = 0x%x (0x%x)!!!!!!!\n", + drv_data->ptvai, dptccr); + + /* disable DPTC and mask its interrupt */ + dptccr = (dptccr & ~(dptc_data->dptc_enable_bit)) | + (dptc_data->irq_mask); + dptccr = (dptccr & ~(dptc_data->dptc_nvcr_bit)); + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + + if (drv_data->turbo_mode_active == 1) + schedule_delayed_work(&drv_data->dptc_work, 0); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static void dptc_workqueue_handler(struct work_struct *work1) +{ + struct delayed_work *dptc_work_tmp = + container_of(work1, struct delayed_work, work); + struct dptc_device *drv_data = + container_of(dptc_work_tmp, struct dptc_device, dptc_work); + struct mxc_dptc_data *dptc_data = drv_data->dptc_platform_data; + u32 dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + + switch (drv_data->ptvai) { + case DPTC_PTVAI_DECREASE: + drv_data->curr_wp++; + break; + case DPTC_PTVAI_INCREASE: + case DPTC_PTVAI_EMERG: + drv_data->curr_wp--; + if (drv_data->curr_wp < 0) { + /* already max voltage */ + drv_data->curr_wp = 0; + printk(KERN_WARNING "dptc: already maximum voltage\n"); + } + break; + + /* Unknown interrupt cause */ + default: + BUG(); + } + + if (drv_data->curr_wp > dptc_data->dptc_wp_supported + || drv_data->curr_wp < 0) { + panic("Can't support this working point: %d\n", + drv_data->curr_wp); + } + update_dptc_wp(drv_data, drv_data->curr_wp); + + /* Enable DPTC and unmask its interrupt */ + dptccr = (dptccr & ~(dptc_data->irq_mask)) | + dptc_data->dptc_nvcr_bit | dptc_data->dptc_enable_bit; + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); +} + +/* Start DPTC unconditionally */ +static int start_dptc(struct device *dev) +{ + struct mxc_dptc_data *dptc_data = dev->platform_data; + struct dptc_device *drv_data = dev->driver_data; + u32 dptccr; + unsigned long flags; + unsigned long clk_rate; + int voltage_uV; + + /* Get the voltage */ + voltage_uV = regulator_get_voltage(drv_data->dptc_reg); + drv_data->curr_wp = + (dptc_data->dptc_wp_allfreq[0].voltage - (voltage_uV / 1000)) / 25; + + update_dptc_wp(drv_data, drv_data->curr_wp); + + /* Set the voltage */ + spin_lock_irqsave(&drv_data->lock, flags); + + clk_rate = clk_get_rate(drv_data->dptc_clk); + + if (clk_rate < dptc_data->clk_max_val) + goto err; + + if (dptc_data->gpc_irq_bit != 0x0) { + /* Enable ARM domain frequency and/or voltage update needed + and enable ARM IRQ */ + __raw_writel(dptc_data->gpc_irq_bit | dptc_data->gpc_adu, + dptc_data->gpc_cntr_reg_addr); + } + + dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + + /* Enable DPTC and unmask its interrupt */ + dptccr = ((dptccr & ~(dptc_data->irq_mask)) | dptc_data->enable_config); + + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + + spin_unlock_irqrestore(&drv_data->lock, flags); + + drv_data->dptc_is_active = 1; + drv_data->turbo_mode_active = 1; + + pr_info("DPTC has been started \n"); + + return 0; + +err: + spin_unlock_irqrestore(&drv_data->lock, flags); + pr_info("DPTC is not enabled\n"); + return -1; +} + +/* Stop DPTC unconditionally */ +static void stop_dptc(struct device *dev) +{ + struct mxc_dptc_data *dptc_data = dev->platform_data; + struct dptc_device *drv_data = dev->driver_data; + u32 dptccr; + + dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + + /* disable DPTC and mask its interrupt */ + dptccr = ((dptccr & ~(dptc_data->dptc_enable_bit)) | + dptc_data->irq_mask) & (~dptc_data->dptc_nvcr_bit); + + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + + /* Restore Turbo Mode voltage to highest wp */ + update_dptc_wp(drv_data, 0); + drv_data->curr_wp = 0; + + regulator_put(drv_data->dptc_reg); + + pr_info("DPTC has been stopped\n"); +} + +/* + This function does not change the working point. It can be + called from an interrupt context. +*/ +void dptc_suspend(int id) +{ + struct mxc_dptc_data *dptc_data; + struct dptc_device *drv_data; + u32 dptccr; + + switch (id) { + case DPTC_GP_ID: + dptc_data = dev_data0->platform_data; + drv_data = dev_data0->driver_data; + break; + case DPTC_LP_ID: + if (dev_data1 == NULL) + return; + + dptc_data = dev_data1->platform_data; + drv_data = dev_data1->driver_data; + break; + /* Unknown DPTC ID */ + default: + return; + } + + if (!drv_data->dptc_is_active) + return; + + dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + + /* Disable DPTC and mask its interrupt */ + dptccr = (dptccr & ~(dptc_data->dptc_enable_bit)) | dptc_data->irq_mask; + + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); +} +EXPORT_SYMBOL(dptc_suspend); + +/* + This function does not change the working point. It can be + called from an interrupt context. +*/ +void dptc_resume(int id) +{ + struct mxc_dptc_data *dptc_data; + struct dptc_device *drv_data; + u32 dptccr; + + switch (id) { + case DPTC_GP_ID: + dptc_data = dev_data0->platform_data; + drv_data = dev_data0->driver_data; + break; + case DPTC_LP_ID: + if (dev_data1 == NULL) + return; + + dptc_data = dev_data1->platform_data; + drv_data = dev_data1->driver_data; + break; + /* Unknown DPTC ID */ + default: + return; + } + + if (!drv_data->dptc_is_active) + return; + + __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr0, + dptc_data->dcvr0_reg_addr); + __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr1, + dptc_data->dcvr0_reg_addr + 0x4); + __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr2, + dptc_data->dcvr0_reg_addr + 0x8); + __raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr3, + dptc_data->dcvr0_reg_addr + 0xC); + + dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + + /* Enable DPTC and unmask its interrupt */ + dptccr = (dptccr & ~(dptc_data->irq_mask)) | dptc_data->dptc_enable_bit; + + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); +} +EXPORT_SYMBOL(dptc_resume); + +/*! + * This function is called to put the DPTC in a low power state. + * + */ +void dptc_disable(struct device *dev) +{ + struct dptc_device *drv_data = dev->driver_data; + + if (!(drv_data->dptc_is_active)) + return; + + stop_dptc(dev); + drv_data->dptc_is_active = 0; + drv_data->turbo_mode_active = 0; +} + +/*! + * This function is called to resume the DPTC from a low power state. + * + */ +int dptc_enable(struct device *dev) +{ + struct dptc_device *drv_data = dev->driver_data; + + if (drv_data->dptc_is_active) + return 0; + + return start_dptc(dev); +} + +static ssize_t dptc_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dptc_device *drv_data = dev->driver_data; + + if (drv_data->dptc_is_active) + return sprintf(buf, "DPTC is enabled\n"); + else + return sprintf(buf, "DPTC is disabled\n"); +} + +static ssize_t dptc_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + if (strstr(buf, "0") != NULL) { + dptc_disable(dev); + } else if (strstr(buf, "1") != NULL) { + dptc_enable(dev); + } + + return size; +} + +static DEVICE_ATTR(enable, 0644, dptc_show, dptc_store); + +/*! + * This is the probe routine for the DPTC driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ +static int __devinit mxc_dptc_probe(struct platform_device *pdev) +{ + struct dptc_device *dptc_device_data; + int ret = 0; + struct resource *res; + u32 dptccr = 0; + struct clk *ckih_clk; + struct mxc_dptc_data *dptc_data = pdev->dev.platform_data; + + if (dptc_data == NULL) { + printk(KERN_ERR "DPTC: Pointer to DPTC data is NULL\ + not started\n"); + return -1; + } + + dptc_device_data = kzalloc(sizeof(struct dptc_device), GFP_KERNEL); + if (!dptc_device_data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + ret = -ENODEV; + goto err1; + } + + /* + * Request the DPTC interrupt + */ + dptc_device_data->irq = platform_get_irq(pdev, 0); + if (dptc_device_data->irq < 0) { + ret = dptc_device_data->irq; + goto err1; + } + + ret = + request_irq(dptc_device_data->irq, dptc_irq, IRQF_SHARED, + pdev->name, &pdev->dev); + if (ret) { + printk(KERN_ERR "DPTC: Unable to attach to DPTC interrupt\n"); + goto err1; + } + + dptc_device_data->curr_wp = 0; + dptc_device_data->dptc_is_active = 0; + dptc_device_data->turbo_mode_active = 0; + dptc_device_data->ptvai = 0; + + dptccr = __raw_readl(dptc_data->dptccr_reg_addr); + + printk(KERN_INFO "DPTC mxc_dptc_probe()\n"); + + spin_lock_init(&dptc_device_data->lock); + + if (dptc_data->dptc_wp_allfreq == NULL) { + ckih_clk = clk_get(NULL, "ckih"); + if (cpu_is_mx31() & + (mxc_cpu_is_rev(CHIP_REV_2_0) < 0) & + (clk_get_rate(ckih_clk) == 27000000)) + printk(KERN_ERR "DPTC: DPTC not supported on TO1.x \ + & ckih = 27M\n"); + else + printk(KERN_ERR "DPTC: Pointer to DPTC table is NULL\ + not started\n"); + goto err1; + } + + dptc_device_data->dptc_reg = regulator_get(NULL, dptc_data->reg_id); + if (IS_ERR(dptc_device_data->dptc_reg)) { + clk_put(dptc_device_data->dptc_clk); + printk(KERN_ERR "%s: failed to get regulator\n", __func__); + goto err1; + } + + INIT_DELAYED_WORK(&dptc_device_data->dptc_work, dptc_workqueue_handler); + + /* Enable Reference Circuits */ + dptccr = (dptccr & ~(dptc_data->dcr_mask)) | dptc_data->init_config; + __raw_writel(dptccr, dptc_data->dptccr_reg_addr); + + ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_enable.attr); + if (ret) { + printk(KERN_ERR + "DPTC: Unable to register sysdev entry for dptc"); + goto err1; + } + + if (ret != 0) { + printk(KERN_ERR "DPTC: Unable to start"); + goto err1; + } + + dptc_device_data->dptc_clk = clk_get(NULL, dptc_data->clk_id); + + if (pdev->id == 0) + dev_data0 = &pdev->dev; + else + dev_data1 = &pdev->dev; + + dptc_device_data->dptc_platform_data = pdev->dev.platform_data; + + /* Set driver data */ + platform_set_drvdata(pdev, dptc_device_data); + + return 0; + +err1: + dev_err(&pdev->dev, "Failed to probe DPTC\n"); + kfree(dptc_device_data); + return ret; +} + +/*! + * This function is called to put DPTC in a low power state. + * + * @param pdev the device structure + * @param state the power state the device is entering + * + * @return The function always returns 0. + */ +static int mxc_dptc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dptc_device *drv_data = pdev->dev.driver_data; + + if (drv_data->dptc_is_active) + stop_dptc(&pdev->dev); + + return 0; +} + +/*! + * This function is called to resume the MU from a low power state. + * + * @param dev the device structure + * @param level the stage in device suspension process that we want the + * device to be put in + * + * @return The function always returns 0. + */ +static int mxc_dptc_resume(struct platform_device *pdev) +{ + struct dptc_device *drv_data = pdev->dev.driver_data; + + if (drv_data->dptc_is_active) + return start_dptc(&pdev->dev); + + return 0; +} + +static struct platform_driver mxc_dptc_driver = { + .driver = { + .name = "mxc_dptc", + .owner = THIS_MODULE, + }, + .probe = mxc_dptc_probe, + .suspend = mxc_dptc_suspend, + .resume = mxc_dptc_resume, +}; + +/*! + * This function is called to resume the MU from a low power state. + * + * @param dev the device structure used to give information on which MU + * device (0 through 3 channels) to suspend + * @param level the stage in device suspension process that we want the + * device to be put in + * + * @return The function always returns 0. + */ + +static int __init dptc_init(void) +{ + if (platform_driver_register(&mxc_dptc_driver) != 0) { + printk(KERN_ERR "mxc_dptc_driver register failed\n"); + return -ENODEV; + } + + printk(KERN_INFO "DPTC driver module loaded\n"); + + return 0; +} + +static void __exit dptc_cleanup(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&mxc_dptc_driver); + + printk("DPTC driver module unloaded\n"); +} + +module_init(dptc_init); +module_exit(dptc_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("DPTC driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c new file mode 100644 index 000000000000..d14bac145344 --- /dev/null +++ b/arch/arm/plat-mxc/dvfs_core.c @@ -0,0 +1,802 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file dvfs_core.c + * + * @brief A simplied driver for the Freescale Semiconductor MXC DVFS module. + * + * Upon initialization, the DVFS driver initializes the DVFS hardware + * sets up driver nodes attaches to the DVFS interrupt and initializes internal + * data structures. When the DVFS interrupt occurs the driver checks the cause + * of the interrupt (lower frequency, increase frequency or emergency) and + * changes the CPU voltage according to translation table that is loaded into + * the driver. + * + * @ingroup PM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MXC_DVFSTHRS_UPTHR_MASK 0x0FC00000 +#define MXC_DVFSTHRS_UPTHR_OFFSET 22 +#define MXC_DVFSTHRS_DNTHR_MASK 0x003F0000 +#define MXC_DVFSTHRS_DNTHR_OFFSET 16 +#define MXC_DVFSTHRS_PNCTHR_MASK 0x0000003F +#define MXC_DVFSTHRS_PNCTHR_OFFSET 0 + +#define MXC_DVFSCOUN_DNCNT_MASK 0x00FF0000 +#define MXC_DVFSCOUN_DNCNT_OFFSET 16 +#define MXC_DVFSCOUN_UPCNT_MASK 0x000000FF +#define MXC_DVFSCOUN_UPCNT_OFFSET 0 + +#define MXC_DVFSEMAC_EMAC_MASK 0x000001FF +#define MXC_DVFSEMAC_EMAC_OFFSET 0 + +#define MXC_DVFSCNTR_DVFEV 0x10000000 +#define MXC_DVFSCNTR_LBMI 0x08000000 +#define MXC_DVFSCNTR_LBFL 0x06000000 +#define MXC_DVFSCNTR_DVFIS 0x01000000 +#define MXC_DVFSCNTR_FSVAIM 0x00400000 +#define MXC_DVFSCNTR_FSVAI_MASK 0x00300000 +#define MXC_DVFSCNTR_FSVAI_OFFSET 20 +#define MXC_DVFSCNTR_WFIM 0x00080000 +#define MXC_DVFSCNTR_WFIM_OFFSET 19 +#define MXC_DVFSCNTR_MAXF_MASK 0x00040000 +#define MXC_DVFSCNTR_MAXF_OFFSET 18 +#define MXC_DVFSCNTR_MINF_MASK 0x00020000 +#define MXC_DVFSCNTR_MINF_OFFSET 17 +#define MXC_DVFSCNTR_LTBRSR_MASK 0x00000018 +#define MXC_DVFSCNTR_LTBRSR_OFFSET 3 +#define MXC_DVFSCNTR_DVFEN 0x00000001 + +#define MXC_GPCCNTR_GPCIRQ 0x00100000 +#define MXC_GPCCNTR_DVFS0CR 0x00010000 +#define MXC_GPCCNTR_ADU 0x00008000 +#define MXC_GPCCNTR_STRT 0x00004000 +#define MXC_GPCCNTR_FUPD 0x00002000 +#define MXC_GPCCNTR_HTRI_MASK 0x0000000F +#define MXC_GPCCNTR_HTRI_OFFSET 0 +#define MXC_GPCCNTR_GPCIRQM 0x00200000 + +#define MXC_GPCVCR_VINC_MASK 0x00020000 +#define MXC_GPCVCR_VINC_OFFSET 17 +#define MXC_GPCVCR_VCNTU_MASK 0x00010000 +#define MXC_GPCVCR_VCNTU_OFFSET 16 +#define MXC_GPCVCR_VCNT_MASK 0x00007FFF +#define MXC_GPCVCR_VCNT_OFFSET 0 + +extern void setup_pll(void); +static struct delayed_work dvfs_core_work; +static struct mxc_dvfs_platform_data *dvfs_data; +static struct device *dvfs_dev; +static struct cpu_wp *cpu_wp_tbl; +int dvfs_core_resume; +int curr_wp; +int old_wp; +int dvfs_core_is_active; +int cpufreq_trig_needed; +struct timeval core_prev_intr; + +/* + * Clock structures + */ +static struct clk *pll1_sw_clk; +static struct clk *cpu_clk; +static struct clk *dvfs_clk; +static struct regulator *core_regulator; + +extern int cpu_wp_nr; +#ifdef CONFIG_ARCH_MX51 +extern struct cpu_wp *(*get_cpu_wp)(int *wp); +#endif + +enum { + FSVAI_FREQ_NOCHANGE = 0x0, + FSVAI_FREQ_INCREASE, + FSVAI_FREQ_DECREASE, + FSVAI_FREQ_EMERG, +}; + +/* + * Load tracking buffer source: 1 for ld_add; 0 for pre_ld_add; 2 for after EMA + */ +#define DVFS_LTBRSR (2 << MXC_DVFSCNTR_LTBRSR_OFFSET) + +extern struct dvfs_wp dvfs_core_setpoint[2]; +extern int low_bus_freq_mode; +extern int high_bus_freq_mode; +extern int set_low_bus_freq(void); +extern int set_high_bus_freq(int high_bus_speed); +extern int low_freq_bus_used(void); +extern void propagate_rate(struct clk *tclk); + +DEFINE_SPINLOCK(mxc_dvfs_core_lock); + +void dvfs_core_set_bus_freq(void) +{ + u32 reg; + int low_freq_bus_ready = 0; + + /* Mask DVFS irq */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + /* FSVAIM=1 */ + reg |= MXC_DVFSCNTR_FSVAIM; + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + + low_freq_bus_ready = low_freq_bus_used(); + + if ((curr_wp == cpu_wp_nr - 1) && (!low_bus_freq_mode) + && (low_freq_bus_ready)) + set_low_bus_freq(); + else if (!low_freq_bus_ready) + set_high_bus_freq(0); + /* Enable DVFS interrupt */ + /* FSVAIM=0 */ + reg = (reg & ~MXC_DVFSCNTR_FSVAIM); + /* LBFL=1 */ + reg = (reg & ~MXC_DVFSCNTR_LBFL); + reg |= MXC_DVFSCNTR_LBFL; + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); +} + +static void dvfs_load_config(int set_point) +{ + u32 reg; + reg = 0; + + reg |= dvfs_core_setpoint[set_point].upthr << MXC_DVFSTHRS_UPTHR_OFFSET; + reg |= dvfs_core_setpoint[set_point].downthr << + MXC_DVFSTHRS_DNTHR_OFFSET; + reg |= dvfs_core_setpoint[set_point].panicthr; + __raw_writel(reg, dvfs_data->dvfs_thrs_reg_addr); + + reg = 0; + reg |= dvfs_core_setpoint[set_point].downcnt << + MXC_DVFSCOUN_DNCNT_OFFSET; + reg |= dvfs_core_setpoint[set_point].upcnt << MXC_DVFSCOUN_UPCNT_OFFSET; + __raw_writel(reg, dvfs_data->dvfs_coun_reg_addr); +} + +static int set_cpu_freq(int wp) +{ + int arm_podf; + int podf; + int vinc = 0; + int ret = 0; + int org_cpu_rate; + unsigned long rate = 0; + int gp_volt = 0; + u32 reg; + u32 reg1; + + if (cpu_wp_tbl[wp].pll_rate != cpu_wp_tbl[old_wp].pll_rate) { + /* PLL_RELOCK, set ARM_FREQ_SHIFT_DIVIDER */ + reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr); + reg &= 0xFFFFFFFB; + __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr); + org_cpu_rate = clk_get_rate(cpu_clk); + rate = cpu_wp_tbl[wp].cpu_rate; + + if (org_cpu_rate == rate) + return ret; + + gp_volt = cpu_wp_tbl[wp].cpu_voltage; + + if (gp_volt == 0) + return ret; + + /*Set the voltage for the GP domain. */ + if (rate > org_cpu_rate) { + ret = regulator_set_voltage(core_regulator, gp_volt, + gp_volt); + if (ret < 0) { + printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE\n"); + return ret; + } + udelay(dvfs_data->delay_time); + } + + setup_pll(); + /* START the GPC main control FSM */ + /* set VINC */ + reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr); + reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK | + MXC_GPCVCR_VCNT_MASK); + + if (rate > org_cpu_rate) + reg |= 1 << MXC_GPCVCR_VINC_OFFSET; + + reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) | + (100 << MXC_GPCVCR_VCNT_OFFSET); + __raw_writel(reg, dvfs_data->gpc_vcr_reg_addr); + + reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg |= MXC_GPCCNTR_FUPD; + reg |= MXC_GPCCNTR_ADU; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + + reg |= MXC_GPCCNTR_STRT; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + while (__raw_readl(dvfs_data->gpc_cntr_reg_addr) & 0x4000) + udelay(10); + + if (rate < org_cpu_rate) { + ret = regulator_set_voltage(core_regulator, + gp_volt, gp_volt); + if (ret < 0) { + printk(KERN_DEBUG + "COULD NOT SET GP VOLTAGE!!!!\n"); + return ret; + } + old_wp = wp; + } + + clk_set_rate(cpu_clk, rate); + } else { + podf = cpu_wp_tbl[wp].cpu_podf; + gp_volt = cpu_wp_tbl[wp].cpu_voltage; + + /* Change arm_podf only */ + /* set ARM_FREQ_SHIFT_DIVIDER */ + reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr); + reg &= 0xFFFFFFFB; + reg |= 1 << 2; + __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr); + + /* Get ARM_PODF */ + reg = __raw_readl(dvfs_data->ccm_cacrr_reg_addr); + arm_podf = reg & 0x07; + if (podf == arm_podf) { + printk(KERN_DEBUG + "No need to change freq and voltage!!!!\n"); + return 0; + } + + /* Check if FSVAI indicate freq up */ + if (podf < arm_podf) { + ret = regulator_set_voltage(core_regulator, + gp_volt, gp_volt); + if (ret < 0) { + printk(KERN_DEBUG + "COULD NOT SET GP VOLTAGE!!!!\n"); + return 0; + } + udelay(dvfs_data->delay_time); + vinc = 1; + dvfs_load_config(0); + } else { + vinc = 0; + dvfs_load_config(1); + } + + arm_podf = podf; + /* Set ARM_PODF */ + reg &= 0xFFFFFFF8; + reg |= arm_podf; + + reg1 = __raw_readl(dvfs_data->ccm_cdhipr_reg_addr); + if ((reg1 & 0x00010000) == 0) + __raw_writel(reg, dvfs_data->ccm_cacrr_reg_addr); + else { + printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n"); + return 0; + } + + /* START the GPC main control FSM */ + reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg |= MXC_GPCCNTR_FUPD; + /* ADU=1, select ARM domain */ + reg |= MXC_GPCCNTR_ADU; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + /* set VINC */ + reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr); + reg &= + ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK | + MXC_GPCVCR_VCNT_MASK); + reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) | + (100 << MXC_GPCVCR_VCNT_OFFSET) | + (vinc << MXC_GPCVCR_VINC_OFFSET); + __raw_writel(reg, dvfs_data->gpc_vcr_reg_addr); + + reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg &= (~(MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD)); + reg |= MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD | MXC_GPCCNTR_STRT; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + + /* Wait for arm podf Enable */ + while ((__raw_readl(dvfs_data->gpc_cntr_reg_addr) & + MXC_GPCCNTR_STRT) == MXC_GPCCNTR_STRT) { + printk(KERN_DEBUG "Waiting arm_podf enabled!\n"); + udelay(10); + } + + if (vinc == 0) { + ret = regulator_set_voltage(core_regulator, + gp_volt, gp_volt); + if (ret < 0) { + printk(KERN_DEBUG + "COULD NOT SET GP VOLTAGE!!!!\n"); + return ret; + } + udelay(dvfs_data->delay_time); + } + + propagate_rate(pll1_sw_clk); +#if defined(CONFIG_CPU_FREQ) + cpufreq_trig_needed = 1; +#endif + old_wp = wp; + } + + return ret; +} + +static int start_dvfs(void) +{ + u32 reg; + unsigned long flags; + + if (dvfs_core_is_active) + return 0; + + spin_lock_irqsave(&mxc_dvfs_core_lock, flags); + + clk_enable(dvfs_clk); + + /* config reg GPC_CNTR */ + reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + + /* GPCIRQ=1, select ARM IRQ */ + reg |= MXC_GPCCNTR_GPCIRQ; + /* ADU=1, select ARM domain */ + reg |= MXC_GPCCNTR_ADU; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + + /* Set PREDIV bits */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = (reg & ~(dvfs_data->prediv_mask)); + reg |= (dvfs_data->prediv_val) << (dvfs_data->prediv_offset); + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + + /* Enable DVFS interrupt */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + /* FSVAIM=0 */ + reg = (reg & ~MXC_DVFSCNTR_FSVAIM); + /* Set MAXF, MINF */ + reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); + reg |= 1 << MXC_DVFSCNTR_MAXF_OFFSET; + /* Select ARM domain */ + reg |= MXC_DVFSCNTR_DVFIS; + /* Enable DVFS frequency adjustment interrupt */ + reg = (reg & ~MXC_DVFSCNTR_FSVAIM); + /* Set load tracking buffer register source */ + reg = (reg & ~MXC_DVFSCNTR_LTBRSR_MASK); + reg |= DVFS_LTBRSR; + /* Set DIV3CK */ + reg = (reg & ~(dvfs_data->div3ck_mask)); + reg |= (dvfs_data->div3ck_val) << (dvfs_data->div3ck_offset); + /* Enable DVFS */ + reg |= MXC_DVFSCNTR_DVFEN; + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + + dvfs_core_is_active = 1; + + spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); + + printk(KERN_DEBUG "DVFS is started\n"); + + return 0; +} + +/*! + * This function is called for module initialization. + * It sets up the DVFS hardware. + * It sets default values for DVFS thresholds and counters. The default + * values was chosen from a set of different reasonable values. They was tested + * and the default values in the driver gave the best results. + * More work should be done to find optimal values. + * + * @return 0 if successful; non-zero otherwise. + * + */ +static int init_dvfs_controller(void) +{ + /* DVFS loading config */ + dvfs_load_config(0); + + /* Set EMAC value */ + __raw_writel((dvfs_data->emac_val << MXC_DVFSEMAC_EMAC_OFFSET), + dvfs_data->dvfs_emac_reg_addr); + + return 0; +} + +static irqreturn_t dvfs_irq(int irq, void *dev_id) +{ + u32 reg; + + /* Check if DVFS0 (ARM) id requesting for freqency/voltage update */ + if ((__raw_readl(dvfs_data->gpc_cntr_reg_addr) & MXC_GPCCNTR_DVFS0CR) == + 0) + return IRQ_NONE; + + /* Mask DVFS irq */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + /* FSVAIM=1 */ + reg |= MXC_DVFSCNTR_FSVAIM; + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + + /* Mask GPC1 irq */ + reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg |= MXC_GPCCNTR_GPCIRQM | 0x1000000; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); + + schedule_delayed_work(&dvfs_core_work, 0); + + return IRQ_HANDLED; +} + +static void dvfs_core_workqueue_handler(struct work_struct *work) +{ + u32 fsvai; + u32 reg; + u32 curr_cpu; + int ret = 0; + int maxf = 0, minf = 0; + int low_freq_bus_ready = 0; + + /* Check DVFS frequency adjustment interrupt status */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + fsvai = (reg & MXC_DVFSCNTR_FSVAI_MASK) >> MXC_DVFSCNTR_FSVAI_OFFSET; + + /* Check FSVAI, FSVAI=0 is error */ + if (fsvai == FSVAI_FREQ_NOCHANGE) { + /* Do nothing. Freq change is not required */ + goto END; + } + + curr_cpu = clk_get_rate(cpu_clk); + + /* If FSVAI indicate freq down, + check arm-clk is not in lowest frequency 200 MHz */ + if (fsvai == FSVAI_FREQ_DECREASE) { + if (curr_cpu == cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) { + minf = 1; + goto END; + } else { + /* freq down */ + curr_wp++; + if (curr_wp >= cpu_wp_nr) { + curr_wp = cpu_wp_nr - 1; + goto END; + } + + if (curr_wp == cpu_wp_nr - 1) + minf = 1; + } + } else { + if (curr_cpu == cpu_wp_tbl[0].cpu_rate) { + maxf = 1; + goto END; + } else { + /* freq up */ + curr_wp = 0; + maxf = 1; + } + } + + low_freq_bus_ready = low_freq_bus_used(); + if ((curr_wp == cpu_wp_nr - 1) && (!low_bus_freq_mode) + && (low_freq_bus_ready)) { + ret = set_cpu_freq(curr_wp); + set_low_bus_freq(); + } else { + set_high_bus_freq(0); + ret = set_cpu_freq(curr_wp); + } + +#if defined(CONFIG_CPU_FREQ) + if (cpufreq_trig_needed == 1) { + cpufreq_trig_needed = 0; + cpufreq_update_policy(0); + } +#endif + +END: /* Set MAXF, MINF */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); + reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET; + reg |= minf << MXC_DVFSCNTR_MINF_OFFSET; + + /* Enable DVFS interrupt */ + /* FSVAIM=0 */ + reg = (reg & ~MXC_DVFSCNTR_FSVAIM); + reg |= FSVAI_FREQ_NOCHANGE; + /* LBFL=1 */ + reg = (reg & ~MXC_DVFSCNTR_LBFL); + reg |= MXC_DVFSCNTR_LBFL; + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + /*Unmask GPC1 IRQ */ + reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); + reg &= ~MXC_GPCCNTR_GPCIRQM; + __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); +} + +/*! + * This function disables the DVFS module. + */ +static void stop_dvfs(void) +{ + u32 reg = 0; + unsigned long flags; + u32 curr_cpu; + + if (dvfs_core_is_active) { + spin_lock_irqsave(&mxc_dvfs_core_lock, flags); + + /* Mask dvfs irq, disable DVFS */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + /* FSVAIM=1 */ + reg |= MXC_DVFSCNTR_FSVAIM; + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); + + dvfs_core_is_active = 0; + spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); + + curr_wp = 0; + if (!high_bus_freq_mode) + set_high_bus_freq(1); + + curr_cpu = clk_get_rate(cpu_clk); + if (curr_cpu != cpu_wp_tbl[curr_wp].cpu_rate) { + set_cpu_freq(curr_wp); + /* disable DVFS */ + reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr); + reg = (reg & ~MXC_DVFSCNTR_DVFEN); + __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr); +#if defined(CONFIG_CPU_FREQ) + if (cpufreq_trig_needed == 1) { + cpufreq_trig_needed = 0; + cpufreq_update_policy(0); + } +#endif + } + + clk_disable(dvfs_clk); + } + + printk(KERN_DEBUG "DVFS is stopped\n"); +} + +static ssize_t dvfs_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (dvfs_core_is_active) + return sprintf(buf, "DVFS is enabled\n"); + else + return sprintf(buf, "DVFS is disabled\n"); +} + +static ssize_t dvfs_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + if (strstr(buf, "1") != NULL) { + if (start_dvfs() != 0) + printk(KERN_ERR "Failed to start DVFS\n"); + } else if (strstr(buf, "0") != NULL) + stop_dvfs(); + + return size; +} + +static DEVICE_ATTR(enable, 0644, dvfs_enable_show, dvfs_enable_store); + +/*! + * This is the probe routine for the DVFS driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + */ +static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) +{ + int err = 0; + struct resource *res; + int irq; + + printk(KERN_INFO "mxc_dvfs_core_probe\n"); + dvfs_dev = &pdev->dev; + dvfs_data = pdev->dev.platform_data; + + INIT_DELAYED_WORK(&dvfs_core_work, dvfs_core_workqueue_handler); + + pll1_sw_clk = clk_get(NULL, "pll1_sw_clk"); + if (IS_ERR(pll1_sw_clk)) { + printk(KERN_INFO "%s: failed to get pll1_sw_clk\n", __func__); + return PTR_ERR(pll1_sw_clk); + } + + cpu_clk = clk_get(NULL, dvfs_data->clk1_id); + if (IS_ERR(cpu_clk)) { + printk(KERN_ERR "%s: failed to get cpu clock\n", __func__); + return PTR_ERR(cpu_clk); + } + + dvfs_clk = clk_get(NULL, dvfs_data->clk2_id); + if (IS_ERR(dvfs_clk)) { + printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__); + return PTR_ERR(dvfs_clk); + } + + core_regulator = regulator_get(NULL, dvfs_data->reg_id); + if (IS_ERR(core_regulator)) { + clk_put(cpu_clk); + clk_put(dvfs_clk); + printk(KERN_ERR "%s: failed to get gp regulator\n", __func__); + return PTR_ERR(core_regulator); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -ENODEV; + goto err1; + } + + /* + * Request the DVFS interrupt + */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + err = irq; + goto err1; + } + + /* request the DVFS interrupt */ + err = request_irq(irq, dvfs_irq, IRQF_SHARED, "dvfs", dvfs_dev); + if (err) + printk(KERN_ERR + "DVFS: Unable to attach to DVFS interrupt,err = %d", + err); + + clk_enable(dvfs_clk); + err = init_dvfs_controller(); + if (err) { + printk(KERN_ERR "DVFS: Unable to initialize DVFS"); + return err; + } + clk_disable(dvfs_clk); + + err = sysfs_create_file(&dvfs_dev->kobj, &dev_attr_enable.attr); + if (err) { + printk(KERN_ERR + "DVFS: Unable to register sysdev entry for DVFS"); + return err; + } + + /* Set the current working point. */ + cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr); + old_wp = 0; + curr_wp = 0; + dvfs_core_resume = 0; + cpufreq_trig_needed = 0; + + return err; + +err1: + dev_err(&pdev->dev, "Failed to probe DVFS CORE\n"); + return err; +} + +/*! + * This function is called to put DVFS in a low power state. + * + * @param pdev the device structure + * @param state the power state the device is entering + * + * @return The function always returns 0. + */ +static int mxc_dvfs_core_suspend(struct platform_device *pdev, + pm_message_t state) +{ + if (dvfs_core_is_active) { + dvfs_core_resume = 1; + stop_dvfs(); + } + + return 0; +} + +/*! + * This function is called to resume the MU from a low power state. + * + * @param dev the device structure + * @param level the stage in device suspension process that we want the + * device to be put in + * + * @return The function always returns 0. + */ +static int mxc_dvfs_core_resume(struct platform_device *pdev) +{ + if (dvfs_core_resume) { + dvfs_core_resume = 0; + start_dvfs(); + } + + return 0; +} + +static struct platform_driver mxc_dvfs_core_driver = { + .driver = { + .name = "mxc_dvfs_core", + }, + .probe = mxc_dvfs_core_probe, + .suspend = mxc_dvfs_core_suspend, + .resume = mxc_dvfs_core_resume, +}; + +static int __init dvfs_init(void) +{ + if (platform_driver_register(&mxc_dvfs_core_driver) != 0) { + printk(KERN_ERR "mxc_dvfs_core_driver register failed\n"); + return -ENODEV; + } + + dvfs_core_is_active = 0; + printk(KERN_INFO "DVFS driver module loaded\n"); + return 0; +} + +static void __exit dvfs_cleanup(void) +{ + stop_dvfs(); + + /* release the DVFS interrupt */ + free_irq(MXC_INT_GPC1, NULL); + + sysfs_remove_file(&dvfs_dev->kobj, &dev_attr_enable.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&mxc_dvfs_core_driver); + + clk_put(cpu_clk); + clk_put(dvfs_clk); + + dvfs_core_is_active = 0; + printk(KERN_INFO "DVFS driver module unloaded\n"); + +} + +module_init(dvfs_init); +module_exit(dvfs_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("DVFS driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/entry-pm.S b/arch/arm/plat-mxc/entry-pm.S new file mode 100644 index 000000000000..4a3af0e16191 --- /dev/null +++ b/arch/arm/plat-mxc/entry-pm.S @@ -0,0 +1,315 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/entry-pm.S + * + * @brief This file contains common pm entry . + * + * @ingroup MXC_PM + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WAIT_MODE 111 +#define DOZE_MODE 112 +#define STOP_MODE 113 +#define DSM_MODE 114 + +#define PM_XLOAD_SIZE 0x04 +#define PM_XLOAD_ENTRY 0x08 +#define PM_XLOAD_SUSPEND_MODE 0x0C +#define PM_XLOAD_CORE_SP 0x10 + +#define PROCINFO_PROC_FNS 36 +#define PROC_FIN_FN 12 +#define PROC_IDLE_FN 20 + +#ifdef CONFIG_FIQ +#define ARM_CONTEXT_SIZE 12 +#else +#define ARM_CONTEXT_SIZE 8 +#endif + +#ifdef CONFIG_PM_VERBOSE +resume_str: + .string "Resume from DSM..." + .size resume_str, . - resume_str + +.macro show_resume_str + ldr r0, =resume_str + bl printk +.endm + +#else +.macro show_resume_str +.endm +#endif + + .data + .align 3 +arm_core_context: + .rept ARM_CONTEXT_SIZE + .long 0 + .endr + +#ifdef CONFIG_VFP + .text + .align 5 +arm_vfp_save: + mov ip, sp + stmdb sp!, {r0-r8, fp, ip, lr, pc} + sub fp, ip, #4 + mov r1, #THREAD_SIZE + sub r1, r1, #1 + bic r0, sp, r1 + ldr r8, [r0, #TI_CPU] + add r4, r0, #TI_VFPSTATE + + ldr r3, =last_VFP_context + VFPFMRX r2, FPEXC + tst r2, #FPEXC_EN + bne 1f + + ldr r4, [r3, r8, lsl #2] + cmp r4, #0 + beq dead_vfp +1: + bic r1, r2, #FPEXC_EN + VFPFMXR FPEXC, r1 + /*TODO: SMP */ + VFPFSTMIA r4, r1 + VFPFMRX r5, FPSCR + tst r2, #FPEXC_EX + VFPFMRX r6, FPINST, NE + tstne r2, #FPEXC_FP2V + VFPFMRX r7, FPINST2, NE + stmia r4, {r2, r5, r6, r7} + + mov r1, #0 + str r1, [r3, r8, lsl #2] +dead_vfp: + ldmia sp, {r0-r8, fp, sp, pc} +#endif +/* + * The function just be called in this file + * Current r0 ~r4 are not saved. + * Otherwise, the working registers should be saved + */ + .text + .align 5 +arm_core_save: + mov ip, sp + stmdb sp!, {r8, r9, sl, fp, ip, lr, pc} + sub fp, ip, #4 + ldr r0, =arm_core_context + mov r3, r0 + /* SVC mode */ + mrs r1, spsr @Save spsr + mrs r2, cpsr @Save cpsr + stmia r0!, {r1, r2} + /* Abort mode */ + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | ABT_MODE + stmia r0!, {sp} @Save stack pointer for abort mode + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | UND_MODE + stmia r0!, {sp} @Save stack pointer for undefine mode + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | IRQ_MODE + stmia r0!, {sp} @Save stack pointer for irq mode +#ifdef CONFIG_FIQ + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | FIQ_MODE + /*Save general register and sp for fiq mode*/ + stmia r0!, {r8-r9, sl, fp, ip, sp} +#endif + ldr r0, [r3, #4] + msr cpsr_c, r0 + ldmia sp, {r8-r9, sl, fp, sp, pc} + +/* + * The function just be called in this file + * Current r0 ~r4 are not saved. + * Otherwise, the working registers should be saved + */ +arm_core_restore: + mov ip, sp + stmdb sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + ldr r0, =arm_core_context + mov r3, r0 + /* SVC mode */ + add r0, r0, #8 @skip svc mode + /* Abort mode */ + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | ABT_MODE + ldmia r0!, {sp} @restore stack pointer for abort mode + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | UND_MODE + ldmia r0!, {sp} @restore stack pointer for undefine mode + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | IRQ_MODE + ldmia r0!, {sp} @restore stack pointer for irq mode +#ifdef CONFIG_FIQ + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | FIQ_MODE + /*Save general register and sp for fiq mode*/ + ldmia r0!, {r8-r9, sl, fp, ip, sp} +#endif + ldmia r3!, {r1, r2} + msr cpsr, r2 @restore cpsr + msr spsr, r1 @restore spsr + ldmia sp, {fp, sp, pc} + +mxc_cp15_context: + .rept 16 + .long 0 + .endr + + .align 5 +mxc_cp15_restore: + /* Physical address */ + adr r0, mxc_cp15_context + ldmia r0, {r1-r9} +#ifndef CONFIG_PM_DEBUG + @Add dynamic check to skip this block when debug + sub lr, lr, #PHYS_OFFSET + add lr, lr, #PAGE_OFFSET +#endif + mcr p15, 0, r3, c1, c0, 2 @CP Access Register + mcr p15, 0, r2, c1, c0, 1 @Aux Control register + +#ifndef CONFIG_PM_DEBUG + mcr p15, 0, r0, c7, c5, 6 @flush BTAC/BTB + mcr p15, 0, r0, c7, c7, 0 @invalidate both caches + mcr p15, 0, r0, c8, c7, 0 @Inval TLBs +#endif + + mcr p15, 0, r4, c13, c0, 0 @PID + mcr p15, 0, r5, c13, c0, 1 @Context ID + + mcr p15, 0, r6, c3, c0, 0 @Domain Access Register + mcr p15, 0, r7, c2, c0, 0 @TTB0 + mcr p15, 0, r8, c2, c0, 1 @TTB1 + mcr p15, 0, r9, c2, c0, 2 @TTBC + + mcr p15, 0, r1, c1, c0, 0 @Control Register + /* mcu enabled */ + mrc p15, 0, r0, c2, c0, 0 + + mov pc, lr + nop + nop + nop + nop + nop + nop + nop + nop + +mxc_cp15_save: + mov ip, sp + stmdb sp!, {r8-r9, fp, ip, lr, pc} + sub fp, ip, #4 + ldr r0, =mxc_cp15_context +/* System Control Registers */ + mrc p15, 0, r1, c1, c0, 0 @Control Register + mrc p15, 0, r2, c1, c0, 1 @Aux Control Register + mrc p15, 0, r3, c1, c0, 2 @CP access Register + +/* Memory management Registers */ + mrc p15, 0, r4, c13, c0, 0 @PID + mrc p15, 0, r5, c13, c0, 1 @Context ID + + mrc p15, 0, r6, c3, c0, 0 @Domain Access Register + + mrc p15, 0, r7, c2, c0, 0 @TTB0 + mrc p15, 0, r8, c2, c0, 1 @TTB1 + mrc p15, 0, r9, c2, c0, 2 @TTBC + stmia r0, {r1-r9} + ldmia sp, {r8, r9, fp, sp, pc} + +/* + * int __mxc_pm_arch_entry(u32 entry, u32 size) + */ + .align 5 + .globl mxc_pm_arch_entry +mxc_pm_arch_entry: + mov ip, sp + stmdb sp!, {r4-r9, sl, fp, ip, lr, pc} + sub fp, ip, #4 + sub sp, sp, #4 + mov r8, r0 @save entry + mov r9, r1 @save entry size +#ifdef CONFIG_VFP + bl arm_vfp_save +#endif + /* r0 ~r3, ip is dirty*/ + bl arm_core_save @save arm context + bl mxc_cp15_save + mov r0, sp + mov r1, r8 @restore entry + mov r2, r9 @restore entry size + bl __mxc_pm_xload_setup +1: bl cpu_v6_proc_fin + bl cpu_v6_do_idle + nop + nop + nop + nop +__mxc_pm_arch_leave: + adr r0, __mxc_pm_xload_info + ldr sp, [r0, #PM_XLOAD_CORE_SP] + +#ifndef CONFIG_PM_DEBUG + sub sp, sp, #PAGE_OFFSET + add sp, sp, #PHYS_OFFSET +#endif + bl mxc_cp15_restore +#ifndef CONFIG_PM_DEBUG + sub sp, sp, #PHYS_OFFSET + add sp, sp, #PAGE_OFFSET +#endif + show_resume_str + bl arm_core_restore + ldmib sp, {r4-r9, sl, fp, sp, pc} + +__mxc_pm_xload_info: + adr pc, __mxc_pm_xload_entry @Jump instruction + .long __mxc_pm_xload_end - __mxc_pm_xload_info @loader size + .long (__mxc_pm_arch_leave - PAGE_OFFSET + PHYS_OFFSET) @resume entry + .long 0 @suspend state + .long 0 @Core Stack pointer +__mxc_pm_xload_entry: + adr r0, __mxc_pm_xload_info + ldr pc, [r0, #PM_XLOAD_ENTRY] +__mxc_pm_xload_end: + +/* + * __mxc_pm_xload_setup(u32 sp, u32 entry, u32 size) + * r0~r6 is dirty + */ +__mxc_pm_xload_setup: + ldr r3, =__mxc_pm_xload_info + str r0, [r3, #PM_XLOAD_CORE_SP] + ldr r4, [r3, #PM_XLOAD_SIZE] + cmp r2, r4 + blo 2f +1: ldr r5, [r3], #4 + str r5, [r1], #4 + subs r4, r4, #4 + bhi 1b + b 3f +2: str r3, [r1] +3: mov pc, lr diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 7506d963be4b..a4ff5d768484 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c @@ -20,12 +20,32 @@ */ #include +#include #include #include #include +#include +#include #include #include +#if defined(CONFIG_ARCH_MX2) +#else +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x00 +#define GPIO_GDIR 0x04 +#define GPIO_PSR 0x08 +#define GPIO_ICR1 0x0C +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_ISR 0x18 +#define GPIO_INT_LOW_LEV 0x0 +#define GPIO_INT_HIGH_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_FALL_EDGE 0x3 +#define GPIO_INT_NONE 0x4 +#endif + static struct mxc_gpio_port *mxc_gpio_ports; static int gpio_table_size; @@ -162,16 +182,23 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) } } -#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1) -/* MX1 and MX3 has one interrupt *per* gpio port */ -static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) +#ifndef CONFIG_ARCH_MX2 +/* one interrupt *per* gpio port */ +static void gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; + u32 mask = 0xFFFFFFFF; struct mxc_gpio_port *port = (struct mxc_gpio_port *)get_irq_data(irq); - irq_stat = __raw_readl(port->base + GPIO_ISR) & - __raw_readl(port->base + GPIO_IMR); +#ifdef MXC_GPIO_SPLIT_IRQ_2 + if (irq == port->irq) + mask = 0x0000FFFF; + else + mask = 0xFFFF0000; +#endif + irq_stat = __raw_readl(port->base + GPIO_ISR) & + (__raw_readl(port->base + GPIO_IMR) & mask); mxc_gpio_irq_handler(port, irq_stat); } #endif @@ -197,11 +224,44 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) } #endif +/* + * Set interrupt number "irq" in the GPIO as a wake-up source. + * While system is running all registered GPIO interrupts need to have + * wake-up enabled. When system is suspended, only selected GPIO interrupts + * need to have wake-up enabled. + * @param irq interrupt source number + * @param enable enable as wake-up if equal to non-zero + * @return This function returns 0 on success. + */ +static int gpio_set_wake_irq(u32 irq, u32 enable) +{ + u32 gpio = irq_to_gpio(irq); + u32 gpio_idx = gpio & 0x1F; + struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32]; + + if (enable) { + port->suspend_wakeup |= (1 << gpio_idx); + if (port->irq_high && (gpio_idx >= 16)) + enable_irq_wake(port->irq_high); + else + enable_irq_wake(port->irq); + } else { + port->suspend_wakeup &= ~(1 << gpio_idx); + if (port->irq_high && (gpio_idx >= 16)) + disable_irq_wake(port->irq_high); + else + disable_irq_wake(port->irq); + } + + return 0; +} + static struct irq_chip gpio_irq_chip = { .ack = gpio_ack_irq, .mask = gpio_mask_irq, .unmask = gpio_unmask_irq, .set_type = gpio_set_irq_type, + .set_wake = gpio_set_wake_irq, }; static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, @@ -252,9 +312,98 @@ static int mxc_gpio_direction_output(struct gpio_chip *chip, return 0; } +#ifdef CONFIG_PM +/*! + * This function puts the GPIO in low-power mode/state. + * All the interrupts that are enabled are first saved. + * Only those interrupts which registers as a wake source by calling + * enable_irq_wake are enabled. All other interrupts are disabled. + * + * @param dev the system device structure used to give information + * on GPIO to suspend + * @param mesg the power state the device is entering + * + * @return The function always returns 0. + */ +static int mxc_gpio_suspend(struct sys_device *dev, pm_message_t mesg) +{ + int i; + struct mxc_gpio_port *port = mxc_gpio_ports; + + for (i = 0; i < gpio_table_size; i++) { + void __iomem *isr_reg; + void __iomem *imr_reg; + + isr_reg = port[i].base + GPIO_ISR; + imr_reg = port[i].base + GPIO_IMR; + + if (__raw_readl(isr_reg) & port[i].suspend_wakeup) + return -EPERM; + + port[i].saved_wakeup = __raw_readl(imr_reg); + __raw_writel(port[i].suspend_wakeup, imr_reg); + } + + return 0; +} + +/*! + * This function brings the GPIO back from low-power state. + * All the interrupts enabled before suspension are re-enabled from + * the saved information. + * + * @param dev the system device structure used to give information + * on GPIO to resume + * + * @return The function always returns 0. + */ +static int mxc_gpio_resume(struct sys_device *dev) +{ + int i; + struct mxc_gpio_port *port = mxc_gpio_ports; + + for (i = 0; i < gpio_table_size; i++) { + void __iomem *isr_reg; + void __iomem *imr_reg; + + isr_reg = port[i].base + GPIO_ISR; + imr_reg = port[i].base + GPIO_IMR; + + __raw_writel(port[i].saved_wakeup, imr_reg); + } + + return 0; +} +#else +#define mxc_gpio_suspend NULL +#define mxc_gpio_resume NULL +#endif /* CONFIG_PM */ + +/*! + * This structure contains pointers to the power management callback functions. + */ +static struct sysdev_class mxc_gpio_sysclass = { + .name = "mxc_gpio", + .suspend = mxc_gpio_suspend, + .resume = mxc_gpio_resume, +}; + +/*! + * This structure represents GPIO as a system device. + * System devices follow a slightly different driver model. + * They don't need to do dynammic driver binding, can't be probed, + * and don't reside on any type of peripheral bus. + * So, it is represented and treated a little differently. + */ +static struct sys_device mxc_gpio_device = { + .id = 0, + .cls = &mxc_gpio_sysclass, +}; + int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) { int i, j; + int ret = 0; /* save for local usage */ mxc_gpio_ports = port; @@ -284,10 +433,13 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) /* its a serious configuration bug when it fails */ BUG_ON( gpiochip_add(&port[i].chip) < 0 ); -#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1) - /* setup one handler for each entry */ - set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler); +#ifndef CONFIG_ARCH_MX2 + set_irq_chained_handler(port[i].irq, gpio_irq_handler); set_irq_data(port[i].irq, &port[i]); + if (port[i].irq_high) { + set_irq_chained_handler(port[i].irq_high, gpio_irq_handler); + set_irq_data(port[i].irq_high, &port[i]); + } #endif } @@ -296,5 +448,10 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) set_irq_chained_handler(port[0].irq, mx2_gpio_irq_handler); set_irq_data(port[0].irq, port); #endif - return 0; + + ret = sysdev_class_register(&mxc_gpio_sysclass); + if (ret == 0) + ret = sysdev_register(&mxc_gpio_device); + + return ret; } diff --git a/arch/arm/plat-mxc/include/mach/arc_otg.h b/arch/arm/plat-mxc/include/mach/arc_otg.h new file mode 100644 index 000000000000..2d58f2e6d6fd --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/arc_otg.h @@ -0,0 +1,343 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MXC_ARC_OTG_H__ +#define __ASM_ARCH_MXC_ARC_OTG_H__ + +#define USB_OTGREGS_BASE (OTG_BASE_ADDR + 0x000) +#define USB_H1REGS_BASE (OTG_BASE_ADDR + 0x200) +#define USB_H2REGS_BASE (OTG_BASE_ADDR + 0x400) +#ifdef CONFIG_ARCH_MX51 +#define USB_H3REGS_BASE (OTG_BASE_ADDR + 0x600) +#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x800) +#else +#define USB_OTHERREGS_BASE (OTG_BASE_ADDR + 0x600) +#endif + + +#define USBOTG_REG32(offset) (*((volatile u32 *)(IO_ADDRESS(USB_OTGREGS_BASE + (offset))))) +#define USBOTG_REG16(offset) (*((volatile u16 *)(IO_ADDRESS(USB_OTGREGS_BASE + (offset))))) + +#define USBH1_REG32(offset) (*((volatile u32 *)(IO_ADDRESS(USB_H1REGS_BASE + (offset))))) +#define USBH1_REG16(offset) (*((volatile u16 *)(IO_ADDRESS(USB_H1REGS_BASE + (offset))))) + +#define USBH2_REG32(offset) (*((volatile u32 *)(IO_ADDRESS(USB_H2REGS_BASE + (offset))))) +#define USBH2_REG16(offset) (*((volatile u16 *)(IO_ADDRESS(USB_H2REGS_BASE + (offset))))) + +#define USBOTHER_REG(offset) (*((volatile u32 *)(IO_ADDRESS(USB_OTHERREGS_BASE + (offset))))) + +/* + * OTG registers + */ +#define UOG_ID USBOTG_REG32(0x00) /* Host ID */ +#define UOG_HWGENERAL USBOTG_REG32(0x04) /* Host General */ +#define UOG_HWHOST USBOTG_REG32(0x08) /* Host h/w params */ +#define UOG_HWTXBUF USBOTG_REG32(0x10) /* TX buffer h/w params */ +#define UOG_HWRXBUF USBOTG_REG32(0x14) /* RX buffer h/w params */ +#define UOG_CAPLENGTH USBOTG_REG16(0x100) /* Capability register length */ +#define UOG_HCIVERSION USBOTG_REG16(0x102) /* Host Interface version */ +#define UOG_HCSPARAMS USBOTG_REG32(0x104) /* Host control structural params */ +#define UOG_HCCPARAMS USBOTG_REG32(0x108) /* control capability params */ +#define UOG_DCIVERSION USBOTG_REG32(0x120) /* device interface version */ +/* start EHCI registers: */ +#define UOG_USBCMD USBOTG_REG32(0x140) /* USB command register */ +#define UOG_USBSTS USBOTG_REG32(0x144) /* USB status register */ +#define UOG_USBINTR USBOTG_REG32(0x148) /* interrupt enable register */ +#define UOG_FRINDEX USBOTG_REG32(0x14c) /* USB frame index */ +/* segment (0x150) addr bits 63:32 if needed */ +#define UOG_PERIODICLISTBASE USBOTG_REG32(0x154) /* host crtlr frame list base addr */ +#define UOG_DEVICEADDR USBOTG_REG32(0x154) /* device crtlr device address */ +#define UOG_ASYNCLISTADDR USBOTG_REG32(0x158) /* host ctrlr next async addr */ +#define UOG_EPLISTADDR USBOTG_REG32(0x158) /* device ctrlr endpoint list addr */ +#define UOG_BURSTSIZE USBOTG_REG32(0x160) /* host ctrlr embedded TT async buf status */ +#define UOG_TXFILLTUNING USBOTG_REG32(0x164) /* TX FIFO fill tuning */ +#define UOG_ULPIVIEW USBOTG_REG32(0x170) /* ULPI viewport */ +#define UOG_CFGFLAG USBOTG_REG32(0x180) /* configflag (supports HS) */ +#define UOG_PORTSC1 USBOTG_REG32(0x184) /* port status and control */ +/* end EHCI registers: */ +#define UOG_OTGSC USBOTG_REG32(0x1a4) /* OTG status and control */ +#define UOG_USBMODE USBOTG_REG32(0x1a8) /* USB device mode */ +#define UOG_ENDPTSETUPSTAT USBOTG_REG32(0x1ac) /* endpoint setup status */ +#define UOG_ENDPTPRIME USBOTG_REG32(0x1b0) /* endpoint initialization */ +#define UOG_ENDPTFLUSH USBOTG_REG32(0x1b4) /* endpoint de-initialize */ +#define UOG_ENDPTSTAT USBOTG_REG32(0x1b8) /* endpoint status */ +#define UOG_ENDPTCOMPLETE USBOTG_REG32(0x1bc) /* endpoint complete */ +#define UOG_EPCTRL0 USBOTG_REG32(0x1c0) /* endpoint control0 */ +#define UOG_EPCTRL1 USBOTG_REG32(0x1c4) /* endpoint control1 */ +#define UOG_EPCTRL2 USBOTG_REG32(0x1c8) /* endpoint control2 */ +#define UOG_EPCTRL3 USBOTG_REG32(0x1cc) /* endpoint control3 */ +#define UOG_EPCTRL4 USBOTG_REG32(0x1d0) /* endpoint control4 */ +#define UOG_EPCTRL5 USBOTG_REG32(0x1d4) /* endpoint control5 */ +#define UOG_EPCTRL6 USBOTG_REG32(0x1d8) /* endpoint control6 */ +#define UOG_EPCTRL7 USBOTG_REG32(0x1dc) /* endpoint control7 */ + +/* + * Host 1 registers + */ +#define UH1_ID USBH1_REG32(0x00) /* Host ID */ +#define UH1_HWGENERAL USBH1_REG32(0x04) /* Host General */ +#define UH1_HWHOST USBH1_REG32(0x08) /* Host h/w params */ +#define UH1_HWTXBUF USBH1_REG32(0x10) /* TX buffer h/w params */ +#define UH1_HWRXBUF USBH1_REG32(0x14) /* RX buffer h/w params */ +#define UH1_CAPLENGTH USBH1_REG16(0x100) /* Capability register length */ +#define UH1_HCIVERSION USBH1_REG16(0x102) /* Host Interface version */ +#define UH1_HCSPARAMS USBH1_REG32(0x104) /* Host control structural params */ +#define UH1_HCCPARAMS USBH1_REG32(0x108) /* control capability params */ +/* start EHCI registers: */ +#define UH1_USBCMD USBH1_REG32(0x140) /* USB command register */ +#define UH1_USBSTS USBH1_REG32(0x144) /* USB status register */ +#define UH1_USBINTR USBH1_REG32(0x148) /* interrupt enable register */ +#define UH1_FRINDEX USBH1_REG32(0x14c) /* USB frame index */ +/* segment (0x150) addr bits 63:32 if needed */ +#define UH1_PERIODICLISTBASE USBH1_REG32(0x154) /* host crtlr frame list base addr */ +#define UH1_ASYNCLISTADDR USBH1_REG32(0x158) /* host ctrlr nest async addr */ +#define UH1_BURSTSIZE USBH1_REG32(0x160) /* host ctrlr embedded TT async buf status */ +#define UH1_TXFILLTUNING USBH1_REG32(0x164) /* TX FIFO fill tuning */ +/* configured_flag (0x180) configflag (supports HS) */ +#define UH1_PORTSC1 USBH1_REG32(0x184) /* port status and control */ +/* end EHCI registers: */ +#define UH1_USBMODE USBH1_REG32(0x1a8) /* USB device mode */ + +/* + * Host 2 registers + */ +#define UH2_ID USBH2_REG32(0x00) /* Host ID */ +#define UH2_HWGENERAL USBH2_REG32(0x04) /* Host General */ +#define UH2_HWHOST USBH2_REG32(0x08) /* Host h/w params */ +#define UH2_HWTXBUF USBH2_REG32(0x10) /* TX buffer h/w params */ +#define UH2_HWRXBUF USBH2_REG32(0x14) /* RX buffer h/w params */ +#define UH2_CAPLENGTH USBH2_REG16(0x100) /* Capability register length */ +#define UH2_HCIVERSION USBH2_REG16(0x102) /* Host Interface version */ +#define UH2_HCSPARAMS USBH2_REG32(0x104) /* Host control structural params */ +#define UH2_HCCPARAMS USBH2_REG32(0x108) /* control capability params */ +/* start EHCI registers: */ +#define UH2_USBCMD USBH2_REG32(0x140) /* USB command register */ +#define UH2_USBSTS USBH2_REG32(0x144) /* USB status register */ +#define UH2_USBINTR USBH2_REG32(0x148) /* interrupt enable register */ +#define UH2_FRINDEX USBH2_REG32(0x14c) /* USB frame index */ +/* segment (0x150) addr bits 63:32 if needed */ +#define UH2_PERIODICLISTBASE USBH2_REG32(0x154) /* host crtlr frame list base addr */ +#define UH2_ASYNCLISTADDR USBH2_REG32(0x158) /* host ctrlr nest async addr */ +#define UH2_BURSTSIZE USBH2_REG32(0x160) /* host ctrlr embedded TT async buf status */ +#define UH2_TXFILLTUNING USBH2_REG32(0x164) /* TX FIFO fill tuning */ +#define UH2_ULPIVIEW USBH2_REG32(0x170) /* ULPI viewport */ +/* configured_flag (0x180) configflag (supports HS) */ +#define UH2_PORTSC1 USBH2_REG32(0x184) /* port status and control */ +/* end EHCI registers */ +#define UH2_USBMODE USBH2_REG32(0x1a8) /* USB device mode */ + +/* + * other regs (not part of ARC core) + */ +#define USBCTRL USBOTHER_REG(0x00) /* USB Control register */ +#define USB_OTG_MIRROR USBOTHER_REG(0x04) /* USB OTG mirror register */ +#define USB_PHY_CTR_FUNC USBOTHER_REG(0x08) /* OTG UTMI PHY Function Control register */ +#define USB_PHY_CTR_FUNC2 USBOTHER_REG(0x0c) /* OTG UTMI PHY Function Control register */ +#define USB_CTRL_1 USBOTHER_REG(0x10) /* USB Cotrol Register 1*/ +#define USBCTRL_HOST2 USBOTHER_REG(0x14) /* USB Cotrol Register 1*/ +#define USBCTRL_HOST3 USBOTHER_REG(0x18) /* USB Cotrol Register 1*/ + +/* + * register bits + */ + +/* x_PORTSCx */ +#define PORTSC_PTS_MASK (3 << 30) /* parallel xcvr select mask */ +#define PORTSC_PTS_UTMI (0 << 30) /* UTMI/UTMI+ */ +#define PORTSC_PTS_PHILIPS (1 << 30) /* Philips classic */ +#define PORTSC_PTS_ULPI (2 << 30) /* ULPI */ +#define PORTSC_PTS_SERIAL (3 << 30) /* serial */ +#define PORTSC_STS (1 << 29) /* serial xcvr select */ +#define PORTSC_PTW (1 << 28) /* UTMI width */ +#define PORTSC_PHCD (1 << 23) /* Low Power Suspend */ +#define PORTSC_PORT_POWER (1 << 12) /* port power */ +#define PORTSC_LS_MASK (3 << 10) /* Line State mask */ +#define PORTSC_LS_SE0 (0 << 10) /* SE0 */ +#define PORTSC_LS_K_STATE (1 << 10) /* K-state */ +#define PORTSC_LS_J_STATE (2 << 10) /* J-state */ +#define PORTSC_PORT_RESET (1 << 8) /* Port reset */ +#define PORTSC_PORT_SUSPEND (1 << 7) /* Suspend */ +#define PORTSC_PORT_FORCE_RESUME (1 << 6) /* Force port resume */ +#define PORTSC_OVER_CURRENT_CHG (1 << 5) /* over current change */ +#define PORTSC_OVER_CURRENT_ACT (1 << 4) /* over currrent active */ +#define PORTSC_PORT_EN_DIS_CHANGE (1 << 3) /* port {en,dis}able change */ +#define PORTSC_PORT_ENABLE (1 << 2) /* port enabled */ +#define PORTSC_CONNECT_STATUS_CHANGE (1 << 1) /* connect status change */ +#define PORTSC_CURRENT_CONNECT_STATUS (1 << 0) /* current connect status */ + +#define PORTSC_W1C_BITS \ + ( PORTSC_CONNECT_STATUS_CHANGE | \ + PORTSC_PORT_EN_DIS_CHANGE | \ + PORTSC_OVER_CURRENT_CHG ) + +/* UOG_OTGSC Register Bits */ +/* control bits: */ +#define OTGSC_CTRL_VBUS_DISCHARGE (1 << 0) +#define OTGSC_CTRL_VBUS_CHARGE (1 << 1) +#define OTGSC_CTRL_OTG_TERM (1 << 3) /* controls DM pulldown */ +#define OTGSC_CTRL_DATA_PULSING (1 << 4) +#define OTGSC_CTRL_USB_ID_PU (1 << 5) /* enable ID pullup */ +/* current status: (R/O) */ +#define OTGSC_STS_USB_ID (1 << 8) /* 0=A-device 1=B-device */ +#define OTGSC_STS_A_VBUS_VALID (1 << 9) +#define OTGSC_STS_A_SESSION_VALID (1 << 10) +#define OTGSC_STS_B_SESSION_VALID (1 << 11) +#define OTGSC_STS_B_SESSION_END (1 << 12) +#define OTGSC_STS_1ms_TIMER (1 << 13) +#define OTGSC_STS_DATA_PULSE (1 << 14) +/* interrupt status: (write to clear) */ +#define OTGSC_IS_MASK (0x7f << 16) +#define OTGSC_IS_USB_ID (1 << 16) +#define OTGSC_IS_A_VBUS_VALID (1 << 17) +#define OTGSC_IS_A_SESSION_VALID (1 << 18) +#define OTGSC_IS_B_SESSION_VALID (1 << 19) +#define OTGSC_IS_B_SESSION_END (1 << 20) +#define OTGSC_IS_1ms_TIMER (1 << 21) +#define OTGSC_IS_DATA_PULSE (1 << 22) +/* interrupt enables: */ +#define OTGSC_IE_MASK (0x7f << 24) +#define OTGSC_IE_USB_ID (1 << 24) +#define OTGSC_IE_A_VBUS_VALID (1 << 25) +#define OTGSC_IE_A_SESSION_VALID (1 << 26) +#define OTGSC_IE_B_SESSION_VALID (1 << 27) +#define OTGSC_IE_B_SESSION_END (1 << 28) +#define OTGSC_IE_1ms_TIMER (1 << 29) +#define OTGSC_IE_DATA_PULSE (1 << 30) + +#if 1 /* FIXME these here for compatibility between my names and Leo's */ +/* OTG interrupt enable bit masks */ +#define OTGSC_INTERRUPT_ENABLE_BITS_MASK OTGSC_IE_MASK +#define OTGSC_INTSTS_MASK OTGSC_IS_MASK + +/* OTG interrupt status bit masks */ +#define OTGSC_INTERRUPT_STATUS_BITS_MASK OTGSC_IS_MASK +#endif + +/* x_USBMODE */ +#define USBMODE_SLOM (1 << 3) /* setup lockout mode */ +#define USBMODE_ES (1 << 2) /* (big) endian select */ +#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */ +#define USBMODE_CM_HOST (3 << 0) /* host */ +#define USBMODE_CM_DEVICE (2 << 0) /* device */ +#define USBMODE_CM_reserved (1 << 0) /* reserved */ + +/* USBCTRL */ +#define UCTRL_OWIR (1 << 31) /* OTG wakeup intr request received */ +#define UCTRL_OSIC_MASK (3 << 29) /* OTG Serial Interface Config: */ +#define UCTRL_OSIC_DU6 (0 << 29) /* Differential/unidirectional 6 wire */ +#define UCTRL_OSIC_DB4 (1 << 29) /* Differential/bidirectional 4 wire */ +#define UCTRL_OSIC_SU6 (2 << 29) /* single-ended/unidirectional 6 wire */ +#define UCTRL_OSIC_SB3 (3 << 29) /* single-ended/bidirectional 3 wire */ + +#define UCTRL_OUIE (1 << 28) /* OTG ULPI intr enable */ +#define UCTRL_OWIE (1 << 27) /* OTG wakeup intr enable */ +#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */ +#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */ +#define UCTRL_OPM (1 << 24) /* OTG power mask */ +#define UCTRL_H2WIR (1 << 23) /* HOST2 wakeup intr request received */ +#define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */ +#define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */ +#define UCTRL_H2SIC_DB4 (1 << 21) /* Differential/bidirectional 4 wire */ +#define UCTRL_H2SIC_SU6 (2 << 21) /* single-ended/unidirectional 6 wire */ +#define UCTRL_H2SIC_SB3 (3 << 21) /* single-ended/bidirectional 3 wire */ + +#ifdef CONFIG_ARCH_MX51 +#define UCTRL_H2UIE (1 << 8) /* HOST2 ULPI intr enable */ +#define UCTRL_H2WIE (1 << 7) /* HOST2 wakeup intr enable */ +#define UCTRL_H2PP 0 /* Power Polarity for uh2 */ +#define UCTRL_H2PM (1 << 4) /* HOST2 power mask */ +#else +#define UCTRL_H2UIE (1 << 20) /* HOST2 ULPI intr enable */ +#define UCTRL_H2WIE (1 << 19) /* HOST2 wakeup intr enable */ +#define UCTRL_H2PP (1 << 18) /* Power Polarity for uh2 */ +#define UCTRL_H2PM (1 << 16) /* HOST2 power mask */ +#endif + +#define UCTRL_H1WIR (1 << 15) /* HOST1 wakeup intr request received */ +#define UCTRL_H1SIC_MASK (3 << 13) /* HOST1 Serial Interface Config: */ +#define UCTRL_H1SIC_DU6 (0 << 13) /* Differential/unidirectional 6 wire */ +#define UCTRL_H1SIC_DB4 (1 << 13) /* Differential/bidirectional 4 wire */ +#define UCTRL_H1SIC_SU6 (2 << 13) /* single-ended/unidirectional 6 wire */ +#define UCTRL_H1SIC_SB3 (3 << 13) /* single-ended/bidirectional 3 wire */ +#define UCTRL_OLOCKD (1 << 13) /* otg lock disable */ +#define UCTRL_H2LOCKD (1 << 12) /* HOST2 lock disable */ +#define UCTRL_H1UIE (1 << 12) /* Host1 ULPI interrupt enable */ + +#define UCTRL_PP (1 << 11) /* power polarity bit */ +#define UCTRL_H1WIE (1 << 11) /* HOST1 wakeup intr enable */ +#define UCTRL_H1BPVAL_RXDP (1 << 10) /* HOST1 RxDp status in bypass mode */ +#define UCTRL_XCSO (1 << 10) /* Xcvr Clock Select for OTG port */ +#define UCTRL_H1BPVAL_RXDM (1 << 9) /* HOST1 RxDm status in bypass mode */ +#define UCTRL_XCSH2 (1 << 9) /* Xcvr Clock Select for Host port */ +#define UCTRL_H1PM (1 << 8) /* HOST1 power mask */ +#define UCTRL_IP_PULIDP (1 << 8) /* Ipp_Puimpel_Pullup_Dp */ + +#define UCTRL_IP_PUE_UP (1 << 7) /* ipp_pue_pullup_dp */ +#define UCTRL_IP_PUE_DOWN (1 << 6) /* ipp_pue_pulldwn_dpdm */ +#define UCTRL_H2DT (1 << 5) /* HOST2 TLL disabled */ +#define UCTRL_H1DT (1 << 4) /* HOST1 TLL disabled */ +#define UCTRL_USBTE (1 << 4) /* USBT Transceiver enable */ +#define UCTRL_OCPOL (1 << 3) /* OverCurrent Polarity */ +#define UCTRL_OCE (1 << 2) /* OverCurrent Enable */ +#define UCTRL_H2OCPOL (1 << 2) /* OverCurrent Polarity of Host2 */ +#define UCTRL_H2OCS (1 << 1) /* Host OverCurrent State */ +#define UCTRL_BPE (1 << 0) /* bypass mode enable */ +#define UCTRL_OTD (1 << 0) /* OTG TLL Disable */ +#define UCTRL_OOCS (1 << 0) /* OTG OverCurrent State */ + +/* USBCMD */ +#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ +#define UCMD_RESET (1 << 1) /* controller reset */ +#define UCMD_ITC_NO_THRESHOLD ~(0xff << 16) /* Interrupt Threshold Control */ + +/* OTG_MIRROR */ +#define OTGM_SESEND (1 << 4) /* B device session end */ +#define OTGM_VBUSVAL (1 << 3) /* Vbus valid */ +#define OTGM_BSESVLD (1 << 2) /* B session Valid */ +#define OTGM_ASESVLD (1 << 1) /* A session Valid */ +#define OTGM_IDIDG (1 << 0) /* OTG ID pin status */ + /* 1=high: Operate as B-device */ + /* 0=low : Operate as A-device */ + +/* USB_PHY_CTRL_FUNC */ +#define USB_UTMI_PHYCTRL_UTMI_ENABLE (1 << 24) +#define USB_UTMI_PHYCTRL_CHGRDETEN (1 << 24) /* Enable Charger Detector */ +#define USB_UTMI_PHYCTRL_CHGRDETON (1 << 23) /* Charger Detector Power On Control */ +#define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */ +#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */ +/* USB_PHY_CTRL_FUNC2*/ +#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3 +#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0 +#define USB_UTMI_PHYCTRL2_HSDEVSEL_MASK 0x3 +#define USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT 19 + +/* USB_CTRL_1 */ +#define USB_CTRL_UH1_EXT_CLK_EN (1 << 25) +#define USB_CTRL_UH2_EXT_CLK_EN (1 << 26) + +/* ULPIVIEW register bits */ +#define ULPIVW_OFF (0x170) +#define ULPIVW_WU (1 << 31) /* Wakeup */ +#define ULPIVW_RUN (1 << 30) /* read/write run */ +#define ULPIVW_WRITE (1 << 29) /* 0=read 1=write */ +#define ULPIVW_SS (1 << 27) /* SyncState */ +#define ULPIVW_PORT_MASK 0x07 /* Port field */ +#define ULPIVW_PORT_SHIFT 24 +#define ULPIVW_ADDR_MASK 0xFF /* data address field */ +#define ULPIVW_ADDR_SHIFT 16 +#define ULPIVW_RDATA_MASK 0xFF /* read data field */ +#define ULPIVW_RDATA_SHIFT 8 +#define ULPIVW_WDATA_MASK 0xFF /* write data field */ +#define ULPIVW_WDATA_SHIFT 0 + +#define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */ +#endif diff --git a/arch/arm/plat-mxc/include/mach/audio_controls.h b/arch/arm/plat-mxc/include/mach/audio_controls.h new file mode 100644 index 000000000000..810bf50b16a8 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/audio_controls.h @@ -0,0 +1,220 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + + /*! + * @file include/asm-arm/arch-mxc/audio_controls.h + * @brief this file implements the mxc sound driver interface to OSS framework + * @ingroup SOUND_DRV + */ +#ifndef __ASM_ARCH_MXC_AUDIO_CONTROLS_H__ +#define __ASM_ARCH_MXC_AUDIO_CONTROLS_H__ + +/*! + * This ioctl can be used to get the adder configuration, use the audio control + * SNDCTL_MC13783_READ_OUT_MIXER.\n + * Possible returned values are : + * @see MC13783_AUDIO_ADDER_STEREO + * @see MC13783_AUDIO_ADDER_STEREO_OPPOSITE + * @see MC13783_AUDIO_ADDER_MONO + * @see MC13783_AUDIO_ADDER_MONO_OPPOSITE + * + */ +#define SNDCTL_MC13783_READ_OUT_ADDER _SIOR('Z', 6, int) + +/*! + * To set the adder configuration, use the audio control + * SNDCTL_MC13783_WRITE_OUT_MIXER. Possible arguments are : \n + * @see MC13783_AUDIO_ADDER_STEREO + * @see MC13783_AUDIO_ADDER_STEREO_OPPOSITE + * @see MC13783_AUDIO_ADDER_MONO + * @see MC13783_AUDIO_ADDER_MONO_OPPOSITE + * + */ +#define SNDCTL_MC13783_WRITE_OUT_ADDER _SIOWR('Z', 7, int) + +/*! + * To get the codec balance configuration, use the audio control + * SNDCTL_MC13783_READ_OUT_BALANCE.\n + * Range is 0 (-21 dB left) to 100 (-21 dB right), linear, 3dB step ; + * 50 is no balance. + * \n Examples: + * \n 0 : -21dB left 50 : balance deactivated 100 : -21 dB right + * + */ +#define SNDCTL_MC13783_READ_OUT_BALANCE _SIOR('Z', 8, int) + +/*! + * To set the codec balance configuration, use the audio control + * SNDCTL_MC13783_WRITE_OUT_BALANCE.\n + * Range is 0 (-21 dB left) to 100 (-21 dB right), linear, 3dB step ; + * 50 is no balance. + * \n Examples: + * \n 0 : -21dB left 50 : balance deactivated 100 : -21 dB right + * + */ +#define SNDCTL_MC13783_WRITE_OUT_BALANCE _SIOWR('Z', 9, int) + +/*! + * To set the codec filter configuration, use the audio control + * SNDCTL_MC13783_WRITE_CODEC_FILTER. + * The new configuration replaces the old one.\n + * Possible arguments are : + * @see MC13783_CODEC_FILTER_DISABLE + * @see MC13783_CODEC_FILTER_HIGH_PASS_IN + * @see MC13783_CODEC_FILTER_HIGH_PASS_OUT + * @see MC13783_CODEC_FILTER_DITHERING \n + * + */ +#define SNDCTL_MC13783_WRITE_CODEC_FILTER _SIOWR('Z', 20, int) + +/*! + * To get the codec filter configuration, use the audio control : + * SNDCTL_MC13783_READ_CODEC_FILTER. + * The new configuration replaces the old one.\n + * Possible returned values are : + * @see MC13783_CODEC_FILTER_DISABLE + * @see MC13783_CODEC_FILTER_HIGH_PASS_IN + * @see MC13783_CODEC_FILTER_HIGH_PASS_OUT + * @see MC13783_CODEC_FILTER_DITHERING \n + * + */ +#define SNDCTL_MC13783_READ_CODEC_FILTER _SIOR('Z', 21, int) + +/* + * To set the clock configuration, use the audio control + * SNDCTL_MC13783_WRITE_MASTER_CLOCK. \n + * Possible arguments are : \n + * 1 : to MCU master \n + * 2 : to MC13783 master + */ +#define SNDCTL_MC13783_WRITE_MASTER_CLOCK _SIOR('Z', 30, int) + +/*! + * To set the output port, use the audio control + * SNDCTL_MC13783_WRITE_PORT.\n + * Possible returned values are : + * \n 1 : to port 4 + * \n 2 : to port 5 + * Possible returned values are : + * \n 1 : port 4 + * \n 2 : port 5 + */ +#define SNDCTL_MC13783_WRITE_PORT _SIOR('Z', 31, int) + +/*! + * Argument for the mc13783 adder configuration + * @see SNDCTL_MC13783_WRITE_OUT_ADDER + * @see SNDCTL_MC13783_READ_OUT_ADDER + */ +#define MC13783_AUDIO_ADDER_STEREO 0x1 +/*! + * Argument for the mc13783 adder configuration + * @see SNDCTL_MC13783_WRITE_OUT_ADDER + * @see SNDCTL_MC13783_READ_OUT_ADDER + */ +#define MC13783_AUDIO_ADDER_STEREO_OPPOSITE 0x2 +/*! + * Argument for the mc13783 adder configuration + * @see SNDCTL_MC13783_WRITE_OUT_ADDER + * @see SNDCTL_MC13783_READ_OUT_ADDER + */ +#define MC13783_AUDIO_ADDER_MONO 0x4 +/*! + * Argument for the mc13783 adder configuration + * @see SNDCTL_MC13783_WRITE_OUT_ADDER + * @see SNDCTL_MC13783_READ_OUT_ADDER + */ +#define MC13783_AUDIO_ADDER_MONO_OPPOSITE 0x8 + +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_DISABLE 0x0 +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_HIGH_PASS_IN 0x1 +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_HIGH_PASS_OUT 0x2 +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_DITHERING 0x4 + +/*! + * Argument for the system audio clocking selection + * @see MXC_AUDIO_CLOCKING_MCU_MASTER + * @see SNDCTL_CLK_SET_MASTER + */ +#define MXC_AUDIO_CLOCKING_MC13783_MASTER 0x0 + +/*! + * Argument for the system audio clocking selection + * @see MXC_AUDIO_CLOCKING_MC13783_MASTER + * @see SNDCTL_CLK_SET_MASTER + */ +#define MXC_AUDIO_CLOCKING_MCU_MASTER 0x1 + +/*! + * Argument for the DAM output port selection + * @see SNDCTL_DAM_SET_OUT_PORT + * @see MXC_DAM_OUT_PORT_AD2 + */ +#define MXC_DAM_OUT_PORT_AD1 0x0 + +/*! + * Argument for the DAM output port selection + * @see SNDCTL_DAM_SET_OUT_PORT + * @see MXC_DAM_OUT_PORT_AD1 + */ +#define MXC_DAM_OUT_PORT_AD2 0x1 + +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_DISABLE 0x0 + +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_HIGH_PASS_IN 0x1 + +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_HIGH_PASS_OUT 0x2 + +/*! + * Argument for the mc13783 codec filter configuration + * @see SNDCTL_MC13783_WRITE_CODEC_FILTER + * @see SNDCTL_MC13783_READ_CODEC_FILTER + */ +#define MC13783_CODEC_FILTER_DITHERING 0x4 + +#endif /* __ASM_ARCH_MXC_AUDIO_CONTROLS_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h index 43a82d0c534d..e9333bb1729b 100644 --- a/arch/arm/plat-mxc/include/mach/clock.h +++ b/arch/arm/plat-mxc/include/mach/clock.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -38,6 +38,8 @@ struct clk { struct clk *parent; /* Secondary clock to enable/disable with this clock */ struct clk *secondary; + /* Current clock rate */ + unsigned long rate; /* Reference count of clock enable/disable */ __s8 usecount; /* Register bit position for clock's enable/disable control. */ @@ -45,8 +47,9 @@ struct clk { /* Register address for clock's enable/disable control. */ void __iomem *enable_reg; u32 flags; - /* get the current clock rate (always a fresh value) */ - unsigned long (*get_rate) (struct clk *); + /* Function ptr to recalculate the clock's rate based on parent + clock's rate */ + void (*recalc) (struct clk *); /* Function ptr to set the clock to a new rate. The rate must match a supported rate returned from round_rate. Leave blank if clock is not programmable */ @@ -66,6 +69,16 @@ struct clk { int clk_register(struct clk *clk); void clk_unregister(struct clk *clk); +int clk_get_usecount(struct clk *clk); +int clk_set_pll_dither(struct clk *clk, unsigned int pll_ppm); + +/* Clock flags */ +#define RATE_PROPAGATES (1 << 0) /* Program children too */ +#define ALWAYS_ENABLED (1 << 1) /* Clock cannot be disabled */ +#define RATE_FIXED (1 << 2) /* Fixed clock rate */ +#define CPU_FREQ_TRIG_UPDATE (1 << 3) /* CPUFREQ trig update */ +#define AHB_HIGH_SET_POINT (1 << 4) /* Requires max AHB clock */ +#define AHB_MED_SET_POINT (1 << 5) /* Requires med AHB clock */ unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref); diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 02c3cd004db3..b66644df843c 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -16,16 +16,26 @@ struct clk; extern void mx1_map_io(void); extern void mx21_map_io(void); +extern void mx25_map_io(void); extern void mx27_map_io(void); extern void mx31_map_io(void); extern void mx35_map_io(void); +extern void mx37_map_io(void); +extern void mx51_map_io(void); extern void mxc_init_irq(void); -extern void mxc_timer_init(struct clk *timer_clk); +extern void mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq); extern int mx1_clocks_init(unsigned long fref); extern int mx21_clocks_init(unsigned long lref, unsigned long fref); +extern int mx25_clocks_init(unsigned long fref); extern int mx27_clocks_init(unsigned long fref); extern int mx31_clocks_init(unsigned long fref); extern int mx35_clocks_init(void); +extern int mx37_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); +extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); +extern int mxc_init_devices(void); +extern void mxc_cpu_init(void) __init; +extern void mxc_cpu_common_init(void); +extern void __init early_console_setup(char *); extern int mxc_register_gpios(void); extern int mxc_register_device(struct platform_device *pdev, void *data); extern void mxc_set_cpu_type(unsigned int type); diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h new file mode 100644 index 000000000000..d2f6091cebb3 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/dma.h @@ -0,0 +1,293 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARCH_MXC_DMA_H__ +#define __ASM_ARCH_MXC_DMA_H__ + +#include + +#define MXC_DMA_DYNAMIC_CHANNEL 255 + +#define MXC_DMA_DONE 0x0 +#define MXC_DMA_REQUEST_TIMEOUT 0x1 +#define MXC_DMA_TRANSFER_ERROR 0x2 + +/*! This defines the list of device ID's for DMA */ +typedef enum mxc_dma_device { + MXC_DMA_UART1_RX, + MXC_DMA_UART1_TX, + MXC_DMA_UART2_RX, + MXC_DMA_UART2_TX, + MXC_DMA_UART3_RX, + MXC_DMA_UART3_TX, + MXC_DMA_UART4_RX, + MXC_DMA_UART4_TX, + MXC_DMA_UART5_RX, + MXC_DMA_UART5_TX, + MXC_DMA_UART6_RX, + MXC_DMA_UART6_TX, + MXC_DMA_MMC1_WIDTH_1, + MXC_DMA_MMC1_WIDTH_4, + MXC_DMA_MMC2_WIDTH_1, + MXC_DMA_MMC2_WIDTH_4, + MXC_DMA_SSI1_8BIT_RX0, + MXC_DMA_SSI1_8BIT_TX0, + MXC_DMA_SSI1_16BIT_RX0, + MXC_DMA_SSI1_16BIT_TX0, + MXC_DMA_SSI1_24BIT_RX0, + MXC_DMA_SSI1_24BIT_TX0, + MXC_DMA_SSI1_8BIT_RX1, + MXC_DMA_SSI1_8BIT_TX1, + MXC_DMA_SSI1_16BIT_RX1, + MXC_DMA_SSI1_16BIT_TX1, + MXC_DMA_SSI1_24BIT_RX1, + MXC_DMA_SSI1_24BIT_TX1, + MXC_DMA_SSI2_8BIT_RX0, + MXC_DMA_SSI2_8BIT_TX0, + MXC_DMA_SSI2_16BIT_RX0, + MXC_DMA_SSI2_16BIT_TX0, + MXC_DMA_SSI2_24BIT_RX0, + MXC_DMA_SSI2_24BIT_TX0, + MXC_DMA_SSI2_8BIT_RX1, + MXC_DMA_SSI2_8BIT_TX1, + MXC_DMA_SSI2_16BIT_RX1, + MXC_DMA_SSI2_16BIT_TX1, + MXC_DMA_SSI2_24BIT_RX1, + MXC_DMA_SSI2_24BIT_TX1, + MXC_DMA_FIR_RX, + MXC_DMA_FIR_TX, + MXC_DMA_CSPI1_RX, + MXC_DMA_CSPI1_TX, + MXC_DMA_CSPI2_RX, + MXC_DMA_CSPI2_TX, + MXC_DMA_CSPI3_RX, + MXC_DMA_CSPI3_TX, + MXC_DMA_ATA_RX, + MXC_DMA_ATA_TX, + MXC_DMA_MEMORY, + MXC_DMA_FIFO_MEMORY, + MXC_DMA_DSP_PACKET_DATA0_RD, + MXC_DMA_DSP_PACKET_DATA0_WR, + MXC_DMA_DSP_PACKET_DATA1_RD, + MXC_DMA_DSP_PACKET_DATA1_WR, + MXC_DMA_DSP_LOG0_CHNL, + MXC_DMA_DSP_LOG1_CHNL, + MXC_DMA_DSP_LOG2_CHNL, + MXC_DMA_DSP_LOG3_CHNL, + MXC_DMA_CSI_RX, + MXC_DMA_SPDIF_16BIT_TX, + MXC_DMA_SPDIF_16BIT_RX, + MXC_DMA_SPDIF_32BIT_TX, + MXC_DMA_SPDIF_32BIT_RX, + MXC_DMA_ASRC_A_RX, + MXC_DMA_ASRC_A_TX, + MXC_DMA_ASRC_B_RX, + MXC_DMA_ASRC_B_TX, + MXC_DMA_ASRC_C_RX, + MXC_DMA_ASRC_C_TX, + MXC_DMA_ASRCA_ESAI, + MXC_DMA_ASRCB_ESAI, + MXC_DMA_ASRCC_ESAI, + MXC_DMA_ASRCA_SSI1_TX0, + MXC_DMA_ASRCA_SSI1_TX1, + MXC_DMA_ASRCA_SSI2_TX0, + MXC_DMA_ASRCA_SSI2_TX1, + MXC_DMA_ASRCB_SSI1_TX0, + MXC_DMA_ASRCB_SSI1_TX1, + MXC_DMA_ASRCB_SSI2_TX0, + MXC_DMA_ASRCB_SSI2_TX1, + MXC_DMA_ESAI_16BIT_RX, + MXC_DMA_ESAI_16BIT_TX, + MXC_DMA_ESAI_24BIT_RX, + MXC_DMA_ESAI_24BIT_TX, + MXC_DMA_TEST_RAM2D2RAM, + MXC_DMA_TEST_RAM2RAM2D, + MXC_DMA_TEST_RAM2D2RAM2D, + MXC_DMA_TEST_RAM2RAM, + MXC_DMA_TEST_HW_CHAINING, + MXC_DMA_TEST_SW_CHAINING +} mxc_dma_device_t; + +/*! This defines the prototype of callback funtion registered by the drivers */ +typedef void (*mxc_dma_callback_t) (void *arg, int error_status, + unsigned int count); + +/*! This defines the type of DMA transfer requested */ +typedef enum mxc_dma_mode { + MXC_DMA_MODE_READ, + MXC_DMA_MODE_WRITE, +} mxc_dma_mode_t; + +/*! This defines the DMA channel parameters */ +typedef struct mxc_dma_channel { + unsigned int active:1; /*!< When there has a active tranfer, it is set to 1 */ + unsigned int lock; /*!< Defines the channel is allocated or not */ + int curr_buf; /*!< Current buffer */ + mxc_dma_mode_t mode; /*!< Read or Write */ + unsigned int channel; /*!< Channel info */ + unsigned int dynamic:1; /*!< Channel not statically allocated when 1 */ + char *dev_name; /*!< Device name */ + void *private; /*!< Private structure for platform */ + mxc_dma_callback_t cb_fn; /*!< The callback function */ + void *cb_args; /*!< The argument of callback function */ +} mxc_dma_channel_t; + +/*! This structure contains the information about a dma transfer */ +typedef struct mxc_dma_requestbuf { + dma_addr_t src_addr; /*!< source address */ + dma_addr_t dst_addr; /*!< destination address */ + int num_of_bytes; /*!< the length of this transfer : bytes */ +} mxc_dma_requestbuf_t; + +/*! This struct contains the information for asrc special*/ +struct dma_channel_asrc_info { + u32 channs; /*!< data channels in asrc */ +}; + +/*! This struct contains the information for device special*/ +struct dma_channel_info { + struct dma_channel_asrc_info asrc; /*!< asrc special information */ +}; + +#if defined(CONFIG_ARCH_MX27) || defined(CONFIG_ARCH_MX21) +#include +#else +#include +#endif + +/*! + * This function is generally called by the driver at open time. + * The DMA driver would do any initialization steps that is required + * to get the channel ready for data transfer. + * + * @param channel_id a pre-defined id. The peripheral driver would specify + * the id associated with its peripheral. This would be + * used by the DMA driver to identify the peripheral + * requesting DMA and do the necessary setup on the + * channel associated with the particular peripheral. + * The DMA driver could use static or dynamic DMA channel + * allocation. + * @param dev_name module name or device name + * @param data the customized parameter for special channel. + * @return returns a negative number on error if request for a DMA channel did not + * succeed, returns the channel number to be used on success. + */ +extern int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name, + struct dma_channel_info *info); + +static inline int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name) +{ + return mxc_dma_request_ext(channel_id, dev_name, NULL); +} + +/*! + * This function is generally called by the driver at close time. The DMA + * driver would do any cleanup associated with this channel. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +extern int mxc_dma_free(int channel_num); + +/*! + * This function would just configure the buffers specified by the user into + * dma channel. The caller must call mxc_dma_enable to start this transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param dma_buf an array of physical addresses to the user defined + * buffers. The caller must guarantee the dma_buf is + * available until the transfer is completed. + * @param num_buf number of buffers in the array + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not be + * added with DMA for transfer. On Success, it returns 0 + */ +extern int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t *dma_buf, + int num_buf, mxc_dma_mode_t mode); + +/*! + * This function would just configure the scatterlist specified by the + * user into dma channel. This is a slight variation of mxc_dma_config(), + * it is provided for the convenience of drivers that have a scatterlist + * passed into them. It is the calling driver's responsibility to have the + * correct physical address filled in the "dma_address" field of the + * scatterlist. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param sg a scatterlist of buffers. The caller must guarantee + * the dma_buf is available until the transfer is + * completed. + * @param num_buf number of buffers in the array + * @param num_of_bytes total number of bytes to transfer. If set to 0, this + * would imply to use the length field of the scatterlist + * for each DMA transfer. Else it would calculate the size + * for each DMA transfer. + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not + * be added with DMA for transfer. On Success, it returns 0 + */ +extern int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, + mxc_dma_mode_t mode); + +/*! + * This function is provided if the driver would like to set/change its + * callback function. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param callback a callback function to provide notification on transfer + * completion, user could specify NULL if he does not wish + * to be notified + * @param arg an argument that gets passed in to the callback + * function, used by the user to do any driver specific + * operations. + * @return this function returns a negative number on error if the callback + * could not be set for the channel or 0 on success + */ +extern int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback, + void *arg); + +/*! + * This stops the DMA channel and any ongoing transfers. Subsequent use of + * mxc_dma_enable() will restart the channel and restart the transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +extern int mxc_dma_disable(int channel_num); + +/*! + * This starts DMA transfer. Or it restarts DMA on a stopped channel + * previously stopped with mxc_dma_disable(). + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +extern int mxc_dma_enable(int channel_num); + +#endif diff --git a/arch/arm/plat-mxc/include/mach/dptc.h b/arch/arm/plat-mxc/include/mach/dptc.h new file mode 100644 index 000000000000..ac897bbea2a7 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/dptc.h @@ -0,0 +1,186 @@ + +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_DPTC_H__ +#define __ASM_ARCH_MXC_DPTC_H__ + +#include + +/*! + * DPTC proc file system entry name + */ +#define PROC_NODE_NAME "dptc" + +int __init init_dptc_controller(dvfs_dptc_params_s * params); + +/*! + * This function enables the DPTC module. this function updates the DPTC + * thresholds, updates the PMIC, unmasks the DPTC interrupt and enables + * the DPTC module + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * + * @return 0 if DPTC module was enabled else returns -EINVAL. + */ +int start_dptc(dvfs_dptc_params_s * params); +/*! + * This function disables the DPTC module. + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * + * @return 0 if DPTC module was disabled else returns -EINVAL. + */ +int stop_dptc(dvfs_dptc_params_s * params); +/*! + * This function updates the drivers current working point index. This index is + * used for access the current DTPC table entry and it corresponds to the + * current CPU working point measured by the DPTC hardware. + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * @param new_wp New working point index value to be set. + * + */ +void set_dptc_wp(dvfs_dptc_params_s * params, int new_wp); +/*! + * This function updates the DPTC threshold registers. + * + * @param dvfs_dptc_tables_ptr pointer to the DPTC translation table. + * @param wp current wp value. + * @param freq_index translation table index of the current CPU + * frequency. + * + */ +void update_dptc_thresholds(dvfs_dptc_tables_s * dptc_tables_ptr, + int wp, int freq_index); +/*! + * This function adds a new entry to the DPTC log buffer. + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * @param dptc_log pointer to the DPTC log buffer structure. + * @param wp value of the working point index written + * to the log buffer. + * @param freq_index value of the frequency index written to + * the log buffer. + * + * @return number of log buffer entries. + * + */ + +void add_dptc_log_entry(dvfs_dptc_params_s * params, + dptc_log_s * dptc_log, int wp, int freq_index); + +/*! + * This function updates the CPU voltage, produced by PMIC, by calling PMIC + * driver functions. + * + * @param dptc_tables_ptr pointer to the DPTC translation table. + * @param wp current wp value. + */ +void set_pmic_voltage(dvfs_dptc_tables_s * dptc_tables_ptr, int wp); + +/*! + * This function enables the DPTC reference circuits. + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * @param rc_state each high bit specifies which + * reference circuite to enable. + * @return 0 on success, error code on failure + */ +int enable_ref_circuits(dvfs_dptc_params_s * params, unsigned char rc_state); + +/*! + * This function disables the DPTC reference circuits. + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * @param rc_state each high bit specifies which + * reference circuite to disable + * @return 0 on success, error code on failure + */ +int disable_ref_circuits(dvfs_dptc_params_s * params, unsigned char rc_state); + +/*! + * This function is the DPTC Interrupt handler. + * This function wakes-up the dptc_workqueue_handler function that handles the + * DPTC interrupt. + */ +void dptc_irq(void); + +/*! + * This function updates the drivers current frequency index.This index is + * used for access the current DTPC table entry and it corresponds to the + * current CPU frequency (each CPU frequency has a separate index number + * according to the loaded DPTC table). + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + * @param freq_index New frequency index value to be set. + * + * @return 0 if the frequency index was updated (the new index is a + * valid index and the DPTC module isn't active) else returns + * -EINVAL. + * + */ +int set_dptc_curr_freq(dvfs_dptc_params_s * params, unsigned int freq_index); + +#ifdef CONFIG_MXC_DVFS_SDMA +/* + * DPTC SDMA callback. + * Updates the PMIC voltage + * + * @param params pointer to the DVFS & DPTC driver parameters structure. + */ +void dptc_sdma_callback(dvfs_dptc_params_s * params); +#endif + +/*! + * This function is called to put the DPTC in a low power state. + * + * @param pdev the device structure used to give information on which + * device to suspend (not relevant for DPTC) + * @param state the power state the device is entering + * + * @return The function always returns 0. + */ +int mxc_dptc_suspend(struct platform_device *pdev, pm_message_t state); + +/*! + * This function is called to put the DPTC in a low power state. + * + */ +void dptc_suspend(void); + +/*! + * This function is called to resume the DPTC from a low power state. + * + * @param pdev the device structure used to give information on which + * device to suspend (not relevant for DPTC) + * + * @return The function always returns 0. + */ +int mxc_dptc_resume(struct platform_device *dev); + +/*! + * This function is called to resume the DPTC from a low power state. + * + */ +void dptc_resume(void); + +/*! + * This function initializes DPTC according to turbo mode status + * + * @param status Turbo mode disable, 1 - turbo mode enabled + * + */ +void dptc_set_turbo_mode(unsigned int status); + +#endif /* __ASM_ARCH_MXC_DPTC_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/dvfs_dptc_struct.h b/arch/arm/plat-mxc/include/mach/dvfs_dptc_struct.h new file mode 100644 index 000000000000..006bcf293d63 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/dvfs_dptc_struct.h @@ -0,0 +1,169 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file arch-mxc/dvfs_dptc_struct.h + * + * @brief MXC dvfs & dptc structure definitions file. + * + * @ingroup PM_MX27 PM_MX31 PM_MXC91321 PM_MXC91311 + */ +#ifndef __ASM_ARCH_MXC_DVFS_DPTC_STRUCT_H__ +#define __ASM_ARCH_MXC_DVFS_DPTC_STRUCT_H__ + +#include +#include + +/*! + * Number of entries in the DPTC log buffer + */ +#define LOG_ENTRIES 1024 + +/*! + * Log buffer Structure.\n + * This structure records the DPTC changes. \n + * This structure can be read by the user using the proc file system DPTC read entry. + */ +typedef struct { + /*! + * Index to the head of the log buffer + */ + int head; + + /*! + * Index to the tail of the log buffer + */ + int tail; + + /*! + * Mutex to allow access to the log buffer + */ + struct semaphore mutex; + + /*! + * Array of log buffer entries + */ + dptc_log_entry_s entries[LOG_ENTRIES]; +} dptc_log_s; + +/*! + * DPTC driver data structure.\n + * Holds all driver parameters and data structures. + */ +typedef struct { + /*! + * This variable holds the current frequency index + */ + int current_freq_index; + + /*! + * Boolean variable, if TRUE the DPTC module is enabled + * if FALSE the DPTC module is disabled + */ + int dptc_is_active; + + /*! + * Boolean variable, if TRUE turbo mode enable + * if FALSE turbo mode disabled + */ + int turbo_mode_active; + + /*! + * Boolean variable, if TRUE the DVFS module is enabled + * if FALSE the DPTC module is disabled + */ + int dvfs_is_active; + + /*! + * Boolean variable, if TRUE the DPTC module is suspended + */ + int suspended; + + unsigned char rc_state; + + /*! + * Pointer to the DVFS & DPTC translation table + */ + dvfs_dptc_tables_s *dvfs_dptc_tables_ptr; + + /*! + * The DPTC log buffer + */ + dptc_log_s dptc_log_buffer; + + /*! + * The DVFS log buffer + */ + unsigned char *dvfs_log_buffer; + + /*! + * The DVFS log buffer physical address (for SDMA) + */ + dma_addr_t dvfs_log_buffer_phys; + +#ifdef CONFIG_MXC_DVFS_SDMA + /*! + * SDMA channel number + */ + int sdma_channel; + + /*! + * This holds the previous working point + */ + int prev_wp; + + /*! + * Wait entry for predictive DVFS + */ + wait_queue_head_t dvfs_pred_wait; +#endif + + /*! + * This holds the current DVFS mode + */ + unsigned int dvfs_mode; + + /*! + * Log buffer read pointer + */ + unsigned char *read_ptr; + + /* + * Number of characters in log buffer + */ + int chars_in_buffer; +} dvfs_dptc_params_s; + +/*! + * This struct contains the array with values of supported frequencies in Hz + */ +typedef struct { + /* + * Number of supported states + */ + unsigned int num_of_states; + /*! + * Array of frequencies + */ + unsigned int *freqs; +} dvfs_states_table; + +/* + * if not defined define TREU and FALSE values. + */ +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif /* TRUE */ + +#endif diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S index 5f01d60da845..92f553baf447 100644 --- a/arch/arm/plat-mxc/include/mach/entry-macro.S +++ b/arch/arm/plat-mxc/include/mach/entry-macro.S @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Lennert Buytenhek - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -18,9 +18,13 @@ .endm .macro get_irqnr_preamble, base, tmp +#ifdef CONFIG_MXC_TZIC + ldr \base, =TZIC_IO_ADDRESS(TZIC_BASE_ADDR) +#else ldr \base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR) #ifdef CONFIG_MXC_IRQ_PRIOR ldr r4, [\base, #AVIC_NIMASK] +#endif #endif .endm @@ -31,6 +35,32 @@ @ and returns its number in irqnr @ and returns if an interrupt occured in irqstat .macro get_irqnr_and_base, irqnr, irqstat, base, tmp +#ifdef CONFIG_MXC_TZIC + @ Load offset & priority of the highest priority + @ interrupt pending. + @ 0xD80 is HIPND0 register + ldr \irqnr, =0 + ldr \irqstat, =0x0D80 +1000: + ldr \tmp, [\irqstat, \base] + cmp \tmp, #0 + bne 1001f + addeq \irqnr, \irqnr, #32 + addeq \irqstat, \irqstat, #4 + cmp \irqnr, #128 + blo 1000b + b 2001f +1001: ldr \irqstat, =1 +1002: tst \tmp, \irqstat + bne 2002f + movs \tmp, \tmp, lsr #1 + addne \irqnr, \irqnr, #1 + bne 1002b +2001: + ldr \irqnr, =0 +2002: + movs \irqnr, \irqnr +#else @ Load offset & priority of the highest priority @ interrupt pending from AVIC_NIVECSR ldr \irqstat, [\base, #0x40] @@ -43,6 +73,7 @@ bicne \tmp, \irqstat, #0xFFFFFFE0 strne \tmp, [\base, #AVIC_NIMASK] streq r4, [\base, #AVIC_NIMASK] +#endif #endif .endm diff --git a/arch/arm/plat-mxc/include/mach/fsl_usb.h b/arch/arm/plat-mxc/include/mach/fsl_usb.h new file mode 100644 index 000000000000..2149d38c91c5 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/fsl_usb.h @@ -0,0 +1,86 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * USB Host side, platform-specific functionality. + */ + +#include +#include + +static void fsl_setup_phy(struct ehci_hcd *ehci, + enum fsl_usb2_phy_modes phy_mode, + int port_offset); + +static inline void fsl_platform_usb_setup(struct ehci_hcd *ehci) +{ + struct fsl_usb2_platform_data *pdata; + + pdata = ehci_to_hcd(ehci)->self.controller->platform_data; + fsl_setup_phy(ehci, pdata->phy_mode, 0); +} + +static inline void fsl_platform_set_host_mode(struct usb_hcd *hcd) +{ + unsigned int temp; + struct fsl_usb2_platform_data *pdata; + + pdata = hcd->self.controller->platform_data; + + if (pdata->xcvr_ops && pdata->xcvr_ops->set_host) + pdata->xcvr_ops->set_host(); + + /* set host mode */ + temp = readl(hcd->regs + 0x1a8); + writel(temp | USBMODE_CM_HOST, hcd->regs + 0x1a8); +} + +/* Needed for enable PP and i2c/serial transceivers */ +static inline void +fsl_platform_set_vbus_power(struct fsl_usb2_platform_data *pdata, int on) +{ + u32 temp; + + /* HCSPARAMS */ + temp = readl(pdata->regs + 0x104); + /* Port Power Control */ + if (temp & HCSPARAMS_PPC) { + temp = readl(pdata->regs + FSL_SOC_USB_PORTSC1); + writel(temp | PORT_POWER, pdata->regs + FSL_SOC_USB_PORTSC1); + } + + if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power) + pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on); +} + +/* Set USB AHB burst length for host */ +static inline void fsl_platform_set_ahb_burst(struct usb_hcd *hcd) +{ + struct fsl_usb2_platform_data *pdata; + unsigned int temp; + + pdata = hcd->self.controller->platform_data; + if (pdata->change_ahb_burst) { + temp = readl(hcd->regs + FSL_SOC_USB_SBUSCFG); + writel((temp & (~(0x7))) | pdata->ahb_burst_mode, + hcd->regs + FSL_SOC_USB_SBUSCFG); + } + + /* Increase TX fifo threshold for USB+ATA for i.mx35 2.0 */ + if (cpu_is_mx35_rev(CHIP_REV_2_0) >= 1) { + temp = readl(hcd->regs + FSL_SOC_USB_TXFILLTUNING); + /* Change TX FIFO threshold to be 0x20 */ + writel((temp & (~(0x3f << 16))) | (0x20 << 16), + hcd->regs + FSL_SOC_USB_TXFILLTUNING); + } +} diff --git a/arch/arm/plat-mxc/include/mach/fsl_usb_gadget.h b/arch/arm/plat-mxc/include/mach/fsl_usb_gadget.h new file mode 100644 index 000000000000..d3c581e70765 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/fsl_usb_gadget.h @@ -0,0 +1,40 @@ +/* + * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * USB Gadget side, platform-specific functionality. + */ + +#include + +/* Needed for i2c/serial transceivers */ +static inline void +fsl_platform_set_device_mode(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->set_device) + pdata->xcvr_ops->set_device(); +} + +static inline void +fsl_platform_pullup_enable(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->pullup) + pdata->xcvr_ops->pullup(1); +} + +static inline void +fsl_platform_pullup_disable(struct fsl_usb2_platform_data *pdata) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->pullup) + pdata->xcvr_ops->pullup(0); +} diff --git a/arch/arm/plat-mxc/include/mach/gpio.h b/arch/arm/plat-mxc/include/mach/gpio.h index 894d2f87c856..9f382e64ccfd 100644 --- a/arch/arm/plat-mxc/include/mach/gpio.h +++ b/arch/arm/plat-mxc/include/mach/gpio.h @@ -33,9 +33,12 @@ struct mxc_gpio_port { void __iomem *base; int irq; + int irq_high; int virtual_irq_start; struct gpio_chip chip; u32 both_edges; + u32 suspend_wakeup; + u32 saved_wakeup; }; int mxc_gpio_init(struct mxc_gpio_port*, int); diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h index 42e4ee37ca1f..b110686e3651 100644 --- a/arch/arm/plat-mxc/include/mach/hardware.h +++ b/arch/arm/plat-mxc/include/mach/hardware.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -22,9 +22,33 @@ #include +/* + * --------------------------------------------------------------------------- + * Processor specific defines + * --------------------------------------------------------------------------- + */ +#define CHIP_REV_1_0 0x10 +#define CHIP_REV_1_1 0x11 +#define CHIP_REV_1_2 0x12 +#define CHIP_REV_1_3 0x13 +#define CHIP_REV_2_0 0x20 +#define CHIP_REV_2_1 0x21 +#define CHIP_REV_2_2 0x22 +#define CHIP_REV_2_3 0x23 +#define CHIP_REV_3_0 0x30 +#define CHIP_REV_3_1 0x31 +#define CHIP_REV_3_2 0x32 + +#define BOARD_REV_1 0x000 +#define BOARD_REV_2 0x100 + #ifdef CONFIG_ARCH_MX3 #include #include +#endif + +#ifdef CONFIG_ARCH_MX35 +#include #include #endif @@ -42,6 +66,44 @@ # include #endif +#ifdef CONFIG_ARCH_MX37 +#include +#endif + +#ifdef CONFIG_ARCH_MX51 +#include +#endif + +#ifdef CONFIG_ARCH_MX25 +#include +#endif + +#ifndef __ASSEMBLY__ +extern unsigned int system_rev; +#define board_is_rev(rev) (((system_rev & 0x0F00) == rev) ? 1 : 0) +#endif + #include +/*! + * Register an interrupt handler for the SMN as well as the SCC. In some + * implementations, the SMN is not connected at all, and in others, it is + * on the same interrupt line as the SCM. Comment this line out accordingly + */ +#define USE_SMN_INTERRUPT + +/*! + * This option is used to set or clear the RXDMUXSEL bit in control reg 3. + * Certain platforms need this bit to be set in order to receive Irda data. + */ +#define MXC_UART_IR_RXDMUX 0x0004 +/*! + * This option is used to set or clear the RXDMUXSEL bit in control reg 3. + * Certain platforms need this bit to be set in order to receive UART data. + */ +#define MXC_UART_RXDMUX 0x0004 + +#ifndef MXC_INT_FORCE +#define MXC_INT_FORCE -1 +#endif #endif /* __ASM_ARCH_MXC_HARDWARE_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/hw_events.h b/arch/arm/plat-mxc/include/mach/hw_events.h new file mode 100644 index 000000000000..f0aa3ad7a266 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/hw_events.h @@ -0,0 +1,65 @@ +/* + * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * hw_events.h + * include the headset/cvbs interrupt detect + */ + +#ifndef HW_EVENT_H +#define HW_EVENT_H + +#define HW_EVENT_GROUP 2 +#define HWE_DEF_PRIORITY 1 +#define HWE_HIGH_PRIORITY 0 + +typedef enum { + + HWE_PHONEJACK_PLUG = 0, + HWE_BAT_CHARGER_PLUG, + HWE_BAT_CHARGER_OVERVOLTAGE, + HWE_BAT_BATTERY_LOW, + HWE_BAT_POWER_FAILED, + HWE_BAT_CHARGER_FULL, + HWE_POWER_KEY, +} HW_EVENT_T; + +typedef enum { + + PJT_NONE = 0, + PJT_CVBS, + PJT_HEADSET, +} PHONEJACK_TYPE; + +typedef enum { + + PWRK_UNPRESS = 0, + PWRK_PRESS, +} POWERKEY_TYPE; + +typedef enum { + + UNPLUG = 0, + PLUGGED, +} PLUG_TYPE; + +struct mxc_hw_event { + unsigned int event; + int args; +}; + +#ifdef __KERNEL__ +extern int hw_event_send(int priority, struct mxc_hw_event *new_event); +#endif + +#endif /* HW_EVENT_H */ diff --git a/arch/arm/plat-mxc/include/mach/io.h b/arch/arm/plat-mxc/include/mach/io.h index b4f2de769466..311bb6337b64 100644 --- a/arch/arm/plat-mxc/include/mach/io.h +++ b/arch/arm/plat-mxc/include/mach/io.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -14,29 +14,33 @@ /* Allow IO space to be anywhere in the memory */ #define IO_SPACE_LIMIT 0xffffffff -#ifdef CONFIG_ARCH_MX3 -#define __arch_ioremap __mx3_ioremap -#define __arch_iounmap __iounmap +extern void __iomem *__mxc_ioremap(unsigned long cookie, size_t size, + unsigned int mtype); -static inline void __iomem * -__mx3_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) -{ - if (mtype == MT_DEVICE) { - /* Access all peripherals below 0x80000000 as nonshared device - * but leave l2cc alone. - */ - if ((phys_addr < 0x80000000) && ((phys_addr < 0x30000000) || - (phys_addr >= 0x30000000 + SZ_1M))) - mtype = MT_DEVICE_NONSHARED; - } - - return __arm_ioremap(phys_addr, size, mtype); -} -#endif +#define __arch_ioremap(a, s, f) __mxc_ioremap(a, s, f) +#define __arch_iounmap __iounmap /* io address mapping macro */ #define __io(a) __typesafe_io(a) #define __mem_pci(a) (a) +/*! + * This function is called to read a CPLD register over CSPI. + * + * @param offset number of the cpld register to be read + * + * @return Returns 0 on success -1 on failure. + */ +unsigned int __weak spi_cpld_read(unsigned int offset); + +/*! + * This function is called to write to a CPLD register over CSPI. + * + * @param offset number of the cpld register to be written + * @param reg_val value to be written + * + * @return Returns 0 on success -1 on failure. + */ +unsigned int __weak spi_cpld_write(unsigned int offset, unsigned int reg_val); #endif diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h index 518a36504b88..59a9c4548634 100644 --- a/arch/arm/plat-mxc/include/mach/irqs.h +++ b/arch/arm/plat-mxc/include/mach/irqs.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -12,9 +12,9 @@ #define __ASM_ARCH_MXC_IRQS_H__ /* - * So far all i.MX SoCs have 64 internal interrupts + * So far all i.MX SoCs have 128 internal interrupts */ -#define MXC_INTERNAL_IRQS 64 +#define MXC_INTERNAL_IRQS 128 #define MXC_GPIO_IRQ_START MXC_INTERNAL_IRQS @@ -22,8 +22,14 @@ #define MXC_GPIO_IRQS (32 * 4) #elif defined CONFIG_ARCH_MX2 #define MXC_GPIO_IRQS (32 * 6) -#elif defined CONFIG_ARCH_MX3 +#elif defined CONFIG_ARCH_MX25 +#define MXC_GPIO_IRQS (32 * 4) +#elif defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX35 +#define MXC_GPIO_IRQS (32 * 3) +#elif defined CONFIG_ARCH_MX37 #define MXC_GPIO_IRQS (32 * 3) +#elif defined CONFIG_ARCH_MX51 +#define MXC_GPIO_IRQS (32 * 4) #endif /* @@ -33,7 +39,14 @@ * within sensible limits. */ #define MXC_BOARD_IRQ_START (MXC_INTERNAL_IRQS + MXC_GPIO_IRQS) +#ifdef CONFIG_MXC_PSEUDO_IRQS +#define MXC_PSEUDO_IO_BASE (MXC_BOARD_IRQ_START + 16) +#define MXC_MAX_PSEUDO_IO_LINES 16 +#define MXC_BOARD_IRQS 32 +#else #define MXC_BOARD_IRQS 16 +#define MXC_MAX_PSEUDO_IO_LINES 0 +#endif #define MXC_IPU_IRQ_START (MXC_BOARD_IRQ_START + MXC_BOARD_IRQS) @@ -52,4 +65,17 @@ extern int imx_irq_set_priority(unsigned char irq, unsigned char prio); /* switch betwean IRQ and FIQ */ extern int mxc_set_irq_fiq(unsigned int irq, unsigned int type); +#define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_BOARD_IRQ_START) + +/* + * This function is used to get the AVIC Lo and Hi interrupts + * that are enabled as wake up sources to wake up the core from suspend + */ +void mxc_get_wake_irq(u32 * wake_src[]); + +/* Define interrupt number for OProfile */ +#if defined CONFIG_ARCH_MX51 +#define MXC_INT_PMU 77 +#endif + #endif /* __ASM_ARCH_MXC_IRQS_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/memory.h b/arch/arm/plat-mxc/include/mach/memory.h index 6065e00176ed..c898f884a371 100644 --- a/arch/arm/plat-mxc/include/mach/memory.h +++ b/arch/arm/plat-mxc/include/mach/memory.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -11,6 +11,9 @@ #ifndef __ASM_ARCH_MXC_MEMORY_H__ #define __ASM_ARCH_MXC_MEMORY_H__ +#include +#include + #if defined CONFIG_ARCH_MX1 #define PHYS_OFFSET UL(0x08000000) #elif defined CONFIG_ARCH_MX2 @@ -24,6 +27,19 @@ #define PHYS_OFFSET UL(0x80000000) #endif +#ifdef CONFIG_ARCH_MX51 +#define PHYS_OFFSET UL(0x90000000) +#endif + +#ifdef CONFIG_ARCH_MX37 +#define PHYS_OFFSET UL(0x40000000) +#endif + +#ifndef PHYS_OFFSET +#define PHYS_OFFSET UL(0x80000000) +#endif + +/* Size of contiguous memory for DMA and other h/w blocks */ #if defined(CONFIG_MX1_VIDEO) /* * Increase size of DMA-consistent memory region. @@ -40,4 +56,35 @@ #define CONSISTENT_DMA_SIZE SZ_8M #endif /* CONFIG_MX3_VIDEO */ +#ifdef CONFIG_ARCH_MX51 +#define CONSISTENT_DMA_SIZE (64 * SZ_1M) +#else +#define CONSISTENT_DMA_SIZE (32 * SZ_1M) +#endif + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_DMA_ZONE_SIZE +#define MXC_DMA_ZONE_SIZE ((CONFIG_DMA_ZONE_SIZE * SZ_1M) >> PAGE_SHIFT) +#else +#define MXC_DMA_ZONE_SIZE ((12 * SZ_1M) >> PAGE_SHIFT) +#endif + +static inline void __arch_adjust_zones(int node, unsigned long *zone_size, + unsigned long *zhole_size) +{ + if (node != 0) + return; + /* Create separate zone to reserve memory for DMA */ + zone_size[1] = zone_size[0] - MXC_DMA_ZONE_SIZE; + zone_size[0] = MXC_DMA_ZONE_SIZE; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + +#define arch_adjust_zones(node, size, holes) \ + __arch_adjust_zones(node, size, holes) + +#endif + #endif /* __ASM_ARCH_MXC_MEMORY_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mmc.h b/arch/arm/plat-mxc/include/mach/mmc.h index de2128dada5c..80cc61c175ea 100644 --- a/arch/arm/plat-mxc/include/mach/mmc.h +++ b/arch/arm/plat-mxc/include/mach/mmc.h @@ -33,4 +33,21 @@ struct imxmmc_platform_data { void (*setpower)(struct device *, unsigned int vdd); }; +struct mxc_mmc_platform_data { + unsigned int ocr_mask; /* available voltages */ + unsigned int vendor_ver; + unsigned int caps; + unsigned int min_clk; + unsigned int max_clk; + unsigned int clk_flg; /* 1 clock enable, 0 not */ + unsigned int reserved:16; + unsigned int card_fixed:1; + unsigned int card_inserted_state:1; +// u32 (*translate_vdd)(struct device *, unsigned int); + unsigned int (*status) (struct device *); + int (*wp_status) (struct device *); + char *power_mmc; + char *clock_mmc; +}; + #endif diff --git a/arch/arm/plat-mxc/include/mach/mtd-xip.h b/arch/arm/plat-mxc/include/mach/mtd-xip.h index 1ab1bba5688d..0e74f19b1eae 100644 --- a/arch/arm/plat-mxc/include/mach/mtd-xip.h +++ b/arch/arm/plat-mxc/include/mach/mtd-xip.h @@ -4,6 +4,7 @@ * Do not include this file directly. It's included from linux/mtd/xip.h * * Copyright (C) 2008 Darius Augulis , Teltonika, Inc. + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,12 +12,14 @@ * */ +#include +#include +#include #include #ifndef __ARCH_IMX_MTD_XIP_H__ #define __ARCH_IMX_MTD_XIP_H__ -#ifdef CONFIG_ARCH_MX1 /* AITC registers */ #define AITC_BASE IO_ADDRESS(AVIC_BASE_ADDR) #define NIPNDH (AITC_BASE + 0x58) @@ -26,9 +29,34 @@ /* MTD macros */ #define xip_irqpending() ((__raw_readl(INTENABLEH) & __raw_readl(NIPNDH)) \ || (__raw_readl(INTENABLEL) & __raw_readl(NIPNDL))) +#ifdef CONFIG_ARCH_MX1 #define xip_currtime() (__raw_readl(TIMER_BASE + MXC_TCN)) #define xip_elapsed_since(x) (signed)((__raw_readl(TIMER_BASE + MXC_TCN) - (x)) / 96) #define xip_cpu_idle() asm volatile ("mcr p15, 0, %0, c7, c0, 4" :: "r" (0)) +#else + +extern struct clocksource *mtd_xip_clksrc; + +#define xip_currtime() (unsigned long)clocksource_read(mtd_xip_clksrc) + +#if CLOCK_TICK_RATE > 1000000 +#define NUMERATOR 1 +#define DENOMINATOR (CLOCK_TICK_RATE/1000000 + 1) +#else +#define NUMERATOR (1000000/CLOCK_TICK_RATE) +#define DENOMINATOR 1 +#endif + +static inline unsigned long xip_elapsed_since(unsigned long x) +{ + return (((xip_currtime() - x) * NUMERATOR) / DENOMINATOR); +} + +/* + * Wait For Interrupt command for XIP kernel to put CPU in Idle mode + */ +#define xip_cpu_idle() arch_idle() + #endif /* CONFIG_ARCH_MX1 */ #endif /* __ARCH_IMX_MTD_XIP_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mx25.h b/arch/arm/plat-mxc/include/mach/mx25.h new file mode 100644 index 000000000000..6b1622906c20 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mx25.h @@ -0,0 +1,462 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file arch-mxc/mx25.h + * @brief This file contains register definitions. + * + * @ingroup MSL_MX25 + */ + +#ifndef __ASM_ARCH_MXC_MX25_H__ +#define __ASM_ARCH_MXC_MX25_H__ + +#ifndef __ASM_ARCH_MXC_HARDWARE_H__ +#error "Do not include directly." +#endif + +/*! + * Define this option to specify we are using the newer SDMA module. + */ +#define MXC_SDMA_V2 + +/* + * MX25 memory map: + * + * Virt Phys Size What + * --------------------------------------------------------------------------- + * FC000000 43F00000 1M AIPS 1 + * FC100000 50000000 1M SPBA + * FC200000 53F00000 1M AIPS 2 + * FC300000 60000000 1M ROMPATCH (128M) + * FC400000 68000000 1M ASIC (128M) + * FC500000 78000000 128K FBC RAM (IRAM) + * 80000000 256M SDRAM0 + * 90000000 256M SDRAM1 + * A0000000 128M CS0 Flash + * A8000000 128M CS1 Flash + * B0000000 32M CS2 SRAM + * B2000000 32M CS3 + * B4000000 32M CS4 + * B6000000 32M CS5 + * FC520000 B8000000 64K SDRAM, WEIM, M3IF, EMI controllers + * FC530000 BB000000 8K NFC + */ + +/* + * IRAM + */ +#define IRAM_BASE_ADDR 0x78000000 /* internal ram */ +#define IRAM_BASE_ADDR_VIRT 0xFC500000 +#define IRAM_SIZE SZ_128K + +#ifndef CONFIG_SDMA_IRAM +#define CONFIG_SDMA_IRAM_SIZE 0 +#endif +#ifdef CONFIG_SND_MXC_SOC_IRAM +#define SND_RAM_SIZE 0x10000 +#else +#define SND_RAM_SIZE 0 +#endif + +#define SND_RAM_BASE_ADDR (IRAM_BASE_ADDR + CONFIG_SDMA_IRAM_SIZE) + +#define USB_IRAM_BASE_ADDR (SND_RAM_BASE_ADDR + SND_RAM_SIZE) +#ifdef CONFIG_USB_STATIC_IRAM_PPH +#define USB_IRAM_SIZE (2*SZ_8K) +#else +#define USB_IRAM_SIZE 0 +#endif + +/* + * AIPS 1 + */ +#define AIPS1_BASE_ADDR 0x43F00000 +#define AIPS1_BASE_ADDR_VIRT 0xFC000000 +#define AIPS1_SIZE SZ_1M + +#define MAX_BASE_ADDR (AIPS1_BASE_ADDR + 0x00004000) +#define CLKCTL_BASE_ADDR (AIPS1_BASE_ADDR + 0x00008000) +#define ETB_SLOT4_BASE_ADDR (AIPS1_BASE_ADDR + 0x0000C000) +#define ETB_SLOT5_BASE_ADDR (AIPS1_BASE_ADDR + 0x00010000) +#define AAPE_BASE_ADDR (AIPS1_BASE_ADDR + 0x00014000) +#define I2C_BASE_ADDR (AIPS1_BASE_ADDR + 0x00080000) +#define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x00084000) +#define CAN1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00088000) +#define CAN3_BASE_ADDR (AIPS1_BASE_ADDR + 0x0008C000) +#define UART1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00090000) +#define UART2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00094000) +#define I2C2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00098000) +#define OWIRE_BASE_ADDR (AIPS1_BASE_ADDR + 0x0009C000) +#define ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A0000) +#define CSPI1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A4000) +#define KPP_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A8000) +#define IOMUXC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000AC000) +#define AUDMUX_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B0000) +#define ECT_A_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B8000) +#define ECT_B_BASE_ADDR (AIPS1_BASE_ADDR + 0x000BC000) + +/* + * SPBA global module enabled #0 + */ +#define SPBA0_BASE_ADDR 0x50000000 +#define SPBA0_BASE_ADDR_VIRT 0xFC100000 +#define SPBA0_SIZE SZ_1M + +#define CSPI3_BASE_ADDR (SPBA0_BASE_ADDR + 0x00004000) +#define UART4_BASE_ADDR (SPBA0_BASE_ADDR + 0x00008000) +#define UART3_BASE_ADDR (SPBA0_BASE_ADDR + 0x0000C000) +#define CSPI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00010000) +#define SSI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00014000) +#define ESAI_BASE_ADDR (SPBA0_BASE_ADDR + 0x00018000) +#define ATA_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00020000) +#define SIM1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00024000) +#define SIM2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00028000) +#define UART5_BASE_ADDR (SPBA0_BASE_ADDR + 0x0002C000) +#define TSC_BASE_ADDR (SPBA0_BASE_ADDR + 0x00030000) +#define SSI1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00034000) +#define FEC_BASE_ADDR (SPBA0_BASE_ADDR + 0x00038000) +#define SPBA_CTRL_BASE_ADDR (SPBA0_BASE_ADDR + 0x0003C000) + +/*! + * defines for SPBA modules + */ +#define SPBA_CSPI3 (0x1 << 2) +#define SPBA_UART4 (0x2 << 2) +#define SPBA_UART3 (0x3 << 2) +#define SPBA_CSPI2 (0x4 << 2) +#define SPBA_SSI2 (0x5 << 2) +#define SPBA_ESAI (0x6 << 2) +#define SPBA_ATA (0x8 << 2) +#define SPBA_SIM1 (0x9 << 2) +#define SPBA_SIM2 (0xA << 2) +#define SPBA_UART5 (0xB << 2) +#define SPBA_ANALOG (0xC << 2) +#define SPBA_SSI1 (0xD << 2) +#define SPBA_FEC (0xE << 2) + +/*! + * Defines for modules using static and dynamic DMA channels + */ +#define MXC_DMA_CHANNEL_IRAM 30 +#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART4_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART4_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART5_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART5_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_SSI1_TX (MXC_DMA_CHANNEL_IRAM + 1) +#else +#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL +#endif +#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ESAI_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ESAI_TX MXC_DMA_DYNAMIC_CHANNEL + +/* + * AIPS 2 + */ +#define AIPS2_BASE_ADDR 0x53F00000 +#define AIPS2_BASE_ADDR_VIRT 0xFC200000 +#define AIPS2_SIZE SZ_1M + +#define CCM_BASE_ADDR (AIPS2_BASE_ADDR + 0x00080000) +#define GPT4_BASE_ADDR (AIPS2_BASE_ADDR + 0x00084000) +#define GPT3_BASE_ADDR (AIPS2_BASE_ADDR + 0x00088000) +#define GPT2_BASE_ADDR (AIPS2_BASE_ADDR + 0x0008C000) +#define GPT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00090000) +#define EPIT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00094000) +#define EPIT2_BASE_ADDR (AIPS2_BASE_ADDR + 0x00098000) +#define GPIO4_BASE_ADDR (AIPS2_BASE_ADDR + 0x0009C000) +#define PWM2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A0000) +#define GPIO3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AD000) +#define PWM3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A8000) +#define SCC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AC000) +#define RNGB_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B0000) +#define MMC_SDHC1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B4000) +#define MMC_SDHC2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B8000) +#define LCDC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000BC000) +#define SLCDC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C0000) +#define PWM4_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C8000) +#define GPIO1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000CC000) +#define GPIO2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D0000) +#define SDMA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D4000) +#define WDOG1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DC000) +#define PWM1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E0000) +#define RTIC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000EC000) +#define IIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F0000) +#define USBOTG_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F4000) +#define OTG_BASE_ADDR USBOTG_BASE_ADDR +#define CSI_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F8000) +#define DRYICE_BASE_ADDR (AIPS2_BASE_ADDR + 0x000FC000) +#define SRTC_BASE_ADDR (DRYICE_BASE_ADDR) + +/* + * ROMP and ASIC + */ +#define ROMP_BASE_ADDR 0x60000000 +#define ROMP_BASE_ADDR_VIRT 0xFC300000 +#define ROMP_SIZE SZ_1M + +#define ASIC_BASE_ADDR 0x68000000 +#define ASIC_BASE_ADDR_VIRT 0xFC400000 +#define ASIC_SIZE SZ_1M +#define AVIC_BASE_ADDR ASIC_BASE_ADDR +#define AVIC_BASE_ADDR_VIRT ASIC_BASE_ADDR_VIRT +#define AVIC_SIZE ASIC_SIZE + +/* + * SDRAM, WEIM, M3IF, EMI controllers + */ +#define X_MEMC_BASE_ADDR 0xB8000000 +#define X_MEMC_BASE_ADDR_VIRT 0xFC520000 +#define X_MEMC_SIZE SZ_64K + +#define SDRAMC_BASE_ADDR (X_MEMC_BASE_ADDR + 0x1000) +#define WEIM_BASE_ADDR (X_MEMC_BASE_ADDR + 0x2000) +#define M3IF_BASE_ADDR (X_MEMC_BASE_ADDR + 0x3000) +#define EMI_CTL_BASE_ADDR (X_MEMC_BASE_ADDR + 0x4000) + +/* + * NFC controller + */ +#define NFC_BASE_ADDR 0xBB000000 +#define NFC_BASE_ADDR_VIRT 0xFC530000 +#define NFC_SIZE SZ_8K + +/* + * Memory regions and CS + */ +#define CSD0_BASE_ADDR 0x80000000 +#define CSD1_BASE_ADDR 0x90000000 + +#define SDRAM_BASE_ADDR CSD0_BASE_ADDR + +#define CS0_BASE_ADDR 0xA0000000 +#define CS1_BASE_ADDR 0xA8000000 +#define CS2_BASE_ADDR 0xB0000000 +#define CS3_BASE_ADDR 0xB2000000 +#define CS4_BASE_ADDR 0xB4000000 +#define CS4_SIZE SZ_32M +#define CS5_BASE_ADDR 0xB6000000 +#define CS5_SIZE SZ_32M + +/*! + * This macro defines the physical to virtual address mapping for all the + * peripheral modules. It is used by passing in the physical address as x + * and returning the virtual address. If the physical address is not mapped, + * it returns 0xDEADBEEF + */ +#define IO_ADDRESS(x) \ + (void __force __iomem *) \ + (((x >= AIPS1_BASE_ADDR) && (x < (AIPS1_BASE_ADDR + AIPS1_SIZE))) ? AIPS1_IO_ADDRESS(x):\ + ((x >= SPBA0_BASE_ADDR) && (x < (SPBA0_BASE_ADDR + SPBA0_SIZE))) ? SPBA0_IO_ADDRESS(x):\ + ((x >= AIPS2_BASE_ADDR) && (x < (AIPS2_BASE_ADDR + AIPS2_SIZE))) ? AIPS2_IO_ADDRESS(x):\ + ((x >= ROMP_BASE_ADDR) && (x < (ROMP_BASE_ADDR + ROMP_SIZE))) ? ROMP_IO_ADDRESS(x):\ + ((x >= ASIC_BASE_ADDR) && (x < (ASIC_BASE_ADDR + AVIC_SIZE))) ? ASIC_IO_ADDRESS(x):\ + ((x >= IRAM_BASE_ADDR) && (x < (IRAM_BASE_ADDR + IRAM_SIZE))) ? IRAM_IO_ADDRESS(x):\ + ((x >= X_MEMC_BASE_ADDR) && (x < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? X_MEMC_IO_ADDRESS(x):\ + ((x >= NFC_BASE_ADDR) && (x < (NFC_BASE_ADDR + NFC_SIZE))) ? NFC_IO_ADDRESS(x):\ + 0xDEADBEEF) + +/* + * define the address mapping macros: in physical address order + */ + +#define AIPS1_IO_ADDRESS(x) \ + (((x) - AIPS1_BASE_ADDR) + AIPS1_BASE_ADDR_VIRT) + +#define SPBA0_IO_ADDRESS(x) \ + (((x) - SPBA0_BASE_ADDR) + SPBA0_BASE_ADDR_VIRT) + +#define AIPS2_IO_ADDRESS(x) \ + (((x) - AIPS2_BASE_ADDR) + AIPS2_BASE_ADDR_VIRT) + +#define ROMP_IO_ADDRESS(x) \ + (((x) - ROMP_BASE_ADDR) + ROMP_BASE_ADDR_VIRT) + +#define ASIC_IO_ADDRESS(x) \ + (((x) - ASIC_BASE_ADDR) + ASIC_BASE_ADDR_VIRT) + +/* for entry-macro.S */ +#define AVIC_IO_ADDRESS(x) ASIC_IO_ADDRESS(x) + +#define IRAM_IO_ADDRESS(x) \ + (((x) - IRAM_BASE_ADDR) + IRAM_BASE_ADDR_VIRT) + +#define X_MEMC_IO_ADDRESS(x) \ + (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT) + +#define NFC_IO_ADDRESS(x) \ + (((x) - NFC_BASE_ADDR) + NFC_BASE_ADDR_VIRT) + +#define IS_MEM_DEVICE_NONSHARED(x) 0 + +/* + * DMA request assignments + */ +#define DMA_REQ_EXTREQ0 0 +#define DMA_REQ_CCM 1 +#define DMA_REQ_ATA_TX_END 2 +#define DMA_REQ_ATA_TX 3 +#define DMA_REQ_ATA_RX 4 +#define DMA_REQ_CSPI2_RX 6 +#define DMA_REQ_CSPI2_TX 7 +#define DMA_REQ_CSPI1_RX 8 +#define DMA_REQ_CSPI1_TX 9 +#define DMA_REQ_UART3_RX 10 +#define DMA_REQ_UART3_TX 11 +#define DMA_REQ_UART4_RX 12 +#define DMA_REQ_UART4_TX 13 +#define DMA_REQ_EXTREQ1 14 +#define DMA_REQ_EXTREQ2 15 +#define DMA_REQ_UART2_RX 16 +#define DMA_REQ_UART2_TX 17 +#define DMA_REQ_UART1_RX 18 +#define DMA_REQ_UART1_TX 19 +#define DMA_REQ_SSI2_RX1 22 +#define DMA_REQ_SSI2_TX1 23 +#define DMA_REQ_SSI2_RX0 24 +#define DMA_REQ_SSI2_TX0 25 +#define DMA_REQ_SSI1_RX1 26 +#define DMA_REQ_SSI1_TX1 27 +#define DMA_REQ_SSI1_RX0 28 +#define DMA_REQ_SSI1_TX0 29 +#define DMA_REQ_NFC 30 +#define DMA_REQ_ECT 31 +#define DMA_REQ_ESAI_RX 32 +#define DMA_REQ_ESAI_TX 33 +#define DMA_REQ_CSPI3_RX 34 +#define DMA_REQ_CSPI3_TX 35 +#define DMA_REQ_SIM2_RX 36 +#define DMA_REQ_SIM2_TX 37 +#define DMA_REQ_SIM1_RX 38 +#define DMA_REQ_SIM1_TX 39 +#define DMA_REQ_TSC_GCQ 44 +#define DMA_REQ_TSC_TCQ 45 +#define DMA_REQ_UART5_RX 46 +#define DMA_REQ_UART5_TX 47 + +/* + * Interrupt numbers + */ +#define MXC_INT_CSPI3 0 +#define MXC_INT_GPT4 1 +#define MXC_INT_OWIRE 2 +#define MXC_INT_I2C 3 +#define MXC_INT_I2C2 4 +#define MXC_INT_UART4 5 +#define MXC_INT_RTIC 6 +#define MXC_INT_ESAI 7 +#define MXC_INT_SDHC2 8 +#define MXC_INT_SDHC1 9 +#define MXC_INT_I2C3 10 +#define MXC_INT_SSI2 11 +#define MXC_INT_SSI1 12 +#define MXC_INT_CSPI2 13 +#define MXC_INT_CSPI1 14 +#define MXC_INT_ATA 15 +#define MXC_INT_GPIO3 16 +#define MXC_INT_CSI 17 +#define MXC_INT_UART3 18 +#define MXC_INT_IIM 19 +#define MXC_INT_SIM1 20 +#define MXC_INT_SIM2 21 +#define MXC_INT_RNG 22 +#define MXC_INT_GPIO4 23 +#define MXC_INT_KPP 24 +#define MXC_INT_DRYICE_NORM 25 +#define MXC_INT_PWM 26 +#define MXC_INT_EPIT2 27 +#define MXC_INT_EPIT1 28 +#define MXC_INT_GPT3 29 +#define MXC_INT_POWER_FAIL 30 +#define MXC_INT_CRM 31 +#define MXC_INT_UART2 32 +#define MXC_INT_NANDFC 33 +#define MXC_INT_SDMA 34 +#define MXC_INT_USB_HTG 35 +#define MXC_INT_PWM2 36 +#define MXC_INT_USB_OTG 37 +#define MXC_INT_SLCDC 38 +#define MXC_INT_LCDC 39 +#define MXC_INT_UART5 40 +#define MXC_INT_PWM3 41 +#define MXC_INT_PWM4 42 +#define MXC_INT_CAN1 43 +#define MXC_INT_CAN2 44 +#define MXC_INT_UART1 45 +#define MXC_INT_TSC 46 +#define MXC_INT_ECT 48 +#define MXC_INT_SCC_SCM 49 +#define MXC_INT_SCC_SMN 50 +#define MXC_INT_GPIO2 51 +#define MXC_INT_GPIO1 52 +#define MXC_INT_GPT2 53 +#define MXC_INT_GPT1 54 +#define MXC_INT_WDOG 55 +#define MXC_INT_DRYICE_SEC 56 +#define MXC_INT_FEC 57 +#define MXC_INT_EXT_INT5 58 +#define MXC_INT_EXT_INT4 59 +#define MXC_INT_EXT_INT3 60 +#define MXC_INT_EXT_INT2 61 +#define MXC_INT_EXT_INT1 62 +#define MXC_INT_EXT_INT0 63 + +#define MXC_INT_GPT MXC_INT_GPT1 + +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x00 +#define GPIO_GDIR 0x04 +#define GPIO_PSR 0x08 +#define GPIO_ICR1 0x0C +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_ISR 0x18 +#define GPIO_INT_LOW_LEV 0x0 +#define GPIO_INT_HIGH_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_FALL_EDGE 0x3 +#define GPIO_INT_NONE 0x4 + +#define MXC_TIMER_GPT1 1 +#define MXC_TIMER_GPT2 2 +#define MXC_TIMER_GPT3 3 +#define MXC_TIMER_GPT4 4 + +/*! + * NFMS bit in RCSR register for pagesize of nandflash + */ +#define NFMS (*((volatile u32 *)IO_ADDRESS(CCM_BASE_ADDR + 0x28))) +#define NFMS_NF_DWIDTH 14 +#define NFMS_NF_PG_SZ 8 + +#endif /* __ASM_ARCH_MXC_MX25_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mx2_dma.h b/arch/arm/plat-mxc/include/mach/mx2_dma.h new file mode 100644 index 000000000000..8f5ae658f96b --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mx2_dma.h @@ -0,0 +1,261 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_MX2_H__ +#define __ASM_ARCH_MXC_MX2_H__ + +/*! + * @defgroup DMA_MX27 DMA driver for i.MX27 + */ + +/*! + *@file arch-mxc/mx2_dma.h + *@brief DMA driver header file + * + * @ingroup DMA_MX27 + * + */ + +#include +#include +#include + +#define MXC_DMA_INTR_0 32 + +#define DMA_DCR 0x000 /* 32bit dma control reg */ +#define DMA_DISR 0x004 /* 32bit dma interrupt status reg */ +#define DMA_DIMR 0x008 /* 32bit dma interrupt mask reg */ +#define DMA_DBTOSR 0x00c /* 32bit dma burst timeout stat reg */ +#define DMA_DRTOSR 0x010 /* 32bit dma req timeout status reg */ +#define DMA_DSESR 0x014 /* 32bit dma transfer err status reg */ +#define DMA_DBOSR 0x018 /* 32bit dma buffer overflow stat reg */ +#define DMA_DBTOCR 0x01c /* 32bit dma burst timeout ctrl reg */ + +#define DMA_WSRA 0x040 /* 32bit dma W-size A reg */ +#define DMA_XSRA 0x044 /* 32bit dma X-size A reg */ +#define DMA_YSRA 0x048 /* 32bit dma Y-size A reg */ +#define DMA_WSRB 0x04C /* 32bit dma W-size B reg */ +#define DMA_XSRB 0x050 /* 32bit dma X-size B reg */ +#define DMA_YSRB 0x054 /* 32bit dma Y-size B reg */ + +#define DMA_CH_BASE(x) (0x080+0x040*(x)) + +#define DMA_SAR(x) (DMA_CH_BASE(x)+0x000) +#define DMA_DAR(x) (DMA_CH_BASE(x)+0x004) +#define DMA_CNTR(x) (DMA_CH_BASE(x)+0x008) +#define DMA_CCR(x) (DMA_CH_BASE(x)+0x00C) /* 32bit dma ch0 control reg */ +#define DMA_RSSR(x) (DMA_CH_BASE(x)+0x010) /* 32bit dma ch0 req source sel reg */ +#define DMA_BLR(x) (DMA_CH_BASE(x)+0x014) /* 32bit dma ch0 burst lenght reg */ +#define DMA_RTOR(x) (DMA_CH_BASE(x)+0x018) /* 32bit dma ch0 req time out reg */ +#define DMA_BUCR(x) (DMA_CH_BASE(x)+0x018) /* 32bit dma ch0 bus utilization reg */ +#define DMA_CCNR(x) (DMA_CH_BASE(x)+0x01C) /* 32bit dma ch0 */ + +#define DMA_TCR 0x480 /*32bit dma test control reg */ +#define DMA_TFIFOA 0x484 /* 32bit dma test fifo A reg */ +#define DMA_TDRR 0x488 /* 32bit dma test request reg */ +#define DMA_TDIPR 0x48c /* 32bit dma test in progress reg */ +#define DMA_TFIFOB 0x490 /* 32bit dma test fifo B reg */ + +/*! + * This defines maximum DMA address + */ +#define MAX_DMA_ADDRESS 0xffffffff + +#define MXC_DMA_CHANNELS 16 +#define MAX_DMA_CHANNELS MXC_DMA_CHANNELS + +#define MX_DMA_CHANNELS MXC_DMA_CHANNELS + +/*!@def DMA_MEM_SIZE_8 DMA access port size, 8 bit*/ +/*!@def DMA_MEM_SIZE_16 DMA access port size, 16 bit*/ +/*!@def DMA_MEM_SIZE_32 DMA access port size, 32 bit*/ +#define DMA_MEM_SIZE_8 0x1 +#define DMA_MEM_SIZE_16 0x2 +#define DMA_MEM_SIZE_32 0x0 + +/*!@def DMA_TYPE_LINEAR DMA transfer type, linear*/ +/*!@def DMA_TYPE_2D DMA transfer type, 2D*/ +/*!@def DMA_TYPE_FIFO DMA transfer type, FIFO*/ +/*!@def DMA_TYPE_EBE DMA transfer type, end-of-burst enable FIFO*/ +#define DMA_TYPE_LINEAR 0x0 +#define DMA_TYPE_2D 0x01 +#define DMA_TYPE_FIFO 0x2 +#define DMA_TYPE_EBE 0x3 + +/*!@def DMA_DONE DMA transfer done*/ +/*!@def DMA_BURST_TIMEOUT DMA transfer timeout error*/ +/*!@def DMA_REQUEST_TIMEOUT DMA transfer request timeout error*/ +/*!@def DMA_TRANSFER_ERROR DMA transfer error*/ +/*!@def DMA_BUFFER_OVERFLOW DMA transfer buffer overflow error*/ +#define DMA_DONE 0x1000 +#define DMA_BURST_TIMEOUT 0x1 +#define DMA_REQUEST_TIMEOUT 0x2 +#define DMA_TRANSFER_ERROR 0x4 +#define DMA_BUFFER_OVERFLOW 0x8 + +/*!@brief DMA control register*/ +typedef struct { + volatile u32 CEN:1; /*!< Dma channel enable */ + volatile u32 FRC:1; /*!< Force a dma cycle bit */ + volatile u32 RPT:1; /*!< Repeat bit */ + volatile u32 REN:1; /*!< Request enable bit */ + volatile u32 SSIZ:2; /*!< Source port size, 2 bit in length */ + volatile u32 DSIZ:2; /*!< Dest port size, 2 bit in length */ + volatile u32 MSEL:1; /*!< 2D memory register set bit */ + volatile u32 MDIR:1; /*!< Transfer direction, inversed or normal */ + volatile u32 SMOD:2; /*!< Source mode, 2 bit in length */ + volatile u32 DMOD:2; /*!< Dest mode, 2 bit in length */ + volatile u32 ACRPT:1; /*!< Auto clear repeat bit */ + volatile u32 Reserver:17; /*!< Reserved bits */ + +} dma_regs_control; + +#define DMA_CTL_CEN 0x1 +#define DMA_CTL_FRC 0x2 +#define DMA_CTL_RPT 0x4 +#define DMA_CTL_REN 0x8 + +#define DMA_CTL_MSEL 0x100 +#define DMA_CTL_MDIR 0x200 +#define DMA_CTL_ACRPT 0x4000 + +#define DMA_CTL_GET_SSIZ(x) (((x)>>4)&0x3) +#define DMA_CTL_GET_DSIZ(x) (((x)>>6)&0x3) +#define DMA_CTL_GET_SMOD(x) (((x)>>10)&0x3) +#define DMA_CTL_GET_DMOD(x) (((x)>>12)&0x3) + +#define DMA_CTL_SET_SSIZ(x,value) do{ \ + (x)&=~(0x3<<4); \ + (x)|=(value)<<4; \ + }while(0) + +#define DMA_CTL_SET_DSIZ(x,value) do{ \ + (x)&=~(0x3<<6); \ + (x)|=(value)<<6; \ + }while(0) + +#define DMA_CTL_SET_SMOD(x,value) do{ \ + (x)&=~(0x3<<10); \ + (x)|=(value)<<10; \ + }while(0) + +#define DMA_CTL_SET_DMOD(x,value) do{ \ + (x)&=~(0x3<<12); \ + (x)|=(value)<<12; \ + }while(0) + +typedef struct { + volatile u32 SourceAddr; + volatile u32 DestAddr; + volatile u32 Count; + volatile u32 Ctl; + volatile u32 RequestSource; + volatile u32 BurstLength; + union { + volatile u32 ReqTimeout; + volatile u32 BusUtilt; + }; + volatile u32 transferd; +} dma_regs_t; + +#ifndef TRANSFER_32BIT +/*! + * This defines DMA access data size + */ + +#define TRANSFER_8BIT DMA_MEM_SIZE_8 +#define TRANSFER_16BIT DMA_MEM_SIZE_16 +#define TRANSFER_32BIT DMA_MEM_SIZE_32 + +#endif + +/*! + * This defines maximum device name length passed during mxc_request_dma(). + */ +#define MAX_DEVNAME_LENGTH 32 +#define MAX_BD_SIZE 32 + +/*! + * Structure containing dma channel parameters. + */ +typedef struct { + unsigned long dma_chan; /*!< the dma channel information: dynamic or channel number */ + u32 mode:1; /*!< the initialized dma mode, 0 for dma read, 1 for dma write */ + u32 rto_en:1; /*!< enable request-timeout. It is valid when REN=1 */ + u32 dir:1; /*!< Transfer direction, 0 for increment, 1 for decrement */ + u32 dma_chaining:1; /*!< Autoclear bit for chainbuffer */ + u32 ren:1; /*!< enable transfer based request signal */ + u32 M2D_Valid:1; /*!< enable 2D address module. 0 for disable it. 1 for enabled it */ + u32 msel:1; /*!<2D memory selection, 0 for set A, 1 for set B */ + u32 burstLength; /*!< Channel burst length */ + u32 request; /*!< Request source. */ + u32 busuntils; /*!< when REN=0, Bus utilization, otherwise it it request timeout */ + u32 sourceType; /*!< Source type, see DMA_TYPE_* */ + u32 sourcePort; /*!< Source port size, see DMA_MEM_SIZE_* */ + u32 destType; /*!< Destination type, see DMA_TYPE_* */ + u32 destPort; /*!< Destination port size, see DMA_MEM_SIZE_* */ + __u32 per_address; /*< Peripheral source/destination + * physical address + */ + u32 W; /*!< 2D Wide-size */ + u32 X; /*!< 2D X-size */ + u32 Y; /*!< 2D Y-size */ +} mx2_dma_info_t; + +/*! + * Structure of dma buffer descriptor + */ +typedef struct { + unsigned long state; /*!< dma bd state */ + int mode; /*!< the dma mode of this bd */ + unsigned long count; /*!< the length of the dma transfer */ + unsigned long src_addr; /*!< the source address of the dma transfer */ + unsigned long dst_addr; /*!< the destination address of the dma transfer */ +} mx2_dma_bd_t; + +/*! + * the states of dma buffer descriptor + */ +#define DMA_BD_ST_BUSY 0x20000000 /*!< dma bd is transfering or has be configured into controller */ +#define DMA_BD_ST_PEND 0x10000000 /*!< dma bd is waiting to be configured into controller */ +#define DMA_BD_ST_LAST 0x08000000 /*!< dma bd is the last dma bd which is built in one dma transfer request + * When completed this bd, the callback function must be called. + */ + +/*! + * This structure containing the private information for MX2 + */ +typedef struct mx2_dma_priv_s { + unsigned int dma_chaining:1; /* 1: using headware dma chaining feature */ + unsigned int ren:1; /* 1: dma start besed on request signal */ + unsigned long trans_bytes; /* To store the transfered data bytes in this transfer */ + mx2_dma_info_t *dma_info; /* To store the pointer for dma parameter for reading and wirting */ + int bd_rd; /* the read index of bd ring */ + int bd_wr; /* the write index of bd ring */ + atomic_t bd_used; /* the valid bd number in bd ring */ + mx2_dma_bd_t *bd_ring; /* the pointer of bd ring */ + unsigned long dma_base; /* register base address of this channel */ + int dma_irq; /* irq number of this channel */ +} mx2_dma_priv_t; + +/*! + * @brief get the dma info by channel_id + */ +extern mx2_dma_info_t *mxc_dma_get_info(mxc_dma_device_t channel_id); + +/*! + * @brief: scan dma parameter list . And collect information about which channels are dynamic . + */ +extern void mxc_dma_load_info(mxc_dma_channel_t * dma); + +#endif diff --git a/arch/arm/plat-mxc/include/mach/mx31.h b/arch/arm/plat-mxc/include/mach/mx31.h index 0b06941b6139..2ca31d6413a6 100644 --- a/arch/arm/plat-mxc/include/mach/mx31.h +++ b/arch/arm/plat-mxc/include/mach/mx31.h @@ -3,6 +3,14 @@ */ #define MX31_IRAM_BASE_ADDR 0x1FFC0000 /* internal ram */ #define MX31_IRAM_SIZE SZ_16K +#define MX31_IRAM_BASE_ADDR_VIRT 0xFC340000 + +#define USB_IRAM_BASE_ADDR (MX31_IRAM_BASE_ADDR) +#ifdef CONFIG_USB_STATIC_IRAM +#define USB_IRAM_SIZE (2*SZ_8K) +#else +#define USB_IRAM_SIZE 0 +#endif #define OTG_BASE_ADDR (AIPS1_BASE_ADDR + 0x00088000) #define ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x0008C000) @@ -14,21 +22,98 @@ #define SIM1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00018000) #define IIM_BASE_ADDR (SPBA0_BASE_ADDR + 0x0001C000) +/*! + * defines for SPBA modules + */ +#define SPBA_SDHC1 0x04 +#define SPBA_SDHC2 0x08 +#define SPBA_SIM 0x18 +#define SPBA_IIM 0x1C + #define CSPI3_BASE_ADDR (AIPS2_BASE_ADDR + 0x00084000) #define FIRI_BASE_ADDR (AIPS2_BASE_ADDR + 0x0008C000) #define SCM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AE000) #define SMN_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AF000) #define MPEG4_ENC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C8000) +#define VPU_BASE_ADDR MPEG4_ENC_BASE_ADDR #define MX31_NFC_BASE_ADDR (X_MEMC_BASE_ADDR + 0x0000) +#define NFC_BASE_ADDR (X_MEMC_BASE_ADDR + 0x0000) +#define NFC_SIZE 0x1000 +#define NFC_IO_ADDRESS(x) 0 + +/* + * VL2CC for i.MX32 + */ +#define VL2CC_BASE_ADDR 0xE0000000 + +/*! + * Defines for modules using static and dynamic DMA channels + */ + +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_IRAM 30 +#endif /*CONFIG_SDMA_IRAM */ + +#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART4_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART4_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART5_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART5_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC2 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL + +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_SSI2_TX (MXC_DMA_CHANNEL_IRAM + 1) +#else /*CONFIG_SDMA_IRAM */ +#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL +#endif /*CONFIG_SDMA_IRAM */ + +#define MXC_DMA_CHANNEL_FIR_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_FIR_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_FIFO_MEMORY MXC_DMA_DYNAMIC_CHANNEL + +/* + * DMA request assignments + */ +#define DMA_REQ_SDHC2 21 +#define DMA_REQ_SDHC1 20 +#define DMA_REQ_FIRI_TX 17 +#define DMA_REQ_FIRI_RX 16 +#define DMA_REQ_UART4_TX 13 +#define DMA_REQ_UART4_RX 12 +#define DMA_REQ_CSPI3_TX 11 +#define DMA_REQ_CSPI3_RX 10 +#define DMA_REQ_UART5_TX 11 +#define DMA_REQ_UART5_RX 10 +#define DMA_REQ_UART3_TX 9 +#define DMA_REQ_UART3_RX 8 +#define DMA_REQ_SIM 5 #define MXC_INT_MPEG4_ENCODER 5 #define MXC_INT_FIRI 7 #define MX31_INT_MMC_SDHC2 8 +#define MXC_INT_MMC_SDHC2 8 #define MXC_INT_MMC_SDHC1 9 #define MX31_INT_SSI2 11 #define MX31_INT_SSI1 12 #define MXC_INT_MBX 16 +#define MXC_INT_VPU MXC_INT_MBX #define MXC_INT_CSPI3 17 #define MXC_INT_SIM2 20 #define MXC_INT_SIM1 21 @@ -43,3 +128,13 @@ #define MXC_INT_CCM 53 #define MXC_INT_PCMCIA 54 +#define ARM11_PMU_IRQ MXC_INT_EVTMON + +/*! + * NFMS bit in RCSR register for pagesize of nandflash + */ +#define NFMS (*((volatile u32 *)IO_ADDRESS(CCM_BASE_ADDR+0xc))) +#define NFMS_BIT 30 +#define NFMS_NF_DWIDTH 31 +#define NFMS_NF_PG_SZ 30 + diff --git a/arch/arm/plat-mxc/include/mach/mx35.h b/arch/arm/plat-mxc/include/mach/mx35.h index 6465fefb42e3..da83e11b4070 100644 --- a/arch/arm/plat-mxc/include/mach/mx35.h +++ b/arch/arm/plat-mxc/include/mach/mx35.h @@ -1,11 +1,56 @@ + +/*! + * Define this option to specify we are using the newer SDMA module. + */ +#define MXC_SDMA_V2 + /* * IRAM */ #define MX35_IRAM_BASE_ADDR 0x10000000 /* internal ram */ +#define IRAM_BASE_ADDR MX35_IRAM_BASE_ADDR +#define IRAM_BASE_ADDR_VIRT 0xFC600000 #define MX35_IRAM_SIZE SZ_128K +#ifndef CONFIG_SDMA_IRAM +#define CONFIG_SDMA_IRAM_SIZE 0 +#endif +#ifdef CONFIG_SND_MXC_SOC_IRAM +#define SND_RAM_SIZE 0x10000 +#else +#define SND_RAM_SIZE 0 +#endif + +#define SND_RAM_BASE_ADDR (MX35_IRAM_BASE_ADDR + CONFIG_SDMA_IRAM_SIZE) +#define MLB_IRAM_ADDR_OFFSET (CONFIG_SDMA_IRAM_SIZE + SND_RAM_SIZE) + #define MXC_FEC_BASE_ADDR 0x50038000 #define MX35_NFC_BASE_ADDR 0xBB000000 +#define NFC_BASE_ADDR MX35_NFC_BASE_ADDR +#define NFC_BASE_ADDR_VIRT 0xFC700000 +#define NFC_SIZE SZ_1M +#define NFC_IO_ADDRESS(x) (((x) - NFC_BASE_ADDR) + NFC_BASE_ADDR_VIRT) + + +#define MMC_SDHC1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B4000) +#define MMC_SDHC2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B8000) +#define MMC_SDHC3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000BC000) +#define CAN1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E4000) +#define CAN2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E8000) +#define IIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F0000) +#define OTG_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F4000) +#define MLB_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F8000) +#define SPDIF_BASE_ADDR (SPBA0_BASE_ADDR + 0x00028000) +#define ATA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00020000) +#define ASRC_BASE_ADDR (SPBA0_BASE_ADDR + 0x0002C000) +#define ESAI_BASE_ADDR (SPBA0_BASE_ADDR + 0x00034000) +#define RNGC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B0000) + +#define SPBA_MSHC 0x24 +#define SPBA_SPDIR 0x28 +#define SPBA_ASRC 0x2C +#define SPBA_ESAI 0x34 +#define SPBA_FEC 0x38 /* * Interrupt numbers @@ -16,6 +61,8 @@ #define MXC_INT_MMC_SDHC3 9 #define MX35_INT_SSI1 11 #define MX35_INT_SSI2 12 +#define MXC_INT_SSI1 MX35_INT_SSI1 +#define MXC_INT_SSI2 MX35_INT_SSI2 #define MXC_INT_GPU2D 16 #define MXC_INT_ASRC 17 #define MXC_INT_USBHS 35 @@ -26,4 +73,84 @@ #define MXC_INT_MLB 46 #define MXC_INT_SPDIF 47 #define MXC_INT_FEC 57 +#define MXC_INT_RNGC MXC_INT_RNGA + +#define MXC_INT_FORCE MXC_INT_RESV1 + +/*! + * Defines for modules using static and dynamic DMA channels + */ +#define MXC_DMA_CHANNEL_IRAM 30 +#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC2 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC3 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_SSI1_TX (MXC_DMA_CHANNEL_IRAM + 1) +#else +#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL +#endif +#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SPDIF_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SPDIF_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCC_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCC_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ESAI_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ESAI_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_ESAI MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_ESAI MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCC_ESAI MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_SSI1_TX0 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_SSI1_TX1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_SSI2_TX0 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCA_SSI2_TX1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_SSI1_TX0 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_SSI1_TX1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_SSI2_TX0 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ASRCB_SSI2_TX1 MXC_DMA_DYNAMIC_CHANNEL + +#define DMA_REQ_ASRC_DMA6 41 +#define DMA_REQ_ASRC_DMA5 40 +#define DMA_REQ_ASRC_DMA4 39 +#define DMA_REQ_ASRC_DMA3 38 +#define DMA_REQ_ASRC_DMA2 37 +#define DMA_REQ_ASRC_DMA1 36 +#define DMA_REQ_RSVD3 35 +#define DMA_REQ_RSVD2 34 +#define DMA_REQ_ESAI_TX 33 +#define DMA_REQ_ESAI_RX 32 +#define DMA_REQ_IPU 21 +#define DMA_REQ_RSVD1 20 +#define DMA_REQ_SPDIF_TX 13 +#define DMA_REQ_SPDIF_RX 12 +#define DMA_REQ_UART3_TX 11 +#define DMA_REQ_UART3_RX 10 +#define DMA_REQ_MSHC 5 +#define DMA_REQ_DPTC 1 +#define DMA_REQ_DVFS 1 +/*! + * NFMS bit in RCSR register for pagesize of nandflash + */ +#define NFMS (*((volatile u32 *)IO_ADDRESS(CCM_BASE_ADDR+0x18))) +#define NFMS_BIT 8 +#define NFMS_NF_DWIDTH 14 +#define NFMS_NF_PG_SZ 8 diff --git a/arch/arm/plat-mxc/include/mach/mx37.h b/arch/arm/plat-mxc/include/mach/mx37.h new file mode 100644 index 000000000000..7539900cbacd --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mx37.h @@ -0,0 +1,474 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MXC_MX37_H__ +#define __ASM_ARCH_MXC_MX37_H__ + +#ifndef __ASM_ARCH_MXC_HARDWARE_H__ +#error "Do not include directly." +#endif + +/*! + * @file arch-mxc/mx37.h + * @brief This file contains register definitions. + * + * @ingroup MSL_MX37 + */ + +/*! + * Define this option to specify we are using the newer SDMA module. + */ +#define MXC_SDMA_V2 + +/* + * IRAM + */ +#define IRAM_BASE_ADDR 0x10000000 /* internal ram */ +#define IRAM_BASE_ADDR_VIRT 0xF8000000 +#define IRAM_SIZE (9*SZ_8K) /* 72KB */ + +#if defined(CONFIG_MXC_SECURITY_SCC2) \ + || defined(CONFIG_MXC_SECURITY_SCC2_MODULE) +#define SCC_IRAM_SIZE SZ_16K +#else +#define SCC_IRAM_SIZE 0 +#endif + +/*#ifndef CONFIG_SDMA_IRAM +#define CONFIG_SDMA_IRAM_SIZE 0 +#endif*/ +#ifdef CONFIG_SDMA_IRAM +#define SDMA_IRAM_SIZE CONFIG_SDMA_IRAM_SIZE +#else +#define SDMA_IRAM_SIZE 0 +#endif + +#ifdef CONFIG_SND_MXC_SOC_IRAM +#define SND_RAM_SIZE 0x6000 +#else +#define SND_RAM_SIZE 0 +#endif + +#ifdef CONFIG_USB_STATIC_IRAM +#define USB_IRAM_SIZE SZ_8K +#else +#define USB_IRAM_SIZE 0 +#endif + +#if (IRAM_SIZE < (SCC_IRAM_SIZE + SDMA_IRAM_SIZE + SND_RAM_SIZE + \ + USB_IRAM_SIZE)) +#error "IRAM size exceeded" +#endif + +#ifdef CONFIG_MXC_VPU_IRAM +#define VPU_IRAM_SIZE (IRAM_BASE_ADDR + IRAM_SIZE - VPU_IRAM_BASE_ADDR) +#else +#define VPU_IRAM_SIZE 0 +#endif + +#define SCC_IRAM_BASE_ADDR (IRAM_BASE_ADDR + IRAM_SIZE - SCC_IRAM_SIZE) +#define SDMA_RAM_BASE_ADDR (IRAM_BASE_ADDR) +#define SND_RAM_BASE_ADDR (IRAM_BASE_ADDR + SDMA_IRAM_SIZE) +#define USB_IRAM_BASE_ADDR (SND_RAM_BASE_ADDR + SND_RAM_SIZE) +#define VPU_IRAM_BASE_ADDR (USB_IRAM_BASE_ADDR + USB_IRAM_SIZE) + +/* + * NFC + */ +#define NFC_BASE_ADDR_AXI 0x7FFF0000 /* NAND flash AXI */ +#define NFC_BASE_ADDR_AXI_VIRT 0xF9000000 +#define NFC_AXI_SIZE SZ_64K + +/* + * L2CC + */ +#define L2CC_BASE_ADDR 0xB0000000 + +#define PLATFORM_BASE_ADDR 0xB0400000 +#define PLATFORM_BASE_ADDR_VIRT 0xFA000000 +#define PLATFORM_SIZE SZ_1M +#define EVTMON_BASE_ADDR (PLATFORM_BASE_ADDR + 0x00000000) +#define ARM1176_BASE_ADDR (PLATFORM_BASE_ADDR + 0x00004000) + +#define TZIC_BASE_ADDR 0xB0800000 +#define TZIC_BASE_ADDR_VIRT 0xFA100000 +#define TZIC_SIZE SZ_1M + +#define DEBUG_BASE_ADDR 0xB0C00000 +#define DEBUG_BASE_ADDR_VIRT 0xFA200000 +#define DEBUG_SIZE SZ_1M +#define ETB_BASE_ADDR (DEBUG_BASE_ADDR + 0x00001000) +#define ETM_BASE_ADDR (DEBUG_BASE_ADDR + 0x00002000) +#define TPIU_BASE_ADDR (DEBUG_BASE_ADDR + 0x00003000) +#define CTI0_BASE_ADDR (DEBUG_BASE_ADDR + 0x00004000) +#define CTI1_BASE_ADDR (DEBUG_BASE_ADDR + 0x00005000) +#define CTI2_BASE_ADDR (DEBUG_BASE_ADDR + 0x00006000) + +/* + * AIPS 1 + */ +#define AIPS1_BASE_ADDR 0xC3F00000 +#define AIPS1_BASE_ADDR_VIRT 0xFC000000 +#define AIPS1_SIZE SZ_1M + +#define MAX_BASE_ADDR (AIPS1_BASE_ADDR + 0x00080000) +#define GPIO1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00084000) +#define GPIO2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00088000) +#define GPIO3_BASE_ADDR (AIPS1_BASE_ADDR + 0x0008C000) +#define KPP_BASE_ADDR (AIPS1_BASE_ADDR + 0x00094000) +#define WDOG1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00098000) +#define WDOG2_BASE_ADDR (AIPS1_BASE_ADDR + 0x0009C000) +#define GPT1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A0000) +#define SRTC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A4000) +#define IOMUXC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A8000) +#define IIM_BASE_ADDR (AIPS1_BASE_ADDR + 0x000AC000) +#define CSU_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B0000) +#define SDMA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B4000) +#define SCC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000BC000) +#define ROMCP_BASE_ADDR (AIPS1_BASE_ADDR + 0x000C0000) +#define RTIC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000C4000) +#define VPU_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D0000) +#define OTG_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D4000) +#define ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D8000) +#define MSHC1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E0000) +#define FEC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E8000) +#define RNGC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000EC000) +#define TVE_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F0000) + +/* + * SPBA global module enabled #0 + */ +#define SPBA0_BASE_ADDR 0xC0000000 +#define SPBA0_BASE_ADDR_VIRT 0xFC100000 +#define SPBA0_SIZE SZ_1M + +#define MMC_SDHC1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00004000) +#define MMC_SDHC2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00008000) +#define UART3_BASE_ADDR (SPBA0_BASE_ADDR + 0x0000C000) +#define CSPI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00010000) +#define SSI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00014000) +#define MMC_SDHC3_BASE_ADDR (SPBA0_BASE_ADDR + 0x00020000) +#define SPDIF_BASE_ADDR (SPBA0_BASE_ADDR + 0x00028000) +#define ATA_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00034000) +#define SPBA_CTRL_BASE_ADDR (SPBA0_BASE_ADDR + 0x0003C000) + +/*! + * defines for SPBA modules + */ +#define SPBA_SDHC1 0x04 +#define SPBA_SDHC2 0x08 +#define SPBA_UART3 0x0C +#define SPBA_CSPI2 0x10 +#define SPBA_SSI2 0x14 +#define SPBA_SDHC3 0x20 +#define SPBA_SPDIF 0x28 +#define SPBA_ATA 0x34 + +/*! + * Defines for modules using static and dynamic DMA channels + */ +#define MXC_DMA_CHANNEL_IRAM 30 +#define MXC_DMA_CHANNEL_SPDIF_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC2 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_SSI2_TX (MXC_DMA_CHANNEL_IRAM + 1) +#else /*CONFIG_SDMA_IRAM */ +#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL +#endif /*CONFIG_SDMA_IRAM */ +#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL + +/* + * AIPS 2 + */ +#define AIPS2_BASE_ADDR 0xE3F00000 +#define AIPS2_BASE_ADDR_VIRT 0xFC200000 +#define AIPS2_SIZE SZ_1M + +#define PLL0_BASE_ADDR (AIPS2_BASE_ADDR + 0x00080000) +#define PLL1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00084000) +#define PLL2_BASE_ADDR (AIPS2_BASE_ADDR + 0x00088000) +#define CCM_BASE_ADDR (AIPS2_BASE_ADDR + 0x0008C000) +#define GPC_BASE_ADDR (AIPS2_BASE_ADDR + 0x00090000) +#define SRC_BASE_ADDR (AIPS2_BASE_ADDR + 0x00094000) +#define EPIT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00098000) +#define EPIT2_BASE_ADDR (AIPS2_BASE_ADDR + 0x0009C000) +#define PWM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A0000) +#define OWIRE_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A4000) +#define CSPI3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A8000) +#define CSPI1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AC000) +#define UART1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B0000) +#define UART2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000BC000) +#define I2C3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C0000) +#define I2C2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C4000) +#define I2C_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C8000) +#define SSI1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000CC000) +#define AUDMUX_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D0000) +#define EMI_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DBF00) + +#define M4IF_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D8000) +#define ESDCTL_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D9000) +#define WEIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DA000) +#define NFC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DB000) + +/* + * Memory regions and CS + */ +#define IPU_CTRL_BASE_ADDR 0x80000000 +#define CSD0_BASE_ADDR 0x40000000 +#define CSD1_BASE_ADDR 0x50000000 + +#define CS0_BASE_ADDR 0x60000000 +#define CS1_BASE_ADDR 0x68000000 +#define CS2_BASE_ADDR 0x70000000 + +/*! + * This macro defines the physical to virtual address mapping for all the + * peripheral modules. It is used by passing in the physical address as x + * and returning the virtual address. If the physical address is not mapped, + * it returns 0xDEADBEEF + */ +#define IO_ADDRESS(x) \ + (void __force __iomem *) \ + (((x >= (unsigned long)IRAM_BASE_ADDR) && (x < (unsigned long)IRAM_BASE_ADDR + IRAM_SIZE)) ? IRAM_IO_ADDRESS(x):\ + ((x >= (unsigned long)PLATFORM_BASE_ADDR) && (x < (unsigned long)PLATFORM_BASE_ADDR + PLATFORM_SIZE)) ? PLATFORM_IO_ADDRESS(x):\ + ((x >= (unsigned long)TZIC_BASE_ADDR) && (x < (unsigned long)TZIC_BASE_ADDR + TZIC_SIZE)) ? TZIC_IO_ADDRESS(x):\ + ((x >= (unsigned long)DEBUG_BASE_ADDR) && (x < (unsigned long)DEBUG_BASE_ADDR + DEBUG_SIZE)) ? DEBUG_IO_ADDRESS(x):\ + ((x >= (unsigned long)SPBA0_BASE_ADDR) && (x < (unsigned long)SPBA0_BASE_ADDR + SPBA0_SIZE)) ? SPBA0_IO_ADDRESS(x):\ + ((x >= (unsigned long)AIPS1_BASE_ADDR) && (x < (unsigned long)AIPS1_BASE_ADDR + AIPS1_SIZE)) ? AIPS1_IO_ADDRESS(x):\ + ((x >= (unsigned long)AIPS2_BASE_ADDR) && (x < (unsigned long)AIPS2_BASE_ADDR + AIPS2_SIZE)) ? AIPS2_IO_ADDRESS(x):\ + ((x >= (unsigned long)NFC_BASE_ADDR_AXI) && (x < (unsigned long)NFC_BASE_ADDR_AXI + NFC_AXI_SIZE)) ? NFC_BASE_ADDR_AXI_IO_ADDRESS(x):\ + 0xDEADBEEF) + +/* + * define the address mapping macros: in physical address order + */ + +#define IRAM_IO_ADDRESS(x) \ + (((x) - IRAM_BASE_ADDR) + IRAM_BASE_ADDR_VIRT) + +#define PLATFORM_IO_ADDRESS(x) \ + (((x) - PLATFORM_BASE_ADDR) + PLATFORM_BASE_ADDR_VIRT) + +#define TZIC_IO_ADDRESS(x) \ + (((x) - TZIC_BASE_ADDR) + TZIC_BASE_ADDR_VIRT) + +#define DEBUG_IO_ADDRESS(x) \ + (((x) - DEBUG_BASE_ADDR) + DEBUG_BASE_ADDR_VIRT) + +#define SPBA0_IO_ADDRESS(x) \ + (((x) - SPBA0_BASE_ADDR) + SPBA0_BASE_ADDR_VIRT) + +#define AIPS1_IO_ADDRESS(x) \ + (((x) - AIPS1_BASE_ADDR) + AIPS1_BASE_ADDR_VIRT) + +#define AIPS2_IO_ADDRESS(x) \ + (((x) - AIPS2_BASE_ADDR) + AIPS2_BASE_ADDR_VIRT) + +#define NFC_BASE_ADDR_AXI_IO_ADDRESS(x) \ + (((x) - NFC_BASE_ADDR_AXI) + NFC_BASE_ADDR_AXI_VIRT) + +#define IS_MEM_DEVICE_NONSHARED(x) ((x) >= 0x80000000) + +/* + * DMA request assignments + */ +#define DMA_REQ_RESV47 47 +#define DMA_REQ_VPU 46 +#define DMA_REQ_SPDIF_TX 45 +#define DMA_REQ_UART3_TX 44 +#define DMA_REQ_UART3_RX 43 +#define DMA_REQ_I2C2 42 +#define DMA_REQ_I2C1 41 +#define DMA_REQ_SDHC3 40 +#define DMA_REQ_CSPI3_TX 39 +#define DMA_REQ_CSPI3_RX 38 +#define DMA_REQ_RESV37 37 +#define DMA_REQ_IPU 36 +#define DMA_REQ_RESV35 35 +#define DMA_REQ_EPIT2 34 +#define DMA_REQ_RESV33 33 +#define DMA_REQ_RESV32 32 +#define DMA_REQ_ECT 31 +#define DMA_REQ_NFC 30 +#define DMA_REQ_SSI1_TX1 29 +#define DMA_REQ_SSI1_RX1 28 +#define DMA_REQ_SSI1_TX2 27 +#define DMA_REQ_SSI1_RX2 26 +#define DMA_REQ_SSI2_TX1 25 +#define DMA_REQ_SSI2_RX1 24 +#define DMA_REQ_SSI2_TX2 23 +#define DMA_REQ_SSI2_RX2 22 +#define DMA_REQ_SDHC2 21 +#define DMA_REQ_SDHC1 20 +#define DMA_REQ_UART1_TX 19 +#define DMA_REQ_UART1_RX 18 +#define DMA_REQ_UART2_TX 17 +#define DMA_REQ_UART2_RX 16 +#define DMA_REQ_GPIO1_0 15 +#define DMA_REQ_GPIO1_1 14 +#define DMA_REQ_RESV13 13 +#define DMA_REQ_RESV12 12 +#define DMA_REQ_RESV11 11 +#define DMA_REQ_RESV10 10 +#define DMA_REQ_CSPI1_TX 9 +#define DMA_REQ_CSPI1_RX 8 +#define DMA_REQ_CSPI2_TX 7 +#define DMA_REQ_CSPI2_RX 6 +#define DMA_REQ_RESV5 5 +#define DMA_REQ_ATA_TX_END 4 +#define DMA_REQ_ATA_TX 3 +#define DMA_REQ_ATA_RX 2 +#define DMA_REQ_GPC 1 +#define DMA_REQ_RESV0 0 + +/* + * Interrupt numbers + */ +#define MXC_INT_BASE 0 +#define MXC_INT_RESV0 0 +#define MXC_INT_MMC_SDHC1 1 +#define MXC_INT_MMC_SDHC2 2 +#define MXC_INT_MMC_SDHC3 3 +#define MXC_INT_RESV4 4 +#define MXC_INT_RESV5 5 +#define MXC_INT_SDMA 6 +#define MXC_INT_IOMUX 7 +#define MXC_INT_RESV8 8 +#define MXC_INT_VPU 9 +#define MXC_INT_IPU_ERR 10 +#define MXC_INT_IPU_SYN 11 +#define MXC_INT_RESV12 12 +#define MXC_INT_RESV13 13 +#define MXC_INT_RNG 14 +#define MXC_INT_EMI 15 +#define MXC_INT_RESV16 16 +#define MXC_INT_RESV17 17 +#define MXC_INT_USB_OTG 18 +#define MXC_INT_RESV19 19 +#define MXC_INT_RESV20 20 +#define MXC_INT_SCC_SMN 21 +#define MXC_INT_SCC_STZ 22 +#define MXC_INT_SCC_SCM 23 +#define MXC_INT_SRTC_NTZ 24 +#define MXC_INT_SRTC_TZ 25 +#define MXC_INT_RTIC 26 +#define MXC_INT_CSU 27 +#define MXC_INT_RESV28 28 +#define MXC_INT_SSI1 29 +#define MXC_INT_SSI2 30 +#define MXC_INT_UART1 31 +#define MXC_INT_UART2 32 +#define MXC_INT_UART3 33 +#define MXC_INT_RESV34 34 +#define MXC_INT_RESV35 35 +#define MXC_INT_CSPI1 36 +#define MXC_INT_CSPI2 37 +#define MXC_INT_CSPI3 38 +#define MXC_INT_GPT 39 +#define MXC_INT_EPIT1 40 +#define MXC_INT_EPIT2 41 +#define MXC_INT_GPIO1_INT7 42 +#define MXC_INT_GPIO1_INT6 43 +#define MXC_INT_GPIO1_INT5 44 +#define MXC_INT_GPIO1_INT4 45 +#define MXC_INT_GPIO1_INT3 46 +#define MXC_INT_GPIO1_INT2 47 +#define MXC_INT_GPIO1_INT1 48 +#define MXC_INT_GPIO1_INT0 49 +#define MXC_INT_GPIO1_LOW 50 +#define MXC_INT_GPIO1_HIGH 51 +#define MXC_INT_GPIO2_LOW 52 +#define MXC_INT_GPIO2_HIGH 53 +#define MXC_INT_GPIO3_LOW 54 +#define MXC_INT_GPIO3_HIGH 55 +#define MXC_INT_RESV56 56 +#define MXC_INT_RESV57 57 +#define MXC_INT_WDOG1 58 +#define MXC_INT_WDOG2 59 +#define MXC_INT_KPP 60 +#define MXC_INT_PWM 61 +#define MXC_INT_I2C 62 +#define MXC_INT_I2C2 63 +#define MXC_INT_I2C3 64 +#define MXC_INT_MSHC1 65 +#define MXC_INT_RESV66 66 +#define MXC_INT_RESV67 67 +#define MXC_INT_RESV68 68 +#define MXC_INT_IIM 69 +#define MXC_INT_ATA 70 +#define MXC_INT_CCM1 71 +#define MXC_INT_CCM2 72 +#define MXC_INT_GPC1 73 +#define MXC_INT_GPC2 74 +#define MXC_INT_SRC 75 +#define MXC_INT_EVTMON 76 +#define MXC_INT_PER_MEASURE 77 +#define MXC_INT_DECODE_ERR 78 +#define MXC_INT_EVT_COUNT 79 +#define MXC_INT_SLAVE_ERR 80 +#define MXC_INT_RESV81 81 +#define MXC_INT_RESV82 82 +#define MXC_INT_RESV83 83 +#define MXC_INT_RESV84 84 +#define MXC_INT_RESV85 85 +#define MXC_INT_RESV86 86 +#define MXC_INT_FEC 87 +#define MXC_INT_OWIRE 88 +#define MXC_INT_CTI0 89 +#define MXC_INT_CTM0 90 +#define MXC_INT_SPDIF 91 +#define MXC_INT_TVOUT 92 + +/*! + * Interrupt Number for ARM11 PMU + */ +#define ARM11_PMU_IRQ MXC_INT_EVTMON + +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x00 +#define GPIO_GDIR 0x04 +#define GPIO_PSR 0x08 +#define GPIO_ICR1 0x0C +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_ISR 0x18 +#define GPIO_INT_LOW_LEV 0x0 +#define GPIO_INT_HIGH_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_FALL_EDGE 0x3 +#define GPIO_INT_NONE 0x4 + +/*! + * Macro to convert elv, llv, ulv to a data which is used to set DCVR0, DCVR1, + * DCVR2, or DCVR3. + */ +#define DCVR(elv, llv, ulv) ((elv << 0) | (llv << 10) | (ulv << 21)) + +#endif /* __ASM_ARCH_MXC_MX37_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mx3x.h b/arch/arm/plat-mxc/include/mach/mx3x.h index b559a4bb5769..d297a832d3ad 100644 --- a/arch/arm/plat-mxc/include/mach/mx3x.h +++ b/arch/arm/plat-mxc/include/mach/mx3x.h @@ -8,8 +8,8 @@ * published by the Free Software Foundation. */ -#ifndef __ASM_ARCH_MXC_MX31_H__ -#define __ASM_ARCH_MXC_MX31_H__ +#ifndef __ASM_ARCH_MXC_MX3X_H__ +#define __ASM_ARCH_MXC_MX3X_H__ #ifndef __ASM_ARCH_MXC_HARDWARE_H__ #error "Do not include directly." @@ -99,6 +99,11 @@ #define MSHC1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00024000) #define SPBA_CTRL_BASE_ADDR (SPBA0_BASE_ADDR + 0x0003C000) +#define SPBA_UART3 0x0C +#define SPBA_CSPI2 0x10 +#define SPBA_SSI2 0x14 +#define SPBA_ATA 0x20 + /* * AIPS 2 */ @@ -118,7 +123,7 @@ #define GPIO2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D0000) #define SDMA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D4000) #define RTC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D8000) -#define WDOG_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DC000) +#define WDOG1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DC000) #define PWM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E0000) #define RTIC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000EC000) @@ -168,6 +173,7 @@ ((x >= AVIC_BASE_ADDR) && (x < (AVIC_BASE_ADDR + AVIC_SIZE))) ? AVIC_IO_ADDRESS(x):\ ((x >= CS4_BASE_ADDR) && (x < (CS4_BASE_ADDR + CS4_SIZE))) ? CS4_IO_ADDRESS(x):\ ((x >= X_MEMC_BASE_ADDR) && (x < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? X_MEMC_IO_ADDRESS(x):\ + ((x >= NFC_BASE_ADDR) && (x < (NFC_BASE_ADDR + NFC_SIZE))) ? NFC_IO_ADDRESS(x):\ 0xDEADBEEF) /* @@ -203,9 +209,39 @@ #define PCMCIA_IO_ADDRESS(x) \ (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT) +/* + * DMA request assignments + */ +#define DMA_REQ_ECT 31 +#define DMA_REQ_NFC 30 +#define DMA_REQ_SSI1_TX1 29 +#define DMA_REQ_SSI1_RX1 28 +#define DMA_REQ_SSI1_TX2 27 +#define DMA_REQ_SSI1_RX2 26 +#define DMA_REQ_SSI2_TX1 25 +#define DMA_REQ_SSI2_RX1 24 +#define DMA_REQ_SSI2_TX2 23 +#define DMA_REQ_SSI2_RX2 22 +#define DMA_REQ_UART1_TX 19 +#define DMA_REQ_UART1_RX 18 +#define DMA_REQ_UART2_TX 17 +#define DMA_REQ_UART2_RX 16 +#define DMA_REQ_EXTREQ1 15 +#define DMA_REQ_EXTREQ2 14 +#define DMA_REQ_CSPI1_TX 9 +#define DMA_REQ_CSPI1_RX 8 +#define DMA_REQ_CSPI2_TX 7 +#define DMA_REQ_CSPI2_RX 6 +#define DMA_REQ_ATA_RX 4 +#define DMA_REQ_ATA_TX 3 +#define DMA_REQ_ATA_TX_END 2 +#define DMA_REQ_CCM 1 +#define DMA_REQ_EXTREQ0 0 + /* * Interrupt numbers */ +#define MXC_INT_RESV1 1 #define MXC_INT_I2C3 3 #define MXC_INT_I2C2 4 #define MXC_INT_RTIC 6 @@ -224,6 +260,7 @@ #define MXC_INT_EPIT1 28 #define MXC_INT_GPT 29 #define MXC_INT_POWER_FAIL 30 +#define MXC_INT_DVFS 31 #define MXC_INT_UART2 32 #define MXC_INT_NANDFC 33 #define MXC_INT_SDMA 34 @@ -245,6 +282,8 @@ #define MXC_INT_EXT_WDOG 62 #define MXC_INT_EXT_TV 63 +#define ARM11_PMU_IRQ MXC_INT_EVTMON + #define PROD_SIGNATURE 0x1 /* For MX31 */ /* silicon revisions specific to i.MX31 */ diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h new file mode 100644 index 000000000000..ab9ddb2c07e1 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mx51.h @@ -0,0 +1,511 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_MX51_H__ +#define __ASM_ARCH_MXC_MX51_H__ + +#ifndef __ASM_ARCH_MXC_HARDWARE_H__ +#error "Do not include directly." +#endif + +/*! + * @file arch-mxc/mx51.h + * @brief This file contains register definitions. + * + * @ingroup MSL_MX51 + */ + +/*! + * Register an interrupt handler for the SMN as well as the SCC. In some + * implementations, the SMN is not connected at all, and in others, it is + * on the same interrupt line as the SCM. Comment this line out accordingly + */ +#define USE_SMN_INTERRUPT + +/*! + * This option is used to set or clear the RXDMUXSEL bit in control reg 3. + * Certain platforms need this bit to be set in order to receive Irda data. + */ +#define MXC_UART_IR_RXDMUX 0x0004 +/*! + * This option is used to set or clear the RXDMUXSEL bit in control reg 3. + * Certain platforms need this bit to be set in order to receive UART data. + */ +#define MXC_UART_RXDMUX 0x0004 + +/*! + * This option is used to set or clear the dspdma bit in the SDMA config + * register. + */ +#define MXC_SDMA_DSPDMA 0 + +/*! + * Define this option to specify we are using the newer SDMA module. + */ +#define MXC_SDMA_V2 + + /* + * IRAM + */ +#define IRAM_BASE_ADDR 0x1FFE0000 /* internal ram */ +#define IRAM_BASE_ADDR_VIRT 0xFA3E0000 +#define IRAM_PARTITIONS 16 +#define IRAM_PARTITIONS_TO1 12 +#define IRAM_SIZE (IRAM_PARTITIONS*SZ_8K) /* 128KB */ + +#if defined(CONFIG_MXC_SECURITY_SCC2) \ + || defined(CONFIG_MXC_SECURITY_SCC2_MODULE) +#define SCC_IRAM_SIZE SZ_16K +#else +#define SCC_IRAM_SIZE 0 +#endif + +#ifdef CONFIG_SDMA_IRAM +#define SDMA_IRAM_SIZE CONFIG_SDMA_IRAM_SIZE +#else +#define SDMA_IRAM_SIZE 0 +#endif + +#ifdef CONFIG_SND_MXC_SOC_IRAM +#define SND_RAM_SIZE 0x6000 +#else +#define SND_RAM_SIZE 0 +#endif + +#ifdef CONFIG_MXC_VPU_IRAM +#define VPU_IRAM_SIZE 0x7000 +#else +#define VPU_IRAM_SIZE 0 +#endif + +#if (IRAM_SIZE < (SDMA_IRAM_SIZE + SND_RAM_SIZE + VPU_IRAM_SIZE + \ + SCC_IRAM_SIZE)) +#error "IRAM size exceeded" +#endif + +#define SCC_IRAM_BASE_ADDR (IRAM_BASE_ADDR + IRAM_SIZE - SCC_IRAM_SIZE) +#define VPU_IRAM_BASE_ADDR (SCC_IRAM_BASE_ADDR - VPU_IRAM_SIZE) +#define SND_RAM_BASE_ADDR (VPU_IRAM_BASE_ADDR - SND_RAM_SIZE) +#define SDMA_IRAM_BASE_ADDR (SND_RAM_BASE_ADDR - SDMA_IRAM_SIZE) +#define IDLE_IRAM_BASE_ADDR (SDMA_IRAM_BASE_ADDR - SZ_4K) +#define SUSPEND_IRAM_BASE_ADDR (IDLE_IRAM_BASE_ADDR - SZ_4K) +/* + * NFC + */ +#define NFC_BASE_ADDR_AXI 0xCFFF0000 /* NAND flash AXI */ +#define NFC_BASE_ADDR_AXI_VIRT 0xF9000000 +#define NFC_AXI_SIZE SZ_64K + +/* + * Graphics Memory of GPU + */ +#define GPU_BASE_ADDR 0x20000000 +#define GPU2D_BASE_ADDR 0xD0000000 + +#define TZIC_BASE_ADDR 0x8FFFC000 +#define TZIC_BASE_ADDR_VIRT 0xFA100000 +#define TZIC_SIZE SZ_16K + +#define DEBUG_BASE_ADDR 0x60000000 +#define DEBUG_BASE_ADDR_VIRT 0xFA200000 +#define DEBUG_SIZE SZ_1M +#define ETB_BASE_ADDR (DEBUG_BASE_ADDR + 0x00001000) +#define ETM_BASE_ADDR (DEBUG_BASE_ADDR + 0x00002000) +#define TPIU_BASE_ADDR (DEBUG_BASE_ADDR + 0x00003000) +#define CTI0_BASE_ADDR (DEBUG_BASE_ADDR + 0x00004000) +#define CTI1_BASE_ADDR (DEBUG_BASE_ADDR + 0x00005000) +#define CTI2_BASE_ADDR (DEBUG_BASE_ADDR + 0x00006000) +#define CTI3_BASE_ADDR (DEBUG_BASE_ADDR + 0x00007000) +#define CORTEX_DBG_BASE_ADDR (DEBUG_BASE_ADDR + 0x00008000) + +/* + * SPBA global module enabled #0 + */ +#define SPBA0_BASE_ADDR 0x70000000 +#define SPBA0_BASE_ADDR_VIRT 0xFB100000 +#define SPBA0_SIZE SZ_1M + +#define MMC_SDHC1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00004000) +#define MMC_SDHC2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00008000) +#define UART3_BASE_ADDR (SPBA0_BASE_ADDR + 0x0000C000) +#define CSPI1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00010000) +#define SSI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00014000) +#define MMC_SDHC3_BASE_ADDR (SPBA0_BASE_ADDR + 0x00020000) +#define MMC_SDHC4_BASE_ADDR (SPBA0_BASE_ADDR + 0x00024000) +#define SPDIF_BASE_ADDR (SPBA0_BASE_ADDR + 0x00028000) +#define ATA_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00030000) +#define SLIM_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00034000) +#define HSI2C_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00038000) +#define SPBA_CTRL_BASE_ADDR (SPBA0_BASE_ADDR + 0x0003C000) + +/*! + * defines for SPBA modules + */ +#define SPBA_SDHC1 0x04 +#define SPBA_SDHC2 0x08 +#define SPBA_UART3 0x0C +#define SPBA_CSPI1 0x10 +#define SPBA_SSI2 0x14 +#define SPBA_SDHC3 0x20 +#define SPBA_SDHC4 0x24 +#define SPBA_SPDIF 0x28 +#define SPBA_ATA 0x30 +#define SPBA_SLIM 0x34 +#define SPBA_HSI2C 0x38 +#define SPBA_CTRL 0x3C + +/* + * AIPS 1 + */ +#define AIPS1_BASE_ADDR 0x73F00000 +#define AIPS1_BASE_ADDR_VIRT 0xFB000000 +#define AIPS1_SIZE SZ_1M + +#define OTG_BASE_ADDR (AIPS1_BASE_ADDR + 0x00080000) +#define GPIO1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00084000) +#define GPIO2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00088000) +#define GPIO3_BASE_ADDR (AIPS1_BASE_ADDR + 0x0008C000) +#define GPIO4_BASE_ADDR (AIPS1_BASE_ADDR + 0x00090000) +#define KPP_BASE_ADDR (AIPS1_BASE_ADDR + 0x00094000) +#define WDOG1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00098000) +#define WDOG2_BASE_ADDR (AIPS1_BASE_ADDR + 0x0009C000) +#define GPT1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A0000) +#define SRTC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A4000) +#define IOMUXC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A8000) +#define EPIT1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000AC000) +#define EPIT2_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B0000) +#define PWM1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B4000) +#define PWM2_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B8000) +#define UART1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000BC000) +#define UART2_BASE_ADDR (AIPS1_BASE_ADDR + 0x000C0000) +#define SRC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D0000) +#define CCM_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D4000) +#define GPC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000D8000) + +/*! + * Defines for modules using static and dynamic DMA channels + */ +#define MXC_DMA_CHANNEL_IRAM 30 +#define MXC_DMA_CHANNEL_SPDIF_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MMC2 MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL +#ifdef CONFIG_SDMA_IRAM +#define MXC_DMA_CHANNEL_SSI2_TX (MXC_DMA_CHANNEL_IRAM + 1) +#else /*CONFIG_SDMA_IRAM */ +#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL +#endif /*CONFIG_SDMA_IRAM */ +#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_CSPI3_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL +#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL + +/* + * AIPS 2 + */ +#define AIPS2_BASE_ADDR 0x83F00000 +#define AIPS2_BASE_ADDR_VIRT 0xFB200000 +#define AIPS2_SIZE SZ_1M + +#define PLL1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00080000) +#define PLL2_BASE_ADDR (AIPS2_BASE_ADDR + 0x00084000) +#define PLL3_BASE_ADDR (AIPS2_BASE_ADDR + 0x00088000) +#define AHBMAX_BASE_ADDR (AIPS2_BASE_ADDR + 0x00094000) +#define IIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x00098000) +#define CSU_BASE_ADDR (AIPS2_BASE_ADDR + 0x0009C000) +#define ARM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A0000) +#define OWIRE_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A4000) +#define FIRI_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A8000) +#define CSPI2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AC000) +#define SDMA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B0000) +#define SCC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B4000) +#define ROMCP_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B8000) +#define RTIC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000BC000) +#define CSPI3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C0000) +#define I2C2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C4000) +#define I2C1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C8000) +#define SSI1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000CC000) +#define AUDMUX_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D0000) +#define M4IF_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D8000) +#define ESDCTL_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D9000) +#define WEIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DA000) +#define NFC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DB000) +#define EMI_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DBF00) +#define MIPI_HSC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DC000) +#define ATA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E0000) +#define SIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E4000) +#define SSI3BASE_ADDR (AIPS2_BASE_ADDR + 0x000E8000) +#define FEC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000EC000) +#define TVE_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F0000) +#define VPU_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F4000) +#define SAHARA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000F8000) + +/* + * Memory regions and CS + */ +#define GPU_CTRL_BASE_ADDR 0x30000000 +#define IPU_CTRL_BASE_ADDR 0x40000000 +#define CSD0_BASE_ADDR 0x90000000 +#define CSD1_BASE_ADDR 0xA0000000 +#define CS0_BASE_ADDR 0xB0000000 +#define CS1_BASE_ADDR 0xB8000000 +#define CS2_BASE_ADDR 0xC0000000 +#define CS3_BASE_ADDR 0xC8000000 +#define CS4_BASE_ADDR 0xCC000000 +#define CS5_BASE_ADDR 0xCE000000 + +/*! + * This macro defines the physical to virtual address mapping for all the + * peripheral modules. It is used by passing in the physical address as x + * and returning the virtual address. If the physical address is not mapped, + * it returns 0xDEADBEEF + */ +#define IO_ADDRESS(x) \ + (void __force __iomem *) \ + ((((x) >= (unsigned long)IRAM_BASE_ADDR) && \ + ((x) < (unsigned long)IRAM_BASE_ADDR + IRAM_SIZE)) ? \ + IRAM_IO_ADDRESS(x):\ + (((x) >= (unsigned long)TZIC_BASE_ADDR) && \ + ((x) < (unsigned long)TZIC_BASE_ADDR + TZIC_SIZE)) ? \ + TZIC_IO_ADDRESS(x):\ + (((x) >= (unsigned long)DEBUG_BASE_ADDR) && \ + ((x) < (unsigned long)DEBUG_BASE_ADDR + DEBUG_SIZE)) ? \ + DEBUG_IO_ADDRESS(x):\ + (((x) >= (unsigned long)SPBA0_BASE_ADDR) && \ + ((x) < (unsigned long)SPBA0_BASE_ADDR + SPBA0_SIZE)) ? \ + SPBA0_IO_ADDRESS(x):\ + (((x) >= (unsigned long)AIPS1_BASE_ADDR) && \ + ((x) < (unsigned long)AIPS1_BASE_ADDR + AIPS1_SIZE)) ? \ + AIPS1_IO_ADDRESS(x):\ + (((x) >= (unsigned long)AIPS2_BASE_ADDR) && \ + ((x) < (unsigned long)AIPS2_BASE_ADDR + AIPS2_SIZE)) ? \ + AIPS2_IO_ADDRESS(x):\ + (((x) >= (unsigned long)NFC_BASE_ADDR_AXI) && \ + ((x) < (unsigned long)NFC_BASE_ADDR_AXI + NFC_AXI_SIZE)) ? \ + NFC_BASE_ADDR_AXI_IO_ADDRESS(x):\ + 0xDEADBEEF) + +/* + * define the address mapping macros: in physical address order + */ +#define IRAM_IO_ADDRESS(x) \ + (((x) - IRAM_BASE_ADDR) + IRAM_BASE_ADDR_VIRT) + +#define TZIC_IO_ADDRESS(x) \ + (((x) - TZIC_BASE_ADDR) + TZIC_BASE_ADDR_VIRT) + +#define DEBUG_IO_ADDRESS(x) \ + (((x) - DEBUG_BASE_ADDR) + DEBUG_BASE_ADDR_VIRT) + +#define SPBA0_IO_ADDRESS(x) \ + (((x) - SPBA0_BASE_ADDR) + SPBA0_BASE_ADDR_VIRT) + +#define AIPS1_IO_ADDRESS(x) \ + (((x) - AIPS1_BASE_ADDR) + AIPS1_BASE_ADDR_VIRT) + +#define AIPS2_IO_ADDRESS(x) \ + (((x) - AIPS2_BASE_ADDR) + AIPS2_BASE_ADDR_VIRT) + +#define NFC_BASE_ADDR_AXI_IO_ADDRESS(x) \ + (((x) - NFC_BASE_ADDR_AXI) + NFC_BASE_ADDR_AXI_VIRT) + +#define IS_MEM_DEVICE_NONSHARED(x) 0 + +/* + * DMA request assignments + */ +#define DMA_REQ_SSI3_TX1 47 +#define DMA_REQ_SSI3_RX1 46 +#define DMA_REQ_SPDIF 45 +#define DMA_REQ_UART3_TX 44 +#define DMA_REQ_UART3_RX 43 +#define DMA_REQ_SLIM_B_TX 42 +#define DMA_REQ_SDHC4 41 +#define DMA_REQ_SDHC3 40 +#define DMA_REQ_CSPI_TX 39 +#define DMA_REQ_CSPI_RX 38 +#define DMA_REQ_SSI3_TX2 37 +#define DMA_REQ_IPU 36 +#define DMA_REQ_SSI3_RX2 35 +#define DMA_REQ_EPIT2 34 +#define DMA_REQ_CTI2_1 33 +#define DMA_REQ_EMI_WR 32 +#define DMA_REQ_CTI2_0 31 +#define DMA_REQ_EMI_RD 30 +#define DMA_REQ_SSI1_TX1 29 +#define DMA_REQ_SSI1_RX1 28 +#define DMA_REQ_SSI1_TX2 27 +#define DMA_REQ_SSI1_RX2 26 +#define DMA_REQ_SSI2_TX1 25 +#define DMA_REQ_SSI2_RX1 24 +#define DMA_REQ_SSI2_TX2 23 +#define DMA_REQ_SSI2_RX2 22 +#define DMA_REQ_SDHC2 21 +#define DMA_REQ_SDHC1 20 +#define DMA_REQ_UART1_TX 19 +#define DMA_REQ_UART1_RX 18 +#define DMA_REQ_UART2_TX 17 +#define DMA_REQ_UART2_RX 16 +#define DMA_REQ_GPU 15 +#define DMA_REQ_EXTREQ1 14 +#define DMA_REQ_FIRI_TX 13 +#define DMA_REQ_FIRI_RX 12 +#define DMA_REQ_HS_I2C_RX 11 +#define DMA_REQ_HS_I2C_TX 10 +#define DMA_REQ_CSPI2_TX 9 +#define DMA_REQ_CSPI2_RX 8 +#define DMA_REQ_CSPI1_TX 7 +#define DMA_REQ_CSPI1_RX 6 +#define DMA_REQ_SLIM_B 5 +#define DMA_REQ_ATA_TX_END 4 +#define DMA_REQ_ATA_TX 3 +#define DMA_REQ_ATA_RX 2 +#define DMA_REQ_GPC 1 +#define DMA_REQ_VPU 0 + +/* + * Interrupt numbers + */ +#define MXC_INT_BASE 0 +#define MXC_INT_RESV0 0 +#define MXC_INT_MMC_SDHC1 1 +#define MXC_INT_MMC_SDHC2 2 +#define MXC_INT_MMC_SDHC3 3 +#define MXC_INT_MMC_SDHC4 4 +#define MXC_INT_RESV5 5 +#define MXC_INT_SDMA 6 +#define MXC_INT_IOMUX 7 +#define MXC_INT_NFC 8 +#define MXC_INT_VPU 9 +#define MXC_INT_IPU_ERR 10 +#define MXC_INT_IPU_SYN 11 +#define MXC_INT_GPU 12 +#define MXC_INT_RESV13 13 +#define MXC_INT_USB_H1 14 +#define MXC_INT_EMI 15 +#define MXC_INT_USB_H2 16 +#define MXC_INT_USB_H3 17 +#define MXC_INT_USB_OTG 18 +#define MXC_INT_SAHARA_H0 19 +#define MXC_INT_SAHARA_H1 20 +#define MXC_INT_SCC_SMN 21 +#define MXC_INT_SCC_STZ 22 +#define MXC_INT_SCC_SCM 23 +#define MXC_INT_SRTC_NTZ 24 +#define MXC_INT_SRTC_TZ 25 +#define MXC_INT_RTIC 26 +#define MXC_INT_CSU 27 +#define MXC_INT_SLIM_B 28 +#define MXC_INT_SSI1 29 +#define MXC_INT_SSI2 30 +#define MXC_INT_UART1 31 +#define MXC_INT_UART2 32 +#define MXC_INT_UART3 33 +#define MXC_INT_RESV34 34 +#define MXC_INT_RESV35 35 +#define MXC_INT_CSPI1 36 +#define MXC_INT_CSPI2 37 +#define MXC_INT_CSPI 38 +#define MXC_INT_GPT 39 +#define MXC_INT_EPIT1 40 +#define MXC_INT_EPIT2 41 +#define MXC_INT_GPIO1_INT7 42 +#define MXC_INT_GPIO1_INT6 43 +#define MXC_INT_GPIO1_INT5 44 +#define MXC_INT_GPIO1_INT4 45 +#define MXC_INT_GPIO1_INT3 46 +#define MXC_INT_GPIO1_INT2 47 +#define MXC_INT_GPIO1_INT1 48 +#define MXC_INT_GPIO1_INT0 49 +#define MXC_INT_GPIO1_LOW 50 +#define MXC_INT_GPIO1_HIGH 51 +#define MXC_INT_GPIO2_LOW 52 +#define MXC_INT_GPIO2_HIGH 53 +#define MXC_INT_GPIO3_LOW 54 +#define MXC_INT_GPIO3_HIGH 55 +#define MXC_INT_GPIO4_LOW 56 +#define MXC_INT_GPIO4_HIGH 57 +#define MXC_INT_WDOG1 58 +#define MXC_INT_WDOG2 59 +#define MXC_INT_KPP 60 +#define MXC_INT_PWM1 61 +#define MXC_INT_I2C1 62 +#define MXC_INT_I2C2 63 +#define MXC_INT_HS_I2C 64 +#define MXC_INT_RESV65 65 +#define MXC_INT_RESV66 66 +#define MXC_INT_SIM_IPB 67 +#define MXC_INT_SIM_DAT 68 +#define MXC_INT_IIM 69 +#define MXC_INT_ATA 70 +#define MXC_INT_CCM1 71 +#define MXC_INT_CCM2 72 +#define MXC_INT_GPC1 73 +#define MXC_INT_GPC2 74 +#define MXC_INT_SRC 75 +#define MXC_INT_NM 76 +#define MXC_INT_PMU 77 +#define MXC_INT_CTI_IRQ 78 +#define MXC_INT_CTI1_TG0 79 +#define MXC_INT_CTI1_TG1 80 +#define MXC_INT_MCG_ERR 81 +#define MXC_INT_MCG_TMR 82 +#define MXC_INT_MCG_FUNC 83 +#define MXC_INT_GPU2_IRQ 84 +#define MXC_INT_GPU2_BUSY 85 +#define MXC_INT_RESV86 86 +#define MXC_INT_FEC 87 +#define MXC_INT_OWIRE 88 +#define MXC_INT_CTI1_TG2 89 +#define MXC_INT_SJC 90 +#define MXC_INT_SPDIF 91 +#define MXC_INT_TVE 92 +#define MXC_INT_FIRI 93 +#define MXC_INT_PWM2 94 +#define MXC_INT_SLIM_EXP 95 +#define MXC_INT_SSI3 96 +#define MXC_INT_EMI_BOOT 97 +#define MXC_INT_CTI1_TG3 98 +#define MXC_INT_SMC_RX 99 +#define MXC_INT_VPU_IDLE 100 +#define MXC_INT_EMI_NFC 101 +#define MXC_INT_GPU_IDLE 102 + +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x00 +#define GPIO_GDIR 0x04 +#define GPIO_PSR 0x08 +#define GPIO_ICR1 0x0C +#define GPIO_ICR2 0x10 +#define GPIO_IMR 0x14 +#define GPIO_ISR 0x18 +#define GPIO_INT_LOW_LEV 0x0 +#define GPIO_INT_HIGH_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_FALL_EDGE 0x3 +#define GPIO_INT_NONE 0x4 + +#endif /* __ASM_ARCH_MXC_MX51_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h index 5fa2a07f4eaf..f1cbce461cac 100644 --- a/arch/arm/plat-mxc/include/mach/mxc.h +++ b/arch/arm/plat-mxc/include/mach/mxc.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) * * This program is free software; you can redistribute it and/or @@ -26,9 +26,13 @@ #define MXC_CPU_MX1 1 #define MXC_CPU_MX21 21 +#define MXC_CPU_MX25 25 #define MXC_CPU_MX27 27 #define MXC_CPU_MX31 31 +#define MXC_CPU_MX32 32 #define MXC_CPU_MX35 35 +#define MXC_CPU_MX37 37 +#define MXC_CPU_MX51 51 #ifndef __ASSEMBLY__ extern unsigned int __mxc_cpu_type; @@ -58,6 +62,18 @@ extern unsigned int __mxc_cpu_type; # define cpu_is_mx21() (0) #endif +#ifdef CONFIG_ARCH_MX25 +# ifdef mxc_cpu_type +# undef mxc_cpu_type +# define mxc_cpu_type __mxc_cpu_type +# else +# define mxc_cpu_type MXC_CPU_MX25 +# endif +# define cpu_is_mx25() (mxc_cpu_type == MXC_CPU_MX25) +#else +# define cpu_is_mx25() (0) +#endif + #ifdef CONFIG_MACH_MX27 # ifdef mxc_cpu_type # undef mxc_cpu_type @@ -94,6 +110,558 @@ extern unsigned int __mxc_cpu_type; # define cpu_is_mx35() (0) #endif +#ifdef CONFIG_ARCH_MX37 +# ifdef mxc_cpu_type +# undef mxc_cpu_type +# define mxc_cpu_type __mxc_cpu_type +# else +# define mxc_cpu_type MXC_CPU_MX37 +# endif +# define cpu_is_mx37() (mxc_cpu_type == MXC_CPU_MX37) +#else +# define cpu_is_mx37() (0) +#endif + +#ifdef CONFIG_ARCH_MX51 +# ifdef mxc_cpu_type +# undef mxc_cpu_type +# define mxc_cpu_type __mxc_cpu_type +# else +# define mxc_cpu_type MXC_CPU_MX51 +# endif +# define cpu_is_mx51() (mxc_cpu_type == MXC_CPU_MX51) +#else +# define cpu_is_mx51() (0) +#endif + +#define cpu_is_mx32() (0) + +/* + * Create inline functions to test for cpu revision + * Function name is cpu_is__rev(rev) + * + * Returns: + * 0 - not the cpu queried + * 1 - cpu and revision match + * 2 - cpu matches, but cpu revision is greater than queried rev + * -1 - cpu matches, but cpu revision is less than queried rev + */ +#ifndef __ASSEMBLY__ +extern unsigned int system_rev; +#define mxc_set_system_rev(part, rev) ({ \ + system_rev = (part << 12) | rev; \ +}) +#define mxc_cpu() (system_rev >> 12) +#define mxc_cpu_rev() (system_rev & 0xFF) +#define mxc_cpu_rev_major() ((system_rev >> 4) & 0xF) +#define mxc_cpu_rev_minor() (system_rev & 0xF) +#define mxc_cpu_is_rev(rev) \ + ((mxc_cpu_rev() == rev) ? 1 : ((mxc_cpu_rev() < rev) ? -1 : 2)) +#define cpu_rev(type) \ +static inline int type## _rev (int rev) \ +{ \ + return (type() ? mxc_cpu_is_rev(rev) : 0); \ +} +cpu_rev(cpu_is_mx21); +cpu_rev(cpu_is_mx25); +cpu_rev(cpu_is_mx27); +cpu_rev(cpu_is_mx31); +cpu_rev(cpu_is_mx35); +cpu_rev(cpu_is_mx37); +cpu_rev(cpu_is_mx51); + + +#include + +/*! + * This structure is used to define the One wire platform data. + * It includes search rom accelerator. + */ +struct mxc_w1_config { + int search_rom_accelerator; +}; +/*! + * This structure is used to define the SPI master controller's platform + * data. It includes the SPI bus number and the maximum number of + * slaves/chips it supports. + */ +struct mxc_spi_master { + /*! + * SPI Master's bus number. + */ + unsigned int bus_num; + /*! + * SPI Master's maximum number of chip selects. + */ + unsigned int maxchipselect; + /*! + * CSPI Hardware Version. + */ + unsigned int spi_version; + /*! + * CSPI chipselect pin table. + * Workaround for ecspi chipselect pin may not keep correct level when + * idle. + */ + void (*chipselect_active) (int cspi_mode, int status, int chipselect); + void (*chipselect_inactive) (int cspi_mode, int status, int chipselect); +}; + +struct mxc_ipu_config { + int rev; + struct clk *di_clk[2]; +}; + +struct mxc_ir_platform_data { + int uart_ir_mux; + int ir_rx_invert; + int ir_tx_invert; + struct clk *uart_clk; +}; + +struct mxc_i2c_platform_data { + u32 i2c_clk; +}; + +/* + * This struct is to define the number of SSIs on a platform, + * DAM source port config, DAM external port config, + * regulator names, and other stuff audio needs. + */ +struct mxc_audio_platform_data { + int ssi_num; + int src_port; + int ext_port; + + int intr_id_hp; + int ext_ram; + struct clk *ssi_clk[2]; + char *regulator1; + char *regulator2; + + int hp_irq; + int (*hp_status) (void); + + char *vddio_reg; + char *vdda_reg; + char *vddd_reg; + int vddio; /* voltage of VDDIO (uv) */ + int vdda; /* voltage of vdda (uv) */ + int vddd; /* voltage of vddd (uv), 0 if not connected */ + int sysclk; + + int (*init) (void); /* board specific init */ + int (*amp_enable) (int enable); + int (*finit) (void); /* board specific finit */ + void *priv; /* used by board specific functions */ +}; + +struct mxc_spdif_platform_data { + int spdif_tx; + int spdif_rx; + int spdif_clk_44100; + int spdif_clk_48000; + int spdif_clkid; + struct clk *spdif_clk; + struct clk *spdif_core_clk; + struct clk *spdif_audio_clk; +}; + +struct mxc_asrc_platform_data { + struct clk *asrc_core_clk; + struct clk *asrc_audio_clk; + unsigned int channel_bits; +}; + +struct mxc_bt_platform_data { + char *bt_vdd; + char *bt_vdd_parent; + char *bt_vusb; + char *bt_vusb_parent; + void (*bt_reset) (void); +}; + +struct mxc_lightsensor_platform_data { + char *vdd_reg; + int rext; +}; + +struct mxc_fb_platform_data { + struct fb_videomode *mode; + char *mode_str; + u32 interface_pix_fmt; +}; + +struct mxc_lcd_platform_data { + char *io_reg; + char *core_reg; + char *analog_reg; + void (*reset) (void); +}; + +struct mxc_dvfs_platform_data { + /** Supply voltage regulator name string */ + char *reg_id; + /* CPU clock name string */ + char *clk1_id; + /* DVFS clock name string */ + char *clk2_id; + /* GPC control reg address */ + void __iomem *gpc_cntr_reg_addr; + /* GPC voltage counter reg address */ + void __iomem *gpc_vcr_reg_addr; + /* CCM DVFS control reg address */ + void __iomem *ccm_cdcr_reg_addr; + /* CCM ARM clock root reg address */ + void __iomem *ccm_cacrr_reg_addr; + /* CCM divider handshake in-progree reg address */ + void __iomem *ccm_cdhipr_reg_addr; + /* DVFS threshold reg address */ + void __iomem *dvfs_thrs_reg_addr; + /* DVFS counters reg address */ + void __iomem *dvfs_coun_reg_addr; + /* DVFS EMAC reg address */ + void __iomem *dvfs_emac_reg_addr; + /* DVFS control reg address */ + void __iomem *dvfs_cntr_reg_addr; + /* PREDIV mask */ + u32 prediv_mask; + /* PREDIV offset */ + int prediv_offset; + /* PREDIV value */ + int prediv_val; + /* DIV3CK mask */ + u32 div3ck_mask; + /* DIV3CK offset */ + int div3ck_offset; + /* DIV3CK value */ + int div3ck_val; + /* EMAC value */ + int emac_val; + /* Frequency increase threshold. Increase frequency change request + will be sent if DVFS counter value will be more than this value */ + int upthr_val; + /* Frequency decrease threshold. Decrease frequency change request + will be sent if DVFS counter value will be less than this value */ + int dnthr_val; + /* Panic threshold. Panic frequency change request + will be sent if DVFS counter value will be more than this value */ + int pncthr_val; + /* The amount of times the up threshold should be exceeded + before DVFS will trigger frequency increase request */ + int upcnt_val; + /* The amount of times the down threshold should be exceeded + before DVFS will trigger frequency decrease request */ + int dncnt_val; + /* Delay time in us */ + int delay_time; + /* Number of woking points supported */ + int num_wp; +}; + +struct mxc_tsc_platform_data { + char *vdd_reg; + int penup_threshold; + void (*active) (void); + void (*inactive) (void); +}; + +struct mxc_tvout_platform_data { + char *io_reg; + char *core_reg; + char *analog_reg; + u32 detect_line; +}; + +struct mxc_tvin_platform_data { + char *dvddio_reg; + char *dvdd_reg; + char *avdd_reg; + char *pvdd_reg; + void (*pwdn) (int pwdn); + void (*reset) (void); +}; + +/*! Platform data for the IDE drive structure. */ +struct mxc_ide_platform_data { + char *power_drive; /*!< The power pointer */ + char *power_io; /*!< The power pointer */ +}; + +struct mxc_camera_platform_data { + char *core_regulator; + char *io_regulator; + char *analog_regulator; + char *gpo_regulator; + u32 mclk; + u32 csi; +}; + +/*gpo1-3 is in fixed state by hardware design, + * only deal with reset pin and clock_enable pin + * only poll mode can be used to control the chip, + * interrupt mode is not supported by 3ds*/ +struct mxc_fm_platform_data { + char *reg_vio; + char *reg_vdd; + void (*gpio_get) (void); + void (*gpio_put) (void); + void (*reset) (void); + void (*clock_ctl) (int flag); + u8 sksnr; /*0,disable;1,most stop;0xf,fewest stop*/ + u8 skcnt; /*0,disable;1,most stop;0xf,fewest stop*/ + /* + 00 = 87.5-108 MHz (USA,Europe) (Default). + 01 = 76-108 MHz (Japan wide band). + 10 = 76-90 MHz (Japan). + 11 = Reserved. + */ + u8 band; + /* + 00 = 200 kHz (USA, Australia) (default). + 01 = 100 kHz (Europe, Japan). + 10 = 50 kHz. + */ + u8 space; + u8 seekth; +}; + +struct mxc_mma7450_platform_data { + char *reg_dvdd_io; + char *reg_avdd; + void (*gpio_pin_get) (void); + void (*gpio_pin_put) (void); + int int1; + int int2; +}; + +struct mxc_keyp_platform_data { + u16 *matrix; + void (*active) (void); + void (*inactive) (void); + char *vdd_reg; +}; + +struct mxc_unifi_platform_data { + void (*hardreset) (int pin_level); + void (*enable) (int en); + /* power parameters */ + char *reg_gpo1; + char *reg_gpo2; + char *reg_1v5_ana_bb; + char *reg_vdd_vpa; + char *reg_1v5_dd; + + int host_id; + + void *priv; +}; + +struct mxc_gps_platform_data { + char *core_reg; + char *analog_reg; + struct regulator *gps_regu_core; + struct regulator *gps_regu_analog; +}; + +struct mxc_mlb_platform_data { + u32 buf_address; + u32 phy_address; + char *reg_nvcc; + char *mlb_clk; +}; + +struct flexcan_platform_data { + char *core_reg; + char *io_reg; + void (*xcvr_enable) (int id, int en); + void (*active) (int id); + void (*inactive) (int id); +}; + +struct mxc_srtc_platform_data { + u32 srtc_sec_mode_addr; +}; + +struct tve_platform_data { + char *dac_reg; + char *dig_reg; +}; + +/* The name that links the i.MX NAND Flash Controller driver to its devices. */ + +#define IMX_NFC_DRIVER_NAME ("imx_nfc") + +/* Resource names for the i.MX NAND Flash Controller driver. */ + +#define IMX_NFC_BUFFERS_ADDR_RES_NAME \ + ("i.MX NAND Flash Controller Buffer") +#define IMX_NFC_PRIMARY_REGS_ADDR_RES_NAME \ + ("i.MX NAND Flash Controller Primary Registers") +#define IMX_NFC_SECONDARY_REGS_ADDR_RES_NAME \ + ("i.MX NAND Flash Controller Secondary Registers") +#define IMX_NFC_INTERRUPT_RES_NAME \ + ("i.MX NAND Flash Controller Interrupt") + +/** + * struct imx_nfc_platform_data - i.MX NFC driver platform data. + * + * This structure communicates information to the i.MX NFC driver that can't be + * expressed as resources. + * + * @nfc_major_version: The "major version" of the NFC hardware. + * @nfc_minor_version: The "minor version" of the NFC hardware. + * @force_ce: If true, this flag causes the driver to assert the + * hardware chip enable signal for the currently selected + * chip as long as the MTD NAND Flash HAL has the chip + * selected (not just when an I/O transaction is in + * progress). + * @target_cycle_in_ns: The target read and write cycle period, in nanoseconds. + * NAND Flash part data sheets give minimum times for read + * and write cycles in nanoseconds (usually tRC and tWC, + * respectively). Set this value to the maximum of these + * two parameters. The driver will set the NFC clock as + * close as possible without violating this value. + * @clock_name: The name of the clock used by the NAND Flash controller. + * @init: A pointer to a function the driver must call so the + * platform can prepare for this device to operate. This + * pointer may be NULL. + * @exit: A pointer to a function the driver must call so the + * platform clean up after this device stops operating. + * This pointer may be NULL. + * @set_page_size: A pointer to a function the driver can call to set the + * page size. This pointer may be NULL. + * + * For some i.MX SoC's, the NFC gets information about the + * page size from signals driven by a system register + * outside the NFC. The address and format of this external + * register varies across SoC's. In other SoC's, the NFC + * still receives this signal, but it is overridden by a + * page size register in the NFC itself. + * + * For SoC's where the page size *must* be set in an + * external register, the driver must rely on a platform- + * specific function, and this member must point to it. + * + * For SoC's where the NFC has its own page size register, + * the driver will set that register itself and ignore the + * external signals. In this case, there's no need for the + * platform-specific function and this member must be NULL. + * + * This function accepts the page size in bytes (MTD calls + * this the "writesize") discovered by the NAND Flash MTD + * base driver (e.g., 512, 2048, 4096). This size refers + * specifically to the the data bytes in the page, *not* + * including out-of-band bytes. The return value is zero if + * the operation succeeded. The driver does *not* view a + * non-zero value as an error code - only an indication of + * failure. The driver will decide for itself what error + * code to return to its caller. + * @interleave: Indicates that the driver should "interleave" the NAND + * Flash chips it finds. If true, the driver will aggregate + * the chips "horizontally" such that MTD will see a single + * chip with a potentially very large page size. This can + * improve write performance for some applications. + * @partitions: An optional pointer to an array of partitions. If this + * is NULL, the driver will create a single MTD that + * represents the entire medium. + * @partition_count: The number of elements in the partition array. + */ + +struct imx_nfc_platform_data { + unsigned int nfc_major_version; + unsigned int nfc_minor_version; + int force_ce; + unsigned int target_cycle_in_ns; + char *clock_name; + int (*init)(void); + void (*exit)(void); + int (*set_page_size)(unsigned int data_size_in_bytes); + int interleave; + struct mtd_partition *partitions; + unsigned int partition_count; +}; + +extern void mxc_wd_reset(void); +unsigned long board_get_ckih_rate(void); + +int mxc_snoop_set_config(u32 num, unsigned long base, int size); +int mxc_snoop_get_status(u32 num, u32 * statl, u32 * stath); + +struct platform_device; +void mxc_pg_enable(struct platform_device *pdev); +void mxc_pg_disable(struct platform_device *pdev); + +struct mxc_unifi_platform_data *get_unifi_plat_data(void); + +struct mxc_sim_platform_data { + unsigned int clk_rate; + char *clock_sim; + char *power_sim; + int (*init)(struct platform_device *pdev); + void (*exit)(void); + unsigned int detect; /* 1 have detect pin, 0 not */ +}; + +#endif /* __ASSEMBLY__ */ + +#define MUX_IO_P 29 +#define MUX_IO_I 24 +#define IOMUX_TO_GPIO(pin) ((((unsigned int)pin >> MUX_IO_P) * 32) + ((pin >> MUX_IO_I) & ((1 << (MUX_IO_P - MUX_IO_I)) -1))) +#define IOMUX_TO_IRQ(pin) (MXC_GPIO_IRQ_START + IOMUX_TO_GPIO(pin)) + +/* DMA driver defines */ +#define MXC_IDE_DMA_WATERMARK 32 /* DMA watermark level in bytes */ +#define MXC_IDE_DMA_BD_NR (512/3/4) /* Number of BDs per channel */ + +#ifndef IS_MEM_DEVICE_NONSHARED +/* all peripherals on MXC so far are below 0x80000000 but leave L2CC alone */ +#define IS_MEM_DEVICE_NONSHARED(x) ((x) < 0x80000000 && (x) != L2CC_BASE_ADDR) +#endif +/*! + * DPTC GP and LP ID + */ +#define DPTC_GP_ID 0 +#define DPTC_LP_ID 1 + +#ifndef __ASSEMBLY__ + +struct cpu_wp { + u32 pll_reg; + u32 pll_rate; + u32 cpu_rate; + u32 pdr0_reg; + u32 pdf; + u32 mfi; + u32 mfd; + u32 mfn; + u32 cpu_voltage; + u32 cpu_podf; +}; + +#ifndef CONFIG_ARCH_MX51 +struct cpu_wp *get_cpu_wp(int *wp); +#endif + +enum mxc_cpu_pwr_mode { + WAIT_CLOCKED, /* wfi only */ + WAIT_UNCLOCKED, /* WAIT */ + WAIT_UNCLOCKED_POWER_OFF, /* WAIT + SRPG */ + STOP_POWER_ON, /* just STOP */ + STOP_POWER_OFF, /* STOP + SRPG */ +}; + +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode); +int tzic_enable_wake(int is_idle); +void gpio_activate_audio_ports(void); +void gpio_inactivate_audio_ports(void); +void gpio_activate_bt_audio_port(void); +void gpio_inactivate_bt_audio_port(void); +void gpio_activate_esai_ports(void); +void gpio_deactivate_esai_ports(void); + +#endif + #if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2) #define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10) #define CSCR_L(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10 + 0x4) diff --git a/arch/arm/plat-mxc/include/mach/mxc_dptc.h b/arch/arm/plat-mxc/include/mach/mxc_dptc.h new file mode 100644 index 000000000000..b42fc36af3e1 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_dptc.h @@ -0,0 +1,111 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup DPTC Dynamic Process and Temperatur Compensation (DPTC) Driver + */ + +/*! + * @file arch-mxc/mxc_dptc.h + * + * @brief This file contains the DPTC configuration structure definition. + * + * + * @ingroup DPTC + */ + +#ifndef __ASM_ARCH_MXC_DPTC_H__ +#define __ASM_ARCH_MXC_DPTC_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#define DPTC_WP_SUPPORTED 17 +#define DPTC_GP_WP_SUPPORTED 7 +#define DPTC_LP_WP_SUPPORTED 9 + +struct dptc_wp { + u32 dcvr0; + u32 dcvr1; + u32 dcvr2; + u32 dcvr3; + u32 voltage; +}; + +/*! + * This structure is used to define the dptc controller's platform + * data. It includes the regulator name string and DPTC clock name string. + */ +struct mxc_dptc_data { + /** Regulator name string */ + char *reg_id; + /* DPTC clock name string */ + char *clk_id; + /* Control reg address */ + unsigned int dptccr_reg_addr; + /* Comparator value reg 0 address */ + unsigned int dcvr0_reg_addr; + /* GPC control reg address */ + unsigned int gpc_cntr_reg_addr; + /* DPTC interrupt status bit */ + unsigned int dptccr; + /* The number of DPTC working points */ + unsigned int dptc_wp_supported; + /* Maximum value of DPTC clock rate */ + unsigned long clk_max_val; + /* DPTC working points */ + struct dptc_wp *dptc_wp_allfreq; + /* DPTC enable bit */ + u32 dptc_enable_bit; + /* DPTC ADU bit */ + int gpc_adu; + /* VAI mask */ + u32 vai_mask; + /* VAI offset */ + int vai_offset; + /* Mask DPTC interrupt */ + u32 irq_mask; + /* DPTC no voltage change request bit */ + u32 dptc_nvcr_bit; + /* ARM interrrupt bit */ + u32 gpc_irq_bit; + /* dptc init config */ + u32 init_config; + /* dptc enable config */ + u32 enable_config; + /* dptc counting range mask */ + u32 dcr_mask; +}; + +/*! + * This function is called to put the DPTC in a low power state. + * + * @param id The DPTC device id. DPTC_GP_ID is for DPTC GP; + * DPTC_LP_ID is for DPTC LP + */ +void dptc_suspend(int id); +/*! + * This function is called to resume the DPTC from a low power state. + * + * @param id The DPTC device id. DPTC_GP_ID is for DPTC GP; + * DPTC_LP_ID is for DPTC LP + */ +void dptc_resume(int id); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_DPTC_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h new file mode 100644 index 000000000000..99ddb077d9d1 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h @@ -0,0 +1,51 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup DVFS Dynamic Voltage and Frequency Scaling (DVFS) Driver + */ + +/*! + * @file arch-mxc/mxc_dvfs.h + * + * @brief This file contains the DVFS configuration structure definition. + * + * + * @ingroup DVFS + */ + +#ifndef __ASM_ARCH_MXC_DVFS_H__ +#define __ASM_ARCH_MXC_DVFS_H__ + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* + * DVFS structure + */ +struct dvfs_wp { + int upthr; + int downthr; + int panicthr; + int upcnt; + int downcnt; + int emac; +}; + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_DVFS_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mxc_edid.h b/arch/arm/plat-mxc/include/mach/mxc_edid.h new file mode 100644 index 000000000000..aac49ad93ec5 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_edid.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup Framebuffer Framebuffer Driver for SDC and ADC. + */ + +/*! + * @file mxc_edid.h + * + * @brief MXC EDID tools + * + * @ingroup Framebuffer + */ + +#ifndef MXC_EDID_H +#define MXC_EDID_H + +int read_edid(struct i2c_adapter *adp, + struct fb_var_screeninfo *einfo, + int *dvi); + +#endif diff --git a/arch/arm/plat-mxc/include/mach/mxc_gpc.h b/arch/arm/plat-mxc/include/mach/mxc_gpc.h new file mode 100644 index 000000000000..d3b3ae2d1b13 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_gpc.h @@ -0,0 +1,74 @@ + +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup LPMD Low-Level Power Management Driver + */ + +/*! + * @file arch-mxc/mxc_gpc.h + * + * @brief This file contains the chip level configuration details and + * public API declarations for GPC module + * + * @ingroup LPMD + */ + +#ifndef __ASM_ARCH_MXC_GPC_H__ +#define __ASM_ARCH_MXC_GPC_H__ + +/* AP Power Gating modules */ +typedef enum { + POWER_GATING_MODULE_AP_EMBEDDED_MEM_DEEPSLEEP, + POWER_GATING_MODULE_DISPLAY_BUFFER, + POWER_GATING_MODULE_EMI_DEEPSLEEP, + POWER_GATING_MODULE_IPU_STOP, + POWER_GATING_MODULE_L2_MEM_STOP, + POWER_GATING_MODULE_ARM_PLATFORM_STOP, +} mxc_pm_ap_power_gating_modules_t; + +/* AP Power Gating pull-down config of modules */ +typedef enum { + POWER_GATING_PULL_DOWN_DISPLAY_BUFFER, + POWER_GATING_PULL_DOWN_EMI, + POWER_GATING_PULL_DOWN_IPU, + POWER_GATING_PULL_DOWN_L2_MEM, + POWER_GATING_PULL_DOWN_ARMPLATFORM, +} mxc_pm_ap_power_gating_pulldown_t; + +/*! + * This function enables/disables the AP power gating by writing the APPCR + * register of the GPC module. + * + * @param enable Enable/Disable module power down + * 0 - disable; 1 - enable + * @param modules The desired module to be power gated + * + */ +void mxc_gpc_powergate_module(int enable, + mxc_pm_ap_power_gating_modules_t module); + +/*! + * This function enables/disables the AP power gating pull down selection of a + * module by writing the APPCR register of the GPC module. + * + * @param enable Enable/Disable module pull down + * 0 - disable; 1 - enable + * @param modules The desired module to be pulled down + * + */ +void mxc_gpc_powergate_pulldown(int enable, + mxc_pm_ap_power_gating_pulldown_t pulldown); + +#endif diff --git a/arch/arm/plat-mxc/include/mach/mxc_pm.h b/arch/arm/plat-mxc/include/mach/mxc_pm.h new file mode 100644 index 000000000000..b4d389a6611e --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_pm.h @@ -0,0 +1,252 @@ + +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup LPMD Low-Level Power Management Driver + */ + +/*! + * @file arch-mxc/mxc_pm.h + * + * @brief This file contains the chip level configuration details and + * public API declarations for CRM_AP module + * + * @ingroup LPMD + */ + +#ifndef __ASM_ARCH_MXC_PM_H__ +#define __ASM_ARCH_MXC_PM_H__ + +#define WAIT_MODE 111 +#define DOZE_MODE 112 +#define STOP_MODE 113 +#define DSM_MODE 114 +/* + * MXC91231 Break-Point Frequency below which is low frequency and + * above which is high frequency + */ +#define BREAKPT_FREQ ((long)(400000000)) + +#define GATE_STOP_WAIT 9 +#define GATE_STOP 10 + +/* + * Used for MHz conversion + */ +#define MEGA_HERTZ 1000000 + +/* + * If invalid frequency value other than the following + * CORE_133 - ARM desired to run @133MHz, LoV (1.2V) + * CORE_266 - ARM desired to run @266MHz, LoV (1.2V) + * CORE_399 - ARM desired to run @399MHz, LoV (1.2V) + * CORE_532 - ARM desired to run @133MHz, HiV (1.6V) + * are passed then this error is returned, + */ +#define ERR_FREQ_INVALID 1 + +/* + * For MXC91231 Pass1, Integer DVFS greater than 133MHz is not allowed + * due to the hardware issue + */ +#define INTEGER_DVFS_NOT_ALLOW 1 + +/* + * If PLL freq is less than desired ARM frequency during Integer + * DVFS, then return this error + */ +#define PLL_LESS_ARM_ERR 2 + +/* + * Frequency change within the same-lo voltage is not approved. + * Inorder to do Integer DFS, move to the high voltage range and + * then set LFDF and move to the low voltage range + */ +#define INT_DFS_LOW_NOT_ALLOW 3 + +/* + * If the desired AHB or IPG exceeds 133MHz or 66.5MHz respectively, + * then return this error + */ +#define AHB_IPG_EXCEED_LIMIT 4 + +/* + * If the desired ARM frequency is too low to get by PLL scaling + * and the mxc_pm_pllscale API is called, return this error: + */ +#define PLL_DVFS_FREQ_TOO_LOW 5 + +/* + * Invalid frequencies requested + */ +#define MXC_PM_INVALID_PARAM 6 + +/* + * If AHB and/or IPG frequencies are greater than maximum allowed + */ +#define FREQ_OUT_OF_RANGE 2 + +/* + * If AHB and/or IPG frequencies are other than 100 or 50Mhz + */ +#define BUS_FREQ_INVALID 2 + +/* + * If MAX_PDF is greater than max value (8) then return this error + */ +#define AHB_MAX_DIV_ERR 3 + +/* + * If IPG_PDF is greater than max value (2) then return this error + */ +#define IPG_MAX_DIV_ERR 4 + +/* + * If ARM freq is out of range i.e., less than 133 or greater than + * 399 then return this error + */ +#define INVALID_ARM_FREQ 5 + +/* + * This file includes all platform APIs. Some of the APIs are not + * appicable to some platforms. So, this error is used to indicate + * that a particular API is not available + */ +#define MXC_PM_API_NOT_SUPPORTED 6 + +/* + * Error when frequency scaling is attempted while switch between MPLL and + * TPLL is in progress on MXC91321 + */ +#define ERR_DFSP_SWITCH 2 + +/*! + * Additional define for stop mode + */ +#define PM_SUSPEND_STOP ((__force suspend_state_t) 2) + +/*! + * CKOH pins configuration + */ +#define CKOH_AP_SEL 1 +#define CKOH_AHB_SEL 2 +#define CKOH_IP_SEL 3 + +/*! + * Defines for Stop and DSM mode acknowledgements + */ +#define MXC_PM_LOWPWR_ACK_SDMA 0x01 +#define MXC_PM_LOWPWR_ACK_IPU 0x02 +#define MXC_PM_LOWPWR_ACK_MAX 0x04 +#define MXC_PM_LOWPWR_ACK_MQSPI 0x08 +#define MXC_PM_LOWPWR_ACK_USB 0x10 +#define MXC_PM_LOWPWR_ACK_RTIC 0x20 + +/* + * PMIC configuration + */ +#define MXC_PMIC_1_2_VOLT 0xC +#define MXC_PMIC_1_6_VOLT 0x1C +#define MXC_PMIC_1_0_VOLT 0x4 +#if defined(CONFIG_ARCH_MXC91321) || defined(CONFIG_ARCH_MXC91231) +#define MXC_PMIC_DVS_SPEED 0x1 +#else +#define MXC_PMIC_DVS_SPEED 0x3 +#endif + +/*! + * Implementing Level 1 CRM Gate Control. Level 2 gate control + * is provided at module level using LPMD registers + * + * @param group The desired clock gate control register bits. + * Possible values are 0 through 6 + * @param opt The desired option requesting clock to run during stop + * and wait modes or just during the stop mode. Possible + * values are GATE_STOP_WAIT and GATE_STOP. + * + */ +void mxc_pm_clockgate(int group, int opt); + +/*! + * Implementing steps required to transition to low-power modes + * + * @param mode The desired low-power mode. Possible values are, + * WAIT_MODE, STOP_MODE or DSM_MODE + * + */ +void mxc_pm_lowpower(int mode); + +/*! + * Enables acknowledgement from module when entering stop or DSM mode. + * + * @param ack The desired module acknowledgement to enable. + * + */ +void mxc_pm_lp_ack_enable(int ack); + +/*! + * Disables acknowledgement from module when entering stop or DSM mode. + * + * @param ack The desired module acknowledgement to disable. + * + */ +void mxc_pm_lp_ack_disable(int ack); + +/*! + * Implementing steps required to set Integer Scaling + * + * @param armfreq The desired ARM frequency. AHB and IP + * frequency are changed depending on ARM + * frequency and the divider values. + * @param ahbfreq The desired AHB frequency + * @param ipfreq The desired IP frequency + * + * @return Returns 0 on success or + * Returns -PLL_LESS_ARM_ERR if pllfreq is less than + * desired core freq + */ +int mxc_pm_intscale(long armfreq, long ahbfreq, long ipfreq); + +/*! + * To calculate MFI, MFN, MFD values. Using this the output frequency + * whose value is calculated using, + * 2 * REF_FREQ * (MF / PDF), where + * REF_FREQ is 26 Mhz + * MF = MFI + (MFN + MFD) + * PDF is assumed to be 1 + * + * @param armfreq The desired ARM frequency + * @param ahbfreq The desired AHB frequency + * @param ipfreq The desired IP frequency + * + * @return Returns 0 on success or + * Returns -1 on error + */ +int mxc_pm_pllscale(long armfreq, long ahbfreq, long ipfreq); + +/*! + * To change AP core frequency and/or voltage suitably + * + * @param armfreq The desired ARM frequency + * @param ahbfreq The desired AHB frequency + * @param ipfreq The desired IP frequency + * + * @return Returns -ERR_FREQ_INVALID on failure + * Returns 0 on success + */ +int mxc_pm_dvfs(unsigned long armfreq, long ahbfreq, long ipfreq); + +extern void mxc_pm_arch_entry(void *entry, u32 size); + +#endif diff --git a/arch/arm/plat-mxc/include/mach/mxc_scc.h b/arch/arm/plat-mxc/include/mach/mxc_scc.h new file mode 100644 index 000000000000..d23f6c3e9913 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_scc.h @@ -0,0 +1,45 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file arch-mxc/mxc_scc.h + * + * @brief This is intended to be the file which contains all of code or changes + * needed to port the driver. + * + * @ingroup MXCSCC + */ + +#ifndef __ASM_ARCH_MXC_SCC_H__ +#define __ASM_ARCH_MXC_SCC_H__ + +#include + +/*! + * Expected to come from platform header files. + * This symbol must be the address of the SCC + */ +#define SCC_BASE SCC_BASE_ADDR + +/*! + * This must be the interrupt line number of the SCM interrupt. + */ +#define INT_SCC_SCM MXC_INT_SCC_SCM + +/*! + * if #USE_SMN_INTERRUPT is defined, this must be the interrupt line number of + * the SMN interrupt. + */ +#define INT_SCC_SMN MXC_INT_SCC_SMN + +#endif diff --git a/arch/arm/plat-mxc/include/mach/mxc_timer.h b/arch/arm/plat-mxc/include/mach/mxc_timer.h new file mode 100644 index 000000000000..59fe2dceeb07 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_timer.h @@ -0,0 +1,157 @@ +/* + * mxc_timer.h + * + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * Platform independent (i.MX1, i.MX2, i.MX3) definition for timer handling. + * + * 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. + */ + +#ifndef __PLAT_MXC_TIMER_H +#define __PLAT_MXC_TIMER_H + +#include +#include + +#ifdef CONFIG_ARCH_IMX +#define TIMER_BASE IO_ADDRESS(TIM1_BASE_ADDR) +#define TIMER_INTERRUPT TIM1_INT + +#define TCTL_VAL TCTL_CLK_PCLK1 +#define TCTL_IRQEN (1<<4) +#define TCTL_FRR (1<<8) +#define TCTL_CLK_PCLK1 (1<<1) +#define TCTL_CLK_PCLK1_4 (2<<1) +#define TCTL_CLK_TIN (3<<1) +#define TCTL_CLK_32 (4<<1) + +#define MXC_TCTL 0x00 +#define MXC_TPRER 0x04 +#define MXC_TCMP 0x08 +#define MXC_TCR 0x0c +#define MXC_TCN 0x10 +#define MXC_TSTAT 0x14 +#define TSTAT_CAPT (1<<1) +#define TSTAT_COMP (1<<0) + +static inline void gpt_irq_disable(void) +{ + unsigned int tmp; + + tmp = __raw_readl(TIMER_BASE + MXC_TCTL); + __raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL); +} + +static inline void gpt_irq_enable(void) +{ + __raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN, + TIMER_BASE + MXC_TCTL); +} + +static void gpt_irq_acknowledge(void) +{ + __raw_writel(0, TIMER_BASE + MXC_TSTAT); +} + +#elif defined(CONFIG_ARCH_MX2) +#define TIMER_BASE IO_ADDRESS(GPT1_BASE_ADDR) +#define TIMER_INTERRUPT MXC_INT_GPT1 + +#define MXC_TCTL 0x00 +#define TCTL_VAL TCTL_CLK_PCLK1 +#define TCTL_CLK_PCLK1 (1<<1) +#define TCTL_CLK_PCLK1_4 (2<<1) +#define TCTL_IRQEN (1<<4) +#define TCTL_FRR (1<<8) +#define MXC_TPRER 0x04 +#define MXC_TCMP 0x08 +#define MXC_TCR 0x0c +#define MXC_TCN 0x10 +#define MXC_TSTAT 0x14 +#define TSTAT_CAPT (1<<1) +#define TSTAT_COMP (1<<0) + +static inline void gpt_irq_disable(void) +{ + unsigned int tmp; + + tmp = __raw_readl(TIMER_BASE + MXC_TCTL); + __raw_writel(tmp & ~TCTL_IRQEN, TIMER_BASE + MXC_TCTL); +} + +static inline void gpt_irq_enable(void) +{ + __raw_writel(__raw_readl(TIMER_BASE + MXC_TCTL) | TCTL_IRQEN, + TIMER_BASE + MXC_TCTL); +} + +static void gpt_irq_acknowledge(void) +{ + __raw_writel(TSTAT_CAPT | TSTAT_COMP, TIMER_BASE + MXC_TSTAT); +} + +#else +#define TIMER_BASE IO_ADDRESS(GPT1_BASE_ADDR) +#define TIMER_INTERRUPT MXC_INT_GPT + +#define MXC_TCTL 0x00 +#define TCTL_VAL (TCTL_CLK_HIGH_FREQ | TCTL_WAITEN) +#define TCTL_CLK_IPG (1<<6) +#define TCTL_CLK_HIGH_FREQ (2<<6) +#define TCTL_FRR (1<<9) +#define TCTL_WAITEN (1<<3) + +#define MXC_TPRER 0x04 +#define MXC_TSTAT 0x08 +#define TSTAT_OF1 (1<<0) +#define TSTAT_OF2 (1<<1) +#define TSTAT_OF3 (1<<2) +#define TSTAT_IF1 (1<<3) +#define TSTAT_IF2 (1<<4) +#define TSTAT_ROV (1<<5) +#define MXC_IR 0x0c +#define MXC_TCMP 0x10 +#define MXC_TCMP2 0x14 +#define MXC_TCMP3 0x18 +#define MXC_TCR 0x1c +#define MXC_TCN 0x24 + +static inline void gpt_irq_disable(void) +{ + __raw_writel(0, TIMER_BASE + MXC_IR); +} + +static inline void gpt_irq_enable(void) +{ + __raw_writel(1<<0, TIMER_BASE + MXC_IR); +} + +static inline void gpt_irq_acknowledge(void) +{ + __raw_writel(TSTAT_OF1, TIMER_BASE + MXC_TSTAT); +} +#endif /* CONFIG_ARCH_MX3 */ + +#define TCTL_SWR (1<<15) +#define TCTL_CC (1<<10) +#define TCTL_OM (1<<9) +#define TCTL_CAP_RIS (1<<6) +#define TCTL_CAP_FAL (2<<6) +#define TCTL_CAP_RIS_FAL (3<<6) +#define TCTL_CAP_ENA (1<<5) +#define TCTL_TEN (1<<0) + +#endif diff --git a/arch/arm/plat-mxc/include/mach/mxc_uart.h b/arch/arm/plat-mxc/include/mach/mxc_uart.h new file mode 100644 index 000000000000..d1db8023d724 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_uart.h @@ -0,0 +1,275 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup UART Universal Asynchronous Receiver Transmitter (UART) Driver + */ + +/*! + * @file arch-mxc/mxc_uart.h + * + * @brief This file contains the UART configuration structure definition. + * + * + * @ingroup UART + */ + +#ifndef __ASM_ARCH_MXC_UART_H__ +#define __ASM_ARCH_MXC_UART_H__ + +#ifdef __KERNEL__ + +#include +#include + +/* + * The modes of the UART ports + */ +#define MODE_DTE 0 +#define MODE_DCE 1 +/* + * Is the UART configured to be a IR port + */ +#define IRDA 0 +#define NO_IRDA 1 + +/*! + * This structure is used to store the the physical and virtual + * addresses of the UART DMA receive buffer. + */ +typedef struct { + /*! + * DMA Receive buffer virtual address + */ + char *rx_buf; + /*! + * DMA Receive buffer physical address + */ + dma_addr_t rx_handle; +} mxc_uart_rxdmamap; + +/*! + * This structure is a way for the low level driver to define their own + * \b uart_port structure. This structure includes the core \b uart_port + * structure that is provided by Linux as an element and has other + * elements that are specifically required by this low-level driver. + */ +typedef struct { + /*! + * The port structure holds all the information about the UART + * port like base address, and so on. + */ + struct uart_port port; + /*! + * Flag to determine if the interrupts are muxed. + */ + int ints_muxed; + /*! + * Array that holds the receive and master interrupt numbers + * when the interrupts are not muxed. + */ + int irqs[2]; + /*! + * Flag to determine the DTE/DCE mode. + */ + int mode; + /*! + * Flag to hold the IR mode of the port. + */ + int ir_mode; + /*! + * Flag to enable/disable the UART port. + */ + int enabled; + /*! + * Flag to indicate if we wish to use hardware-driven hardware + * flow control. + */ + int hardware_flow; + /*! + * Holds the threshold value at which the CTS line is deasserted in + * case we use hardware-driven hardware flow control. + */ + unsigned int cts_threshold; + /*! + * Flag to enable/disable DMA data transfer. + */ + int dma_enabled; + /*! + * Holds the DMA receive buffer size. + */ + int dma_rxbuf_size; + /*! + * DMA Receive buffers information + */ + mxc_uart_rxdmamap *rx_dmamap; + /*! + * DMA RX buffer id + */ + int dma_rxbuf_id; + /*! + * DMA Transmit buffer virtual address + */ + char *tx_buf; + /*! + * DMA Transmit buffer physical address + */ + dma_addr_t tx_handle; + /*! + * Holds the RxFIFO threshold value. + */ + unsigned int rx_threshold; + /*! + * Holds the TxFIFO threshold value. + */ + unsigned int tx_threshold; + /*! + * Information whether this is a shared UART + */ + unsigned int shared; + /*! + * Clock id for UART clock + */ + struct clk *clk; + /*! + * Information whether RXDMUXSEL must be set or not for IR port + */ + int rxd_mux; + int ir_tx_inv; + int ir_rx_inv; + /*! + * DMA ID for transmit + */ + mxc_dma_device_t dma_tx_id; + /*! + * DMA ID for receive + */ + mxc_dma_device_t dma_rx_id; +} uart_mxc_port; + +/* Address offsets of the UART registers */ +#define MXC_UARTURXD 0x000 /* Receive reg */ +#define MXC_UARTUTXD 0x040 /* Transmitter reg */ +#define MXC_UARTUCR1 0x080 /* Control reg 1 */ +#define MXC_UARTUCR2 0x084 /* Control reg 2 */ +#define MXC_UARTUCR3 0x088 /* Control reg 3 */ +#define MXC_UARTUCR4 0x08C /* Control reg 4 */ +#define MXC_UARTUFCR 0x090 /* FIFO control reg */ +#define MXC_UARTUSR1 0x094 /* Status reg 1 */ +#define MXC_UARTUSR2 0x098 /* Status reg 2 */ +#define MXC_UARTUESC 0x09C /* Escape character reg */ +#define MXC_UARTUTIM 0x0A0 /* Escape timer reg */ +#define MXC_UARTUBIR 0x0A4 /* BRM incremental reg */ +#define MXC_UARTUBMR 0x0A8 /* BRM modulator reg */ +#define MXC_UARTUBRC 0x0AC /* Baud rate count reg */ +#define MXC_UARTONEMS 0x0B0 /* One millisecond reg */ +#define MXC_UARTUTS 0x0B4 /* Test reg */ + +/* Bit definations of UCR1 */ +#define MXC_UARTUCR1_ADEN 0x8000 +#define MXC_UARTUCR1_ADBR 0x4000 +#define MXC_UARTUCR1_TRDYEN 0x2000 +#define MXC_UARTUCR1_IDEN 0x1000 +#define MXC_UARTUCR1_RRDYEN 0x0200 +#define MXC_UARTUCR1_RXDMAEN 0x0100 +#define MXC_UARTUCR1_IREN 0x0080 +#define MXC_UARTUCR1_TXMPTYEN 0x0040 +#define MXC_UARTUCR1_RTSDEN 0x0020 +#define MXC_UARTUCR1_SNDBRK 0x0010 +#define MXC_UARTUCR1_TXDMAEN 0x0008 +#define MXC_UARTUCR1_ATDMAEN 0x0004 +#define MXC_UARTUCR1_DOZE 0x0002 +#define MXC_UARTUCR1_UARTEN 0x0001 + +/* Bit definations of UCR2 */ +#define MXC_UARTUCR2_ESCI 0x8000 +#define MXC_UARTUCR2_IRTS 0x4000 +#define MXC_UARTUCR2_CTSC 0x2000 +#define MXC_UARTUCR2_CTS 0x1000 +#define MXC_UARTUCR2_PREN 0x0100 +#define MXC_UARTUCR2_PROE 0x0080 +#define MXC_UARTUCR2_STPB 0x0040 +#define MXC_UARTUCR2_WS 0x0020 +#define MXC_UARTUCR2_RTSEN 0x0010 +#define MXC_UARTUCR2_ATEN 0x0008 +#define MXC_UARTUCR2_TXEN 0x0004 +#define MXC_UARTUCR2_RXEN 0x0002 +#define MXC_UARTUCR2_SRST 0x0001 + +/* Bit definations of UCR3 */ +#define MXC_UARTUCR3_DTREN 0x2000 +#define MXC_UARTUCR3_PARERREN 0x1000 +#define MXC_UARTUCR3_FRAERREN 0x0800 +#define MXC_UARTUCR3_DSR 0x0400 +#define MXC_UARTUCR3_DCD 0x0200 +#define MXC_UARTUCR3_RI 0x0100 +#define MXC_UARTUCR3_RXDSEN 0x0040 +#define MXC_UARTUCR3_AWAKEN 0x0010 +#define MXC_UARTUCR3_DTRDEN 0x0008 +#define MXC_UARTUCR3_RXDMUXSEL 0x0004 +#define MXC_UARTUCR3_INVT 0x0002 + +/* Bit definations of UCR4 */ +#define MXC_UARTUCR4_CTSTL_OFFSET 10 +#define MXC_UARTUCR4_CTSTL_MASK (0x3F << 10) +#define MXC_UARTUCR4_INVR 0x0200 +#define MXC_UARTUCR4_ENIRI 0x0100 +#define MXC_UARTUCR4_REF16 0x0040 +#define MXC_UARTUCR4_IRSC 0x0020 +#define MXC_UARTUCR4_TCEN 0x0008 +#define MXC_UARTUCR4_OREN 0x0002 +#define MXC_UARTUCR4_DREN 0x0001 + +/* Bit definations of UFCR */ +#define MXC_UARTUFCR_RFDIV 0x0200 /* Ref freq div is set to 2 */ +#define MXC_UARTUFCR_RFDIV_OFFSET 7 +#define MXC_UARTUFCR_RFDIV_MASK (0x7 << 7) +#define MXC_UARTUFCR_TXTL_OFFSET 10 +#define MXC_UARTUFCR_DCEDTE 0x0040 + +/* Bit definations of URXD */ +#define MXC_UARTURXD_ERR 0x4000 +#define MXC_UARTURXD_OVRRUN 0x2000 +#define MXC_UARTURXD_FRMERR 0x1000 +#define MXC_UARTURXD_BRK 0x0800 +#define MXC_UARTURXD_PRERR 0x0400 + +/* Bit definations of USR1 */ +#define MXC_UARTUSR1_PARITYERR 0x8000 +#define MXC_UARTUSR1_RTSS 0x4000 +#define MXC_UARTUSR1_TRDY 0x2000 +#define MXC_UARTUSR1_RTSD 0x1000 +#define MXC_UARTUSR1_FRAMERR 0x0400 +#define MXC_UARTUSR1_RRDY 0x0200 +#define MXC_UARTUSR1_AGTIM 0x0100 +#define MXC_UARTUSR1_DTRD 0x0080 +#define MXC_UARTUSR1_AWAKE 0x0010 + +/* Bit definations of USR2 */ +#define MXC_UARTUSR2_TXFE 0x4000 +#define MXC_UARTUSR2_IDLE 0x1000 +#define MXC_UARTUSR2_RIDELT 0x0400 +#define MXC_UARTUSR2_RIIN 0x0200 +#define MXC_UARTUSR2_DCDDELT 0x0040 +#define MXC_UARTUSR2_DCDIN 0x0020 +#define MXC_UARTUSR2_TXDC 0x0008 +#define MXC_UARTUSR2_ORE 0x0002 +#define MXC_UARTUSR2_RDR 0x0001 +#define MXC_UARTUSR2_BRCD 0x0004 + +/* Bit definations of UTS */ +#define MXC_UARTUTS_LOOP 0x1000 + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_UART_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mxc_vpu.h b/arch/arm/plat-mxc/include/mach/mxc_vpu.h new file mode 100644 index 000000000000..8a42c7de5634 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mxc_vpu.h @@ -0,0 +1,94 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU Lesser General + * Public License. You may obtain a copy of the GNU Lesser General + * Public License Version 2.1 or later at the following locations: + * + * http://www.opensource.org/licenses/lgpl-license.html + * http://www.gnu.org/copyleft/lgpl.html + */ + +/*! + * @defgroup VPU Video Processor Unit Driver + */ + +/*! + * @file arch-mxc/mxc_vpu.h + * + * @brief VPU system initialization and file operation definition + * + * @ingroup VPU + */ + +#ifndef __ASM_ARCH_MXC_VPU_H__ +#define __ASM_ARCH_MXC_VPU_H__ + +#include + +struct vpu_mem_desc { + u32 size; + dma_addr_t phy_addr; + u32 cpu_addr; /* cpu address to free the dma mem */ + u32 virt_uaddr; /* virtual user space address */ +}; + +#define VPU_IOC_MAGIC 'V' + +#define VPU_IOC_PHYMEM_ALLOC _IO(VPU_IOC_MAGIC, 0) +#define VPU_IOC_PHYMEM_FREE _IO(VPU_IOC_MAGIC, 1) +#define VPU_IOC_WAIT4INT _IO(VPU_IOC_MAGIC, 2) +#define VPU_IOC_PHYMEM_DUMP _IO(VPU_IOC_MAGIC, 3) +#define VPU_IOC_REG_DUMP _IO(VPU_IOC_MAGIC, 4) +#define VPU_IOC_VL2CC_FLUSH _IO(VPU_IOC_MAGIC, 5) +#define VPU_IOC_IRAM_SETTING _IO(VPU_IOC_MAGIC, 6) +#define VPU_IOC_CLKGATE_SETTING _IO(VPU_IOC_MAGIC, 7) +#define VPU_IOC_GET_WORK_ADDR _IO(VPU_IOC_MAGIC, 8) +#define VPU_IOC_GET_PIC_PARA_ADDR _IO(VPU_IOC_MAGIC, 9) +#define VPU_IOC_GET_USER_DATA_ADDR _IO(VPU_IOC_MAGIC, 10) +#define VPU_IOC_SYS_SW_RESET _IO(VPU_IOC_MAGIC, 11) +#define VPU_IOC_GET_SHARE_MEM _IO(VPU_IOC_MAGIC, 12) + +#define BIT_CODE_RUN 0x000 +#define BIT_CODE_DOWN 0x004 +#define BIT_INT_CLEAR 0x00C +#define BIT_INT_STATUS 0x010 + +#define BIT_WORK_CTRL_BUF_BASE 0x100 +#define BIT_WORK_CTRL_BUF_REG(i) (BIT_WORK_CTRL_BUF_BASE + i * 4) +#define BIT_CODE_BUF_ADDR BIT_WORK_CTRL_BUF_REG(0) +#define BIT_WORK_BUF_ADDR BIT_WORK_CTRL_BUF_REG(1) +#define BIT_PARA_BUF_ADDR BIT_WORK_CTRL_BUF_REG(2) +#define BIT_BIT_STREAM_CTRL BIT_WORK_CTRL_BUF_REG(3) +#define BIT_FRAME_MEM_CTRL BIT_WORK_CTRL_BUF_REG(4) +#define BIT_BIT_STREAM_PARAM BIT_WORK_CTRL_BUF_REG(5) + +#define BIT_RESET_CTRL 0x11C + +/* i could be 0, 1, 2, 3 */ +#define BIT_RD_PTR_BASE 0x120 +#define BIT_RD_PTR_REG(i) (BIT_RD_PTR_BASE + i * 8) +#define BIT_WR_PTR_REG(i) (BIT_RD_PTR_BASE + i * 8 + 4) + +/* i could be 0, 1, 2, 3 */ +#define BIT_FRM_DIS_FLG_BASE (cpu_is_mx51() ? 0x150 : 0x140) +#define BIT_FRM_DIS_FLG_REG(i) (BIT_FRM_DIS_FLG_BASE + i * 4) + +#define BIT_BUSY_FLAG 0x160 +#define BIT_RUN_COMMAND 0x164 +#define BIT_INT_ENABLE 0x170 + +#define BITVAL_PIC_RUN 8 + +#define VPU_SLEEP_REG_VALUE 10 +#define VPU_WAKE_REG_VALUE 11 + +int vl2cc_init(u32 vl2cc_hw_base); +void vl2cc_enable(void); +void vl2cc_flush(void); +void vl2cc_disable(void); +void vl2cc_cleanup(void); + +#endif diff --git a/arch/arm/plat-mxc/include/mach/pcmcia.h b/arch/arm/plat-mxc/include/mach/pcmcia.h new file mode 100644 index 000000000000..c50302bbbac5 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/pcmcia.h @@ -0,0 +1,218 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MXC_PCMCIA_H__ +#define __ASM_ARCH_MXC_PCMCIA_H__ + +#include + +#define WINDOW_SIZE 0x1000000 /* The size of a window: 16M */ +#define PCMCIA_WINDOWS 5 /* How many windows / socket */ +#define SOCKET_NO 1 /* How many sockets */ + +#define ATTRIBUTE_MEMORY_WINDOW 0 +#define IO_WINDOW 1 +#define COMMON_MEMORY_WINDOW 2 + +/* + * PCMCIA socket + */ +#define PCMCIAPrtSp WINDOW_SIZE /* PCMCIA window size */ +#define PCMCIASp (4*PCMCIAPrtSp) /* PCMCIA Space [byte] */ +#define PCMCIAIOSp PCMCIAPrtSp /* PCMCIA I/O Space [byte] */ +#define PCMCIAAttrSp PCMCIAPrtSp /* PCMCIA Attribute Space [byte] */ +#define PCMCIAMemSp PCMCIAPrtSp /* PCMCIA Memory Space [byte] */ + +#define PCMCIA0Sp PCMCIASp /* PCMCIA 0 Space [byte] */ +#define PCMCIA0IOSp PCMCIAIOSp /* PCMCIA 0 I/O Space [byte] */ +#define PCMCIA0AttrSp PCMCIAAttrSp /* PCMCIA 0 Attribute Space [byte] */ +#define PCMCIA0MemSp PCMCIAMemSp /* PCMCIA 0 Memory Space [byte] */ + +#define _PCMCIA(Nb) /* PCMCIA [0..1] */ \ + (PCMCIA_MEM_BASE_ADDR + (Nb) * PCMCIASp) + +#define _PCMCIAAttr(Nb) _PCMCIA (Nb) /* PCMCIA I/O [0..1] */ + +#define _PCMCIAIO(Nb) /* PCMCIA Attribute [0..1] */ \ + (_PCMCIA (Nb) + (IO_WINDOW) * PCMCIAPrtSp) +#define _PCMCIAMem(Nb) /* PCMCIA Memory [0..1] */ \ + (_PCMCIA (Nb) + (COMMON_MEMORY_WINDOW) * PCMCIAPrtSp) + +#define _PCMCIA0 _PCMCIA (0) /* PCMCIA 0 */ +#define _PCMCIA0IO _PCMCIAIO (0) /* PCMCIA 0 I/O */ +#define _PCMCIA0Attr _PCMCIAAttr (0) /* PCMCIA 0 Attribute */ +#define _PCMCIA0Mem _PCMCIAMem (0) /* PCMCIA 0 Memory */ + +/* + * Module: PCMCIA, Addr Range: 0xB8004000 - 0xB8004FFF, Size: 4 Kbyte + */ +#define PCMCIA_BASE_ADDR (PCMCIA_CTL_BASE_ADDR) /* PCMCIA Base Address */ +#define PCMCIA_IO_ADDR(x) (* (volatile u32 *)PCMCIA_IO_ADDRESS(x)) + +#define _reg_PCMCIA_PIPR PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x00) /* PCMCIA input pins register */ +#define _reg_PCMCIA_PSCR PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x04) /* PCMCIA Status Changed Register */ +#define _reg_PCMCIA_PER PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x08) /* PCMCIA Enable Register */ + +/* win: 0-4 */ +#define _reg_PCMCIA_PBR(win) PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x0C + 4 * (win)) /* PCMCIA Base Register x */ +#define _reg_PCMCIA_POR(win) PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x28 + 4 * (win)) /* PCMCIA Option Register x */ +#define _reg_PCMCIA_POFR(win) PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x44 + 4 * (win)) /* PCMCIA Offset Register x */ + +#define _reg_PCMCIA_PGCR PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x60) /* PCMCIA General Control Register */ +#define _reg_PCMCIA_PGSR PCMCIA_IO_ADDR(PCMCIA_BASE_ADDR + 0x64) /* PCMCIA General Status Register */ + +/* PCMCIA_PIPR - PCMCIA Input Pins Register - fields */ +#define PCMCIA_PIPR_POWERON (1 << 8) /* card indicates "power on" */ +#define PCMCIA_PIPR_RDY (1 << 7) /* card is ready */ +#define PCMCIA_PIPR_BVD2 (1 << 6) /* battery voltage 2/SPKR in */ +#define PCMCIA_PIPR_BVD1 (1 << 5) /* battery voltage 1/STSCHG */ +#define PCMCIA_PIPR_CD (3 << 3) /* card detect 1 and 2 */ +#define PCMCIA_PIPR_WP (1 << 2) /* write protect switch enabled */ +#define PCMCIA_PIPR_VS (3 << 0) /* voltage sense bits */ +#define PCMCIA_PIPR_VS_5V (1 << 0) /* 5v */ + +/* PCMCIA_PSCR - PCMCIA Status Change Register - fields */ +#define PCMCIA_PSCR_POWC (1 << 11) /* */ +#define PCMCIA_PSCR_RDYR (1 << 10) /* */ +#define PCMCIA_PSCR_RDYF (1 << 9) /* */ +#define PCMCIA_PSCR_RDYH (1 << 8) /* */ +#define PCMCIA_PSCR_RDYL (1 << 7) /* */ +#define PCMCIA_PSCR_BVDC2 (1 << 6) /* */ +#define PCMCIA_PSCR_BVDC1 (1 << 5) /* */ +#define PCMCIA_PSCR_CDC2 (1 << 4) /* */ +#define PCMCIA_PSCR_CDC1 (1 << 3) /* */ +#define PCMCIA_PSCR_WPC (1 << 2) /* */ +#define PCMCIA_PSCR_VSC2 (1 << 1) /* */ +#define PCMCIA_PSCR_VSC1 (1 << 0) /* */ + +/* PCMCIA_PER - PCMCIA Enable Register - fields */ +#define PCMCIA_PER_ERRINTEN (1 << 12) /* error interrupt enable */ +#define PCMCIA_PER_POWERONEN (1 << 11) /* power on interrupt enable */ +#define PCMCIA_PER_RDYRE (1 << 10) /* RDY/nIREQ pin rising edge */ +#define PCMCIA_PER_RDYFE (1 << 9) /* RDY/nIREQ pin falling edge */ +#define PCMCIA_PER_RDYHE (1 << 8) /* RDY/nIREQ pin high */ +#define PCMCIA_PER_RDYLE (1 << 7) /* RDY/nIREQ pin low */ +#define PCMCIA_PER_BVDE2 (1 << 6) /* battery voltage 2/SPKR in */ +#define PCMCIA_PER_BVDE1 (1 << 5) /* battery voltage 1/STSCHG */ +#define PCMCIA_PER_CDE2 (1 << 4) /* card detect 2 */ +#define PCMCIA_PER_CDE1 (1 << 3) /* card detect 1 */ +#define PCMCIA_PER_WPE (1 << 2) /* write protect */ +#define PCMCIA_PER_VSE2 (1 << 1) /* voltage sense 2 */ +#define PCMCIA_PER_VSE1 (1 << 0) /* voltage sense 1 */ + +/* PCMCIA_POR[0-4] - PCMCIA Option Registers 0-4 - fields */ +#define PCMCIA_POR_PV (1 << 29) /* set iff bank is valid */ +#define PCMCIA_POR_WPEN (1 << 28) /* write protect (WP) input signal is enabled */ +#define PCMCIA_POR_WP (1 << 27) /* write protected */ + +#define PCMCIA_POR_PRS_SHIFT (25) +#define PCMCIA_POR_PRS(x) (((x) & 0x3) << PCMCIA_POR_PRS_SHIFT ) +#define PCMCIA_POR_PRS_MASK PCMCIA_POR_PRS(3) /* PCMCIA region select */ +#define PCMCIA_POR_PRS_COMMON (0) /* values of POR_PRS field */ +#define PCMCIA_POR_PRS_TRUE_IDE (1) +#define PCMCIA_POR_PRS_ATTRIBUTE (2) +#define PCMCIA_POR_PRS_IO (3) + +#define PCMCIA_POR_PPS_8 (1 << 24) /* PCMCIA Port size = 8bits */ +#define PCMCIA_POR_PPS_16 (0 << 24) /* PCMCIA Port size = 16bits */ + +#define PCMCIA_POR_PSL_SHIFT (17) /* strobe length */ +#define PCMCIA_POR_PSL(x) (((x) & 0x7F) << PCMCIA_POR_PSL_SHIFT) +#define PCMCIA_POR_PSL_MASK PCMCIA_POR_PSL(0x7f) + +#define PCMCIA_POR_PSST_SHIFT (11) /* strobe setup time */ +#define PCMCIA_POR_PSST(x) (((x) & 0x3F) << PCMCIA_POR_PSST_SHIFT) +#define PCMCIA_POR_PSST_MASK PCMCIA_POR_PSST(0x3f) + +#define PCMCIA_POR_PSHT_SHIFT (5) /* strobe hold time */ +#define PCMCIA_POR_PSHT(x) (((x) & 0x3F) << PCMCIA_POR_PSHT_SHIFT) +#define PCMCIA_POR_PSHT_MASK PCMCIA_POR_PSHT(0x3f) + +#define PCMCIA_POR_BSIZE_SHIFT (0) /* bank size */ +#define PCMCIA_POR_BSIZE(x) (((x) & 0x1F) << PCMCIA_POR_BSIZE_SHIFT) +#define PCMCIA_POR_BSIZE_MASK PCMCIA_POR_BSIZE(0x1F) + +/* some handy BSIZE values */ +#define POR_BSIZE_1 PCMCIA_POR_BSIZE(0x00) +#define POR_BSIZE_2 PCMCIA_POR_BSIZE(0x01) +#define POR_BSIZE_4 PCMCIA_POR_BSIZE(0x03) +#define POR_BSIZE_8 PCMCIA_POR_BSIZE(0x02) +#define POR_BSIZE_16 PCMCIA_POR_BSIZE(0x06) +#define POR_BSIZE_32 PCMCIA_POR_BSIZE(0x07) +#define POR_BSIZE_64 PCMCIA_POR_BSIZE(0x05) +#define POR_BSIZE_128 PCMCIA_POR_BSIZE(0x04) +#define POR_BSIZE_256 PCMCIA_POR_BSIZE(0x0C) +#define POR_BSIZE_512 PCMCIA_POR_BSIZE(0x0D) +#define POR_BSIZE_1K PCMCIA_POR_BSIZE(0x0F) +#define POR_BSIZE_2K PCMCIA_POR_BSIZE(0x0E) + +#define POR_BSIZE_4K PCMCIA_POR_BSIZE(0x0A) +#define POR_BSIZE_8K PCMCIA_POR_BSIZE(0x0B) +#define POR_BSIZE_16K PCMCIA_POR_BSIZE(0x09) +#define POR_BSIZE_32K PCMCIA_POR_BSIZE(0x08) +#define POR_BSIZE_64K PCMCIA_POR_BSIZE(0x18) +#define POR_BSIZE_128K PCMCIA_POR_BSIZE(0x19) +#define POR_BSIZE_256K PCMCIA_POR_BSIZE(0x1B) +#define POR_BSIZE_512K PCMCIA_POR_BSIZE(0x1A) +#define POR_BSIZE_1M PCMCIA_POR_BSIZE(0x1E) +#define POR_BSIZE_2M PCMCIA_POR_BSIZE(0x1F) +#define POR_BSIZE_4M PCMCIA_POR_BSIZE(0x1D) +#define POR_BSIZE_8M PCMCIA_POR_BSIZE(0x1C) +#define POR_BSIZE_16M PCMCIA_POR_BSIZE(0x14) +#define POR_BSIZE_32M PCMCIA_POR_BSIZE(0x15) +#define POR_BSIZE_64M PCMCIA_POR_BSIZE(0x17) + +/* Window size */ +#define POR_1 0x1 +#define POR_2 0x2 +#define POR_4 0x4 +#define POR_8 0x8 +#define POR_16 0x10 +#define POR_32 0x20 +#define POR_64 0x40 +#define POR_128 0x80 +#define POR_256 0x100 +#define POR_512 0x200 + +#define POR_1K 0x400 +#define POR_2K 0x800 +#define POR_4K 0x1000 +#define POR_8K 0x2000 +#define POR_16K 0x4000 +#define POR_32K 0x8000 +#define POR_64K 0x10000 +#define POR_128K 0x20000 +#define POR_256K 0x40000 +#define POR_512K 0x80000 + +#define POR_1M 0x100000 +#define POR_2M 0x200000 +#define POR_4M 0x400000 +#define POR_8M 0x800000 +#define POR_16M 0x1000000 +#define POR_32M 0x2000000 +#define POR_64M 0x4000000 + +/* PCMCIA_PGCR - PCMCIA General Control Register - fields */ +#define PCMCIA_PGCR_LPMEN (1 << 3) /* Low power Mode Enable */ +#define PCMCIA_PGCR_SPKREN (1 << 2) /* SPKROUT routing enable */ +#define PCMCIA_PGCR_POE (1 << 1) /* Controller out enable */ +#define PCMCIA_PGCR_RESET (1 << 0) /* Card reset */ + +/* PCMCIA_PGSR - PCMCIA General Status Register - fields */ +#define PCMCIA_PGSR_NWINE (1 << 4) /* No Window error */ +#define PCMCIA_PGSR_LPE (1 << 3) /* Low Power error */ +#define PCMCIA_PGSR_SE (1 << 2) /* Size error */ +#define PCMCIA_PGSR_CDE (1 << 1) /* Card Detect error */ +#define PCMCIA_PGSR_WPE (1 << 0) /* Write Protect error */ + +#endif /* __ASM_ARCH_MXC_PCMCIA_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/pmic_audio.h b/arch/arm/plat-mxc/include/mach/pmic_audio.h new file mode 100644 index 000000000000..8ec3d2c642e4 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/pmic_audio.h @@ -0,0 +1,2315 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MXC_PMIC_AUDIO_H__ +#define __ASM_ARCH_MXC_PMIC_AUDIO_H__ + +/*! + * @defgroup PMIC_AUDIO PMIC Audio Driver + * @ingroup PMIC_DRVRS + */ + +/*! + * @file arch-mxc/pmic_audio.h + * @brief External definitions for the PMIC Audio Client driver. + * + * The PMIC Audio driver and this API were developed to support the + * audio playback, recording, and mixing capabilities of the power + * management ICs that are available from Freescale Semiconductor, Inc. + * + * The following table shows which audio-related capabilities are supported + * by each power management IC: + * + * @ingroup PMIC_AUDIO + */ + +#include +#include + +/*************************************************************************** + * TYPEDEFS AND ENUMERATIONS * + ***************************************************************************/ + +/*! + * @name General Setup and Audio Device Access Typedefs and Enumerations + * Typedefs and enumerations that are used for initial access to the + * PMIC Audio hardware. + */ +/*@{*/ + +/*! + * @typedef PMIC_AUDIO_HANDLE + * @brief Define typedef for a handle to the PMIC Audio hardware. + * + * Define a "handle" that is returned when the PMIC Audio hardware + * is opened. This handle grants exclusive access to the PMIC Audio + * hardware and must be used in all subsequent function calls. When access + * to the PMIC Audio hardware is no longer required, then a close + * operation must be done with this handle. The handle is no longer valid + * if the close operation was successful. + */ +typedef long *PMIC_AUDIO_HANDLE; + +/*! + * @enum PMIC_AUDIO_EVENTS + * @brief Identify the audio events that have been detected and should be + * handled. + * + * This enumeration defines all of the possible PMIC Audio events. Multiple + * events may be selected when defining a mask and multiple events may be + * signalled together. + * + * Note that the MICROPHONE_DETECT and MICROPHONE_REMOVED events may also be + * used to signal the operation of a serial or parallel microphone switch + * when used with a combined headset+microphone device. In that case the + * HEADSET_DETECT state must also be checked to determine if it's only the + * microphone switch being operated or whether the microphone has truly been + * inserted/removed (along with the headset). + */ +typedef enum { + HEADSET_DETECTED = 1, /*!< Detected headset insertion. */ + HEADSET_STEREO = 2, /*!< Detected stereo headset device. */ + HEADSET_MONO = 4, /*!< Detected mono headset device. */ + HEADSET_THERMAL_SHUTDOWN = 8, /*!< Detected output amplifier + shutdown due to thermal + limits . */ + HEADSET_SHORT_CIRCUIT = 16, /*!< Detected output amplifier + short circuit condition + . */ + HEADSET_REMOVED = 32, /*!< Detected headset removal. */ + MICROPHONE_DETECTED = 64, /*!< Detected microphone insertion. */ + MICROPHONE_REMOVED = 128, /*!< Detected microphone removal. */ + PTT_BUTTON_PRESS = 256, /*!< Detected PTT button down + . */ + PTT_BUTTON_RANGE = 512, /*!< Detected PTT button within + voltage range + . */ + PTT_SHORT_OR_INVALID = 1024 /*!< Detected PTT button outside + of voltage range or invalid + device . */ +} PMIC_AUDIO_EVENTS; + +/*! + * @typedef PMIC_AUDIO_CALLBACK + * @brief Typedef for PMIC Audio event notification callback function. + * + * Define a typedef for the PMIC Audio event notification callback + * function. The signalled events are passed to the function as the first + * argument. The callback function should then process whatever events it + * can and then return the set of unhandled events (if any). + */ +typedef PMIC_AUDIO_EVENTS(*PMIC_AUDIO_CALLBACK) (const PMIC_AUDIO_EVENTS event); + +typedef struct { + int hs_state; + int event_type; +} PMIC_HS_STATE; + +/*! + * @enum PMIC_AUDIO_SOURCE + * @brief Select an audio signal processing component. + * + * This enumeration defines all of the possible PMIC audio signal handling + * components which can be acquired by calling pmic_audio_open(). + * + * Note that the EXTERNAL_STEREO_IN selection is used to simply gain access + * to the stereo input pins. The stereo input signal can then be routed + * directly to the output amplifiers. In this case, no signal processing is + * done by either the Voice CODEC or the Stereo DAC. + */ +typedef enum { + STEREO_DAC, /*!< Open connection to Stereo DAC. */ + VOICE_CODEC, /*!< Open connection to Voice CODEC. */ + EXTERNAL_STEREO_IN /*!< Open connection to external stereo inputs. */ +} PMIC_AUDIO_SOURCE; + +/*@}*/ + +/*! + * @name Data Bus Setup and Configuration Typedefs and Enumerations + * Typedefs and enumerations that are used to define and configure + * the data bus protocol in order to communicate with the Stereo DAC + * or the Voice CODEC. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_DATA_BUS + * @brief Select the data bus used to transfer data between the host and + * Voice CODEC and/or the Stereo DAC. + * + * This enumeration defines all of the possible PMIC audio data buses that + * can be used to transfer data between the host and the Voice CODEC and/or + * the Stereo DAC on the PMIC. + * + * Note that the same data bus may be used to transfer audio data to/from + * the Voice CODEC and the Stereo DAC. However, in this case, the data bus + * must be configured for network mode with different timeslots assigned to + * the Voice CODEC and the Stereo DAC. Also, the sampling rates must be + * identical for both the Voice CODEC and the Stereo DAC in order to avoid + * a data bus timing conflict and audio signal distortion. + */ +typedef enum { + AUDIO_DATA_BUS_1, /*!< Use data bus 1 for audio data. */ + AUDIO_DATA_BUS_2 /*!< Use data bus 2 for audio data. */ +} PMIC_AUDIO_DATA_BUS; + +/*! + * @enum PMIC_AUDIO_BUS_PROTOCOL + * @brief Select the data bus protocol to be used. + * + * This enumeration defines all of the possible PMIC audio data bus protocols + * that may be selected. + */ +typedef enum { + NORMAL_MSB_JUSTIFIED_MODE, /*!< Transmit and receive audio data + in normal MSB-justified mode. */ + NETWORK_MODE, /*!< Transmit and receive audio data + in network mode. */ + I2S_MODE, /*!< Transmit and receive audio data + in I2S mode. */ + SPD_IF_MODE /*!< Transmit and receive audio data + in SPD/IF mode . */ +} PMIC_AUDIO_BUS_PROTOCOL; + +/*! + * @enum PMIC_AUDIO_BUS_MODE + * @brief Select the data bus mode to be used. + * + * This enumeration defines all of the possible PMIC audio data bus modes + * that may be selected. When configured in BUS_MASTER_MODE, the PMIC is + * responsible for supplying the data bus clock signals. Alternatively, + * when configured in BUS_SLAVE_MODE, the PMIC will use the data bus clock + * signals that are supplied by the bus master. + */ +typedef enum { + BUS_MASTER_MODE = 0, /*!< Operate as bus master. */ + BUS_SLAVE_MODE = 1 /*!< Operate as bus slave. */ +} PMIC_AUDIO_BUS_MODE; + +/*! + * @enum PMIC_AUDIO_CLOCK_IN_SOURCE + * @brief Select the clock signal source when in bus master mode. + * + * This enumeration defines all of the possible PMIC audio clock signal + * sources that may be selected. One of these clock signal sources must + * be selected in order to use either the Voice CODEC or the Stereo DAC. + * + * When configured in BUS_MASTER_MODE, the PMIC's onboard PLL circuits + * will also be driven by the selected clock input signal. + */ +typedef enum { + CLOCK_IN_DEFAULT, /*!< Just use default (power-up) clock input. */ + CLOCK_IN_CLIA, /*!< Use the CLIA clock source (Stereo DAC + default) . */ + CLOCK_IN_CLIB, /*!< Use the CLIB clock source (Voice CODEC + default) . */ + CLOCK_IN_CLKIN, /*!< Use the CLKIN clock source + . */ + CLOCK_IN_MCLK, /*!< Disable the internal PLL and use the MCLK + clock source (Stereo DAC only) + . */ + CLOCK_IN_FSYNC, /*!< Internal PLL input from external framesync + (Stereo DAC only) . */ + CLOCK_IN_BITCLK /*!< Internal PLL input from external bitclock + (Stereo DAC only) */ +} PMIC_AUDIO_CLOCK_IN_SOURCE; + +/*! + * @enum PMIC_AUDIO_CLOCK_INVERT + * @brief Select whether to invert the frame sync or bit clock signals. + * + * This enumeration enables or disables the inversion of the incoming + * frame sync or bit clock signals. + */ +typedef enum { + NO_INVERT = 0, /*!< Do not invert the clock signals. */ + INVERT_BITCLOCK = 1, /*!< Invert the BCLK input signal. */ + INVERT_FRAMESYNC = 2 /*!< Invert the FSYNC input signal. */ +} PMIC_AUDIO_CLOCK_INVERT; + +/*! + * @enum PMIC_AUDIO_NUMSLOTS + * @brief Select whether to invert the frame sync or bit clock signals. + * + * This enumeration defines all of the possible number of timeslots that may + * be selected when the PMIC is configured as the data bus master. One of these + * options must be selected if the Stereo DAC is to provide the data bus + * clock signals. + * + * Note that the Voice CODEC currently only allows USE_4_TIMESLOTS when + * operating in data bus master mode. + */ +typedef enum { + USE_2_TIMESLOTS, /*!< Configure for 2 timeslots. */ + USE_4_TIMESLOTS, /*!< Configure for 4 timeslots. */ + USE_8_STAR_TIMESLOTS, /*!< Configure for 8 (Left, Right, 6 other) timeslots. */ + USE_8_TIMESLOTS /*!< Configure for 8 timeslots. */ +} PMIC_AUDIO_NUMSLOTS; + +/*! + * @enum PMIC_AUDIO_STDAC_SAMPLING_RATE + * @brief Select the audio data sampling rate for the Stereo DAC. + * + * This enumeration defines all of the possible sampling rates currently + * supported by the Stereo DAC. One of these sampling rates must be selected + * and it must match that of the audio stream or else signal distortion will + * occur. + */ +typedef enum { + STDAC_RATE_8_KHZ, /*!< Use 8 kHz sampling rate. */ + STDAC_RATE_11_025_KHZ, /*!< Use 11.025 kHz sampling rate. */ + STDAC_RATE_12_KHZ, /*!< Use 12 kHz sampling rate. */ + STDAC_RATE_16_KHZ, /*!< Use 16 kHz sampling rate. */ + STDAC_RATE_22_050_KHZ, /*!< Use 22.050 kHz sampling rate. */ + STDAC_RATE_24_KHZ, /*!< Use 24 kHz sampling rate. */ + STDAC_RATE_32_KHZ, /*!< Use 32 kHz sampling rate. */ + STDAC_RATE_44_1_KHZ, /*!< Use 44.1 kHz sampling rate. */ + STDAC_RATE_48_KHZ, /*!< Use 48 kHz sampling rate. */ + STDAC_RATE_64_KHZ, /*!< Use 64 kHz sampling rate + . */ + STDAC_RATE_96_KHZ /*!< Use 96 kHz sampling rate. + . */ +} PMIC_AUDIO_STDAC_SAMPLING_RATE; + +/*! + * @enum PMIC_AUDIO_VCODEC_SAMPLING_RATE + * @brief Select the audio data sampling rate for the Voice CODEC. + * + * This enumeration defines all of the possible sampling rates currently + * supported by the Voice CODEC. One of these sampling rates must be selected + * and it must match that of the audio stream or else signal distortion will + * occur. + */ +typedef enum { + VCODEC_RATE_8_KHZ, /*!< Use 8 kHz sampling rate. */ + VCODEC_RATE_16_KHZ, /*!< Use 16 kHz sampling rate. */ +} PMIC_AUDIO_VCODEC_SAMPLING_RATE; + +/*! + * @enum PMIC_AUDIO_ANTI_POP_RAMP_SPEED + * @brief Select the anti-pop circuitry's ramp up speed. + * + * This enumeration defines all of the possible ramp up speeds for the + * anti-pop circuitry. A slow ramp up speed may be required in order to + * avoid the popping noise that is typically generated during the insertion + * or removal of a headset or microphone. + */ +typedef enum { + ANTI_POP_RAMP_FAST, /*!< Select fast ramp up. */ + ANTI_POP_RAMP_SLOW /*!< Select slow ramp up. */ +} PMIC_AUDIO_ANTI_POP_RAMP_SPEED; + +/*@}*/ + +/*! + * @name General Voice CODEC Configuration Typedefs and Enumerations + * Typedefs and enumerations that are used to define and configure + * the basic operating options for the Voice CODEC. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_VCODEC_CLOCK_IN_FREQ + * @brief Select the Voice CODEC input clock frequency. + * + * This enumeration defines all of the supported Voice CODEC input clock + * frequencies. One of these frequencies must be selected in order to + * properly configure the Voice CODEC to operate at the required sampling + * rate. + */ +typedef enum { + VCODEC_CLI_13MHZ, /*!< Clock frequency is 13MHz. */ + VCODEC_CLI_15_36MHZ, /*!< Clock frequency is 15.36MHz. */ + VCODEC_CLI_16_8MHZ, /*!< Clock frequency is 16.8MHz + . */ + VCODEC_CLI_26MHZ, /*!< Clock frequency is 26MHz. */ + VCODEC_CLI_33_6MHZ, /*!< Clock frequency is 33.6MHz. */ +} PMIC_AUDIO_VCODEC_CLOCK_IN_FREQ; + +/*! + * @enum PMIC_AUDIO_VCODEC_CONFIG + * @brief Select the Voice CODEC configuration options. + * + * This enumeration is used to enable/disable each of the Voice CODEC options. + * This includes the use of highpass digital filters and audio signal + * loopback modes. + * + * Note that resetting the digital filters is now handled by the + * pmic_audio_digital_filter_reset() API. + */ +typedef enum { + DITHERING = 1, /*!< Enable/disable dithering. */ + INPUT_HIGHPASS_FILTER = 2, /*!< Enable/disable the input high + pass digital filter. */ + OUTPUT_HIGHPASS_FILTER = 4, /*!< Enable/disable the output high + pass digital filter. */ + ANALOG_LOOPBACK = 8, /*!< Enable/disable the analog + loopback path + . */ + DIGITAL_LOOPBACK = 16, /*!< Enable/disable the digital + loopback path. */ + VCODEC_MASTER_CLOCK_OUTPUTS = 32, /*!< Enable/disable the bus master + clock outputs. */ + TRISTATE_TS = 64 /*!< Enable/disable FSYNC, BITCLK, + and TX tristate. */ +} PMIC_AUDIO_VCODEC_CONFIG; + +/*@}*/ + +/*! + * @name General Stereo DAC Configuration Typedefs and Enumerations + * Typedefs and enumerations that are used to define and configure + * the basic operating options for the Stereo DAC. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_STDAC_CLOCK_IN_FREQ + * @brief Select the Stereo DAC input clock frequency. + * + * This enumeration defines all of the supported Stereo DAC input clock + * frequencies. One of these frequencies must be selected in order to + * properly configure the Stereo DAC to operate at the required sampling + * rate. + */ +typedef enum { + STDAC_CLI_3_36864MHZ, /*!< Clock frequency is 3.36864MHz + . */ + STDAC_CLI_12MHZ, /*!< Clock frequency is 12MHz. + . */ + STDAC_CLI_13MHZ, /*!< Clock frequency is 13MHz. */ + STDAC_CLI_15_36MHZ, /*!< Clock frequency is 15.36MHz. */ + STDAC_CLI_16_8MHZ, /*!< Clock frequency is 16.8MHz + . */ + STDAC_CLI_26MHZ, /*!< Clock frequency is 26MHz. */ + STDAC_CLI_33_6MHZ, /*!< Clock frequency is 33.6MHz. */ + STDAC_MCLK_PLL_DISABLED, /*!< Use MCLK and disable internal PLL. */ + STDAC_FSYNC_IN_PLL, /*!< Use FSYNC as internal PLL input. */ + STDAC_BCLK_IN_PLL /*!< Use BCLK as internal PLL input. */ +} PMIC_AUDIO_STDAC_CLOCK_IN_FREQ; + +/*! + * @enum PMIC_AUDIO_STDAC_CONFIG + * @brief Select the Stereo DAC configuration options. + * + * This enumeration is used to enable/disable each of the Stereo DAC options. + */ +typedef enum { + STDAC_MASTER_CLOCK_OUTPUTS = 1 /*!< Enable/disable the bus master clock + outputs. */ +} PMIC_AUDIO_STDAC_CONFIG; + +/*@}*/ + +/*! + * @name Voice CODEC Audio Port Mixing Typedefs and Enumerations + * Typedefs and enumerations that are used for setting up the audio mixer + * within the Voice CODEC. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_VCODEC_TIMESLOT + * @brief Select the Stereo DAC configuration options. + * + * This enumeration is used to select the timeslot for both the primary and + * secondary (for mc13783-only) audio channels to the Voice CODEC. + */ +typedef enum { + USE_TS0, /*!< Use timeslot 0 for audio signal source + . */ + USE_TS1, /*!< Use timeslot 1 for audio signal source + . */ + USE_TS2, /*!< Use timeslot 2 for audio signal source + . */ + USE_TS3 /*!< Use timeslot 3 for audio signal source + . */ +} PMIC_AUDIO_VCODEC_TIMESLOT; + +/*! + * @enum PMIC_AUDIO_VCODEC_MIX_IN_GAIN + * @brief Select the secondary channel input gain for the Voice CODEC mixer. + * + * This enumeration selects the secondary channel input gain for the Voice + * CODEC mixer. + */ +typedef enum { + VCODEC_NO_MIX, /*!< No audio mixing . */ + VCODEC_MIX_IN_0DB, /*!< Mix with 0dB secondary channel gain + . */ + VCODEC_MIX_IN_MINUS_6DB, /*!< Mix with -6dB secondary channel gain + . */ + VCODEC_MIX_IN_MINUS_12DB, /*!< Mix with -12dB secondary channel gain + . */ +} PMIC_AUDIO_VCODEC_MIX_IN_GAIN; + +/*! + * @enum PMIC_AUDIO_VCODEC_MIX_OUT_GAIN + * @brief Select the output gain for the Voice CODEC mixer. + * + * This enumeration selects the output gain for the Voice CODEC mixer. + */ +typedef enum { + VCODEC_MIX_OUT_0DB, /*!< Select 0dB mixer output gain + . */ + VCODEC_MIX_OUT_MINUS_6DB, /*!< Select -6dB mixer output gain + . */ +} PMIC_AUDIO_VCODEC_MIX_OUT_GAIN; + +/*@}*/ + +/*! + * @name Stereo DAC Audio Port Mixing Typedefs and Enumerations + * Typedefs and enumerations that are used for setting up the audio mixer + * within the Stereo DAC. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_STDAC_TIMESLOTS + * @brief Select the timeslots used to transmit the left and right audio + * channels to the Stereo DAC. + * + * This enumeration is used to select the timeslots used to transmit the + * data corresponding to the left and right audio channels to the Stereo + * DAC. + */ +typedef enum { + USE_TS0_TS1, /*!< Use timeslots 0 and 1 for left and + right channels, respectively. */ + USE_TS2_TS3, /*!< Use timeslots 2 and 3 for left and + right channels, respectively + . */ + USE_TS4_TS5, /*!< Use timeslots 4 and 5 for left and + right channels, respectively + . */ + USE_TS6_TS7 /*!< Use timeslots 6 and 7 for left and + right channels, respectively + . */ +} PMIC_AUDIO_STDAC_TIMESLOTS; + +/*! + * @enum PMIC_AUDIO_STDAC_MIX_IN_GAIN + * @brief Select the secondary channel input gain for the Stereo DAC mixer. + * + * This enumeration is used to select the secondary channel input gain for + * the Stereo DAC mixer. + */ +typedef enum { + STDAC_NO_MIX, /*!< No mixing, keep separate left + and right audio channels. */ + STDAC_MIX_IN_0DB, /*!< Mix left and right audio channels + together with 0dB secondary + channel gain. */ + STDAC_MIX_IN_MINUS_6DB, /*!< Mix left and right audio channels + together with -6dB secondary + channel gain. */ + STDAC_MIX_IN_MINUS_12DB /*!< Mix left and right audio channels + together with -12dB secondary + channel gain . */ +} PMIC_AUDIO_STDAC_MIX_IN_GAIN; + +/*! + * @enum PMIC_AUDIO_STDAC_MIX_OUT_GAIN + * @brief Select the output gain for the Stereo DAC mixer. + * + * This enumeration is used to select the output gain for the Stereo DAC + * mixer. + */ +typedef enum { + STDAC_MIX_OUT_0DB, /*!< Select 0dB mixer output gain. */ + STDAC_MIX_OUT_MINUS_6DB, /*!< Select -6dB mixer output gain + . */ +} PMIC_AUDIO_STDAC_MIX_OUT_GAIN; + +/*@}*/ + +/*! + * @name Microphone Input Typedefs and Enumerations + * Typedefs and enumerations that are used for selecting and setting up + * one or more or microphone inputs for recording. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_MIC_BIAS + * @brief Select the microphone bias circuit to be enabled/disabled. + * + * This enumeration lists all of the available microphone bias circuits that + * may be enabled or disabled. + */ +typedef enum { + NO_BIAS = 0, /*!< No microphone bias circuit selected. */ + MIC_BIAS1 = 1, /*!< Enable/disable microphone bias 1 circuit. */ + MIC_BIAS2 = 2, /*!< Enable/disable microphone bias 2 circuit. */ +} PMIC_AUDIO_MIC_BIAS; + +/*! + * @enum PMIC_AUDIO_INPUT_PORT + * @brief Select an audio input port for recording. + * + * This enumeration lists all of the available audio input ports that may + * be selected for a recording operation. + */ +typedef enum { + NO_MIC, /*!< No microphone input selected. */ + MIC1_LEFT, /*!< Enable left/mono channel microphone input + . */ + MIC1_RIGHT_MIC_MONO, /*!< Enable right channel microphone input. */ + MIC2_AUX, /*!< Enable auxiliary microphone input. */ + TXIN_EXT /*!< Enable external mono input. */ +} PMIC_AUDIO_INPUT_PORT; + +/*! + * @enum PMIC_AUDIO_INPUT_MIC_STATE + * @brief Control whether the input microphone is on/off. + * + * This enumeration allows the currently selected input microphone amplifier + * to be turned on/off. + */ +typedef enum { + MICROPHONE_ON, /*!< Turn microphone input on for recording. */ + MICROPHONE_OFF /*!< Turn microphone input off (mute). */ +} PMIC_AUDIO_INPUT_MIC_STATE; + +/*! + * @enum PMIC_AUDIO_INPUT_CONFIG + * @brief Enable/disable the audio input options. + * + * This enumeration allows for enabling/disabling any of the audio input + * section options. + */ +typedef enum { + MIC_AMP_AUTO_DISABLE = 1 /*!< Enable/disable automatic disabling of + microphone input amplifiers following + headset insertion/removal */ +} PMIC_AUDIO_INPUT_CONFIG; + +/*! + * @enum PMIC_AUDIO_MIC_AMP_MODE + * @brief Select the operating mode for the microphone amplifiers. + * + * This enumeration is used to select the operating mode for the microphone + * amplifier. + */ +typedef enum { + AMP_OFF, /*!< Disable input amplifier. */ + VOLTAGE_TO_VOLTAGE, /*!< Operate input amplifier in + voltage-to-voltage mode + . */ + CURRENT_TO_VOLTAGE /*!< Operate input amplifier in + current-to-voltage mode */ +} PMIC_AUDIO_MIC_AMP_MODE; + +/*! + * @enum PMIC_AUDIO_MIC_GAIN + * @brief Select the microphone amplifier gain level. + * + * This enumeration lists all of the available microphone amplifier gain + * levels. + */ +typedef enum { + MIC_GAIN_MINUS_8DB, /*!< Select -8dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_7DB, /*!< Select -7dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_6DB, /*!< Select -6dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_5DB, /*!< Select -5dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_4DB, /*!< Select -4dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_3DB, /*!< Select -3dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_2DB, /*!< Select -2dB microphone amplifier gain + . */ + MIC_GAIN_MINUS_1DB, /*!< Select -1dB microphone amplifier gain + . */ + MIC_GAIN_0DB, /*!< Select 0dB microphone amplifier gain. */ + MIC_GAIN_PLUS_1DB, /*!< Select 1dB microphone amplifier gain. */ + MIC_GAIN_PLUS_2DB, /*!< Select 2dB microphone amplifier gain. */ + MIC_GAIN_PLUS_3DB, /*!< Select 3dB microphone amplifier gain. */ + MIC_GAIN_PLUS_4DB, /*!< Select 4dB microphone amplifier gain. */ + MIC_GAIN_PLUS_5DB, /*!< Select 5dB microphone amplifier gain. */ + MIC_GAIN_PLUS_6DB, /*!< Select 6dB microphone amplifier gain. */ + MIC_GAIN_PLUS_7DB, /*!< Select 7dB microphone amplifier gain. */ + MIC_GAIN_PLUS_8DB, /*!< Select 8dB microphone amplifier gain. */ + MIC_GAIN_PLUS_9DB, /*!< Select 9dB microphone amplifier gain. */ + MIC_GAIN_PLUS_10DB, /*!< Select 10dB microphone amplifier gain. */ + MIC_GAIN_PLUS_11DB, /*!< Select 11dB microphone amplifier gain. */ + MIC_GAIN_PLUS_12DB, /*!< Select 12dB microphone amplifier gain. */ + MIC_GAIN_PLUS_13DB, /*!< Select 13dB microphone amplifier gain. */ + MIC_GAIN_PLUS_14DB, /*!< Select 14dB microphone amplifier gain. */ + MIC_GAIN_PLUS_15DB, /*!< Select 15dB microphone amplifier gain. */ + MIC_GAIN_PLUS_16DB, /*!< Select 16dB microphone amplifier gain. */ + MIC_GAIN_PLUS_17DB, /*!< Select 17dB microphone amplifier gain. */ + MIC_GAIN_PLUS_18DB, /*!< Select 18dB microphone amplifier gain. */ + MIC_GAIN_PLUS_19DB, /*!< Select 19dB microphone amplifier gain. */ + MIC_GAIN_PLUS_20DB, /*!< Select 20dB microphone amplifier gain. */ + MIC_GAIN_PLUS_21DB, /*!< Select 21dB microphone amplifier gain. */ + MIC_GAIN_PLUS_22DB, /*!< Select 22dB microphone amplifier gain. */ + MIC_GAIN_PLUS_23DB, /*!< Select 23dB microphone amplifier gain. */ + MIC_GAIN_PLUS_24DB, /*!< Select 24dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_25DB, /*!< Select 25dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_26DB, /*!< Select 26dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_27DB, /*!< Select 27dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_28DB, /*!< Select 28dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_29DB, /*!< Select 29dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_30DB, /*!< Select 30dB microphone amplifier gain + . */ + MIC_GAIN_PLUS_31DB /*!< Select 31dB microphone amplifier gain + . */ +} PMIC_AUDIO_MIC_GAIN; + +/*@}*/ + +/*! + * @name Audio Output Section Typedefs and Enumerations + * Typedefs and enumerations that are used for selecting and setting up + * one or more or audio output ports for playback. + */ +/*@{*/ + +/*! + * @enum PMIC_AUDIO_OUTPUT_PORT + * @brief Select the audio output port. + * + * This enumeration lists all of the available audio output ports. One or + * more may be selected as desired to handle the output audio stream from + * either the Voice CODEC or the Stereo DAC. + */ +typedef enum { + MONO_SPEAKER = 1, /*!< Select mono output speaker. */ + MONO_LOUDSPEAKER = 2, /*!< Select mono loudspeaker + . */ + MONO_ALERT = 4, /*!< Select mono alert output */ + MONO_EXTOUT = 8, /*!< Select mono external output */ + MONO_CDCOUT = 16, /*!< Select dedicated Voice CODEC output + . */ + STEREO_LEFT_LOW_POWER = 32, /*!< Select stereo left channel low power + output . */ + STEREO_HEADSET_LEFT = 64, /*!< Select stereo headset left channel. */ + STEREO_HEADSET_RIGHT = 128, /*!< Select stereo headset right channel. */ + STEREO_OUT_LEFT = 256, /*!< Select stereo external left channel + output . */ + STEREO_OUT_RIGHT = 512 /*!< Select stereo external right channel + output . */ +} PMIC_AUDIO_OUTPUT_PORT; + +/*! + * @enum PMIC_AUDIO_OUTPUT_CONFIG + * @brief Enable/disable the audio output section options. + * + * This enumeration is used to enable/disable any of the audio output section + * options. + */ +typedef enum { + MONO_SPEAKER_INVERT_OUT_ONLY = 1, /*!< Enable/disable the non-inverted + mono speaker output */ + MONO_LOUDSPEAKER_COMMON_BIAS = 2, /*!< Enable/disable the loudspeaker + output amplifier common bias + . */ + HEADSET_DETECT_ENABLE = 4, /*!< Enable/disable headset + insertion/removal detection + . */ + STEREO_HEADSET_AMP_AUTO_DISABLE = 8 /*!< Enable/disable automatic + disabling of the stereo headset + output amplifiers following + headset insertion/removal. */ +} PMIC_AUDIO_OUTPUT_CONFIG; + +/*! + * @enum PMIC_AUDIO_STEREO_IN_GAIN + * @brief Select the amplifier gain for the external stereo inputs. + * + * This enumeration is used to select the amplifier gain level to be used for + * the external stereo inputs. + */ +typedef enum { + STEREO_IN_GAIN_0DB, /*!< Select 0dB external stereo signal + input gain. */ + STEREO_IN_GAIN_PLUS_18DB /*!< Select 18dB external stereo signal + input gain . */ +} PMIC_AUDIO_STEREO_IN_GAIN; + +/*! + * @enum PMIC_AUDIO_OUTPUT_PGA_GAIN + * @brief Select the output PGA amplifier gain level. + * + * This enumeration is used to select the output PGA amplifier gain level. + */ +typedef enum { + OUTPGA_GAIN_MINUS_33DB, /*!< Select -33dB output PGA gain + . */ + OUTPGA_GAIN_MINUS_30DB, /*!< Select -30dB output PGA gain + . */ + OUTPGA_GAIN_MINUS_27DB, /*!< Select -27dB output PGA gain + . */ + OUTPGA_GAIN_MINUS_24DB, /*!< Select -24dB output PGA gain. */ + OUTPGA_GAIN_MINUS_21DB, /*!< Select -21dB output PGA gain. */ + OUTPGA_GAIN_MINUS_18DB, /*!< Select -18dB output PGA gain. */ + OUTPGA_GAIN_MINUS_15DB, /*!< Select -15dB output PGA gain. */ + OUTPGA_GAIN_MINUS_12DB, /*!< Select -12dB output PGA gain. */ + OUTPGA_GAIN_MINUS_9DB, /*!< Select -9dB output PGA gain. */ + OUTPGA_GAIN_MINUS_6DB, /*!< Select -6dB output PGA gain. */ + OUTPGA_GAIN_MINUS_3DB, /*!< Select -3dB output PGA gain. */ + OUTPGA_GAIN_0DB, /*!< Select 0dB output PGA gain. */ + OUTPGA_GAIN_PLUS_3DB, /*!< Select 3dB output PGA gain. */ + OUTPGA_GAIN_PLUS_6DB, /*!< Select 6dB output PGA gain. */ + OUTPGA_GAIN_PLUS_9DB, /*!< Select 9dB output PGA gain. + . */ + OUTPGA_GAIN_PLUS_12DB, /*!< Select 12dB output PGA gain + . */ + OUTPGA_GAIN_PLUS_15DB, /*!< Select 15dB output PGA gain + . */ + OUTPGA_GAIN_PLUS_18DB, /*!< Select 18dB output PGA gain + . */ + OUTPGA_GAIN_PLUS_21DB /*!< Select 21dB output PGA gain + . */ +} PMIC_AUDIO_OUTPUT_PGA_GAIN; + +/*! + * @enum PMIC_AUDIO_OUTPUT_BALANCE_GAIN + * @brief Select the left/right channel balance gain level. + * + * This enumeration is used to select the balance gain level that is to be + * separately applied to the left and right audio channels. + */ +typedef enum { + BAL_GAIN_MINUS_21DB, /*!< Select -21dB channel balance + gain . */ + BAL_GAIN_MINUS_18DB, /*!< Select -18dB channel balance + gain . */ + BAL_GAIN_MINUS_15DB, /*!< Select -15dB channel balance + gain . */ + BAL_GAIN_MINUS_12DB, /*!< Select -12dB channel balance + gain . */ + BAL_GAIN_MINUS_9DB, /*!< Select -9dB channel balance + gain . */ + BAL_GAIN_MINUS_6DB, /*!< Select -6dB channel balance + gain . */ + BAL_GAIN_MINUS_3DB, /*!< Select -3dB channel balance + gain . */ + BAL_GAIN_0DB /*!< Select 0dB channel balance gain. */ +} PMIC_AUDIO_OUTPUT_BALANCE_GAIN; + +/*! + * @enum PMIC_AUDIO_MONO_ADDER_MODE + * @brief Select the output mono adder operating mode. + * + * This enumeration is used to select the operating mode for the mono adder + * in the audio output section. + */ +typedef enum { + MONO_ADDER_OFF, /*!< Disable mono adder (keep separate + left and right channels). */ + MONO_ADD_LEFT_RIGHT, /*!< Add left and right channels. */ + MONO_ADD_OPPOSITE_PHASE, /*!< Add left and right channels but + with outputs in opposite phase + . */ + STEREO_OPPOSITE_PHASE /*!< Keep separate left and right + channels but invert phase of + left channel . */ +} PMIC_AUDIO_MONO_ADDER_MODE; + +/*! + * @enum PMIC_AUDIO_MONO_ADDER_OUTPUT_GAIN + * @brief Select the mono adder output amplifier gain level. + * + * This enumeration is used to select the output amplifier gain level for + * the mono adder. + */ +typedef enum { + MONOADD_GAIN_MINUS_6DB, /*!< Select -6dB mono adder output gain + . */ + MONOADD_GAIN_MINUS_3DB, /*!< Select -3dB mono adder output gain + . */ + MONOADD_GAIN_0DB /*!< Select 0dB mono adder output gain. */ +} PMIC_AUDIO_MONO_ADDER_OUTPUT_GAIN; + +/*@}*/ + +/*************************************************************************** + * PMIC-SPECIFIC DEFINITIONS * + ***************************************************************************/ + +/*! + * @name Definition of PMIC-specific Capabilities + * Constants that are used to define PMIC-specific capabilities. + */ +/*@{*/ + +/*! + * Define the minimum Stereo DAC sampling rate (Hz). + */ +extern const unsigned MIN_STDAC_SAMPLING_RATE_HZ; +/*! + * Define the maximum Stereo DAC sampling rate (Hz). + */ +extern const unsigned MAX_STDAC_SAMPLING_RATE_HZ; + +/*@}*/ + +#define DEBUG_AUDIO + +#ifdef __KERNEL__ + +/*************************************************************************** + * PMIC API DEFINITIONS * + ***************************************************************************/ + +/*! + * @name General Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Audio + * hardware. + */ +/*@{*/ + +/*! + * This function enables the Headset detection mechanism in hardware + */ +PMIC_STATUS pmic_audio_set_autodetect(int val); + +/*! + * @brief Request exclusive access to the PMIC Audio hardware. + * + * Attempt to open and gain exclusive access to a key PMIC audio hardware + * component (e.g., the Stereo DAC or the Voice CODEC). Depending upon the + * type of audio operation that is desired and the nature of the audio data + * stream, the Stereo DAC and/or the Voice CODEC will be a required hardware + * component and needs to be acquired by calling this function. + * + * If the open request is successful, then a numeric handle is returned + * and this handle must be used in all subsequent function calls to complete + * the configuration of either the Stereo DAC or the Voice CODEC and along + * with any other associated audio hardware components that will be needed. + * + * The same handle must also be used in the close call when use of the PMIC + * audio hardware is no longer required. + * + * The open request will fail if the requested audio hardware component has + * already been acquired by a previous open call but not yet closed. + * + * @param[out] handle Device handle to be used for subsequent PMIC + * Connectivity API calls. + * @param[in] device The required PMIC audio hardware component. + * + * @retval PMIC_SUCCESS If the open request was successful + * @retval PMIC_PARAMETER_ERROR If the handle argument is NULL. + * @retval PMIC_ERROR If the audio hardware component is + * unavailable. + */ +PMIC_STATUS pmic_audio_open(PMIC_AUDIO_HANDLE * const handle, + const PMIC_AUDIO_SOURCE device); + +/*! + * @brief Terminate further access to the PMIC audio hardware. + * + * Terminate further access to the PMIC audio hardware that was previously + * acquired by calling pmic_audio_open(). This now allows another thread to + * successfully call pmic_audio_open() to gain access. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the close request was successful. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_audio_close(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Configure the data bus protocol to be used. + * + * Provide the parameters needed to properly configure the audio data bus + * protocol so that data can be read/written to either the Stereo DAC or + * the Voice CODEC. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] busID Select data bus to be used. + * @param[in] protocol Select the data bus protocol. + * @param[in] masterSlave Select the data bus timing mode. + * @param[in] numSlots Define the number of timeslots (only if in + * master mode). + * + * @retval PMIC_SUCCESS If the protocol was successful configured. + * @retval PMIC_PARAMETER_ERROR If the handle or the protocol parameters + * are invalid. + */ +PMIC_STATUS pmic_audio_set_protocol(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_DATA_BUS busID, + const PMIC_AUDIO_BUS_PROTOCOL protocol, + const PMIC_AUDIO_BUS_MODE masterSlave, + const PMIC_AUDIO_NUMSLOTS numSlots); + +/*! + * @brief Retrieve the current data bus protocol configuration. + * + * Retrieve the parameters that define the current audio data bus protocol. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] busID The data bus being used. + * @param[out] protocol The data bus protocol being used. + * @param[out] masterSlave The data bus timing mode being used. + * @param[out] numSlots The number of timeslots being used (if in + * master mode). + * + * @retval PMIC_SUCCESS If the protocol was successful retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_audio_get_protocol(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_DATA_BUS * const busID, + PMIC_AUDIO_BUS_PROTOCOL * const protocol, + PMIC_AUDIO_BUS_MODE * const masterSlave, + PMIC_AUDIO_NUMSLOTS * const numSlots); + +/*! + * @brief Enable the Stereo DAC or the Voice CODEC. + * + * Explicitly enable the Stereo DAC or the Voice CODEC to begin audio + * playback or recording as required. This should only be done after + * successfully configuring all of the associated audio components (e.g., + * microphones, amplifiers, etc.). + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the device was successful enabled. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_ERROR If the device could not be enabled. + */ +PMIC_STATUS pmic_audio_enable(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Disable the Stereo DAC or the Voice CODEC. + * + * Explicitly disable the Stereo DAC or the Voice CODEC to end audio + * playback or recording as required. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the device was successful disabled. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_ERROR If the device could not be disabled. + */ +PMIC_STATUS pmic_audio_disable(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Reset the selected audio hardware control registers to their + * power on state. + * + * This resets all of the audio hardware control registers currently + * associated with the device handle back to their power on states. For + * example, if the handle is associated with the Stereo DAC and a + * specific output port and output amplifiers, then this function will + * reset all of those components to their power on state. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the reset operation was successful. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_ERROR If the reset was unsuccessful. + */ +PMIC_STATUS pmic_audio_reset(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Reset all audio hardware control registers to their power on state. + * + * This resets all of the audio hardware control registers back to their + * power on states. Use this function with care since it also invalidates + * (i.e., automatically closes) all currently opened device handles. + * + * @retval PMIC_SUCCESS If the reset operation was successful. + * @retval PMIC_ERROR If the reset was unsuccessful. + */ +PMIC_STATUS pmic_audio_reset_all(void); + +/*! + * @brief Set the Audio callback function. + * + * Register a callback function that will be used to signal PMIC audio + * events. For example, the OSS audio driver should register a callback + * function in order to be notified of headset connect/disconnect events. + * + * @param[in] func A pointer to the callback function. + * @param[in] eventMask A mask selecting events to be notified. + * @param[in] hs_state To know the headset state. + * + * @retval PMIC_SUCCESS If the callback was successfully + * registered. + * @retval PMIC_PARAMETER_ERROR If the handle or the eventMask is invalid. + */ +PMIC_STATUS pmic_audio_set_callback(void *func, + const PMIC_AUDIO_EVENTS eventMask, + PMIC_HS_STATE * hs_state); + +/*! + * @brief Deregisters the existing audio callback function. + * + * Deregister the callback function that was previously registered by calling + * pmic_audio_set_callback(). + * + * + * @retval PMIC_SUCCESS If the callback was successfully + * deregistered. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_audio_clear_callback(void); + +/*! + * @brief Get the current audio callback function settings. + * + * Get the current callback function and event mask. + * + * @param[out] func The current callback function. + * @param[out] eventMask The current event selection mask. + * + * @retval PMIC_SUCCESS If the callback information was + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_audio_get_callback(PMIC_AUDIO_CALLBACK * const func, + PMIC_AUDIO_EVENTS * const eventMask); + +/*! + * @brief Enable the anti-pop circuitry to avoid extra noise when inserting + * or removing a external device (e.g., a headset). + * + * Enable the use of the built-in anti-pop circuitry to prevent noise from + * being generated when an external audio device is inserted or removed + * from an audio plug. A slow ramp speed may be needed to avoid extra noise. + * + * @param[in] rampSpeed The desired anti-pop circuitry ramp speed. + * + * @retval PMIC_SUCCESS If the anti-pop circuitry was successfully + * enabled. + * @retval PMIC_ERROR If the anti-pop circuitry could not be + * enabled. + */ +PMIC_STATUS pmic_audio_antipop_enable(const PMIC_AUDIO_ANTI_POP_RAMP_SPEED + rampSpeed); + +/*! + * @brief Disable the anti-pop circuitry. + * + * Disable the use of the built-in anti-pop circuitry to prevent noise from + * being generated when an external audio device is inserted or removed + * from an audio plug. + * + * @retval PMIC_SUCCESS If the anti-pop circuitry was successfully + * disabled. + * @retval PMIC_ERROR If the anti-pop circuitry could not be + * disabled. + */ +PMIC_STATUS pmic_audio_antipop_disable(void); + +/*! + * @brief Performs a reset of the Voice CODEC/Stereo DAC digital filter. + * + * This function performs a reset of the digital filter using the back-to-back + * SPI write procedure. + * + * @retval PMIC_SUCCESS If the digital filter was successfully + * reset. + * @retval PMIC_ERROR If the digital filter could not be reset. + */ +PMIC_STATUS pmic_audio_digital_filter_reset(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Get the most recent PTT button voltage reading. + * + * This function returns the most recent reading for the PTT button voltage. + * The value may be used during the processing of the PTT_BUTTON_RANGE event + * as part of the headset ID detection process. + * + * @retval PMIC_SUCCESS If the most recent PTT button voltage was + * returned. + * @retval PMIC_PARAMETER_ERROR If a NULL pointer argument was given. + */ +PMIC_STATUS pmic_audio_get_ptt_button_level(unsigned int *const level); + +#ifdef DEBUG_AUDIO + +/*! + * @brief Provide a hexadecimal dump of all PMIC audio registers (DEBUG only). + * + * This function is intended strictly for debugging purposes only (i.e., + * the DEBUG macro must be defined) and will print the current values of the + * following PMIC registers: + * + * - AUD_CODEC (Voice CODEC state) + * - ST_DAC (Stereo DAC state) + * - RX_AUD_AMPS (audio input section state) + * - TX_AUD_AMPS (audio output section state) + * + * The register fields will also be decoded. + */ +void pmic_audio_dump_registers(void); + +#endif /* DEBUG */ + +/*@}*/ + +/*! + * @name General Voice CODEC Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Voice + * CODEC hardware. + */ +/*@{*/ + +/*! + * @brief Set the Voice CODEC clock source and operating characteristics. + * + * Define the Voice CODEC clock source and operating characteristics. This + * must be done before the Voice CODEC is enabled. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] clockIn Select the clock signal source. + * @param[in] clockFreq Select the clock signal frequency. + * @param[in] samplingRate Select the audio data sampling rate. + * @param[in] invert Enable inversion of the frame sync and/or + * bit clock inputs. + * + * @retval PMIC_SUCCESS If the Voice CODEC clock settings were + * successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or clock configuration was + * invalid. + * @retval PMIC_ERROR If the Voice CODEC clock configuration + * could not be set. + */ +PMIC_STATUS pmic_audio_vcodec_set_clock(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_CLOCK_IN_SOURCE + clockIn, + const PMIC_AUDIO_VCODEC_CLOCK_IN_FREQ + clockFreq, + const PMIC_AUDIO_VCODEC_SAMPLING_RATE + samplingRate, + const PMIC_AUDIO_CLOCK_INVERT invert); + +/*! + * @brief Get the Voice CODEC clock source and operating characteristics. + * + * Get the current Voice CODEC clock source and operating characteristics. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] clockIn The clock signal source. + * @param[out] clockFreq The clock signal frequency. + * @param[out] samplingRate The audio data sampling rate. + * @param[out] invert Inversion of the frame sync and/or + * bit clock inputs is enabled/disabled. + * + * @retval PMIC_SUCCESS If the Voice CODEC clock settings were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle invalid. + * @retval PMIC_ERROR If the Voice CODEC clock configuration + * could not be retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_clock(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_CLOCK_IN_SOURCE * + const clockIn, + PMIC_AUDIO_VCODEC_CLOCK_IN_FREQ * + const clockFreq, + PMIC_AUDIO_VCODEC_SAMPLING_RATE * + const samplingRate, + PMIC_AUDIO_CLOCK_INVERT * const invert); + +/*! + * @brief Set the Voice CODEC primary audio channel timeslot. + * + * Set the Voice CODEC primary audio channel timeslot. This function must be + * used if the default timeslot for the primary audio channel is to be changed. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] timeslot Select the primary audio channel timeslot. + * + * @retval PMIC_SUCCESS If the Voice CODEC primary audio channel + * timeslot was successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or audio channel timeslot + * was invalid. + * @retval PMIC_ERROR If the Voice CODEC primary audio channel + * timeslot could not be set. + */ +PMIC_STATUS pmic_audio_vcodec_set_rxtx_timeslot(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_VCODEC_TIMESLOT + timeslot); + +/*! + * @brief Get the current Voice CODEC primary audio channel timeslot. + * + * Get the current Voice CODEC primary audio channel timeslot. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] timeslot The primary audio channel timeslot. + * + * @retval PMIC_SUCCESS If the Voice CODEC primary audio channel + * timeslot was successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Voice CODEC primary audio channel + * timeslot could not be retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_rxtx_timeslot(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_VCODEC_TIMESLOT * + const timeslot); + +/*! + * @brief Set the Voice CODEC secondary recording audio channel timeslot. + * + * Set the Voice CODEC secondary audio channel timeslot. This function must be + * used if the default timeslot for the secondary audio channel is to be + * changed. The secondary audio channel timeslot is used to transmit the audio + * data that was recorded by the Voice CODEC from the secondary audio input + * channel. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] timeslot Select the secondary audio channel timeslot. + * + * @retval PMIC_SUCCESS If the Voice CODEC secondary audio channel + * timeslot was successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or audio channel timeslot + * was invalid. + * @retval PMIC_ERROR If the Voice CODEC secondary audio channel + * timeslot could not be set. + */ +PMIC_STATUS pmic_audio_vcodec_set_secondary_txslot(const PMIC_AUDIO_HANDLE + handle, + const + PMIC_AUDIO_VCODEC_TIMESLOT + timeslot); + +/*! + * @brief Get the Voice CODEC secondary recording audio channel timeslot. + * + * Get the Voice CODEC secondary audio channel timeslot. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] timeslot The secondary audio channel timeslot. + * + * @retval PMIC_SUCCESS If the Voice CODEC secondary audio channel + * timeslot was successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Voice CODEC secondary audio channel + * timeslot could not be retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_secondary_txslot(const PMIC_AUDIO_HANDLE + handle, + PMIC_AUDIO_VCODEC_TIMESLOT * + const timeslot); + +/*! + * @brief Set/Enable the Voice CODEC options. + * + * Set or enable various Voice CODEC options. The available options include + * the use of dithering, highpass digital filters, and loopback modes. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The Voice CODEC options to enable. + * + * @retval PMIC_SUCCESS If the Voice CODEC options were + * successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or Voice CODEC options + * were invalid. + * @retval PMIC_ERROR If the Voice CODEC options could not be + * successfully set/enabled. + */ +PMIC_STATUS pmic_audio_vcodec_set_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_VCODEC_CONFIG config); + +/*! + * @brief Clear/Disable the Voice CODEC options. + * + * Clear or disable various Voice CODEC options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The Voice CODEC options to be cleared/disabled. + * + * @retval PMIC_SUCCESS If the Voice CODEC options were + * successfully cleared/disabled. + * @retval PMIC_PARAMETER_ERROR If the handle or the Voice CODEC options + * were invalid. + * @retval PMIC_ERROR If the Voice CODEC options could not be + * cleared/disabled. + */ +PMIC_STATUS pmic_audio_vcodec_clear_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_VCODEC_CONFIG + config); + +/*! + * @brief Get the current Voice CODEC options. + * + * Get the current Voice CODEC options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] config The current set of Voice CODEC options. + * + * @retval PMIC_SUCCESS If the Voice CODEC options were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Voice CODEC options could not be + * retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_config(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_VCODEC_CONFIG * + const config); + +/*! + * @brief Enable the Voice CODEC bypass audio pathway. + * + * Enables the Voice CODEC bypass pathway for audio data. This allows direct + * output of the voltages on the TX data bus line to the output amplifiers + * (bypassing the digital-to-analog converters within the Voice CODEC). + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the Voice CODEC bypass was successfully + * enabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Voice CODEC bypass could not be + * enabled. + */ +PMIC_STATUS pmic_audio_vcodec_enable_bypass(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Disable the Voice CODEC bypass audio pathway. + * + * Disables the Voice CODEC bypass pathway for audio data. This means that + * the TX data bus line will deliver digital data to the digital-to-analog + * converters within the Voice CODEC. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the Voice CODEC bypass was successfully + * disabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Voice CODEC bypass could not be + * disabled. + */ +PMIC_STATUS pmic_audio_vcodec_disable_bypass(const PMIC_AUDIO_HANDLE handle); + +/*@}*/ + +/*! + * @name General Stereo DAC Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Stereo + * DAC hardware. + */ +/*@{*/ + +/*! + * @brief Set the Stereo DAC clock source and operating characteristics. + * + * Define the Stereo DAC clock source and operating characteristics. This + * must be done before the Stereo DAC is enabled. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] clockIn Select the clock signal source. + * @param[in] clockFreq Select the clock signal frequency. + * @param[in] samplingRate Select the audio data sampling rate. + * @param[in] invert Enable inversion of the frame sync and/or + * bit clock inputs. + * + * @retval PMIC_SUCCESS If the Stereo DAC clock settings were + * successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or clock configuration was + * invalid. + * @retval PMIC_ERROR If the Stereo DAC clock configuration + * could not be set. + */ +PMIC_STATUS pmic_audio_stdac_set_clock(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_CLOCK_IN_SOURCE clockIn, + const PMIC_AUDIO_STDAC_CLOCK_IN_FREQ + clockFreq, + const PMIC_AUDIO_STDAC_SAMPLING_RATE + samplingRate, + const PMIC_AUDIO_CLOCK_INVERT invert); + +/*! + * @brief Get the Stereo DAC clock source and operating characteristics. + * + * Get the current Stereo DAC clock source and operating characteristics. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] clockIn The clock signal source. + * @param[out] clockFreq The clock signal frequency. + * @param[out] samplingRate The audio data sampling rate. + * @param[out] invert Inversion of the frame sync and/or + * bit clock inputs is enabled/disabled. + * + * @retval PMIC_SUCCESS If the Stereo DAC clock settings were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle invalid. + * @retval PMIC_ERROR If the Stereo DAC clock configuration + * could not be retrieved. + */ +PMIC_STATUS pmic_audio_stdac_get_clock(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_CLOCK_IN_SOURCE * + const clockIn, + PMIC_AUDIO_STDAC_SAMPLING_RATE * + const samplingRate, + PMIC_AUDIO_STDAC_CLOCK_IN_FREQ * + const clockFreq, + PMIC_AUDIO_CLOCK_INVERT * const invert); + +/*! + * @brief Set the Stereo DAC primary audio channel timeslot. + * + * Set the Stereo DAC primary audio channel timeslot. This function must be + * used if the default timeslot for the primary audio channel is to be changed. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] timeslot Select the primary audio channel timeslot. + * + * @retval PMIC_SUCCESS If the Stereo DAC primary audio channel + * timeslot was successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or audio channel timeslot + * was invalid. + * @retval PMIC_ERROR If the Stereo DAC primary audio channel + * timeslot could not be set. + */ +PMIC_STATUS pmic_audio_stdac_set_rxtx_timeslot(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_STDAC_TIMESLOTS + timeslot); + +/*! + * @brief Get the current Stereo DAC primary audio channel timeslot. + * + * Get the current Stereo DAC primary audio channel timeslot. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] timeslot The primary audio channel timeslot. + * + * @retval PMIC_SUCCESS If the Stereo DAC primary audio channel + * timeslot was successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Stereo DAC primary audio channel + * timeslot could not be retrieved. + */ +PMIC_STATUS pmic_audio_stdac_get_rxtx_timeslot(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_STDAC_TIMESLOTS * + const timeslot); + +/*! + * @brief Set/Enable the Stereo DAC options. + * + * Set or enable various Stereo DAC options. The available options include + * enabling/disabling the bus master clock outputs. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The Stereo DAC options to enable. + * + * @retval PMIC_SUCCESS If the Stereo DAC options were + * successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or Stereo DAC options + * were invalid. + * @retval PMIC_ERROR If the Stereo DAC options could not be + * successfully set/enabled. + */ +PMIC_STATUS pmic_audio_stdac_set_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_STDAC_CONFIG config); + +/*! + * @brief Clear/Disable the Stereo DAC options. + * + * Clear or disable various Stereo DAC options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The Stereo DAC options to be cleared/disabled. + * + * @retval PMIC_SUCCESS If the Stereo DAC options were + * successfully cleared/disabled. + * @retval PMIC_PARAMETER_ERROR If the handle or the Stereo DAC options + * were invalid. + * @retval PMIC_ERROR If the Stereo DAC options could not be + * cleared/disabled. + */ +PMIC_STATUS pmic_audio_stdac_clear_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_STDAC_CONFIG config); + +/*! + * @brief Get the current Stereo DAC options. + * + * Get the current Stereo DAC options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] config The current set of Stereo DAC options. + * + * @retval PMIC_SUCCESS If the Stereo DAC options were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Stereo DAC options could not be + * retrieved. + */ +PMIC_STATUS pmic_audio_stdac_get_config(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_STDAC_CONFIG * const config); + +/*@}*/ + +/*! + * @name Audio Input Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC audio + * input hardware. + */ +/*@{*/ + +/*! + * @brief Set/Enable the audio input section options. + * + * Set or enable various audio input section options. The only available + * option right now is to enable the automatic disabling of the microphone + * input amplifiers when a microphone/headset is inserted or removed. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The audio input section options to enable. + * + * @retval PMIC_SUCCESS If the audio input section options were + * successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle or audio input section + * options were invalid. + * @retval PMIC_ERROR If the audio input section options could + * not be successfully set/enabled. + */ +PMIC_STATUS pmic_audio_input_set_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_INPUT_CONFIG config); + +/*! + * @brief Clear/Disable the audio input section options. + * + * Clear or disable various audio input section options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The audio input section options to be + * cleared/disabled. + * + * @retval PMIC_SUCCESS If the audio input section options were + * successfully cleared/disabled. + * @retval PMIC_PARAMETER_ERROR If the handle or the audio input section + * options were invalid. + * @retval PMIC_ERROR If the audio input section options could + * not be cleared/disabled. + */ +PMIC_STATUS pmic_audio_input_clear_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_INPUT_CONFIG config); + +/*! + * @brief Get the current audio input section options. + * + * Get the current audio input section options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] config The current set of audio input section options. + * + * @retval PMIC_SUCCESS If the audio input section options were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the audio input section options could + * not be retrieved. + */ +PMIC_STATUS pmic_audio_input_get_config(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_INPUT_CONFIG * const config); + +/*@}*/ + +/*! + * @name Audio Recording Using the Voice CODEC Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Voice CODEC + * to perform audio recording. + */ +/*@{*/ + +/*! + * @brief Select the microphone inputs to be used for Voice CODEC recording. + * + * Select left and right microphone inputs for Voice CODEC + * recording. It is possible to disable or not use a particular microphone + * input channel by specifying NO_MIC as a parameter. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] leftChannel Select the left microphone input channel. + * @param[in] rightChannel Select the right microphone input channel. + * + * @retval PMIC_SUCCESS If the microphone input channels were + * successfully enabled. + * @retval PMIC_PARAMETER_ERROR If the handle or microphone input ports + * were invalid. + * @retval PMIC_ERROR If the microphone input channels could + * not be successfully enabled. + */ +PMIC_STATUS pmic_audio_vcodec_set_mic(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_INPUT_PORT leftChannel, + const PMIC_AUDIO_INPUT_PORT rightChannel); + +/*! + * @brief Get the current microphone inputs being used for Voice CODEC + * recording. + * + * Get the left and right microphone inputs currently being + * used for Voice CODEC recording. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] leftChannel The left microphone input channel. + * @param[out] rightChannel The right microphone input channel. + * + * @retval PMIC_SUCCESS If the microphone input channels were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the microphone input channels could + * not be retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_mic(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_INPUT_PORT * const leftChannel, + PMIC_AUDIO_INPUT_PORT * + const rightChannel); + +/*! + * @brief Enable/disable the microphone input. + * + * This function enables/disables the current microphone input channel. The + * input amplifier is automatically turned off when the microphone input is + * disabled. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] leftChannel The left microphone input channel state. + * @param[in] rightChannel the right microphone input channel state. + * + * @retval PMIC_SUCCESS If the microphone input channels were + * successfully reconfigured. + * @retval PMIC_PARAMETER_ERROR If the handle or microphone input states + * were invalid. + * @retval PMIC_ERROR If the microphone input channels could + * not be reconfigured. + */ +PMIC_STATUS pmic_audio_vcodec_set_mic_on_off(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_INPUT_MIC_STATE + leftChannel, + const PMIC_AUDIO_INPUT_MIC_STATE + rightChannel); + +/*! + * @brief Return the current state of the microphone inputs. + * + * This function returns the current state (on/off) of the microphone + * input channels. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] leftChannel The current left microphone input channel + * state. + * @param[out] rightChannel the current right microphone input channel + * state. + * + * @retval PMIC_SUCCESS If the microphone input channel states + * were successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the microphone input channel states + * could not be retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_mic_on_off(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_INPUT_MIC_STATE * + const leftChannel, + PMIC_AUDIO_INPUT_MIC_STATE * + const rightChannel); + +/*! + * @brief Set the microphone input amplifier mode and gain level. + * + * This function sets the current microphone input amplifier operating mode + * and gain level. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] leftChannelMode The left microphone input amplifier mode. + * @param[in] leftChannelGain The left microphone input amplifier gain level. + * @param[in] rightChannelMode The right microphone input amplifier mode. + * @param[in] rightChannelGain The right microphone input amplifier gain + * level. + * + * @retval PMIC_SUCCESS If the microphone input amplifiers were + * successfully reconfigured. + * @retval PMIC_PARAMETER_ERROR If the handle or microphone input amplifier + * modes or gain levels were invalid. + * @retval PMIC_ERROR If the microphone input amplifiers could + * not be reconfigured. + */ +PMIC_STATUS pmic_audio_vcodec_set_record_gain(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_MIC_AMP_MODE + leftChannelMode, + const PMIC_AUDIO_MIC_GAIN + leftChannelGain, + const PMIC_AUDIO_MIC_AMP_MODE + rightChannelMode, + const PMIC_AUDIO_MIC_GAIN + rightChannelGain); + +/*! + * @brief Get the current microphone input amplifier mode and gain level. + * + * This function gets the current microphone input amplifier operating mode + * and gain level. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] leftChannelMode The left microphone input amplifier mode. + * @param[out] leftChannelGain The left microphone input amplifier gain level. + * @param[out] rightChannelMode The right microphone input amplifier mode. + * @param[out] rightChannelGain The right microphone input amplifier gain + * level. + * + * @retval PMIC_SUCCESS If the microphone input amplifier modes + * and gain levels were successfully + * retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the microphone input amplifier modes + * and gain levels could not be retrieved. + */ +PMIC_STATUS pmic_audio_vcodec_get_record_gain(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_MIC_AMP_MODE * + const leftChannelMode, + PMIC_AUDIO_MIC_GAIN * + const leftChannelGain, + PMIC_AUDIO_MIC_AMP_MODE * + const rightChannelMode, + PMIC_AUDIO_MIC_GAIN * + const rightChannelGain); + +/*! + * @brief Enable a microphone bias circuit. + * + * This function enables one of the available microphone bias circuits. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] biasCircuit The microphone bias circuit to be enabled. + * + * @retval PMIC_SUCCESS If the microphone bias circuit was + * successfully enabled. + * @retval PMIC_PARAMETER_ERROR If the handle or selected microphone bias + * circuit was invalid. + * @retval PMIC_ERROR If the microphone bias circuit could not + * be enabled. + */ +PMIC_STATUS pmic_audio_vcodec_enable_micbias(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_MIC_BIAS + biasCircuit); + +/*! + * @brief Disable a microphone bias circuit. + * + * This function disables one of the available microphone bias circuits. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] biasCircuit The microphone bias circuit to be disabled. + * + * @retval PMIC_SUCCESS If the microphone bias circuit was + * successfully disabled. + * @retval PMIC_PARAMETER_ERROR If the handle or selected microphone bias + * circuit was invalid. + * @retval PMIC_ERROR If the microphone bias circuit could not + * be disabled. + */ +PMIC_STATUS pmic_audio_vcodec_disable_micbias(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_MIC_BIAS + biasCircuit); + +/*@}*/ + +/*! + * @name Audio Playback Using the Voice CODEC Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Voice CODEC + * to perform audio playback. + */ +/*@{*/ + +/*! + * @brief Configure and enable the Voice CODEC mixer. + * + * This function configures and enables the Voice CODEC mixer. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] rxSecondaryTimeslot The timeslot used for the secondary audio + * channel. + * @param[in] gainIn The secondary audio channel gain level. + * @param[in] gainOut The mixer output gain level. + * + * @retval PMIC_SUCCESS If the Voice CODEC mixer was successfully + * configured and enabled. + * @retval PMIC_PARAMETER_ERROR If the handle or mixer configuration + * was invalid. + * @retval PMIC_ERROR If the Voice CODEC mixer could not be + * reconfigured or enabled. + */ +PMIC_STATUS pmic_audio_vcodec_enable_mixer(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_VCODEC_TIMESLOT + rxSecondaryTimeslot, + const PMIC_AUDIO_VCODEC_MIX_IN_GAIN + gainIn, + const PMIC_AUDIO_VCODEC_MIX_OUT_GAIN + gainOut); + +/*! + * @brief Disable the Voice CODEC mixer. + * + * This function disables the Voice CODEC mixer. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the Voice CODEC mixer was successfully + * disabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Voice CODEC mixer could not be + * disabled. + */ +PMIC_STATUS pmic_audio_vcodec_disable_mixer(const PMIC_AUDIO_HANDLE handle); + +/*@}*/ + +/*! + * @name Audio Playback Using the Stereo DAC Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Stereo DAC + * to perform audio playback. + */ +/*@{*/ + +/*! + * @brief Configure and enable the Stereo DAC mixer. + * + * This function configures and enables the Stereo DAC mixer. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] rxSecondaryTimeslot The timeslot used for the secondary audio + * channel. + * @param[in] gainIn The secondary audio channel gain level. + * @param[in] gainOut The mixer output gain level. + * + * @retval PMIC_SUCCESS If the Stereo DAC mixer was successfully + * configured and enabled. + * @retval PMIC_PARAMETER_ERROR If the handle or mixer configuration + * was invalid. + * @retval PMIC_ERROR If the Stereo DAC mixer could not be + * reconfigured or enabled. + */ +PMIC_STATUS pmic_audio_stdac_enable_mixer(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_STDAC_TIMESLOTS + rxSecondaryTimeslot, + const PMIC_AUDIO_STDAC_MIX_IN_GAIN + gainIn, + const PMIC_AUDIO_STDAC_MIX_OUT_GAIN + gainOut); + +/*! + * @brief Disable the Stereo DAC mixer. + * + * This function disables the Stereo DAC mixer. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the Stereo DAC mixer was successfully + * disabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the Stereo DAC mixer could not be + * disabled. + */ +PMIC_STATUS pmic_audio_stdac_disable_mixer(const PMIC_AUDIO_HANDLE handle); + +/*@}*/ + +/*! + * @name Audio Output Section Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC audio output + * section to support playback. + */ +/*@{*/ + +/*! + * @brief Select the audio output ports. + * + * This function selects the audio output ports to be used. This also enables + * the appropriate output amplifiers. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] port The audio output ports to be used. + * + * @retval PMIC_SUCCESS If the audio output ports were successfully + * acquired. + * @retval PMIC_PARAMETER_ERROR If the handle or output ports were + * invalid. + * @retval PMIC_ERROR If the audio output ports could not be + * acquired. + */ +PMIC_STATUS pmic_audio_output_set_port(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_OUTPUT_PORT port); + +/*! + * @brief Deselect/disable the audio output ports. + * + * This function disables the audio output ports that were previously enabled + * by calling pmic_audio_output_set_port(). + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] port The audio output ports to be disabled. + * + * @retval PMIC_SUCCESS If the audio output ports were successfully + * disabled. + * @retval PMIC_PARAMETER_ERROR If the handle or output ports were + * invalid. + * @retval PMIC_ERROR If the audio output ports could not be + * disabled. + */ +PMIC_STATUS pmic_audio_output_clear_port(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_OUTPUT_PORT port); + +/*! + * @brief Get the current audio output ports. + * + * This function retrieves the audio output ports that are currently being + * used. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] port The audio output ports currently being used. + * + * @retval PMIC_SUCCESS If the audio output ports were successfully + * retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the audio output ports could not be + * retrieved. + */ +PMIC_STATUS pmic_audio_output_get_port(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_OUTPUT_PORT * const port); + +/*! + * @brief Set the gain level for the external stereo inputs. + * + * This function sets the gain levels for the external stereo inputs. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] gain The external stereo input gain level. + * + * @retval PMIC_SUCCESS If the gain level was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle or gain level was invalid. + * @retval PMIC_ERROR If the gain level could not be set. + */ +PMIC_STATUS pmic_audio_output_set_stereo_in_gain(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_STEREO_IN_GAIN + gain); + +/*! + * @brief Get the current gain level for the external stereo inputs. + * + * This function retrieves the current gain levels for the external stereo + * inputs. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] gain The current external stereo input gain + * level. + * + * @retval PMIC_SUCCESS If the gain level was successfully + * retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the gain level could not be retrieved. + */ +PMIC_STATUS pmic_audio_output_get_stereo_in_gain(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_STEREO_IN_GAIN * + const gain); + +/*! + * @brief Set the output PGA gain level. + * + * This function sets the audio output PGA gain level. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] gain The output PGA gain level. + * + * @retval PMIC_SUCCESS If the gain level was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle or gain level was invalid. + * @retval PMIC_ERROR If the gain level could not be set. + */ +PMIC_STATUS pmic_audio_output_set_pgaGain(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_OUTPUT_PGA_GAIN + gain); + +/*! + * @brief Get the output PGA gain level. + * + * This function retrieves the current audio output PGA gain level. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] gain The current output PGA gain level. + * + * @retval PMIC_SUCCESS If the gain level was successfully + * retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the gain level could not be retrieved. + */ +PMIC_STATUS pmic_audio_output_get_pgaGain(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_OUTPUT_PGA_GAIN * + const gain); + +/*! + * @brief Enable the output mixer. + * + * This function enables the output mixer for the audio stream that + * corresponds to the current handle (i.e., the Voice CODEC, Stereo DAC, or + * the external stereo inputs). + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the mixer was successfully enabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the mixer could not be enabled. + */ +PMIC_STATUS pmic_audio_output_enable_mixer(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Disable the output mixer. + * + * This function disables the output mixer for the audio stream that + * corresponds to the current handle (i.e., the Voice CODEC, Stereo DAC, or + * the external stereo inputs). + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the mixer was successfully disabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the mixer could not be disabled. + */ +PMIC_STATUS pmic_audio_output_disable_mixer(const PMIC_AUDIO_HANDLE handle); + +/*! + * @brief Configure and enable the output balance amplifiers. + * + * This function configures and enables the output balance amplifiers. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] leftGain The desired left channel gain level. + * @param[in] rightGain The desired right channel gain level. + * + * @retval PMIC_SUCCESS If the output balance amplifiers were + * successfully configured and enabled. + * @retval PMIC_PARAMETER_ERROR If the handle or gain levels were invalid. + * @retval PMIC_ERROR If the output balance amplifiers could not + * be reconfigured or enabled. + */ +PMIC_STATUS pmic_audio_output_set_balance(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_OUTPUT_BALANCE_GAIN + leftGain, + const PMIC_AUDIO_OUTPUT_BALANCE_GAIN + rightGain); + +/*! + * @brief Get the current output balance amplifier gain levels. + * + * This function retrieves the current output balance amplifier gain levels. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] leftGain The current left channel gain level. + * @param[out] rightGain The current right channel gain level. + * + * @retval PMIC_SUCCESS If the output balance amplifier gain levels + * were successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the output balance amplifier gain levels + * could be retrieved. + */ +PMIC_STATUS pmic_audio_output_get_balance(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_OUTPUT_BALANCE_GAIN * + const leftGain, + PMIC_AUDIO_OUTPUT_BALANCE_GAIN * + const rightGain); + +/*! + * @brief Configure and enable the output mono adder. + * + * This function configures and enables the output mono adder. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] mode The desired mono adder operating mode. + * + * @retval PMIC_SUCCESS If the mono adder was successfully + * configured and enabled. + * @retval PMIC_PARAMETER_ERROR If the handle or mono adder mode was + * invalid. + * @retval PMIC_ERROR If the mono adder could not be reconfigured + * or enabled. + */ +PMIC_STATUS pmic_audio_output_enable_mono_adder(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_MONO_ADDER_MODE + mode); + +/*! + * @brief Disable the output mono adder. + * + * This function disables the output mono adder. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the mono adder was successfully + * disabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the mono adder could not be disabled. + */ +PMIC_STATUS pmic_audio_output_disable_mono_adder(const PMIC_AUDIO_HANDLE + handle); + +/*! + * @brief Configure the mono adder output gain level. + * + * This function configures the mono adder output amplifier gain level. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] gain The desired output gain level. + * + * @retval PMIC_SUCCESS If the mono adder output amplifier gain + * level was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle or gain level was invalid. + * @retval PMIC_ERROR If the mono adder output amplifier gain + * level could not be reconfigured. + */ +PMIC_STATUS pmic_audio_output_set_mono_adder_gain(const PMIC_AUDIO_HANDLE + handle, + const + PMIC_AUDIO_MONO_ADDER_OUTPUT_GAIN + gain); + +/*! + * @brief Get the current mono adder output gain level. + * + * This function retrieves the current mono adder output amplifier gain level. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] gain The current output gain level. + * + * @retval PMIC_SUCCESS If the mono adder output amplifier gain + * level was successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the mono adder output amplifier gain + * level could not be retrieved. + */ +PMIC_STATUS pmic_audio_output_get_mono_adder_gain(const PMIC_AUDIO_HANDLE + handle, + PMIC_AUDIO_MONO_ADDER_OUTPUT_GAIN + * const gain); + +/*! + * @brief Set various audio output section options. + * + * This function sets one or more audio output section configuration + * options. The currently supported options include whether to disable + * the non-inverting mono speaker output, enabling the loudspeaker common + * bias circuit, enabling detection of headset insertion/removal, and + * whether to automatically disable the headset amplifiers when a headset + * insertion/removal has been detected. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The desired audio output section + * configuration options to be set. + * + * @retval PMIC_SUCCESS If the desired configuration options were + * all successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle or configuration options + * were invalid. + * @retval PMIC_ERROR If the desired configuration options + * could not be set. + */ +PMIC_STATUS pmic_audio_output_set_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_OUTPUT_CONFIG config); + +/*! + * @brief Clear various audio output section options. + * + * This function clears one or more audio output section configuration + * options. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[in] config The desired audio output section + * configuration options to be cleared. + * + * @retval PMIC_SUCCESS If the desired configuration options were + * all successfully cleared. + * @retval PMIC_PARAMETER_ERROR If the handle or configuration options + * were invalid. + * @retval PMIC_ERROR If the desired configuration options + * could not be cleared. + */ +PMIC_STATUS pmic_audio_output_clear_config(const PMIC_AUDIO_HANDLE handle, + const PMIC_AUDIO_OUTPUT_CONFIG + config); + +/*! + * @brief Get the current audio output section options. + * + * This function retrieves the current audio output section configuration + * option settings. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * @param[out] config The current audio output section + * configuration option settings. + * + * @retval PMIC_SUCCESS If the current configuration options were + * successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the current configuration options + * could not be retrieved. + */ +PMIC_STATUS pmic_audio_output_get_config(const PMIC_AUDIO_HANDLE handle, + PMIC_AUDIO_OUTPUT_CONFIG * + const config); + +/*! + * @brief Enable the phantom ground circuit that is used to help identify + * the type of headset that has been inserted. + * + * This function enables the phantom ground circuit that is used to help + * identify the type of headset (e.g., stereo or mono) that has been inserted. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the phantom ground circuit was + * successfully enabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the phantom ground circuit could not + * be enabled. + */ +PMIC_STATUS pmic_audio_output_enable_phantom_ground(void); + +/*! + * @brief Disable the phantom ground circuit that is used to help identify + * the type of headset that has been inserted. + * + * This function disables the phantom ground circuit that is used to help + * identify the type of headset (e.g., stereo or mono) that has been inserted. + * + * @param[in] handle Device handle from pmic_audio_open() call. + * + * @retval PMIC_SUCCESS If the phantom ground circuit was + * successfully disabled. + * @retval PMIC_PARAMETER_ERROR If the handle was invalid. + * @retval PMIC_ERROR If the phantom ground circuit could not + * be disabled. + */ +PMIC_STATUS pmic_audio_output_disable_phantom_ground(void); + +/*! + * @brief Enable/Disable fm output + * + * This function enables/disables the fm output. + * + * @param[in] enable True to enable and false to disable + * + * @retval PMIC_SUCCESS If the fm output was + * successfully enable or disabled + * @retval PMIC_ERROR If the operation fails + */ +PMIC_STATUS pmic_audio_fm_output_enable(bool enable); + +/*@}*/ + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_PMIC_AUDIO_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/pmic_convity.h b/arch/arm/plat-mxc/include/mach/pmic_convity.h new file mode 100644 index 000000000000..b88bb54bad26 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/pmic_convity.h @@ -0,0 +1,873 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ASM_ARCH_MXC_PMIC_CONVITY_H__ +#define __ASM_ARCH_MXC_PMIC_CONVITY_H__ + +/*! + * @defgroup PMIC_CONNECTIVITY PMIC Connectivity Driver + * @ingroup PMIC_DRVRS + */ + +/*! + * @file arch-mxc/pmic_convity.h + * @brief External definitions for the PMIC Connectivity Client driver. + * + * The PMIC Connectivity driver and this API were developed to support the + * external connectivity capabilities of several power management ICs that + * are available from Freescale Semiconductor, Inc. + * + * The following operating modes, in terms of external connectivity, are + * supported: + * + * + * + * @ingroup PMIC_CONNECTIVITY + */ + +#include +#include + +/*************************************************************************** + * TYPEDEFS AND ENUMERATIONS * + ***************************************************************************/ + +/*! + * @name General Setup and Configuration Typedefs and Enumerations + * Typedefs and enumerations that are used for initial access to and + * configuration of the PMIC Connectivity hardware. + */ +/*@{*/ + +#define DEBUG_CONVITY + +/*! + * @typedef PMIC_CONVITY_HANDLE + * @brief Define typedef for a handle to the PMIC Connectivity hardware. + * + * Define a "handle" that is returned when the PMIC Connectivity hardware + * is opened. This handle grants exclusive access to the PMIC Connectivity + * hardware and must be used in all subsequent function calls. When access + * to the PMIC Connectivity hardware is no longer required, then a close + * operation must be done with this handle. The handle is no longer valid + * if the close operation was successful. + */ +typedef long PMIC_CONVITY_HANDLE; + +/*! + * @enum PMIC_CONVITY_MODE + * @brief Select the main Connectivity operating mode. + * + * Defines all possible PMIC Connectivity main operating modes. Only one of + * these modes can be active at a time. + */ +typedef enum { + USB, /*!< Select USB mode (this is also the Reset/Default + mode). */ + RS232, /*!< Select RS-232 mode. for SC55112 */ + RS232_1, /*!< Select RS-232_1 mode. */ + RS232_2, /*!< Select RS-232_2 mode. */ + CEA936_MONO, /*!< Select CE-936 Mono mode . */ + CEA936_STEREO, /*!< Select CE-936 Stereo mode . */ + CEA936_TEST_RIGHT, /*!< Select CE-936 Right Channel Test mode + . */ + CEA936_TEST_LEFT /*!< Select CE-936 Left Channel Test mode + . */ +} PMIC_CONVITY_MODE; + +/*! + * @enum PMIC_CONVITY_EVENTS + * @brief Identify the connectivity events that have been detected and should + * be handled. + * + * Defines all possible PMIC Connectivity events. Multiple events may be + * selected when defining a mask. + */ +typedef enum { + USB_DETECT_4V4_RISE = 1, /*!< Detected 4.4V rising edge. */ + USB_DETECT_4V4_FALL = 2, /*!< Detected 4.4V falling edge. */ + USB_DETECT_2V0_RISE = 4, /*!< Detected 2.0V rising edge. */ + USB_DETECT_2V0_FALL = 8, /*!< Detected 2.0V falling edge. */ + USB_DETECT_0V8_RISE = 16, /*!< Detected 0.8V rising edge. */ + USB_DETECT_0V8_FALL = 32, /*!< Detected 0.8V falling edge. */ + USB_DETECT_MINI_A = 64, /*!< Detected USB mini A plug. */ + USB_DETECT_MINI_B = 128, /*!< Detected USB mini B plug. */ + USB_DETECT_NON_USB_ACCESSORY = 256, /*!< Detected a non-USB connection + . */ + USB_DETECT_FACTORY_MODE = 512, /*!< Detected a factory-mode + connection . */ + USB_DP_HI = 1024, + + USB_DM_HI = 2048 +} PMIC_CONVITY_EVENTS; + +/*! + * @typedef PMIC_CONVITY_CALLBACK + * @brief Typedef for PMIC Connectivity event notification callback function. + * + * Define a typedef for the PMIC Connectivity event notification callback + * function. The signalled events are passed to the function as the first + * argument. The callback function should then process whatever events it + * can and then return the set of unhandled events (if any). + */ +typedef void (*PMIC_CONVITY_CALLBACK) (const PMIC_CONVITY_EVENTS event); + +/*@}*/ + +/*! + * @name USB and USB On-The-Go Mode-specific Typedefs and Enumerations + * Typedefs and enumerations that are used only for setting up and controlling + * the USB and USB On-The-Go modes of operation. + */ +/*@{*/ + +/*! + * @enum PMIC_CONVITY_USB_DEVICE_TYPE + * @brief Select the USB device type (either A or B). + * + * Defines all possible USB device types. This must match the physical + * connector being used. + */ +typedef enum { + USB_A_DEVICE, + USB_B_DEVICE +} PMIC_CONVITY_USB_DEVICE_TYPE; + +/*! + * @enum PMIC_CONVITY_USB_SPEED + * @brief Select the USB transceiver operating speed. + * + * Defines all possible USB transceiver operating speeds. Only one + * speed setting may be used at a time. + */ +typedef enum { + USB_LOW_SPEED, /*!< Select 1.5 Mbps. */ + USB_FULL_SPEED, /*!< Select 12 Mbps. */ + USB_HIGH_SPEED /*!< Select 480 Mbps (currently + not supported). */ +} PMIC_CONVITY_USB_SPEED; + +/*! + * @enum PMIC_CONVITY_USB_MODE + * @brief Select the USB transceiver operating mode. + * + * Defines all possible USB transceiver operating modes. Only one + * mode may be used at a time. The selected mode, in combination with + * the USB bus speed, determines the selection of pull-up and pull-down + * resistors. + */ +typedef enum { + USB_HOST, + USB_PERIPHERAL +} PMIC_CONVITY_USB_MODE; + +/*! + * @enum PMIC_CONVITY_USB_POWER_IN + * @brief Select the USB transceiver's power regulator input source. + * + * Defines all possible input power sources for the USB transceiver power + * regulator. Only one power supply source may be selected at a time. + */ +typedef enum { + + USB_POWER_INTERNAL_BOOST, /*!< Select internal power source + with boost. */ + + USB_POWER_VBUS, /*!< Select VBUS power source. */ + + USB_POWER_INTERNAL /*!< Select internal power source + . */ +} PMIC_CONVITY_USB_POWER_IN; + +/*! + * @enum PMIC_CONVITY_USB_POWER_OUT + * @brief Select the USB transceiver power regulator output voltage. + * + * Defines all possible output voltages for the USB transceiver power + * regulator. Only one power output voltage level may be selected at + * a time. + */ +typedef enum { + USB_POWER_2V775, /*!< Select 2.775V output voltage + . */ + USB_POWER_3V3 /*!< Select 3.3V output voltage. */ +} PMIC_CONVITY_USB_POWER_OUT; + +/*! + * @enum PMIC_CONVITY_USB_TRANSCEIVER_MODE + * @brief Select the USB transceiver operating mode. + * + * Defines all valid USB transceiver operating modes. Only one of the + * following USB transceiver modes may be selected at a time. + */ +typedef enum { + USB_TRANSCEIVER_OFF, /*!< USB transceiver currently off + . */ + USB_SINGLE_ENDED_UNIDIR, /*!< Select Single-ended + unidirectional transmit mode. */ + USB_SINGLE_ENDED_UNIDIR_TX, /*!< Select Single-ended + unidirectional transmit mode. */ + USB_SINGLE_ENDED_UNIDIR_RX, /*!< Select Single-ended + unidirectional receive mode. */ + USB_SINGLE_ENDED_BIDIR, /*!< Select Single-ended + bidirectional transmit mode. */ + USB_SINGLE_ENDED_LOW, /*!< Select USB SE0 mode. */ + USB_DIFFERENTIAL_UNIDIR_TX, /*!< Select Differential + unidirectional transmit mode + . */ + USB_DIFFERENTIAL_UNIDIR, /*!< Select Differential + unidirectional transmit mode + . */ + + USB_DIFFERENTIAL_UNIDIR_RX, /*!< Select Differential + unidirectional receive mode. */ + USB_DIFFERENTIAL_BIDIR, /*!< Select Differential + bidirectional transmit mode + */ + USB_SUSPEND_ON, /*!< Select Suspend mode. */ + USB_SUSPEND_OFF, /*!< Terminate Suspend mode. */ + USB_OTG_SRP_DLP_START, /*!< Start USB On-The-Go Session + Request Protocol using Data + Line Pulsing. */ + USB_OTG_SRP_DLP_STOP /*!< Terminate USB On-The-Go Session + Request Protocol using Data + Line Pulsing. */ +} PMIC_CONVITY_USB_TRANSCEIVER_MODE; + +/*! + * @enum PMIC_CONVITY_USB_OTG_CONFIG + * @brief Select the USB On-The-Go configuration options. + * + * Defines all possible USB On-The-Go configuration options. Multiple + * configuration options may be selected at the same time. However, only one + * VBUS current limit may be selected at a time. Selecting more than one + * VBUS current limit will result in undefined and implementation-dependent + * behavior. + */ +typedef enum { + USB_OTG_SE0CONN = 0x00001, /*!< Enable automatic + connection of a pull-up + resistor to VUSB when the + SE0 condition is detected. */ + USB_OTG_DLP_SRP = 0x00002, /*!< Enable use of the hardware + timer to control the + duration of the data line + pulse during the session + request protocol. */ + USB_PULL_OVERRIDE = 0x00004, /*!< Enable automatic disconnect + of pull-up and pull-down + resistors when transmitter + is enabled. */ + + USB_DP150K_PU = 0x00008, + + USB_VBUS_CURRENT_LIMIT_HIGH = 0x00010, /*!< Select current limit to 200mA + for VBUS regulator. */ + USB_VBUS_CURRENT_LIMIT_LOW = 0x00020, /*!< Select low current limit + for VBUS regulator. */ + USB_VBUS_CURRENT_LIMIT_LOW_10MS = 0x00040, /*!< Select low current limit + for VBUS regulator for + 10 ms . */ + USB_VBUS_CURRENT_LIMIT_LOW_20MS = 0x00080, /*!< Select low current limit + for VBUS regulator for + 20 ms . */ + USB_VBUS_CURRENT_LIMIT_LOW_30MS = 0x00100, /*!< Select low current limit + for VBUS regulator for + 30 ms . */ + USB_VBUS_CURRENT_LIMIT_LOW_40MS = 0x00200, /*!< Select low current limit + for VBUS regulator for + 40 ms . */ + USB_VBUS_CURRENT_LIMIT_LOW_50MS = 0x00400, /*!< Select low current limit + for VBUS regulator for + 50 ms . */ + USB_VBUS_CURRENT_LIMIT_LOW_60MS = 0x00800, /*!< Select low current limit + for VBUS regulator for + 60 ms . */ + + USB_VBUS_PULLDOWN = 0x01000, /*!< Enable VBUS pull-down. */ + + USB_USBCNTRL = 0x02000, + + USB_UDP_PD = 0x04000, + + USB_UDM_PD = 0x08000, + + USB_PU = 0x10000, + + USBXCVREN = 0x20000 +} PMIC_CONVITY_USB_OTG_CONFIG; +/*@}*/ + +/*! + * @name RS-232 Mode-specific Typedefs and Enumerations + * Typedefs and enumerations that are used only for setting up and controlling + * the RS-232 mode of operation. + */ +/*@{*/ + +/*! + * @enum PMIC_CONVITY_RS232_EXTERNAL + * @brief Select the RS-232 transceiver external connections. + * + * Defines all valid RS-232 transceiver external RX/TX connection options. + * Only one connection mode may be selected at a time. + */ +typedef enum { + RS232_TX_UDM_RX_UDP, /*!< Select RS-232 TX on UDM */ + RS232_TX_UDP_RX_UDM, /*!< Select RS-232 TX on UDP + . */ + RS232_TX_RX_EXTERNAL_DEFAULT /*!< Use power on default. */ +} PMIC_CONVITY_RS232_EXTERNAL; + +/*! + * @enum PMIC_CONVITY_RS232_INTERNAL + * @brief Select the RS-232 transceiver internal connections. + * + * Defines all valid RS-232 transceiver internal RX/TX connection options. + * Only one connection mode can be selected at a time. + */ +typedef enum { + RS232_TX_USE0VM_RX_UDATVP, /*!< Select RS-232 TX from USE0VM + . */ + RS232_TX_UDATVP_RX_URXVM, /*!< Select RS-232 TX from UDATVP + . */ + RS232_TX_UTXDI_RX_URXDO, /*!< Select RS-232 TX from UTXDI + . */ + RS232_TX_RX_INTERNAL_DEFAULT /*!< Use power on default. */ +} PMIC_CONVITY_RS232_INTERNAL; + +/*@}*/ + +/*! + * @name CEA-936 Mode-specific Typedefs and Enumerations + * Typedefs and enumerations that are used only for setting up and controlling + * the CEA-936 mode of operation. + */ +/*@{*/ + +/*! + * @enum PMIC_CONVITY_CEA936_EXIT_SIGNAL + * @brief Select the CEA-936 mode exit signal. + * + * Defines all valid CEA-936 connection termination signals. Only one + * termination signal can be selected at a time. + */ +typedef enum { + CEA936_UID_NO_PULLDOWN, /*!< No UID pull-down . */ + CEA936_UID_PULLDOWN_6MS, /*!< UID pull-down for 6 ms (+/-2 ms) + . */ + CEA936_UID_PULLDOWN, /*!< UID pulled down . */ + CEA936_UDMPULSE /*!< UDM pulsed . */ +} PMIC_CONVITY_CEA936_EXIT_SIGNAL; + +/*@}*/ + +/*************************************************************************** + * PMIC API DEFINITIONS * + ***************************************************************************/ + +/*! + * @name General Setup and Configuration APIs + * Functions for general setup and configuration of the PMIC Connectivity + * hardware. + */ +/*@{*/ + +/*! + * @brief Request exclusive access to the PMIC Connectivity hardware. + * + * Attempt to open and gain exclusive access to the PMIC Connectivity + * hardware. An initial operating mode (e.g., USB or RS-232) must also + * be specified. + * + * If the open request is successful, then a numeric handle is returned + * and this handle must be used in all subsequent function calls. The + * same handle must also be used in the close call when use of the PMIC + * connectivity hardware is no longer required. + * + * The open request will fail if another thread has already obtained the + * device handle and has not yet called pmic_convity_close() with it. + * + * @param handle Device handle to be used for subsequent PMIC + * Connectivity API calls. + * @param mode Initial connectivity operating mode. + * + * @retval PMIC_SUCCESS If the open request was successful + * @retval PMIC_ERROR If the connectivity hardware cannot be opened. + */ +PMIC_STATUS pmic_convity_open(PMIC_CONVITY_HANDLE * const handle, + const PMIC_CONVITY_MODE mode); + +/*! + * @brief Terminate further access to the PMIC Connectivity hardware. + * + * Terminate further access to the PMIC Connectivity hardware. This also + * allows another thread to successfully call pmic_convity_open() to gain + * access. + * + * @param handle Device handle from open() call. + * + * @retval PMIC_SUCCESS If the close request was successful. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_close(const PMIC_CONVITY_HANDLE handle); + +/*! + * @brief Set the PMIC Connectivity main operating mode. + * + * Change the current operating mode of the PMIC Connectivity hardware. + * The available connectivity operating modes are hardware-dependent and + * consists of one or more of the following: USB (including USB On-the-Go), + * RS-232, and CEA-936. Requesting an operating mode that is not supported + * by the PMIC hardware will return PMIC_NOT_SUPPORTED. + * + * @param handle Device handle from open() call. + * @param mode Desired operating mode. + * + * @retval PMIC_SUCCESS If the requested mode was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the PMIC hardware does not support + * the desired operating mode. + */ +PMIC_STATUS pmic_convity_set_mode(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_MODE mode); + +/*! + * @brief Get the current PMIC Connectivity main operating mode. + * + * Get the current operating mode for the PMIC Connectivity hardware. + * + * @param handle Device handle from open() call. + * @param mode The current PMIC Connectivity operating mode. + * + * @retval PMIC_SUCCESS If the requested mode was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_get_mode(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_MODE * const mode); + +/*! + * @brief Reset the Connectivity hardware to it's power on state. + * + * Restore all registers to the initial power-on/reset state. + * + * @param handle Device handle from open() call. + * + * @retval PMIC_SUCCESS If the reset was successful. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_reset(const PMIC_CONVITY_HANDLE handle); + +/*! + * @brief Set the Connectivity callback function. + * + * Register a callback function that will be used to signal PMIC Connectivity + * events. For example, the USB subsystem should register a callback function + * in order to be notified of device connect/disconnect events. Note, however, + * that non-USB events may also be signalled depending upon the PMIC hardware + * capabilities. Therefore, the callback function must be able to properly + * handle all of the possible events if support for non-USB peripherals is + * also to be included. + * + * @param handle Device handle from open() call. + * @param func A pointer to the callback function. + * @param eventMask A mask selecting events to be notified. + * + * @retval PMIC_SUCCESS If the callback was successfully registered. + * @retval PMIC_PARAMETER_ERROR If the handle or the eventMask is invalid. + */ +PMIC_STATUS pmic_convity_set_callback(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_CALLBACK func, + const PMIC_CONVITY_EVENTS eventMask); + +/*! + * @brief Deregisters the existing Connectivity callback function. + * + * Deregister the callback function that was previously registered by calling + * pmic_convity_set_callback(). + * + * @param handle Device handle from open() call. + * + * @retval PMIC_SUCCESS If the callback was successfully deregistered. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_clear_callback(const PMIC_CONVITY_HANDLE handle); + +/*! + * @brief Get the current Connectivity callback function settings. + * + * Get the current callback function and event mask. + * + * @param handle Device handle from open() call. + * @param func The current callback function. + * @param eventMask The current event selection mask. + * + * @retval PMIC_SUCCESS If the callback information was successfully + * retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_get_callback(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_CALLBACK * const func, + PMIC_CONVITY_EVENTS * const eventMask); + +/*@}*/ + +/***************************************************************************/ + +/*! + * @name USB and USB On-The-Go APIs + * USB Connectivity mode-specific configuration and setup functions. + */ +/*@{*/ + +/*! + * @brief Set the USB transceiver's operating speed. + * + * Set the USB transceiver speed. + * + * @param handle Device handle from open() call. + * @param speed The desired USB transceiver speed. + * + * @retval PMIC_SUCCESS If the transceiver speed was successfully + * set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the high speed (480 Mbps) mode is + * requested. + */ +PMIC_STATUS pmic_convity_usb_set_speed(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_SPEED speed); + +/*! + * This function enables/disables VUSB and VBUS output. + * This API configures the VUSBEN and VBUSEN bits of USB register + * + * @param handle Device handle from open() call. + * @param out_type true, for VUSB + * false, for VBUS + * @param out if true, output is enabled + * if false, output is disabled + * + * @return This function returns PMIC_SUCCESS if successful. + */ + +PMIC_STATUS pmic_convity_set_output(const PMIC_CONVITY_HANDLE handle, + bool out_type, bool out); + +/*! + * @brief Get the USB transceiver's operating speed. + * + * Get the USB transceiver speed. + * + * @param handle Device handle from open() call. + * @param speed The current USB transceiver speed. + * @param mode The current USB transceiver mode. + * + * @retval PMIC_SUCCESS If the transceiver speed was successfully + * set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * obtained + */ +PMIC_STATUS pmic_convity_usb_get_speed(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_USB_SPEED * const speed, + PMIC_CONVITY_USB_MODE * const mode); + +/*! + * @brief Set the USB transceiver's power supply configuration. + * + * Set the USB transceiver's power supply configuration. + * + * @param handle Device handle from open() call. + * @param pwrin USB transceiver regulator input power source. + * @param pwrout USB transceiver regulator output power level. + * + * @retval PMIC_SUCCESS If the USB transceiver's power supply + * configuration was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the PMIC hardware does not support + * the desired configuration. + */ +PMIC_STATUS pmic_convity_usb_set_power_source(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_POWER_IN + pwrin, + const PMIC_CONVITY_USB_POWER_OUT + pwrout); + +/*! + * @brief Get the USB transceiver's power supply configuration. + * + * Get the USB transceiver's current power supply configuration. + * + * @param handle Device handle from open() call. + * @param pwrin USB transceiver regulator input power source + * @param pwrout USB transceiver regulator output power level + * + * @retval PMIC_SUCCESS If the USB transceiver's power supply + * configuration was successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_usb_get_power_source(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_USB_POWER_IN * + const pwrin, + PMIC_CONVITY_USB_POWER_OUT * + const pwrout); + +/*! + * @brief Set the current USB transceiver operating mode. + * + * Set the USB transceiver's operating mode. + * + * @param handle Device handle from open() call. + * @param mode Desired operating mode. + * + * @retval PMIC_SUCCESS If the USB transceiver's operating mode + * was successfully configured. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the desired USB transceiver mode is + * not supported by the PMIC hardware. + */ +PMIC_STATUS pmic_convity_usb_set_xcvr(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_TRANSCEIVER_MODE + mode); + +/*! + * @brief Get the current USB transceiver operating mode. + * + * Get the USB transceiver's current operating mode. + * + * @param handle Device handle from open() call. + * @param mode Current operating mode. + * + * @retval PMIC_SUCCESS If the USB transceiver's operating mode + * was successfully retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_usb_get_xcvr(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_USB_TRANSCEIVER_MODE * + const mode); + +/*! + * @brief Set the current USB On-The-Go data line pulse duration (ms). + * + * Set the Data Line Pulse duration (in milliseconds) for the USB OTG + * Session Request Protocol. + * + * Note that for mc13783 the duration is fixed at 7.5 ms and calling this + * function will simply return PMIC_NOT_SUPPORTED. + * + * @param handle Device handle from open() call. + * @param duration The data line pulse duration (ms). + * + * @retval PMIC_SUCCESS If the pulse duration was successfully set. + * @retval PMIC_PARAMETER_ERROR If the handle or the data line pulse + * duration is invalid. + * @retval PMIC_NOT_SUPPORTED If the desired data line pulse duration + * is not supported by the PMIC hardware. + */ +PMIC_STATUS pmic_convity_usb_otg_set_dlp_duration(const PMIC_CONVITY_HANDLE + handle, + const unsigned int duration); + +/*! + * @brief Get the current USB On-The-Go data line pulse duration (ms). + * + * Get the current Data Line Pulse duration (in milliseconds) for the USB + * OTG Session Request Protocol. + * + * Note that the Data Line Pulse duration is fixed at 7.5 ms for the mc13783 + * PMIC. Therefore, calling this function while using the mc13783 PMIC will + * simply return PMIC_NOT_SUPPORTED. + * + * @param handle Device handle from open() call. + * @param duration The data line pulse duration (ms). + * + * @retval PMIC_SUCCESS If the pulse duration was successfully + * obtained. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If called using the mc13783 PMIC. + */ +PMIC_STATUS pmic_convity_usb_otg_get_dlp_duration(const PMIC_CONVITY_HANDLE + handle, + unsigned int *const duration); + +/*! + * @brief Start the USB OTG Host Negotiation Protocol (HNP) process. + * + * This function must be called during the start of the HNP process to + * properly reconfigure the pull-up resistor on the D+ line for both + * the USB A and B devices. + * + * @param handle device handle from open() call + * @param deviceType the USB device type (either A or B) + * + * @return PMIC_SUCCESS if the HNP was successfully started + */ +PMIC_STATUS pmic_convity_usb_otg_begin_hnp(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_DEVICE_TYPE + deviceType); + +/*! + * @brief Complete the USB OTG Host Negotiation Protocol (HNP) process. + * + * This function must be called during the end of the HNP process to + * properly reconfigure the pull-up resistor on the D+ line for both + * the USB A and B devices. + * + * @param handle device handle from open() call + * @param deviceType the USB device type (either A or B) + * + * @return PMIC_SUCCESS if the HNP was successfully ended + */ +PMIC_STATUS pmic_convity_usb_otg_end_hnp(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_DEVICE_TYPE + deviceType); + +/*! + * @brief Set the current USB On-The-Go configuration. + * + * Set the USB On-The-Go (OTG) configuration. Multiple configuration settings + * may be OR'd together in a single call. However, selecting conflicting + * settings (e.g., multiple VBUS current limits) will result in undefined + * behavior. + * + * @param handle Device handle from open() call. + * @param cfg Desired USB OTG configuration. + * + * @retval PMIC_SUCCESS If the OTG configuration was successfully + * set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the desired USB OTG configuration is + * not supported by the PMIC hardware. + */ +PMIC_STATUS pmic_convity_usb_otg_set_config(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_OTG_CONFIG + cfg); + +/*! + * @brief Clear the current USB On-The-Go configuration. + * + * Clears the USB On-The-Go (OTG) configuration. Multiple configuration settings + * may be OR'd together in a single call. However, selecting conflicting + * settings (e.g., multiple VBUS current limits) will result in undefined + * behavior. + * + * @param handle Device handle from open() call. + * @param cfg USB OTG configuration settings to be cleared. + * + * @retval PMIC_SUCCESS If the OTG configuration was successfully + * cleared. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the desired USB OTG configuration is + * not supported by the PMIC hardware. + */ +PMIC_STATUS pmic_convity_usb_otg_clear_config(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_USB_OTG_CONFIG + cfg); + +/*! + * @brief Get the current USB On-The-Go configuration. + * + * Get the current USB On-The-Go (OTG) configuration. + * + * @param handle Device handle from open() call. + * @param cfg The current USB OTG configuration. + * + * @retval PMIC_SUCCESS If the OTG configuration was successfully + * retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_usb_otg_get_config(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_USB_OTG_CONFIG * + const cfg); + +/*@}*/ + +/***************************************************************************/ + +/*! + * @name RS-232 APIs + * RS-232 Connectivity mode-specific configuration and setup functions. + */ +/*@{*/ + +/*! + * @brief Set the current RS-232 operating configuration. + * + * Set the connectivity interface to the selected RS-232 operating mode. + * Note that the RS-232 operating mode will be automatically overridden + * if the USB_EN is asserted at any time (e.g., when a USB device is + * attached). + * + * @param handle Device handle from open() call. + * @param cfgInternal RS-232 transceiver internal connections. + * @param cfgExternal RS-232 transceiver external connections. + * + * @retval PMIC_SUCCESS If the requested RS-232 mode was set. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the desired RS-232 configuration is + * not supported by the PMIC hardware. + */ +PMIC_STATUS pmic_convity_rs232_set_config(const PMIC_CONVITY_HANDLE handle, + const PMIC_CONVITY_RS232_INTERNAL + cfgInternal, + const PMIC_CONVITY_RS232_EXTERNAL + cfgExternal); + +/*! + * @brief Get the current RS-232 operating configuration. + * + * Get the connectivity interface's current RS-232 operating mode. + * + * @param handle Device handle from open() call. + * @param cfgInternal RS-232 transceiver internal connections. + * @param cfgExternal RS-232 transceiver external connections. + * + * @retval PMIC_SUCCESS If the requested RS-232 mode was retrieved. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + */ +PMIC_STATUS pmic_convity_rs232_get_config(const PMIC_CONVITY_HANDLE handle, + PMIC_CONVITY_RS232_INTERNAL * + const cfgInternal, + PMIC_CONVITY_RS232_EXTERNAL * + const cfgExternal); + +/***************************************************************************/ + +/*@}*/ + +/*! + * @name CE-936 APIs + * CE-936 Connectivity mode-specific configuration and setup functions. + */ +/*@{*/ + +/*! + * @brief Send a signal to exit CEA-936 mode. + * + * Signal the attached device to exit the current CEA-936 operating mode. + * Returns an error if the current operating mode is not CEA-936. + * + * @param handle Device handle from open() call. + * @param signal Type of exit signal to be sent. + * + * @retval PMIC_SUCCESS If the CEA-936 exit mode signal was sent. + * @retval PMIC_PARAMETER_ERROR If the handle is invalid. + * @retval PMIC_NOT_SUPPORTED If the desired CEA-936 exit mode signal + * is not supported by the PMIC hardware. + */ +PMIC_STATUS pmic_convity_cea936_exit_signal(const PMIC_CONVITY_HANDLE handle, + const + PMIC_CONVITY_CEA936_EXIT_SIGNAL + signal); + +/*@}*/ + +#endif /* __ASM_ARCH_MXC_PMIC_CONVITY_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/pmic_power.h b/arch/arm/plat-mxc/include/mach/pmic_power.h new file mode 100644 index 000000000000..60f23ab9c888 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/pmic_power.h @@ -0,0 +1,1358 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU Lesser General + * Public License. You may obtain a copy of the GNU Lesser General + * Public License Version 2.1 or later at the following locations: + * + * http://www.opensource.org/licenses/lgpl-license.html + * http://www.gnu.org/copyleft/lgpl.html + */ +#ifndef __ASM_ARCH_MXC_PMIC_POWER_H__ +#define __ASM_ARCH_MXC_PMIC_POWER_H__ + +/*! + * @defgroup PMIC_POWER PMIC Power Driver + * @ingroup PMIC_DRVRS + */ + +/*! + * @file arch-mxc/pmic_power.h + * @brief This is the header of PMIC power driver. + * + * @ingroup PMIC_POWER + */ + +#include +#include +#include + +/*! + * @name IOCTL user space interface + */ +/*! @{ */ + +/*! + * Turn on a regulator. + */ +#define PMIC_REGULATOR_ON _IOWR('p', 0xf0, int) + +/*! + * Turn off a regulator. + */ +#define PMIC_REGULATOR_OFF _IOWR('p', 0xf1, int) + +/*! + * Set regulator configuration. + */ +#define PMIC_REGULATOR_SET_CONFIG _IOWR('p', 0xf2, int) + +/*! + * Get regulator configuration. + */ +#define PMIC_REGULATOR_GET_CONFIG _IOWR('p', 0xf3, int) + +/*! + * Miscellaneous Power Test. + */ +#define PMIC_POWER_CHECK_MISC _IOWR('p', 0xf4, int) + +/*! @} */ + +/*! + * This enumeration define all power interrupts + */ +typedef enum { + /*! + * BP turn on threshold detection + */ + PWR_IT_BPONI = 0, + /*! + * End of life / low battery detect + */ + PWR_IT_LOBATLI, + /*! + * Low battery warning + */ + PWR_IT_LOBATHI, + /*! + * ON1B event + */ + PWR_IT_ONOFD1I, + /*! + * ON2B event + */ + PWR_IT_ONOFD2I, + /*! + * ON3B event + */ + PWR_IT_ONOFD3I, + /*! + * System reset + */ + PWR_IT_SYSRSTI, + /*! + * Power ready + */ + PWR_IT_PWRRDYI, + /*! + * Power cut event + */ + PWR_IT_PCI, + /*! + * Warm start event + */ + PWR_IT_WARMI, + /*! + * Memory hold event + */ +} t_pwr_int; + +/*! + * VHOLD regulator output voltage setting. + */ +typedef enum { + VH_1_875V, /*!< 1.875V */ + VH_2_5V, /*!< 2.5V */ + VH_1_55V, /*!< 1.55V */ + VH_PASSTHROUGH, /*!< Pass-through mode */ +} t_vhold_voltage; + +/*! + * PMIC power control configuration. + */ + +typedef struct { + bool pc_enable; /*!< Power cut enable */ + unsigned char pc_timer; /*!< Power cut timer value */ + bool pc_count_enable; /*!< Power cut counter enable, + If TURE, Power cuts are disabled + when pc_count > pc_max_count; + If FALSE, Power cuts are not + disabled when + pc_count > pc_max_count */ + unsigned char pc_count; /*!< Power cut count */ + unsigned char pc_max_count; /*!< Power cut maximum count */ + bool warm_enable; /*!< User Off state enable */ + bool user_off_pc; /*!< Automatic transition to user off + during power cut */ + bool clk_32k_enable; /*!< 32 kHz output buffer enable + during memory hold */ + bool clk_32k_user_off; /*!< Keeps the CLK32KMCU active during + user off power cut modes */ + bool en_vbkup1; /*!< enable VBKUP1 regulator */ + bool auto_en_vbkup1; /*!< automatically enable VBKUP1 + regulator in the memory hold + and user of modes */ + t_vhold_voltage vhold_voltage; /*!< output voltage for VBKUP1 */ + bool en_vbkup2; /*!< enable VBKUP2 regulator */ + bool auto_en_vbkup2; /*!< automatically enable VBKUP2 + regulator in the memory hold + and user of modes */ + t_vhold_voltage vhold_voltage2; /*!< output voltage for VBKUP2 */ + unsigned char mem_timer; /*!< duration of the memory hold + timer */ + bool mem_allon; /*!< memory hold timer infinity mode, + If TRUE, the memory hold timer + will be set to infinity and + the mem_timer filed will be + ignored */ +} t_pc_config; + +/*! + * brief PMIC regulators. + */ + +typedef enum { + SW_SW1A = 0, /*!< SW1A or SW1 */ + SW_SW1B, /*!< SW1B */ + SW_SW2A, /*!< SW2A or SW2 */ + SW_SW2B, /*!< SW2B */ + SW_SW3, /*!< SW3 */ + SW_PLL, /*!< PLL */ + REGU_VAUDIO, /*!< VAUDIO */ + REGU_VIOHI, /*!< VIOHI */ + REGU_VIOLO, /*!< VIOLO */ + REGU_VDIG, /*!< VDIG */ + REGU_VGEN, /*!< VGEN */ + REGU_VRFDIG, /*!< VRFDIG */ + REGU_VRFREF, /*!< VRFREF */ + REGU_VRFCP, /*!< VRFCP */ + REGU_VSIM, /*!< VSIM */ + REGU_VESIM, /*!< VESIM */ + REGU_VCAM, /*!< VCAM */ + REGU_VRFBG, /*!< VRFBG */ + REGU_VVIB, /*!< VVIB */ + REGU_VRF1, /*!< VRF1 */ + REGU_VRF2, /*!< VRF2 */ + REGU_VMMC1, /*!< VMMC1 or VMMC */ + REGU_VMMC2, /*!< VMMC2 */ + REGU_GPO1, /*!< GPIO1 */ + REGU_GPO2, /*!< GPO2 */ + REGU_GPO3, /*!< GPO3 */ + REGU_GPO4, /*!< GPO4 */ + REGU_V1, /*!< V1 */ + REGU_V2, /*!< V2 */ + REGU_V3, /*!< V3 */ + REGU_V4, /*!< V4 */ +} t_pmic_regulator; + +/*! + * @enum t_pmic_regulator_voltage_sw1 + * @brief PMIC Switch mode regulator SW1 output voltages. + */ + +typedef enum { + SW1_1V = 0, /*!< 1.0 V */ + SW1_1_1V, /*!< 1.1 V */ + SW1_1_2V, /*!< 1.2 V */ + SW1_1_3V, /*!< 1.3 V */ + SW1_1_4V, /*!< 1.4 V */ + SW1_1_55V, /*!< 1.55 V */ + SW1_1_625V, /*!< 1.625 V */ + SW1_1_875V, /*!< 1.875 V */ +} t_pmic_regulator_voltage_sw1; + +/*! + * @enum t_pmic_regulator_voltage_sw1a + * @brief PMIC regulator SW1A output voltage. + */ +typedef enum { + SW1A_0_9V = 0, /*!< 0.900 V */ + SW1A_0_925V, /*!< 0.925 V */ + SW1A_0_95V, /*!< 0.950 V */ + SW1A_0_975V, /*!< 0.975 V */ + SW1A_1V, /*!< 1.000 V */ + SW1A_1_025V, /*!< 1.025 V */ + SW1A_1_05V, /*!< 1.050 V */ + SW1A_1_075V, /*!< 1.075 V */ + SW1A_1_1V, /*!< 1.100 V */ + SW1A_1_125V, /*!< 1.125 V */ + SW1A_1_15V, /*!< 1.150 V */ + SW1A_1_175V, /*!< 1.175 V */ + SW1A_1_2V, /*!< 1.200 V */ + SW1A_1_225V, /*!< 1.225 V */ + SW1A_1_25V, /*!< 1.250 V */ + SW1A_1_275V, /*!< 1.275 V */ + SW1A_1_3V, /*!< 1.300 V */ + SW1A_1_325V, /*!< 1.325 V */ + SW1A_1_35V, /*!< 1.350 V */ + SW1A_1_375V, /*!< 1.375 V */ + SW1A_1_4V, /*!< 1.400 V */ + SW1A_1_425V, /*!< 1.425 V */ + SW1A_1_45V, /*!< 1.450 V */ + SW1A_1_475V, /*!< 1.475 V */ + SW1A_1_5V, /*!< 1.500 V */ + SW1A_1_525V, /*!< 1.525 V */ + SW1A_1_55V, /*!< 1.550 V */ + SW1A_1_575V, /*!< 1.575 V */ + SW1A_1_6V, /*!< 1.600 V */ + SW1A_1_625V, /*!< 1.625 V */ + SW1A_1_65V, /*!< 1.650 V */ + SW1A_1_675V, /*!< 1.675 V */ + SW1A_1_7V, /*!< 1.700 V */ + SW1A_1_8V = 36, /*!< 1.800 V */ + SW1A_1_85V = 40, /*!< 1.850 V */ + SW1A_2V = 44, /*!< 2_000 V */ + SW1A_2_1V = 48, /*!< 2_100 V */ + SW1A_2_2V = 52, /*!< 2_200 V */ +} t_pmic_regulator_voltage_sw1a; + +/*! + * @enum t_pmic_regulator_voltage_sw1b + * @brief PMIC regulator SW1B output voltage. + */ +typedef enum { + SW1B_0_9V = 0, /*!< 0.900 V */ + SW1B_0_925V, /*!< 0.925 V */ + SW1B_0_95V, /*!< 0.950 V */ + SW1B_0_975V, /*!< 0.975 V */ + SW1B_1V, /*!< 1.000 V */ + SW1B_1_025V, /*!< 1.025 V */ + SW1B_1_05V, /*!< 1.050 V */ + SW1B_1_075V, /*!< 1.075 V */ + SW1B_1_1V, /*!< 1.100 V */ + SW1B_1_125V, /*!< 1.125 V */ + SW1B_1_15V, /*!< 1.150 V */ + SW1B_1_175V, /*!< 1.175 V */ + SW1B_1_2V, /*!< 1.200 V */ + SW1B_1_225V, /*!< 1.225 V */ + SW1B_1_25V, /*!< 1.250 V */ + SW1B_1_275V, /*!< 1.275 V */ + SW1B_1_3V, /*!< 1.300 V */ + SW1B_1_325V, /*!< 1.325 V */ + SW1B_1_35V, /*!< 1.350 V */ + SW1B_1_375V, /*!< 1.375 V */ + SW1B_1_4V, /*!< 1.400 V */ + SW1B_1_425V, /*!< 1.425 V */ + SW1B_1_45V, /*!< 1.450 V */ + SW1B_1_475V, /*!< 1.475 V */ + SW1B_1_5V, /*!< 1.500 V */ + SW1B_1_525V, /*!< 1.525 V */ + SW1B_1_55V, /*!< 1.550 V */ + SW1B_1_575V, /*!< 1.575 V */ + SW1B_1_6V, /*!< 1.600 V */ + SW1B_1_625V, /*!< 1.625 V */ + SW1B_1_65V, /*!< 1.650 V */ + SW1B_1_675V, /*!< 1.675 V */ + SW1B_1_7V, /*!< 1.700 V */ + SW1B_1_8V = 36, /*!< 1.800 V */ + SW1B_1_85V = 40, /*!< 1.850 V */ + SW1B_2V = 44, /*!< 2_000 V */ + SW1B_2_1V = 48, /*!< 2_100 V */ + SW1B_2_2V = 52, /*!< 2_200 V */ +} t_pmic_regulator_voltage_sw1b; + +/*! + * @enum t_pmic_regulator_voltage_sw2 + * @brief PMIC Switch mode regulator SW2 output voltages. + */ +typedef enum { + SW2_1V = 0, /*!< 1.0 V */ + SW2_1_1V, /*!< 1.1 V */ + SW2_1_2V, /*!< 1.2 V */ + SW2_1_3V, /*!< 1.3 V */ + SW2_1_4V, /*!< 1.4 V */ + SW2_1_55V, /*!< 1.55 V */ + SW2_1_625V, /*!< 1.625 V */ + SW2_1_875V, /*!< 1.875 V */ +} t_pmic_regulator_voltage_sw2; + +/*! + * @enum t_pmic_regulator_voltage_sw2a + * @brief PMIC regulator SW2A output voltage. + */ +typedef enum { + SW2A_0_9V = 0, /*!< 0.900 V */ + SW2A_0_925V, /*!< 0.925 V */ + SW2A_0_95V, /*!< 0.950 V */ + SW2A_0_975V, /*!< 0.975 V */ + SW2A_1V, /*!< 1.000 V */ + SW2A_1_025V, /*!< 1.025 V */ + SW2A_1_05V, /*!< 1.050 V */ + SW2A_1_075V, /*!< 1.075 V */ + SW2A_1_1V, /*!< 1.100 V */ + SW2A_1_125V, /*!< 1.125 V */ + SW2A_1_15V, /*!< 1.150 V */ + SW2A_1_175V, /*!< 1.175 V */ + SW2A_1_2V, /*!< 1.200 V */ + SW2A_1_225V, /*!< 1.225 V */ + SW2A_1_25V, /*!< 1.250 V */ + SW2A_1_275V, /*!< 1.275 V */ + SW2A_1_3V, /*!< 1.300 V */ + SW2A_1_325V, /*!< 1.325 V */ + SW2A_1_35V, /*!< 1.350 V */ + SW2A_1_375V, /*!< 1.375 V */ + SW2A_1_4V, /*!< 1.400 V */ + SW2A_1_425V, /*!< 1.425 V */ + SW2A_1_45V, /*!< 1.450 V */ + SW2A_1_475V, /*!< 1.475 V */ + SW2A_1_5V, /*!< 1.500 V */ + SW2A_1_525V, /*!< 1.525 V */ + SW2A_1_55V, /*!< 1.550 V */ + SW2A_1_575V, /*!< 1.575 V */ + SW2A_1_6V, /*!< 1.600 V */ + SW2A_1_625V, /*!< 1.625 V */ + SW2A_1_65V, /*!< 1.650 V */ + SW2A_1_675V, /*!< 1.675 V */ + SW2A_1_7V, /*!< 1.700 V */ + SW2A_1_8V = 36, /*!< 1.800 V */ + SW2A_1_9V = 40, /*!< 1.900 V */ + SW2A_2V = 44, /*!< 2_000 V */ + SW2A_2_1V = 48, /*!< 2_100 V */ + SW2A_2_2V = 52, /*!< 2_200 V */ +} t_pmic_regulator_voltage_sw2a; + +/*! + * @enum t_pmic_regulator_voltage_sw2b + * @brief PMIC regulator SW2B output voltage. + */ +typedef enum { + SW2B_0_9V = 0, /*!< 0.900 V */ + SW2B_0_925V, /*!< 0.925 V */ + SW2B_0_95V, /*!< 0.950 V */ + SW2B_0_975V, /*!< 0.975 V */ + SW2B_1V, /*!< 1.000 V */ + SW2B_1_025V, /*!< 1.025 V */ + SW2B_1_05V, /*!< 1.050 V */ + SW2B_1_075V, /*!< 1.075 V */ + SW2B_1_1V, /*!< 1.100 V */ + SW2B_1_125V, /*!< 1.125 V */ + SW2B_1_15V, /*!< 1.150 V */ + SW2B_1_175V, /*!< 1.175 V */ + SW2B_1_2V, /*!< 1.200 V */ + SW2B_1_225V, /*!< 1.225 V */ + SW2B_1_25V, /*!< 1.250 V */ + SW2B_1_275V, /*!< 1.275 V */ + SW2B_1_3V, /*!< 1.300 V */ + SW2B_1_325V, /*!< 1.325 V */ + SW2B_1_35V, /*!< 1.350 V */ + SW2B_1_375V, /*!< 1.375 V */ + SW2B_1_4V, /*!< 1.400 V */ + SW2B_1_425V, /*!< 1.425 V */ + SW2B_1_45V, /*!< 1.450 V */ + SW2B_1_475V, /*!< 1.475 V */ + SW2B_1_5V, /*!< 1.500 V */ + SW2B_1_525V, /*!< 1.525 V */ + SW2B_1_55V, /*!< 1.550 V */ + SW2B_1_575V, /*!< 1.575 V */ + SW2B_1_6V, /*!< 1.600 V */ + SW2B_1_625V, /*!< 1.625 V */ + SW2B_1_65V, /*!< 1.650 V */ + SW2B_1_675V, /*!< 1.675 V */ + SW2B_1_7V, /*!< 1.700 V */ + SW2B_1_8V = 36, /*!< 1.800 V */ + SW2B_1_9V = 40, /*!< 1.900 V */ + SW2B_2V = 44, /*!< 2_000 V */ + SW2B_2_1V = 48, /*!< 2_100 V */ + SW2B_2_2V = 52, /*!< 2_200 V */ +} t_pmic_regulator_voltage_sw2b; + +/*! + * @enum t_pmic_regulator_voltage_sw3 + * @brief PMIC Switch mode regulator SW3 output voltages. + */ +typedef enum { + SW3_5V = 0, /*!< 5.0 V */ + SW3_5_1V = 0, /*!< 5.1 V */ + SW3_5_6V, /*!< 5.6 V */ +} t_pmic_regulator_voltage_sw3; + +/*! + * @enum t_switcher_factor + * @brief PLL multiplication factor + */ +typedef enum { + FACTOR_28 = 0, /*!< 917 504 kHz */ + FACTOR_29, /*!< 950 272 kHz */ + FACTOR_30, /*!< 983 040 kHz */ + FACTOR_31, /*!< 1 015 808 kHz */ + FACTOR_32, /*!< 1 048 576 kHz */ + FACTOR_33, /*!< 1 081 344 kHz */ + FACTOR_34, /*!< 1 114 112 kHz */ + FACTOR_35, /*!< 1 146 880 kHz */ +} t_switcher_factor; + +/*! + * @enum t_pmic_regulator_voltage_violo + * @brief PMIC regulator VIOLO output voltage. + */ +typedef enum { + VIOLO_1_2V = 0, /*!< 1.2 V */ + VIOLO_1_3V, /*!< 1.3 V */ + VIOLO_1_5V, /*!< 1.5 V */ + VIOLO_1_8V, /*!< 1.8 V */ +} t_pmic_regulator_voltage_violo; + +/*! + * @enum t_pmic_regulator_voltage_vdig + * @brief PMIC regulator VDIG output voltage. + */ +typedef enum { + VDIG_1_2V = 0, /*!< 1.2 V */ + VDIG_1_3V, /*!< 1.3 V */ + VDIG_1_5V, /*!< 1.5 V */ + VDIG_1_8V, /*!< 1.8 V */ +} t_pmic_regulator_voltage_vdig; + +/*! + * @enum t_pmic_regulator_voltage_vgen + * @brief PMIC regulator VGEN output voltage. + */ +typedef enum { + VGEN_1_2V = 0, /*!< 1.2 V */ + VENG_1_3V, /*!< 1.3 V */ + VGEN_1_5V, /*!< 1.5 V */ + VGEN_1_8V, /*!< 1.8 V */ + VGEN_1_1V, /*!< 1.1 V */ + VGEN_2V, /*!< 2 V */ + VGEN_2_775V, /*!< 2.775 V */ + VGEN_2_4V, /*!< 2.4 V */ +} t_pmic_regulator_voltage_vgen; + +/*! + * @enum t_pmic_regulator_voltage_vrfdig + * @brief PMIC regulator VRFDIG output voltage. + */ +typedef enum { + VRFDIG_1_2V = 0, /*!< 1.2 V */ + VRFDIG_1_5V, /*!< 1.5 V */ + VRFDIG_1_8V, /*!< 1.8 V */ + VRFDIG_1_875V, /*!< 1.875 V */ +} t_pmic_regulator_voltage_vrfdig; + +/*! + * @enum t_pmic_regulator_voltage_vrfref + * @brief PMIC regulator VRFREF output voltage. + */ +typedef enum { + VRFREF_2_475V = 0, /*!< 2.475 V */ + VRFREF_2_6V, /*!< 2.600 V */ + VRFREF_2_7V, /*!< 2.700 V */ + VRFREF_2_775V, /*!< 2.775 V */ +} t_pmic_regulator_voltage_vrfref; + +/*! + * @enum t_pmic_regulator_voltage_vrfcp + * @brief PMIC regulator VRFCP output voltage. + */ +typedef enum { + VRFCP_2_7V = 0, /*!< 2.700 V */ + VRFCP_2_775V, /*!< 2.775 V */ +} t_pmic_regulator_voltage_vrfcp; + +/*! + * @enum t_pmic_regulator_voltage_vsim + * @brief PMIC linear regulator VSIM output voltage. + */ +typedef enum { + VSIM_1_8V = 0, /*!< 1.8 V */ + VSIM_2_9V, /*!< 2.90 V */ + VSIM_3V = 1, /*!< 3 V */ +} t_pmic_regulator_voltage_vsim; + +/*! + * @enum t_pmic_regulator_voltage_vesim + * @brief PMIC regulator VESIM output voltage. + */ +typedef enum { + VESIM_1_8V = 0, /*!< 1.80 V */ + VESIM_2_9V, /*!< 2.90 V */ +} t_pmic_regulator_voltage_vesim; + +/*! + * @enum t_pmic_regulator_voltage_vcam + * @brief PMIC regulator VCAM output voltage. + */ +typedef enum { + VCAM_1_5V = 0, /*!< 1.50 V */ + VCAM_1_8V, /*!< 1.80 V */ + VCAM_2_5V, /*!< 2.50 V */ + VCAM_2_55V, /*!< 2.55 V */ + VCAM_2_6V, /*!< 2.60 V */ + VCAM_2_75V, /*!< 2.75 V */ + VCAM_2_8V, /*!< 2.80 V */ + VCAM_3V, /*!< 3.00 V */ +} t_pmic_regulator_voltage_vcam; + +/*! + * @enum t_pmic_regulator_voltage_vvib + * @brief PMIC linear regulator V_VIB output voltage. + */ +typedef enum { + VVIB_1_3V = 0, /*!< 1.30 V */ + VVIB_1_8V, /*!< 1.80 V */ + VVIB_2V, /*!< 2 V */ + VVIB_3V, /*!< 3 V */ +} t_pmic_regulator_voltage_vvib; + +/*! + * @enum t_pmic_regulator_voltage_vrf1 + * @brief PMIC regulator VRF1 output voltage. + */ +typedef enum { + VRF1_1_5V = 0, /*!< 1.500 V */ + VRF1_1_875V, /*!< 1.875 V */ + VRF1_2_7V, /*!< 2.700 V */ + VRF1_2_775V, /*!< 2.775 V */ +} t_pmic_regulator_voltage_vrf1; + +/*! + * @enum t_pmic_regulator_voltage_vrf2 + * @brief PMIC regulator VRF2 output voltage. + */ +typedef enum { + VRF2_1_5V = 0, /*!< 1.500 V */ + VRF2_1_875V, /*!< 1.875 V */ + VRF2_2_7V, /*!< 2.700 V */ + VRF2_2_775V, /*!< 2.775 V */ +} t_pmic_regulator_voltage_vrf2; + +/*! + * @enum t_pmic_regulator_voltage_vmmc + * @brief PMIC linear regulator VMMC output voltage. + */ +typedef enum { + VMMC_OFF = 0, /*!< Output off */ + VMMC_1_6V, /*!< 1.6 V */ + VMMC_1_8V, /*!< 1.8 V */ + VMMC_2V, /*!< 2 V */ + VMMC_2_2V, /*!< 2.2 V */ + VMMC_2_4V, /*!< 2.4 V */ + VMMC_2_6V, /*!< 2.6 V */ + VMMC_2_8V, /*!< 2.8 V */ + VMMC_3V, /*!< 3 V */ + VMMC_3_2V, /*!< 3.2 V */ + VMMC_3_3V, /*!< 3.3 V */ + VMMC_3_4V, /*!< 3.4 V */ +} t_pmic_regulator_voltage_vmmc; + +/*! + * @enum t_pmic_regulator_voltage_vmmc1 + * @brief PMIC regulator VMMC1 output voltage. + */ +typedef enum { + VMMC1_1_6V = 0, /*!< 1.60 V */ + VMMC1_1_8V, /*!< 1.80 V */ + VMMC1_2V, /*!< 2.00 V */ + VMMC1_2_6V, /*!< 2.60 V */ + VMMC1_2_7V, /*!< 2.70 V */ + VMMC1_2_8V, /*!< 2.80 V */ + VMMC1_2_9V, /*!< 2.90 V */ + VMMC1_3V, /*!< 3.00 V */ +} t_pmic_regulator_voltage_vmmc1; + +/*! + * @enum t_pmic_regulator_voltage_vmmc2 + * @brief PMIC regulator VMMC2 output voltage. + */ +typedef enum { + VMMC2_1_6V = 0, /*!< 1.60 V */ + VMMC2_1_8V, /*!< 1.80 V */ + VMMC2_2V, /*!< 2.00 V */ + VMMC2_2_6V, /*!< 2.60 V */ + VMMC2_2_7V, /*!< 2.70 V */ + VMMC2_2_8V, /*!< 2.80 V */ + VMMC2_2_9V, /*!< 2.90 V */ + VMMC2_3V, /*!< 3.00 V */ +} t_pmic_regulator_voltage_vmmc2; + +/*! + * @enum t_pmic_regulator_voltage_v1 + * @brief PMIC linear regulator V1 output voltages. + */ +typedef enum { + V1_2_775V = 0, /*!< 2.775 V */ + V1_1_2V, /*!< 1.2 V */ + V1_1_3V, /*!< 1.3 V */ + V1_1_4V, /*!< 1.4 V */ + V1_1_55V, /*!< 1.55 V */ + V1_1_75V, /*!< 1.75 V */ + V1_1_875V, /*!< 1.875 V */ + V1_2_475V, /*!< 2.475 V */ +} t_pmic_regulator_voltage_v1; + +/*! + * @enum t_pmic_regulator_voltage_v2 + * @brief PMIC linear regulator V2 output voltage, V2 has fixed + * output voltage 2.775 volts. + */ +typedef enum { + V2_2_775V = 0, /*!< 2.775 V */ +} t_pmic_regulator_voltage_v2; + +/*! + * @enum t_pmic_regulator_voltage_v3 + * @brief PMIC linear regulator V3 output voltage. + */ +typedef enum { + V3_1_875V = 0, /*!< 1.875 V */ + V3_2_775V, /*!< 2.775 V */ +} t_pmic_regulator_voltage_v3; + +/*! + * @enum t_pmic_regulator_voltage_v4 + * @brief PMIC linear regulator V4 output voltage, V4 has fixed + * output voltage 2.775 volts. + */ +typedef enum { + V4_2_775V = 0, /*!< 2.775 V */ +} t_pmic_regulator_voltage_v4; + +/*! + * @union t_regulator_voltage + * @brief PMIC regulator output voltages. + */ +typedef union { + t_pmic_regulator_voltage_sw1 sw1; /*!< SW1 voltage */ + t_pmic_regulator_voltage_sw1a sw1a; /*!< SW1A voltage */ + t_pmic_regulator_voltage_sw1b sw1b; /*!< SW1B voltage */ + t_pmic_regulator_voltage_sw2 sw2; /*!< SW2 voltage */ + t_pmic_regulator_voltage_sw2a sw2a; /*!< SW2A voltage */ + t_pmic_regulator_voltage_sw2b sw2b; /*!< SW2B voltage */ + t_pmic_regulator_voltage_sw3 sw3; /*!< SW3 voltage */ + t_pmic_regulator_voltage_violo violo; /*!< VIOLO voltage */ + t_pmic_regulator_voltage_vdig vdig; /*!< VDIG voltage */ + t_pmic_regulator_voltage_vgen vgen; /*!< VGEN voltage */ + t_pmic_regulator_voltage_vrfdig vrfdig; /*!< VRFDIG voltage */ + t_pmic_regulator_voltage_vrfref vrfref; /*!< VRFREF voltage */ + t_pmic_regulator_voltage_vrfcp vrfcp; /*!< VRFCP voltage */ + t_pmic_regulator_voltage_vsim vsim; /*!< VSIM voltage */ + t_pmic_regulator_voltage_vesim vesim; /*!< VESIM voltage */ + t_pmic_regulator_voltage_vcam vcam; /*!< VCAM voltage */ + t_pmic_regulator_voltage_vvib vvib; /*!< VVIB voltage */ + t_pmic_regulator_voltage_vrf1 vrf1; /*!< VRF1 voltage */ + t_pmic_regulator_voltage_vrf2 vrf2; /*!< VRF2 voltage */ + t_pmic_regulator_voltage_vmmc vmmc; /*!< VMMC voltage */ + t_pmic_regulator_voltage_vmmc1 vmmc1; /*!< VMMC1 voltage */ + t_pmic_regulator_voltage_vmmc2 vmmc2; /*!< VMMC2 voltage */ + t_pmic_regulator_voltage_v1 v1; /*!< V1 voltage */ + t_pmic_regulator_voltage_v2 v2; /*!< V2 voltage */ + t_pmic_regulator_voltage_v3 v3; /*!< V3 voltage */ + t_pmic_regulator_voltage_v4 v4; /*!< V4 voltage */ +} t_regulator_voltage; + +/*! + * @enum t_pmic_regulator_sw_mode + * @brief define switch mode regulator mode. + * + * The synchronous rectifier can be disabled (and pulse-skipping enabled) + * to improve low current efficiency. Software should disable synchronous + * rectifier / enable the pulse skipping for average loads less than + * approximately 30 mA, depending on the quiescent current penalty due to + * synchronous mode. + */ +typedef enum { + SYNC_RECT = 0, + NO_PULSE_SKIP, + PULSE_SKIP, + LOW_POWER, +} t_pmic_regulator_sw_mode; + +/*! + * Generic PMIC switch mode regulator mode. + */ +typedef t_pmic_regulator_sw_mode t_regulator_sw_mode; +typedef t_pmic_regulator_sw_mode t_regulator_stby_mode; + +/*! + * @enum t_regulator_lp_mode + * @brief Low power mode control modes. + */ + +typedef enum { + /*! + * Low Power Mode is disabled + */ + LOW_POWER_DISABLED = 0, + /*! + * Low Power Mode is controlled by STANDBY pin and/or LVS pin + */ + LOW_POWER_CTRL_BY_PIN, + /*! + * Set Low Power mode no matter of hardware pins + */ + LOW_POWER_EN, + /*! + * Set Low Power mode and control by STANDBY + */ + LOW_POWER_AND_LOW_POWER_CTRL_BY_PIN, +} t_regulator_lp_mode; + +/*! + * @enum t_switcher_dvs_speed + * @brief DVS speed setting + */ +typedef enum { + /*! + * Transition speed is dictated by the current + * limit and input -output conditions + */ + DICTATED = 0, + /*! + * 25mV step each 4us + */ + DVS_4US, + /*! + * 25mV step each 8us + */ + DVS_8US, + /*! + * 25mV step each 16us + */ + DVS_16US, +} t_switcher_dvs_speed; + +/*! + * @struct t_regulator_config + * @brief regulator configuration. + * + */ + +typedef struct { + /*! + * Switch mode regulator operation mode. This field only applies to + * switch mode regulators. + */ + t_regulator_sw_mode mode; + /*! + * Switch mode stby regulator operation mode. This field only applies + * to switch mode regulators. + */ + t_regulator_stby_mode stby_mode; + /*! + * Regulator output voltage. + */ + t_regulator_voltage voltage; + /*! + * Regulator output voltage in LVS mode. + */ + t_regulator_voltage voltage_lvs; + /*! + * Regulator output voltage in standby mode. + */ + t_regulator_voltage voltage_stby; + /*! + * Regulator low power mode. + */ + t_regulator_lp_mode lp_mode; + /*! + * Switcher dvs speed + */ + t_switcher_dvs_speed dvs_speed; + /*! + * Switcher panic mode + */ + bool panic_mode; + /*! + * Switcher softstart + */ + bool softstart; + /*! + * PLL Multiplication factor + */ + t_switcher_factor factor; +} t_regulator_config; + +/*! + * @struct t_regulator_cfg_param + * @brief regulator configuration structure for IOCTL. + * + */ +typedef struct { + /*! + * Regulator. + */ + t_pmic_regulator regulator; + /*! + * Regulator configuration. + */ + t_regulator_config cfg; +} t_regulator_cfg_param; + +/*! + * This struct list all state reads in Power Up Sense + */ +struct t_p_up_sense { + /*! + * power up sense ictest + */ + bool state_ictest; + /*! + * power up sense clksel + */ + bool state_clksel; + /*! + * power up mode supply 1 + */ + bool state_pums1; + /*! + * power up mode supply 2 + */ + bool state_pums2; + /*! + * power up mode supply 3 + */ + bool state_pums3; + /*! + * power up sense charge mode 0 + */ + bool state_chrgmode0; + /*! + * power up sense charge mode 1 + */ + bool state_chrgmode1; + /*! + * power up sense USB mode + */ + bool state_umod; + /*! + * power up sense boot mode enable for USB/RS232 + */ + bool state_usben; + /*! + * power up sense switcher 1a1b joined + */ + bool state_sw_1a1b_joined; + /*! + * power up sense switcher 1a1b joined + */ + bool state_sw_2a2b_joined; +}; + +/*! + * This enumeration define all On_OFF button + */ +typedef enum { + /*! + * ON1B + */ + BT_ON1B = 0, + /*! + * ON2B + */ + BT_ON2B, + /*! + * ON3B + */ + BT_ON3B, +} t_button; + +#ifdef __KERNEL__ +/* EXPORTED FUNCTIONS */ + +/*! + * This function sets user power off in power control register and thus powers + * off the phone. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +void pmic_power_off(void); + +/*! + * This function sets the power control configuration. + * + * @param pc_config power control configuration. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_set_pc_config(t_pc_config * pc_config); + +/*! + * This function retrives the power control configuration. + * + * @param pc_config pointer to power control configuration. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_get_pc_config(t_pc_config * pc_config); + +/*! + * This function turns on a regulator. + * + * @param regulator The regulator to be turned on. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_on(t_pmic_regulator regulator); + +/*! + * This function turns off a regulator. + * + * @param regulator The regulator to be turned off. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_off(t_pmic_regulator regulator); + +/*! + * This function sets the regulator output voltage. + * + * @param regulator The regulator to be turned off. + * @param voltage The regulator output voltage. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_set_voltage(t_pmic_regulator regulator, + t_regulator_voltage voltage); + +/*! + * This function retrieves the regulator output voltage. + * + * @param regulator The regulator to be turned off. + * @param voltage Pointer to regulator output voltage. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_get_voltage(t_pmic_regulator regulator, + t_regulator_voltage * voltage); + +/*! + * This function sets the DVS voltage + * + * @param regulator The regulator to be configured. + * @param dvs The switch Dynamic Voltage Scaling + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_dvs(t_pmic_regulator regulator, + t_regulator_voltage dvs); + +/*! + * This function gets the DVS voltage + * + * @param regulator The regulator to be handled. + * @param dvs The switch Dynamic Voltage Scaling + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_dvs(t_pmic_regulator regulator, + t_regulator_voltage * dvs); + +/*! + * This function sets the standby voltage + * + * @param regulator The regulator to be configured. + * @param stby The switch standby voltage + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_stby(t_pmic_regulator regulator, + t_regulator_voltage stby); + +/*! + * This function gets the standby voltage + * + * @param regulator The regulator to be handled. + * @param stby The switch standby voltage + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_stby(t_pmic_regulator regulator, + t_regulator_voltage * stby); + +/*! + * This function sets the switchers mode. + * + * @param regulator The regulator to be configured. + * @param mode The switcher mode + * @param stby Switch between main and standby. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_mode(t_pmic_regulator regulator, + t_regulator_sw_mode mode, bool stby); + +/*! + * This function gets the switchers mode. + * + * @param regulator The regulator to be handled. + * @param mode The switcher mode. + * @param stby Switch between main and standby. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_mode(t_pmic_regulator regulator, + t_regulator_sw_mode * mode, bool stby); + +/*! + * This function sets the switch dvs speed + * + * @param regulator The regulator to be configured. + * @param speed The dvs speed. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_dvs_speed(t_pmic_regulator regulator, + t_switcher_dvs_speed speed); + +/*! + * This function gets the switch dvs speed + * + * @param regulator The regulator to be handled. + * @param speed The dvs speed. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_dvs_speed(t_pmic_regulator regulator, + t_switcher_dvs_speed * speed); + +/*! + * This function sets the switch panic mode + * + * @param regulator The regulator to be configured. + * @param panic_mode Enable or disable panic mode + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_panic_mode(t_pmic_regulator regulator, + bool panic_mode); + +/*! + * This function gets the switch panic mode + * + * @param regulator The regulator to be handled + * @param panic_mode Enable or disable panic mode + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_panic_mode(t_pmic_regulator regulator, + bool * panic_mode); + +/*! + * This function sets the switch softstart mode + * + * @param regulator The regulator to be configured. + * @param softstart Enable or disable softstart. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_softstart(t_pmic_regulator regulator, + bool softstart); + +/*! + * This function gets the switch softstart mode + * + * @param regulator The regulator to be handled + * @param softstart Enable or disable softstart. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_softstart(t_pmic_regulator regulator, + bool * softstart); + +/*! + * This function sets the PLL multiplication factor + * + * @param regulator The regulator to be configured. + * @param factor The multiplication factor. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_set_factor(t_pmic_regulator regulator, + t_switcher_factor factor); + +/*! + * This function gets the PLL multiplication factor + * + * @param regulator The regulator to be handled + * @param factor The multiplication factor. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_switcher_get_factor(t_pmic_regulator regulator, + t_switcher_factor * factor); + +/*! + * This function enables or disables low power mode. + * + * @param regulator The regulator to be configured. + * @param mode Select nominal or low power mode. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_set_lp_mode(t_pmic_regulator regulator, + t_regulator_lp_mode lp_mode); + +/*! + * This function gets low power mode. + * + * @param regulator The regulator to be handled + * @param mode Select nominal or low power mode. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_get_lp_mode(t_pmic_regulator regulator, + t_regulator_lp_mode * lp_mode); + +/*! + * This function sets the regulator configuration. + * + * @param regulator The regulator to be turned off. + * @param config The regulator output configuration. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_set_config(t_pmic_regulator regulator, + t_regulator_config * config); + +/*! + * This function retrieves the regulator output configuration. + * + * @param regulator The regulator to be turned off. + * @param config Pointer to regulator configuration. + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_regulator_get_config(t_pmic_regulator regulator, + t_regulator_config * config); + +/*! + * This function enables automatically VBKUP2 in the memory hold modes. + * + * @param en if true, enable VBKUP2AUTOMH + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_vbkup2_auto_en(bool en); + +/*! + * This function gets state of automatically VBKUP2. + * + * @param en if true, VBKUP2AUTOMH is enabled + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_get_vbkup2_auto_state(bool * en); + +/*! + * This function enables battery detect function. + * + * @param en if true, enable BATTDETEN + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_bat_det_en(bool en); + +/*! + * This function gets state of battery detect function. + * + * @param en if true, BATTDETEN is enabled + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_get_bat_det_state(bool * en); + +/*! + * This function enables control of VVIB by VIBEN pin. + * + * @param en if true, enable VIBPINCTRL + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_vib_pin_en(bool en); + +/*! + * This function gets state of control of VVIB by VIBEN pin. + * @param en if true, VIBPINCTRL is enabled + * + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_gets_vib_pin_state(bool * en); + +/*! + * This function returns power up sense value + * + * @param p_up_sense value of power up sense + * @return This function returns PMIC_SUCCESS if successful. + */ +PMIC_STATUS pmic_power_get_power_mode_sense(struct t_p_up_sense *p_up_sense); + +/*! + * This function configures the Regen assignment for all regulator + * + * @param regulator type of regulator + * @param en_dis if true, the regulator is enabled by regen. + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_set_regen_assig(t_pmic_regulator regulator, bool en_dis); + +/*! + * This function gets the Regen assignment for all regulator + * + * @param regulator type of regulator + * @param en_dis return value, if true : + * the regulator is enabled by regen. + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_get_regen_assig(t_pmic_regulator regu, bool * en_dis); + +/*! + * This function sets the Regen polarity. + * + * @param en_dis If true regen is inverted. + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_set_regen_inv(bool en_dis); + +/*! + * This function gets the Regen polarity. + * + * @param en_dis If true regen is inverted. + * + * @return This function returns 0 if successful. + */ + +PMIC_STATUS pmic_power_get_regen_inv(bool * en_dis); + +/*! + * This function enables esim control voltage. + * + * @param vesim if true, enable VESIMESIMEN + * @param vmmc1 if true, enable VMMC1ESIMEN + * @param vmmc2 if true, enable VMMC2ESIMEN + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_esim_v_en(bool vesim, bool vmmc1, bool vmmc2); + +/*! + * This function gets esim control voltage values. + * + * @param vesim if true, enable VESIMESIMEN + * @param vmmc1 if true, enable VMMC1ESIMEN + * @param vmmc2 if true, enable VMMC2ESIMEN + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_gets_esim_v_state(bool * vesim, + bool * vmmc1, bool * vmmc2); + +/*! + * This function enables auto reset after a system reset. + * + * @param en if true, the auto reset is enabled + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_set_auto_reset_en(bool en); + +/*! + * This function gets auto reset configuration. + * + * @param en if true, the auto reset is enabled + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_get_auto_reset_en(bool * en); + +/*! + * This function configures a system reset on a button. + * + * @param bt type of button. + * @param sys_rst if true, enable the system reset on this button + * @param deb_time sets the debounce time on this button pin + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_set_conf_button(t_button bt, bool sys_rst, int deb_time); + +/*! + * This function gets configuration of a button. + * + * @param bt type of button. + * @param sys_rst if true, the system reset is enabled on this button + * @param deb_time gets the debounce time on this button pin + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_get_conf_button(t_button bt, + bool * sys_rst, int *deb_time); + +/*! + * This function is used to subscribe on power event IT. + * + * @param event type of event. + * @param callback event callback function. + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_event_sub(t_pwr_int event, void *callback); + +/*! + * This function is used to un subscribe on power event IT. + * + * @param event type of event. + * @param callback event callback function. + * + * @return This function returns 0 if successful. + */ +PMIC_STATUS pmic_power_event_unsub(t_pwr_int event, void *callback); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_PMIC_POWER_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/sdma.h b/arch/arm/plat-mxc/include/mach/sdma.h new file mode 100644 index 000000000000..d864b0680fbd --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/sdma.h @@ -0,0 +1,561 @@ + +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_SDMA_H__ +#define __ASM_ARCH_MXC_SDMA_H__ + +/*! + * @defgroup SDMA Smart Direct Memory Access (SDMA) Driver + */ + +/*! + * @file arch-mxc/sdma.h + * + * @brief This file contains the SDMA API declarations. + * + * SDMA is responsible on moving data between peripherals and memories (MCU, EMI and DSP). + * + * @ingroup SDMA + */ + +#include +#include +#include + +#include +#include + +/*! + * This defines maximum DMA address + */ +#define MAX_DMA_ADDRESS 0xffffffff + +/*! + * This defines maximum number of DMA channels + */ +#ifdef CONFIG_MXC_SDMA_API +#define MAX_DMA_CHANNELS 32 +#define MAX_BD_NUMBER 16 +#define MXC_SDMA_DEFAULT_PRIORITY 1 +#define MXC_SDMA_MIN_PRIORITY 1 +#define MXC_SDMA_MAX_PRIORITY 7 +#else +#define MAX_DMA_CHANNELS 0 +#endif + +#define MXC_FIFO_MEM_DEST_FIXED 0x1 +#define MXC_FIFO_MEM_SRC_FIXED 0x2 + +#define SDMA_ASRC_INFO_WML_OFF 0 +#define SDMA_ASRC_INFO_WML_MASK ((1 << 10) - 1) +#define SDMA_ASRC_INFO_PS (1 << 10) +#define SDMA_ASRC_INFO_PA (1 << 11) +#define SDMA_ASRC_INFO_TXFR_DIR (1 << 14) +#define SDMA_ASRC_INFO_N_OFF (24) +#define SDMA_ASRC_INFO_N_MASK ((1 << 4) - 1) + +#define SDMA_ASRC_P2P_INFO_LWML_OFF 0 +#define SDMA_ASRC_P2P_INFO_LWML_MASK ((1 << 8) - 1) +#define SDMA_ASRC_P2P_INFO_PS (1 << 8) +#define SDMA_ASRC_P2P_INFO_PA (1 << 9) +#define SDMA_ASRC_P2P_INFO_SPDIF (1 << 10) +#define SDMA_ASRC_P2P_INFO_SP (1 << 11) +#define SDMA_ASRC_P2P_INFO_DP (1 << 12) +#define SDMA_ASRC_P2P_INFO_HWML_OFF 14 +#define SDMA_ASRC_P2P_INFO_HWML_MASK ((1 << 10) - 1) +#define SDMA_ASRC_P2P_INFO_LWE (1 << 28) +#define SDMA_ASRC_P2P_INFO_HWE (1 << 29) +#define SDMA_ASRC_P2P_INFO_CONT (1 << 31) + +/*! + * This enumerates transfer types + */ +typedef enum { + emi_2_per = 0, /*!< EMI memory to peripheral */ + emi_2_int, /*!< EMI memory to internal RAM */ + emi_2_emi, /*!< EMI memory to EMI memory */ + emi_2_dsp, /*!< EMI memory to DSP memory */ + per_2_int, /*!< Peripheral to internal RAM */ + per_2_emi, /*!< Peripheral to internal EMI memory */ + per_2_dsp, /*!< Peripheral to DSP memory */ + per_2_per, /*!< Peripheral to Peripheral */ + int_2_per, /*!< Internal RAM to peripheral */ + int_2_int, /*!< Internal RAM to Internal RAM */ + int_2_emi, /*!< Internal RAM to EMI memory */ + int_2_dsp, /*!< Internal RAM to DSP memory */ + dsp_2_per, /*!< DSP memory to peripheral */ + dsp_2_int, /*!< DSP memory to internal RAM */ + dsp_2_emi, /*!< DSP memory to EMI memory */ + dsp_2_dsp, /*!< DSP memory to DSP memory */ + emi_2_dsp_loop, /*!< EMI memory to DSP memory loopback */ + dsp_2_emi_loop, /*!< DSP memory to EMI memory loopback */ + dvfs_pll, /*!< DVFS script with PLL change */ + dvfs_pdr /*!< DVFS script without PLL change */ +} sdma_transferT; + +/*! + * This enumerates peripheral types + */ +typedef enum { + SSI, /*!< MCU domain SSI */ + SSI_SP, /*!< Shared SSI */ + MMC, /*!< MMC */ + SDHC, /*!< SDHC */ + UART, /*!< MCU domain UART */ + UART_SP, /*!< Shared UART */ + FIRI, /*!< FIRI */ + CSPI, /*!< MCU domain CSPI */ + CSPI_SP, /*!< Shared CSPI */ + SIM, /*!< SIM */ + ATA, /*!< ATA */ + CCM, /*!< CCM */ + EXT, /*!< External peripheral */ + MSHC, /*!< Memory Stick Host Controller */ + MSHC_SP, /*!< Shared Memory Stick Host Controller */ + DSP, /*!< DSP */ + MEMORY, /*!< Memory */ + FIFO_MEMORY, /*!< FIFO type Memory */ + SPDIF, /*!< SPDIF */ + IPU_MEMORY, /*!< IPU Memory */ + ASRC, /*!< ASRC */ + ESAI, /*!< ESAI */ +} sdma_periphT; + +#ifndef TRANSFER_32BIT +/*! + * This defines SDMA access data size + */ +#define TRANSFER_32BIT 0x00 +#define TRANSFER_8BIT 0x01 +#define TRANSFER_16BIT 0x02 +#define TRANSFER_24BIT 0x03 + +#endif + +/*! + * This defines maximum device name length passed during mxc_request_dma(). + */ +#define MAX_DEVNAME_LENGTH 32 + +/*! + * This defines SDMA interrupt callback function prototype. + */ +typedef void (*dma_callback_t) (void *arg); + +/*! + * Structure containing sdma channel parameters. + */ +typedef struct { + __u32 watermark_level; /*!< Lower/upper threshold that + * triggers SDMA event + * for p2p, this is event1 watermark level + */ + __u32 per_address; /*!< Peripheral source/destination + * physical address + * for p2p, this is destination address + */ + sdma_periphT peripheral_type; /*!< Peripheral type */ + sdma_transferT transfer_type; /*!< Transfer type */ + int event_id; /*!< Event number, + * needed by all channels + * that started by peripherals dma + * request (per_2_*,*_2_per) + * Not used for memory and DSP + * transfers. + */ + int event_id2; /*!< Second event number, + * used in ATA scripts only. + */ + int bd_number; /*!< Buffer descriptors number. + * If not set, single buffer + * descriptor will be used. + */ + dma_callback_t callback; /*! callback function */ + void *arg; /*! callback argument */ + unsigned long word_size:8; /*!< SDMA data access word size */ + unsigned long ext:1; /*!< 1: extend parameter structure */ +} dma_channel_params; + +typedef struct { + dma_channel_params common; + unsigned long p2p_dir:1; /*!< 0: per2 to per. + * the device of peripheral_type is per. + * 1: per to per2 + * the device of peripheral_type is per2 + */ + unsigned long info_bits; /*!< info field in context */ + unsigned long info_mask; /*!< info field mask in context */ + __u32 watermark_level2; /*!< event2 threshold that + * triggers SDMA event + * just valid for p2p. + */ + __u32 per_address2; /*!< Peripheral source + * physical address. + * just valid for p2p. + */ + struct dma_channel_info info; /*!< the channel special parameter */ +} dma_channel_ext_params; + +/*! + * Structure containing sdma request parameters. + */ +typedef struct { + /*! physical source memory address */ + __u8 *sourceAddr; + /*! physical destination memory address */ + __u8 *destAddr; + /*! amount of data to transfer, + * updated during mxc_dma_get_config + */ + __u16 count; + /*!< DONE bit of the buffer descriptor, + * updated during mxc_dma_get_config + * 0 - means the BD is done and closed by SDMA + * 1 - means the BD is still being processed by SDMA + */ + int bd_done; + /*!< CONT bit of the buffer descriptor, + * set it if full multi-buffer descriptor mechanism + * required. + */ + int bd_cont; + /*!< ERROR bit of the buffer descriptor, + * updated during mxc_dma_get_config. + * If it is set - there was an error during BD processing. + */ + int bd_error; +} dma_request_t; + +/*! + * Structure containing sdma request parameters. + */ +typedef struct { + /*! address of ap_2_ap script */ + int mxc_sdma_ap_2_ap_addr; + /*! address of ap_2_bp script */ + int mxc_sdma_ap_2_bp_addr; + /*! address of ap_2_ap_fixed script */ + int mxc_sdma_ap_2_ap_fixed_addr; + /*! address of bp_2_ap script */ + int mxc_sdma_bp_2_ap_addr; + /*! address of loopback_on_dsp_side script */ + int mxc_sdma_loopback_on_dsp_side_addr; + /*! address of mcu_interrupt_only script */ + int mxc_sdma_mcu_interrupt_only_addr; + + /*! address of firi_2_per script */ + int mxc_sdma_firi_2_per_addr; + /*! address of firi_2_mcu script */ + int mxc_sdma_firi_2_mcu_addr; + /*! address of per_2_firi script */ + int mxc_sdma_per_2_firi_addr; + /*! address of mcu_2_firi script */ + int mxc_sdma_mcu_2_firi_addr; + + /*! address of uart_2_per script */ + int mxc_sdma_uart_2_per_addr; + /*! address of uart_2_mcu script */ + int mxc_sdma_uart_2_mcu_addr; + /*! address of per_2_app script */ + int mxc_sdma_per_2_app_addr; + /*! address of mcu_2_app script */ + int mxc_sdma_mcu_2_app_addr; + /*! address of per_2_per script */ + int mxc_sdma_per_2_per_addr; + + /*! address of uartsh_2_per script */ + int mxc_sdma_uartsh_2_per_addr; + /*! address of uartsh_2_mcu script */ + int mxc_sdma_uartsh_2_mcu_addr; + /*! address of per_2_shp script */ + int mxc_sdma_per_2_shp_addr; + /*! address of mcu_2_shp script */ + int mxc_sdma_mcu_2_shp_addr; + + /*! address of ata_2_mcu script */ + int mxc_sdma_ata_2_mcu_addr; + /*! address of mcu_2_ata script */ + int mxc_sdma_mcu_2_ata_addr; + + /*! address of app_2_per script */ + int mxc_sdma_app_2_per_addr; + /*! address of app_2_mcu script */ + int mxc_sdma_app_2_mcu_addr; + /*! address of shp_2_per script */ + int mxc_sdma_shp_2_per_addr; + /*! address of shp_2_mcu script */ + int mxc_sdma_shp_2_mcu_addr; + + /*! address of mshc_2_mcu script */ + int mxc_sdma_mshc_2_mcu_addr; + /*! address of mcu_2_mshc script */ + int mxc_sdma_mcu_2_mshc_addr; + + /*! address of spdif_2_mcu script */ + int mxc_sdma_spdif_2_mcu_addr; + /*! address of mcu_2_spdif script */ + int mxc_sdma_mcu_2_spdif_addr; + + /*! address of asrc_2_mcu script */ + int mxc_sdma_asrc_2_mcu_addr; + + /*! address of ext_mem_2_ipu script */ + int mxc_sdma_ext_mem_2_ipu_addr; + + /*! address of descrambler script */ + int mxc_sdma_descrambler_addr; + + /*! address of dptc_dvfs script */ + int mxc_sdma_dptc_dvfs_addr; + + int mxc_sdma_utra_addr; + + /*! address where ram code starts */ + int mxc_sdma_ram_code_start_addr; + /*! size of the ram code */ + int mxc_sdma_ram_code_size; + /*! RAM image address */ + unsigned short *mxc_sdma_start_addr; +} sdma_script_start_addrs; + +/*! Structure to store the initialized dma_channel parameters */ +typedef struct mxc_sdma_channel_params { + /*! Channel type (static channel number or dynamic channel) */ + unsigned int channel_num; + /*! Channel priority [0x1(lowest) - 0x7(highest)] */ + unsigned int chnl_priority; + /*! Channel params */ + dma_channel_params chnl_params; +} mxc_sdma_channel_params_t; + +/*! Structure to store the initialized dma_channel extend parameters */ +typedef struct mxc_sdma_channel_ext_params { + /*! Channel type (static channel number or dynamic channel) */ + unsigned int channel_num; + /*! Channel priority [0x1(lowest) - 0x7(highest)] */ + unsigned int chnl_priority; + /*! Channel extend params */ + dma_channel_ext_params chnl_ext_params; +} mxc_sdma_channel_ext_params_t; + +/*! Private SDMA data structure */ +typedef struct mxc_dma_channel_private { + /*! ID of the buffer that was processed */ + unsigned int buf_tail; + /*! Tasklet for the channel */ + struct tasklet_struct chnl_tasklet; + /*! Flag indicates if interrupt is required after every BD transfer */ + int intr_after_every_bd; +} mxc_dma_channel_private_t; + +/*! + * Setup channel according to parameters. + * Must be called once after mxc_request_dma() + * + * @param channel channel number + * @param p channel parameters pointer + * @return 0 on success, error code on fail + */ +int mxc_dma_setup_channel(int channel, dma_channel_params * p); + +/*! + * Setup the channel priority. This can be used to change the default priority + * for the channel. + * + * @param channel channel number + * @param priority priority to be set for the channel + * + * @return 0 on success, error code on failure + */ +int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority); + +/*! + * Allocates dma channel. + * If channel's value is 0, then the function allocates a free channel + * dynamically and sets its value to channel. + * Else allocates requested channel if it is free. + * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned. + * + * @param channel pointer to channel number + * @param devicename device name + * @return 0 on success, error code on fail + */ +int mxc_request_dma(int *channel, const char *devicename); + +/*! + * Configures request parameters. Can be called multiple times after + * mxc_request_dma() and mxc_dma_setup_channel(). + * + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to set + * @return 0 on success, error code on fail + */ +/* int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index); */ +int mxc_dma_set_config(int channel, dma_request_t * p, int bd_index); + +/*! + * Returns request parameters. + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to get + * @return 0 on success, error code on fail + */ +/* int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index); */ +int mxc_dma_get_config(int channel, dma_request_t * p, int bd_index); + +/*! + * This function is used by MXC IPC's write_ex2. It passes the a pointer to the + * data control structure to iapi_write_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr); + +/*! + * This function is used by MXC IPC's read_ex2. It passes the a pointer to the + * data control structure to iapi_read_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr); + +/*! + * Starts dma channel. + * + * @param channel channel number + */ +int mxc_dma_start(int channel); + +/*! + * Stops dma channel. + * + * @param channel channel number + */ +int mxc_dma_stop(int channel); + +/*! + * Frees dma channel. + * + * @param channel channel number + */ +void mxc_free_dma(int channel); + +/*! + * Sets callback function. Used with standard dma api + * for supporting interrupts + * + * @param channel channel number + * @param callback callback function pointer + * @param arg argument for callback function + */ +void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg); + +/*! + * Allocates uncachable buffer. Uses hash table. + * + * @param size size of allocated buffer + * @return pointer to buffer + */ +void *sdma_malloc(size_t size); + +#ifdef CONFIG_SDMA_IRAM +/*! + * Allocates uncachable buffer from IRAM.. + * + * @param size size of allocated buffer + * @return pointer to buffer + */ +void *sdma_iram_malloc(size_t size); +#endif /*CONFIG_SDMA_IRAM */ + +/*! + * Frees uncachable buffer. Uses hash table. + */ +void sdma_free(void *buf); + +/*! + * Converts virtual to physical address. Uses hash table. + * + * @param buf virtual address pointer + * @return physical address value + */ +unsigned long sdma_virt_to_phys(void *buf); + +/*! + * Converts physical to virtual address. Uses hash table. + * + * @param buf physical address value + * @return virtual address pointer + */ +void *sdma_phys_to_virt(unsigned long buf); + +/*! + * Configures the BD_INTR bit on a buffer descriptor parameters. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * @param bd_intr flag to set or clear the BD_INTR bit + */ +void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr); + +/*! + * Gets the BD_INTR bit on a buffer descriptor. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * + * @return returns the BD_INTR bit status + */ +int mxc_dma_get_bd_intr(int channel, int bd_index); + +/*! + * Stop the current transfer + * + * @param channel channel number + * @param buffer_number number of buffers (beginning with 0), + * whose done bits should be reset to 0 + */ +int mxc_dma_reset(int channel, int buffer_number); + +/*! + * This functions Returns the SDMA paramaters associated for a module + * + * @param channel_id the ID of the module requesting DMA + * @return returns the sdma parameters structure for the device + */ +mxc_sdma_channel_params_t *mxc_sdma_get_channel_params(mxc_dma_device_t + channel_id); + +/*! + * This functions marks the SDMA channels that are statically allocated + * + * @param chnl the channel array used to store channel information + */ +void mxc_get_static_channels(mxc_dma_channel_t * chnl); + +/*! + * Initializes SDMA driver + */ +int __init sdma_init(void); + +#define DEFAULT_ERR 1 + +#endif diff --git a/arch/arm/plat-mxc/include/mach/spba.h b/arch/arm/plat-mxc/include/mach/spba.h new file mode 100644 index 000000000000..8d018be8a0b7 --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/spba.h @@ -0,0 +1,66 @@ + +/* + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup SPBA Shared Peripheral Bus Arbiter (SPBA) + * @ingroup MSL_MX31 MSL_MX35 MSL_MX37 MSL_MX51 MSL_MXC91321 + */ + +/*! + * @file arch-mxc/spba.h + * @brief This file contains the Shared Peripheral Bus Arbiter (spba) API. + * + * @ingroup SPBA + */ + +#ifndef __ASM_ARCH_MXC_SPBA_H__ +#define __ASM_ARCH_MXC_SPBA_H__ + +#ifdef __KERNEL__ + +#define MXC_SPBA_RAR_MASK 0x7 + +/*! + * Defines three SPBA masters: A - ARM, C - SDMA (no master B for MX31) + */ +enum spba_masters { + SPBA_MASTER_A = 1, + SPBA_MASTER_B = 2, + SPBA_MASTER_C = 4, +}; + +/*! + * This function allows the three masters (A, B, C) to take ownership of a + * shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; -1 otherwise. + */ +int spba_take_ownership(int mod, int master); + +/*! + * This function releases the ownership for a shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; -1 otherwise. + */ +int spba_rel_ownership(int mod, int master); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARCH_MXC_SPBA_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h index e56241af870e..126bc8713159 100644 --- a/arch/arm/plat-mxc/include/mach/system.h +++ b/arch/arm/plat-mxc/include/mach/system.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 ARM Limited * Copyright (C) 2000 Deep Blue Solutions Ltd - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. * * 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 @@ -21,10 +21,7 @@ #ifndef __ASM_ARCH_MXC_SYSTEM_H__ #define __ASM_ARCH_MXC_SYSTEM_H__ -static inline void arch_idle(void) -{ - cpu_do_idle(); -} +extern void arch_idle(void); void arch_reset(char mode, const char *cmd); diff --git a/arch/arm/plat-mxc/include/mach/timex.h b/arch/arm/plat-mxc/include/mach/timex.h index 07b4a73c9d2f..46ebeabf8bce 100644 --- a/arch/arm/plat-mxc/include/mach/timex.h +++ b/arch/arm/plat-mxc/include/mach/timex.h @@ -22,10 +22,14 @@ #if defined CONFIG_ARCH_MX1 #define CLOCK_TICK_RATE 16000000 -#elif defined CONFIG_ARCH_MX2 +#elif defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX25 #define CLOCK_TICK_RATE 13300000 -#elif defined CONFIG_ARCH_MX3 +#elif defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX35 #define CLOCK_TICK_RATE 16625000 +#elif defined CONFIG_ARCH_MX37 +#define CLOCK_TICK_RATE 8000000 +#elif defined CONFIG_ARCH_MX51 +#define CLOCK_TICK_RATE 8000000 #endif #endif /* __ASM_ARCH_MXC_TIMEX_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/uncompress.h b/arch/arm/plat-mxc/include/mach/uncompress.h index de6fe0365982..8314fafacfd5 100644 --- a/arch/arm/plat-mxc/include/mach/uncompress.h +++ b/arch/arm/plat-mxc/include/mach/uncompress.h @@ -27,6 +27,8 @@ #include +unsigned int system_rev; + #define UART(x) (*(volatile unsigned long *)(serial_port + (x))) #define USR2 0x98 diff --git a/arch/arm/plat-mxc/io.c b/arch/arm/plat-mxc/io.c new file mode 100644 index 000000000000..7681ecf8dfb6 --- /dev/null +++ b/arch/arm/plat-mxc/io.c @@ -0,0 +1,41 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * mxc custom ioremap implementation. + */ + +#include +#include +#include +#include + +void *__iomem __mxc_ioremap(unsigned long cookie, size_t size, + unsigned int mtype) +{ + if (mtype == MT_DEVICE && IS_MEM_DEVICE_NONSHARED(cookie)) { + mtype = MT_DEVICE_NONSHARED; + } + return __arm_ioremap(cookie, size, mtype); +} + +EXPORT_SYMBOL(__mxc_ioremap); + +void __mxc_iounmap(void __iomem * addr) +{ + extern void __iounmap(volatile void __iomem * addr); + + __iounmap(addr); +} + +EXPORT_SYMBOL(__mxc_iounmap); diff --git a/arch/arm/plat-mxc/irq.c b/arch/arm/plat-mxc/irq.c index 8aee76304f8f..c98e5b3c7edf 100644 --- a/arch/arm/plat-mxc/irq.c +++ b/arch/arm/plat-mxc/irq.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,11 @@ static void __iomem *avic_base; +#define IRQ_BIT(irq) (1 << (irq)) + +static uint32_t saved_wakeup_low, saved_wakeup_high; +static uint32_t suspend_wakeup_low, suspend_wakeup_high; + int imx_irq_set_priority(unsigned char irq, unsigned char prio) { #ifdef CONFIG_MXC_IRQ_PRIOR @@ -102,12 +108,121 @@ static void mxc_unmask_irq(unsigned int irq) __raw_writel(irq, avic_base + AVIC_INTENNUM); } +/*! + * Set interrupt number "irq" in the AVIC as a wake-up source. + * + * @param irq interrupt source number + * @param enable enable as wake-up if equal to non-zero + * disble as wake-up if equal to zero + * + * @return This function returns 0 on success. + */ +static int mxc_set_wake_irq(unsigned int irq, unsigned int enable) +{ + uint32_t *wakeup_intr; + uint32_t irq_bit; + + if (irq < 32) { + wakeup_intr = &suspend_wakeup_low; + irq_bit = IRQ_BIT(irq); + } else { + wakeup_intr = &suspend_wakeup_high; + irq_bit = IRQ_BIT(irq - 32); + } + + if (enable) { + *wakeup_intr |= irq_bit; + } else { + *wakeup_intr &= ~irq_bit; + } + + return 0; +} + static struct irq_chip mxc_avic_chip = { .ack = mxc_mask_irq, .mask = mxc_mask_irq, .unmask = mxc_unmask_irq, + .set_wake = mxc_set_wake_irq, +}; + +#ifdef CONFIG_PM +/*! + * This function puts the AVIC in low-power mode/state. + * All the interrupts that are enabled are first saved. + * Only those interrupts which registers as a wake source by calling + * enable_irq_wake are enabled. All other interrupts are disabled. + * + * @param dev the system device structure used to give information + * on AVIC to suspend + * @param mesg the power state the device is entering + * + * @return The function always returns 0. + */ +static int mxc_avic_suspend(struct sys_device *dev, pm_message_t mesg) +{ + saved_wakeup_high = __raw_readl(avic_base + AVIC_INTENABLEH); + saved_wakeup_low = __raw_readl(avic_base + AVIC_INTENABLEL); + + __raw_writel(suspend_wakeup_high, avic_base + AVIC_INTENABLEH); + __raw_writel(suspend_wakeup_low, avic_base + AVIC_INTENABLEL); + + return 0; +} + +/*! + * This function brings the AVIC back from low-power state. + * All the interrupts enabled before suspension are re-enabled from + * the saved information. + * + * @param dev the system device structure used to give information + * on AVIC to resume + * + * @return The function always returns 0. + */ +static int mxc_avic_resume(struct sys_device *dev) +{ + __raw_writel(saved_wakeup_high, avic_base + AVIC_INTENABLEH); + __raw_writel(saved_wakeup_low, avic_base + AVIC_INTENABLEL); + + return 0; +} + +#else +#define mxc_avic_suspend NULL +#define mxc_avic_resume NULL +#endif /* CONFIG_PM */ +/*! + * This structure contains pointers to the power management callback functions. + */ +static struct sysdev_class mxc_avic_sysclass = { + .name = "mxc_irq", + .suspend = mxc_avic_suspend, + .resume = mxc_avic_resume, +}; + +/*! + * This structure represents AVIC as a system device. + * System devices follow a slightly different driver model. + * They don't need to do dynammic driver binding, can't be probed, + * and don't reside on any type of peripheral bus. + * So, it is represented and treated a little differently. + */ +static struct sys_device mxc_avic_device = { + .id = 0, + .cls = &mxc_avic_sysclass, }; +/* + * This function is used to get the AVIC Lo and Hi interrupts + * that are enabled as wake up sources to wake up the core from suspend + */ +void mxc_get_wake_irq(u32 * wake_src[]) +{ + *wake_src[0] = __raw_readl(avic_base + AVIC_INTENABLEL); + *wake_src[1] = __raw_readl(avic_base + AVIC_INTENABLEH); +} + /* * This function initializes the AVIC hardware and disables all the * interrupts. It registers the interrupt enable and disable functions @@ -142,14 +257,39 @@ void __init mxc_init_irq(void) for (i = 0; i < 8; i++) __raw_writel(0, avic_base + AVIC_NIPRIORITY(i)); - /* init architectures chained interrupt handler */ - mxc_register_gpios(); #ifdef CONFIG_FIQ /* Initialize FIQ */ init_FIQ(); #endif + if (MXC_INT_FORCE >= 32) + __raw_writel(1 << (MXC_INT_FORCE & 31), avic_base + AVIC_INTFRCH); + else if (MXC_INT_FORCE >= 0) + __raw_writel(1 << MXC_INT_FORCE, avic_base + AVIC_INTFRCL); + printk(KERN_INFO "MXC IRQ initialized\n"); } +/*! + * This function registers AVIC hardware as a system device. + * System devices will only be suspended with interrupts disabled, and + * after all other devices have been suspended. On resume, they will be + * resumed before any other devices, and also with interrupts disabled. + * + * @return This function returns 0 on success. + */ +static int __init mxc_avic_sysinit(void) +{ + int ret = 0; + + ret = sysdev_class_register(&mxc_avic_sysclass); + if (ret == 0) { + ret = sysdev_register(&mxc_avic_device); + } + + return ret; +} + +arch_initcall(mxc_avic_sysinit); + diff --git a/arch/arm/plat-mxc/isp1301xc.c b/arch/arm/plat-mxc/isp1301xc.c new file mode 100644 index 000000000000..dceea44fd4da --- /dev/null +++ b/arch/arm/plat-mxc/isp1301xc.c @@ -0,0 +1,290 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * ISP1301 register addresses,all register of ISP1301 + * is one-byte length register + */ + +/* ISP1301: I2C device address */ +#define ISP1301_DEV_ADDR 0x2D + +/* ISP 1301 register set*/ +#define ISP1301_MODE_REG1_SET 0x04 +#define ISP1301_MODE_REG1_CLR 0x05 + +#define ISP1301_CTRL_REG1_SET 0x06 +#define ISP1301_CTRL_REG1_CLR 0x07 + +#define ISP1301_INT_SRC_REG 0x08 +#define ISP1301_INT_LAT_REG_SET 0x0a +#define ISP1301_INT_LAT_REG_CLR 0x0b +#define ISP1301_INT_FALSE_REG_SET 0x0c +#define ISP1301_INT_FALSE_REG_CLR 0x0d +#define ISP1301_INT_TRUE_REG_SET 0x0e +#define ISP1301_INT_TRUE_REG_CLR 0x0f + +#define ISP1301_CTRL_REG2_SET 0x10 +#define ISP1301_CTRL_REG2_CLR 0x11 + +#define ISP1301_MODE_REG2_SET 0x12 +#define ISP1301_MODE_REG2_CLR 0x13 + +#define ISP1301_BCD_DEV_REG0 0x14 +#define ISP1301_BCD_DEV_REG1 0x15 + +/* OTG Control register bit description */ +#define DP_PULLUP 0x01 +#define DM_PULLUP 0x02 +#define DP_PULLDOWN 0x04 +#define DM_PULLDOWN 0x08 +#define ID_PULLDOWN 0x10 +#define VBUS_DRV 0x20 +#define VBUS_DISCHRG 0x40 +#define VBUS_CHRG 0x80 + +/* Mode Control 1 register bit description */ +#define SPEED_REG 0x01 +#define SUSPEND_REG 0x02 +#define DAT_SE0 0x04 +#define TRANSP_EN 0x08 +#define BDIS_ACON_EN 0x10 +#define OE_INT_EN 0x20 +#define UART_EN 0x40 + +/* Mode Control 2 register bit description */ +#define SPD_SUSP_CTRL 0x02 +#define BI_DI 0x04 + +static int isp1301_attach(struct i2c_adapter *adapter); +static int isp1301_detach(struct i2c_client *client); + +static struct i2c_driver isp1301_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "isp1301 Client", + }, + .attach_adapter = isp1301_attach, + .detach_client = isp1301_detach, +}; + +static struct i2c_client isp1301_i2c_client = { + .name = "isp1301 I2C dev", + .addr = ISP1301_DEV_ADDR, + .driver = &isp1301_i2c_driver, +}; + +static unsigned short normal_i2c[] = { ISP1301_DEV_ADDR, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static int isp1301_detect_client(struct i2c_adapter *adapter, int address, + int kind) +{ + isp1301_i2c_client.adapter = adapter; + if (i2c_attach_client(&isp1301_i2c_client)) { + isp1301_i2c_client.adapter = NULL; + printk(KERN_ERR "isp1301_attach: i2c_attach_client failed\n"); + return -1; + } + + printk(KERN_INFO "isp1301 Detected\n"); + return 0; +} + +/*! + * isp1301 I2C attach function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int isp1301_attach(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, &isp1301_detect_client); +} + +/*! + * isp1301 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int isp1301_detach(struct i2c_client *client) +{ + int err; + + if (!isp1301_i2c_client.adapter) + return -1; + + err = i2c_detach_client(&isp1301_i2c_client); + isp1301_i2c_client.adapter = NULL; + + return err; +} + +static void isp1301_init(struct fsl_xcvr_ops *this) +{ + pr_debug("%s\n", __FUNCTION__); + + i2c_add_driver(&isp1301_i2c_driver); +} + +static void isp1301_uninit(struct fsl_xcvr_ops *this) +{ + // DDD do this for host only: + /* disable OTG VBUS */ + i2c_del_driver(&isp1301_i2c_driver); +} + +/* Write ISP1301 register*/ +static inline void isp1301_write_reg(char reg, char data) +{ + i2c_smbus_write_byte_data(&isp1301_i2c_client, reg, data); +} + +/* read ISP1301 register*/ +static inline char isp1301_read_reg(char reg) +{ + return i2c_smbus_read_byte_data(&isp1301_i2c_client, reg); +} + +/* set ISP1301 as USB host*/ +static inline void isp1301_set_serial_host(void) +{ + pr_debug("%s\n", __FUNCTION__); + + isp1301_write_reg(ISP1301_MODE_REG2_CLR, 0xFF); +#if defined(CONFIG_MXC_USB_SB3) || defined(CONFIG_MXC_USB_DB4) + isp1301_write_reg(ISP1301_MODE_REG2_SET, SPD_SUSP_CTRL | BI_DI); +#else + isp1301_write_reg(ISP1301_MODE_REG2_SET, SPD_SUSP_CTRL); +#endif + + isp1301_write_reg(ISP1301_MODE_REG1_CLR, 0xFF); +#if defined(CONFIG_MXC_USB_SB3) || defined(CONFIG_MXC_USB_SU6) + isp1301_write_reg(ISP1301_MODE_REG1_SET, DAT_SE0 | SPEED_REG); +#else + isp1301_write_reg(ISP1301_MODE_REG1_SET, SPEED_REG); +#endif + + /* configure transceiver for host mode */ + isp1301_write_reg(ISP1301_CTRL_REG1_SET, + (VBUS_DRV | DP_PULLDOWN | DM_PULLDOWN)); +} + +/* set ISP1301 as USB device */ +static inline void isp1301_set_serial_dev(void) +{ + pr_debug("%s\n", __FUNCTION__); + + isp1301_write_reg(ISP1301_MODE_REG2_CLR, 0xFF); +#if defined(CONFIG_MXC_USB_SB3) || defined(CONFIG_MXC_USB_DB4) + isp1301_write_reg(ISP1301_MODE_REG2_SET, SPD_SUSP_CTRL | BI_DI); +#else + isp1301_write_reg(ISP1301_MODE_REG2_SET, SPD_SUSP_CTRL); +#endif + + isp1301_write_reg(ISP1301_MODE_REG1_CLR, 0xFF); +#if defined(CONFIG_MXC_USB_SB3) || defined(CONFIG_MXC_USB_SU6) + isp1301_write_reg(ISP1301_MODE_REG1_SET, DAT_SE0 | SPEED_REG); +#else + isp1301_write_reg(ISP1301_MODE_REG1_SET, SPEED_REG); +#endif + + /* FS mode, DP pull down, DM pull down */ + isp1301_write_reg(ISP1301_CTRL_REG1_SET, + (DP_PULLDOWN | DM_PULLDOWN | DP_PULLUP)); +} + +static void isp1301_set_vbus_power(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, int on) +{ + pr_debug("%s(on=%d)\n", __FUNCTION__, on); + if (on) { + /* disable D+ pull-up */ + isp1301_write_reg(ISP1301_CTRL_REG1_CLR, DP_PULLUP); + /* enable D+ pull-down */ + isp1301_write_reg(ISP1301_CTRL_REG1_SET, DP_PULLDOWN); + /* turn on Vbus */ + isp1301_write_reg(ISP1301_CTRL_REG1_SET, VBUS_DRV); + } else { + /* D+ pull up, D- pull down */ + isp1301_write_reg(ISP1301_CTRL_REG1_SET, + (DP_PULLUP | DM_PULLDOWN)); + /* disable D- pull up, disable D+ pull down */ + isp1301_write_reg(ISP1301_CTRL_REG1_CLR, + (DM_PULLUP | DP_PULLDOWN)); + } +} + +/* + * Enable or disable the D+ pullup. + */ +static void isp1301_pullup(int on) +{ + pr_debug("%s(%d)\n", __func__, on); + + if (on) + isp1301_write_reg(ISP1301_CTRL_REG1_SET, DP_PULLUP); + else + isp1301_write_reg(ISP1301_CTRL_REG1_CLR, DP_PULLUP); +} + +static struct fsl_xcvr_ops isp1301_ops_otg = { + .name = "isp1301", + .xcvr_type = PORTSC_PTS_SERIAL, + .init = isp1301_init, + .uninit = isp1301_uninit, + .set_host = isp1301_set_serial_host, + .set_device = isp1301_set_serial_dev, + .set_vbus_power = isp1301_set_vbus_power, + .pullup = isp1301_pullup, +}; + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); + +static int __init isp1301xc_init(void) +{ + pr_debug("%s\n", __FUNCTION__); + + fsl_usb_xcvr_register(&isp1301_ops_otg); + + return 0; +} + +extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops); + +static void __exit isp1301xc_exit(void) +{ + fsl_usb_xcvr_unregister(&isp1301_ops_otg); +} + +module_init(isp1301xc_init); +module_exit(isp1301xc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("isp1301"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/isp1504xc.c b/arch/arm/plat-mxc/isp1504xc.c new file mode 100644 index 000000000000..e9a126454d53 --- /dev/null +++ b/arch/arm/plat-mxc/isp1504xc.c @@ -0,0 +1,279 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* ISP 1504 register addresses */ +#define ISP1504_VID_LOW 0x00 /* Vendor ID low */ +#define ISP1504_VID_HIGH 0x01 /* Vendor ID high */ +#define ISP1504_PID_LOW 0x02 /* Product ID low */ +#define ISP1504_PID_HIGH 0x03 /* Product ID high */ +#define ISP1504_FUNC 0x04 /* Function Control */ +#define ISP1504_ITFCTL 0x07 /* Interface Control */ +#define ISP1504_OTGCTL 0x0A /* OTG Control */ + +/* add to above register address to access Set/Clear functions */ +#define ISP1504_REG_SET 0x01 +#define ISP1504_REG_CLEAR 0x02 + +/* 1504 OTG Control Register bits */ +#define USE_EXT_VBUS_IND (1 << 7) /* Use ext. Vbus indicator */ +#define DRV_VBUS_EXT (1 << 6) /* Drive Vbus external */ +#define DRV_VBUS (1 << 5) /* Drive Vbus */ +#define CHRG_VBUS (1 << 4) /* Charge Vbus */ +#define DISCHRG_VBUS (1 << 3) /* Discharge Vbus */ +#define DM_PULL_DOWN (1 << 2) /* enable DM Pull Down */ +#define DP_PULL_DOWN (1 << 1) /* enable DP Pull Down */ +#define ID_PULL_UP (1 << 0) /* enable ID Pull Up */ + +/* 1504 OTG Function Control Register bits */ +#define SUSPENDM (1 << 6) /* places the PHY into + low-power mode */ +#define DRV_RESET (1 << 5) /* Active HIGH transceiver + reset */ + +/*! + * read ULPI register 'reg' thru VIEWPORT register 'view' + * + * @param reg register to read + * @param view the ULPI VIEWPORT register address + * @return return isp1504 register value + */ +static u8 isp1504_read(int reg, volatile u32 *view) +{ + u32 data; + + /* make sure interface is running */ + if (!(__raw_readl(view) && ULPIVW_SS)) { + __raw_writel(ULPIVW_WU, view); + do { /* wait for wakeup */ + data = __raw_readl(view); + } while (data & ULPIVW_WU); + } + + /* read the register */ + __raw_writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view); + + do { /* wait for completion */ + data = __raw_readl(view); + } while (data & ULPIVW_RUN); + + return (u8) (data >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK; +} + +/*! + * set bits into OTG ISP1504 register 'reg' thru VIEWPORT register 'view' + * + * @param bits set value + * @param reg which register + * @param view the ULPI VIEWPORT register address + */ +static void isp1504_set(u8 bits, int reg, volatile u32 *view) +{ + u32 data; + + /* make sure interface is running */ + if (!(__raw_readl(view) && ULPIVW_SS)) { + __raw_writel(ULPIVW_WU, view); + do { /* wait for wakeup */ + data = __raw_readl(view); + } while (data & ULPIVW_WU); + } + + __raw_writel((ULPIVW_RUN | ULPIVW_WRITE | + ((reg + ISP1504_REG_SET) << ULPIVW_ADDR_SHIFT) | + ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), + view); + + while (__raw_readl(view) & ULPIVW_RUN) /* wait for completion */ + continue; +} + +/*! + * clear bits in OTG ISP1504 register 'reg' thru VIEWPORT register 'view' + * + * @param bits bits to clear + * @param reg in this register + * @param view the ULPI VIEWPORT register address + */ +static void isp1504_clear(u8 bits, int reg, volatile u32 *view) +{ + __raw_writel((ULPIVW_RUN | ULPIVW_WRITE | + ((reg + ISP1504_REG_CLEAR) << ULPIVW_ADDR_SHIFT) | + ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), + view); + + while (__raw_readl(view) & ULPIVW_RUN) /* wait for completion */ + continue; +} + +extern int gpio_usbotg_hs_active(void); + +static void isp1508_fix(u32 *view) +{ + if (!machine_is_mx31_3ds()) + gpio_usbotg_hs_active(); + + /* Set bits IND_PASS_THRU and IND_COMPL */ + isp1504_set(0x60, ISP1504_ITFCTL, view); + + /* Set bit USE_EXT_VBUS_IND */ + isp1504_set(USE_EXT_VBUS_IND, ISP1504_OTGCTL, view); +} + +/*! + * set vbus power + * + * @param view viewport register + * @param on power on or off + */ +static void isp1504_set_vbus_power(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, int on) +{ + u32 *view = pdata->regs + ULPIVW_OFF; + + pr_debug("real %s(on=%d) view=0x%p\n", __FUNCTION__, on, view); + + pr_debug("ULPI Vendor ID 0x%x Product ID 0x%x\n", + (isp1504_read(ISP1504_VID_HIGH, view) << 8) | + isp1504_read(ISP1504_VID_LOW, view), + (isp1504_read(ISP1504_PID_HIGH, view) << 8) | + isp1504_read(ISP1504_PID_LOW, view)); + + pr_debug("OTG Control before=0x%x\n", + isp1504_read(ISP1504_OTGCTL, view)); + + if (on) { + isp1504_set(DRV_VBUS_EXT | /* enable external Vbus */ + DRV_VBUS | /* enable internal Vbus */ + USE_EXT_VBUS_IND | /* use external indicator */ + CHRG_VBUS, /* charge Vbus */ + ISP1504_OTGCTL, view); + + } else { + isp1508_fix(view); + + isp1504_clear(DRV_VBUS_EXT | /* disable external Vbus */ + DRV_VBUS, /* disable internal Vbus */ + ISP1504_OTGCTL, view); + + isp1504_set(USE_EXT_VBUS_IND | /* use external indicator */ + DISCHRG_VBUS, /* discharge Vbus */ + ISP1504_OTGCTL, view); + } + + pr_debug("OTG Control after = 0x%x\n", + isp1504_read(ISP1504_OTGCTL, view)); +} + +/*! + * set remote wakeup + * + * @param view viewport register + */ +static void isp1504_set_remote_wakeup(u32 * view) +{ + __raw_writel(~ULPIVW_WRITE & __raw_readl(view), view); + __raw_writel((1 << ULPIVW_PORT_SHIFT) | __raw_readl(view), view); + __raw_writel(ULPIVW_RUN | __raw_readl(view), view); + + while (__raw_readl(view) & ULPIVW_RUN) /* wait for completion */ + continue; +} + +static void isp1504_init(struct fsl_xcvr_ops *this) +{ + pr_debug("%s:\n", __FUNCTION__); +} + +static void isp1504_uninit(struct fsl_xcvr_ops *this) +{ + pr_debug("%s:\n", __FUNCTION__); +} + +static void isp1504_suspend(struct fsl_xcvr_ops *this) +{ + pr_debug("%s\n", __func__); + + /* send suspend command */ + isp1504_clear(SUSPENDM, ISP1504_FUNC, &UOG_ULPIVIEW); + pr_debug("%s.\n", __func__); +} + +/*! + * Set the 1504 transceiver to the proper mode for testing purposes. + * + * @param view the ULPI VIEWPORT register address + * @param test_mode Set the 1504 transceiver to disable bit stuffing and NRZI + */ + static void isp1504_set_test_mode(u32 *view, enum usb_test_mode test_mode) +{ + if (test_mode == USB_TEST_J || test_mode == USB_TEST_K) { + printk(KERN_INFO "udc: disable bit stuffing and NRZI\n"); + /* Disable bit-stuffing and NRZI encoding. */ + isp1504_set(0x10, 0x04, view); + } +} + +static struct fsl_xcvr_ops isp1504_ops = { + .name = "isp1504", + .xcvr_type = PORTSC_PTS_ULPI, + .init = isp1504_init, + .uninit = isp1504_uninit, + .suspend = isp1504_suspend, + .set_vbus_power = isp1504_set_vbus_power, + .set_remote_wakeup = isp1504_set_remote_wakeup, + .set_test_mode = isp1504_set_test_mode, +}; + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); +extern int fsl_usb_xcvr_suspend(struct fsl_xcvr_ops *xcvr_ops); + +static int __init isp1504xc_init(void) +{ + pr_debug("%s\n", __FUNCTION__); + + fsl_usb_xcvr_register(&isp1504_ops); + + /* suspend isp1504 */ + if (fsl_usb_xcvr_suspend(&isp1504_ops)) + pr_debug("%s: failed to suspend isp1504\n", __func__); + + return 0; +} + +extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops); + +static void __exit isp1504xc_exit(void) +{ + fsl_usb_xcvr_unregister(&isp1504_ops); +} + +module_init(isp1504xc_init); +module_exit(isp1504xc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("isp1504 xcvr driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/leds.c b/arch/arm/plat-mxc/leds.c new file mode 100644 index 000000000000..e059d238f82b --- /dev/null +++ b/arch/arm/plat-mxc/leds.c @@ -0,0 +1,111 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * The LED can be used for debugging purpose. To enalbe the LEDs, in the + * config file, select: + * CONFIG_LEDS + * CONFIG_LEDS_TIMER --- enable the OS tick LED once every 50 ticks (.5sec) + * CONFIG_LEDS_CPU --- enable the cpu idle in/out LED (blink fast) + * + * The two LEDs can be disabled through user space by issuing: + * echo "claim" > /sys/devices/system/leds/leds0/event + * To release the LEDs back to the normal operation, do: + * echo "release" > /sys/devices/system/leds/leds0/event + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LED_STATE_ENABLED (1 << 0) +#define LED_STATE_CLAIMED (1 << 1) + +static unsigned int led_state; +static unsigned int hw_led_state; + +static void mxc_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state = MXC_BD_LED1 | MXC_BD_LED2; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + case led_halted: + hw_led_state = 0; + led_state &= ~LED_STATE_ENABLED; + MXC_BD_LED_OFF(MXC_BD_LED1 | MXC_BD_LED2); + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = 0; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = 0; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= MXC_BD_LED1; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~MXC_BD_LED2; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= MXC_BD_LED2; + break; +#endif + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) { + MXC_BD_LED_OFF(~hw_led_state); + MXC_BD_LED_ON(hw_led_state); + } + + local_irq_restore(flags); +} + +static int __init mxc_leds_init(void) +{ + led_state = LED_STATE_ENABLED; + leds_event = mxc_leds_event; + return 0; +} + +core_initcall(mxc_leds_init); diff --git a/arch/arm/plat-mxc/mc13783_xc.c b/arch/arm/plat-mxc/mc13783_xc.c new file mode 100644 index 000000000000..3fad32f3b230 --- /dev/null +++ b/arch/arm/plat-mxc/mc13783_xc.c @@ -0,0 +1,299 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Events to be passed to the thread */ +#define MC13783_USB_VBUS_ON 0x0001 +#define MC13783_USB_VBUS_OFF 0x0002 +#define MC13783_USB_DETECT_MINI_A 0x0004 +#define MC13783_USB_DETECT_MINI_B 0x0008 + +extern void otg_set_serial_peripheral(void); +extern void otg_set_serial_host(void); + +static unsigned int p_event; +static PMIC_CONVITY_EVENTS g_event; +static PMIC_CONVITY_HANDLE pmic_handle = (PMIC_CONVITY_HANDLE) NULL; + +static void xc_workqueue_handler(struct work_struct *work); + +DECLARE_WORK(xc_work, xc_workqueue_handler); + +DECLARE_MUTEX(pmic_mx); + +static void pmic_event_handler(const PMIC_CONVITY_EVENTS event) +{ + if (event & USB_DETECT_4V4_RISE) + pr_debug("%s: USB_DETECT_4V4_RISE\n", __func__); + + if (event & USB_DETECT_4V4_FALL) + pr_debug("%s: USB_DETECT_4V4_FALL\n", __func__); + + if (event & USB_DETECT_2V0_RISE) + pr_debug("%s: USB_DETECT_2V0_RISE\n", __func__); + + if (event & USB_DETECT_2V0_FALL) + pr_debug("%s: USB_DETECT_2V0_FALL\n", __func__); + + if (event & USB_DETECT_0V8_RISE) + pr_debug("%s: USB_DETECT_0V8_RISE\n", __func__); + + if (event & USB_DETECT_0V8_FALL) + pr_debug("%s: USB_DETECT_0V8_FALL\n", __func__); + + if (event & USB_DETECT_MINI_B) { + pr_debug("%s: USB_DETECT_MINI_B\n", __func__); + otg_set_serial_peripheral(); + g_event = USB_DETECT_MINI_B; + p_event = MC13783_USB_DETECT_MINI_B; + schedule_work(&xc_work); + } + if (event & USB_DETECT_MINI_A) { + pr_debug("%s: USB_DETECT_MINI_A\n", __func__); + otg_set_serial_host(); + g_event = USB_DETECT_MINI_A; + p_event = MC13783_USB_DETECT_MINI_A; + schedule_work(&xc_work); + } + + /* + * Mini-B cable insertion/removal does not generate cable-detect + * event, so we rely on the VBUS changes to identify a mini-b cable + * connect. This logic is only used if mini-b is the first cable that + * is connected after bootup. At all other times, removal of mini-a + * cable is used to initialize peripheral. + */ + if (g_event != USB_DETECT_MINI_A && g_event != USB_DETECT_MINI_B) { + if ((event & USB_DETECT_0V8_RISE) && + (event & USB_DETECT_2V0_RISE) && + (event & USB_DETECT_4V4_RISE)) { + otg_set_serial_peripheral(); + g_event = USB_DETECT_MINI_B; + p_event = MC13783_USB_DETECT_MINI_B; + schedule_work(&xc_work); + } + } +} + +static int usb_pmic_mod_init(void) +{ + PMIC_STATUS rs = PMIC_ERROR; + + init_MUTEX_LOCKED(&pmic_mx); + + rs = pmic_convity_open(&pmic_handle, USB); + if (rs != PMIC_SUCCESS) { + printk(KERN_ERR "pmic_convity_open returned error %d\n", rs); + return rs; + } + + rs = pmic_convity_set_callback(pmic_handle, pmic_event_handler, + USB_DETECT_4V4_RISE | USB_DETECT_4V4_FALL + | USB_DETECT_2V0_RISE | + USB_DETECT_2V0_FALL | USB_DETECT_0V8_RISE + | USB_DETECT_0V8_FALL | USB_DETECT_MINI_A + | USB_DETECT_MINI_B); + + if (rs != PMIC_SUCCESS) { + printk(KERN_ERR + "pmic_convity_set_callback returned error %d\n", rs); + return rs; + } + + return rs; +} + +static void usb_pmic_mod_exit(void) +{ + PMIC_STATUS rs; + + pmic_convity_set_mode(pmic_handle, RS232_1); + pmic_convity_clear_callback(pmic_handle); + + if (pmic_handle != (PMIC_CONVITY_HANDLE) NULL) { + rs = pmic_convity_close(pmic_handle); + if (rs != PMIC_SUCCESS) { + printk(KERN_ERR + "pmic_convity_close() returned error %d", rs); + } else { + pmic_handle = (PMIC_CONVITY_HANDLE) NULL; + } + } +} + +static inline void mc13783_set_host(void) +{ + PMIC_STATUS rs = PMIC_ERROR; + + rs = pmic_convity_usb_otg_clear_config(pmic_handle, USB_OTG_SE0CONN); + rs |= pmic_convity_usb_otg_clear_config(pmic_handle, USB_PU); + + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USB_UDM_PD); + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USB_UDP_PD); + + if (rs != PMIC_SUCCESS) + printk(KERN_ERR "mc13783_set_host failed\n"); + +} + +static inline void mc13783_set_peripheral(void) +{ + PMIC_STATUS rs = PMIC_ERROR; + + rs = pmic_convity_usb_otg_clear_config(pmic_handle, USB_UDM_PD); + rs |= pmic_convity_usb_otg_clear_config(pmic_handle, USB_UDP_PD); + + rs |= pmic_convity_usb_set_speed(pmic_handle, USB_FULL_SPEED); + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USB_OTG_SE0CONN); + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USB_PU); + + if (rs != PMIC_SUCCESS) + printk(KERN_ERR "mc13783_set_peripheral failed\n"); +} + +void mc13783_set_vbus_power(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, int on) +{ + if (on) { + p_event = MC13783_USB_VBUS_ON; + schedule_work(&xc_work); + } +} + +static struct fsl_xcvr_ops mc13783_ops_otg = { + .name = "mc13783", + .xcvr_type = PORTSC_PTS_SERIAL, + .set_host = mc13783_set_host, + .set_device = mc13783_set_peripheral, + .set_vbus_power = mc13783_set_vbus_power, +}; + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); + +static void xc_workqueue_handler(struct work_struct *work) +{ + PMIC_STATUS rs = PMIC_ERROR; + + down(&pmic_mx); + + switch (p_event) { + case MC13783_USB_VBUS_OFF: + mc13783_set_peripheral(); + break; + case MC13783_USB_VBUS_ON: + mc13783_set_host(); + break; + case MC13783_USB_DETECT_MINI_B: + rs = pmic_convity_set_output(pmic_handle, true, false); + rs |= + pmic_convity_usb_otg_clear_config(pmic_handle, + USB_VBUS_CURRENT_LIMIT_LOW_30MS); + + if (rs != PMIC_SUCCESS) + printk(KERN_ERR "MC13783_USB_VBUS_OFF failed\n"); + break; + case MC13783_USB_DETECT_MINI_A: + rs = pmic_convity_set_output(pmic_handle, true, true); + rs |= + pmic_convity_usb_otg_set_config(pmic_handle, + USB_VBUS_CURRENT_LIMIT_LOW_30MS); + + if (rs != PMIC_SUCCESS) + printk(KERN_ERR "MC13783_USB_VBUS_ON failed\n"); + break; + default: + break; + } + up(&pmic_mx); +} + +int mc13783xc_init(void) +{ + PMIC_STATUS rs = PMIC_ERROR; + +#if defined(CONFIG_MXC_USB_SB3) + int xc_mode = USB_SINGLE_ENDED_BIDIR; +#elif defined(CONFIG_MXC_USB_SU6) + int xc_mode = USB_SINGLE_ENDED_UNIDIR; +#elif defined(CONFIG_MXC_USB_DB4) + int xc_mode = USB_DIFFERENTIAL_BIDIR; +#else + int xc_mode = USB_DIFFERENTIAL_UNIDIR; +#endif + + rs = usb_pmic_mod_init(); + if (rs != PMIC_SUCCESS) { + usb_pmic_mod_exit(); + printk(KERN_ERR "usb_pmic_mod_init failed\n"); + return rs; + } + + rs = pmic_convity_usb_set_xcvr(pmic_handle, xc_mode); + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USB_OTG_SE0CONN); + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USBXCVREN); + rs |= pmic_convity_set_output(pmic_handle, false, true); + + rs |= pmic_convity_usb_otg_set_config(pmic_handle, USB_PULL_OVERRIDE); + rs |= pmic_convity_usb_otg_clear_config(pmic_handle, USB_USBCNTRL); + rs |= pmic_convity_usb_otg_clear_config(pmic_handle, USB_DP150K_PU); + + if (rs != PMIC_SUCCESS) + printk(KERN_ERR "pmic configuration failed\n"); + + fsl_usb_xcvr_register(&mc13783_ops_otg); + + mc13783_set_peripheral(); + + return rs; +} + +extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops); + +void mc13783xc_uninit(void) +{ + /* Clear stuff from init */ + pmic_convity_usb_otg_clear_config(pmic_handle, USB_OTG_SE0CONN); + pmic_convity_usb_otg_clear_config(pmic_handle, USBXCVREN); + pmic_convity_set_output(pmic_handle, false, false); + pmic_convity_usb_otg_clear_config(pmic_handle, USB_PULL_OVERRIDE); + + /* Clear host mode */ + pmic_convity_usb_otg_clear_config(pmic_handle, USB_UDP_PD); + pmic_convity_usb_otg_clear_config(pmic_handle, USB_UDM_PD); + + /* Clear peripheral mode */ + pmic_convity_usb_otg_clear_config(pmic_handle, USB_PU); + + /* Vbus off */ + pmic_convity_set_output(pmic_handle, true, false); + pmic_convity_usb_otg_clear_config(pmic_handle, + USB_VBUS_CURRENT_LIMIT_LOW_30MS); + + usb_pmic_mod_exit(); + + fsl_usb_xcvr_unregister(&mc13783_ops_otg); +} + +module_init(mc13783xc_init); +module_exit(mc13783xc_uninit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("mc13783xc"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c index ae34198a79dd..1c663acd89fa 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/arch/arm/plat-mxc/pwm.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. * * Derived from pxa PWM driver by eric miao + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. */ #include @@ -34,7 +35,12 @@ #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) #define MX3_PWMCR_EN (1 << 0) - +#define MX3_PWMCR_STOPEN (1 << 25) +#define MX3_PWMCR_DOZEEN (1 << 24) +#define MX3_PWMCR_WAITEN (1 << 23) +#define MX3_PWMCR_DBGEN (1 << 22) +#define MX3_PWMCR_CLKSRC_IPG (1 << 16) +#define MX3_PWMCR_CLKSRC_IPG_32k (3 << 16) struct pwm_device { struct list_head node; @@ -55,7 +61,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) return -EINVAL; - if (cpu_is_mx27() || cpu_is_mx3()) { + if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx51()) { unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; c = clk_get_rate(pwm->clk); @@ -73,7 +79,9 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); writel(period_cycles, pwm->mmio_base + MX3_PWMPR); writel(MX3_PWMCR_PRESCALER(prescale - 1) | - MX3_PWMCR_CLKSRC_IPG_HIGH | MX3_PWMCR_EN, + MX3_PWMCR_CLKSRC_IPG_HIGH | + MX3_PWMCR_STOPEN | MX3_PWMCR_DOZEEN | + MX3_PWMCR_WAITEN | MX3_PWMCR_DBGEN, pwm->mmio_base + MX3_PWMCR); } else if (cpu_is_mx1() || cpu_is_mx21()) { /* The PWM subsystem allows for exact frequencies. However, @@ -105,6 +113,7 @@ EXPORT_SYMBOL(pwm_config); int pwm_enable(struct pwm_device *pwm) { + unsigned long reg; int rc = 0; if (!pwm->clk_enabled) { @@ -112,16 +121,27 @@ int pwm_enable(struct pwm_device *pwm) if (!rc) pwm->clk_enabled = 1; } + + reg = readl(pwm->mmio_base + MX3_PWMCR); + reg |= MX3_PWMCR_EN; + writel(reg, pwm->mmio_base + MX3_PWMCR); return rc; } EXPORT_SYMBOL(pwm_enable); void pwm_disable(struct pwm_device *pwm) { + unsigned long reg; + if (pwm->clk_enabled) { clk_disable(pwm->clk); pwm->clk_enabled = 0; } + + reg = readl(pwm->mmio_base + MX3_PWMCR); + reg &= ~MX3_PWMCR_EN; + writel(reg, pwm->mmio_base + MX3_PWMCR); + } EXPORT_SYMBOL(pwm_disable); diff --git a/arch/arm/plat-mxc/sdma/Makefile b/arch/arm/plat-mxc/sdma/Makefile new file mode 100644 index 000000000000..59f94b2da7d0 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/Makefile @@ -0,0 +1,18 @@ +ifneq ($(KBUILD_SRC),) +ccflags-y += -I$(KBUILD_SRC)/arch/arm/plat-mxc/sdma/iapi/include \ + -I$(KBUILD_SRC)/include/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +else +ccflags-y += -Iarch/arm/plat-mxc/sdma/iapi/include \ + -Iinclude/linux \ + -DMCU -DOS=LINUX \ + -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \ + -DENDIANNESS=L_I_T_T_L_E_ENDIAN +endif + +obj-y += dma_sdma.o +obj-$(CONFIG_MXC_SDMA_API) += sdma.o +obj-$(CONFIG_MXC_SDMA_API) += iapi/ +obj-$(CONFIG_MXC_SDMA_API) += sdma_malloc.o diff --git a/arch/arm/plat-mxc/sdma/dma_sdma.c b/arch/arm/plat-mxc/sdma/dma_sdma.c new file mode 100644 index 000000000000..5ca75d08bd08 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/dma_sdma.c @@ -0,0 +1,697 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/sdma/dma_sdma.c + * @brief Front-end to the DMA handling. This handles the allocation/freeing + * of DMA channels, and provides a unified interface to the machines + * DMA facilities. This file contains functions for Smart DMA. + * + * @ingroup SDMA + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MXC_SDMA_API + +static mxc_dma_channel_t mxc_sdma_channels[MAX_DMA_CHANNELS]; +static mxc_dma_channel_private_t mxc_sdma_private[MAX_DMA_CHANNELS]; + +extern struct clk *mxc_sdma_ahb_clk, *mxc_sdma_ipg_clk; + +/*! + * Tasket to handle processing the channel buffers + * + * @param arg channel id + */ +static void mxc_sdma_channeltasklet(unsigned long arg) +{ + dma_request_t request_t; + dma_channel_params chnl_param; + mxc_dma_channel_t *chnl_info; + mxc_dma_channel_private_t *data_priv; + int bd_intr = 0, error = MXC_DMA_DONE; + + chnl_info = &mxc_sdma_channels[arg]; + data_priv = chnl_info->private; + chnl_param = + mxc_sdma_get_channel_params(chnl_info->channel)->chnl_params; + + mxc_dma_get_config(arg, &request_t, data_priv->buf_tail); + + while (request_t.bd_done == 0) { + bd_intr = mxc_dma_get_bd_intr(arg, data_priv->buf_tail); + if ((data_priv->buf_tail += 1) >= chnl_param.bd_number) { + data_priv->buf_tail = 0; + } + chnl_info->active = 0; + if (request_t.bd_error) { + error = MXC_DMA_TRANSFER_ERROR; + } + + if (bd_intr != 0) { + chnl_info->cb_fn(chnl_info->cb_args, error, + request_t.count); + error = MXC_DMA_DONE; + } + + if (data_priv->buf_tail == chnl_info->curr_buf) { + break; + } + memset(&request_t, 0, sizeof(dma_request_t)); + mxc_dma_get_config(arg, &request_t, data_priv->buf_tail); + } +} + +/*! + * This function is generally called by the driver at open time. + * The DMA driver would do any initialization steps that is required + * to get the channel ready for data transfer. + * + * @param channel_id a pre-defined id. The peripheral driver would specify + * the id associated with its peripheral. This would be + * used by the DMA driver to identify the peripheral + * requesting DMA and do the necessary setup on the + * channel associated with the particular peripheral. + * The DMA driver could use static or dynamic DMA channel + * allocation. + * @param dev_name module name or device name + * @return returns a negative number on error if request for a DMA channel did not + * succeed, returns the channel number to be used on success. + */ +int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name, + struct dma_channel_info *info) +{ + mxc_sdma_channel_params_t *chnl; + mxc_dma_channel_private_t *data_priv; + int ret = 0, i = 0, channel_num = 0; + mxc_sdma_channel_ext_params_t *p; + + chnl = mxc_sdma_get_channel_params(channel_id); + if (chnl == NULL) { + return -EINVAL; + } + + if (info) { + if (!chnl->chnl_params.ext) + return -EINVAL; + p = (mxc_sdma_channel_ext_params_t *)chnl; + memcpy(&p->chnl_ext_params.info, info, sizeof(info)); + } + + + /* Enable the SDMA clock */ + clk_enable(mxc_sdma_ahb_clk); + clk_enable(mxc_sdma_ipg_clk); + + channel_num = chnl->channel_num; + if (chnl->channel_num == MXC_DMA_DYNAMIC_CHANNEL) { + /* Get the first free channel */ + for (i = (MAX_DMA_CHANNELS - 1); i > 0; i--) { + /* See if channel is available */ + if ((mxc_sdma_channels[i].dynamic != 1) + || (mxc_sdma_channels[i].lock != 0)) { + continue; + } + channel_num = i; + /* Check to see if we can get this channel */ + ret = mxc_request_dma(&channel_num, dev_name); + if (ret == 0) { + break; + } else { + continue; + } + } + if (ret != 0) { + /* No free channel */ + goto err_ret; + } + } else { + if (mxc_sdma_channels[chnl->channel_num].lock == 1) { + ret = -ENODEV; + goto err_ret; + } + ret = mxc_request_dma(&channel_num, dev_name); + if (ret != 0) { + goto err_ret; + } + } + + ret = mxc_dma_setup_channel(channel_num, &chnl->chnl_params); + + if (ret == 0) { + if (chnl->chnl_priority != MXC_SDMA_DEFAULT_PRIORITY) { + ret = + mxc_dma_set_channel_priority(channel_num, + chnl->chnl_priority); + if (ret != 0) { + pr_info("Failed to set channel prority,\ + continue with the existing \ + priority\n"); + goto err_ret; + } + } + mxc_sdma_channels[channel_num].lock = 1; + if ((chnl->chnl_params.transfer_type == per_2_emi) + || (chnl->chnl_params.transfer_type == dsp_2_emi)) { + mxc_sdma_channels[channel_num].mode = MXC_DMA_MODE_READ; + } else { + mxc_sdma_channels[channel_num].mode = + MXC_DMA_MODE_WRITE; + } + mxc_sdma_channels[channel_num].channel = channel_id; + data_priv = mxc_sdma_channels[channel_num].private; + tasklet_init(&data_priv->chnl_tasklet, + mxc_sdma_channeltasklet, channel_num); + if ((channel_id == MXC_DMA_ATA_RX) + || (channel_id == MXC_DMA_ATA_TX)) { + data_priv->intr_after_every_bd = 0; + } else { + data_priv->intr_after_every_bd = 1; + } + } + err_ret: + if (ret != 0) { + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + channel_num = -ENODEV; + } + + return channel_num; +} + +/*! + * This function is generally called by the driver at close time. The DMA + * driver would do any cleanup associated with this channel. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_free(int channel_num) +{ + mxc_dma_channel_private_t *data_priv; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_free_dma(channel_num); + + /* Disable the SDMA clock */ + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + + mxc_sdma_channels[channel_num].lock = 0; + mxc_sdma_channels[channel_num].active = 0; + mxc_sdma_channels[channel_num].curr_buf = 0; + data_priv = mxc_sdma_channels[channel_num].private; + data_priv->buf_tail = 0; + tasklet_kill(&data_priv->chnl_tasklet); + + return 0; +} + +/*! + * Callback function called from the SDMA Interrupt routine + * + * @param arg driver specific argument that was registered + */ +static void mxc_dma_chnl_callback(void *arg) +{ + int priv; + mxc_dma_channel_private_t *data_priv; + + priv = (int)arg; + data_priv = mxc_sdma_channels[priv].private; + /* Process the buffers in a tasklet */ + tasklet_schedule(&data_priv->chnl_tasklet); +} + +/*! + * This function would just configure the buffers specified by the user into + * dma channel. The caller must call mxc_dma_enable to start this transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param dma_buf an array of physical addresses to the user defined + * buffers. The caller must guarantee the dma_buf is + * available until the transfer is completed. + * @param num_buf number of buffers in the array + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not be + * added with DMA for transfer. On Success, it returns 0 + */ +int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf, + int num_buf, mxc_dma_mode_t mode) +{ + int ret = 0, i = 0, prev_buf; + mxc_dma_channel_t *chnl_info; + mxc_dma_channel_private_t *data_priv; + mxc_sdma_channel_params_t *chnl; + dma_channel_params chnl_param; + dma_request_t request_t; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (num_buf <= 0) { + return -EINVAL; + } + + chnl_info = &mxc_sdma_channels[channel_num]; + data_priv = chnl_info->private; + if (chnl_info->lock != 1) { + return -ENODEV; + } + + /* Check to see if all buffers are taken */ + if (chnl_info->active == 1) { + return -EBUSY; + } + + chnl = mxc_sdma_get_channel_params(chnl_info->channel); + chnl_param = chnl->chnl_params; + + /* Re-setup the SDMA channel if the transfer direction is changed */ + if ((chnl_param.peripheral_type != MEMORY) && (mode != chnl_info->mode)) { + if (chnl_param.peripheral_type == DSP) { + if (mode == MXC_DMA_MODE_READ) { + chnl_param.transfer_type = dsp_2_emi; + } else { + chnl_param.transfer_type = emi_2_dsp; + } + } else if (chnl_param.peripheral_type == FIFO_MEMORY) { + if (mode == MXC_DMA_MODE_READ) + chnl_param.per_address = MXC_FIFO_MEM_SRC_FIXED; + else + chnl_param.per_address = + MXC_FIFO_MEM_DEST_FIXED; + } else { + if (mode == MXC_DMA_MODE_READ) { + chnl_param.transfer_type = per_2_emi; + } else { + chnl_param.transfer_type = emi_2_per; + } + } + chnl_param.callback = mxc_dma_chnl_callback; + chnl_param.arg = (void *)channel_num; + ret = mxc_dma_setup_channel(channel_num, &chnl_param); + if (ret != 0) { + return ret; + } + if (chnl->chnl_priority != MXC_SDMA_DEFAULT_PRIORITY) { + ret = + mxc_dma_set_channel_priority(channel_num, + chnl->chnl_priority); + if (ret != 0) { + pr_info("Failed to set channel prority,\ + continue with the existing \ + priority\n"); + } + } + chnl_info->mode = mode; + } + + for (i = 0; i < num_buf; i++, dma_buf++) { + /* Check to see if all buffers are taken */ + if (chnl_info->active == 1) { + break; + } + request_t.destAddr = (__u8 *) dma_buf->dst_addr; + request_t.sourceAddr = (__u8 *) dma_buf->src_addr; + if (chnl_param.peripheral_type == ASRC) + request_t.count = dma_buf->num_of_bytes / 4; + else + request_t.count = dma_buf->num_of_bytes; + request_t.bd_cont = 1; + ret = mxc_dma_set_config(channel_num, &request_t, + chnl_info->curr_buf); + if (ret != 0) { + break; + } + if (data_priv->intr_after_every_bd == 0) { + if (i == num_buf - 1) { + mxc_dma_set_bd_intr(channel_num, + chnl_info->curr_buf, 1); + } else { + mxc_dma_set_bd_intr(channel_num, + chnl_info->curr_buf, 0); + } + } + + prev_buf = chnl_info->curr_buf; + if ((chnl_info->curr_buf += 1) >= chnl_param.bd_number) { + chnl_info->curr_buf = 0; + } + if (chnl_info->curr_buf == data_priv->buf_tail) { + if ((data_priv->intr_after_every_bd == 0) + && (i != num_buf - 1)) { + /* + * Set the BD_INTR flag on the last BD that + * was queued + */ + mxc_dma_set_bd_intr(channel_num, prev_buf, 1); + } + chnl_info->active = 1; + } + } + + if (i == 0) { + return -EBUSY; + } + return 0; +} + +/*! + * This function would just configure the scatterlist specified by the + * user into dma channel. This is a slight variation of mxc_dma_config(), + * it is provided for the convenience of drivers that have a scatterlist + * passed into them. It is the calling driver's responsibility to have the + * correct physical address filled in the "dma_address" field of the + * scatterlist. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param sg a scatterlist of buffers. The caller must guarantee + * the dma_buf is available until the transfer is + * completed. + * @param num_buf number of buffers in the array + * @param num_of_bytes total number of bytes to transfer. If set to 0, this + * would imply to use the length field of the scatterlist + * for each DMA transfer. Else it would calculate the size + * for each DMA transfer. + * @param mode specifies whether this is READ or WRITE operation + * @return This function returns a negative number on error if buffer could not + * be added with DMA for transfer. On Success, it returns 0 + */ +int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, mxc_dma_mode_t mode) +{ + int ret = 0, i = 0; + mxc_dma_requestbuf_t *dma_buf; + + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + dma_buf = + (mxc_dma_requestbuf_t *) kmalloc(num_buf * + sizeof(mxc_dma_requestbuf_t), + GFP_KERNEL); + + if (dma_buf == NULL) { + return -EFAULT; + } + + for (i = 0; i < num_buf; i++) { + if (mode == MXC_DMA_MODE_READ) { + (dma_buf + i)->dst_addr = sg->dma_address; + } else { + (dma_buf + i)->src_addr = sg->dma_address; + } + + if ((num_of_bytes > sg->length) || (num_of_bytes == 0)) { + (dma_buf + i)->num_of_bytes = sg->length; + } else { + (dma_buf + i)->num_of_bytes = num_of_bytes; + } + sg++; + num_of_bytes -= (dma_buf + i)->num_of_bytes; + } + + ret = mxc_dma_config(channel_num, dma_buf, num_buf, mode); + kfree(dma_buf); + return ret; +} + +/*! + * This function is provided if the driver would like to set/change its + * callback function. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @param callback a callback function to provide notification on transfer + * completion, user could specify NULL if he does not wish + * to be notified + * @param arg an argument that gets passed in to the callback + * function, used by the user to do any driver specific + * operations. + * @return this function returns a negative number on error if the callback + * could not be set for the channel or 0 on success + */ +int mxc_dma_callback_set(int channel_num, + mxc_dma_callback_t callback, void *arg) +{ + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_sdma_channels[channel_num].cb_fn = callback; + mxc_sdma_channels[channel_num].cb_args = arg; + + mxc_dma_set_callback(channel_num, mxc_dma_chnl_callback, + (void *)channel_num); + + return 0; +} + +/*! + * This stops the DMA channel and any ongoing transfers. Subsequent use of + * mxc_dma_enable() will restart the channel and restart the transfer. + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_disable(int channel_num) +{ + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_dma_stop(channel_num); + return 0; +} + +/*! + * This starts DMA transfer. Or it restarts DMA on a stopped channel + * previously stopped with mxc_dma_disable(). + * + * @param channel_num the channel number returned at request time. This + * would be used by the DMA driver to identify the calling + * driver and do the necessary cleanup on the channel + * associated with the particular peripheral + * @return returns a negative number on error or 0 on success + */ +int mxc_dma_enable(int channel_num) +{ + if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) { + return -EINVAL; + } + + if (mxc_sdma_channels[channel_num].lock != 1) { + return -ENODEV; + } + + mxc_dma_start(channel_num); + return 0; +} + +/*! + * Initializes dma structure with dma_operations + * + * @param dma dma structure + * @return returns 0 on success + */ +static int __init mxc_dma_init(void) +{ + int i; + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + mxc_sdma_channels[i].active = 0; + mxc_sdma_channels[i].lock = 0; + mxc_sdma_channels[i].curr_buf = 0; + mxc_sdma_channels[i].dynamic = 1; + mxc_sdma_private[i].buf_tail = 0; + mxc_sdma_channels[i].private = &mxc_sdma_private[i]; + } + /* + * Make statically allocated channels unavailable for dynamic channel + * requests + */ + mxc_get_static_channels(mxc_sdma_channels); + + return 0; +} + +arch_initcall(mxc_dma_init); + +#else +int mxc_request_dma(int *channel, const char *devicename) +{ + return -ENODEV; +} + +int mxc_dma_setup_channel(int channel, dma_channel_params * p) +{ + return -ENODEV; +} + +int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority) +{ + return -ENODEV; +} + +int mxc_dma_set_config(int channel, dma_request_t * p, int bd_index) +{ + return -ENODEV; +} + +int mxc_dma_get_config(int channel, dma_request_t * p, int bd_index) +{ + return -ENODEV; +} + +int mxc_dma_start(int channel) +{ + return -ENODEV; +} + +int mxc_dma_stop(int channel) +{ + return -ENODEV; +} + +void mxc_free_dma(int channel) +{ +} + +void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg) +{ +} + +void *sdma_malloc(size_t size) +{ + return 0; +} + +void sdma_free(void *buf) +{ +} + +void *sdma_phys_to_virt(unsigned long buf) +{ + return 0; +} + +unsigned long sdma_virt_to_phys(void *buf) +{ + return 0; +} + +int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name) +{ + return -ENODEV; +} + +int mxc_dma_free(int channel_num) +{ + return -ENODEV; +} + +int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf, + int num_buf, mxc_dma_mode_t mode) +{ + return -ENODEV; +} + +int mxc_dma_sg_config(int channel_num, struct scatterlist *sg, + int num_buf, int num_of_bytes, mxc_dma_mode_t mode) +{ + return -ENODEV; +} + +int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback, + void *arg) +{ + return -ENODEV; +} + +int mxc_dma_disable(int channel_num) +{ + return -ENODEV; +} + +int mxc_dma_enable(int channel_num) +{ + return -ENODEV; +} + +EXPORT_SYMBOL(mxc_request_dma); +EXPORT_SYMBOL(mxc_dma_setup_channel); +EXPORT_SYMBOL(mxc_dma_set_channel_priority); +EXPORT_SYMBOL(mxc_dma_set_config); +EXPORT_SYMBOL(mxc_dma_get_config); +EXPORT_SYMBOL(mxc_dma_start); +EXPORT_SYMBOL(mxc_dma_stop); +EXPORT_SYMBOL(mxc_free_dma); +EXPORT_SYMBOL(mxc_dma_set_callback); +EXPORT_SYMBOL(sdma_malloc); +EXPORT_SYMBOL(sdma_free); +EXPORT_SYMBOL(sdma_phys_to_virt); +EXPORT_SYMBOL(sdma_virt_to_phys); + +#endif + +EXPORT_SYMBOL(mxc_dma_request_ext); +EXPORT_SYMBOL(mxc_dma_free); +EXPORT_SYMBOL(mxc_dma_config); +EXPORT_SYMBOL(mxc_dma_sg_config); +EXPORT_SYMBOL(mxc_dma_callback_set); +EXPORT_SYMBOL(mxc_dma_disable); +EXPORT_SYMBOL(mxc_dma_enable); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC Linux SDMA API"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/sdma/iapi/Makefile b/arch/arm/plat-mxc/sdma/iapi/Makefile new file mode 100644 index 000000000000..b6a5d6aebda0 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for I.API sources. +# + +obj-y := src/ \ No newline at end of file diff --git a/arch/arm/plat-mxc/sdma/iapi/include/epm.h b/arch/arm/plat-mxc/sdma/iapi/include/epm.h new file mode 100644 index 000000000000..a12fff923a15 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/epm.h @@ -0,0 +1,187 @@ +/* + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __ASM_ARCH_MXC_SDMA_REGS_H__ +#define __ASM_ARCH_MXC_SDMA_REGS_H__ + +#include + +/* SDMA Reg definition */ +#define SDMA_BASE_IO_ADDR IO_ADDRESS(SDMA_BASE_ADDR) + +#define SDMA_H_C0PTR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x000)) +#define SDMA_H_INTR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x004)) +#define SDMA_H_STATSTOP *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x008)) +#define SDMA_H_START *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x00C)) +#define SDMA_H_EVTOVR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x010)) +#define SDMA_H_DSPOVR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x014)) +#define SDMA_H_HOSTOVR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x018)) +#define SDMA_H_EVTPEND *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x01C)) +#define SDMA_H_DSPENBL *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x020)) +#define SDMA_H_RESET *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x024)) +#define SDMA_H_EVTERR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x028)) +#define SDMA_H_INTRMSK *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x02C)) +#define SDMA_H_PSW *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x030)) +#define SDMA_H_EVTERRDBG *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x034)) +#define SDMA_H_CONFIG *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x038)) +#define SDMA_ONCE_ENB *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x040)) +#define SDMA_ONCE_DATA *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x044)) +#define SDMA_ONCE_INSTR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x048)) +#define SDMA_ONCE_STAT *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x04C)) +#define SDMA_ONCE_CMD *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x050)) +#define SDMA_EVT_MIRROR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x054)) +#define SDMA_ILLINSTADDR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x058)) +#define SDMA_CHN0ADDR *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x05C)) +#define SDMA_ONCE_RTB *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x060)) +#define SDMA_XTRIG_CONF1 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x070)) +#define SDMA_XTRIG_CONF2 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x074)) + +#ifdef MXC_SDMA_V2 +#define SDMA_CHNENBL_0 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x200)) +#define SDMA_CHNENBL_1 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x204)) +#define SDMA_CHNENBL_2 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x208)) +#define SDMA_CHNENBL_3 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x20C)) +#define SDMA_CHNENBL_4 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x210)) +#define SDMA_CHNENBL_5 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x214)) +#define SDMA_CHNENBL_6 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x218)) +#define SDMA_CHNENBL_7 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x21C)) +#define SDMA_CHNENBL_8 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x220)) +#define SDMA_CHNENBL_9 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x224)) +#define SDMA_CHNENBL_10 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x228)) +#define SDMA_CHNENBL_11 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x22C)) +#define SDMA_CHNENBL_12 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x230)) +#define SDMA_CHNENBL_13 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x234)) +#define SDMA_CHNENBL_14 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x238)) +#define SDMA_CHNENBL_15 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x23C)) +#define SDMA_CHNENBL_16 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x240)) +#define SDMA_CHNENBL_17 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x244)) +#define SDMA_CHNENBL_18 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x248)) +#define SDMA_CHNENBL_19 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x24C)) +#define SDMA_CHNENBL_20 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x250)) +#define SDMA_CHNENBL_21 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x254)) +#define SDMA_CHNENBL_22 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x258)) +#define SDMA_CHNENBL_23 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x25C)) +#define SDMA_CHNENBL_24 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x260)) +#define SDMA_CHNENBL_25 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x264)) +#define SDMA_CHNENBL_26 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x268)) +#define SDMA_CHNENBL_27 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x26C)) +#define SDMA_CHNENBL_28 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x270)) +#define SDMA_CHNENBL_29 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x274)) +#define SDMA_CHNENBL_30 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x278)) +#define SDMA_CHNENBL_31 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x27C)) +#define SDMA_CHNENBL_32 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x280)) +#define SDMA_CHNENBL_33 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x284)) +#define SDMA_CHNENBL_34 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x288)) +#define SDMA_CHNENBL_35 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x28C)) +#define SDMA_CHNENBL_36 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x290)) +#define SDMA_CHNENBL_37 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x294)) +#define SDMA_CHNENBL_38 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x298)) +#define SDMA_CHNENBL_39 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x29C)) +#define SDMA_CHNENBL_40 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2A0)) +#define SDMA_CHNENBL_41 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2A4)) +#define SDMA_CHNENBL_42 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2A8)) +#define SDMA_CHNENBL_43 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2AC)) +#define SDMA_CHNENBL_44 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2B0)) +#define SDMA_CHNENBL_45 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2B4)) +#define SDMA_CHNENBL_46 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2B8)) +#define SDMA_CHNENBL_47 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x2BC)) + +#define SDMA_ONCE_COUNT *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x300)) +#define SDMA_ONCE_ECTL *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x304)) +#define SDMA_ONCE_EAA *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x308)) +#define SDMA_ONCE_EAB *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x30C)) +#define SDMA_ONCE_EAM *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x310)) +#define SDMA_ONCE_ED *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x314)) +#define SDMA_ONCE_EDM *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x318)) +#define SDMA_ONCE_PCMATCH *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x31C)) + +#else + +#define SDMA_CHNENBL_0 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x080)) +#define SDMA_CHNENBL_1 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x084)) +#define SDMA_CHNENBL_2 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x088)) +#define SDMA_CHNENBL_3 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x08C)) +#define SDMA_CHNENBL_4 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x090)) +#define SDMA_CHNENBL_5 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x094)) +#define SDMA_CHNENBL_6 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x098)) +#define SDMA_CHNENBL_7 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x09C)) +#define SDMA_CHNENBL_8 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0A0)) +#define SDMA_CHNENBL_9 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0A4)) +#define SDMA_CHNENBL_10 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0A8)) +#define SDMA_CHNENBL_11 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0AC)) +#define SDMA_CHNENBL_12 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0B0)) +#define SDMA_CHNENBL_13 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0B4)) +#define SDMA_CHNENBL_14 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0B8)) +#define SDMA_CHNENBL_15 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0BC)) +#define SDMA_CHNENBL_16 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0C0)) +#define SDMA_CHNENBL_17 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0C4)) +#define SDMA_CHNENBL_18 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0C8)) +#define SDMA_CHNENBL_19 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0CC)) +#define SDMA_CHNENBL_20 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0D0)) +#define SDMA_CHNENBL_21 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0D4)) +#define SDMA_CHNENBL_22 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0D8)) +#define SDMA_CHNENBL_23 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0DC)) +#define SDMA_CHNENBL_24 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0E0)) +#define SDMA_CHNENBL_25 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0E4)) +#define SDMA_CHNENBL_26 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0E8)) +#define SDMA_CHNENBL_27 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0EC)) +#define SDMA_CHNENBL_28 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0F0)) +#define SDMA_CHNENBL_29 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0F4)) +#define SDMA_CHNENBL_30 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0F8)) +#define SDMA_CHNENBL_31 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x0FC)) + +#define SDMA_ONCE_COUNT *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x200)) +#define SDMA_ONCE_ECTL *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x204)) +#define SDMA_ONCE_EAA *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x208)) +#define SDMA_ONCE_EAB *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x20C)) +#define SDMA_ONCE_EAM *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x210)) +#define SDMA_ONCE_ED *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x214)) +#define SDMA_ONCE_EDM *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x218)) +#define SDMA_ONCE_PCMATCH *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x21C)) + +#endif /* MXC_SDMA_V2 */ + +#define SDMA_CHNPRI_0 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x100)) +#define SDMA_CHNPRI_1 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x104)) +#define SDMA_CHNPRI_2 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x108)) +#define SDMA_CHNPRI_3 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x10C)) +#define SDMA_CHNPRI_4 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x110)) +#define SDMA_CHNPRI_5 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x114)) +#define SDMA_CHNPRI_6 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x118)) +#define SDMA_CHNPRI_7 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x11C)) +#define SDMA_CHNPRI_8 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x120)) +#define SDMA_CHNPRI_9 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x124)) +#define SDMA_CHNPRI_10 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x128)) +#define SDMA_CHNPRI_11 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x12C)) +#define SDMA_CHNPRI_12 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x130)) +#define SDMA_CHNPRI_13 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x134)) +#define SDMA_CHNPRI_14 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x138)) +#define SDMA_CHNPRI_15 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x13C)) +#define SDMA_CHNPRI_16 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x140)) +#define SDMA_CHNPRI_17 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x144)) +#define SDMA_CHNPRI_18 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x148)) +#define SDMA_CHNPRI_19 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x14C)) +#define SDMA_CHNPRI_20 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x150)) +#define SDMA_CHNPRI_21 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x154)) +#define SDMA_CHNPRI_22 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x158)) +#define SDMA_CHNPRI_23 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x15C)) +#define SDMA_CHNPRI_24 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x160)) +#define SDMA_CHNPRI_25 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x164)) +#define SDMA_CHNPRI_26 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x168)) +#define SDMA_CHNPRI_27 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x16C)) +#define SDMA_CHNPRI_28 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x170)) +#define SDMA_CHNPRI_29 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x174)) +#define SDMA_CHNPRI_30 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x178)) +#define SDMA_CHNPRI_31 *((volatile unsigned long *)(SDMA_BASE_IO_ADDR + 0x17C)) + +#endif /* _mcuEpm_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapi.h b/arch/arm/plat-mxc/sdma/iapi/include/iapi.h new file mode 100644 index 000000000000..d7300218057b --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapi.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapi.h + * + * $Id iapi.h $ + * + * Description: + * Unique include for the whole IAPI library. + * + * + * http//compass.mot.com/go/115342679 + * + * $Log iapi.h $ + * + * ***************************************************************************/ + +#ifndef _iapi_h +#define _iapi_h + +/* **************************************************************************** + * Include File Section + * ***************************************************************************/ + +#include "sdmaStruct.h" +#include "iapiDefaults.h" +#include "iapiLow.h" +#include "iapiMiddle.h" +#include "iapiHigh.h" + +#ifdef MCU +#include "iapiLowMcu.h" +#include "iapiMiddleMcu.h" +#endif /* MCU */ + + + +#endif /* _iapi_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h new file mode 100644 index 000000000000..b03a53ae1893 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h @@ -0,0 +1,128 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiDefaults.h + * + * $Id iapiDefaults.h $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * + * + * + * + * $Log iapiDefaults.h $ + * + *****************************************************************************/ + + +#ifndef _iapi_defaults_h +#define _iapi_defaults_h + +/****************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "sdmaStruct.h" + +/* **************************************************************************** + * Macro-command Section + * ***************************************************************************/ + +/** + * Error codes + * lower 5 bits free to include channel number when available + * and bit number 6 must be set when channel number is available + * + * Note : + * 1) Abbreviations / naming convention : + * - BD : Buffer Descriptor + * - CC : Channel Context + * - CCB : Channel Control Block + * - CD : Channel Descriptor + * - B : Buffer + * - CH : Channel + * + */ +#define IAPI_SUCCESS 0 +#define IAPI_FAILURE -1 +#define IAPI_ERR_CH_AVAILABLE 0x00020 +#define IAPI_ERR_NO_ERROR 0x00000 +#define IAPI_ERR_NO_CCB_DEFINED 0x01000 +#define IAPI_ERR_BD_UNINITIALIZED 0x02000 +#define IAPI_ERR_BD_ALLOCATED 0x03000 +#define IAPI_ERR_BD_ALLOCATION 0x04000 +#define IAPI_ERR_CCB_ALLOC_FAILED 0x05000 +#define IAPI_ERR_CCB_UNINITIALIZED 0x06000 +#define IAPI_ERR_CC_ALREADY_DEFINED 0x07000 +#define IAPI_ERR_CC_ALLOC_FAILED 0x08000 +#define IAPI_ERR_CD_ALREADY_DEFINED 0x09000 +#define IAPI_ERR_CD_ALLOC_FAILED 0x0A000 +#define IAPI_ERR_CD_CHANGE_CH_NUMBER 0x0B000 +#define IAPI_ERR_CD_CHANGE_CCB_PTR 0x0C000 +#define IAPI_ERR_CD_CHANGE_UNKNOWN 0x0D000 +#define IAPI_ERR_CD_CHANGE 0x0E000 +#define IAPI_ERR_CD_UNINITIALIZED 0x0F000 +#define IAPI_ERR_CLOSE 0x10000 +#define IAPI_ERR_B_ALLOC_FAILED 0x11000 +#define IAPI_ERR_CONFIG_OVERRIDE 0x12000 +#define IAPI_ERR_CH_IN_USE 0x13000 +#define IAPI_ERR_CALLBACKSYNCH_UNKNOWN 0x14000 +#define IAPI_ERR_INVALID_PARAMETER 0x15000 +#define IAPI_ERR_TRUST 0x16000 +#define IAPI_ERR_CHANNEL_UNINITIALIZED 0x17000 +#define IAPI_ERR_RROR_BIT_READ 0x18000 +#define IAPI_ERR_RROR_BIT_WRITE 0x19000 +#define IAPI_ERR_NOT_ALLOWED 0x1A000 +#define IAPI_ERR_NO_OS_FN 0x1B000 + + +/* + * Global Variable Section + */ + +/* + * Table to hold pointers to the callback functions registered by the users of + *I.API + */ +extern void (* callbackIsrTable[CH_NUM])(channelDescriptor * cd_p, void * arg); + +/* + * Table to hold user registered data pointers, to be privided in the callback + *function + */ +extern void * userArgTable[CH_NUM]; + +/* channelDescriptor data structure filled with default data*/ +extern channelDescriptor iapi_ChannelDefaults; + +/* Global variable to hold the last error encountered in I.API operations*/ +extern unsigned int iapi_errno; + +/* Used in synchronization, to mark started channels*/ +extern volatile unsigned long iapi_SDMAIntr; + +/* Hold a pointer to the start of the CCB array, to be used in the IRQ routine + *to find the channel descriptor for the channed sending the interrupt to the + *core. + */ +extern channelControlBlock * iapi_CCBHead; + +/* configs_data structure filled with default data*/ +extern configs_data iapi_ConfigDefaults; + +#endif /* iapiDefaults_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h new file mode 100644 index 000000000000..14cfae539eb8 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h @@ -0,0 +1,136 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiHigh.h + * + * $Id iapiHigh.h $ + * + * Description: + * prototypes for high level function of I.API + * + * + * http://venerque.sps.mot.com/pjt/sfs/www/iapi/softsim_api.pdf + * + * $Log iapiHigh.h + * + * ***************************************************************************/ + +#ifndef _iapiHigh_h +#define _iapiHigh_h + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" + +/* **************************************************************************** + * Macro-command Section + *****************************************************************************/ +enum { + IAPI_CHANGE_CHANDESC, + IAPI_CHANGE_BDNUM, + IAPI_CHANGE_BUFFSIZE, + IAPI_CHANGE_CHANBLOCK, + IAPI_CHANGE_INSTANCE, + IAPI_CHANGE_OWNERSHIP, + IAPI_CHANGE_SYNCH, + IAPI_CHANGE_TRUST, + IAPI_CHANGE_CALLBACKFUNC, + IAPI_CHANGE_CHANCCB, + IAPI_CHANGE_PRIORITY, + IAPI_CHANGE_BDWRAP, + IAPI_CHANGE_WATERMARK, + IAPI_CHANGE_SET_BDCONT, + IAPI_CHANGE_UNSET_BDCONT, + IAPI_CHANGE_SET_BDEXTD, + IAPI_CHANGE_UNSET_BDEXTD, + IAPI_CHANGE_EVTMASK1, + IAPI_CHANGE_EVTMASK2, + IAPI_CHANGE_PERIPHADDR, + IAPI_CHANGE_SET_BDINTR, + IAPI_CHANGE_UNSET_BDINTR, + IAPI_CHANGE_SET_TRANSFER_CD, + IAPI_CHANGE_FORCE_CLOSE, + IAPI_CHANGE_SET_TRANSFER, + IAPI_CHANGE_USER_ARG, + IAPI_CHANGE_SET_BUFFERADDR, + IAPI_CHANGE_SET_EXTDBUFFERADDR, + IAPI_CHANGE_SET_COMMAND, + IAPI_CHANGE_SET_COUNT, + IAPI_CHANGE_SET_STATUS, + IAPI_CHANGE_GET_BUFFERADDR, + IAPI_CHANGE_GET_EXTDBUFFERADDR, + IAPI_CHANGE_GET_COMMAND, + IAPI_CHANGE_GET_COUNT, + IAPI_CHANGE_GET_STATUS, + IAPI_CHANGE_SET_ENDIANNESS +}; + + +/* + * Public Function Prototype Section + */ +int iapi_Open ( channelDescriptor * cd_p, unsigned char channelNumber ); +int iapi_Close( channelDescriptor * cd_p ); +int iapi_Read ( channelDescriptor * cd_p, void * buf, unsigned short nbyte ); +int iapi_Write( channelDescriptor * cd_p, void * buf, unsigned short nbyte ); +int iapi_MemCopy(channelDescriptor * cd_p, void* dest, void* src, + unsigned long size); +int iapi_IoCtl( channelDescriptor * cd_p, unsigned long ctlRequest, + unsigned long param); + + +int iapi_Read_ipcv2( channelDescriptor * cd_p, void * data_control_struct_ipcv2); + +int iapi_Write_ipcv2( channelDescriptor * cd_p, void * data_control_struct_ipcv2); + +#ifdef MCU +int iapi_Init(channelDescriptor * cd_p, configs_data * config_p, + unsigned short* ram_image, unsigned short code_size, + unsigned long start_addr); +#endif /* MCU */ +#ifdef DSP +int iapi_Init(channelDescriptor * cd_p); +#endif /* DSP */ + +int iapi_StartChannel(unsigned char channel); +int iapi_StopChannel(unsigned char channel); +int iapi_SynchChannel(unsigned char channel); + +int iapi_GetChannelNumber(channelDescriptor * cd_p); +unsigned long iapi_GetError(channelDescriptor * cd_p); +int iapi_GetCount(channelDescriptor * cd_p); +int iapi_GetCountAll(channelDescriptor * cd_p); + +#ifndef IRQ_KEYWORD +#define IRQ_KEYWORD +#endif /* IRQ_KEYWORD */ + +IRQ_KEYWORD void IRQ_Handler(void); + +#ifdef MCU +int iapi_GetScript(channelDescriptor * cd_p, void * buf, unsigned short size, + unsigned long address); +int iapi_GetContext(channelDescriptor * cd_p, void * buf, + unsigned char channel); +int iapi_SetScript(channelDescriptor * cd_p, void * buf, unsigned short nbyte, + unsigned long destAddr); +int iapi_SetContext(channelDescriptor * cd_p, void * buf, + unsigned char channel); +int iapi_AssignScript(channelDescriptor * cd_p, script_data * data_p); + +int iapi_SetChannelEventMapping(unsigned char event, unsigned long channel_map); +#endif /* MCU */ + +#endif /* _iapiHigh_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h new file mode 100644 index 000000000000..43aff7a4e903 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h @@ -0,0 +1,78 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLow.h + * + * $Id iapiLow.h $ + * + * Description: + * prototypes for low level function of I.API + * + * + * + * + * $Log iapiLow.h + * + * ***************************************************************************/ + +#ifndef _iapiLow_h +#define _iapiLow_h + +/* **************************************************************************** + * Boolean identifiers + *****************************************************************************/ +#define NO_OS 0 +#define LINUX 1 +#define SYMBIAN 2 +#define WINCE 3 + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" +#include "iapiDefaults.h" +#include "iapiOS.h" +#ifdef MCU +#include "iapiLowMcu.h" +#endif /*MCU*/ +#if OS == NO_OS +#include +#elif OS == LINUX +#include +#endif + + +/* **************************************************************************** + * Macro-command Section + *****************************************************************************/ + +#define GOTO_SLEEP(x) (iapi_GotoSleep)(x) +#define INIT_SLEEP(x) (iapi_InitSleep)(x) + +/* **************************************************************************** + * Public Function Prototype Section + *****************************************************************************/ +void iapi_lowStartChannel ( unsigned char channel ); +void iapi_lowStopChannel ( unsigned char channel ); +void iapi_AttachCallbackISR (channelDescriptor * cd_p, + void (* func_p)(channelDescriptor * cd_p, void * arg)); +void iapi_DetachCallbackISR (channelDescriptor * cd_p); +void iapi_ChangeCallbackISR (channelDescriptor * cd_p, + void (* func_p)(channelDescriptor * cd_p, void * arg)); +void iapi_lowSynchChannel ( unsigned char channel ); +void iapi_SetBufferDescriptor(bufferDescriptor *bd_p, unsigned char command, + unsigned char status, unsigned short count, + void * buffAddr, void * extBufferAddr); + +#endif /* _iapiLow_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h new file mode 100644 index 000000000000..0adaa2548b9e --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* **************************************************************************** + * + * File: iapiLowDsp.h + * + * $Id iapiLowDsp.h $ + * + * Description: + * prototypes for low level function of I.API for DSP side only + * + * + * + * + * $Log iapiLowDsp.h + * + * ***************************************************************************/ + +#ifndef _iapiLowDsp_h +#define _iapiLowDsp_h + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ + + +/* **************************************************************************** + * Public Function Prototype Section + *****************************************************************************/ +/* WARNING !!!!! + * This file is empty and it is normal, because there is no low level functions + * dedicated to the DSP but the file (iapi_LowDsp.h) must still exist because + * some project directly links the file. Previously, there were function + * iapi_EnableInterrupts,iapi_DisableInterrupts,iapi_WaitCore,iapi_StartChannel + * iapi_StopChannel but they are common to both MCU and DSP, so they have been + * moved to iapi_Low.h file. + */ + +#endif /* _iapiLowDsp_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h new file mode 100644 index 000000000000..12bea564c116 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLowMcu.h + * + * $Id iapiLowMcu.h $ + * + * Description: + * prototypes for low level function of I.API of MCU side only + * + * + * + * + * $Log iapiLowMcu.h $ + * + * ***************************************************************************/ + +#ifndef _iapiLowMcu_h +#define _iapiLowMcu_h + +/****************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" +#include "iapiDefaults.h" + +/* **************************************************************************** + * Public Function Prototype Section + * ***************************************************************************/ + + +void iapi_InitChannelTables ( void ); +int iapi_ChannelConfig(unsigned char channel, unsigned eventOverride, + unsigned mcuOverride, unsigned dspOverride); +int iapi_Channel0Command(channelDescriptor * cd_p, void * buf, + unsigned short nbyte, unsigned char command); +void iapi_lowGetScript(channelDescriptor * cd_p, void * buf, unsigned short size, + unsigned long address); +void iapi_lowGetContext(channelDescriptor * cd_p, void * buf, + unsigned char channel); +void iapi_lowSetScript(channelDescriptor * cd_p, void * buf, unsigned short nbyte, + unsigned long destAddr); +void iapi_lowSetContext(channelDescriptor * cd_p, void * buf, + unsigned char channel); +int iapi_lowAssignScript(channelDescriptor * cd_p, script_data * data_p); + +int iapi_lowSetChannelEventMapping(unsigned char event, unsigned long channel_map); + +#endif /* _iapiLowMcu_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h new file mode 100644 index 000000000000..2470ffcaabf1 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddle.h + * + * $Id iapiMiddle.h $ + * + * Description: + * prototypes for middle level function of I.API + * + * + * + * + * $Log iapiMiddle.h + * + * ***************************************************************************/ + +#ifndef _iapiMiddle_h +#define _iapiMiddle_h + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ +#include "sdmaStruct.h" +#ifdef MCU +#include "iapiMiddleMcu.h" +#endif /* MCU */ + +/* **************************************************************************** + * Public Function Prototype Section + ******************************************************************************/ +bufferDescriptor * iapi_AllocBD (channelControlBlock * ccb_p); +int iapi_AllocContext(contextData ** ctxd_p, unsigned char channel); +int iapi_AllocChannelDesc(channelDescriptor ** cd_p, unsigned char channel); +int iapi_ChangeChannelDesc (channelDescriptor * cd_p, + unsigned char whatToChange, unsigned long newval); +void iapi_InitializeCallbackISR (void (* func_p)(channelDescriptor * cd_p, + void * arg)); +int iapi_InitializeMemory (channelControlBlock * ccb_p); + +#endif /* iapiMiddle_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h new file mode 100644 index 000000000000..a47c02d4440b --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddleMcu.h + * + * $Id iapiMiddleMcu.h $ + * + * Description: + * prototypes for middle level function of I.API + * + * + * + * + * $Log iapiMiddleMcu.h + * + * ***************************************************************************/ + +#ifndef _iapiMiddleMcu_h +#define _iapiMiddleMcu_h + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ +#include "sdmaStruct.h" + +/* **************************************************************************** + * Public Function Prototype Section + ******************************************************************************/ + +#endif /* iapiMiddleMcu_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h b/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h new file mode 100644 index 000000000000..17186dae0fd5 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiOS.h + * + * $Id iapiOS.h $ + * + * Description: + * prototypes for OS level function of I.API + * + * + * + * + * $Log iapiOS.h + * + * ***************************************************************************/ + +#ifndef _iapiOS_h +#define _iapiOS_h + +/* **************************************************************************** + * Boolean identifiers + *****************************************************************************/ +#define NO_OS 0 +#define LINUX 1 +#define SYMBIAN 2 +#define WINCE 3 + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "sdmaStruct.h" +#include "iapiDefaults.h" +#ifdef MCU +#include "iapiLowMcu.h" +#endif /*MCU*/ +#if OS == NO_OS +#include +#elif OS == LINUX +#include +#endif + +/* **************************************************************************** + * Macro-command Section + *****************************************************************************/ +#define SDMA_ERAM 0 +#define SDMA_IRAM 1 +#ifdef CONFIG_SDMA_IRAM +#define MALLOC(x, s) (s == SDMA_ERAM)? (* iapi_Malloc)(x):(* iapi_iram_Malloc)(x) +#else /*CONFIG_SDMA_IRAM */ +#define MALLOC(x, s) (* iapi_Malloc)(x) +#endif /*CONFIG_SDMA_IRAM */ +#define FREE(x) if (x!=NULL) (* iapi_Free)(x) + +#define GOTO_SLEEP(x) (iapi_GotoSleep)(x) +#define INIT_SLEEP(x) (iapi_InitSleep)(x) + +/* **************************************************************************** + * Public Function Prototype Section + *****************************************************************************/ + +#ifdef CONFIG_SDMA_IRAM +extern void*(* iapi_iram_Malloc) (size_t size); +#endif /*CONFIG_SDMA_IRAM*/ + +extern void*(* iapi_Malloc) (size_t size); +extern void (* iapi_Free) (void * ptr); + +extern void*(* iapi_Virt2Phys) (void * ptr); +extern void*(* iapi_Phys2Virt) (void * ptr); + +extern void (* iapi_WakeUp)(int); +extern void (* iapi_GotoSleep)(int); +extern void (* iapi_InitSleep)(int); + +extern void*(* iapi_memcpy)(void *dest, const void *src, size_t count); +extern void*(* iapi_memset)(void *dest, int c, size_t count); + +extern void (* iapi_EnableInterrupts)(void); +extern void (* iapi_DisableInterrupts)(void); + +extern int (* iapi_GetChannel)(int); +extern int (* iapi_ReleaseChannel)(int); + +#endif /* _iapiOS_h */ diff --git a/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h b/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h new file mode 100644 index 000000000000..bc42dabba554 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h @@ -0,0 +1,426 @@ +/****************************************************************************** + * + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: sdmaStruct.h + * + * $Id sdmaStruct.h $ + * + * Description: provides necessary definitions and inclusion for ipcmStruct.c + * + * $Log $ + * + *****************************************************************************/ +#ifndef _sdmaStruct_h +#define _sdmaStruct_h + +/* **************************************************************************** + * Include File Section + ******************************************************************************/ + +/* **************************************************************************** + * Macro-command Section + ******************************************************************************/ + +/** + * Identifier NULL + */ +#ifndef NULL +#define NULL 0 +#endif + +/** + * Boolean identifiers + */ +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/** + * Number of channels + */ +#define CH_NUM 32 +/** + * Number of events + */ +#ifdef MXC_SDMA_V2 +#define EVENTS_NUM 48 +#else +#define EVENTS_NUM 32 +#endif +/** + * Channel configuration + */ +#define DONT_OWN_CHANNEL 0 +#define OWN_CHANNEL 1 + +/** + * Ownership (value defined to computed decimal value) + */ +#define CH_OWNSHP_OFFSET_EVT 0 +#define CH_OWNSHP_OFFSET_MCU 1 +#define CH_OWNSHP_OFFSET_DSP 2 +/** + * Indexof the greg which holds address to start a script from when channel + * becomes current. + */ +#define SDMA_NUMBER_GREGS 8 + +/** + * Channel contexts management + */ + +#define CHANNEL_CONTEXT_BASE_ADDRESS 0x800 +/** + * Buffer descriptor status values. + */ +#define BD_DONE 0x01 +#define BD_WRAP 0x02 +#define BD_CONT 0x04 +#define BD_INTR 0x08 +#define BD_RROR 0x10 +#define BD_LAST 0x20 +#define BD_EXTD 0x80 + + +/** + * Data Node descriptor status values. + */ +#define DND_END_OF_FRAME 0x80 +#define DND_END_OF_XFER 0x40 +#define DND_DONE 0x20 +#define DND_UNUSED 0x01 + +/** + * IPCV2 descriptor status values. + */ +#define BD_IPCV2_END_OF_FRAME 0x40 + + +#define IPCV2_MAX_NODES 50 +/** + * Error bit set in the CCB status field by the SDMA, + * in setbd routine, in case of a transfer error + */ +#define DATA_ERROR 0x10000000 + +/** + * Buffer descriptor commands. + */ +#define C0_ADDR 0x01 +#define C0_LOAD 0x02 +#define C0_DUMP 0x03 +#define C0_SETCTX 0x07 +#define C0_GETCTX 0x03 +#define C0_SETDM 0x01 +#define C0_SETPM 0x04 +#define C0_GETDM 0x02 +#define C0_GETPM 0x08 +/** + * Transfer types, encoded in the BD command field + */ +#define TRANSFER_32BIT 0x00 +#define TRANSFER_8BIT 0x01 +#define TRANSFER_16BIT 0x02 +#define TRANSFER_24BIT 0x03 +/** + * Change endianness indicator in the BD command field + */ +#define CHANGE_ENDIANNESS 0x80 +/** + * Size in bytes + */ +#define SDMA_BD_SIZE 8 +#define SDMA_EXTENDED_BD_SIZE 12 +#define BD_NUMBER 4 +/** + * Channel interrupt policy + */ +#define DEFAULT_POLL 0 +#define CALLBACK_ISR 1 +/** + * Channel status + */ +#define UNINITIALIZED 0 +#define INITIALIZED 1 + +/** + * IoCtl particular values + */ +#define SET_BIT_ALL 0xFFFFFFFF +#define BD_NUM_OFFSET 16 +#define BD_NUM_MASK 0xFFFF0000 + +/** + * Maximum values for IoCtl calls, used in high or middle level calls + */ +#define MAX_BD_NUM 256 +#define MAX_BD_SIZE 65536 +#define MAX_BLOCKING 2 +#define MAX_SYNCH 2 +#define MAX_OWNERSHIP 8 +#define MAX_CH_PRIORITY 8 +#define MAX_TRUST 2 +#define MAX_WML 256 + + +/** + * Access to channelDescriptor fields + */ +enum { + IAPI_CHANNELNUMBER, + IAPI_BUFFERDESCNUMBER, + IAPI_BUFFERSIZE, + IAPI_BLOCKING, + IAPI_CALLBACKSYNCH, + IAPI_OWNERSHIP, + IAPI_PRIORITY, + IAPI_TRUST, + IAPI_UNUSED, + IAPI_CALLBACKISR_PTR, + IAPI_CCB_PTR, + IAPI_BDWRAP, + IAPI_WML +}; + +/** + * Default values for channel descriptor - nobody ownes the channel + */ +#define CD_DEFAULT_OWNERSHIP 7 + + +/** + * User Type Section + */ + +/** + * Command/Mode/Count of buffer descriptors + */ + +#if (ENDIANNESS==B_I_G_ENDIAN) +typedef struct iapi_modeCount_ipcv2 { + unsigned long status : 8; /**< L, E , D bits stored here */ + unsigned long reserved : 8; + unsigned long count : 16; /**< +#include + +#include "epm.h" +#include "iapi.h" + +/* **************************************************************************** + * External Reference Section (for compatibility with already developed code) + *****************************************************************************/ +static void iapi_read_ipcv2_callback(struct iapi_channelDescriptor* cd_p, void* data); + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ +#define MAX_CHANNEL 32 + +static dataNodeDescriptor* dnd_read_control_struct[MAX_CHANNEL]; + +/* MASK to get Nullify all the bits of Status in Data Node descriptor apart from L, E and D*/ + +#define GET_LED_MASK 0xE0 + +/*Table defines mapping of Data Node Descriptor to Buffer Descriptor status*/ + +static unsigned char dnd_2_bd_status[]= +{ +0x85, /*00 L = 0, E = 0, D = 0*/ +0x00, /*01*/ +0x00, /*02*/ +0x00, /*03*/ +0x00, /*04*/ +0x00, /*05*/ +0x00, /*06*/ +0x00, /*07*/ +0x00, /*08*/ +0x00, /*09*/ +0x00, /*0A*/ +0x00, /*0B*/ +0x00, /*0C*/ +0x00, /*0D*/ +0x00, /*0E*/ +0x00, /*0F*/ +0x00, /*10*/ +0x00,/*11*/ +0x00,/*12*/ +0x00,/*13*/ +0x00,/*14*/ +0x00,/*15*/ +0x00,/*16*/ +0x00,/*17*/ +0x00,/*18*/ +0x00,/*19*/ +0x00,/*1A*/ +0x00,/*1B*/ +0x00,/*1C*/ +0x00,/*1D*/ +0x00,/*1E*/ +0x00,/*1F*/ +0x84,/*20 L = 0, E = 0, D = 1 */ +0x00,/*21*/ +0x00,/*22*/ +0x00,/*23*/ +0x00,/*24*/ +0x00,/*25*/ +0x00,/*26*/ +0x00,/*27*/ +0x00,/*28*/ +0x00,/*29*/ +0x00,/*2A*/ +0x00,/*2B*/ +0x00,/*2C*/ +0x00,/*2D*/ +0x00,/*2E*/ +0x00,/*2F*/ +0x00,/*30*/ +0x00,/*31*/ +0x00,/*32*/ +0x00,/*33*/ +0x00,/*34*/ +0x00,/*35*/ +0x00,/*36*/ +0x00,/*37*/ +0x00,/*38*/ +0x00,/*39*/ +0x00,/*3A*/ +0x00,/*3B*/ +0x00,/*3C*/ +0x00,/*3D*/ +0x00,/*3E*/ +0x00,/*3F*/ +0xAB,/*40 L = 0, E = 1, D = 0*/ +0x00,/*41*/ +0x00,/*42*/ +0x00,/*43*/ +0x00,/*44*/ +0x00,/*45*/ +0x00,/*46*/ +0x00,/*47*/ +0x00,/*48*/ +0x00,/*49*/ +0x00,/*4A*/ +0x00,/*4B*/ +0x00,/*4C*/ +0x00,/*4D*/ +0x00,/*4E*/ +0x00,/*4F*/ +0x00,/*50*/ +0x00,/*51*/ +0x00,/*52*/ +0x00,/*53*/ +0x00,/*54*/ +0x00,/*55*/ +0x00,/*56*/ +0x00,/*57*/ +0x00,/*58*/ +0x00,/*59*/ +0x00,/*5A*/ +0x00,/*5B*/ +0x00,/*5C*/ +0x00,/*5D*/ +0x00,/*5E*/ +0x00,/*5F*/ +0xAA,/*60 L = 0, E = 1, D = 1*/ +0x00,/*61*/ +0x00,/*62*/ +0x00,/*63*/ +0x00,/*64*/ +0x00,/*65*/ +0x00,/*66*/ +0x00,/*67*/ +0x00,/*68*/ +0x00,/*69*/ +0x00,/*6A*/ +0x00,/*6B*/ +0x00,/*6C*/ +0x00,/*6D*/ +0x00,/*6E*/ +0x00,/*6F*/ +0x00,/*70*/ +0x00,/*71*/ +0x00,/*72*/ +0x00,/*73*/ +0x00,/*74*/ +0x00,/*75*/ +0x00,/*76*/ +0x00,/*77*/ +0x00,/*78*/ +0x00,/*79*/ +0x00,/*7A*/ +0x00,/*7B*/ +0x00,/*7C*/ +0x00,/*7D*/ +0x00,/*7E*/ +0x00,/*7F*/ +0xC5,/*80 L = 1, E = 0, D = 0*/ +0x00,/*81*/ +0x00,/*82*/ +0x00,/*83*/ +0x00,/*84*/ +0x00,/*85*/ +0x00,/*86*/ +0x00,/*87*/ +0x00,/*88*/ +0x00,/*89*/ +0x00,/*8A*/ +0x00,/*8B*/ +0x00,/*8C*/ +0x00,/*8D*/ +0x00,/*8E*/ +0x00,/*8F*/ +0x00,/*90*/ +0x00,/*91*/ +0x00,/*92*/ +0x00,/*93*/ +0x00,/*94*/ +0x00,/*95*/ +0x00,/*96*/ +0x00,/*97*/ +0x00,/*98*/ +0x00,/*99*/ +0x00,/*9A*/ +0x00,/*9B*/ +0x00,/*9C*/ +0x00,/*9D*/ +0x00,/*9E*/ +0x00,/*9F*/ +0xC4,/*A0 L = 1, E = 0, D = 1*/ +0x00,/*A1*/ +0x00,/*A2*/ +0x00,/*A3*/ +0x00,/*A4*/ +0x00,/*A5*/ +0x00,/*A6*/ +0x00,/*A7*/ +0x00,/*A8*/ +0x00,/*A9*/ +0x00,/*AA*/ +0x00,/*AB*/ +0x00,/*AC*/ +0x00,/*AD*/ +0x00,/*AE*/ +0x00,/*AF*/ +0x00,/*B0*/ +0x00,/*B1*/ +0x00,/*B2*/ +0x00,/*B3*/ +0x00,/*B4*/ +0x00,/*B5*/ +0x00,/*B6*/ +0x00,/*B7*/ +0x00,/*B8*/ +0x00,/*B9*/ +0x00,/*BA*/ +0x00,/*BB*/ +0x00,/*BC*/ +0x00,/*BD*/ +0x00,/*BE*/ +0x00,/*BF*/ +0xEB,/*C0 L = 1, E = 1, D = 0*/ +0x00,/*C1*/ +0x00,/*C2*/ +0x00,/*C3*/ +0x00,/*C4*/ +0x00,/*C5*/ +0x00,/*C6*/ +0x00,/*C7*/ +0x00,/*C8*/ +0x00,/*C9*/ +0x00,/*CA*/ +0x00,/*CB*/ +0x00,/*CC*/ +0x00,/*CD*/ +0x00,/*CE*/ +0x00,/*CF*/ +0x00,/*D0*/ +0x00,/*D1*/ +0x00,/*D2*/ +0x00,/*D3*/ +0x00,/*D4*/ +0x00,/*D5*/ +0x00,/*D6*/ +0x00,/*D7*/ +0x00,/*D8*/ +0x00,/*D9*/ +0x00,/*DA*/ +0x00,/*DB*/ +0x00,/*DC*/ +0x00,/*DD*/ +0x00,/*DE*/ +0x00,/*DF*/ +0xEA,/*E0 L = 1, E = 1, D = 1*/ +0x00,/*E1*/ +0x00,/*E2*/ +0x00,/*E3*/ +0x00,/*E4*/ +0x00,/*E5*/ +0x00,/*E6*/ +0x00,/*E7*/ +0x00,/*E8*/ +0x00,/*E9*/ +0x00,/*EA*/ +0x00,/*EB*/ +0x00,/*EC*/ +0x00,/*ED*/ +0x00,/*EE*/ +0x00,/*EF*/ +0x00,/*F0*/ +0x00,/*F1*/ +0x00,/*F2*/ +0x00,/*F3*/ +0x00,/*F4*/ +0x00,/*F5*/ +0x00,/*F6*/ +0x00,/*F7*/ +0x00,/*F8*/ +0x00,/*F9*/ +0x00,/*FA*/ +0x00,/*FB*/ +0x00,/*FC*/ +0x00,/*FD*/ +0x00,/*FE*/ +0x00/*FF*/ +}; +/* **************************************************************************** + * Function Section + *****************************************************************************/ + +/* ***************************************************************************/ +/**Opens an SDMA channel to be used by the library. + * + * Algorithm:\n + * + * - Check if initialization is necessary. + * - Check that user initialized OS dependant functions. + * - Test validity of input parameters + * - Check whole channel control block data structure + * - Finish initializations (tables with default values) + * - Initialize channel 0 is dedicated to communications with SDMA + * - Check channel control block definition + * - if the channel descriptor is not initialized, initialize it with + * the default value + * - If buffer descriptor already allocated, exit with iapi_errno filled + * complete the lowest bits with the number of 'D' bits set + * - Buffer Descriptors allocation + * - Channel's configuration properties (mcu side only) + * - read/write direction => enable/disable channel setting + * + * @param *cd_p -If channelNumber is 0, it is pointer to channel descriptor for the channnel 0 to be opened and + has default values. + * For other channels,this function should be called after channel 0 has been opened, and it is channel descriptor for + channel 0.Must be allocated. + * @param channelNumber channel to be opened + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : close failed, return negated value of iapi_errno + */ +int +iapi_Open (channelDescriptor * cd_p, unsigned char channelNumber) +{ + channelControlBlock * ccb_p; + channelControlBlock * local_ccb_p; + channelDescriptor * local_cd_p; + bufferDescriptor * bd_p; + unsigned char index = 0; + int result = IAPI_SUCCESS; +#ifdef MCU + volatile unsigned long * channelPriorityMatx; +#endif /* MCU */ + + + /* + * 1. Check if initialization is necessary + */ + if (cd_p == NULL){ + result = IAPI_ERR_CD_UNINITIALIZED | + IAPI_ERR_CH_AVAILABLE | channelNumber; + iapi_errno = result; + return -result; + } + + /* Verify these functions every time*/ + if((iapi_GetChannel == NULL)||(iapi_ReleaseChannel == NULL)) + { + result = IAPI_ERR_NO_OS_FN | channelNumber; + iapi_errno = result; + return -result; + } + + /* Try to aquire channel*/ + if(iapi_GetChannel(channelNumber) != 0) + { + result = IAPI_ERR_CH_IN_USE | channelNumber; + iapi_errno = result; + return -result; + } + + if (channelNumber == 0 && cd_p->ccb_ptr == NULL){ + /* Verify that the user initialized all OS dependant functions required + * by the library. + */ + if((iapi_Malloc == NULL)||(iapi_Free == NULL)||(iapi_Virt2Phys == NULL)|| + (iapi_Phys2Virt == NULL)||(iapi_GotoSleep == NULL)|| + (iapi_WakeUp == NULL)||(iapi_InitSleep == NULL)||(iapi_memset == NULL)|| + (iapi_memcpy == NULL)) + { + result = IAPI_ERR_NO_OS_FN | channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + /* Whole channel control block data structure */ + ccb_p = (channelControlBlock *) + MALLOC(CH_NUM*sizeof(channelControlBlock), SDMA_IRAM); + if (ccb_p == NULL){ + result = IAPI_ERR_CCB_ALLOC_FAILED | + IAPI_ERR_CH_AVAILABLE | channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + /* Zero-out the CCB structures array just allocated*/ + iapi_memset(ccb_p, 0x00, CH_NUM*sizeof(channelControlBlock)); + /* Save the address of the CCB structures array*/ + iapi_CCBHead = ccb_p; + + cd_p->ccb_ptr = (struct iapi_channelControlBlock *)ccb_p; + ccb_p->channelDescriptor = cd_p; +#ifdef MCU + /* finish initializations */ + iapi_InitChannelTables(); +#endif /* MCU */ + /* Channel 0 is dedicated to communications with SDMA */ + cd_p->ownership = ((DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT ) | + ( OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU ) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP )); + cd_p->bufferDescNumber = 1; + } + + /* + * 2. Check channel control block + */ + ccb_p = cd_p->ccb_ptr; + if (ccb_p == NULL){ + result = IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE|channelNumber; + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + local_ccb_p = &ccb_p[channelNumber]; + local_cd_p = ccb_p[channelNumber].channelDescriptor; + + /* If the channel is not initialized, initialize it with the default value */ + if (local_cd_p == NULL){ + result = iapi_AllocChannelDesc (&local_cd_p, channelNumber); + if ( result!= IAPI_SUCCESS) + { + iapi_ReleaseChannel(channelNumber); + return result; //is allready negated from iapi_AllocChannelDesc + } + + local_cd_p->ccb_ptr = (struct iapi_channelControlBlock *)local_ccb_p; + local_ccb_p->channelDescriptor = local_cd_p; + } + + /* + * 3. If buffer descriptor already allocated, exit with iapi_errno filled + */ + if ( local_ccb_p->baseBDptr != NULL ){ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(local_ccb_p->baseBDptr); + result = IAPI_ERR_BD_ALLOCATED; + for (index=1 ; index< local_cd_p->bufferDescNumber ; index++){ + if ((bd_p->mode.status & BD_DONE) == BD_DONE){ + /* complete the lowest bits with the number of 'D' bits set */ + result++; + } + bd_p++; + } + iapi_errno = result; + iapi_ReleaseChannel(channelNumber); + return -result; + } + + /* + * 4. Buffer Descriptors allocation + */ + iapi_InitializeMemory(local_ccb_p); + +#ifdef MCU + /* + * 5. Channel's configuration properties (mcu side only) + */ + iapi_ChannelConfig( channelNumber, + ( local_cd_p->ownership >> CH_OWNSHP_OFFSET_EVT ) & 1UL, + ( local_cd_p->ownership >> CH_OWNSHP_OFFSET_MCU ) & 1UL, + ( local_cd_p->ownership >> CH_OWNSHP_OFFSET_DSP ) & 1UL); +#endif /* MCU */ + + /* Setting interrupt handling */ + iapi_ChangeCallbackISR(local_cd_p, local_cd_p->callbackISR_ptr); + + /* Call initialization fn for polling synch on this channel*/ + INIT_SLEEP(channelNumber); + + /* No user arg pointer yet*/ + userArgTable[cd_p->channelNumber]= NULL; + + /* + * 6. read/write direction => enable/disable channel + */ +#ifdef MCU + channelPriorityMatx = &SDMA_CHNPRI_0; + channelPriorityMatx[channelNumber] = 1; +#endif /* MCU */ + + local_ccb_p->status.openedInit = TRUE; + iapi_ReleaseChannel(channelNumber); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/** Attempts to read nbyte from the data buffer descriptor associated with the + * channel channelNumber, into the user's data buffer pointed to by buf. + * + * Algorithm:\n + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Control block & Descriptor associated with the channel being worked on + * - Check initialization has been done for trusted channels + * - If transfer data size is used, check validity of combination transfer + * size/requested bytes + * - Set the 'D' done bits on all buffer descriptors + * - Starting of the channel + * - Synchronization mechanism handling: + * - for callback: just exit function + * - for polling: call the synchronization function then read data from + * buffer until either nbyte parameter is reached or all buffer descriptors + * have been processed. + * + * Notes:\n + * 1) Virtual DMA SDMA channels are unidirectional, an iapi_Read authorized + * on a channel means that we are expecting to receive from the SDMA. The + * meaning of an interrupt received from the SDMA is therefore that the + * data has been copied from the SDMA to the host's data buffers and is + * already passed on upper layers of the application.\n + * + * @param *cd_p chanenl descriptor for the channel to read from + * @param *buf buffer to receive the data + * @param nbyte number of bytes to read from channel + * + * @return + * - number of bytes read + * - -iapi_errno : in case of failure return negated value of iapi_errno + */ +int +iapi_Read (channelDescriptor * cd_p, void * buf, unsigned short nbyte) +{ + int index = 0; + int readBytes; + int toRead; + int result = IAPI_SUCCESS; + unsigned int copyFinished; + int bufsize; + bufferDescriptor * bd_p; + channelControlBlock * ccb_p; + unsigned char * local_buf; + unsigned char chNum; + unsigned char div; + + iapi_errno = IAPI_ERR_NO_ERROR; + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL){ + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL){ + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Try to aquire channel*/ + if(iapi_GetChannel(chNum) != 0) + { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* Check if channel is already opened/initialized */ + if (ccb_p->status.openedInit == FALSE) { + result = IAPI_ERR_CHANNEL_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Buffer descriptor validity */ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL ){ + result = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + + /* Check initialization has been done for trusted channels */ + if (cd_p->trust == TRUE) { + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + for(index=0 ; index < cd_p->bufferDescNumber ; index++){ + if ((bd_p->bufferAddr == NULL) || (bd_p->mode.count == 0)){ + result = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + /*If transfer data size is used, check that the required read length is + * divisible by transfer data size expressed in bytes + */ + if(cd_p->useDataSize) + { + /*Check for divisibility only if data size different then 8bit*/ + if(cd_p->dataSize != TRANSFER_8BIT) + { + switch(cd_p->dataSize) + { + case TRANSFER_32BIT: + div = 4; + break; + case TRANSFER_16BIT: + div = 2; + break; + case TRANSFER_24BIT: + div = 3; + break; + /*we should not get to default*/ + default: + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*check the total number of bytes requested*/ + if((nbyte % div) != 0) + { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*now check the length of every BD*/ + for(index=0 ; index < cd_p->bufferDescNumber ; index++) + { + if((bd_p->mode.count % div) != 0) + { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + } + + /* + * 2. Set the 'D' done bits on all buffer descriptors + */ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + for (index=0 ; index < cd_p->bufferDescNumber ; index++) { + bd_p->mode.status |= BD_DONE; + bd_p++; + } + + /* + * 3. Starting of the channel + */ + iapi_lowStartChannel (chNum); + ccb_p->status.execute = TRUE; + readBytes = 0; + + /* + * 4. Synchronization mechanism handling + */ + if( cd_p->callbackSynch == DEFAULT_POLL){ + iapi_SynchChannel(chNum); + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + toRead = nbyte; + copyFinished = FALSE; + local_buf = (unsigned char *)buf; + + /* + * Check the 'RROR' bit on all buffer descriptors, set error number + * and return IAPI_FAILURE if set. + */ + for (index=0 ; index < cd_p->bufferDescNumber ; index++) + { + if(bd_p->mode.status & BD_RROR) + { + result = IAPI_ERR_RROR_BIT_READ | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + + + /* + * 5. Read loop + */ + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + while (!copyFinished) + { + if (!(bd_p->mode.status & BD_DONE)) + { + if (cd_p->trust == FALSE) { + bufsize = cd_p->bufferSize; + } else { + bufsize = bd_p->mode.count; + } + /*if L bit is set, read only "count" bytes and exit the loop*/ + if(bd_p->mode.status & BD_LAST) + { + bufsize = bd_p->mode.count; + copyFinished = TRUE; + } + if (toRead > bufsize) + { + if (cd_p->trust == FALSE) + { + iapi_memcpy(local_buf, iapi_Phys2Virt(bd_p->bufferAddr), bufsize); + local_buf += bufsize; + } + readBytes += bufsize; + toRead -= bufsize; + /*advance bd_p only if bit L is not set. The loop will exit anyway.*/ + if(!(bd_p->mode.status & BD_LAST)) + { + if (bd_p->mode.status & BD_WRAP) + { + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + } + else if(((bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr) + + (cd_p->bufferDescNumber - 1)*sizeof(bufferDescriptor)) != bd_p) + { + bd_p++; + } + else + { + /* finished here : end of buffer descriptors */ + copyFinished = TRUE; + } + } + } + else + { + if (cd_p->trust == FALSE) + { + iapi_memcpy(local_buf, iapi_Phys2Virt(bd_p->bufferAddr), toRead); + local_buf += toRead; + } + readBytes += toRead; + toRead = 0; + /* finished successfully : readBytes = nbytes */ + copyFinished = TRUE; + } + } + else + { + /* finished here : buffer not already done*/ + copyFinished = TRUE; + } + } + iapi_ReleaseChannel(chNum); + } + + /* + *If synchronization type is callback, the user of I.API must + *release the channel + */ + return readBytes; +} + +/* ***************************************************************************/ +/*Attempts to write nbyte from the buffer pointed to by buf to the channel + * data buffers associated with the opened channel number channelNumber + * + * Algorithm:\n + * + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Channel control block validity + * - Buffer descriptor validity + * - If transfer data size is used, check validity of combination transfer + * size/requested bytes + * - Write loop\n + * Write occurs in the buffer acceded form buffer descriptor and continues + * to the "next" buffer which can be:\n + * -# the last BD of the ring so re-start from beginning\n + * -# the last BD of the BD array but no ring so finish\n + * -# (general case) the next BD in the BD array\n + * And copy continues until data fit in the current buffer or the nbyte + * parameter is reached. + * - Starting of the channel + * + * Notes:\n + * 1) Virtual DMA SDMA channels are unidirectionnal, an iapi_Write authorized + * on a channel means that we are expecting to send to the SDMA. The + * meaning of an interrupt received from the SDMA is therfore that the + * data has been delivered to the SDMA. + * + * @param *cd_p chanenl descriptor for the channel to write to + * @param *buf buffer with data to be written + * @param nbyte number of bytes to write to channel + * + * @return + * - number of bytes written + * - -iapi_errno if failure + */ +int +iapi_Write (channelDescriptor * cd_p, void * buf, unsigned short nbyte) +{ + unsigned int writtenBytes = 0; + unsigned int toWrite; + int result = IAPI_SUCCESS; + unsigned int copyFinished; + unsigned int buffsize; + unsigned int index = 0; + bufferDescriptor * bd_p; + channelControlBlock * ccb_p; + unsigned char * local_buf; + unsigned char chNum; + unsigned char div; + + iapi_errno = IAPI_ERR_NO_ERROR; + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL){ + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL){ + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptpor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Try to aquire channel*/ + if(iapi_GetChannel(chNum) != 0) + { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* Buffer descriptor validity */ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL ){ + result = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + + /* Check initialization has been done for trusted channels */ + if (cd_p->trust == TRUE) { + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + for(index=0 ; index < cd_p->bufferDescNumber ; index++){ + if ((bd_p->bufferAddr == NULL) || (bd_p->mode.count == 0)){ + result = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + /*If transfer data size is used, check that the required write length is + * divisible by transfer data size expressed in bytes + */ + if(cd_p->useDataSize) + { + /*Check for divisibility only if data size different then 8bit*/ + if(cd_p->dataSize != TRANSFER_8BIT) + { + switch(cd_p->dataSize) + { + case TRANSFER_32BIT: + div = 4; + break; + case TRANSFER_16BIT: + div = 2; + break; + case TRANSFER_24BIT: + div = 3; + break; + /*we should not get to default*/ + default: + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*check the total number of bytes requested*/ + if((nbyte % div) != 0) + { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + /*now check the length of every BD*/ + for(index=0 ; index < cd_p->bufferDescNumber ; index++) + { + if((bd_p->mode.count % div) != 0) + { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + } + + /* + * 2. Write loop + */ + + local_buf = (unsigned char *)buf; + toWrite = nbyte; + copyFinished = FALSE; + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + + while (!copyFinished){ + + /* variable buffsize contains the nb of bytes that the SDMA will transfer at each pass of the while loop*/ + + /* in NON trusted mode, buffsize is copied from Channel descriptor bufferSize (same size for all transfers) */ + if (cd_p->trust == FALSE) { + buffsize = cd_p->bufferSize; + } + /* in TRUSTED mode, it's up to the user to specify the size of each buffer thru an IoCtl call */ + /* This IoCtl has directly modified the bd_p->mode.count */ + /* therefore, buffersize is copied from the bd_p->mode.count */ + else { + buffsize = bd_p->mode.count; + } + + /* in any mode (trusted or non trusted), the transfer size must be overridden by */ + /* "toWrite" when there is less remaining bytes to transfer than the current buffer size */ + if (toWrite < buffsize) { + buffsize = toWrite; + } + + + if (!(bd_p->mode.status & BD_DONE)){ + /* More data to write than a single buffer can contain */ + if (cd_p->trust == FALSE ){ + iapi_memcpy(iapi_Phys2Virt(bd_p->bufferAddr), local_buf, buffsize); + local_buf += buffsize; + } + + /* update the BD count that will be used by the SDMA to transfer the proper nb of bytes */ + bd_p->mode.count = buffsize; + + bd_p->mode.status |= BD_DONE; + writtenBytes += buffsize; + toWrite -= buffsize; + /* Prepares access to the "next" buffer */ + /* - case 1 - finished successfully : writtenBytes = nbytes */ + if (toWrite == 0) { + copyFinished = TRUE; + } + /* - case 2 - Last BD and WRAP bit set so re-start from beginning */ + /*else if ((bd_p->mode.status & BD_WRAP)){ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + }*/ + /* - case 3 - Last BD of the BD but nor ring*/ + else if (((bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr) + + (cd_p->bufferDescNumber - 1) * sizeof(bufferDescriptor)) == bd_p){ + copyFinished = TRUE; + } + /* - case 4 - general : next BD in the BD array */ + else { + bd_p++; + } + + } else { + /* finished here : buffer not already done */ + copyFinished = TRUE; + } + } + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + /* + * 3. Starting of the channel + */ + iapi_lowStartChannel(chNum); + ccb_p->status.execute = TRUE; + + if( cd_p->callbackSynch == DEFAULT_POLL) + { + iapi_SynchChannel(chNum); + /* + * Check the 'RROR' bit on all buffer descriptors, set error number + * and return IAPI_FAILURE if set. + */ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + for (index=0 ; index < cd_p->bufferDescNumber ; index++) + { + if(bd_p->mode.status & BD_RROR) + { + result = IAPI_ERR_RROR_BIT_WRITE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + iapi_ReleaseChannel(chNum); + } + + /* + *If synchronization type is callback, the user of I.API must + *release the channel + */ + return writtenBytes; +} + + + + +/* ***************************************************************************/ +/* This function is used to receive data from the SDMA. + * + * Algorithm:\n + * + * The data control structure would be copied to IPCv1 complied Buffer + * Descriptor Array. This array shall be allocated from non cacheable memory. + * It would then provide this buffer descriptor array as an input to SDMA using + * channel control block and then configure the Host Enable (HE) or + * DSP enable (DE) bit of SDMA for the channel used for this transfer depending + * on the source. + * + * Notes:\n + * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized + * on a channel means that source processor is expecting to send to the destination + * processor. The meaning of an interrupt received from the SDMA notifies that the + * data has been delivered to the destination processor. + * + * @param *cd_p chanenl descriptor for the channel to receive from + * @param *data_control_struct_ipcv2 + + * Data Control structure: + * ------------------------- + * | Data Node Descriptor 1| + * ------------------------- + * | Data Node Descriptor 2| + * ------------------------- + * | : | + * | : | + * ------------------------- + * |Data Node Descriptor n | + * ------------------------- + * + * Data Node Descriptor (Buffer Descriptor): + *------------------------------------------------------------------------------ + *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 … 0| + *------------------------------------------------------------------------------ + *| L E D R R R R R |<---- Reserved ----> |<- Length-> | + *------------------------------------------------------------------------------ + *| <---------------------------- Data Ptr ----------------------------------->| + *------------------------------------------------------------------------------ + * + * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame + * E bit (END): If set, we reached the end of the buffers passed to the function + * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been + * filled by the SDMA. + * Length: Length of data pointed by this node in bytes + * Data Ptr: Pointer to the data pointed to by this node. + * The Function Shall not be called for the same channel unless the Read callback has been + * received for channel for which it has been called already. + * + * @return + * - IAPI_SUCCESS on success, IAPI_ERROR otherwise + * + *- -iapi_errno if failure + */ + +int iapi_Read_ipcv2( channelDescriptor * cd_p, void * data_control_struct_ipcv2) +{ + channelControlBlock * ccb_p; + + +/* The Parameters passed are considered to be validated by the upper layers*/ + + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p; + dataNodeDescriptor *dnd_p = (dataNodeDescriptor*)data_control_struct_ipcv2; + + ccb_p = cd_p->ccb_ptr; + iapi_errno = IAPI_ERR_NO_ERROR; + + if(ccb_p->baseBDptr == NULL) +{ + iapi_errno = IAPI_ERR_BD_UNINITIALIZED; + return -(IAPI_ERR_BD_UNINITIALIZED); +} + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + /* Copy the data Node descriptor information to new BDs */ + bd_ipcv2_p = (bufferDescriptor_ipcv1_v2*)iapi_Phys2Virt(ccb_p->baseBDptr); + + while(1) + { + bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr; + bd_ipcv2_p->mode.count = dnd_p->mode.count; +#ifdef MCU + bd_ipcv2_p->mode.endianness = 1; +#endif +#ifdef DSP + bd_ipcv2_p->mode.endianness = 0; +#endif + + bd_ipcv2_p->mode.status = dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK]; + + if((dnd_p->mode.status & DND_END_OF_XFER) != 0) + { + /* Break the loop at End of Transfer */ + break; + + } + bd_ipcv2_p++; + dnd_p++; + + } + /* + * Store the buffer address + */ + dnd_read_control_struct[cd_p->channelNumber] = (dataNodeDescriptor*)data_control_struct_ipcv2; + /* + * Register the Call Back + */ + + iapi_AttachCallbackISR(cd_p, iapi_read_ipcv2_callback); + + /* + * Starting of the channel + */ + iapi_lowStartChannel(cd_p->channelNumber); + ccb_p->status.execute = TRUE; + + return IAPI_SUCCESS; + +} + + +/* ***************************************************************************/ +/* + * The function is used send a group of buffers to SDMA. + * Algorithm:\n + * + * The data control structure would be copied to IPCv1 complied Buffer + * Descriptor Array. This array shall be allocated from non cacheable memory. + * It would then provide this buffer descriptor array as an input to SDMA using + * channel control block and then configure the Host Enable (HE) or + * DSP enable (DE) bit of SDMA for the channel used for this transfer depending + * on the source. + * The Function Shall not be called for the same channel unless the Read callback has been + * received for channel for which it has been called already. + * + * Notes:\n + * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized + * on a channel means that source processor is expecting to send to the destination + * processor. The meaning of an interrupt received from the SDMA notifies that the + * data has been delivered to the destination processor. + * + * @param *cd_p chanenl descriptor for the channel to write to + * @param *data_control_struct_ipcv2 + + * Data Control structure: + * ------------------------- + * | Data Node Descriptor 1| + * ------------------------- + * | Data Node Descriptor 2| + * ------------------------- + * | : | + * | : | + * ------------------------- + * |Data Node Descriptor n | + * ------------------------- + * + * Data Node Descriptor (Buffer Descriptor): + *------------------------------------------------------------------------------ + *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 … 0| + *------------------------------------------------------------------------------ + *| L E D R R R R R |<---- Reserved ----> |<- Length-> | + *------------------------------------------------------------------------------ + *| <---------------------------- Data Ptr ----------------------------------->| + *------------------------------------------------------------------------------ + * + * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame + * E bit (END): If set, we reached the end of the buffers passed to the function + * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been + * filled by the SDMA. + * Length: Length of data pointed by this node in bytes + * Data Ptr: Pointer to the data pointed to by this node. + * + * + * @return + * - iapi sucess on success. + * - -iapi_errno if failure + */ + +int iapi_Write_ipcv2( channelDescriptor * cd_p, void * data_control_struct_ipcv2) +{ + + channelControlBlock * ccb_p; + +/* The Parameters passed are considered to be validated by the upper layers*/ + + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p; + dataNodeDescriptor *dnd_p = (dataNodeDescriptor*)data_control_struct_ipcv2; + ccb_p = cd_p->ccb_ptr; + iapi_errno = IAPI_ERR_NO_ERROR; + + if(ccb_p->baseBDptr == NULL) +{ + iapi_errno = IAPI_ERR_BD_UNINITIALIZED; + return -(IAPI_ERR_BD_UNINITIALIZED); +} + + + ccb_p->currentBDptr = ccb_p->baseBDptr; + + bd_ipcv2_p = (bufferDescriptor_ipcv1_v2*)iapi_Phys2Virt(ccb_p->currentBDptr); + /* Copy the data Node descriptor information to new BDs */ + while(1) + { + bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr; + bd_ipcv2_p->mode.count = dnd_p->mode.count; + +#ifdef MCU + bd_ipcv2_p->mode.endianness = 1; +#endif +#ifdef DSP + bd_ipcv2_p->mode.endianness = 0; +#endif + + bd_ipcv2_p->mode.status = dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK]; + + if((dnd_p->mode.status & DND_END_OF_XFER) != 0) + { + /* Break the loop at End of Transfer */ + break; + } + bd_ipcv2_p++; + dnd_p++; + + } + + /* + * Starting of the channel + */ + iapi_lowStartChannel(cd_p->channelNumber); + ccb_p->status.execute = TRUE; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/** Call back ISR for the IPCv2 Receive. + * + * Algorithm:\n + * - This would copy back the informationfrom IPCv1 BD to IPCv2 BD on + * the receiving processor + * + * @return + * - void + */ + +void iapi_read_ipcv2_callback(struct iapi_channelDescriptor* cd_p, void* data) +{ + dataNodeDescriptor *dnd_p = dnd_read_control_struct[cd_p->channelNumber];//cd_p->ccb_ptr->channelDNDBuffer; + bufferDescriptor_ipcv1_v2 *bd_ipcv2_p = (bufferDescriptor_ipcv1_v2*)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + int index = MAX_BD_NUM - 1; + + + do + { + dnd_p->mode.status = 0; + dnd_p->mode.count = bd_ipcv2_p->mode.count; + + dnd_p->mode.status |= bd_ipcv2_p->mode.status & BD_DONE ? 0x00 : DND_DONE ; + dnd_p->mode.status |= bd_ipcv2_p->mode.status & BD_IPCV2_END_OF_FRAME ? DND_END_OF_FRAME : 0x00; + dnd_p->mode.status |= bd_ipcv2_p->mode.status & BD_LAST ? DND_END_OF_XFER : 0x00; + cd_p->ccb_ptr->currentBDptr = (bufferDescriptor*)iapi_Virt2Phys(bd_ipcv2_p); + + if((bd_ipcv2_p->mode.status & BD_LAST) != 0 || + (bd_ipcv2_p->mode.status & BD_CONT) == 0 + ) + break; + dnd_p++; + bd_ipcv2_p++; + + }while(index--); + + /*Call back the Original ISR */ + cd_p->callbackISR_ptr(cd_p, data); +} + +/* ***************************************************************************/ +/**Terminates a channel. + * + * Algorithm:\n + * - Check input parameters ans data structures + * - Check that all buffes have been processed (test all 'D' bits) + * - Stop the channel execution + * - Free alocated memory structures + * - Re-instantiate default interrupt handling + * + * @param *cd_p chanenl descriptor for the channel to close + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : close failed + */ +int +iapi_Close (channelDescriptor * cd_p) +{ + int index = 0; + int result = IAPI_SUCCESS; + unsigned char chNum; + bufferDescriptor * bd_p; + channelControlBlock * ccb_p; + + /* + * 1. Check input parameters ans data structures + */ + if (cd_p != NULL){ + if (cd_p->ccb_ptr != NULL) { + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + } else { + result = IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE; + iapi_errno = result; + return -result; + } + } else { + result = IAPI_ERR_CD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE; + iapi_errno = result; + return -result; + } + /* Try to aquire channel*/ + if(iapi_GetChannel(chNum) != 0) + { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* + * 2. Check that all buffes have been processed (test all 'D' bits), + * only if the forceClose bit in channel descriptor is set to FALSE + */ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + if (bd_p == NULL){ + result = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + if(cd_p->forceClose == FALSE) + { + for (index=cd_p->bufferDescNumber ; index>0 ; index--){ + if (bd_p->mode.status & BD_DONE){ + result = IAPI_ERR_CLOSE | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } + bd_p++; + } + } + /*if the closing is forced,mark channel unused,set BD ownership to processor*/ + else + { + ccb_p->status.execute = FALSE; + for (index=cd_p->bufferDescNumber ; index>0 ; index--) + { + bd_p->mode.status &= ~BD_DONE; + bd_p++; + } + } + + /* + * 3. Stop the channel execution + */ + iapi_lowStopChannel(chNum); + + /* + * 4. Free alocated memory structures + */ + if (cd_p->trust == FALSE ){ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr); + for (index=cd_p->bufferDescNumber ; index>0 ; index--){ + FREE (iapi_Phys2Virt(bd_p->bufferAddr)); + bd_p++; + } + } + + /* + * 5. Re-instantiate default interrupt handling + */ + iapi_DetachCallbackISR (cd_p); + FREE ((bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr)); + FREE (cd_p); + ccb_p->baseBDptr = NULL; + ccb_p->currentBDptr = NULL; + ccb_p->channelDescriptor = NULL; + ccb_p->status.openedInit = FALSE; + + iapi_ReleaseChannel(chNum); + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**The request argument selects the control function to be performed. + * + * Algorithm:\n + * + * - Check data structures are properly initialized: + * - Channel descriptor validity + * - Channel control block validity + * - The ctlRequest parameter contains in the lower 16 bits the control code of + * the change to be performed, and in the upper 16 bits, the BD to be + * modified if the change affects a BD od the channel. + * - Selection of the parameter to change and appropriate sanity checks: + * - Channel Descriptor: changes the pointer to the channel descriptor + * structure, the pointer to the new channel descriptor is given in the third + * argument call + * - Buffer Descriptor Number: changes the number of buffer descriptor for the + * channel + * - Buffer size: changes the size of the data buffers pointed to by the + * buffer descriptor; note that all buffer descriptors are assumed to have the + * same size for a given buffer descripotr chain + * - Blocking policy: changes the blocking policy for the read and write calls + * - Ownership: changes direction: turnaround + * - Synchronization method: changes the callback type, default or user. The* + * callback function table is set accordingly + * - Trust property: trust can only be changed through ChangeChannelDesc first + * request, this guarantees the close/open sequence for the channel + * - Callback Interrupt service routine pointer: changes the callback function + * pointer, when this method is used, to replace it with a new one + * - Channel control block pointer: not available + * - Priority: changes the channel priority directly in SDMA register + * - Watermark level: changes the value of the peripheral watermark level that + * passed to the script. The new value is passed in the third parameter call. + * - Wrap bit: changes to set to 1 the Wrap bit of the last buffer descriptor + * + * @param *cd_p channel descriptor for the channel to modify + * @param ctlRequest request control code and, if tha case, number of BD to be + * changed + * @param param parameter for the modification + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed + */ +int +iapi_IoCtl (channelDescriptor * cd_p, unsigned long ctlRequest, + unsigned long param) +{ + int retvalue; + int result = IAPI_SUCCESS; + unsigned char chNum; + unsigned long clean_ctlRequest; /* lower 16 bits of the ctlRequest*/ + unsigned long bd_num; /* upper 16 bits of the ctlRequest*/ + + /* + * 1. Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL){ + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL){ + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + + /* Remove, if exists, BD number specified in upper bits of ctlRequest*/ + clean_ctlRequest = ctlRequest & (~BD_NUM_MASK); + + /* Extract, if exists, BD number specified in upper bits of ctlRequest*/ + bd_num = (ctlRequest & BD_NUM_MASK) >> BD_NUM_OFFSET; + + /* Check that the bd_num is valid*/ + if(bd_num > cd_p->bufferDescNumber) + { + result = IAPI_ERR_INVALID_PARAMETER | chNum; + iapi_errno = result; + return -result; + } + + /*All checks OK, try to aquire channel*/ + if(iapi_GetChannel(chNum) != 0) + { + result = IAPI_ERR_CH_IN_USE | chNum; + iapi_errno = result; + return -result; + } + + /* + * 2. Selection of the parameter to change and appropriate sanity checks + */ + switch (clean_ctlRequest){ + + /* + * Channel Descriptor + * --- Changes the pointer to the channel descriptor structure: the pointer + * to the new channel descriptor is given in the third argument call. + */ + case IAPI_CHANGE_CHANDESC: + if ((void *) param == NULL) { + result = IAPI_ERR_INVALID_PARAMETER; + iapi_errno = result; + iapi_ReleaseChannel(chNum); + return -result; + } else { + channelDescriptor * chParam = (channelDescriptor *)param; + if (chParam->channelNumber != chNum){ + /* Release ch so it can be aquired by the Close fn*/ + iapi_ReleaseChannel(chNum); + result = iapi_Close(cd_p); + if (result == IAPI_SUCCESS){ + FREE((void*)cd_p); + iapi_AllocChannelDesc (&cd_p, chParam->channelNumber); + iapi_memcpy((void*)cd_p, (void*)chParam, sizeof (channelDescriptor)); + /* Channel is released allready, so Open can get the channel*/ + result = iapi_Open(cd_p, chParam->channelNumber); + if(result != IAPI_SUCCESS) + { + return result; /* error code already set in iapi_Open*/ + } + } else { + return result; /* error code already set in iapi_Close*/ + } + } else { + result = IAPI_ERR_CD_CHANGE | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_ReleaseChannel(chNum); + iapi_errno = result; + return -result; + } + return IAPI_SUCCESS; + } + + /* + * Buffer Descriptor Number + * --- Changes the number of buffer descriptor for the channel. + */ + case IAPI_CHANGE_BDNUM: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Buffer size + * --- Changes the size of the data buffers pointed to by the buffer + * descriptor; note that all buffer descriptors are assumed to have the + * same size for a given buffer descripotr chain. + */ + case IAPI_CHANGE_BUFFSIZE: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Blocking policy + * --- Changes the blocking policy for the read and write calls. + */ + case IAPI_CHANGE_CHANBLOCK: + result = iapi_ChangeChannelDesc(cd_p, IAPI_BLOCKING, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Ownership + * --- Changes direction: turnaround + */ + case IAPI_CHANGE_OWNERSHIP: + result = iapi_ChangeChannelDesc(cd_p, IAPI_OWNERSHIP, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Synchronization method + * --- Changes the callback type, default or user. The callback function + * table is set accordingly. + */ + case IAPI_CHANGE_SYNCH: + result = iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKSYNCH, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Trust property + * --- trust can only be changed through ChangeChannelDesc first request, + * this guarantees the close/open sequence for the channel. + */ + case IAPI_CHANGE_TRUST: + result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Callback Interrupt service routine pointer + * --- Cahnges the callback function pointer, when this method is used, to + * replace it with a new one. + */ + case IAPI_CHANGE_CALLBACKFUNC: + result = iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKISR_PTR, param); + iapi_ReleaseChannel(chNum); + return result; + + /* + * Channel control block pointer + * --- NA + */ + case IAPI_CHANGE_CHANCCB: + result = iapi_ChangeChannelDesc(cd_p, IAPI_CCB_PTR, param); + iapi_ReleaseChannel(chNum); + return result; + +#ifdef MCU + /* + * Priority + * --- Changes the channel priority directly in SDMA register + */ + case IAPI_CHANGE_PRIORITY: + { + volatile unsigned long * ChannelPriorities = &SDMA_CHNPRI_0; + if(param < MAX_CH_PRIORITY) + { + ChannelPriorities[ cd_p->channelNumber ] = param; + } + else + { + iapi_ReleaseChannel(chNum); + return IAPI_FAILURE; + } + } + break; +#endif /* MCU */ + + /* + * Wrap + * --- Set to 1 the wrap bit of the last buffer descriptor of the array. + * it provides the possibility to have a circular buffer structure. + */ + case IAPI_CHANGE_BDWRAP: + { + result = iapi_ChangeChannelDesc(cd_p,IAPI_BDWRAP , param); + iapi_ReleaseChannel(chNum); + return result; + } + + /* + * Watermark + * --- Changes the value of the peripheral watermark level that triggers + * a DMA request. It impacts context of the channel, therefore channel 0 + * must be started to update the context with this new value. + */ + case IAPI_CHANGE_WATERMARK: + { + result = iapi_ChangeChannelDesc(cd_p,IAPI_WML , param); + iapi_ReleaseChannel(chNum); + return result; + } + /* + * INTR + * --- Set the INTR bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDINTR: + { + bufferDescriptor * bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.status |= BD_INTR; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_INTR; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * INTR + * --- Unset the INTR bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDINTR: + { + bufferDescriptor * bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.status &= ~BD_INTR; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_INTR; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } +/* + * EventMask1 + * --- Changes the value of the eventMask1 + */ + case IAPI_CHANGE_EVTMASK1: + { + cd_p->eventMask1 = param; + } + break; + /* + * EventMask2 + * --- Changes the value of the eventMask2 + */ + case IAPI_CHANGE_EVTMASK2: + { + cd_p->eventMask2 = param; + } + break; + /* + * Peripheral Address + * --- Changes the value of the peripheralAddr + */ + case IAPI_CHANGE_PERIPHADDR: + { + cd_p->peripheralAddr = param; + } + break; + /* + * Cont + * --- Set the CONT bit on specified BD on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDCONT: + { + bufferDescriptor * bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.status |= BD_CONT; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_CONT; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * Cont + * --- Unset the CONT bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDCONT: + { + bufferDescriptor * bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.status &= ~BD_CONT; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_CONT; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * EXTD + * --- Set the EXTD bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_SET_BDEXTD: + { + bufferDescriptor * bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.status |= BD_EXTD; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status |= BD_EXTD; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTD + * --- Unset the EXTD bit on specified BD or on all BD's if SET_BIT_ALL + * is passed as parameter. + */ + case IAPI_CHANGE_UNSET_BDEXTD: + { + bufferDescriptor * bde_p; + + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.status &= ~BD_EXTD; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.status &= ~BD_EXTD; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + /* + * TRANSFER SIZE to be used for this channel + * --- Set the transfer size used indicator and code for transfer size in + * the CD + */ +case IAPI_CHANGE_SET_TRANSFER_CD: + { + bufferDescriptor * bde_p; + int j = 0; + retvalue = IAPI_SUCCESS; + if((param == TRANSFER_8BIT) || (param == TRANSFER_16BIT) || + (param == TRANSFER_24BIT) || (param == TRANSFER_32BIT)) + { + cd_p->useDataSize = TRUE; + cd_p->dataSize = param; + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.command = param; + bde_p++; + } + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + + + /* + * USER_ARG + * --- Set the user selectable pointer to be received by the callback + * function, if IRQ synch is used + */ + case IAPI_CHANGE_USER_ARG: + { + userArgTable[cd_p->channelNumber]= (void*)param; + iapi_ReleaseChannel(chNum); + return IAPI_SUCCESS; + } + /* + * FORCE_CLOSE + * --- Set the forceClose bit in channelDescriptor to value passed in param. + * If this bit is TRUE, the channel in closed even if some BD are still + * owned by the SDMA. + */ + case IAPI_CHANGE_FORCE_CLOSE: + { + retvalue = IAPI_SUCCESS; + if((param == TRUE) || (param == FALSE)) + { + cd_p->forceClose = param; + } + else + { + iapi_errno = IAPI_ERR_INVALID_PARAMETER | cd_p->channelNumber; + retvalue = -iapi_errno; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * TRANSFER type + * --- Set the last 2 bits in the command field of the BD to specify the + * transfer type 8, 16, 24, or 32 bits on all BD's, allready set in the CD + */ + case IAPI_CHANGE_SET_TRANSFER: + { + bufferDescriptor * bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if((param == TRANSFER_8BIT)||(param == TRANSFER_16BIT)|| + (param == TRANSFER_24BIT)||(param == TRANSFER_32BIT)) + { + bde_p = cd_p->ccb_ptr->baseBDptr; + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.command = param; + bde_p++; + } + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * BUFFER address + * --- Change buffer address in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_BUFFERADDR: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + + /* DO NOT translate address to physical */ + bde_p->bufferAddr = (void*)param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * BUFFER address + * --- Get the buffer address from the BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_GET_BUFFERADDR: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Translate to virtual*/ + *((unsigned long*)param) = (unsigned long)bde_p->bufferAddr; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTENDED BUFFER address + * --- Change extended buffer address in BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_SET_EXTDBUFFERADDR: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + + /* DO NOT translate address to physical. The user might want something else + *here + */ + bde_p->extBufferAddr = (void*)param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * EXTENDED BUFFER address + * --- Get extended buffer address from the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_EXTDBUFFERADDR: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + + /* DO NOT translate address to vitual - user knows what is here. + */ + *((unsigned long*)param) = (unsigned long)bde_p->extBufferAddr; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COMMAND field + * --- Change command field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_COMMAND: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Update command field*/ + bde_p->mode.command = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COMMAND field + * --- Get the command field from the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_COMMAND: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Get the command field*/ + *((unsigned long*)param) = bde_p->mode.command; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COUNT field + * --- Change count field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_COUNT: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Update count field*/ + bde_p->mode.count = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * COUNT field + * --- Get the count field of the BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_GET_COUNT: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Update count field*/ + *((unsigned long*)param) = bde_p->mode.count; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * STATUS field + * --- Change status field in BD specified in the upper 16 bits of the + * ctlRequest. + */ + case IAPI_CHANGE_SET_STATUS: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Update status field*/ + bde_p->mode.status = param; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + /* + * STATUS field + * --- Get the status field of the BD specified in the upper 16 bits + * of the ctlRequest. + */ + case IAPI_CHANGE_GET_STATUS: + { + bufferDescriptor * bde_p; + retvalue = IAPI_SUCCESS; + + /* Get pointer to the BD structure to change*/ + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bde_p+= bd_num; + /* Update status field*/ + *((unsigned long*)param) = bde_p->mode.status; + + iapi_ReleaseChannel(chNum); + return retvalue; + } + +#ifdef MCU + /* + * Endianness + * --- Set the ENDIANNESS indicator in the command filed of the specified BD + * or on all BD's if SET_BIT_ALL is passed as parameter. + */ + case IAPI_CHANGE_SET_ENDIANNESS: + { + bufferDescriptor * bde_p; + int j = 0; + + retvalue = IAPI_SUCCESS; + if(param == SET_BIT_ALL) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for(j = 0; j < cd_p->bufferDescNumber; j++) + { + bde_p->mode.command = CHANGE_ENDIANNESS; + bde_p++; + } + } + else if(param < cd_p->bufferDescNumber) + { + bde_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr) + + param; + bde_p->mode.command = CHANGE_ENDIANNESS; + } + else + { + retvalue = IAPI_FAILURE; + } + iapi_ReleaseChannel(chNum); + return retvalue; + } +#endif + +#ifdef SDMA_SKYE +#ifdef MCU + + /* + * SDMA State + * --- Enter the SDMA into LOCK Mode. No RAM updation allowed except same Context + * update with same PC Value. + */ + case IAPI_ENTER_LOCK_MODE: + { + if(param == RESET_CLEAR_LOCK) + { + SDMA_SDMA_LOCK = (1 << RESET_CLR_BIT_OFFSET); + SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET); + iapi_SdmaState = LOCK; + } + else if(param == RESET_NOCLEAR_LOCK) + { + SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET); + iapi_SdmaState = LOCK; + } + + } + break; + +#endif +#endif + default: + retvalue = IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = retvalue; + iapi_ReleaseChannel(chNum); + return -retvalue; + } + + + iapi_ReleaseChannel(chNum); + return IAPI_SUCCESS; +} +/* ***************************************************************************/ +/**Initialization of the SDMA - opening of channel 0, download RAM image. + * + * Algorithm:\n + * - open channel 0 + * - if ram_image pointer passed is not NULL, download RAM image to SDMA + * + * @param + * - cd_p channel descriptor pointer for channel 0 + * - ram_image pointer to RAM image to download, or NULL if this operation + * is not required + * - code_size size of the RAM image, in bytes + * - start_addr start address for the RAM image + * + * @return + * - IAPI_SUCCESS if all operations were successful + * - negated I.API error code if any operation failed + */ +#ifdef MCU +int +iapi_Init(channelDescriptor * cd_p, configs_data * config_p, unsigned short* ram_image, + unsigned short code_size, unsigned long start_addr) +{ +#endif +#ifdef DSP +int +iapi_Init(channelDescriptor * cd_p) +{ +#endif + +int retvalue = IAPI_SUCCESS; /* Variable to store the results from I.API calls */ + + /* Check initialization not allredy done*/ + if(iapi_CCBHead != NULL) + { + retvalue = IAPI_ERR_NOT_ALLOWED; + iapi_errno = retvalue; + return -retvalue; + } + /* Be sure SDMA has not started yet */ +#ifdef MCU + SDMA_H_C0PTR = 0x0; +#endif +#ifdef DSP + SDMA_D_C0PTR = 0x0; +#endif + + /*Try to open channel 0*/ + retvalue = iapi_Open(cd_p, 0); + if(retvalue != IAPI_SUCCESS) + { + return retvalue; + } + +#ifdef MCU + /* Set Command Channel (Channel Zero) */ + SDMA_CHN0ADDR = 0x4050; + + /* Set bits of CONFIG register but with static context switching */ + SDMA_H_CONFIG = (config_p->dspdma << 12) | (config_p->rtdobs << 11) | + (config_p->acr << 4) | (0); + + /* Send the address for the host channel table to the SDMA*/ + SDMA_H_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead); + /* If required, download the RAM image for SDMA*/ + if(ram_image != NULL) + { + retvalue = iapi_SetScript(cd_p, (void*)ram_image, code_size, + start_addr); + } + + /* Set bits of CONFIG register with given context switching mode */ + SDMA_H_CONFIG = (config_p->dspdma << 12) | (config_p->rtdobs << 11) | + (config_p->acr << 4) | (config_p->csm); + +#endif +#ifdef DSP + /* Send the address for the host channel table to the SDMA*/ + SDMA_D_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead); +#endif + +#ifdef SDMA_SKYE + iapi_SdmaState = OPEN; +#endif + + return retvalue; +} + + +/* ***************************************************************************/ +/**High layer interface for starting a channel + * + * Algorithm:\n + * - call low layer function for starting a channel + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_StartChannel(unsigned char channel) +{ + iapi_lowStartChannel(channel); + return IAPI_SUCCESS; +} +/* ***************************************************************************/ +/**High layer interface for stopping a channel + * + * Algorithm:\n + * - call low layer function for stopping a channel + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_StopChannel(unsigned char channel) +{ + iapi_lowStopChannel(channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for synchronising a channel + * + * Algorithm:\n + * - call low layer function for stopping a channel + * + * @return + * - IAPI_SUCCESS + */ +int iapi_SynchChannel(unsigned char channel) +{ + iapi_lowSynchChannel(channel); + return IAPI_SUCCESS; +} + +#ifdef MCU +/* ***************************************************************************/ +/**High layer interface for getting program memory data from SDMA + * + * Algorithm:\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_GetScript(channelDescriptor * cd_p, void * buf, unsigned short size, + unsigned long address) +{ + iapi_lowGetScript(cd_p, buf, size, address); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for getting data memory from SDMA + * + * Algorithm:\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_GetContext(channelDescriptor * cd_p, void * buf, + unsigned char channel) +{ + iapi_lowGetContext(cd_p, buf, channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for set program memory data to SDMA - e.g. scripts + * + * Algorithm:\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_SetScript(channelDescriptor * cd_p, void * buf, unsigned short nbyte, + unsigned long destAddr) +{ + iapi_lowSetScript(cd_p, buf, nbyte, destAddr); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface for set data memory to SDMA - e.g. contexts. + * + * Algorithm:\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_SetContext(channelDescriptor * cd_p, void * buf, + unsigned char channel) +{ + iapi_lowSetContext(cd_p, buf, channel); + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/**High layer interface used to associate specified channel with a script. + * + * Algorithm:\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_AssignScript(channelDescriptor * cd_p, script_data * data_p) +{ + /* VERIFY THAT THE CHANNEL IT IS OPENED !!!!*/ + return iapi_lowAssignScript(cd_p, data_p); +} + +/* ***************************************************************************/ +/**High layer interface used to associate specified channel with a script. + * + * Algorithm:\n + * - call coresponding low layer function + * + * @return + * - IAPI_SUCCESS + */ +int +iapi_SetChannelEventMapping(unsigned char event, unsigned long channel_map) +{ + return iapi_lowSetChannelEventMapping(event, channel_map); +} +#endif + + + +#ifdef DSP +#define SDMA_DI SDMA_D_INTR +void IRQ_Handler(); +#pragma interrupt IRQ_Handler +#endif + +#ifdef MCU +#define SDMA_DI SDMA_H_INTR +#endif + +#ifndef IRQ_KEYWORD +#define IRQ_KEYWORD +#endif /* IRQ_KEYWORD */ + +/* ***************************************************************************/ +/** + *@brief Find the first set bit in data parameter. + * + * Find the first set bit in unsigned integer parameter data. Data is scanned + * from MSB to LSB, searching for the set bit. The value returned is the + * offset from the most significant bit of data. If bit 31 is set, the value + * returned is zero. If no bits are set, a value of 32 is returned. This is compliant + * with the MCore FF1 instruction. + * + * + * + * @param + * - data: variable to check + * + * @return + * - the offset of the most significant bit set from the MSB + */ +unsigned int +quartz_FF1( unsigned int data ) +{ + register unsigned int result = 0; + while ( (result <= 31 ) && !( data & 0x80000000U) ) + { + data <<= 1U; + result++; + } + + return result; +} + +IRQ_KEYWORD +void +IRQ_Handler(void) +{ + unsigned int intrReg;/* interrupt register mask for clearing the interrupt bit */ + unsigned char chNum; /* SDMA channel number generating the a IRQ*/ + + /* Disable interrupts */ + iapi_DisableInterrupts(); + /* + * Clear interrupt in SDMA DI register => ACK to the SDMA the IT request. + * Get each interrupt number, clear them one after the other. + */ + if(SDMA_DI != 0) + { + chNum = (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI)); + intrReg = (unsigned int)(1 << chNum); + } + else + { + chNum = 32; + intrReg = 0; + } + + while (intrReg != 0) + { + SDMA_DI &= intrReg; + iapi_SDMAIntr |= intrReg; + iapi_WakeUp(chNum); + if (callbackIsrTable[chNum] != NULL) + { + /* release channel before callback, so IoCtl's are available*/ + iapi_ReleaseChannel(chNum); + callbackIsrTable[chNum](iapi_CCBHead[chNum].channelDescriptor, + userArgTable[chNum]); + } + + chNum = (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI)); + intrReg = (unsigned int)(1 << chNum); + } + + /* Enable interrupts */ + iapi_EnableInterrupts(); +} + +/* ***************************************************************************/ +/** + *@brief Perform a memory copy operation, in the memory of the same processor + * + * Size bytes are copied from the src address to dest address. It is used + * the channel pointed by cd_p, which must be configured prior to this call: + * opened, associated with the script to perform the operation - DSP_2_DSP, + * or MCU_2_MCU - and have the synchronization option set. + * + * + * + * @param + * - cd_p: channel configured to perform DSP_2_DSP or MCU_2_MCU transfers + * - dest: destination memory address + * - src : source memory address + * - size: number of bytes to copy from src to dest + * + * @return + * - the offset of the most significant bit set from the MSB + */ + +int iapi_MemCopy(channelDescriptor * cd_p, void* dest, void* src, unsigned long size) +{ + int result = IAPI_SUCCESS; + bufferDescriptor * bd_p; + + /* Channel descriptor validity */ + if (cd_p == NULL) + { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Check and set correct parameter */ + if(cd_p->trust != TRUE) + { + result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, TRUE); + } + + if(cd_p->bufferDescNumber != 1) + { + result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, 1); + if(result != IAPI_SUCCESS) + { + return result; + } + } + + if(cd_p->bufferSize != size) + { + result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, size); + if(result != IAPI_SUCCESS) + { + return result; + } + } + /* Set addresses*/ + bd_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + bd_p->bufferAddr = iapi_Virt2Phys(src); + bd_p->extBufferAddr = iapi_Virt2Phys(dest); + + /* Set mode*/ + bd_p->mode.count = size; + bd_p->mode.command = 0x00; + bd_p->mode.status = BD_INTR|BD_EXTD|BD_DONE|BD_WRAP; + + /*Decide if we sleep or not*/ + if(cd_p->callbackSynch == DEFAULT_POLL) + { + iapi_StartChannel(cd_p->channelNumber); + /* Call synchronization routine*/ + iapi_SynchChannel(cd_p->channelNumber); + } + else + { + /* Just start the channel*/ + iapi_StartChannel(cd_p->channelNumber); + } + + return result; +} + +/* ***************************************************************************/ +/**Return the channel number from the channel descriptor + * + * @param cd_p pointer to channel descriptor to obtain the channel number + * + * @return + * - the channel number + * + */ +int iapi_GetChannelNumber(channelDescriptor * cd_p) +{ + return cd_p->channelNumber; +} + +/* ***************************************************************************/ +/**Return the error bit from the current BD of the channel + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - 0 if no error detected + * - BD_RROR | DATA_ERROR if error detected + * + */ +unsigned long iapi_GetError(channelDescriptor * cd_p) +{ + return ((cd_p->ccb_ptr->currentBDptr->mode.status & BD_RROR) | + (*(unsigned long*)&cd_p->ccb_ptr->status & DATA_ERROR)); +} + +/* ***************************************************************************/ +/**Return the count from the current BD of the channel + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - count field of the current BD for the channel + * + */ +int iapi_GetCount(channelDescriptor * cd_p) +{ + return (int)(cd_p->ccb_ptr->currentBDptr->mode.count); +} + +/* ***************************************************************************/ +/**Return the sum of counts for all the BD's owned by the processor for + * the channel specified by the received parameter. + * + * + * @param cd_p pointer to channel descriptor + * + * @return + * - sum of count fields + * + */ +int iapi_GetCountAll(channelDescriptor * cd_p) +{ + int retval = 0; + int i = 0; + bufferDescriptor* bd_p; + + bd_p = cd_p->ccb_ptr->baseBDptr; + + while((i < cd_p->bufferDescNumber) && ((bd_p->mode.status & BD_DONE) == 0)) + { + retval += bd_p->mode.count; + i++; + bd_p++; + } + return retval; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c new file mode 100644 index 000000000000..205969f82533 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLow.c + * + * $Id iapiLow.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API. + * + * + * / + * + * $Log iapiLow.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "iapiLow.h" + +/** + * Function Section + */ + + +/* ***************************************************************************/ +/**Records an ISR callback function pointer into the ISR callback + * function table + * + * @param cd_p channel descriptor to attach callback to + * @param func_p pointer to the callback function to be registered + * + * @return none + */ +void +iapi_AttachCallbackISR (channelDescriptor * cd_p, + void (* func_p)(channelDescriptor * cd_p, void * arg)) + +{ + if (cd_p->callbackSynch == CALLBACK_ISR) { + iapi_DisableInterrupts(); + callbackIsrTable[cd_p->channelNumber] = func_p; + iapi_EnableInterrupts(); + } else if (cd_p->callbackSynch == DEFAULT_POLL) { + callbackIsrTable[cd_p->channelNumber] = NULL; + } else { + iapi_errno = IAPI_ERR_CALLBACKSYNCH_UNKNOWN | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + } +} + + +/* ***************************************************************************/ +/**Detaches (removes) an ISR callback function pointer from the ISR callback + * function table + * + * Algorithm:\n + * - Attach a null function to replace the original one. + * + * @param cd_p channel descriptor to detach callback from + * + * @return none + */ +void +iapi_DetachCallbackISR (channelDescriptor * cd_p) + +{ + iapi_AttachCallbackISR (cd_p, NULL); +} + +/* ***************************************************************************/ +/**Updates an ISR callback function pointer into the ISR callback function + * table + * + * Algorithm:\n + * - Detach the old function pointer (if any) and attach the new one + * + * @param cd_p channel descriptor to attach callback to + * @param func_p pointer to the callback function to be registered + * + * @return none + */ +void +iapi_ChangeCallbackISR (channelDescriptor * cd_p, + void (* func_p)(channelDescriptor * cd_p, void * arg)) +{ + iapi_DetachCallbackISR(cd_p); + iapi_AttachCallbackISR(cd_p, func_p); +} + +/* ***************************************************************************/ +/**Loop while the channel is not done on the SDMA + * + * Algorithm:\n + * - Loop doing nothing but checking the I.API global variable to indicate + * that the channel has been completed (interrupt from SDMA) + * + * Notes:\n + * - The ISR must update the I.API global variable iapi_SDMAIntr. + * + * @param channel channel number to poll on + * + * @return none + */ +void +iapi_lowSynchChannel (unsigned char channel) +{ + while (!((1UL << channel) & iapi_SDMAIntr)) ; + iapi_SDMAIntr &= ~(1UL << channel); +} + +/* ***************************************************************************/ +/**Fill the buffer descriptor with the values given in parameter. + * + * @return none + */ +void +iapi_SetBufferDescriptor( bufferDescriptor * bd_p, unsigned char command, + unsigned char status, unsigned short count, + void * buffAddr, void * extBufferAddr) +{ + bd_p->mode.command = command; + bd_p->mode.status = status; + bd_p->mode.count = count; + if (buffAddr != NULL) { + bd_p->bufferAddr = iapi_Virt2Phys(buffAddr); + } else { + bd_p->bufferAddr = buffAddr; + } + bd_p->extBufferAddr = extBufferAddr; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c new file mode 100644 index 000000000000..df7d44a9bd46 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLowDsp.c + * + * $Id iapiLowDsp.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API specific to MCU. + * + * + * + * + * $Log iapiLowDsp.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "iapiLow.h" + +/* **************************************************************************** + * Function Section + *****************************************************************************/ +#ifdef DSP + +/* ***************************************************************************/ +/**Starts the channel (core specific register) + * + * Algorithm:\n + * - Bit numbered "channel" of DspEnStartReg register is set + * + * @param channel channel to start + * + * @return none + */ +void +iapi_lowStartChannel (unsigned char channel) +{ + SDMA_D_START |= (1 << channel); +} + +/* ***************************************************************************/ +/**Stops the channel (core specific register) + * + * Algorithm: + * - Bit numbered "channel" of DspEnStopReg register is cleared + * + * Notes:\n + * - This is a write one to clear register + * + * @param channel channel to stop + * + * @return none + */ +void +iapi_lowStopChannel (unsigned char channel) +{ + SDMA_D_STATSTOP &= (1 << channel); +} + +#endif /* DSP */ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c new file mode 100644 index 000000000000..886c70c4c3d3 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c @@ -0,0 +1,518 @@ +/****************************************************************************** + * + * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiLowMcu.c + * + * $Id iapiLowMcu.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the LOW level functions of the I.API specific to MCU. + * + * + * http://compass/mot.com/go/115342679 + * + * $Log iapiLowMcu.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include + +#include "epm.h" +#include "iapiLow.h" + +/* **************************************************************************** + * Function Section + *****************************************************************************/ +#ifdef MCU + +/* ***************************************************************************/ +/**Send a command on SDMA's channel zero. + * Check if buffer descriptor is already used by the sdma, if yes return + * an error as c0BDNum is wrong. + * + * Notes\n + * There is an upgrade in the script on the Context load command and + * the fact that the context structure has a fixed length of 20 or 24 + * depending on SDMA versions. + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if failure + */ +int +iapi_Channel0Command( channelDescriptor * cd_p, void * buf, + unsigned short nbyte, unsigned char command) +{ + channelControlBlock * ccb_p; + bufferDescriptor * bd_p; + int result = IAPI_SUCCESS; + unsigned char chNum; + + + /* + * Check data structures are properly initialized + */ + /* Channel descriptor validity */ + if (cd_p == NULL){ + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Channel control block validity */ + if (cd_p->ccb_ptr == NULL){ + result = IAPI_ERR_CCB_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* Control block & Descriptpor associated with the channel being worked on */ + chNum = cd_p->channelNumber; + ccb_p = cd_p->ccb_ptr; + + /* Is channel already in use ? */ + if (ccb_p->baseBDptr != NULL ) { + result = IAPI_ERR_BD_ALLOCATED | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + + /* Allocation of buffer descriptors */ + bd_p = (bufferDescriptor *)MALLOC(sizeof( bufferDescriptor ), SDMA_ERAM); + if (bd_p != NULL) { + ccb_p->baseBDptr = (bufferDescriptor *)iapi_Virt2Phys(bd_p); + } else { + result = IAPI_ERR_BD_ALLOCATION | IAPI_ERR_CH_AVAILABLE | chNum; + iapi_errno = result; + return -result; + } + + /* Buffer descriptor setting */ + iapi_SetBufferDescriptor( bd_p, command , BD_WRAP|BD_DONE|BD_INTR , nbyte, + buf,NULL); + + /* Actually the transfer */ + iapi_lowStartChannel( cd_p->channelNumber ); + iapi_lowSynchChannel( cd_p->channelNumber ); + + /* Cleaning of allocation */ + FREE( bd_p ); + ccb_p->baseBDptr = NULL; + + return IAPI_SUCCESS; + +} + +/* ***************************************************************************/ +/**Starts the channel (core specific register) + * + * Algorithm:\n + * - Bit numbered "channel" of HostEnStartReg register is set + * + * @param channel channel to start + * + * @return none + */ +void +iapi_lowStartChannel (unsigned char channel) +{ + SDMA_H_START |= 1 << channel; +} + +/* ***************************************************************************/ +/**Stops the channel (core specific register) + * + * Algorithm: + * - Bit numbered "channel" of HostEnStopReg register is cleared + * + * Notes:\n + * - This is a write one to clear register + * + * @param channel channel to stop + * + * @return none + */ +void +iapi_lowStopChannel (unsigned char channel) +{ + SDMA_H_STATSTOP &= 1 << channel; +} + +/* ***************************************************************************/ +/**Initialize the initial priority of registers and channel enable + * RAM from the MCU side. No channels are enabled, all priorities are set to 0. + * + * @return none + */ +void +iapi_InitChannelTables(void) +{ + + /* No channel is enabled*/ + iapi_memset((void *)&SDMA_CHNENBL_0, 0x00, sizeof(unsigned long)*EVENTS_NUM); + /* All channels have priority 0*/ + iapi_memset((void *)&SDMA_CHNPRI_0, 0x00, sizeof(unsigned long)*CH_NUM); +} + +/* ***************************************************************************/ +/** The host enable (HE), hosts override (HO), dsp enable (DE), dsp override + * (DO) registers are involved here. + * Host and Dsp enable registers are here to signify that the MCU or DSP side + * have prepared the appropriate buffers and are now ready. If the channel is + * owned by the MCU the override bit for that channel needs to be cleared : + * the host allows the channel to be used.\n + * + * Then the override bits can define (mcuOverride dspOverride):\n + * - 0 0 channel is public: transfer to/from MCU to DSP + * - 0 1 channel if owned by DSP + * - 1 0 channel if owned by MCU + * - 1 1 channel zero config + * + * See also :\n + * IAPI Table 1.1 "Channel configuration properties" + * + * @param channel channel to configure + * @param eventOverride event ownership + * @param mcuOverride ARM ownership + * @param dspOverride DSP ownership + * + * @return + * - -iapi_errno if the 3 override parameters are all set + * - IAPI_SUCCESS in other cases (valid cases) + */ +int +iapi_ChannelConfig (unsigned char channel, unsigned eventOverride, + unsigned mcuOverride, unsigned dspOverride) +{ + int result = IAPI_SUCCESS; + + if ( ( eventOverride == 1 ) && + ( mcuOverride == 1 ) && + ( dspOverride == 1 ) ){ + result = IAPI_ERR_CONFIG_OVERRIDE ; + iapi_errno = result; + return -result; + } else { + /* + * DSP side + */ + if ( dspOverride ){ + SDMA_H_DSPOVR &= ~( 1 << channel ); + } else { + SDMA_H_DSPOVR |= ( 1 << channel ); + } + /* + * Event + */ + if ( eventOverride ){ + SDMA_H_EVTOVR &= ~( 1 << channel ); + } else { + SDMA_H_EVTOVR |= ( 1 << channel ); + } + /* + * MCU side + */ + if ( mcuOverride ) { + SDMA_H_HOSTOVR &= ~( 1 << channel ); + } else { + SDMA_H_HOSTOVR |= ( 1 << channel ); + } + } + return IAPI_SUCCESS; +} +/* ***************************************************************************/ +/**Load the context data of a channel from SDMA + * + * Algorithm:\n + * - Setup BD with appropiate parameters + * - Start channel + * - Poll for answer + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to receive context data + * @param channel channel for which the context data is requested + * + * @return none + */ +void +iapi_lowGetContext(channelDescriptor * cd_p, void * buf, unsigned char channel) +{ + bufferDescriptor * bd_p; + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command*/ + iapi_SetBufferDescriptor(&bd_p[0], + C0_GETDM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), + (unsigned short)sizeof(contextData)/4, + buf, + (void *)(CHANNEL_CONTEXT_BASE_ADDRESS + (sizeof(contextData)*channel/4))); + /* Receive, polling method*/ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} +/* ***************************************************************************/ +/**Read "size" byte /2 at SDMA address (address) and write them in buf + * + * Algorithm:\n + * - Setup BD with appropiate parameters (C0_GETPM) + * - Start channel + * - Poll for answer + * + * Notes\n + * - Parameter "size" is in bytes, it represents the size of "buf", e.g. + * the size in bytes of the script to be loaded. + * - Parameter "address" denotes the RAM address for the script in SDMA + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to receive the data + * @param size number of bytes to read + * @param address address in SDMA RAM to start reading from + * + * @return none + */ +void +iapi_lowGetScript(channelDescriptor * cd_p, void * buf, unsigned short size, + unsigned long address) +{ + bufferDescriptor * bd_p; + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command*/ + iapi_SetBufferDescriptor(&bd_p[0], + C0_GETPM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), + (unsigned short)size/2,/*count in shorts*/ + buf, + (void *)address); + /* Receive, polling method*/ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + +/* ***************************************************************************/ +/**Load a SDMA script to SDMA + * + * Algorithm:\n + * - Setup BD with appropiate parameters (C0_SETPM) + * - Start channel + * - Poll for answer + * + * Notes\b + * - Parameter "size" is in bytes, it represents the size of "buf", e.g. + * the size in bytes of the script to be uploaded. + * - Parameter "address" denotes the RAM address for the script in SDMA + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to the script + * @param size size of the script, in bytes + * @param address address in SDMA RAM to place the script + * + * @return none + */ +void +iapi_lowSetScript(channelDescriptor * cd_p, void * buf, unsigned short size, + unsigned long address) +{ + bufferDescriptor * bd_p; + + bd_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + /*Setup buffer descriptor with channel 0 command*/ + iapi_SetBufferDescriptor(&bd_p[0], + C0_SETPM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP | BD_EXTD), + (unsigned short)size/2,/*count in shorts*/ + buf, + (void *)(address)); + /* Receive, polling method*/ + iapi_lowStartChannel(cd_p->channelNumber); + iapi_lowSynchChannel(cd_p->channelNumber); +} + + +/* ***************************************************************************/ +/**Load the context for a channel to SDMA + * + * Algorithm:\n + * - Send context and poll for answer. + * + * @param *cd_p channel descriptor for channel 0 + * @param *buf pointer to context data + * @param channel channel to place the context for + * + * @return none + */ +void +iapi_lowSetContext(channelDescriptor * cd_p, void * buf, unsigned char channel) +{ + + bufferDescriptor * local_bd_p; +#ifdef SDMA_SKYE + + unsigned char command =0; + + local_bd_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + + command = channel <<3 ; + command = command | C0_SETCTX; + iapi_SetBufferDescriptor( &local_bd_p[0], + command, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP), + (unsigned short)(sizeof(contextData)/4), + buf, + NULL); +#else + + local_bd_p = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + + + + + iapi_SetBufferDescriptor( &local_bd_p[0], + C0_SETDM, + (unsigned char)(BD_DONE | BD_INTR | BD_WRAP|BD_EXTD), + (unsigned short)(sizeof(contextData)/4), + buf, + (void *)(2048+(sizeof(contextData)/4)*channel)); +#endif + /* Send */ + iapi_lowStartChannel( cd_p->channelNumber ); + iapi_lowSynchChannel( cd_p->channelNumber ); + +} + +/* ***************************************************************************/ +/**Associate specified channel with the script starting at the + * specified address. Channel 0 command is used to load the set-up context + * for the channel. The address used must be generated by the GUI tool + * used to create RAM images for SDMA. + * + * Algorithm:\n + * - Set-up and load the context. + * + * @param *cd_p pointer to the channel descriptor of the channel + * @param *data_p: pointer to the data identifying the script to be associated + * with the channel + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed, return negated value of iapi_errno + */ + +int +iapi_lowAssignScript(channelDescriptor * cd_p, script_data * data_p) +{ + contextData * chContext; /* context to be loaded for the channel */ + channelDescriptor * cd0_p; /* pointer to channel descriptor of channel 0*/ + int result = IAPI_SUCCESS; + + /*Verify passed data*/ + if(cd_p == NULL || data_p == NULL) + { + result = IAPI_ERR_INVALID_PARAMETER; + iapi_errno = result; + return -result; + } + + /* Allocate context and initialize PC to required script start adress*/ + chContext = (contextData *) MALLOC(sizeof(contextData), SDMA_ERAM); + if (chContext == NULL) + { + result = IAPI_ERR_B_ALLOC_FAILED | cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + iapi_memset(chContext, 0x00, sizeof(contextData)); + chContext->channelState.pc = data_p->load_address; + + /* Send by context the event mask,base address for peripheral + * and watermark level + */ + chContext->gReg[0] = data_p->event_mask2; + chContext->gReg[1] = data_p->event_mask1; + chContext->gReg[6] = data_p->shp_addr; + chContext->gReg[7] = data_p->wml; + if (data_p->per_addr) + chContext->gReg[2] = data_p->per_addr; + + /* Set transmited data to the CD*/ + cd_p->watermarkLevel = data_p->wml; + cd_p->eventMask1 = data_p->event_mask1; + cd_p->eventMask2 = data_p->event_mask2; + + /* Get the cd0_p*/ + cd0_p = (cd_p->ccb_ptr - cd_p->channelNumber)->channelDescriptor; + + /*load the context*/ + iapi_lowSetContext(cd0_p, chContext, cd_p->channelNumber); + + /* release allocated memory*/ + FREE(chContext); + + return IAPI_SUCCESS; +} + +/* ***************************************************************************/ +/** Set the channels to be triggered by an event. The for every channel that + *must be triggered by the event, the corresponding bit from channel_map + *parameter must be set to 1. (e.g. for the event to trigger channels 31 and + *0 one must pass 0x80000001) + * + * + * Algorithm:\n + * - Update the register from Channel Enable RAM with the channel_map + * + * @param event event for which to set the channel association + * @param channel_map channels to be triggered by event. Put the corresponding + * bit from this 32-bit value to 1 for every channel that should be + * triggered by the event. + * + * @return + * - IAPI_SUCCESS : OK + * - -iapi_errno : operation failed, return negated value of iapi_errno + */ +int +iapi_lowSetChannelEventMapping(unsigned char event, unsigned long channel_map) +{ + volatile unsigned long * channelEnableMatx; + int result = IAPI_SUCCESS; + + /* Check validity of event*/ + if (event < EVENTS_NUM) + { + channelEnableMatx = &SDMA_CHNENBL_0; + channelEnableMatx[event] |= channel_map; + return result; + } + else + { + result = IAPI_ERR_INVALID_PARAMETER | event; + iapi_errno = result; + return -result; + } +} + +#endif /* MCU */ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c new file mode 100644 index 000000000000..b2423ed2fbd6 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c @@ -0,0 +1,623 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddle.c + * + * $Id iapiMiddle.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the MIDDLE level functions of the I.API. + * + * + * + * + * $Log iapiMiddle.c $ + * + *****************************************************************************/ + + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include + +#include "iapiLow.h" +#include "iapiMiddle.h" + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ + + +/* **************************************************************************** + * Function Section + *****************************************************************************/ + +/* ***************************************************************************/ +/**Allocates one Buffer Descriptor structure using information present in the + * channel descriptor. + * + * @param *ccb_p channel control block used to get the channel descriptor + * + * @return + * - pointer on the new Buffer Descriptor + * - NULL if allocation failed + * + */ +bufferDescriptor * +iapi_AllocBD (channelControlBlock * ccb_p) + +{ + bufferDescriptor * ptrBD = NULL; + + if (ccb_p->channelDescriptor->bufferDescNumber != 0){ +#ifdef CONFIG_SDMA_IRAM + channelDescriptor * cd_p = ccb_p->channelDescriptor; + if(cd_p->channelNumber >= MXC_DMA_CHANNEL_IRAM) { + ptrBD = (bufferDescriptor *) + MALLOC( ccb_p->channelDescriptor->bufferDescNumber * + sizeof(bufferDescriptor), SDMA_IRAM); + } else +#endif /*CONFIG_SDMA_IRAM*/ + { + ptrBD = (bufferDescriptor *) + MALLOC( ccb_p->channelDescriptor->bufferDescNumber * + sizeof(bufferDescriptor), SDMA_ERAM); + } + } + if (ptrBD != NULL) { + ptrBD->mode.command = 0; + ptrBD->mode.status = 0; + ptrBD->mode.count = 0; + ptrBD->bufferAddr = NULL; + } + + return ptrBD; +} + +/* ***************************************************************************/ +/**Allocate one channel context data structure. + * + * @param **ctxd_p pointer to context data to be allocated + * @param channel channel number of context data structure + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if allocation failed + */ +int +iapi_AllocContext(contextData ** ctxd_p, unsigned char channel) +{ + contextData * ctxData; + int result = IAPI_SUCCESS; + + if (*ctxd_p != NULL){ + result = IAPI_ERR_CC_ALREADY_DEFINED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } + + ctxData = (contextData *)MALLOC(sizeof(contextData), SDMA_ERAM); + + if (ctxData !=NULL) { + *ctxd_p = ctxData; + return IAPI_SUCCESS; + + } else { + *ctxd_p = NULL; + result = IAPI_ERR_CC_ALLOC_FAILED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } +} + +/* ***************************************************************************/ +/**Allocates channel description and fill in with default values. + * + * Algorithm:\n + * - Check channel properties. + * - Then modifies the properties of the channel description with default + * + * @param **cd_p pointer to channel descriptor to be allocated + * @param channel channel number of channel descriptor + * + * @return + * - IAPI_SUCCESS + * - -iapi_errno if allocation failed + * + */ +int +iapi_AllocChannelDesc (channelDescriptor ** cd_p, unsigned char channel) +{ +#ifdef MCU + volatile unsigned long * chPriorities = &SDMA_CHNPRI_0; +#endif /* MCU */ + channelDescriptor * tmpCDptr; + int result = IAPI_SUCCESS; + + + if (*cd_p != NULL){ + result = IAPI_ERR_CD_ALREADY_DEFINED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } + + tmpCDptr = (channelDescriptor *)MALLOC(sizeof(channelDescriptor), SDMA_ERAM); + + if (tmpCDptr != NULL){ + iapi_memcpy(tmpCDptr, &iapi_ChannelDefaults, sizeof (channelDescriptor)); + tmpCDptr->channelNumber = channel; +#ifdef MCU + if (chPriorities[channel] != 0) { + tmpCDptr->priority = chPriorities[channel]; + } else { + chPriorities[channel] = tmpCDptr->priority; + } +#endif + * cd_p = tmpCDptr ; + return IAPI_SUCCESS; + } else { + * cd_p = NULL; + result = IAPI_ERR_CD_ALLOC_FAILED | IAPI_ERR_CH_AVAILABLE | channel; + iapi_errno = result; + return -result; + } +} + +/* ***************************************************************************/ +/**Changes channel description information after performing sanity checks. + * + * Algorithm:\n + * - Check channel properties. + * - Then modifies the properties of the channel description. + * + * @param *cd_p channel descriptor of the channel to change + * @param whatToChange control code indicating the desired change + * @param newval new value + * + * @return + * - IAPI_SUCCESS + * - IAPI_FAILURE if change failed + * + */ +int +iapi_ChangeChannelDesc (channelDescriptor * cd_p, unsigned char whatToChange, + unsigned long newval) +{ + bufferDescriptor * tmpBDptr; + unsigned char index = 0; + int result = IAPI_SUCCESS; + + /* verify parameter validity */ + if (cd_p == NULL) { + result = IAPI_ERR_CD_UNINITIALIZED; + iapi_errno = result; + return -result; + } + + /* verify channel descriptor initialization */ + if (cd_p->ccb_ptr == NULL){ + result = IAPI_ERR_CCB_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* verify channel is not in use */ + tmpBDptr = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (index=cd_p->bufferDescNumber ; index>0 ; index--){ + if (tmpBDptr->mode.status & BD_DONE){ + result = IAPI_ERR_CH_IN_USE | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + tmpBDptr++; + } + + /* Select the change accorded to the selector given in parameter */ + switch (whatToChange){ + + /* + * Channel Number + */ + case IAPI_CHANNELNUMBER: + /* Channel number can not be changed (description remains attached) */ + result = IAPI_ERR_CD_CHANGE_CH_NUMBER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + + /* + * Buffer Descriptor Number + */ + case IAPI_BUFFERDESCNUMBER: + if (newval < MAX_BD_NUM){ + if (newval != cd_p->bufferDescNumber){ + /* Free memory used for previous old data */ + if (cd_p->ccb_ptr->baseBDptr != NULL){ + tmpBDptr = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (index=0 ; index < cd_p->bufferDescNumber ; index++){ + if (tmpBDptr->bufferAddr != NULL){ + if (cd_p->trust == FALSE) { + FREE(iapi_Phys2Virt(tmpBDptr->bufferAddr)); + } + } + tmpBDptr ++ ; + } + FREE((bufferDescriptor *)iapi_Phys2Virt((cd_p->ccb_ptr)->baseBDptr)); + } + (cd_p->ccb_ptr)->baseBDptr = NULL; + (cd_p->ccb_ptr)->currentBDptr = NULL; + /* Allocate and initialize structures */ + cd_p->bufferDescNumber = (unsigned char)newval; + cd_p->ccb_ptr->status.openedInit = FALSE; + if (IAPI_SUCCESS !=iapi_InitializeMemory (cd_p->ccb_ptr)) + { + result = IAPI_ERR_BD_ALLOCATION | cd_p->channelNumber; + iapi_errno = result; + return -result; + } + cd_p->ccb_ptr->status.openedInit = TRUE; + } + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Buffer size + */ + case IAPI_BUFFERSIZE: + if (newval < MAX_BD_SIZE) + { + if (newval != cd_p->bufferSize) + { + /* Free memory used for previous old data */ + if (cd_p->ccb_ptr->baseBDptr != NULL) + { + tmpBDptr = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + for (index=0 ; index < cd_p->bufferDescNumber ; index++) + { + if (cd_p->trust == FALSE) + { + FREE(iapi_Phys2Virt(tmpBDptr->bufferAddr)); + } + tmpBDptr ++ ; + } + FREE((bufferDescriptor *)iapi_Phys2Virt((cd_p->ccb_ptr)->baseBDptr)); + } + (cd_p->ccb_ptr)->baseBDptr = NULL; + (cd_p->ccb_ptr)->currentBDptr = NULL; + /* Allocate and initialize structures */ + cd_p->bufferSize = (unsigned short)newval; + cd_p->ccb_ptr->status.openedInit = FALSE; + if (IAPI_SUCCESS !=iapi_InitializeMemory (cd_p->ccb_ptr)) + { + result = IAPI_ERR_BD_ALLOCATION | cd_p->channelNumber; + iapi_errno = result; + return -result; + } + cd_p->ccb_ptr->status.openedInit = TRUE; + } + break; + } + else + { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + + /* + * Blocking / non blocking feature + */ + case IAPI_BLOCKING: + if (newval < MAX_BLOCKING){ + cd_p->blocking = newval; + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Synchronization method + */ + case IAPI_CALLBACKSYNCH: + if (newval < MAX_SYNCH){ + cd_p->callbackSynch = newval; + iapi_ChangeCallbackISR( cd_p, cd_p->callbackISR_ptr); + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + + /* + * Ownership of the channel + */ + case IAPI_OWNERSHIP: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ +#ifdef MCU + if (newval < MAX_OWNERSHIP){ + cd_p->ownership = newval; + iapi_ChannelConfig( cd_p->channelNumber, + ( newval >> CH_OWNSHP_OFFSET_EVT ) & 1, + ( newval >> CH_OWNSHP_OFFSET_MCU ) & 1, + ( newval >> CH_OWNSHP_OFFSET_DSP ) & 1); + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + +#endif /* MCU */ + + /* + * Priority + */ + case IAPI_PRIORITY: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ + +#ifdef MCU + if (newval < MAX_CH_PRIORITY){ + volatile unsigned long * ChannelPriorities = &SDMA_CHNPRI_0; + ChannelPriorities[ cd_p->channelNumber ] = newval; + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } +#endif /* MCU */ + + + /* + * "Trust" property + */ + case IAPI_TRUST: + if (newval < MAX_TRUST){ + if (cd_p->trust != newval){ + cd_p->trust = newval; + if (newval == FALSE) { + if (IAPI_SUCCESS !=iapi_InitializeMemory (cd_p->ccb_ptr)) + { + result = IAPI_ERR_BD_ALLOCATION | cd_p->channelNumber; + iapi_errno = result; + return -result; + } + } + } + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + /* + * Callback function pointer + */ + case IAPI_CALLBACKISR_PTR: + if ( (void *)newval != NULL){ + { + union { + void * voidstar; + void (* funcptr)(channelDescriptor * cd_p, void * arg); + } value; + value.voidstar = (void*) newval; + cd_p->callbackISR_ptr = value.funcptr; + } + iapi_ChangeCallbackISR( cd_p, cd_p->callbackISR_ptr); + break; + } else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + + /* + * Channel Control Block pointer + */ + case IAPI_CCB_PTR: + cd_p->ccb_ptr = (channelControlBlock *)newval; + cd_p->ccb_ptr->channelDescriptor = cd_p; + break; + + /* + * WRAP/UNWRAP + */ + case IAPI_BDWRAP: + /* point to first BD */ + tmpBDptr = (bufferDescriptor *)iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr); + /* to point to last BD */ + tmpBDptr += cd_p->bufferDescNumber - 1; + if (newval == TRUE){ + /* wrap last BD */ + tmpBDptr->mode.status |= BD_WRAP; + break; + } + else if (newval == FALSE){ + /* unwrap last BD */ + tmpBDptr->mode.status &= ~BD_WRAP; + break; + } + else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + + /* + * Watermark level + */ + case IAPI_WML: +#ifdef DSP + result = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber; + iapi_errno = result; + return -result; +#endif /* DSP */ +#ifdef MCU + if (newval < MAX_WML){ + if (cd_p->watermarkLevel != newval){ + cd_p->watermarkLevel = newval; + } + break; + } + else { + result = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } +#endif /* MCU */ + + /* + * Detect errors + */ + default: + result = IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | + cd_p->channelNumber; + iapi_errno = result; + return -result; + } + + return IAPI_SUCCESS; +} + + +/* ***************************************************************************/ +/**Initialize a table of function pointers that contain the interrupt Service + * Routine callback pointers for the SDMA channels with a default value + * + * Algorithm:\n + * - Loop on each element of the global IAPI variable callbackIsrTable + * + * @param *func_p default callback functon for all SDMA channels + * + * @return none + */ +void +iapi_InitializeCallbackISR(void(* func_p)(channelDescriptor * cd_p, void * arg)) +{ + unsigned long chCnt; + + for (chCnt = 0 ; chCnt < CH_NUM ; chCnt++){ + callbackIsrTable[chCnt] = func_p; + } +} + +/* ***************************************************************************/ +/**For the specified channel control block, attach the array of buffer + * descriptors, the channel description structure and initialize channel's + * status using information in the channel descriptor. + * + * @param *ccb_p pointer to channel control block + * + * @return none + * + */ +int +iapi_InitializeMemory (channelControlBlock * ccb_p) +{ + bufferDescriptor * bd_p; + unsigned char index; + int result = IAPI_SUCCESS; + + /* Attach the array of Buffer descriptors */ + bd_p = iapi_AllocBD( ccb_p ); + if (bd_p != NULL) + { + ccb_p->baseBDptr = (bufferDescriptor *)iapi_Virt2Phys(bd_p); + ccb_p->currentBDptr = ccb_p->baseBDptr; + for(index=0 ;index < ccb_p->channelDescriptor->bufferDescNumber-1 ; index++) + { + if (ccb_p->channelDescriptor->trust == TRUE) + { + iapi_SetBufferDescriptor(bd_p, + (unsigned char)ccb_p->channelDescriptor->dataSize, + BD_CONT|BD_EXTD, ccb_p->channelDescriptor->bufferSize, + NULL, NULL); + } + else + { + if (ccb_p->channelDescriptor->bufferSize != 0) + { + iapi_SetBufferDescriptor(bd_p, + (unsigned char)ccb_p->channelDescriptor->dataSize, + BD_CONT|BD_EXTD, ccb_p->channelDescriptor->bufferSize, + MALLOC(ccb_p->channelDescriptor->bufferSize, SDMA_ERAM), NULL); + } + } + bd_p++; + } + + if (ccb_p->channelDescriptor->trust == TRUE) + { + iapi_SetBufferDescriptor(bd_p, + (unsigned char)ccb_p->channelDescriptor->dataSize, + BD_EXTD|BD_WRAP|BD_INTR, ccb_p->channelDescriptor->bufferSize, + NULL, NULL); + } + else + { + if (ccb_p->channelDescriptor->bufferSize != 0) + { + iapi_SetBufferDescriptor(bd_p, + (unsigned char)ccb_p->channelDescriptor->dataSize, + BD_EXTD|BD_WRAP|BD_INTR, + ccb_p->channelDescriptor->bufferSize, + MALLOC(ccb_p->channelDescriptor->bufferSize, SDMA_ERAM), NULL); + } + } + } + else + { + result = IAPI_ERR_BD_ALLOCATION; + return -result; + } + return result; +} diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c new file mode 100644 index 000000000000..8dc814418e4c --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiMiddleMcu.c + * + * $Id iapiMiddleMcu.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the MIDDLE level functions of the I.API specific to MCU. + * + * + * + * + * $Log iapiMiddleMcu.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include + +#include "iapiLow.h" +#include "iapiMiddle.h" + +/* **************************************************************************** + * Global Variable Section + *****************************************************************************/ + +/*extern void * __HEAP_START; +extern void * __HEAP_END; +*/ + +/* **************************************************************************** + * Function Section + *****************************************************************************/ diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c new file mode 100644 index 000000000000..643cab549742 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + ****************************************************************************** + * + * File: iapiOS.c + * + * $Id iapiOS.c $ + * + * Description: + * This library is written in C to guarantee functionality and integrity in + * the usage of SDMA virtual DMA channels. This API (Application Programming + * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE + * fashion. + * These are the OS level functions of the I.API - are OS dependant and must + * be provided by the user of I.API. + * + * + * / + * + * $Log iapiOS.c $ + * + *****************************************************************************/ + +/* **************************************************************************** + * Include File Section + *****************************************************************************/ +#include "epm.h" +#include "iapiLow.h" + +/** + * Function Section + */ +#ifdef CONFIG_SDMA_IRAM +void*(* iapi_iram_Malloc) (size_t size); +#endif /*CONFIG_SDMA_IRAM*/ + +void*(* iapi_Malloc) (size_t size); +void (* iapi_Free) (void * ptr); + +void*(* iapi_Virt2Phys) (void * ptr); +void*(* iapi_Phys2Virt) (void * ptr); + +void (* iapi_WakeUp)(int); +void (* iapi_GotoSleep)(int); +void (* iapi_InitSleep)(int); + +void*(* iapi_memcpy)(void *dest, const void *src, size_t count); +void*(* iapi_memset)(void *dest, int c, size_t count); + +void (* iapi_EnableInterrupts)(void); +void (* iapi_DisableInterrupts)(void); + +int (* iapi_GetChannel)(int); +int (* iapi_ReleaseChannel)(int); diff --git a/arch/arm/plat-mxc/sdma/sdma.c b/arch/arm/plat-mxc/sdma/sdma.c new file mode 100644 index 000000000000..6bdce3375134 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/sdma.c @@ -0,0 +1,1481 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/sdma/sdma.c + * @brief This file contains functions for Smart DMA API + * + * SDMA (Smart DMA) is used for transferring data between MCU and peripherals + * + * @ingroup SDMA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "iapi.h" + +#define M3_BASE_ADDRESS CSD0_BASE_ADDR +#define CHAD(ch) sdma_data[0].cd->ccb_ptr[ch].channelDescriptor + +/*! + * SDMA status mutex + */ +static struct semaphore sdma_status_mutex; + +/*! + * SDMA channel sleep queues + */ +//static struct semaphore sdma_sleep_mutex[MAX_DMA_CHANNELS]; +static wait_queue_head_t sdma_sleep_queue[MAX_DMA_CHANNELS]; + +/*! + * SDMA channel synchronization + */ +static struct semaphore sdma_synch_mutex[MAX_DMA_CHANNELS]; + +/*! + * SDMA buffers pool initialization function + */ +extern void init_sdma_pool(void); + +/*! + * Flags are save and restored during interrupt handler + */ +unsigned long flags; + +struct clk *mxc_sdma_ahb_clk, *mxc_sdma_ipg_clk; + +/*! + * Structure containing sdma channels information. + */ +typedef struct { + /*! Channel number */ + int channel; + /*! Channel usage name */ + int in_use; + /*! Name of device using the channel */ + char devicename[MAX_DEVNAME_LENGTH]; + /*! Transfer type. Needed for setting SDMA script */ + sdma_transferT transfer_type; + /*! Peripheral type. Needed for setting SDMA script */ + sdma_periphT peripheral_type; + /*! Watermark level of device's fifo */ + __u32 watermark_level; + /*! Peripheral event id */ + int event_id; + /*! Peripheral event id2 (for channels that use 2 events) */ + int event_id2; + /*! Running status (boolean) */ + int running; + /*! buffer descriptors number */ + int bd_number; + /*! callback function */ + dma_callback_t callback; + /*! callback argument */ + void *arg; + /*! SDMA data access word size */ + unsigned long word_size:8; + /*! channel descriptor pointer */ + channelDescriptor *cd; +} sdma_struct; + +/*! + * Used to save the status of channels. + */ +static sdma_struct sdma_data[MAX_DMA_CHANNELS]; + +/*! + * Stores the start address of the SDMA scripts + */ +static sdma_script_start_addrs sdma_script_addrs; + +extern void mxc_sdma_get_script_info(sdma_script_start_addrs * sdma_script_add); + +/*! + * Init sleep mutex of the channel + * + * @param channel channel number + */ +static void sdma_init_sleep(int channel) +{ + init_waitqueue_head(&sdma_sleep_queue[channel]); +} + +/*! + * Puts channel to sleep + * + * @param channel channel number + */ +static void sdma_sleep_channel(int channel) +{ + while ((iapi_SDMAIntr & (1 << channel)) == 0) { + wait_event_interruptible(sdma_sleep_queue[channel], + ((iapi_SDMAIntr & (1 << channel)) != + 0)); + } +} + +/*! + * Wake up channel from sleep + * + * @param channel channel number + */ +static void sdma_wakeup_channel(int channel) +{ + wake_up_interruptible(&sdma_sleep_queue[channel]); +} + +/*! + * Sdma interrupt handler routine. + * Calls channels callback function + * + * @param irq the interrupt number + * @param dev_id driver private data + * @return the function returns \b IRQ_RETVAL(1) - interrupt was handled + */ +static irqreturn_t sdma_int_handler(int irq, void *dev_id) +{ + IRQ_Handler(); + return IRQ_RETVAL(1); +} + +/*! + * I.API channel callback function + * + * @param cd channel descriptor structure + * @param channel_data SDMA struct of the current channel + */ +static void iapi_interrupt_callback(channelDescriptor * cd, + sdma_struct * channel_data) +{ + int channel; + dma_callback_t callback; + void *arg; + + channel = channel_data->channel; + + channel_data->running = 0; + + arg = channel_data->arg; + + if (arg == 0) { + arg = (void *)&channel; + } + + callback = channel_data->callback; + + if (callback != 0) { + callback(arg); + } +} + +/*! + * Returns pc of SDMA script according to peripheral and transfer type + * + * @param peripheral_type peripheral type + * @param transfer_type transfer type + * + * @return PC of SDMA script +*/ +static unsigned short sdma_get_pc(sdma_periphT peripheral_type, + sdma_transferT transfer_type) +{ + int res = 0; + + if (peripheral_type == MEMORY) { + switch (transfer_type) { + case emi_2_int: + res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; + break; + case emi_2_emi: + res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; + break; + case int_2_emi: + res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == DSP) { + switch (transfer_type) { + case emi_2_dsp: + res = sdma_script_addrs.mxc_sdma_ap_2_bp_addr; + break; + case dsp_2_emi: + res = sdma_script_addrs.mxc_sdma_bp_2_ap_addr; + break; + case dsp_2_emi_loop: + res = + sdma_script_addrs. + mxc_sdma_loopback_on_dsp_side_addr; + break; + case emi_2_dsp_loop: + res = + sdma_script_addrs.mxc_sdma_mcu_interrupt_only_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == FIRI) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_firi_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_firi_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_firi_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_firi_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == UART) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_uart_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_uart_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_app_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == UART_SP) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_uartsh_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_uartsh_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_shp_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == ATA) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_ata_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_ata_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == CSPI || peripheral_type == EXT || + peripheral_type == SSI) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_app_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_app_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_app_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == SSI_SP || peripheral_type == MMC || + peripheral_type == SDHC || peripheral_type == CSPI_SP || + peripheral_type == ESAI || peripheral_type == MSHC_SP) { + switch (transfer_type) { + case per_2_int: + res = sdma_script_addrs.mxc_sdma_shp_2_per_addr; + break; + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_shp_2_mcu_addr; + break; + case int_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_shp_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == ASRC) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr; + break; + case per_2_per: + res = sdma_script_addrs.mxc_sdma_per_2_per_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == MSHC) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_mshc_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_mshc_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == CCM) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_dptc_dvfs_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == FIFO_MEMORY) { + res = sdma_script_addrs.mxc_sdma_ap_2_ap_fixed_addr; + } else if (peripheral_type == SPDIF) { + switch (transfer_type) { + case per_2_emi: + res = sdma_script_addrs.mxc_sdma_spdif_2_mcu_addr; + break; + case emi_2_per: + res = sdma_script_addrs.mxc_sdma_mcu_2_spdif_addr; + break; + default: + res = -EINVAL; + } + } else if (peripheral_type == IPU_MEMORY) { + if (transfer_type == emi_2_per) { + res = sdma_script_addrs.mxc_sdma_ext_mem_2_ipu_addr; + } else { + res = -EINVAL; + } + } + + if (res < 0) { + printk(KERN_ERR "SDMA script not found\n"); + } + + return res; + +} + +static inline int sdma_asrc_set_info(dma_channel_params *p, + script_data *pcontext, int eflags) +{ + dma_channel_ext_params *ep = (dma_channel_ext_params *) p; + unsigned int wml, tmp, wml1, wml2; + struct dma_channel_asrc_info *info = &(ep->info.asrc); + wml = 0; + if (p->transfer_type == per_2_per) { + if (!p->ext) + return wml; + wml1 = p->watermark_level; + wml2 = ep->watermark_level2; + if (info->channs) { + wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) << + SDMA_ASRC_INFO_N_OFF; + if (ep->p2p_dir) + wml2 *= info->channs & SDMA_ASRC_INFO_N_MASK; + else + wml1 *= info->channs & SDMA_ASRC_INFO_N_MASK; + } + if (info->channs & 1) { + if (ep->p2p_dir) + wml |= SDMA_ASRC_P2P_INFO_PS; + else + wml |= SDMA_ASRC_P2P_INFO_PA; + } + if (wml1 > wml2) { + tmp = wml2 & SDMA_ASRC_P2P_INFO_LWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF; + tmp = wml1 & SDMA_ASRC_P2P_INFO_HWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF; + if (eflags & (1 << 31)) + wml |= SDMA_ASRC_P2P_INFO_LWE; + if (eflags & (1 << 30)) + wml |= SDMA_ASRC_P2P_INFO_HWE; + } else { + tmp = wml1 & SDMA_ASRC_P2P_INFO_LWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF; + tmp = wml2 & SDMA_ASRC_P2P_INFO_HWML_MASK; + wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF; + wml |= eflags >> 2; + tmp = pcontext->event_mask2; + pcontext->event_mask2 = pcontext->event_mask1; + pcontext->event_mask1 = tmp; + } + } else { + if (p->ext && info->channs) { + wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) << + SDMA_ASRC_INFO_N_OFF; + tmp = (info->channs * p->watermark_level) & + SDMA_ASRC_INFO_WML_MASK; + wml |= tmp << SDMA_ASRC_INFO_WML_OFF; + } else { + tmp = (p->watermark_level & SDMA_ASRC_INFO_WML_MASK); + wml |= tmp << SDMA_ASRC_INFO_WML_OFF; + } + + if (p->transfer_type == per_2_emi) + wml |= SDMA_ASRC_INFO_TXFR_DIR; + + if (p->ext && (info->channs & 1)) { + if (p->transfer_type == per_2_emi) + wml |= SDMA_ASRC_INFO_PS; + else + wml |= SDMA_ASRC_INFO_PA; + } + wml |= eflags; + } + return wml; +} + +/*! + * Downloads channel context according to channel parameters + * + * @param channel channel number + * @param p channel parameters + */ +static int sdma_load_context(int channel, dma_channel_params * p) +{ + script_data context; + int res; + int event1_greater_than_32; + int event2_greater_than_32; + dma_channel_ext_params *ep = (dma_channel_ext_params *) p; + + res = 0; + + memset(&context, 0, sizeof(script_data)); + context.load_address = sdma_get_pc(p->peripheral_type, + p->transfer_type); + + if (context.load_address > 0) { + if ((p->peripheral_type != MEMORY) + && (p->peripheral_type != DSP)) { + /* Handle multiple event channels differently */ + if (p->event_id2) { + if (p->event_id2 < 32) { + context.event_mask2 = + 0x1 << p->event_id2; + event2_greater_than_32 = 0; + } else { + context.event_mask2 = + 0x1 << (p->event_id2 - 32); + event2_greater_than_32 = 1 << 31; + } + if (p->event_id < 32) { + context.event_mask1 = + 0x1 << p->event_id; + event1_greater_than_32 = 0; + } else { + context.event_mask1 = + 0x1 << (p->event_id - 32); + event1_greater_than_32 = 1 << 30; + } + } else { + event1_greater_than_32 = 0; + event2_greater_than_32 = 0; + if (p->event_id < 32) { + context.event_mask1 = + 0x1 << p->event_id; + context.event_mask2 = 0; + } else { + context.event_mask1 = 0; + context.event_mask2 = + 0x1 << (p->event_id - 32); + } + } + + if (p->ext) + context.wml = ep->info_bits; + /* Watermark Level */ + if (p->peripheral_type == ASRC) { + context.wml |= sdma_asrc_set_info(p, + &context, + event2_greater_than_32 + | + event1_greater_than_32); + } else + context.wml |= event2_greater_than_32 | + event1_greater_than_32 | p->watermark_level; + + /* Address */ + context.shp_addr = (unsigned long)(p->per_address); + if (p->ext) + context.per_addr = ep->per_address2; + iapi_IoCtl(sdma_data[channel].cd, + IAPI_CHANGE_PERIPHADDR, p->per_address); + } else { + context.wml = M3_BASE_ADDRESS; + } + + sdma_data[channel].transfer_type = p->transfer_type; + sdma_data[channel].peripheral_type = p->peripheral_type; + sdma_data[channel].watermark_level = p->watermark_level; + iapi_AssignScript(sdma_data[channel].cd, &context); + } else { + res = context.load_address; + } + + return res; +} + +/*! + * Setup channel according to parameters. Must be called once after mxc_request_dma() + * + * @param channel channel number + * @param p channel parameters pointer + * @return 0 on success, error code on fail + */ +int mxc_dma_setup_channel(int channel, dma_channel_params * p) +{ + int err = 0; + int i; + + mxc_dma_stop(channel); + + for (i = 0; i < sdma_data[channel].bd_number; i++) { + iapi_IoCtl(sdma_data[channel].cd, + (i << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_STATUS, (unsigned long)0); + } + + sdma_data[channel].bd_number = (p->bd_number <= 0) ? 1 : p->bd_number; + + sdma_data[channel].word_size = p->word_size; + + sdma_data[channel].event_id = p->event_id; + sdma_data[channel].event_id2 = p->event_id2; + + sdma_data[channel].callback = p->callback; + + sdma_data[channel].arg = p->arg; + + err = iapi_IoCtl(sdma_data[channel].cd, + IAPI_CHANGE_BDNUM, sdma_data[channel].bd_number); + + if (err < 0) { + printk(KERN_ERR "Failed allocating buffer \ +descriptors (0x%x)\n", err); + err = -ENOMEM; + goto setup_channel_fail; + } + + if (channel != 0) { + switch (p->transfer_type) { + case dsp_2_per: + break; + case emi_2_per: + case int_2_per: + case per_2_int: + case per_2_emi: + case per_2_per: + /* + * Peripheral <------> Memory + * evtOvr = 0 dspOvr = 1 + */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + if (p->event_id) { + err = iapi_SetChannelEventMapping(p->event_id, + 0x1 << + channel); + } + if (!err && p->event_id2) { + err = iapi_SetChannelEventMapping(p->event_id2, + 0x1 << + channel); + } + break; + case emi_2_dsp: + case int_2_dsp: + case dsp_2_int: + case dsp_2_emi: + case dsp_2_dsp: + /* + * DSP <-----------> Memory + * evtOvr = 1 dspOvr = 0 + */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + break; + case emi_2_int: + case emi_2_emi: + case int_2_int: + case int_2_emi: + case emi_2_dsp_loop: + case dsp_2_emi_loop: + /* evtOvr = 1 dspOvr = 1 */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + break; + case per_2_dsp: + /* evtOvr = 0 dspOvr = 0 */ + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + err = iapi_SetChannelEventMapping(p->event_id, + 0x1 << channel); + break; + default: + break; + printk(KERN_ERR "Wrong SDMA transfer type\n"); + err = -EINVAL; + } + if (err == 0) { + err = sdma_load_context(channel, p); + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, + MXC_SDMA_DEFAULT_PRIORITY); + } + } + setup_channel_fail: + return err; +} + +/*! + * Setup the channel priority. This can be used to change the default priority + * for the channel. + * + * @param channel channel number + * @param priority priority to be set for the channel + * + * @return 0 on success, error code on failure + */ +int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority) +{ + if (priority < MXC_SDMA_MIN_PRIORITY + || priority > MXC_SDMA_MAX_PRIORITY) { + return -EINVAL; + } + return iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, + priority); +} + +/*! + * Allocates dma channel. + * If channel's value is 0, then the function allocates a free channel + * dynamically and sets its value to channel. + * Else allocates requested channel if it is free. + * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned. + * + * @param channel pointer to channel number + * @param devicename device name + * @return 0 on success, error code on fail + */ +int mxc_request_dma(int *channel, const char *devicename) +{ + int i, res; + + res = 0; + + down(&sdma_status_mutex); + + /* Dynamic allocation */ + if (*channel == 0) { + for (i = MAX_DMA_CHANNELS - 1; i > 0; i--) { +#ifdef CONFIG_SDMA_IRAM + /*TODO:It will be removed after DPTC used UDMA interface */ + if (i >= MXC_DMA_CHANNEL_IRAM) + continue; +#endif /*CONFIG_SDMA_IRAM */ + if (!sdma_data[i].in_use) { + *channel = i; + break; + } + } + } + + if (*channel > 0 && *channel < MAX_DMA_CHANNELS && + sdma_data[*channel].in_use == 0) { + res = iapi_Open(sdma_data[0].cd, *channel); + + if (res < 0) { + printk(KERN_ERR "Failed iapi_Open channel %d, 0x%x\n", + *channel, res); + } else { + sdma_data[*channel].in_use = 1; + strcpy(sdma_data[*channel].devicename, devicename); + sdma_data[*channel].cd = CHAD(*channel); + + iapi_IoCtl(sdma_data[*channel].cd, IAPI_CHANGE_SYNCH, + CALLBACK_ISR); + iapi_IoCtl(sdma_data[*channel].cd, + IAPI_CHANGE_CALLBACKFUNC, + (unsigned long)iapi_interrupt_callback); + iapi_IoCtl(sdma_data[*channel].cd, + IAPI_CHANGE_USER_ARG, + (unsigned long)&(sdma_data[*channel])); + } + } else { + res = -EBUSY; + } + + up(&sdma_status_mutex); + + return res; +} + +/*! + * Configures request parameters. Can be called multiple times after + * mxc_request_dma() and mxc_dma_setup_channel(). + * + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to set + * @return 0 on success, error code on fail + */ +int mxc_dma_set_config(int channel, dma_request_t * p, int bd_index) +{ + unsigned char param; + + if (!sdma_data[channel].in_use) { + return -EINVAL; + } + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_TRANSFER_CD, sdma_data[channel].word_size); + + param = BD_DONE | BD_INTR | BD_EXTD; + + if (sdma_data[channel].bd_number > 1 && p->bd_cont == 1) { + param |= BD_CONT; + } + + if (bd_index == sdma_data[channel].bd_number - 1) { + param |= BD_WRAP; + } + + switch (sdma_data[channel].transfer_type) { + case emi_2_per: + case dsp_2_per: + case int_2_per: + case emi_2_dsp: + case int_2_dsp: + case emi_2_dsp_loop: + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_BUFFERADDR, + (unsigned long)p->sourceAddr); + break; + case per_2_int: + case per_2_emi: + case per_2_dsp: + case dsp_2_int: + case dsp_2_emi: + case dsp_2_dsp: + case dsp_2_emi_loop: + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_BUFFERADDR, + (unsigned long)p->destAddr); + break; + case emi_2_int: + case emi_2_emi: + case int_2_int: + case int_2_emi: + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_BUFFERADDR, + (unsigned long)p->sourceAddr); + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_EXTDBUFFERADDR, + (unsigned long)p->destAddr); + break; + default: + break; + } + + /* Change the endianness for DSP to MCU Data transfers */ + if (sdma_data[channel].transfer_type == dsp_2_emi || + sdma_data[channel].transfer_type == emi_2_dsp) { + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_SET_ENDIANNESS, + SET_BIT_ALL); + } + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_COUNT, p->count); + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, param); + + return 0; +} + +/*! + * Configures the BD_INTR bit on a buffer descriptor parameters. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * @param bd_intr flag to set or clear the BD_INTR bit + * @return 0 on success, error code on fail + */ +void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr) +{ + unsigned long param; + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)¶m); + + if (bd_intr) { + param |= BD_INTR; + } else { + param &= ~BD_INTR; + } + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, param); + +} + +/*! + * Gets the BD_INTR bit on a buffer descriptor. + * + * + * @param channel channel number + * @param bd_index index of buffer descriptor to set + * + * @return returns the BD_INTR bit status + */ +int mxc_dma_get_bd_intr(int channel, int bd_index) +{ + unsigned long bd_status = 0; + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status); + + return (bd_status & BD_INTR); +} + +/*! + * Stop the current transfer + * + * @param channel channel number + * @param buffer_number number of buffers (beginning with 0), + * whose done bits should be reset to 0 + */ +int mxc_dma_reset(int channel, int buffer_number) +{ + unsigned char param = 0; + int i = 0; + + if (!sdma_data[channel].in_use) { + return -EINVAL; + } + + /* clear the BD_DONE bits for all the necessary buffers */ + for (i = 0; i < buffer_number; i++) { + + iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)¶m); + + /* clear the BD_DONE bit of the buffer */ + param = param & (~BD_DONE); + + iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_STATUS, param); + } + + return 0; +} + +/*! + * Returns request parameters. + * + * @param channel channel number + * @param p request parameters pointer + * @param bd_index index of buffer descriptor to get + * @return 0 on success, error code on fail + */ +int mxc_dma_get_config(int channel, dma_request_t * p, int bd_index) +{ + int err = 0; + unsigned long bd_status; + unsigned long bd_count; + __u8 *sourceAddr; + __u8 *destAddr; + + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status); + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_COUNT, (unsigned long)&bd_count); + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_BUFFERADDR, (unsigned long)&sourceAddr); + + switch (sdma_data[channel].transfer_type) { + case emi_2_per: + case dsp_2_per: + case int_2_per: + case emi_2_dsp: + case int_2_dsp: + case emi_2_dsp_loop: + p->sourceAddr = sourceAddr; + break; + case per_2_int: + case per_2_emi: + case per_2_dsp: + case dsp_2_int: + case dsp_2_emi: + case dsp_2_dsp: + case dsp_2_emi_loop: + p->destAddr = sourceAddr; + break; + case emi_2_int: + case emi_2_emi: + case int_2_int: + case int_2_emi: + p->sourceAddr = sourceAddr; + iapi_IoCtl(sdma_data[channel].cd, + (bd_index << BD_NUM_OFFSET) | + IAPI_CHANGE_GET_EXTDBUFFERADDR, + (unsigned long)&destAddr); + p->destAddr = destAddr; + break; + default: + break; + } + + p->count = bd_count; + p->bd_done = bd_status & BD_DONE; + p->bd_cont = bd_status & BD_CONT; + p->bd_error = bd_status & BD_RROR; + + return err; +} + +/*! + * This function is used by MXC IPC's write_ex2. It passes the pointer to the + * data control structure to iapi_write_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr) +{ + return iapi_Write_ipcv2(sdma_data[channel].cd, ctrl_ptr); +} + +/*! + * This function is used by MXC IPC's read_ex2. It passes the pointer to the + * data control structure to iapi_read_ipcv2() + * + * @param channel SDMA channel number + * @param ctrl_ptr Data Control structure pointer + */ +int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr) +{ + return iapi_Read_ipcv2(sdma_data[channel].cd, ctrl_ptr); +} + +/*! + * Starts dma channel. + * + * @param channel channel number + */ +int mxc_dma_start(int channel) +{ + if (sdma_data[channel].running == 0) { + sdma_data[channel].running = 1; + iapi_StartChannel(channel); + } + + return 0; +} + +/*! + * Stops dma channel. + * + * @param channel channel number + */ +int mxc_dma_stop(int channel) +{ + iapi_StopChannel(channel); + sdma_data[channel].running = 0; + + return 0; +} + +/*! + * Frees dma channel. + * + * @param channel channel number + */ +void mxc_free_dma(int channel) +{ + int i; + + mxc_dma_stop(channel); + + if (sdma_data[channel].event_id != 0) { + iapi_SetChannelEventMapping(sdma_data[channel].event_id, 0x0); + } + if (sdma_data[channel].event_id2 != 0) { + iapi_SetChannelEventMapping(sdma_data[channel].event_id2, 0x0); + } + + sdma_data[channel].event_id = 0; + + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, 0x0); + iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + + for (i = 0; i < sdma_data[channel].bd_number; i++) { + iapi_IoCtl(sdma_data[channel].cd, + (i << BD_NUM_OFFSET) | + IAPI_CHANGE_SET_STATUS, (unsigned long)0); + } + + iapi_Close(sdma_data[channel].cd); + + strcpy(sdma_data[channel].devicename, "not used"); + + sdma_data[channel].in_use = 0; +} + +/*! + * Initializes channel's priorities + * + */ +static void __init init_priorities(void) +{ + iapi_IoCtl(sdma_data[0].cd, IAPI_CHANGE_PRIORITY, 0x7); +} + +/*! + * Initializes events table + */ +static void __init init_event_table(void) +{ + int channel; + + for (channel = 0; channel < MAX_DMA_CHANNELS; channel++) { + iapi_SetChannelEventMapping(channel, 0); + } +} + +/*! + * Sets callback function. Used with standard dma api + * for supporting interrupts + * + * @param channel channel number + * @param callback callback function pointer + * @param arg argument for callback function + */ +void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg) +{ + sdma_data[channel].callback = callback; + sdma_data[channel].arg = arg; +} + +/*! + * Synchronization function used by I.API + * + * @param channel channel number + */ +static int getChannel(int channel) +{ + if (irqs_disabled() || in_atomic()) { + if (down_trylock(&sdma_synch_mutex[channel])) { + return -EBUSY; + } + } else { + if (down_interruptible(&sdma_synch_mutex[channel])) { + return -EBUSY; + } + } + + return 0; +} + +/*! + * Synchronization function used by I.API + * + * @param channel channel number + */ +static int releaseChannel(int channel) +{ + up(&sdma_synch_mutex[channel]); + return 0; +} + +/*! + * Unmask interrupt function. Used by I.API + * + */ +static void unmask_sdma_interrupt(void) +{ + /* Commented out tp take care of the PREEMPT_RT option + * local_irq_restore(flags); + */ +} + +/*! + * Mask interrupt function. Used by I.API + * + */ +static void mask_sdma_interrupt(void) +{ + /* Commented to take of the PREEMPT_RT option + * local_irq_save(flags); + */ +} + +/*! + * Initializes I.API + */ +static void __init init_iapi_struct(void) +{ + channelDescriptor *cd; + + printk(KERN_INFO "Using SDMA I.API\n"); + + iapi_Malloc = &sdma_malloc; +#ifdef CONFIG_SDMA_IRAM + iapi_iram_Malloc = &sdma_iram_malloc; +#endif /*CONFIG_SDMA_IRAM */ + + iapi_Free = &sdma_free; + iapi_Virt2Phys = (void *(*)(void *))&sdma_virt_to_phys; + iapi_Phys2Virt = (void *(*)(void *))&sdma_phys_to_virt; + iapi_memset = &memset; + iapi_memcpy = &memcpy; + + iapi_GotoSleep = &sdma_sleep_channel; + iapi_WakeUp = &sdma_wakeup_channel; + iapi_InitSleep = &sdma_init_sleep; + iapi_ReleaseChannel = &releaseChannel; + iapi_GetChannel = &getChannel; + + iapi_EnableInterrupts = &unmask_sdma_interrupt; + iapi_DisableInterrupts = &mask_sdma_interrupt; + + cd = kmalloc(sizeof(channelDescriptor), GFP_KERNEL); + + memset(cd, 0, sizeof(channelDescriptor)); + + sdma_data[0].cd = cd; +} + +/*! + * Initializes channel synchronization mutexes + */ +static void __init init_mutexes(void) +{ + int i; + + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + init_MUTEX(&sdma_synch_mutex[i]); + } + + init_MUTEX(&sdma_status_mutex); +} + +/*! + * Channels status read proc file system function + * + * @param buf pointer to the buffer the data shuld be written to. + * @param start pointer to the pointer where the new data is + * written to. + * procedure should update the start pointer to point to + * where in the buffer the data was written. + * @param offset offset from start of the file + * @param count number of bytes to read. + * @param eof pointer to eof flag. sould be set to 1 when + * reaching eof. + * @param data driver specific data pointer. + * + * @return number byte read from the log buffer. + */ +static int proc_read_channels(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + char *log; + char *log_ptr; + char tmp[48]; + int i; + + log = kmalloc(4096, GFP_KERNEL); + memset(log, 0, 4096); + log_ptr = log; + + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + if (sdma_data[i].in_use == 0) { + continue; + } + + memset(tmp, 0, 48); + sprintf(tmp, "Channel %d: %s\n", i, sdma_data[i].devicename); + + strcpy(log_ptr, tmp); + log_ptr += strlen(tmp); + } + + if (offset > strlen(log)) { + *eof = 1; + count = 0; + } else { + if (offset + count > strlen(log)) { + count = strlen(log) - offset; + *eof = 1; + } else { + *eof = 0; + } + + memcpy(buf, log, count); + *start = buf; + kfree(log); + } + + return count; +} + +/*! + * SDMA proc file system read function + */ +static int __init init_proc_fs(void) +{ + struct proc_dir_entry *sdma_proc_dir; + int res; + + res = 0; + + sdma_proc_dir = proc_mkdir("sdma", NULL); + create_proc_read_entry("channels", 0, sdma_proc_dir, + proc_read_channels, NULL); + + if (res < 0) { + printk(KERN_WARNING "Failed create SDMA proc entry\n"); + } + + return res; +} + +/*! + * Initializes SDMA private data + */ +static void __init init_sdma_data(void) +{ + int i; + + memset(sdma_data, 0, sizeof(sdma_struct) * MAX_DMA_CHANNELS); + sdma_data[0].in_use = 1; + strcpy(sdma_data[0].devicename, "MCU"); + + for (i = 0; i < MAX_DMA_CHANNELS; i++) { + sdma_data[i].channel = i; + } +} + +#if defined(CONFIG_MXC_SUPER_GEM) +/*! + * Initialize the Super GEM SDMA channel + * + * @return returns -1 on error, 0 on success. + */ +static int __init init_super_gem(void) +{ + channelDescriptor *cd; + script_data context; + int res = 0; + + res = iapi_Open(sdma_data[0].cd, MXC_DMA_CHANNEL_GEM); + if (res < 0) { + return -1; + } + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 1; + cd = CHAD(MXC_DMA_CHANNEL_GEM); + memset(&context, 0, sizeof(script_data)); + context.load_address = sdma_script_addrs.mxc_sdma_utra_addr; + context.wml = M3_BASE_ADDRESS; + res = iapi_AssignScript(cd, &context); + if (res < 0) { + iapi_Close(cd); + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; + return -1; + } + res = + iapi_IoCtl(cd, IAPI_CHANGE_OWNERSHIP, + (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | + (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | + (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); + if (res < 0) { + iapi_Close(cd); + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; + return -1; + } + /* Set EP=1, which is required to start SuperGem script the first time */ + /* This can be done only on the AP side */ + SDMA_H_EVTPEND |= 1 << MXC_DMA_CHANNEL_GEM; + + res = + iapi_SetChannelEventMapping(DMA_REQ_GEM, 1 << MXC_DMA_CHANNEL_GEM); + if (res < 0) { + iapi_Close(cd); + sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; + return -1; + } + + return 0; +} +#endif + +/*! + * Initializes dma + */ +int __init sdma_init(void) +{ + int res = 0; + configs_data confreg_data; + + /* Initialize to the default values */ + confreg_data = iapi_ConfigDefaults; + + confreg_data.dspdma = 0; + /* Set ACR bit */ + mxc_sdma_ahb_clk = clk_get(NULL, "sdma_ahb_clk"); + mxc_sdma_ipg_clk = clk_get(NULL, "sdma_ipg_clk"); + clk_enable(mxc_sdma_ahb_clk); + clk_enable(mxc_sdma_ipg_clk); + if (clk_get_rate(mxc_sdma_ahb_clk) / clk_get_rate(mxc_sdma_ipg_clk) < 2) { + printk(KERN_INFO "Setting SDMA ACR\n"); + confreg_data.acr = 1; + } + + init_sdma_data(); + + init_sdma_pool(); + + res = request_irq(MXC_INT_SDMA, sdma_int_handler, 0, "mxcsdma", 0); + + if (res < 0) { + goto sdma_init_fail; + } + + init_mutexes(); + + init_iapi_struct(); + + mxc_sdma_get_script_info(&sdma_script_addrs); + + res = iapi_Init(sdma_data[0].cd, &confreg_data, + sdma_script_addrs.mxc_sdma_start_addr, + sdma_script_addrs.mxc_sdma_ram_code_size * 2, + sdma_script_addrs.mxc_sdma_ram_code_start_addr); + + if (res < 0) { + free_irq(MXC_INT_SDMA, 0); + goto sdma_init_fail; + } + + init_priorities(); + + init_event_table(); + +#if defined(CONFIG_MXC_SUPER_GEM) + res = init_super_gem(); + if (res < 0) { + free_irq(MXC_INT_SDMA, 0); + goto sdma_init_fail; + } +#endif + + init_proc_fs(); + + printk(KERN_INFO "MXC DMA API initialized\n"); + + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + return res; + + sdma_init_fail: + printk(KERN_ERR "Error 0x%x in sdma_init\n", res); + clk_disable(mxc_sdma_ahb_clk); + clk_disable(mxc_sdma_ipg_clk); + return res; + +} + +arch_initcall(sdma_init); + +EXPORT_SYMBOL(mxc_request_dma); +EXPORT_SYMBOL(mxc_free_dma); +EXPORT_SYMBOL(mxc_dma_setup_channel); +EXPORT_SYMBOL(mxc_dma_set_channel_priority); +EXPORT_SYMBOL(mxc_dma_set_config); +EXPORT_SYMBOL(mxc_dma_get_config); +EXPORT_SYMBOL(mxc_dma_set_bd_intr); +EXPORT_SYMBOL(mxc_dma_get_bd_intr); +EXPORT_SYMBOL(mxc_dma_reset); +EXPORT_SYMBOL(mxc_sdma_write_ipcv2); +EXPORT_SYMBOL(mxc_sdma_read_ipcv2); +EXPORT_SYMBOL(mxc_dma_start); +EXPORT_SYMBOL(mxc_dma_stop); +EXPORT_SYMBOL(sdma_malloc); +EXPORT_SYMBOL(sdma_free); +EXPORT_SYMBOL(mxc_dma_set_callback); +EXPORT_SYMBOL(sdma_virt_to_phys); +EXPORT_SYMBOL(sdma_phys_to_virt); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC Linux SDMA API"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/sdma/sdma_malloc.c b/arch/arm/plat-mxc/sdma/sdma_malloc.c new file mode 100644 index 000000000000..21118b42c855 --- /dev/null +++ b/arch/arm/plat-mxc/sdma/sdma_malloc.c @@ -0,0 +1,387 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/sdma/sdma_malloc.c + * @brief This file contains functions for SDMA non-cacheable buffers allocation + * + * SDMA (Smart DMA) is used for transferring data between MCU and peripherals + * + * @ingroup SDMA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DEBUG 0 + +#if DEBUG +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef CONFIG_SDMA_IRAM +#define IRAM_VIRT_BASE IRAM_BASE_ADDR_VIRT +#define IRAM_PHYS_BASE IRAM_BASE_ADDR +#if (CONFIG_SDMA_IRAM_SIZE&0x3FF) +#error "IRAM size of SDMA should be multiple of 1Kbytes" +#else +#define IRAM_SDMA_SIZE CONFIG_SDMA_IRAM_SIZE /* 4K */ +#endif +#define IRAM_UNIT_SIZE 512 +#define IRAM_POOL_SIZE (IRAM_SDMA_SIZE/IRAM_UNIT_SIZE) + +#define IS_IRAM_VIRT(x) (((x)IRAM_SDMA_SIZE)?0:1) + +#define IS_IRAM_PHYS(x) (((x)IRAM_SDMA_SIZE)?0:1) +#endif /*CONFIG_SDMA_IRAM */ + +/*! + * Defines SDMA non-cacheable buffers pool + */ +static struct dma_pool *pool; + +#ifdef CONFIG_SDMA_IRAM +typedef struct iram_head_s { + struct list_head list; +} iram_head_t; + +static spinlock_t iram_pool_lock = SPIN_LOCK_UNLOCKED; +static struct list_head iram_free_list; +static unsigned char iram_pool_flag[IRAM_POOL_SIZE]; + +static void sdma_iram_free(void *buf); +#endif /*CONFIG_SDMA_IRAM */ + +/*! + * SDMA memory conversion hashing structure + */ +typedef struct { + struct list_head node; + int use_count; + /*! Virtual address */ + void *virt; + /*! Physical address */ + unsigned long phys; +} virt_phys_struct; + +static struct list_head buf_map; + +/*! + * Defines the size of each buffer in SDMA pool. + * The size must be at least 512 bytes, because + * sdma channel control blocks array size is 512 bytes + */ +#define SDMA_POOL_SIZE 1024 + +/*! + * Adds new buffer structure into conversion hash tables + * + * @param vf SDMA memory conversion hashing structure + * + * @return 1 on success, 0 on fail + */ +static int add_entry(virt_phys_struct * vf) +{ + virt_phys_struct *p; + + vf->phys &= PAGE_MASK; + vf->virt = (void *)((u32) vf->virt & PAGE_MASK); + + list_for_each_entry(p, &buf_map, node) { + if (p->virt == vf->virt) { + p->use_count++; + return 0; + } + } + + p = kmalloc(sizeof(virt_phys_struct), GFP_KERNEL); + if (p == 0) { + return -ENOMEM; + } + + *p = *vf; + p->use_count = 1; + list_add_tail(&p->node, &buf_map); + + DPRINTK("added vaddr 0x%p, paddr 0x%08X to list\n", p->virt, p->phys); + + return 0; +} + +/*! + * Deletes buffer stracture from conversion hash tables + * + * @param buf SDMA memory buffer virtual addr + * + * @return 0 on success, -1 on fail + */ +static int delete_entry(void *buf) +{ + virt_phys_struct *p; + + buf = (void *)((u32) buf & PAGE_MASK); + + list_for_each_entry(p, &buf_map, node) { + if (p->virt == buf) { + p->use_count--; + break; + } + } + + if (p->use_count == 0) { + list_del(&p->node); + kfree(p); + } + + return 0; +} + +/*! + * Virtual to physical address conversion functio + * + * @param buf pointer to virtual address + * + * @return physical address + */ +unsigned long sdma_virt_to_phys(void *buf) +{ + u32 offset = (u32) buf & (~PAGE_MASK); + virt_phys_struct *p; + + DPRINTK("searching for vaddr 0x%p\n", buf); + +#ifdef CONFIG_SDMA_IRAM + if (IS_IRAM_VIRT((unsigned long)buf)) { + if ((unsigned long)buf & (IRAM_UNIT_SIZE - 1)) { + printk(KERN_WARNING "%s buffer offset = %ld\n", + __FUNCTION__, (unsigned long)buf); + } + return (unsigned long)buf + IRAM_PHYS_BASE - IRAM_VIRT_BASE; + } +#endif /*CONFIG_SDMA_IRAM */ + + list_for_each_entry(p, &buf_map, node) { + if ((u32) p->virt == ((u32) buf & PAGE_MASK)) { + return p->phys | offset; + } + } + + if (virt_addr_valid(buf)) { + return virt_to_phys(buf); + } + + printk(KERN_WARNING + "SDMA malloc: could not translate virt address 0x%p\n", buf); + return 0; +} + +/*! + * Physical to virtual address conversion functio + * + * @param buf pointer to physical address + * + * @return virtual address + */ +void *sdma_phys_to_virt(unsigned long buf) +{ + u32 offset = buf & (~PAGE_MASK); + virt_phys_struct *p; + +#ifdef CONFIG_SDMA_IRAM + if (IS_IRAM_PHYS((unsigned long)buf)) { + if (buf & (IRAM_UNIT_SIZE - 1)) { + printk(KERN_WARNING "%s buffer offset = %ld\n", + __FUNCTION__, (unsigned long)buf); + } + return (void *)buf + IRAM_VIRT_BASE - IRAM_PHYS_BASE; + } +#endif /*CONFIG_SDMA_IRAM */ + + list_for_each_entry(p, &buf_map, node) { + if (p->phys == (buf & PAGE_MASK)) { + return (void *)((u32) p->virt | offset); + } + } + + printk(KERN_WARNING + "SDMA malloc: could not translate phys address 0x%lx\n", buf); + return 0; +} + +/*! + * Allocates uncacheable buffer + * + * @param size size of allocated buffer + * @return pointer to buffer + */ +void *sdma_malloc(size_t size) +{ + void *buf; + dma_addr_t dma_addr; + virt_phys_struct vf; + + if (size > SDMA_POOL_SIZE) { + printk(KERN_WARNING + "size in sdma_malloc is more than %d bytes\n", + SDMA_POOL_SIZE); + buf = 0; + } else { + buf = dma_pool_alloc(pool, GFP_KERNEL, &dma_addr); + if (buf > 0) { + vf.virt = buf; + vf.phys = dma_addr; + + if (add_entry(&vf) < 0) { + dma_pool_free(pool, buf, dma_addr); + buf = 0; + } + } + } + + DPRINTK("allocated vaddr 0x%p\n", buf); + return buf; +} + +/*! + * Frees uncacheable buffer + * + * @param buf buffer pointer for deletion + */ +void sdma_free(void *buf) +{ +#ifdef CONFIG_SDMA_IRAM + if (IS_IRAM_VIRT((unsigned long)buf)) { + sdma_iram_free(buf); + return; + } +#endif /*CONFIG_SDMA_IRAM */ + + dma_pool_free(pool, buf, sdma_virt_to_phys(buf)); + delete_entry(buf); +} + +#ifdef CONFIG_SDMA_IRAM +/*! + * Allocates uncacheable buffer from IRAM + */ +void *sdma_iram_malloc(size_t size) +{ + void *buf = NULL; + int index = -1; + unsigned long flags; + if (size > IRAM_UNIT_SIZE) { + printk(KERN_WARNING + "size in sdma_iram_malloc is more than %d bytes\n", + IRAM_UNIT_SIZE); + } else { + spin_lock_irqsave(&iram_pool_lock, flags); + if (!list_empty(&iram_free_list)) { + buf = + list_entry(iram_free_list.next, iram_head_t, list); + list_del(iram_free_list.next); + index = + ((unsigned long)buf - + IRAM_VIRT_BASE) / IRAM_UNIT_SIZE; + if (index < 0 || index >= IRAM_POOL_SIZE) { + spin_unlock_irqrestore(&iram_pool_lock, flags); + printk(KERN_ERR "The iram pool has crashed\n"); + return NULL; + } + if (iram_pool_flag[index]) { + spin_unlock_irqrestore(&iram_pool_lock, flags); + printk(KERN_WARNING + "iram block %d already has been allocated \n", + index); + } + iram_pool_flag[index] = 1; + } + spin_unlock_irqrestore(&iram_pool_lock, flags); + if ((unsigned long)buf & (IRAM_UNIT_SIZE - 1)) { + printk(KERN_WARNING + "the start address is not align of %d, buffer offset %ld\n", + IRAM_UNIT_SIZE, (unsigned long)buf); + + buf = PTR_ALIGN(buf, IRAM_UNIT_SIZE); + } + } + return buf; +} + +/*! + * Free uncacheable buffer into IRAM. + */ +static void sdma_iram_free(void *buf) +{ + iram_head_t *p; + int index; + unsigned long flags; + /* The check of parameter will be done in sdma_free */ + index = ((unsigned long)buf - IRAM_VIRT_BASE) / IRAM_UNIT_SIZE; + spin_lock_irqsave(&iram_pool_lock, flags); + p = (iram_head_t *) ((unsigned long)buf & (~(IRAM_UNIT_SIZE - 1))); + list_add_tail(&(p->list), &iram_free_list); + if (iram_pool_flag[index]) { + iram_pool_flag[index] = 0; + spin_unlock_irqrestore(&iram_pool_lock, flags); + } else { + printk(KERN_WARNING + "Free %p which IRAM block %d is already freed\n", buf, + index); + spin_unlock_irqrestore(&iram_pool_lock, flags); + } +} + +/*! + * Initialized the free list of IRAM. + */ +static void iram_pool_init(void) +{ + int i; + iram_head_t *p; + memset(iram_pool_flag, 0, IRAM_POOL_SIZE); + INIT_LIST_HEAD(&iram_free_list); + for (i = 0; i < IRAM_POOL_SIZE; i++) { + p = (iram_head_t *) (IRAM_VIRT_BASE + i * IRAM_UNIT_SIZE); + list_add_tail(&(p->list), &iram_free_list); + } +} +#endif /*CONFIG_SDMA_IRAM */ + +/*! + * SDMA buffers pool initialization function + */ +void __init init_sdma_pool(void) +{ +#ifdef CONFIG_SDMA_IRAM + iram_pool_init(); +#endif /*CONFIG_SDMA_IRAM */ + + pool = dma_pool_create("SDMA", NULL, SDMA_POOL_SIZE, 0, 0); + + INIT_LIST_HEAD(&buf_map); +} + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC Linux SDMA API"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/serialxc.c b/arch/arm/plat-mxc/serialxc.c new file mode 100644 index 000000000000..cf18bfdc8a76 --- /dev/null +++ b/arch/arm/plat-mxc/serialxc.c @@ -0,0 +1,64 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void usb_serial_init(struct fsl_xcvr_ops *this) +{ +} + +static void usb_serial_uninit(struct fsl_xcvr_ops *this) +{ +} + +static struct fsl_xcvr_ops serial_ops = { + .name = "serial", + .xcvr_type = PORTSC_PTS_SERIAL, + .init = usb_serial_init, + .uninit = usb_serial_uninit, +}; + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); + +static int __init serialxc_init(void) +{ + pr_debug("%s\n", __FUNCTION__); + + fsl_usb_xcvr_register(&serial_ops); + + return 0; +} + +extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops); + +static void __exit serialxc_exit(void) +{ + fsl_usb_xcvr_unregister(&serial_ops); +} + +module_init(serialxc_init); +module_exit(serialxc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("serial xcvr driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/snoop.c b/arch/arm/plat-mxc/snoop.c new file mode 100644 index 000000000000..b6e48c7e59d0 --- /dev/null +++ b/arch/arm/plat-mxc/snoop.c @@ -0,0 +1,133 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include + +#ifdef M4IF_BASE_ADDR +#define SNOOP_V2 +#define MAX_SNOOP 2 +#define g_snoop_base (IO_ADDRESS(M4IF_BASE_ADDR) + 0x4C) +#elif defined(M3IF_BASE_ADDR) +#define MAX_SNOOP 1 +#define g_snoop_base (IO_ADDRESS(M3IF_BASE_ADDR) + 0x28) +#else +#define MAX_SNOOP 0 +#define g_snoop_base 0 +#endif + +/* M3IF Snooping Configuration Register 0 (M3IFSCFG0) READ/WRITE*/ +#define SBAR(x) (x * 0x14) +/* M3IF Snooping Configuration Register 1 (M3IFSCFG1) READ/WRITE*/ +#define SERL(x) ((x * 0x14) + 0x4) +/* M3IF Snooping Configuration Register 2 (M3IFSCFG2) READ/WRITE*/ +#define SERH(x) ((x * 0x14) + 0x8) +/* M3IF Snooping Status Register 0 (M3IFSSR0) READ/WRITE */ +#define SSRL(x) ((x * 0x14) + 0xC) +/* M3IF Snooping Status Register 1 (M3IFSSR1) */ +#define SSRH(x) ((x * 0x14) + 0x10) + +#if MAX_SNOOP + +int mxc_snoop_set_config(u32 num, unsigned long base, int size) +{ + u32 reg; + uint32_t msb; + uint32_t seg_size; + uint32_t window_size = 0; + int i; + + if (num >= MAX_SNOOP) { + return -EINVAL; + } + + /* Setup M3IF for snooping */ + if (size) { + + if (base == 0) { + return -EINVAL; + } + + msb = fls(size); + if (!(size & ((1UL << msb) - 1))) + msb--; /* Already aligned to power 2 */ + if (msb < 11) + msb = 11; + + window_size = (1UL << msb); + seg_size = window_size / 64; + + msb -= 11; + + reg = base & ~((1UL << msb) - 1); + reg |= msb << 1; + reg |= 1; /* enable snooping */ + reg |= 0x80; /* Set pulse width to default (M4IF only) */ + __raw_writel(reg, g_snoop_base + SBAR(num)); + + reg = 0; + for (i = 0; i < 32; i++) { + if (i * seg_size >= size) + break; + reg |= 1UL << i; + } + __raw_writel(reg, g_snoop_base + SERL(num)); + + reg = 0; + for (i = 32; i < 64; i++) { + if (i * seg_size >= size) + break; + reg |= 1UL << (i - 32); + } + __raw_writel(reg, g_snoop_base + SERH(num)); + + pr_debug + ("Snooping unit # %d enabled: window size = 0x%X, M3IFSCFG0=0x%08X, M3IFSCFG1=0x%08X, M3IFSCFG2=0x%08X\n", + num, window_size, __raw_readl(g_snoop_base + SBAR(num)), + __raw_readl(g_snoop_base + SERL(num)), + __raw_readl(g_snoop_base + SERH(num))); + } else { + __raw_writel(0, g_snoop_base + SBAR(num)); + } + + return window_size; +} + +EXPORT_SYMBOL(mxc_snoop_set_config); + +int mxc_snoop_get_status(u32 num, u32 * statl, u32 * stath) +{ + if (num >= MAX_SNOOP) { + return -EINVAL; + } + + *statl = __raw_readl(g_snoop_base + SSRL(num)); + *stath = __raw_readl(g_snoop_base + SSRH(num)); + /* DPRINTK("status = 0x%08X%08X\n", stat[1], stat[0]); */ + +#ifdef SNOOP_V2 + __raw_writel(*statl, g_snoop_base + SSRL(num)); + __raw_writel(*stath, g_snoop_base + SSRH(num)); +#else + __raw_writel(0x0, g_snoop_base + SSRL(num)); + __raw_writel(0x0, g_snoop_base + SSRH(num)); +#endif + return 0; +} + +EXPORT_SYMBOL(mxc_snoop_get_status); + +#endif /* MAX_SNOOP */ diff --git a/arch/arm/plat-mxc/spba.c b/arch/arm/plat-mxc/spba.c new file mode 100644 index 000000000000..a7f21a9e36df --- /dev/null +++ b/arch/arm/plat-mxc/spba.c @@ -0,0 +1,133 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include + +/*! + * @file plat-mxc/spba.c + * + * @brief This file contains the SPBA API implementation details. + * + * @ingroup SPBA + */ + +static DEFINE_SPINLOCK(spba_lock); + +#define SPBA_MASTER_MIN 1 +#define SPBA_MASTER_MAX 7 + +/*! + * the base addresses for the SPBA modules + */ +static unsigned long spba_base = (unsigned long)IO_ADDRESS(SPBA_CTRL_BASE_ADDR); + +/*! + * SPBA clock + */ +static struct clk *spba_clk; +/*! + * This function allows the three masters (A, B, C) to take ownership of a + * shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; -1 otherwise. + */ +int spba_take_ownership(int mod, int master) +{ + unsigned long spba_flags; + __u32 rtn_val = -1; + + if (master < SPBA_MASTER_MIN || master > SPBA_MASTER_MAX) { + printk("spba_take_ownership() invalide master= %d\n", master); + BUG(); /* oops */ + } + + if (spba_clk == NULL) + spba_clk = clk_get(NULL, "spba_clk"); + + clk_enable(spba_clk); + + spin_lock_irqsave(&spba_lock, spba_flags); + __raw_writel(master, spba_base + mod); + + if ((__raw_readl(spba_base + mod) & MXC_SPBA_RAR_MASK) == master) { + rtn_val = 0; + } + + spin_unlock_irqrestore(&spba_lock, spba_flags); + + clk_disable(spba_clk); + return rtn_val; +} + +/*! + * This function releases the ownership for a shared peripheral. + * + * @param mod specified module as defined in \b enum \b #spba_module + * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters + * + * @return 0 if successful; -1 otherwise. + */ +int spba_rel_ownership(int mod, int master) +{ + unsigned long spba_flags; + volatile unsigned long rar; + + if (master < SPBA_MASTER_MIN || master > SPBA_MASTER_MAX) { + printk("spba_take_ownership() invalide master= %d\n", master); + BUG(); /* oops */ + } + + if (spba_clk == NULL) + spba_clk = clk_get(NULL, "spba_clk"); + + clk_enable(spba_clk); + + if ((__raw_readl(spba_base + mod) & master) == 0) { + clk_disable(spba_clk); + return 0; /* does not own it */ + } + + spin_lock_irqsave(&spba_lock, spba_flags); + + /* Since only the last 3 bits are writeable, doesn't need to mask off + bits 31-3 */ + rar = __raw_readl(spba_base + mod) & (~master); + __raw_writel(rar, spba_base + mod); + + if ((__raw_readl(spba_base + mod) & master) != 0) { + spin_unlock_irqrestore(&spba_lock, spba_flags); + clk_disable(spba_clk); + return -1; + } + + spin_unlock_irqrestore(&spba_lock, spba_flags); + + clk_disable(spba_clk); + + return 0; +} + +EXPORT_SYMBOL(spba_take_ownership); +EXPORT_SYMBOL(spba_rel_ownership); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("SPBA"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c index 88fb3a57e029..fbf86e42c3f4 100644 --- a/arch/arm/plat-mxc/time.c +++ b/arch/arm/plat-mxc/time.c @@ -50,6 +50,7 @@ /* MX31, MX35 */ #define MX3_TCTL_WAITEN (1 << 3) #define MX3_TCTL_CLK_IPG (1 << 6) +#define MX3_TCTL_CLK_PER (2 << 6) #define MX3_TCTL_FRR (1 << 9) #define MX3_IR 0x0c #define MX3_TSTAT 0x08 @@ -57,6 +58,8 @@ #define MX3_TCN 0x24 #define MX3_TCMP 0x10 +#define timer_is_v2() (!(cpu_is_mx1() || cpu_is_mx2()) || cpu_is_mx25()) + static struct clock_event_device clockevent_mxc; static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED; @@ -66,7 +69,7 @@ static inline void gpt_irq_disable(void) { unsigned int tmp; - if (cpu_is_mx3()) + if (timer_is_v2()) __raw_writel(0, timer_base + MX3_IR); else { tmp = __raw_readl(timer_base + MXC_TCTL); @@ -76,7 +79,7 @@ static inline void gpt_irq_disable(void) static inline void gpt_irq_enable(void) { - if (cpu_is_mx3()) + if (timer_is_v2()) __raw_writel(1<<0, timer_base + MX3_IR); else { __raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN, @@ -90,7 +93,7 @@ static void gpt_irq_acknowledge(void) __raw_writel(0, timer_base + MX1_2_TSTAT); if (cpu_is_mx2()) __raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP, timer_base + MX1_2_TSTAT); - if (cpu_is_mx3()) + if (timer_is_v2()) __raw_writel(MX3_TSTAT_OF1, timer_base + MX3_TSTAT); } @@ -117,7 +120,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk) { unsigned int c = clk_get_rate(timer_clk); - if (cpu_is_mx3()) + if (timer_is_v2()) clocksource_mxc.read = mx3_get_cycles; clocksource_mxc.mult = clocksource_hz2mult(c, @@ -180,7 +183,7 @@ static void mxc_set_mode(enum clock_event_mode mode, if (mode != clockevent_mode) { /* Set event time into far-far future */ - if (cpu_is_mx3()) + if (timer_is_v2()) __raw_writel(__raw_readl(timer_base + MX3_TCN) - 3, timer_base + MX3_TCMP); else @@ -233,7 +236,7 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id) struct clock_event_device *evt = &clockevent_mxc; uint32_t tstat; - if (cpu_is_mx3()) + if (timer_is_v2()) tstat = __raw_readl(timer_base + MX3_TSTAT); else tstat = __raw_readl(timer_base + MX1_2_TSTAT); @@ -264,7 +267,7 @@ static int __init mxc_clockevent_init(struct clk *timer_clk) { unsigned int c = clk_get_rate(timer_clk); - if (cpu_is_mx3()) + if (timer_is_v2()) clockevent_mxc.set_next_event = mx3_set_next_event; clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC, @@ -281,10 +284,9 @@ static int __init mxc_clockevent_init(struct clk *timer_clk) return 0; } -void __init mxc_timer_init(struct clk *timer_clk) +void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq) { uint32_t tctl_val; - int irq; clk_enable(timer_clk); @@ -303,8 +305,10 @@ void __init mxc_timer_init(struct clk *timer_clk) timer_base = IO_ADDRESS(GPT1_BASE_ADDR); irq = MXC_INT_GPT; #endif - } else - BUG(); + } + if (base) { + timer_base = base; + } /* * Initialise to a known state (all timers off, and timing reset) @@ -313,8 +317,8 @@ void __init mxc_timer_init(struct clk *timer_clk) __raw_writel(0, timer_base + MXC_TCTL); __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */ - if (cpu_is_mx3()) - tctl_val = MX3_TCTL_CLK_IPG | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN; + if (timer_is_v2()) + tctl_val = MX3_TCTL_CLK_PER | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN; else tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN; diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c new file mode 100644 index 000000000000..630d9f789f95 --- /dev/null +++ b/arch/arm/plat-mxc/tzic.c @@ -0,0 +1,181 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + ***************************************** + * TZIC Registers * + ***************************************** + */ +#define TZIC_BASE IO_ADDRESS(TZIC_BASE_ADDR) +#define TZIC_INTCNTL (TZIC_BASE + 0x0000) /* control register */ +#define TZIC_INTTYPE (TZIC_BASE + 0x0004) /* Controller type register */ +#define TZIC_IMPID (TZIC_BASE + 0x0008) /* Distributor Implementer Identification Register */ +#define TZIC_PRIOMASK (TZIC_BASE + 0x000C) /* Priority Mask Reg */ +#define TZIC_SYNCCTRL (TZIC_BASE + 0x0010) /* Synchronizer Control register */ +#define TZIC_DSMINT (TZIC_BASE + 0x0014) /* DSM interrupt Holdoffregister */ +#define TZIC_INTSEC0 (TZIC_BASE + 0x0080) /* interrupt security register 0 */ +#define TZIC_ENSET0 (TZIC_BASE + 0x0100) /* Enable Set Register 0 */ +#define TZIC_ENCLEAR0 (TZIC_BASE + 0x0180) /* Enable Clear Register 0 */ +#define TZIC_SRCSET0 (TZIC_BASE + 0x0200) /* Source Set Register 0 */ +#define TZIC_SRCCLAR0 (TZIC_BASE + 0x0280) /* Source Clear Register 0 */ +#define TZIC_PRIORITY0 (TZIC_BASE + 0x0400) /* Priority Register 0 */ +#define TZIC_PND0 (TZIC_BASE + 0x0D00) /* Pending Register 0 */ +#define TZIC_HIPND0 (TZIC_BASE + 0x0D80) /* High Priority Pending Register */ +#define TZIC_WAKEUP0 (TZIC_BASE + 0x0E00) /* Wakeup Config Register */ +#define TZIC_SWINT (TZIC_BASE + 0x0F00) /* Software Interrupt Rigger Register */ +#define TZIC_ID0 (TZIC_BASE + 0x0FD0) /* Indentification Register 0 */ + +#define TZIC_NUM_IRQS 128 + +/*! + * Disable interrupt number "irq" in the TZIC + * + * @param irq interrupt source number + */ +static void mxc_mask_irq(unsigned int irq) +{ + int index, off; + + index = irq >> 5; + off = irq & 0x1F; + __raw_writel(1 << off, TZIC_ENCLEAR0 + (index << 2)); +} + +/*! + * Enable interrupt number "irq" in the TZIC + * + * @param irq interrupt source number + */ +static void mxc_unmask_irq(unsigned int irq) +{ + int index, off; + + index = irq >> 5; + off = irq & 0x1F; + __raw_writel(1 << off, TZIC_ENSET0 + (index << 2)); +} + +static unsigned int wakeup_intr[4]; + +/*! + * Set interrupt number "irq" in the TZIC as a wake-up source. + * + * @param irq interrupt source number + * @param enable enable as wake-up if equal to non-zero + * disble as wake-up if equal to zero + * + * @return This function returns 0 on success. + */ +static int mxc_set_wake_irq(unsigned int irq, unsigned int enable) +{ + unsigned int index, off; + + index = irq >> 5; + off = irq & 0x1F; + + if (index > 3) + return -1; + + if (enable) + wakeup_intr[index] |= (1 << off); + else + wakeup_intr[index] &= ~(1 << off); + + return 0; +} + +static struct irq_chip mxc_tzic_chip = { + .name = "MXC_TZIC", + .ack = mxc_mask_irq, + .mask = mxc_mask_irq, + .unmask = mxc_unmask_irq, + .set_wake = mxc_set_wake_irq, +}; + +/*! + * This function initializes the TZIC hardware and disables all the + * interrupts. It registers the interrupt enable and disable functions + * to the kernel for each interrupt source. + */ +void __init mxc_init_irq(void) +{ + int i; + + /* put the TZIC into the reset value with + * all interrupts disabled + */ + i = __raw_readl(TZIC_INTCNTL); + + __raw_writel(0x80010001, TZIC_INTCNTL); + i = __raw_readl(TZIC_INTCNTL); + __raw_writel(0x1f, TZIC_PRIOMASK); + i = __raw_readl(TZIC_PRIOMASK); + __raw_writel(0x02, TZIC_SYNCCTRL); + i = __raw_readl(TZIC_SYNCCTRL); + for (i = 0; i < 4; i++) { + __raw_writel(0xFFFFFFFF, TZIC_INTSEC0 + i * 4); + } + /* disable all interrupts */ + for (i = 0; i < 4; i++) { + __raw_writel(0xFFFFFFFF, TZIC_ENCLEAR0 + i * 4); + } + + /* all IRQ no FIQ Warning :: No selection */ + + for (i = 0; i < TZIC_NUM_IRQS; i++) { + set_irq_chip(i, &mxc_tzic_chip); + set_irq_handler(i, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + + printk(KERN_INFO "MXC IRQ initialized\n"); +} + +/*! + * enable wakeup interrupt + * + * @param is_idle 1 if called in idle loop (enset registers); + * 0 to be used when called from low power entry + * @return 0 if successful; non-zero otherwise + */ +int tzic_enable_wake(int is_idle) +{ + unsigned int i, v; + + __raw_writel(1, TZIC_DSMINT); + if (unlikely(__raw_readl(TZIC_DSMINT) == 0)) + return -EAGAIN; + + if (likely(is_idle)) { + for (i = 0; i < 4; i++) { + v = __raw_readl(TZIC_ENSET0 + i * 4); + __raw_writel(v, TZIC_WAKEUP0 + i * 4); + } + } else { + for (i = 0; i < 4; i++) { + v = wakeup_intr[i]; + __raw_writel(v, TZIC_WAKEUP0 + i * 4); + } + } + return 0; +} diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c new file mode 100644 index 000000000000..a1f53fd9f3be --- /dev/null +++ b/arch/arm/plat-mxc/usb_common.c @@ -0,0 +1,860 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * otg_{get,set}_transceiver() are from arm/plat-omap/usb.c. + * which is Copyright (C) 2004 Texas Instruments, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + *@defgroup USB ARC OTG USB Driver + */ + +/*! + * @file usb_common.c + * + * @brief platform related part of usb driver. + * @ingroup USB + */ + +/*! + *Include files + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MXC_NUMBER_USB_TRANSCEIVER 6 +struct fsl_xcvr_ops *g_xc_ops[MXC_NUMBER_USB_TRANSCEIVER] = { NULL }; + +static struct clk *usb_clk; +static struct clk *usb_ahb_clk; + +extern int gpio_usbotg_hs_active(void); +extern int gpio_usbotg_hs_inactive(void); + +/* + * make sure USB_CLK is running at 60 MHz +/- 1000 Hz + */ +static int fsl_check_usbclk(void) +{ + unsigned long freq; + + usb_ahb_clk = clk_get(NULL, "usb_ahb_clk"); + if (clk_enable(usb_ahb_clk)) { + printk(KERN_ERR "clk_enable(usb_ahb_clk) failed\n"); + return -EINVAL; + } + clk_put(usb_ahb_clk); + + usb_clk = clk_get(NULL, "usb_clk"); + freq = clk_get_rate(usb_clk); + clk_put(usb_clk); + if ((freq < 59999000) || (freq > 60001000)) { + printk(KERN_ERR "USB_CLK=%lu, should be 60MHz\n", freq); + return -1; + } + + return 0; +} + +void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops) +{ + int i; + + pr_debug("%s\n", __func__); + for (i = 0; i < MXC_NUMBER_USB_TRANSCEIVER; i++) { + if (g_xc_ops[i] == NULL) { + g_xc_ops[i] = xcvr_ops; + return; + } + } + + pr_debug("Failed %s\n", __func__); +} +EXPORT_SYMBOL(fsl_usb_xcvr_register); + +void fsl_platform_set_test_mode (struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode) +{ + if (pdata->xcvr_ops && pdata->xcvr_ops->set_test_mode) + pdata->xcvr_ops->set_test_mode((u32 *)(pdata->regs + ULPIVW_OFF), mode); +} +EXPORT_SYMBOL(fsl_platform_set_test_mode); + +void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops) +{ + int i; + + pr_debug("%s\n", __func__); + for (i = 0; i < MXC_NUMBER_USB_TRANSCEIVER; i++) { + if (g_xc_ops[i] == xcvr_ops) { + g_xc_ops[i] = NULL; + return; + } + } + + pr_debug("Failed %s\n", __func__); +} +EXPORT_SYMBOL(fsl_usb_xcvr_unregister); + +static struct fsl_xcvr_ops *fsl_usb_get_xcvr(char *name) +{ + int i; + + pr_debug("%s\n", __func__); + if (name == NULL) { + printk(KERN_ERR "get_xcvr(): No tranceiver name\n"); + return NULL; + } + + for (i = 0; i < MXC_NUMBER_USB_TRANSCEIVER; i++) { + if (strcmp(g_xc_ops[i]->name, name) == 0) { + return g_xc_ops[i]; + } + } + pr_debug("Failed %s\n", __func__); + return NULL; +} + +/* The dmamask must be set for EHCI to work */ +static u64 ehci_dmamask = ~(u32) 0; + +/*! + * Register an instance of a USB host platform device. + * + * @param res: resource pointer + * @param n_res: number of resources + * @param config: config pointer + * + * @return newly-registered platform_device + * + * The USB controller supports 3 host interfaces, and the + * kernel can be configured to support some number of them. + * Each supported host interface is registered as an instance + * of the "fsl-ehci" device. Call this function multiple times + * to register each host interface. + */ +static int instance_id = 0; +struct platform_device *host_pdev_register(struct resource *res, int n_res, + struct fsl_usb2_platform_data *config) +{ + struct platform_device *pdev; + int rc; + + pr_debug("register host res=0x%p, size=%d\n", res, n_res); + + pdev = platform_device_register_simple("fsl-ehci", + instance_id, res, n_res); + if (IS_ERR(pdev)) { + pr_debug("can't register %s Host, %ld\n", + config->name, PTR_ERR(pdev)); + return NULL; + } + + pdev->dev.coherent_dma_mask = 0xffffffff; + pdev->dev.dma_mask = &ehci_dmamask; + + /* + * platform_device_add_data() makes a copy of + * the platform_data passed in. That makes it + * impossible to share the same config struct for + * all OTG devices (host,gadget,otg). So, just + * set the platorm_data pointer ourselves. + */ + rc = platform_device_add_data(pdev, config, + sizeof(struct fsl_usb2_platform_data)); + if (rc) { + platform_device_unregister(pdev); + return NULL; + } + + printk(KERN_INFO "usb: %s host (%s) registered\n", config->name, + config->transceiver); + pr_debug("pdev=0x%p dev=0x%p resources=0x%p pdata=0x%p\n", + pdev, &pdev->dev, pdev->resource, pdev->dev.platform_data); + + instance_id++; + + return pdev; +} + +#if defined(CONFIG_USB_OTG) +static struct otg_transceiver *xceiv; + +/** + * otg_get_transceiver - find the (single) OTG transceiver driver + * + * Returns the transceiver driver, after getting a refcount to it; or + * null if there is no such transceiver. The caller is responsible for + * releasing that count. + */ +struct otg_transceiver *otg_get_transceiver(void) +{ + pr_debug("%s xceiv=0x%p\n", __func__, xceiv); + if (xceiv) + get_device(xceiv->dev); + return xceiv; +} +EXPORT_SYMBOL(otg_get_transceiver); + +int otg_set_transceiver(struct otg_transceiver *x) +{ + pr_debug("%s xceiv=0x%p x=0x%p\n", __func__, xceiv, x); + if (xceiv && x) + return -EBUSY; + xceiv = x; + return 0; +} +EXPORT_SYMBOL(otg_set_transceiver); + +static struct resource *otg_resources; + +struct resource *otg_get_resources(void) +{ + return otg_resources; +} +EXPORT_SYMBOL(otg_get_resources); + +int otg_set_resources(struct resource *resources) +{ + otg_resources = resources; + return 0; +} +EXPORT_SYMBOL(otg_set_resources); +#endif + +static void usbh1_set_serial_xcvr(void) +{ + pr_debug("%s: \n", __func__); + USBCTRL &= ~(UCTRL_H1SIC_MASK | UCTRL_BPE); /* disable bypass mode */ + USBCTRL |= UCTRL_H1SIC_SU6 | /* single-ended / unidir. */ + UCTRL_H1WIE | UCTRL_H1DT | /* disable H1 TLL */ + UCTRL_H1PM; /* power mask */ +} + +static void usbh1_set_ulpi_xcvr(void) +{ + pr_debug("%s: \n", __func__); + + /* Stop then Reset */ + UH1_USBCMD &= ~UCMD_RUN_STOP; + while (UH1_USBCMD & UCMD_RUN_STOP) ; + + UH1_USBCMD |= UCMD_RESET; + while (UH1_USBCMD & UCMD_RESET) ; + + /* Select the clock from external PHY */ + USB_CTRL_1 |= USB_CTRL_UH1_EXT_CLK_EN; + + /* select ULPI PHY PTS=2 */ + UH1_PORTSC1 = (UH1_PORTSC1 & ~PORTSC_PTS_MASK) | PORTSC_PTS_ULPI; + + USBCTRL |= UCTRL_H1WIE; /* HOST1 wakeup intr enable */ + USBCTRL |= UCTRL_H1UIE; /* Host1 ULPI interrupt enable */ + USBCTRL &= ~UCTRL_H1PM; /* HOST1 power mask */ + + /* Interrupt Threshold Control:Immediate (no threshold) */ + UH1_USBCMD &= UCMD_ITC_NO_THRESHOLD; + + UH1_USBCMD |= UCMD_RESET; /* reset the controller */ + + /* allow controller to reset, and leave time for + * the ULPI transceiver to reset too. + */ + msleep(100); + + /* Turn off the usbpll for ulpi tranceivers */ + clk_disable(usb_clk); +} +static void usbh2_set_ulpi_xcvr(void) +{ + u32 tmp; + + pr_debug("%s\n", __func__); + USBCTRL &= ~(UCTRL_H2SIC_MASK | UCTRL_BPE); + USBCTRL |= UCTRL_H2WIE | /* wakeup intr enable */ + UCTRL_H2UIE | /* ULPI intr enable */ + UCTRL_H2DT | /* disable H2 TLL */ + UCTRL_H2PM; /* power mask */ + + /* must set ULPI phy before turning off clock */ + tmp = UH2_PORTSC1 & ~PORTSC_PTS_MASK; + tmp |= PORTSC_PTS_ULPI; + UH2_PORTSC1 = tmp; + + UH2_USBCMD |= UCMD_RESET; /* reset the controller */ + + /* allow controller to reset, and leave time for + * the ULPI transceiver to reset too. + */ + msleep(100); + + /* Turn off the usbpll for ulpi tranceivers */ + clk_disable(usb_clk); +} + +static void usbh2_set_serial_xcvr(void) +{ + pr_debug("%s: \n", __func__); + + /* Stop then Reset */ + UH2_USBCMD &= ~UCMD_RUN_STOP; + while (UH2_USBCMD & UCMD_RUN_STOP) ; + + UH2_USBCMD |= UCMD_RESET; + while (UH2_USBCMD & UCMD_RESET) ; + + USBCTRL &= ~(UCTRL_H2SIC_MASK); /* Disable bypass mode */ + USBCTRL &= ~(UCTRL_H2PM); /* Power Mask */ + USBCTRL &= ~UCTRL_H2OCPOL; /* OverCurrent Polarity is Low Active */ + USBCTRL &= ~UCTRL_H2WIE; /* Wakeup intr disable */ + USBCTRL |= UCTRL_IP_PUE_DOWN | /* ipp_pue_pulldwn_dpdm */ + UCTRL_USBTE | /* USBT is enabled */ + UCTRL_H2DT; /* Disable H2 TLL */ + + if (cpu_is_mx35_rev(CHIP_REV_2_0) < 0) { + /* Disable Host2 bus Lock for i.MX35 1.0 */ + USBCTRL |= UCTRL_H2LOCKD; + /* USBOTG_PWR low active */ + USBCTRL &= ~UCTRL_PP; + /* OverCurrent Polarity is Low Active */ + USBCTRL &= ~UCTRL_OCPOL; + } else if (cpu_is_mx35_rev(CHIP_REV_2_0) >= 1) { + /* i.MX35 2.0 OTG and Host2 have seperate OC/PWR polarity */ + USBCTRL &= ~UCTRL_H2PP; + USBCTRL &= ~UCTRL_H2OCPOL; + } else if (cpu_is_mx25()) { + /* + * USBH2_PWR and USBH2_OC are active high. + * Must force xcvr clock to "internal" so that + * we can write to PTS field after it's been + * cleared by ehci_turn_off_all_ports(). + */ + USBCTRL |= UCTRL_H2PP | UCTRL_H2OCPOL | UCTRL_XCSH2; + /* Disable Host2 bus Lock */ + USBCTRL |= UCTRL_H2LOCKD; + } + + USBCTRL &= ~(UCTRL_PP); + UH2_PORTSC1 = (UH2_PORTSC1 & (~PORTSC_PTS_MASK)) | PORTSC_PTS_SERIAL; + + if (UH2_HCSPARAMS & HCSPARAMS_PPC) + UH2_PORTSC1 |= PORTSC_PORT_POWER; + + /* Reset controller before set host mode */ + UH2_USBCMD |= UCMD_RESET; + while (UH2_USBCMD & UCMD_RESET) ; + + msleep(100); +} + +/*! + * Register remote wakeup by this usb controller + * + * @param pdev: platform_device for this usb controller + * + * @return 0 or negative error code in case not supportted. + */ +static int usb_register_remote_wakeup(struct platform_device *pdev) +{ + struct resource *res; + int irq; + + pr_debug("%s: pdev=0x%p \n", __func__, pdev); + if (!cpu_is_mx51()) + return -ECANCELED; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + irq = res->start; + pdev->dev.power.can_wakeup = 1; + enable_irq_wake(irq); + + return 0; +} + +extern void gpio_usbh1_setback_stp(void); +extern void gpio_usbh2_setback_stp(void); + +int fsl_usb_host_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_xcvr_ops *xops; + + pr_debug("%s: pdev=0x%p pdata=0x%p\n", __func__, pdev, pdata); + + xops = fsl_usb_get_xcvr(pdata->transceiver); + if (!xops) { + printk(KERN_ERR "%s transceiver ops missing\n", pdata->name); + return -EINVAL; + } + pdata->xcvr_ops = xops; + pdata->xcvr_type = xops->xcvr_type; + pdata->pdev = pdev; + + if (fsl_check_usbclk() != 0) + return -EINVAL; + + pr_debug("%s: grab pins\n", __func__); + if (pdata->gpio_usb_active()) + return -EINVAL; + + if (clk_enable(usb_clk)) { + printk(KERN_ERR "clk_enable(usb_clk) failed\n"); + return -EINVAL; + } + + if (cpu_is_mx51()) { + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } + + /* enable board power supply for xcvr */ + if (pdata->xcvr_pwr) { + if (pdata->xcvr_pwr->regu1) + regulator_enable(pdata->xcvr_pwr->regu1); + if (pdata->xcvr_pwr->regu2) + regulator_enable(pdata->xcvr_pwr->regu2); + } + + if (xops->init) + xops->init(xops); + + if (usb_register_remote_wakeup(pdev)) + pr_debug("%s port is not a wakeup source.\n", pdata->name); + + if (xops->xcvr_type == PORTSC_PTS_SERIAL) { + if (cpu_is_mx35()) { + usbh2_set_serial_xcvr(); + /* Close the internal 60Mhz */ + USBCTRL &= ~UCTRL_XCSH2; + } else if (cpu_is_mx25()) + usbh2_set_serial_xcvr(); + else + usbh1_set_serial_xcvr(); + } else if (xops->xcvr_type == PORTSC_PTS_ULPI) { + if (!strcmp("Host 1", pdata->name)) { + usbh1_set_ulpi_xcvr(); + if (cpu_is_mx51()) { +#ifdef CONFIG_USB_EHCI_ARC_H1 + gpio_usbh1_setback_stp(); + /* disable remote wakeup irq */ + USBCTRL &= ~UCTRL_H1WIE; +#endif + } + } + if (!strcmp("Host 2", pdata->name)) { + usbh2_set_ulpi_xcvr(); + if (cpu_is_mx51()) { +#ifdef CONFIG_USB_EHCI_ARC_H2 + gpio_usbh2_setback_stp(); +#endif + } + } + } + + pr_debug("%s: %s success\n", __func__, pdata->name); + return 0; +} +EXPORT_SYMBOL(fsl_usb_host_init); + +void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata) +{ + pr_debug("%s\n", __func__); + + if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) + pdata->xcvr_ops->uninit(pdata->xcvr_ops); + + pdata->regs = NULL; + + pdata->gpio_usb_inactive(); + if (pdata->xcvr_type == PORTSC_PTS_SERIAL) { + /* Workaround an IC issue for ehci driver. + * when turn off root hub port power, EHCI set + * PORTSC reserved bits to be 0, but PTS with 0 + * means UTMI interface, so here force the Host2 + * port use the internal 60Mhz. + */ + if (cpu_is_mx35()) + USBCTRL |= UCTRL_XCSH2; + clk_disable(usb_clk); + } + + /* disable board power supply for xcvr */ + if (pdata->xcvr_pwr) { + if (pdata->xcvr_pwr->regu1) + regulator_disable(pdata->xcvr_pwr->regu1); + if (pdata->xcvr_pwr->regu2) + regulator_disable(pdata->xcvr_pwr->regu2); + } + + if (cpu_is_mx51()) { + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } +} +EXPORT_SYMBOL(fsl_usb_host_uninit); + +static void otg_set_serial_xcvr(void) +{ + pr_debug("%s\n", __func__); +} + +void otg_set_serial_host(void) +{ + pr_debug("%s\n", __func__); + /* set USBCTRL for host operation + * disable: bypass mode, + * set: single-ended/unidir/6 wire, OTG wakeup intr enable, + * power mask + */ + USBCTRL &= ~UCTRL_OSIC_MASK; +#if defined(CONFIG_ARCH_MX27) || defined(CONFIG_ARCH_MX3) + USBCTRL &= ~UCTRL_BPE; +#endif + +#if defined(CONFIG_MXC_USB_SB3) + USBCTRL |= UCTRL_OSIC_SB3 | UCTRL_OWIE | UCTRL_OPM; +#elif defined(CONFIG_MXC_USB_SU6) + USBCTRL |= UCTRL_OSIC_SU6 | UCTRL_OWIE | UCTRL_OPM; +#elif defined(CONFIG_MXC_USB_DB4) + USBCTRL |= UCTRL_OSIC_DB4 | UCTRL_OWIE | UCTRL_OPM; +#else + USBCTRL |= UCTRL_OSIC_DU6 | UCTRL_OWIE | UCTRL_OPM; +#endif + + USB_OTG_MIRROR = OTGM_VBUSVAL | OTGM_ASESVLD; /* 0xa */ +} +EXPORT_SYMBOL(otg_set_serial_host); + +void otg_set_serial_peripheral(void) +{ + /* set USBCTRL for device operation + * disable: bypass mode + * set: differential/unidir/6 wire, OTG wakeup intr enable, + * power mask + */ + USBCTRL &= ~UCTRL_OSIC_MASK; +#if defined(CONFIG_ARCH_MX27) || defined(CONFIG_ARCH_MX3) + USBCTRL &= ~UCTRL_BPE; +#endif + +#if defined(CONFIG_MXC_USB_SB3) + USBCTRL |= UCTRL_OSIC_SB3 | UCTRL_OWIE | UCTRL_OPM; +#elif defined(CONFIG_MXC_USB_SU6) + USBCTRL |= UCTRL_OSIC_SU6 | UCTRL_OWIE | UCTRL_OPM; +#elif defined(CONFIG_MXC_USB_DB4) + USBCTRL |= UCTRL_OSIC_DB4 | UCTRL_OWIE | UCTRL_OPM; +#else + USBCTRL |= UCTRL_OSIC_DU6 | UCTRL_OWIE | UCTRL_OPM; +#endif + + USB_OTG_MIRROR = OTGM_VBUSVAL | OTGM_BSESVLD | OTGM_IDIDG; /* oxd */ +} +EXPORT_SYMBOL(otg_set_serial_peripheral); + +static void otg_set_ulpi_xcvr(void) +{ + u32 tmp; + + pr_debug("%s\n", __func__); + USBCTRL &= ~UCTRL_OSIC_MASK; +#if defined(CONFIG_ARCH_MX27) || defined(CONFIG_ARCH_MX3) + USBCTRL &= ~UCTRL_BPE; +#endif + USBCTRL |= UCTRL_OUIE | /* ULPI intr enable */ + UCTRL_OWIE | /* OTG wakeup intr enable */ + UCTRL_OPM; /* power mask */ + + /* must set ULPI phy before turning off clock */ + tmp = UOG_PORTSC1 & ~PORTSC_PTS_MASK; + tmp |= PORTSC_PTS_ULPI; + UOG_PORTSC1 = tmp; + + /* need to reset the controller here so that the ID pin + * is correctly detected. + */ + UOG_USBCMD |= UCMD_RESET; + + /* allow controller to reset, and leave time for + * the ULPI transceiver to reset too. + */ + msleep(100); + + /* Turn off the usbpll for ulpi tranceivers */ + clk_disable(usb_clk); +} + +int fsl_usb_xcvr_suspend(struct fsl_xcvr_ops *xcvr_ops) +{ + if (!machine_is_mx31_3ds()) + return -ECANCELED; + + if (xcvr_ops->xcvr_type == PORTSC_PTS_ULPI) { + if (fsl_check_usbclk() != 0) + return -EINVAL; + if (gpio_usbotg_hs_active()) + return -EINVAL; + clk_enable(usb_clk); + + otg_set_ulpi_xcvr(); + + if (xcvr_ops->suspend) + /* suspend transceiver */ + xcvr_ops->suspend(xcvr_ops); + + gpio_usbotg_hs_inactive(); + clk_disable(usb_clk); + } + return 0; +} +EXPORT_SYMBOL(fsl_usb_xcvr_suspend); + +static void otg_set_utmi_xcvr(void) +{ + u32 tmp; + + /* Stop then Reset */ + UOG_USBCMD &= ~UCMD_RUN_STOP; + while (UOG_USBCMD & UCMD_RUN_STOP) ; + + UOG_USBCMD |= UCMD_RESET; + while ((UOG_USBCMD) & (UCMD_RESET)) ; + + if (cpu_is_mx51()) { + /* OTG Polarity of Overcurrent is Low active */ + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_OC_POL; + /* Enable OTG Overcurrent Event */ + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_OC_DIS; + } else if (cpu_is_mx25()) { + USBCTRL |= UCTRL_OCPOL; + USBCTRL &= ~UCTRL_PP; + } else { + /* USBOTG_PWR low active */ + USBCTRL &= ~UCTRL_PP; + /* OverCurrent Polarity is Low Active */ + USBCTRL &= ~UCTRL_OCPOL; + + if (cpu_is_mx35_rev(CHIP_REV_2_0) < 0) + /* OTG Lock Disable */ + USBCTRL |= UCTRL_OLOCKD; + } + + USBCTRL &= ~UCTRL_OPM; /* OTG Power Mask */ + USBCTRL &= ~UCTRL_OWIE; /* OTG Wakeup Intr Disable */ + + /* set UTMI xcvr */ + tmp = UOG_PORTSC1 & ~PORTSC_PTS_MASK; + tmp |= PORTSC_PTS_UTMI; + UOG_PORTSC1 = tmp; + + if (cpu_is_mx51()) { + /* Set the PHY clock to 19.2MHz */ + USB_PHY_CTR_FUNC2 &= ~USB_UTMI_PHYCTRL2_PLLDIV_MASK; + USB_PHY_CTR_FUNC2 |= 0x01; + } else if (machine_is_mx37_3ds()) { + /* Reference voltage for HS disconnect envelope detector */ + /* adjust the Squelch level */ + USB_PHY_CTR_FUNC2 &= ~(USB_UTMI_PHYCTRL2_HSDEVSEL_MASK << + USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT); + } + + /* Workaround an IC issue for ehci driver: + * when turn off root hub port power, EHCI set + * PORTSC reserved bits to be 0, but PTW with 0 + * means 8 bits tranceiver width, here change + * it back to be 16 bits and do PHY diable and + * then enable. + */ + UOG_PORTSC1 |= PORTSC_PTW; + + if (cpu_is_mx35() || cpu_is_mx25()) { + /* Enable UTMI interface in PHY control Reg */ + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_UTMI_ENABLE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_UTMI_ENABLE; + } + + /* need to reset the controller here so that the ID pin + * is correctly detected. + */ + /* Stop then Reset */ + UOG_USBCMD &= ~UCMD_RUN_STOP; + while (UOG_USBCMD & UCMD_RUN_STOP) ; + + UOG_USBCMD |= UCMD_RESET; + while ((UOG_USBCMD) & (UCMD_RESET)) ; + + /* allow controller to reset, and leave time for + * the ULPI transceiver to reset too. + */ + msleep(100); + + /* Turn off the usbpll for mx25 UTMI tranceivers */ + /* DDD: can we do this UTMI xcvrs on all boards? */ + if (cpu_is_mx25()) { + clk_disable(usb_clk); + } else if (cpu_is_mx37()) { + /* fix USB PHY Power Gating leakage issue for i.MX37 */ + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CHGRDETON; + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CHGRDETEN; + } +} + +static int otg_used = 0; + +int usbotg_init(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct fsl_xcvr_ops *xops; + + pr_debug("%s: pdev=0x%p pdata=0x%p\n", __func__, pdev, pdata); + + xops = fsl_usb_get_xcvr(pdata->transceiver); + if (!xops) { + printk(KERN_ERR "DR transceiver ops missing\n"); + return -EINVAL; + } + pdata->xcvr_ops = xops; + pdata->xcvr_type = xops->xcvr_type; + pdata->pdev = pdev; + + if (!otg_used) { + if (fsl_check_usbclk() != 0) + return -EINVAL; + + pr_debug("%s: grab pins\n", __func__); + if (pdata->gpio_usb_active()) + return -EINVAL; + + if (clk_enable(usb_clk)) { + printk(KERN_ERR "clk_enable(usb_clk) failed\n"); + return -EINVAL; + } + + if (xops->init) + xops->init(xops); + + UOG_PORTSC1 = UOG_PORTSC1 & ~PORTSC_PHCD; + if (xops->xcvr_type == PORTSC_PTS_SERIAL) { + if (pdata->operating_mode == FSL_USB2_DR_HOST) { + otg_set_serial_host(); + /* need reset */ + UOG_USBCMD |= UCMD_RESET; + msleep(100); + } else if (pdata->operating_mode == FSL_USB2_DR_DEVICE) + otg_set_serial_peripheral(); + otg_set_serial_xcvr(); + } else if (xops->xcvr_type == PORTSC_PTS_ULPI) { + otg_set_ulpi_xcvr(); + } else if (xops->xcvr_type == PORTSC_PTS_UTMI) { + otg_set_utmi_xcvr(); + } + } + + if (usb_register_remote_wakeup(pdev)) + pr_debug("DR is not a wakeup source.\n"); + + otg_used++; + pr_debug("%s: success\n", __func__); + return 0; +} +EXPORT_SYMBOL(usbotg_init); + +void usbotg_uninit(struct fsl_usb2_platform_data *pdata) +{ + pr_debug("%s\n", __func__); + + otg_used--; + if (!otg_used) { + if (pdata->xcvr_ops && pdata->xcvr_ops->uninit) + pdata->xcvr_ops->uninit(pdata->xcvr_ops); + + pdata->regs = NULL; + + if (machine_is_mx31_3ds()) { + if (pdata->xcvr_ops && pdata->xcvr_ops->suspend) + pdata->xcvr_ops->suspend(pdata->xcvr_ops); + clk_disable(usb_clk); + } + msleep(1); + UOG_PORTSC1 = UOG_PORTSC1 | PORTSC_PHCD; + pdata->gpio_usb_inactive(); + if (pdata->xcvr_type == PORTSC_PTS_SERIAL) + clk_disable(usb_clk); + clk_disable(usb_ahb_clk); + } +} +EXPORT_SYMBOL(usbotg_uninit); + +int usb_host_wakeup_irq(struct device *wkup_dev) +{ + int wakeup_req = 0; + struct fsl_usb2_platform_data *pdata = wkup_dev->platform_data; + + if (!strcmp("Host 1", pdata->name)) { + wakeup_req = USBCTRL & UCTRL_H1WIR; + } else if (!strcmp("DR", pdata->name)) { + wakeup_req = USBCTRL & UCTRL_OWIR; + /* If DR is in device mode, let udc handle it */ + if (wakeup_req && ((UOG_USBMODE & 0x3) == 0x2)) + wakeup_req = 0; + } + + return wakeup_req; +} +EXPORT_SYMBOL(usb_host_wakeup_irq); + +void usb_host_set_wakeup(struct device *wkup_dev, bool para) +{ + struct fsl_usb2_platform_data *pdata = wkup_dev->platform_data; + + /* If this device may wakeup */ + if (device_may_wakeup(wkup_dev) && para) { + if (!strcmp("Host 1", pdata->name)) { + USBCTRL |= UCTRL_H1WIE; + } else if (!strcmp("DR", pdata->name)) { + USBCTRL |= UCTRL_OWIE; + /* Enable OTG ID Wakeup */ + USBCTRL_HOST2 |= (1 << 5); + } + } + + if (!para) { + if (!strcmp("Host 1", pdata->name)) + USBCTRL &= ~UCTRL_H1WIE; + else if (!strcmp("DR", pdata->name)) { + USBCTRL &= ~UCTRL_OWIE; + USBCTRL_HOST2 &= ~(1 << 5); + } + } +} +EXPORT_SYMBOL(usb_host_set_wakeup); diff --git a/arch/arm/plat-mxc/utmixc.c b/arch/arm/plat-mxc/utmixc.c new file mode 100644 index 000000000000..a3b2bad03444 --- /dev/null +++ b/arch/arm/plat-mxc/utmixc.c @@ -0,0 +1,106 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct regulator *usbotg_regux; + +static void usb_utmi_init(struct fsl_xcvr_ops *this) +{ +#if defined(CONFIG_MXC_PMIC_MC13892_MODULE) || defined(CONFIG_MXC_PMIC_MC13892) + if (machine_is_mx51_3ds()) { + unsigned int value; + + /* VUSBIN */ + pmic_read_reg(REG_USB1, &value, 0xffffff); + value |= 0x1; + value |= (0x1 << 3); + pmic_write_reg(REG_USB1, value, 0xffffff); + } +#endif +} + +static void usb_utmi_uninit(struct fsl_xcvr_ops *this) +{ +} + +/*! + * set vbus power + * + * @param view viewport register + * @param on power on or off + */ +static void set_power(struct fsl_xcvr_ops *this, + struct fsl_usb2_platform_data *pdata, int on) +{ + struct device *dev = &pdata->pdev->dev; + + pr_debug("real %s(on=%d) pdata=0x%p\n", __func__, on, pdata); + if (machine_is_mx37_3ds()) { + if (on) { + if (!board_is_rev(BOARD_REV_2)) + usbotg_regux = regulator_get(dev, "DCDC2"); + else + usbotg_regux = regulator_get(dev, "SWBST"); + + regulator_enable(usbotg_regux); + } else { + regulator_disable(usbotg_regux); + regulator_put(usbotg_regux); + } + } +} + +static struct fsl_xcvr_ops utmi_ops = { + .name = "utmi", + .xcvr_type = PORTSC_PTS_UTMI, + .init = usb_utmi_init, + .uninit = usb_utmi_uninit, + .set_vbus_power = set_power, +}; + +extern void fsl_usb_xcvr_register(struct fsl_xcvr_ops *xcvr_ops); + +static int __init utmixc_init(void) +{ + fsl_usb_xcvr_register(&utmi_ops); + return 0; +} + +extern void fsl_usb_xcvr_unregister(struct fsl_xcvr_ops *xcvr_ops); + +static void __exit utmixc_exit(void) +{ + fsl_usb_xcvr_unregister(&utmi_ops); +} + +module_init(utmixc_init); +module_exit(utmixc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("utmi xcvr driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-mxc/wdog.c b/arch/arm/plat-mxc/wdog.c new file mode 100644 index 000000000000..8f242e707f58 --- /dev/null +++ b/arch/arm/plat-mxc/wdog.c @@ -0,0 +1,68 @@ +/* + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file plat-mxc/wdog.c + * @brief This file contains watchdog timer implementations. + * + * This file contains watchdog timer implementations for timer tick. + * + * @ingroup WDOG + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WDOG_WT 0x8 /* WDOG WT starting bit inside WCR */ +#define WCR_WOE_BIT (1 << 6) +#define WCR_WDA_BIT (1 << 5) +#define WCR_SRS_BIT (1 << 4) +#define WCR_WRE_BIT (1 << 3) +#define WCR_WDE_BIT (1 << 2) +#define WCR_WDBG_BIT (1 << 1) +#define WCR_WDZST_BIT (1 << 0) + +/* + * WatchDog + */ +#define WDOG_WCR 0 /* 16bit watchdog control reg */ +#define WDOG_WSR 2 /* 16bit watchdog service reg */ +#define WDOG_WRSR 4 /* 16bit watchdog reset status reg */ + +/*! + * The base addresses for the WDOG modules + */ +static void __iomem *wdog_base[2] = { + IO_ADDRESS(WDOG1_BASE_ADDR), +#ifdef WDOG2_BASE_ADDR + IO_ADDRESS(WDOG2_BASE_ADDR), +#endif +}; + +void mxc_wd_reset(void) +{ + u16 reg; + struct clk *clk; + + clk = clk_get(NULL, "wdog_clk"); + clk_enable(clk); + + reg = __raw_readw(wdog_base[0] + WDOG_WCR) & ~WCR_SRS_BIT; + reg |= WCR_WDE_BIT; + __raw_writew(reg, wdog_base[0] + WDOG_WCR); +} -- cgit v1.2.3