diff options
Diffstat (limited to 'arch/arm/mach-mmp')
26 files changed, 1996 insertions, 306 deletions
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig index 5a90b9a3ab6..7fddd01b85b 100644 --- a/arch/arm/mach-mmp/Kconfig +++ b/arch/arm/mach-mmp/Kconfig @@ -2,16 +2,6 @@ if ARCH_MMP menu "Marvell PXA168/910/MMP2 Implmentations" -config MACH_MMP_DT - bool "Support MMP2 platforms from device tree" - select CPU_PXA168 - select CPU_PXA910 - select USE_OF - help - Include support for Marvell MMP2 based platforms using - the device tree. Needn't select any other machine while - MACH_MMP_DT is enabled. - config MACH_ASPENITE bool "Marvell's PXA168 Aspenite Development Board" select CPU_PXA168 @@ -94,6 +84,25 @@ config MACH_GPLUGD Say 'Y' here if you want to support the Marvell PXA168-based GuruPlug Display (gplugD) Board +config MACH_MMP_DT + bool "Support MMP (ARMv5) platforms from device tree" + select CPU_PXA168 + select CPU_PXA910 + select USE_OF + help + Include support for Marvell MMP2 based platforms using + the device tree. Needn't select any other machine while + MACH_MMP_DT is enabled. + +config MACH_MMP2_DT + bool "Support MMP2 (ARMv7) platforms from device tree" + depends on !CPU_MOHAWK + select CPU_MMP2 + select USE_OF + help + Include support for Marvell MMP2 based platforms using + the device tree. + endmenu config CPU_PXA168 @@ -113,4 +122,11 @@ config CPU_MMP2 select CPU_PJ4 help Select code specific to MMP2. MMP2 is ARMv7 compatible. + +config USB_EHCI_MV_U2O + bool "EHCI support for PXA USB OTG controller" + depends on USB_EHCI_MV + help + Enables support for OTG controller which can be switched to host mode. + endif diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile index 4fc0ff5dc96..b786f7e6cd1 100644 --- a/arch/arm/mach-mmp/Makefile +++ b/arch/arm/mach-mmp/Makefile @@ -2,12 +2,17 @@ # Makefile for Marvell's PXA168 processors line # -obj-y += common.o clock.o devices.o time.o +obj-y += common.o clock.o devices.o time.o irq.o # SoC support -obj-$(CONFIG_CPU_PXA168) += pxa168.o irq-pxa168.o -obj-$(CONFIG_CPU_PXA910) += pxa910.o irq-pxa168.o -obj-$(CONFIG_CPU_MMP2) += mmp2.o irq-mmp2.o sram.o +obj-$(CONFIG_CPU_PXA168) += pxa168.o +obj-$(CONFIG_CPU_PXA910) += pxa910.o +obj-$(CONFIG_CPU_MMP2) += mmp2.o sram.o + +ifeq ($(CONFIG_PM),y) +obj-$(CONFIG_CPU_PXA910) += pm-pxa910.o +obj-$(CONFIG_CPU_MMP2) += pm-mmp2.o +endif # board support obj-$(CONFIG_MACH_ASPENITE) += aspenite.o @@ -19,5 +24,6 @@ obj-$(CONFIG_MACH_BROWNSTONE) += brownstone.o obj-$(CONFIG_MACH_FLINT) += flint.o obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o obj-$(CONFIG_MACH_MMP_DT) += mmp-dt.o +obj-$(CONFIG_MACH_MMP2_DT) += mmp2-dt.o obj-$(CONFIG_MACH_TETON_BGA) += teton_bga.o obj-$(CONFIG_MACH_GPLUGD) += gplugd.o diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index bf5d8e195c3..223090b1444 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c @@ -17,6 +17,7 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/nand.h> #include <linux/interrupt.h> +#include <linux/platform_data/mv_usb.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -221,6 +222,21 @@ static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = { .debounce_interval = 30, }; +#if defined(CONFIG_USB_EHCI_MV) +static char *pxa168_sph_clock_name[] = { + [0] = "PXA168-USBCLK", +}; + +static struct mv_usb_platform_data pxa168_sph_pdata = { + .clknum = 1, + .clkname = pxa168_sph_clock_name, + .mode = MV_USB_MODE_HOST, + .phy_init = pxa_usb_phy_init, + .phy_deinit = pxa_usb_phy_deinit, + .set_vbus = NULL, +}; +#endif + static void __init common_init(void) { mfp_config(ARRAY_AND_SIZE(common_pin_config)); @@ -236,6 +252,10 @@ static void __init common_init(void) /* off-chip devices */ platform_device_register(&smc91x_device); + +#if defined(CONFIG_USB_EHCI_MV) + pxa168_add_usb_host(&pxa168_sph_pdata); +#endif } MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform") diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c index 191d9dea873..dd2d8b103cc 100644 --- a/arch/arm/mach-mmp/devices.c +++ b/arch/arm/mach-mmp/devices.c @@ -9,9 +9,13 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/delay.h> #include <asm/irq.h> +#include <mach/irqs.h> #include <mach/devices.h> +#include <mach/cputype.h> +#include <mach/regs-usb.h> int __init pxa_register_device(struct pxa_device_desc *desc, void *data, size_t size) @@ -67,3 +71,281 @@ int __init pxa_register_device(struct pxa_device_desc *desc, return platform_device_add(pdev); } + +#if defined(CONFIG_USB) || defined(CONFIG_USB_GADGET) + +/***************************************************************************** + * The registers read/write routines + *****************************************************************************/ + +static unsigned int u2o_get(void __iomem *base, unsigned int offset) +{ + return readl_relaxed(base + offset); +} + +static void u2o_set(void __iomem *base, unsigned int offset, + unsigned int value) +{ + u32 reg; + + reg = readl_relaxed(base + offset); + reg |= value; + writel_relaxed(reg, base + offset); + readl_relaxed(base + offset); +} + +static void u2o_clear(void __iomem *base, unsigned int offset, + unsigned int value) +{ + u32 reg; + + reg = readl_relaxed(base + offset); + reg &= ~value; + writel_relaxed(reg, base + offset); + readl_relaxed(base + offset); +} + +static void u2o_write(void __iomem *base, unsigned int offset, + unsigned int value) +{ + writel_relaxed(value, base + offset); + readl_relaxed(base + offset); +} + +#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV) + +#if defined(CONFIG_CPU_PXA910) || defined(CONFIG_CPU_PXA168) + +static DEFINE_MUTEX(phy_lock); +static int phy_init_cnt; + +static int usb_phy_init_internal(void __iomem *base) +{ + int loops; + + pr_info("Init usb phy!!!\n"); + + /* Initialize the USB PHY power */ + if (cpu_is_pxa910()) { + u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT) + | (1<<UTMI_CTRL_PU_REF_SHIFT)); + } + + u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT); + u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT); + + /* UTMI_PLL settings */ + u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK + | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK + | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK + | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK); + + u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT + | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT + | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT + | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT); + + /* UTMI_TX */ + u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK + | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK + | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK + | UTMI_TX_AMP_MASK); + u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT + | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT + | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT); + + /* UTMI_RX */ + u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK + | UTMI_REG_SQ_LENGTH_MASK); + u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT + | 2<<UTMI_REG_SQ_LENGTH_SHIFT); + + /* UTMI_IVREF */ + if (cpu_is_pxa168()) + /* fixing Microsoft Altair board interface with NEC hub issue - + * Set UTMI_IVREF from 0x4a3 to 0x4bf */ + u2o_write(base, UTMI_IVREF, 0x4bf); + + /* toggle VCOCAL_START bit of UTMI_PLL */ + udelay(200); + u2o_set(base, UTMI_PLL, VCOCAL_START); + udelay(40); + u2o_clear(base, UTMI_PLL, VCOCAL_START); + + /* toggle REG_RCAL_START bit of UTMI_TX */ + udelay(400); + u2o_set(base, UTMI_TX, REG_RCAL_START); + udelay(40); + u2o_clear(base, UTMI_TX, REG_RCAL_START); + udelay(400); + + /* Make sure PHY PLL is ready */ + loops = 0; + while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) { + mdelay(1); + loops++; + if (loops > 100) { + printk(KERN_WARNING "calibrate timeout, UTMI_PLL %x\n", + u2o_get(base, UTMI_PLL)); + break; + } + } + + if (cpu_is_pxa168()) { + u2o_set(base, UTMI_RESERVE, 1 << 5); + /* Turn on UTMI PHY OTG extension */ + u2o_write(base, UTMI_OTG_ADDON, 1); + } + + return 0; +} + +static int usb_phy_deinit_internal(void __iomem *base) +{ + pr_info("Deinit usb phy!!!\n"); + + if (cpu_is_pxa168()) + u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON); + + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN); + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN); + u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN); + u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT); + u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT); + + return 0; +} + +int pxa_usb_phy_init(void __iomem *phy_reg) +{ + mutex_lock(&phy_lock); + if (phy_init_cnt++ == 0) + usb_phy_init_internal(phy_reg); + mutex_unlock(&phy_lock); + return 0; +} + +void pxa_usb_phy_deinit(void __iomem *phy_reg) +{ + WARN_ON(phy_init_cnt == 0); + + mutex_lock(&phy_lock); + if (--phy_init_cnt == 0) + usb_phy_deinit_internal(phy_reg); + mutex_unlock(&phy_lock); +} +#endif +#endif +#endif + +#ifdef CONFIG_USB_SUPPORT +static u64 usb_dma_mask = ~(u32)0; + +#ifdef CONFIG_USB_MV_UDC +struct resource pxa168_u2o_resources[] = { + /* regbase */ + [0] = { + .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET, + .end = PXA168_U2O_REGBASE + USB_REG_RANGE, + .flags = IORESOURCE_MEM, + .name = "capregs", + }, + /* phybase */ + [1] = { + .start = PXA168_U2O_PHYBASE, + .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE, + .flags = IORESOURCE_MEM, + .name = "phyregs", + }, + [2] = { + .start = IRQ_PXA168_USB1, + .end = IRQ_PXA168_USB1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa168_device_u2o = { + .name = "mv-udc", + .id = -1, + .resource = pxa168_u2o_resources, + .num_resources = ARRAY_SIZE(pxa168_u2o_resources), + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = 0xffffffff, + } +}; +#endif /* CONFIG_USB_MV_UDC */ + +#ifdef CONFIG_USB_EHCI_MV_U2O +struct resource pxa168_u2oehci_resources[] = { + /* regbase */ + [0] = { + .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET, + .end = PXA168_U2O_REGBASE + USB_REG_RANGE, + .flags = IORESOURCE_MEM, + .name = "capregs", + }, + /* phybase */ + [1] = { + .start = PXA168_U2O_PHYBASE, + .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE, + .flags = IORESOURCE_MEM, + .name = "phyregs", + }, + [2] = { + .start = IRQ_PXA168_USB1, + .end = IRQ_PXA168_USB1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa168_device_u2oehci = { + .name = "pxa-u2oehci", + .id = -1, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = 0xffffffff, + }, + + .num_resources = ARRAY_SIZE(pxa168_u2oehci_resources), + .resource = pxa168_u2oehci_resources, +}; +#endif + +#if defined(CONFIG_USB_MV_OTG) +struct resource pxa168_u2ootg_resources[] = { + /* regbase */ + [0] = { + .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET, + .end = PXA168_U2O_REGBASE + USB_REG_RANGE, + .flags = IORESOURCE_MEM, + .name = "capregs", + }, + /* phybase */ + [1] = { + .start = PXA168_U2O_PHYBASE, + .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE, + .flags = IORESOURCE_MEM, + .name = "phyregs", + }, + [2] = { + .start = IRQ_PXA168_USB1, + .end = IRQ_PXA168_USB1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa168_device_u2ootg = { + .name = "mv-otg", + .id = -1, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = 0xffffffff, + }, + + .num_resources = ARRAY_SIZE(pxa168_u2ootg_resources), + .resource = pxa168_u2ootg_resources, +}; +#endif /* CONFIG_USB_MV_OTG */ + +#endif diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h index b1ece08174e..f88a44c0ef9 100644 --- a/arch/arm/mach-mmp/include/mach/addr-map.h +++ b/arch/arm/mach-mmp/include/mach/addr-map.h @@ -31,4 +31,16 @@ #define SMC_CS1_PHYS_BASE 0x90000000 #define SMC_CS1_PHYS_SIZE 0x10000000 +#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800) +#define APMU_REG(x) (APMU_VIRT_BASE + (x)) + +#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000) +#define APBC_REG(x) (APBC_VIRT_BASE + (x)) + +#define MPMU_VIRT_BASE (APB_VIRT_BASE + 0x50000) +#define MPMU_REG(x) (MPMU_VIRT_BASE + (x)) + +#define CIU_VIRT_BASE (AXI_VIRT_BASE + 0x82c00) +#define CIU_REG(x) (CIU_VIRT_BASE + (x)) + #endif /* __ASM_MACH_ADDR_MAP_H */ diff --git a/arch/arm/mach-mmp/include/mach/devices.h b/arch/arm/mach-mmp/include/mach/devices.h index d0ec7dae88e..21217ef11b6 100644 --- a/arch/arm/mach-mmp/include/mach/devices.h +++ b/arch/arm/mach-mmp/include/mach/devices.h @@ -50,4 +50,7 @@ struct pxa_device_desc mmp2_device_##_name __initdata = { \ } extern int pxa_register_device(struct pxa_device_desc *, void *, size_t); +extern int pxa_usb_phy_init(void __iomem *phy_reg); +extern void pxa_usb_phy_deinit(void __iomem *phy_reg); + #endif /* __MACH_DEVICE_H */ diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S index 9cff9e7a2b2..bd152e24e6d 100644 --- a/arch/arm/mach-mmp/include/mach/entry-macro.S +++ b/arch/arm/mach-mmp/include/mach/entry-macro.S @@ -6,13 +6,15 @@ * published by the Free Software Foundation. */ +#include <asm/irq.h> #include <mach/regs-icu.h> .macro get_irqnr_preamble, base, tmp mrc p15, 0, \tmp, c0, c0, 0 @ CPUID and \tmp, \tmp, #0xff00 cmp \tmp, #0x5800 - ldr \base, =ICU_VIRT_BASE + ldr \base, =mmp_icu_base + ldr \base, [\base, #0] addne \base, \base, #0x10c @ PJ1 AP INT SEL register addeq \base, \base, #0x104 @ PJ4 IRQ SEL register .endm diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h index d0e746626a3..fb492a50a81 100644 --- a/arch/arm/mach-mmp/include/mach/irqs.h +++ b/arch/arm/mach-mmp/include/mach/irqs.h @@ -125,7 +125,7 @@ #define IRQ_MMP2_RTC_MUX 5 #define IRQ_MMP2_TWSI1 7 #define IRQ_MMP2_GPU 8 -#define IRQ_MMP2_KEYPAD 9 +#define IRQ_MMP2_KEYPAD_MUX 9 #define IRQ_MMP2_ROTARY 10 #define IRQ_MMP2_TRACKBALL 11 #define IRQ_MMP2_ONEWIRE 12 @@ -163,11 +163,11 @@ #define IRQ_MMP2_DMA_FIQ 47 #define IRQ_MMP2_DMA_RIQ 48 #define IRQ_MMP2_GPIO 49 -#define IRQ_MMP2_SSP_MUX 51 +#define IRQ_MMP2_MIPI_HSI1_MUX 51 #define IRQ_MMP2_MMC2 52 #define IRQ_MMP2_MMC3 53 #define IRQ_MMP2_MMC4 54 -#define IRQ_MMP2_MIPI_HSI 55 +#define IRQ_MMP2_MIPI_HSI0_MUX 55 #define IRQ_MMP2_MSP 58 #define IRQ_MMP2_MIPI_SLIM_DMA 59 #define IRQ_MMP2_PJ4_FREQ_CHG 60 @@ -186,8 +186,14 @@ #define IRQ_MMP2_RTC_ALARM (IRQ_MMP2_RTC_BASE + 0) #define IRQ_MMP2_RTC (IRQ_MMP2_RTC_BASE + 1) +/* secondary interrupt of INT #9 */ +#define IRQ_MMP2_KEYPAD_BASE (IRQ_MMP2_RTC_BASE + 2) +#define IRQ_MMP2_KPC (IRQ_MMP2_KEYPAD_BASE + 0) +#define IRQ_MMP2_ROTORY (IRQ_MMP2_KEYPAD_BASE + 1) +#define IRQ_MMP2_TBALL (IRQ_MMP2_KEYPAD_BASE + 2) + /* secondary interrupt of INT #17 */ -#define IRQ_MMP2_TWSI_BASE (IRQ_MMP2_RTC_BASE + 2) +#define IRQ_MMP2_TWSI_BASE (IRQ_MMP2_KEYPAD_BASE + 3) #define IRQ_MMP2_TWSI2 (IRQ_MMP2_TWSI_BASE + 0) #define IRQ_MMP2_TWSI3 (IRQ_MMP2_TWSI_BASE + 1) #define IRQ_MMP2_TWSI4 (IRQ_MMP2_TWSI_BASE + 2) @@ -212,11 +218,16 @@ #define IRQ_MMP2_COMMRX (IRQ_MMP2_MISC_BASE + 14) /* secondary interrupt of INT #51 */ -#define IRQ_MMP2_SSP_BASE (IRQ_MMP2_MISC_BASE + 15) -#define IRQ_MMP2_SSP1_SRDY (IRQ_MMP2_SSP_BASE + 0) -#define IRQ_MMP2_SSP3_SRDY (IRQ_MMP2_SSP_BASE + 1) +#define IRQ_MMP2_MIPI_HSI1_BASE (IRQ_MMP2_MISC_BASE + 15) +#define IRQ_MMP2_HSI1_CAWAKE (IRQ_MMP2_MIPI_HSI1_BASE + 0) +#define IRQ_MMP2_MIPI_HSI_INT1 (IRQ_MMP2_MIPI_HSI1_BASE + 1) + +/* secondary interrupt of INT #55 */ +#define IRQ_MMP2_MIPI_HSI0_BASE (IRQ_MMP2_MIPI_HSI1_BASE + 2) +#define IRQ_MMP2_HSI0_CAWAKE (IRQ_MMP2_MIPI_HSI0_BASE + 0) +#define IRQ_MMP2_MIPI_HSI_INT0 (IRQ_MMP2_MIPI_HSI0_BASE + 1) -#define IRQ_MMP2_MUX_END (IRQ_MMP2_SSP_BASE + 2) +#define IRQ_MMP2_MUX_END (IRQ_MMP2_MIPI_HSI0_BASE + 2) #define IRQ_GPIO_START 128 #define MMP_NR_BUILTIN_GPIO 192 diff --git a/arch/arm/mach-mmp/include/mach/pm-mmp2.h b/arch/arm/mach-mmp/include/mach/pm-mmp2.h new file mode 100644 index 00000000000..98bd66ce800 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/pm-mmp2.h @@ -0,0 +1,61 @@ +/* + * MMP2 Power Management Routines + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * (C) Copyright 2010 Marvell International Ltd. + * All Rights Reserved + */ + +#ifndef __MMP2_PM_H__ +#define __MMP2_PM_H__ + +#include <mach/addr-map.h> + +#define APMU_PJ_IDLE_CFG APMU_REG(0x018) +#define APMU_PJ_IDLE_CFG_PJ_IDLE (1 << 1) +#define APMU_PJ_IDLE_CFG_PJ_PWRDWN (1 << 5) +#define APMU_PJ_IDLE_CFG_PWR_SW(x) ((x) << 16) +#define APMU_PJ_IDLE_CFG_L2_PWR_SW (1 << 19) +#define APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK (3 << 28) + +#define APMU_SRAM_PWR_DWN APMU_REG(0x08c) + +#define MPMU_SCCR MPMU_REG(0x038) +#define MPMU_PCR_PJ MPMU_REG(0x1000) +#define MPMU_PCR_PJ_AXISD (1 << 31) +#define MPMU_PCR_PJ_SLPEN (1 << 29) +#define MPMU_PCR_PJ_SPSD (1 << 28) +#define MPMU_PCR_PJ_DDRCORSD (1 << 27) +#define MPMU_PCR_PJ_APBSD (1 << 26) +#define MPMU_PCR_PJ_INTCLR (1 << 24) +#define MPMU_PCR_PJ_SLPWP0 (1 << 23) +#define MPMU_PCR_PJ_SLPWP1 (1 << 22) +#define MPMU_PCR_PJ_SLPWP2 (1 << 21) +#define MPMU_PCR_PJ_SLPWP3 (1 << 20) +#define MPMU_PCR_PJ_VCTCXOSD (1 << 19) +#define MPMU_PCR_PJ_SLPWP4 (1 << 18) +#define MPMU_PCR_PJ_SLPWP5 (1 << 17) +#define MPMU_PCR_PJ_SLPWP6 (1 << 16) +#define MPMU_PCR_PJ_SLPWP7 (1 << 15) + +#define MPMU_PLL2_CTRL1 MPMU_REG(0x0414) +#define MPMU_CGR_PJ MPMU_REG(0x1024) +#define MPMU_WUCRM_PJ MPMU_REG(0x104c) +#define MPMU_WUCRM_PJ_WAKEUP(x) (1 << (x)) +#define MPMU_WUCRM_PJ_RTC_ALARM (1 << 17) + +enum { + POWER_MODE_ACTIVE = 0, + POWER_MODE_CORE_INTIDLE, + POWER_MODE_CORE_EXTIDLE, + POWER_MODE_APPS_IDLE, + POWER_MODE_APPS_SLEEP, + POWER_MODE_CHIP_SLEEP, + POWER_MODE_SYS_SLEEP, +}; + +extern void mmp2_pm_enter_lowpower_mode(int state); +extern int mmp2_set_wake(struct irq_data *d, unsigned int on); +#endif diff --git a/arch/arm/mach-mmp/include/mach/pm-pxa910.h b/arch/arm/mach-mmp/include/mach/pm-pxa910.h new file mode 100644 index 00000000000..8cac8ab5253 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/pm-pxa910.h @@ -0,0 +1,77 @@ +/* + * PXA910 Power Management Routines + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * (C) Copyright 2009 Marvell International Ltd. + * All Rights Reserved + */ + +#ifndef __PXA910_PM_H__ +#define __PXA910_PM_H__ + +#define APMU_MOH_IDLE_CFG APMU_REG(0x0018) +#define APMU_MOH_IDLE_CFG_MOH_IDLE (1 << 1) +#define APMU_MOH_IDLE_CFG_MOH_PWRDWN (1 << 5) +#define APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN (1 << 6) +#define APMU_MOH_IDLE_CFG_MOH_PWR_SW(x) (((x) & 0x3) << 16) +#define APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(x) (((x) & 0x3) << 18) +#define APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ (1 << 21) +#define APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN (1 << 20) + +#define APMU_SQU_CLK_GATE_CTRL APMU_REG(0x001c) +#define APMU_MC_HW_SLP_TYPE APMU_REG(0x00b0) + +#define MPMU_FCCR MPMU_REG(0x0008) +#define MPMU_APCR MPMU_REG(0x1000) +#define MPMU_APCR_AXISD (1 << 31) +#define MPMU_APCR_DSPSD (1 << 30) +#define MPMU_APCR_SLPEN (1 << 29) +#define MPMU_APCR_DTCMSD (1 << 28) +#define MPMU_APCR_DDRCORSD (1 << 27) +#define MPMU_APCR_APBSD (1 << 26) +#define MPMU_APCR_BBSD (1 << 25) +#define MPMU_APCR_SLPWP0 (1 << 23) +#define MPMU_APCR_SLPWP1 (1 << 22) +#define MPMU_APCR_SLPWP2 (1 << 21) +#define MPMU_APCR_SLPWP3 (1 << 20) +#define MPMU_APCR_VCTCXOSD (1 << 19) +#define MPMU_APCR_SLPWP4 (1 << 18) +#define MPMU_APCR_SLPWP5 (1 << 17) +#define MPMU_APCR_SLPWP6 (1 << 16) +#define MPMU_APCR_SLPWP7 (1 << 15) +#define MPMU_APCR_MSASLPEN (1 << 14) +#define MPMU_APCR_STBYEN (1 << 13) + +#define MPMU_AWUCRM MPMU_REG(0x104c) +#define MPMU_AWUCRM_AP_ASYNC_INT (1 << 25) +#define MPMU_AWUCRM_AP_FULL_IDLE (1 << 24) +#define MPMU_AWUCRM_SDH1 (1 << 23) +#define MPMU_AWUCRM_SDH2 (1 << 22) +#define MPMU_AWUCRM_KEYPRESS (1 << 21) +#define MPMU_AWUCRM_TRACKBALL (1 << 20) +#define MPMU_AWUCRM_NEWROTARY (1 << 19) +#define MPMU_AWUCRM_RTC_ALARM (1 << 17) +#define MPMU_AWUCRM_AP2_TIMER_3 (1 << 13) +#define MPMU_AWUCRM_AP2_TIMER_2 (1 << 12) +#define MPMU_AWUCRM_AP2_TIMER_1 (1 << 11) +#define MPMU_AWUCRM_AP1_TIMER_3 (1 << 10) +#define MPMU_AWUCRM_AP1_TIMER_2 (1 << 9) +#define MPMU_AWUCRM_AP1_TIMER_1 (1 << 8) +#define MPMU_AWUCRM_WAKEUP(x) (1 << ((x) & 0x7)) + +enum { + POWER_MODE_ACTIVE = 0, + POWER_MODE_CORE_INTIDLE, + POWER_MODE_CORE_EXTIDLE, + POWER_MODE_APPS_IDLE, + POWER_MODE_APPS_SLEEP, + POWER_MODE_SYS_SLEEP, + POWER_MODE_HIBERNATE, + POWER_MODE_UDR, +}; + +extern int pxa910_set_wake(struct irq_data *data, unsigned int on); + +#endif diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h index dc03d580a06..09dcd6e2b6a 100644 --- a/arch/arm/mach-mmp/include/mach/pxa168.h +++ b/arch/arm/mach-mmp/include/mach/pxa168.h @@ -16,6 +16,7 @@ extern void pxa168_clear_keypad_wakeup(void); #include <plat/pxa27x_keypad.h> #include <mach/cputype.h> #include <linux/pxa168_eth.h> +#include <linux/platform_data/mv_usb.h> extern struct pxa_device_desc pxa168_device_uart1; extern struct pxa_device_desc pxa168_device_uart2; @@ -36,12 +37,9 @@ extern struct pxa_device_desc pxa168_device_fb; extern struct pxa_device_desc pxa168_device_keypad; extern struct pxa_device_desc pxa168_device_eth; -struct pxa168_usb_pdata { - /* If NULL, default phy init routine for PXA168 would be called */ - int (*phy_init)(void __iomem *usb_phy_reg_base); -}; /* pdata can be NULL */ -int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata); +extern int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata); + extern struct platform_device pxa168_device_gpio; diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h index e2e1f1e5e12..793634c837e 100644 --- a/arch/arm/mach-mmp/include/mach/pxa910.h +++ b/arch/arm/mach-mmp/include/mach/pxa910.h @@ -20,6 +20,9 @@ extern struct pxa_device_desc pxa910_device_pwm2; extern struct pxa_device_desc pxa910_device_pwm3; extern struct pxa_device_desc pxa910_device_pwm4; extern struct pxa_device_desc pxa910_device_nand; +extern struct platform_device pxa168_device_u2o; +extern struct platform_device pxa168_device_u2ootg; +extern struct platform_device pxa168_device_u2oehci; extern struct platform_device pxa910_device_gpio; extern struct platform_device pxa910_device_rtc; diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h index 8a37fb00365..68b0c93ec6a 100644 --- a/arch/arm/mach-mmp/include/mach/regs-apbc.h +++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h @@ -13,9 +13,6 @@ #include <mach/addr-map.h> -#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000) -#define APBC_REG(x) (APBC_VIRT_BASE + (x)) - /* * APB clock register offsets for PXA168 */ diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/include/mach/regs-apmu.h index 8447ac63e28..7af8deb63e8 100644 --- a/arch/arm/mach-mmp/include/mach/regs-apmu.h +++ b/arch/arm/mach-mmp/include/mach/regs-apmu.h @@ -13,9 +13,6 @@ #include <mach/addr-map.h> -#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800) -#define APMU_REG(x) (APMU_VIRT_BASE + (x)) - /* Clock Reset Control */ #define APMU_IRE APMU_REG(0x048) #define APMU_LCD APMU_REG(0x04c) diff --git a/arch/arm/mach-mmp/include/mach/regs-usb.h b/arch/arm/mach-mmp/include/mach/regs-usb.h new file mode 100644 index 00000000000..b047bf48750 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-usb.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2011 Marvell International Ltd. 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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ASM_ARCH_REGS_USB_H +#define __ASM_ARCH_REGS_USB_H + +#define PXA168_U2O_REGBASE (0xd4208000) +#define PXA168_U2O_PHYBASE (0xd4207000) + +#define PXA168_U2H_REGBASE (0xd4209000) +#define PXA168_U2H_PHYBASE (0xd4206000) + +#define MMP3_HSIC1_REGBASE (0xf0001000) +#define MMP3_HSIC1_PHYBASE (0xf0001800) + +#define MMP3_HSIC2_REGBASE (0xf0002000) +#define MMP3_HSIC2_PHYBASE (0xf0002800) + +#define MMP3_FSIC_REGBASE (0xf0003000) +#define MMP3_FSIC_PHYBASE (0xf0003800) + + +#define USB_REG_RANGE (0x1ff) +#define USB_PHY_RANGE (0xff) + +/* registers */ +#define U2x_CAPREGS_OFFSET 0x100 + +/* phy regs */ +#define UTMI_REVISION 0x0 +#define UTMI_CTRL 0x4 +#define UTMI_PLL 0x8 +#define UTMI_TX 0xc +#define UTMI_RX 0x10 +#define UTMI_IVREF 0x14 +#define UTMI_T0 0x18 +#define UTMI_T1 0x1c +#define UTMI_T2 0x20 +#define UTMI_T3 0x24 +#define UTMI_T4 0x28 +#define UTMI_T5 0x2c +#define UTMI_RESERVE 0x30 +#define UTMI_USB_INT 0x34 +#define UTMI_DBG_CTL 0x38 +#define UTMI_OTG_ADDON 0x3c + +/* For UTMICTRL Register */ +#define UTMI_CTRL_USB_CLK_EN (1 << 31) +/* pxa168 */ +#define UTMI_CTRL_SUSPEND_SET1 (1 << 30) +#define UTMI_CTRL_SUSPEND_SET2 (1 << 29) +#define UTMI_CTRL_RXBUF_PDWN (1 << 24) +#define UTMI_CTRL_TXBUF_PDWN (1 << 11) + +#define UTMI_CTRL_INPKT_DELAY_SHIFT 30 +#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28 +#define UTMI_CTRL_PU_REF_SHIFT 20 +#define UTMI_CTRL_ARC_PULLDN_SHIFT 12 +#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1 +#define UTMI_CTRL_PWR_UP_SHIFT 0 + +/* For UTMI_PLL Register */ +#define UTMI_PLL_PLLCALI12_SHIFT 29 +#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29) + +#define UTMI_PLL_PLLVDD18_SHIFT 27 +#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27) + +#define UTMI_PLL_PLLVDD12_SHIFT 25 +#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25) + +#define UTMI_PLL_CLK_BLK_EN_SHIFT 24 +#define CLK_BLK_EN (0x1 << 24) +#define PLL_READY (0x1 << 23) +#define KVCO_EXT (0x1 << 22) +#define VCOCAL_START (0x1 << 21) + +#define UTMI_PLL_KVCO_SHIFT 15 +#define UTMI_PLL_KVCO_MASK (0x7 << 15) + +#define UTMI_PLL_ICP_SHIFT 12 +#define UTMI_PLL_ICP_MASK (0x7 << 12) + +#define UTMI_PLL_FBDIV_SHIFT 4 +#define UTMI_PLL_FBDIV_MASK (0xFF << 4) + +#define UTMI_PLL_REFDIV_SHIFT 0 +#define UTMI_PLL_REFDIV_MASK (0xF << 0) + +/* For UTMI_TX Register */ +#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27 +#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27) + +#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26 +#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26) + +#define UTMI_TX_TXVDD12_SHIFT 22 +#define UTMI_TX_TXVDD12_MASK (0x3 << 22) + +#define UTMI_TX_CK60_PHSEL_SHIFT 17 +#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17) + +#define UTMI_TX_IMPCAL_VTH_SHIFT 14 +#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14) + +#define REG_RCAL_START (0x1 << 12) + +#define UTMI_TX_LOW_VDD_EN_SHIFT 11 + +#define UTMI_TX_AMP_SHIFT 0 +#define UTMI_TX_AMP_MASK (0x7 << 0) + +/* For UTMI_RX Register */ +#define UTMI_REG_SQ_LENGTH_SHIFT 15 +#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15) + +#define UTMI_RX_SQ_THRESH_SHIFT 4 +#define UTMI_RX_SQ_THRESH_MASK (0xf << 4) + +#define UTMI_OTG_ADDON_OTG_ON (1 << 0) + +/* For MMP3 USB Phy */ +#define USB2_PLL_REG0 0x4 +#define USB2_PLL_REG1 0x8 +#define USB2_TX_REG0 0x10 +#define USB2_TX_REG1 0x14 +#define USB2_TX_REG2 0x18 +#define USB2_RX_REG0 0x20 +#define USB2_RX_REG1 0x24 +#define USB2_RX_REG2 0x28 +#define USB2_ANA_REG0 0x30 +#define USB2_ANA_REG1 0x34 +#define USB2_ANA_REG2 0x38 +#define USB2_DIG_REG0 0x3C +#define USB2_DIG_REG1 0x40 +#define USB2_DIG_REG2 0x44 +#define USB2_DIG_REG3 0x48 +#define USB2_TEST_REG0 0x4C +#define USB2_TEST_REG1 0x50 +#define USB2_TEST_REG2 0x54 +#define USB2_CHARGER_REG0 0x58 +#define USB2_OTG_REG0 0x5C +#define USB2_PHY_MON0 0x60 +#define USB2_RESETVE_REG0 0x64 +#define USB2_ICID_REG0 0x78 +#define USB2_ICID_REG1 0x7C + +/* USB2_PLL_REG0 */ +/* This is for Ax stepping */ +#define USB2_PLL_FBDIV_SHIFT_MMP3 0 +#define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0) + +#define USB2_PLL_REFDIV_SHIFT_MMP3 8 +#define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8) + +#define USB2_PLL_VDD12_SHIFT_MMP3 12 +#define USB2_PLL_VDD18_SHIFT_MMP3 14 + +/* This is for B0 stepping */ +#define USB2_PLL_FBDIV_SHIFT_MMP3_B0 0 +#define USB2_PLL_REFDIV_SHIFT_MMP3_B0 9 +#define USB2_PLL_VDD18_SHIFT_MMP3_B0 14 +#define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF +#define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E00 + +#define USB2_PLL_CAL12_SHIFT_MMP3 0 +#define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0) + +#define USB2_PLL_VCOCAL_START_SHIFT_MMP3 2 + +#define USB2_PLL_KVCO_SHIFT_MMP3 4 +#define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4) + +#define USB2_PLL_ICP_SHIFT_MMP3 8 +#define USB2_PLL_ICP_MASK_MMP3 (0x7<<8) + +#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 12 + +#define USB2_PLL_PU_PLL_SHIFT_MMP3 13 +#define USB2_PLL_PU_PLL_MASK (0x1 << 13) + +#define USB2_PLL_READY_MASK_MMP3 (0x1 << 15) + +/* USB2_TX_REG0 */ +#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 8 +#define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8) + +#define USB2_TX_RCAL_START_SHIFT_MMP3 13 + +/* USB2_TX_REG1 */ +#define USB2_TX_CK60_PHSEL_SHIFT_MMP3 0 +#define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0) + +#define USB2_TX_AMP_SHIFT_MMP3 4 +#define USB2_TX_AMP_MASK_MMP3 (0x7 << 4) + +#define USB2_TX_VDD12_SHIFT_MMP3 8 +#define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8) + +/* USB2_TX_REG2 */ +#define USB2_TX_DRV_SLEWRATE_SHIFT 10 + +/* USB2_RX_REG0 */ +#define USB2_RX_SQ_THRESH_SHIFT_MMP3 4 +#define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4) + +#define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10 +#define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10) + +/* USB2_ANA_REG1*/ +#define USB2_ANA_PU_ANA_SHIFT_MMP3 14 + +/* USB2_OTG_REG0 */ +#define USB2_OTG_PU_OTG_SHIFT_MMP3 3 + +/* fsic registers */ +#define FSIC_MISC 0x4 +#define FSIC_INT 0x28 +#define FSIC_CTRL 0x30 + +/* HSIC registers */ +#define HSIC_PAD_CTRL 0x4 + +#define HSIC_CTRL 0x8 +#define HSIC_CTRL_HSIC_ENABLE (1<<7) +#define HSIC_CTRL_PLL_BYPASS (1<<4) + +#define TEST_GRP_0 0xc +#define TEST_GRP_1 0x10 + +#define HSIC_INT 0x14 +#define HSIC_INT_READY_INT_EN (1<<10) +#define HSIC_INT_CONNECT_INT_EN (1<<9) +#define HSIC_INT_CORE_INT_EN (1<<8) +#define HSIC_INT_HS_READY (1<<2) +#define HSIC_INT_CONNECT (1<<1) +#define HSIC_INT_CORE (1<<0) + +#define HSIC_CONFIG 0x18 +#define USBHSIC_CTRL 0x20 + +#define HSIC_USB_CTRL 0x28 +#define HSIC_USB_CTRL_CLKEN 1 +#define HSIC_USB_CLK_PHY 0x0 +#define HSIC_USB_CLK_PMU 0x1 + +#endif /* __ASM_ARCH_PXA_U2O_H */ diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c deleted file mode 100644 index 7895d277421..00000000000 --- a/arch/arm/mach-mmp/irq-mmp2.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * linux/arch/arm/mach-mmp/irq-mmp2.c - * - * Generic IRQ handling, GPIO IRQ demultiplexing, etc. - * - * Author: Haojian Zhuang <haojian.zhuang@marvell.com> - * Copyright: Marvell International Ltd. - * - * 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. - */ - -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> - -#include <mach/irqs.h> -#include <mach/regs-icu.h> -#include <mach/mmp2.h> - -#include "common.h" - -static void icu_mask_irq(struct irq_data *d) -{ - uint32_t r = __raw_readl(ICU_INT_CONF(d->irq)); - - r &= ~ICU_INT_ROUTE_PJ4_IRQ; - __raw_writel(r, ICU_INT_CONF(d->irq)); -} - -static void icu_unmask_irq(struct irq_data *d) -{ - uint32_t r = __raw_readl(ICU_INT_CONF(d->irq)); - - r |= ICU_INT_ROUTE_PJ4_IRQ; - __raw_writel(r, ICU_INT_CONF(d->irq)); -} - -static struct irq_chip icu_irq_chip = { - .name = "icu_irq", - .irq_mask = icu_mask_irq, - .irq_mask_ack = icu_mask_irq, - .irq_unmask = icu_unmask_irq, -}; - -static void pmic_irq_ack(struct irq_data *d) -{ - if (d->irq == IRQ_MMP2_PMIC) - mmp2_clear_pmic_int(); -} - -#define SECOND_IRQ_MASK(_name_, irq_base, prefix) \ -static void _name_##_mask_irq(struct irq_data *d) \ -{ \ - uint32_t r; \ - r = __raw_readl(prefix##_MASK) | (1 << (d->irq - irq_base)); \ - __raw_writel(r, prefix##_MASK); \ -} - -#define SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \ -static void _name_##_unmask_irq(struct irq_data *d) \ -{ \ - uint32_t r; \ - r = __raw_readl(prefix##_MASK) & ~(1 << (d->irq - irq_base)); \ - __raw_writel(r, prefix##_MASK); \ -} - -#define SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \ -static void _name_##_irq_demux(unsigned int irq, struct irq_desc *desc) \ -{ \ - unsigned long status, mask, n; \ - mask = __raw_readl(prefix##_MASK); \ - while (1) { \ - status = __raw_readl(prefix##_STATUS) & ~mask; \ - if (status == 0) \ - break; \ - n = find_first_bit(&status, BITS_PER_LONG); \ - while (n < BITS_PER_LONG) { \ - generic_handle_irq(irq_base + n); \ - n = find_next_bit(&status, BITS_PER_LONG, n+1); \ - } \ - } \ -} - -#define SECOND_IRQ_CHIP(_name_, irq_base, prefix) \ -SECOND_IRQ_MASK(_name_, irq_base, prefix) \ -SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \ -SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \ -static struct irq_chip _name_##_irq_chip = { \ - .name = #_name_, \ - .irq_mask = _name_##_mask_irq, \ - .irq_unmask = _name_##_unmask_irq, \ -} - -SECOND_IRQ_CHIP(pmic, IRQ_MMP2_PMIC_BASE, MMP2_ICU_INT4); -SECOND_IRQ_CHIP(rtc, IRQ_MMP2_RTC_BASE, MMP2_ICU_INT5); -SECOND_IRQ_CHIP(twsi, IRQ_MMP2_TWSI_BASE, MMP2_ICU_INT17); -SECOND_IRQ_CHIP(misc, IRQ_MMP2_MISC_BASE, MMP2_ICU_INT35); -SECOND_IRQ_CHIP(ssp, IRQ_MMP2_SSP_BASE, MMP2_ICU_INT51); - -static void init_mux_irq(struct irq_chip *chip, int start, int num) -{ - int irq; - - for (irq = start; num > 0; irq++, num--) { - struct irq_data *d = irq_get_irq_data(irq); - - /* mask and clear the IRQ */ - chip->irq_mask(d); - if (chip->irq_ack) - chip->irq_ack(d); - - irq_set_chip(irq, chip); - set_irq_flags(irq, IRQF_VALID); - irq_set_handler(irq, handle_level_irq); - } -} - -void __init mmp2_init_icu(void) -{ - int irq; - - for (irq = 0; irq < IRQ_MMP2_MUX_BASE; irq++) { - icu_mask_irq(irq_get_irq_data(irq)); - irq_set_chip(irq, &icu_irq_chip); - set_irq_flags(irq, IRQF_VALID); - - switch (irq) { - case IRQ_MMP2_PMIC_MUX: - case IRQ_MMP2_RTC_MUX: - case IRQ_MMP2_TWSI_MUX: - case IRQ_MMP2_MISC_MUX: - case IRQ_MMP2_SSP_MUX: - break; - default: - irq_set_handler(irq, handle_level_irq); - break; - } - } - - /* NOTE: IRQ_MMP2_PMIC requires the PMIC MFPR register - * to be written to clear the interrupt - */ - pmic_irq_chip.irq_ack = pmic_irq_ack; - - init_mux_irq(&pmic_irq_chip, IRQ_MMP2_PMIC_BASE, 2); - init_mux_irq(&rtc_irq_chip, IRQ_MMP2_RTC_BASE, 2); - init_mux_irq(&twsi_irq_chip, IRQ_MMP2_TWSI_BASE, 5); - init_mux_irq(&misc_irq_chip, IRQ_MMP2_MISC_BASE, 15); - init_mux_irq(&ssp_irq_chip, IRQ_MMP2_SSP_BASE, 2); - - irq_set_chained_handler(IRQ_MMP2_PMIC_MUX, pmic_irq_demux); - irq_set_chained_handler(IRQ_MMP2_RTC_MUX, rtc_irq_demux); - irq_set_chained_handler(IRQ_MMP2_TWSI_MUX, twsi_irq_demux); - irq_set_chained_handler(IRQ_MMP2_MISC_MUX, misc_irq_demux); - irq_set_chained_handler(IRQ_MMP2_SSP_MUX, ssp_irq_demux); -} diff --git a/arch/arm/mach-mmp/irq-pxa168.c b/arch/arm/mach-mmp/irq-pxa168.c deleted file mode 100644 index 89706a0d08f..00000000000 --- a/arch/arm/mach-mmp/irq-pxa168.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/arch/arm/mach-mmp/irq.c - * - * Generic IRQ handling, GPIO IRQ demultiplexing, etc. - * - * Author: Bin Yang <bin.yang@marvell.com> - * Created: Sep 30, 2008 - * Copyright: Marvell International Ltd. - * - * 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. - */ - -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> - -#include <mach/regs-icu.h> - -#include "common.h" - -#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ) - -#define PRIORITY_DEFAULT 0x1 -#define PRIORITY_NONE 0x0 /* means IRQ disabled */ - -static void icu_mask_irq(struct irq_data *d) -{ - __raw_writel(PRIORITY_NONE, ICU_INT_CONF(d->irq)); -} - -static void icu_unmask_irq(struct irq_data *d) -{ - __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(d->irq)); -} - -static struct irq_chip icu_irq_chip = { - .name = "icu_irq", - .irq_ack = icu_mask_irq, - .irq_mask = icu_mask_irq, - .irq_unmask = icu_unmask_irq, -}; - -void __init icu_init_irq(void) -{ - int irq; - - for (irq = 0; irq < 64; irq++) { - icu_mask_irq(irq_get_irq_data(irq)); - irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } -} diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c new file mode 100644 index 00000000000..fcfe0e3bd70 --- /dev/null +++ b/arch/arm/mach-mmp/irq.c @@ -0,0 +1,458 @@ +/* + * linux/arch/arm/mach-mmp/irq.c + * + * Generic IRQ handling, GPIO IRQ demultiplexing, etc. + * Copyright (C) 2008 - 2012 Marvell Technology Group Ltd. + * + * Author: Bin Yang <bin.yang@marvell.com> + * Haojian Zhuang <haojian.zhuang@gmail.com> + * + * 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. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include <mach/irqs.h> + +#ifdef CONFIG_CPU_MMP2 +#include <mach/pm-mmp2.h> +#endif +#ifdef CONFIG_CPU_PXA910 +#include <mach/pm-pxa910.h> +#endif + +#include "common.h" + +#define MAX_ICU_NR 16 + +struct icu_chip_data { + int nr_irqs; + unsigned int virq_base; + unsigned int cascade_irq; + void __iomem *reg_status; + void __iomem *reg_mask; + unsigned int conf_enable; + unsigned int conf_disable; + unsigned int conf_mask; + unsigned int clr_mfp_irq_base; + unsigned int clr_mfp_hwirq; + struct irq_domain *domain; +}; + +struct mmp_intc_conf { + unsigned int conf_enable; + unsigned int conf_disable; + unsigned int conf_mask; +}; + +void __iomem *mmp_icu_base; +static struct icu_chip_data icu_data[MAX_ICU_NR]; +static int max_icu_nr; + +extern void mmp2_clear_pmic_int(void); + +static void icu_mask_ack_irq(struct irq_data *d) +{ + struct irq_domain *domain = d->domain; + struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; + int hwirq; + u32 r; + + hwirq = d->irq - data->virq_base; + if (data == &icu_data[0]) { + r = readl_relaxed(mmp_icu_base + (hwirq << 2)); + r &= ~data->conf_mask; + r |= data->conf_disable; + writel_relaxed(r, mmp_icu_base + (hwirq << 2)); + } else { +#ifdef CONFIG_CPU_MMP2 + if ((data->virq_base == data->clr_mfp_irq_base) + && (hwirq == data->clr_mfp_hwirq)) + mmp2_clear_pmic_int(); +#endif + r = readl_relaxed(data->reg_mask) | (1 << hwirq); + writel_relaxed(r, data->reg_mask); + } +} + +static void icu_mask_irq(struct irq_data *d) +{ + struct irq_domain *domain = d->domain; + struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; + int hwirq; + u32 r; + + hwirq = d->irq - data->virq_base; + if (data == &icu_data[0]) { + r = readl_relaxed(mmp_icu_base + (hwirq << 2)); + r &= ~data->conf_mask; + r |= data->conf_disable; + writel_relaxed(r, mmp_icu_base + (hwirq << 2)); + } else { + r = readl_relaxed(data->reg_mask) | (1 << hwirq); + writel_relaxed(r, data->reg_mask); + } +} + +static void icu_unmask_irq(struct irq_data *d) +{ + struct irq_domain *domain = d->domain; + struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; + int hwirq; + u32 r; + + hwirq = d->irq - data->virq_base; + if (data == &icu_data[0]) { + r = readl_relaxed(mmp_icu_base + (hwirq << 2)); + r &= ~data->conf_mask; + r |= data->conf_enable; + writel_relaxed(r, mmp_icu_base + (hwirq << 2)); + } else { + r = readl_relaxed(data->reg_mask) & ~(1 << hwirq); + writel_relaxed(r, data->reg_mask); + } +} + +static struct irq_chip icu_irq_chip = { + .name = "icu_irq", + .irq_mask = icu_mask_irq, + .irq_mask_ack = icu_mask_ack_irq, + .irq_unmask = icu_unmask_irq, +}; + +static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc) +{ + struct irq_domain *domain; + struct icu_chip_data *data; + int i; + unsigned long mask, status, n; + + for (i = 1; i < max_icu_nr; i++) { + if (irq == icu_data[i].cascade_irq) { + domain = icu_data[i].domain; + data = (struct icu_chip_data *)domain->host_data; + break; + } + } + if (i >= max_icu_nr) { + pr_err("Spurious irq %d in MMP INTC\n", irq); + return; + } + + mask = readl_relaxed(data->reg_mask); + while (1) { + status = readl_relaxed(data->reg_status) & ~mask; + if (status == 0) + break; + n = find_first_bit(&status, BITS_PER_LONG); + while (n < BITS_PER_LONG) { + generic_handle_irq(icu_data[i].virq_base + n); + n = find_next_bit(&status, BITS_PER_LONG, n + 1); + } + } +} + +static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + return 0; +} + +static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + *out_hwirq = intspec[0]; + return 0; +} + +const struct irq_domain_ops mmp_irq_domain_ops = { + .map = mmp_irq_domain_map, + .xlate = mmp_irq_domain_xlate, +}; + +static struct mmp_intc_conf mmp_conf = { + .conf_enable = 0x51, + .conf_disable = 0x0, + .conf_mask = 0x7f, +}; + +static struct mmp_intc_conf mmp2_conf = { + .conf_enable = 0x20, + .conf_disable = 0x0, + .conf_mask = 0x7f, +}; + +/* MMP (ARMv5) */ +void __init icu_init_irq(void) +{ + int irq; + + max_icu_nr = 1; + mmp_icu_base = ioremap(0xd4282000, 0x1000); + icu_data[0].conf_enable = mmp_conf.conf_enable; + icu_data[0].conf_disable = mmp_conf.conf_disable; + icu_data[0].conf_mask = mmp_conf.conf_mask; + icu_data[0].nr_irqs = 64; + icu_data[0].virq_base = 0; + icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, + &irq_domain_simple_ops, + &icu_data[0]); + for (irq = 0; irq < 64; irq++) { + icu_mask_irq(irq_get_irq_data(irq)); + irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + irq_set_default_host(icu_data[0].domain); +#ifdef CONFIG_CPU_PXA910 + icu_irq_chip.irq_set_wake = pxa910_set_wake; +#endif +} + +/* MMP2 (ARMv7) */ +void __init mmp2_init_icu(void) +{ + int irq; + + max_icu_nr = 8; + mmp_icu_base = ioremap(0xd4282000, 0x1000); + icu_data[0].conf_enable = mmp2_conf.conf_enable; + icu_data[0].conf_disable = mmp2_conf.conf_disable; + icu_data[0].conf_mask = mmp2_conf.conf_mask; + icu_data[0].nr_irqs = 64; + icu_data[0].virq_base = 0; + icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, + &irq_domain_simple_ops, + &icu_data[0]); + icu_data[1].reg_status = mmp_icu_base + 0x150; + icu_data[1].reg_mask = mmp_icu_base + 0x168; + icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE; + icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE; + icu_data[1].nr_irqs = 2; + icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE; + icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs, + icu_data[1].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[1]); + icu_data[2].reg_status = mmp_icu_base + 0x154; + icu_data[2].reg_mask = mmp_icu_base + 0x16c; + icu_data[2].nr_irqs = 2; + icu_data[2].virq_base = IRQ_MMP2_RTC_BASE; + icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs, + icu_data[2].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[2]); + icu_data[3].reg_status = mmp_icu_base + 0x180; + icu_data[3].reg_mask = mmp_icu_base + 0x17c; + icu_data[3].nr_irqs = 3; + icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE; + icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs, + icu_data[3].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[3]); + icu_data[4].reg_status = mmp_icu_base + 0x158; + icu_data[4].reg_mask = mmp_icu_base + 0x170; + icu_data[4].nr_irqs = 5; + icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE; + icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs, + icu_data[4].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[4]); + icu_data[5].reg_status = mmp_icu_base + 0x15c; + icu_data[5].reg_mask = mmp_icu_base + 0x174; + icu_data[5].nr_irqs = 15; + icu_data[5].virq_base = IRQ_MMP2_MISC_BASE; + icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs, + icu_data[5].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[5]); + icu_data[6].reg_status = mmp_icu_base + 0x160; + icu_data[6].reg_mask = mmp_icu_base + 0x178; + icu_data[6].nr_irqs = 2; + icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE; + icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs, + icu_data[6].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[6]); + icu_data[7].reg_status = mmp_icu_base + 0x188; + icu_data[7].reg_mask = mmp_icu_base + 0x184; + icu_data[7].nr_irqs = 2; + icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE; + icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs, + icu_data[7].virq_base, 0, + &irq_domain_simple_ops, + &icu_data[7]); + for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) { + icu_mask_irq(irq_get_irq_data(irq)); + switch (irq) { + case IRQ_MMP2_PMIC_MUX: + case IRQ_MMP2_RTC_MUX: + case IRQ_MMP2_KEYPAD_MUX: + case IRQ_MMP2_TWSI_MUX: + case IRQ_MMP2_MISC_MUX: + case IRQ_MMP2_MIPI_HSI1_MUX: + case IRQ_MMP2_MIPI_HSI0_MUX: + irq_set_chip(irq, &icu_irq_chip); + irq_set_chained_handler(irq, icu_mux_irq_demux); + break; + default: + irq_set_chip_and_handler(irq, &icu_irq_chip, + handle_level_irq); + break; + } + set_irq_flags(irq, IRQF_VALID); + } + irq_set_default_host(icu_data[0].domain); +#ifdef CONFIG_CPU_MMP2 + icu_irq_chip.irq_set_wake = mmp2_set_wake; +#endif +} + +#ifdef CONFIG_OF +static const struct of_device_id intc_ids[] __initconst = { + { .compatible = "mrvl,mmp-intc", .data = &mmp_conf }, + { .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf }, + {} +}; + +static const struct of_device_id mmp_mux_irq_match[] __initconst = { + { .compatible = "mrvl,mmp2-mux-intc" }, + {} +}; + +int __init mmp2_mux_init(struct device_node *parent) +{ + struct device_node *node; + const struct of_device_id *of_id; + struct resource res; + int i, irq_base, ret, irq; + u32 nr_irqs, mfp_irq; + + node = parent; + max_icu_nr = 1; + for (i = 1; i < MAX_ICU_NR; i++) { + node = of_find_matching_node(node, mmp_mux_irq_match); + if (!node) + break; + of_id = of_match_node(&mmp_mux_irq_match[0], node); + ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", + &nr_irqs); + if (ret) { + pr_err("Not found mrvl,intc-nr-irqs property\n"); + ret = -EINVAL; + goto err; + } + ret = of_address_to_resource(node, 0, &res); + if (ret < 0) { + pr_err("Not found reg property\n"); + ret = -EINVAL; + goto err; + } + icu_data[i].reg_status = mmp_icu_base + res.start; + ret = of_address_to_resource(node, 1, &res); + if (ret < 0) { + pr_err("Not found reg property\n"); + ret = -EINVAL; + goto err; + } + icu_data[i].reg_mask = mmp_icu_base + res.start; + icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); + if (!icu_data[i].cascade_irq) { + ret = -EINVAL; + goto err; + } + + irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); + if (irq_base < 0) { + pr_err("Failed to allocate IRQ numbers for mux intc\n"); + ret = irq_base; + goto err; + } + if (!of_property_read_u32(node, "mrvl,clr-mfp-irq", + &mfp_irq)) { + icu_data[i].clr_mfp_irq_base = irq_base; + icu_data[i].clr_mfp_hwirq = mfp_irq; + } + irq_set_chained_handler(icu_data[i].cascade_irq, + icu_mux_irq_demux); + icu_data[i].nr_irqs = nr_irqs; + icu_data[i].virq_base = irq_base; + icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs, + irq_base, 0, + &mmp_irq_domain_ops, + &icu_data[i]); + for (irq = irq_base; irq < irq_base + nr_irqs; irq++) + icu_mask_irq(irq_get_irq_data(irq)); + } + max_icu_nr = i; + return 0; +err: + of_node_put(node); + max_icu_nr = i; + return ret; +} + +void __init mmp_dt_irq_init(void) +{ + struct device_node *node; + const struct of_device_id *of_id; + struct mmp_intc_conf *conf; + int nr_irqs, irq_base, ret, irq; + + node = of_find_matching_node(NULL, intc_ids); + if (!node) { + pr_err("Failed to find interrupt controller in arch-mmp\n"); + return; + } + of_id = of_match_node(intc_ids, node); + conf = of_id->data; + + ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs); + if (ret) { + pr_err("Not found mrvl,intc-nr-irqs property\n"); + return; + } + + mmp_icu_base = of_iomap(node, 0); + if (!mmp_icu_base) { + pr_err("Failed to get interrupt controller register\n"); + return; + } + + irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0); + if (irq_base < 0) { + pr_err("Failed to allocate IRQ numbers\n"); + goto err; + } else if (irq_base != NR_IRQS_LEGACY) { + pr_err("ICU's irqbase should be started from 0\n"); + goto err; + } + icu_data[0].conf_enable = conf->conf_enable; + icu_data[0].conf_disable = conf->conf_disable; + icu_data[0].conf_mask = conf->conf_mask; + icu_data[0].nr_irqs = nr_irqs; + icu_data[0].virq_base = 0; + icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0, + &mmp_irq_domain_ops, + &icu_data[0]); + irq_set_default_host(icu_data[0].domain); + for (irq = 0; irq < nr_irqs; irq++) + icu_mask_irq(irq_get_irq_data(irq)); + mmp2_mux_init(node); + return; +err: + iounmap(mmp_icu_base); +} +#endif diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c index 67075395e40..033cc31b3c7 100644 --- a/arch/arm/mach-mmp/mmp-dt.c +++ b/arch/arm/mach-mmp/mmp-dt.c @@ -14,14 +14,19 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/mach/arch.h> +#include <asm/mach/time.h> #include <mach/irqs.h> #include "common.h" -extern struct sys_timer pxa168_timer; -extern void __init icu_init_irq(void); +extern void __init mmp_dt_irq_init(void); +extern void __init mmp_dt_init_timer(void); -static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = { +static struct sys_timer mmp_dt_timer = { + .init = mmp_dt_init_timer, +}; + +static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL), OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL), OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL), @@ -32,44 +37,47 @@ static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = { {} }; -static int __init mmp_intc_add_irq_domain(struct device_node *np, - struct device_node *parent) -{ - irq_domain_add_simple(np, 0); - return 0; -} - -static int __init mmp_gpio_add_irq_domain(struct device_node *np, - struct device_node *parent) -{ - irq_domain_add_simple(np, IRQ_GPIO_START); - return 0; -} - -static const struct of_device_id mmp_irq_match[] __initconst = { - { .compatible = "mrvl,mmp-intc", .data = mmp_intc_add_irq_domain, }, - { .compatible = "mrvl,mmp-gpio", .data = mmp_gpio_add_irq_domain, }, +static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = { + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL), + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL), + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL), + OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL), + OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL), + OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL), + OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL), {} }; -static void __init mmp_dt_init(void) +static void __init pxa168_dt_init(void) { + of_platform_populate(NULL, of_default_bus_match_table, + pxa168_auxdata_lookup, NULL); +} - of_irq_init(mmp_irq_match); - +static void __init pxa910_dt_init(void) +{ of_platform_populate(NULL, of_default_bus_match_table, - mmp_auxdata_lookup, NULL); + pxa910_auxdata_lookup, NULL); } -static const char *pxa168_dt_board_compat[] __initdata = { +static const char *mmp_dt_board_compat[] __initdata = { "mrvl,pxa168-aspenite", + "mrvl,pxa910-dkb", NULL, }; DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)") .map_io = mmp_map_io, - .init_irq = icu_init_irq, - .timer = &pxa168_timer, - .init_machine = mmp_dt_init, - .dt_compat = pxa168_dt_board_compat, + .init_irq = mmp_dt_irq_init, + .timer = &mmp_dt_timer, + .init_machine = pxa168_dt_init, + .dt_compat = mmp_dt_board_compat, +MACHINE_END + +DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)") + .map_io = mmp_map_io, + .init_irq = mmp_dt_irq_init, + .timer = &mmp_dt_timer, + .init_machine = pxa910_dt_init, + .dt_compat = mmp_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c new file mode 100644 index 00000000000..535a5ed5977 --- /dev/null +++ b/arch/arm/mach-mmp/mmp2-dt.c @@ -0,0 +1,60 @@ +/* + * linux/arch/arm/mach-mmp/mmp2-dt.c + * + * Copyright (C) 2012 Marvell Technology Group Ltd. + * Author: Haojian Zhuang <haojian.zhuang@marvell.com> + * + * 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 + * publishhed by the Free Software Foundation. + */ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/irqs.h> +#include <mach/regs-apbc.h> + +#include "common.h" + +extern void __init mmp_dt_irq_init(void); +extern void __init mmp_dt_init_timer(void); + +static struct sys_timer mmp_dt_timer = { + .init = mmp_dt_init_timer, +}; + +static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = { + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL), + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL), + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL), + OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL), + OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL), + OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL), + OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL), + OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL), + {} +}; + +static void __init mmp2_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, + mmp2_auxdata_lookup, NULL); +} + +static const char *mmp2_dt_board_compat[] __initdata = { + "mrvl,mmp2-brownstone", + NULL, +}; + +DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)") + .map_io = mmp_map_io, + .init_irq = mmp_dt_irq_init, + .timer = &mmp_dt_timer, + .init_machine = mmp2_dt_init, + .dt_compat = mmp2_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c new file mode 100644 index 00000000000..461a191a32d --- /dev/null +++ b/arch/arm/mach-mmp/pm-mmp2.c @@ -0,0 +1,264 @@ +/* + * MMP2 Power Management Routines + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * (C) Copyright 2012 Marvell International Ltd. + * All Rights Reserved + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/suspend.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <asm/mach-types.h> +#include <mach/hardware.h> +#include <mach/cputype.h> +#include <mach/addr-map.h> +#include <mach/pm-mmp2.h> +#include <mach/regs-icu.h> +#include <mach/irqs.h> + +int mmp2_set_wake(struct irq_data *d, unsigned int on) +{ + int irq = d->irq; + struct irq_desc *desc = irq_to_desc(irq); + unsigned long data = 0; + + if (unlikely(irq >= nr_irqs)) { + pr_err("IRQ nubmers are out of boundary!\n"); + return -EINVAL; + } + + if (on) { + if (desc->action) + desc->action->flags |= IRQF_NO_SUSPEND; + } else { + if (desc->action) + desc->action->flags &= ~IRQF_NO_SUSPEND; + } + + /* enable wakeup sources */ + switch (irq) { + case IRQ_MMP2_RTC: + case IRQ_MMP2_RTC_ALARM: + data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM; + break; + case IRQ_MMP2_PMIC: + data = MPMU_WUCRM_PJ_WAKEUP(7); + break; + case IRQ_MMP2_MMC2: + /* mmc use WAKEUP2, same as GPIO wakeup source */ + data = MPMU_WUCRM_PJ_WAKEUP(2); + break; + } + if (on) { + if (data) { + data |= __raw_readl(MPMU_WUCRM_PJ); + __raw_writel(data, MPMU_WUCRM_PJ); + } + } else { + if (data) { + data = ~data & __raw_readl(MPMU_WUCRM_PJ); + __raw_writel(data, MPMU_WUCRM_PJ); + } + } + return 0; +} + +static void pm_scu_clk_disable(void) +{ + unsigned int val; + + /* close AXI fabric clock gate */ + __raw_writel(0x0, CIU_REG(0x64)); + __raw_writel(0x0, CIU_REG(0x68)); + + /* close MCB master clock gate */ + val = __raw_readl(CIU_REG(0x1c)); + val |= 0xf0; + __raw_writel(val, CIU_REG(0x1c)); + + return ; +} + +static void pm_scu_clk_enable(void) +{ + unsigned int val; + + /* open AXI fabric clock gate */ + __raw_writel(0x03003003, CIU_REG(0x64)); + __raw_writel(0x00303030, CIU_REG(0x68)); + + /* open MCB master clock gate */ + val = __raw_readl(CIU_REG(0x1c)); + val &= ~(0xf0); + __raw_writel(val, CIU_REG(0x1c)); + + return ; +} + +static void pm_mpmu_clk_disable(void) +{ + /* + * disable clocks in MPMU_CGR_PJ register + * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M + */ + __raw_writel(0x0000a010, MPMU_CGR_PJ); +} + +static void pm_mpmu_clk_enable(void) +{ + unsigned int val; + + __raw_writel(0xdffefffe, MPMU_CGR_PJ); + val = __raw_readl(MPMU_PLL2_CTRL1); + val |= (1 << 29); + __raw_writel(val, MPMU_PLL2_CTRL1); + + return ; +} + +void mmp2_pm_enter_lowpower_mode(int state) +{ + uint32_t idle_cfg, apcr; + + idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG); + apcr = __raw_readl(MPMU_PCR_PJ); + apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD + | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13)); + idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE; + + switch (state) { + case POWER_MODE_SYS_SLEEP: + apcr |= MPMU_PCR_PJ_SLPEN; /* set the SLPEN bit */ + apcr |= MPMU_PCR_PJ_VCTCXOSD; /* set VCTCXOSD */ + /* fall through */ + case POWER_MODE_CHIP_SLEEP: + apcr |= MPMU_PCR_PJ_SLPEN; + /* fall through */ + case POWER_MODE_APPS_SLEEP: + apcr |= MPMU_PCR_PJ_APBSD; /* set APBSD */ + /* fall through */ + case POWER_MODE_APPS_IDLE: + apcr |= MPMU_PCR_PJ_AXISD; /* set AXISDD bit */ + apcr |= MPMU_PCR_PJ_DDRCORSD; /* set DDRCORSD bit */ + idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN; /* PJ power down */ + apcr |= MPMU_PCR_PJ_SPSD; + /* fall through */ + case POWER_MODE_CORE_EXTIDLE: + idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE; /* set the IDLE bit */ + idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK; + idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3) + | APMU_PJ_IDLE_CFG_L2_PWR_SW; + break; + case POWER_MODE_CORE_INTIDLE: + apcr &= ~MPMU_PCR_PJ_SPSD; + break; + } + + /* set reserve bits */ + apcr |= (1 << 30) | (1 << 25); + + /* finally write the registers back */ + __raw_writel(idle_cfg, APMU_PJ_IDLE_CFG); + __raw_writel(apcr, MPMU_PCR_PJ); /* 0xfe086000 */ +} + +static int mmp2_pm_enter(suspend_state_t state) +{ + int temp; + + temp = __raw_readl(MMP2_ICU_INT4_MASK); + if (temp & (1 << 1)) { + printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__); + return -EAGAIN; + } + + temp = __raw_readl(APMU_SRAM_PWR_DWN); + temp |= ((1 << 19) | (1 << 18)); + __raw_writel(temp, APMU_SRAM_PWR_DWN); + pm_mpmu_clk_disable(); + pm_scu_clk_disable(); + + printk(KERN_INFO "%s: before suspend\n", __func__); + cpu_do_idle(); + printk(KERN_INFO "%s: after suspend\n", __func__); + + pm_mpmu_clk_enable(); /* enable clocks in MPMU */ + pm_scu_clk_enable(); /* enable clocks in SCU */ + + return 0; +} + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int mmp2_pm_prepare(void) +{ + mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP); + + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static void mmp2_pm_finish(void) +{ + mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE); +} + +static int mmp2_pm_valid(suspend_state_t state) +{ + return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM)); +} + +/* + * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. + */ +static const struct platform_suspend_ops mmp2_pm_ops = { + .valid = mmp2_pm_valid, + .prepare = mmp2_pm_prepare, + .enter = mmp2_pm_enter, + .finish = mmp2_pm_finish, +}; + +static int __init mmp2_pm_init(void) +{ + uint32_t apcr; + + if (!cpu_is_mmp2()) + return -EIO; + + suspend_set_ops(&mmp2_pm_ops); + + /* + * Set bit 0, Slow clock Select 32K clock input instead of VCXO + * VCXO is chosen by default, which would be disabled in suspend + */ + __raw_writel(0x5, MPMU_SCCR); + + /* + * Clear bit 23 of CIU_CPU_CONF + * direct PJ4 to DDR access through Memory Controller slow queue + * fast queue has issue and cause lcd will flick + */ + __raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8)); + + /* Clear default low power control bit */ + apcr = __raw_readl(MPMU_PCR_PJ); + apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD + | MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13); + __raw_writel(apcr, MPMU_PCR_PJ); + + return 0; +} + +late_initcall(mmp2_pm_init); diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c new file mode 100644 index 00000000000..48981ca801a --- /dev/null +++ b/arch/arm/mach-mmp/pm-pxa910.c @@ -0,0 +1,285 @@ +/* + * PXA910 Power Management Routines + * + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + * + * (C) Copyright 2009 Marvell International Ltd. + * All Rights Reserved + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/suspend.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <asm/mach-types.h> +#include <mach/hardware.h> +#include <mach/cputype.h> +#include <mach/addr-map.h> +#include <mach/pm-pxa910.h> +#include <mach/regs-icu.h> +#include <mach/irqs.h> + +int pxa910_set_wake(struct irq_data *data, unsigned int on) +{ + int irq = data->irq; + struct irq_desc *desc = irq_to_desc(data->irq); + uint32_t awucrm = 0, apcr = 0; + + if (unlikely(irq >= nr_irqs)) { + pr_err("IRQ nubmers are out of boundary!\n"); + return -EINVAL; + } + + if (on) { + if (desc->action) + desc->action->flags |= IRQF_NO_SUSPEND; + } else { + if (desc->action) + desc->action->flags &= ~IRQF_NO_SUSPEND; + } + + /* setting wakeup sources */ + switch (irq) { + /* wakeup line 2 */ + case IRQ_PXA910_AP_GPIO: + awucrm = MPMU_AWUCRM_WAKEUP(2); + apcr |= MPMU_APCR_SLPWP2; + break; + /* wakeup line 3 */ + case IRQ_PXA910_KEYPAD: + awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS; + apcr |= MPMU_APCR_SLPWP3; + break; + case IRQ_PXA910_ROTARY: + awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY; + apcr |= MPMU_APCR_SLPWP3; + break; + case IRQ_PXA910_TRACKBALL: + awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL; + apcr |= MPMU_APCR_SLPWP3; + break; + /* wakeup line 4 */ + case IRQ_PXA910_AP1_TIMER1: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1; + apcr |= MPMU_APCR_SLPWP4; + break; + case IRQ_PXA910_AP1_TIMER2: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2; + apcr |= MPMU_APCR_SLPWP4; + break; + case IRQ_PXA910_AP1_TIMER3: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3; + apcr |= MPMU_APCR_SLPWP4; + break; + case IRQ_PXA910_AP2_TIMER1: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1; + apcr |= MPMU_APCR_SLPWP4; + break; + case IRQ_PXA910_AP2_TIMER2: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2; + apcr |= MPMU_APCR_SLPWP4; + break; + case IRQ_PXA910_AP2_TIMER3: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3; + apcr |= MPMU_APCR_SLPWP4; + break; + case IRQ_PXA910_RTC_ALARM: + awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM; + apcr |= MPMU_APCR_SLPWP4; + break; + /* wakeup line 5 */ + case IRQ_PXA910_USB1: + case IRQ_PXA910_USB2: + awucrm = MPMU_AWUCRM_WAKEUP(5); + apcr |= MPMU_APCR_SLPWP5; + break; + /* wakeup line 6 */ + case IRQ_PXA910_MMC: + awucrm = MPMU_AWUCRM_WAKEUP(6) + | MPMU_AWUCRM_SDH1 + | MPMU_AWUCRM_SDH2; + apcr |= MPMU_APCR_SLPWP6; + break; + /* wakeup line 7 */ + case IRQ_PXA910_PMIC_INT: + awucrm = MPMU_AWUCRM_WAKEUP(7); + apcr |= MPMU_APCR_SLPWP7; + break; + default: + if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) { + awucrm = MPMU_AWUCRM_WAKEUP(2); + apcr |= MPMU_APCR_SLPWP2; + } else + printk(KERN_ERR "Error: no defined wake up source irq: %d\n", + irq); + } + + if (on) { + if (awucrm) { + awucrm |= __raw_readl(MPMU_AWUCRM); + __raw_writel(awucrm, MPMU_AWUCRM); + } + if (apcr) { + apcr = ~apcr & __raw_readl(MPMU_APCR); + __raw_writel(apcr, MPMU_APCR); + } + } else { + if (awucrm) { + awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM); + __raw_writel(awucrm, MPMU_AWUCRM); + } + if (apcr) { + apcr |= __raw_readl(MPMU_APCR); + __raw_writel(apcr, MPMU_APCR); + } + } + return 0; +} + +void pxa910_pm_enter_lowpower_mode(int state) +{ + uint32_t idle_cfg, apcr; + + idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG); + apcr = __raw_readl(MPMU_APCR); + + apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD + | MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN); + idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE + | APMU_MOH_IDLE_CFG_MOH_PWRDWN); + + switch (state) { + case POWER_MODE_UDR: + /* only shutdown APB in UDR */ + apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD; + /* fall through */ + case POWER_MODE_SYS_SLEEP: + apcr |= MPMU_APCR_SLPEN; /* set the SLPEN bit */ + apcr |= MPMU_APCR_VCTCXOSD; /* set VCTCXOSD */ + /* fall through */ + case POWER_MODE_APPS_SLEEP: + apcr |= MPMU_APCR_DDRCORSD; /* set DDRCORSD */ + /* fall through */ + case POWER_MODE_APPS_IDLE: + apcr |= MPMU_APCR_AXISD; /* set AXISDD bit */ + /* fall through */ + case POWER_MODE_CORE_EXTIDLE: + idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE; + idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN; + idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3) + | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3); + /* fall through */ + case POWER_MODE_CORE_INTIDLE: + break; + } + + /* program the memory controller hardware sleep type and auto wakeup */ + idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ; + idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN; + __raw_writel(0x0, APMU_MC_HW_SLP_TYPE); /* auto refresh */ + + /* set DSPSD, DTCMSD, BBSD, MSASLPEN */ + apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD + | MPMU_APCR_MSASLPEN; + + /*always set SLEPEN bit mainly for MSA*/ + apcr |= MPMU_APCR_SLPEN; + + /* finally write the registers back */ + __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG); + __raw_writel(apcr, MPMU_APCR); + +} + +static int pxa910_pm_enter(suspend_state_t state) +{ + unsigned int idle_cfg, reg = 0; + + /*pmic thread not completed,exit;otherwise system can't be waked up*/ + reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT)); + if ((reg & 0x3) == 0) + return -EAGAIN; + + idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG); + idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN + | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN; + __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG); + + /* disable L2 */ + outer_disable(); + /* wait for l2 idle */ + while (!(readl(CIU_REG(0x8)) & (1 << 16))) + udelay(1); + + cpu_do_idle(); + + /* enable L2 */ + outer_resume(); + /* wait for l2 idle */ + while (!(readl(CIU_REG(0x8)) & (1 << 16))) + udelay(1); + + idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG); + idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN + | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN); + __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG); + + return 0; +} + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int pxa910_pm_prepare(void) +{ + pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR); + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static void pxa910_pm_finish(void) +{ + pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE); +} + +static int pxa910_pm_valid(suspend_state_t state) +{ + return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM)); +} + +static const struct platform_suspend_ops pxa910_pm_ops = { + .valid = pxa910_pm_valid, + .prepare = pxa910_pm_prepare, + .enter = pxa910_pm_enter, + .finish = pxa910_pm_finish, +}; + +static int __init pxa910_pm_init(void) +{ + uint32_t awucrm = 0; + + if (!cpu_is_pxa910()) + return -EIO; + + suspend_set_ops(&pxa910_pm_ops); + + /* Set the following bits for MMP3 playback with VCTXO on */ + __raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30), + APMU_SQU_CLK_GATE_CTRL); + __raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR); + + awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE; + __raw_writel(awucrm, MPMU_AWUCRM); + + return 0; +} + +late_initcall(pxa910_pm_init); diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c index b24d2c32cba..62d787c3447 100644 --- a/arch/arm/mach-mmp/pxa168.c +++ b/arch/arm/mach-mmp/pxa168.c @@ -14,6 +14,7 @@ #include <linux/io.h> #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/platform_data/mv_usb.h> #include <asm/mach/time.h> #include <asm/system_misc.h> @@ -27,6 +28,7 @@ #include <mach/mfp.h> #include <linux/dma-mapping.h> #include <mach/pxa168.h> +#include <mach/regs-usb.h> #include "common.h" #include "clock.h" @@ -93,7 +95,7 @@ static struct clk_lookup pxa168_clkregs[] = { INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL), INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL), INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"), - INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"), + INIT_CLKREG(&clk_usb, NULL, "PXA168-USBCLK"), INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL), }; @@ -184,17 +186,17 @@ struct platform_device pxa168_device_gpio = { struct resource pxa168_usb_host_resources[] = { /* USB Host conroller register base */ [0] = { - .start = 0xd4209000, - .end = 0xd4209000 + 0x200, + .start = PXA168_U2H_REGBASE + U2x_CAPREGS_OFFSET, + .end = PXA168_U2H_REGBASE + USB_REG_RANGE, .flags = IORESOURCE_MEM, - .name = "pxa168-usb-host", + .name = "capregs", }, /* USB PHY register base */ [1] = { - .start = 0xd4206000, - .end = 0xd4206000 + 0xff, + .start = PXA168_U2H_PHYBASE, + .end = PXA168_U2H_PHYBASE + USB_PHY_RANGE, .flags = IORESOURCE_MEM, - .name = "pxa168-usb-phy", + .name = "phyregs", }, [2] = { .start = IRQ_PXA168_USB2, @@ -205,7 +207,7 @@ struct resource pxa168_usb_host_resources[] = { static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32); struct platform_device pxa168_device_usb_host = { - .name = "pxa168-ehci", + .name = "pxa-sph", .id = -1, .dev = { .dma_mask = &pxa168_usb_host_dmamask, @@ -216,7 +218,7 @@ struct platform_device pxa168_device_usb_host = { .resource = pxa168_usb_host_resources, }; -int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata) +int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata) { pxa168_device_usb_host.dev.platform_data = pdata; return platform_device_register(&pxa168_device_usb_host); diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c index 43f8bcc29b6..6da52e9f2bd 100644 --- a/arch/arm/mach-mmp/pxa910.c +++ b/arch/arm/mach-mmp/pxa910.c @@ -109,7 +109,7 @@ static struct clk_lookup pxa910_clkregs[] = { INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL), INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL), INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL), - INIT_CLKREG(&clk_u2o, "pxa-u2o", "U2OCLK"), + INIT_CLKREG(&clk_u2o, NULL, "U2OCLK"), INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL), }; diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c index 71fc4ee4602..936447c7097 100644 --- a/arch/arm/mach-mmp/time.c +++ b/arch/arm/mach-mmp/time.c @@ -25,6 +25,9 @@ #include <linux/io.h> #include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/sched_clock.h> #include <mach/addr-map.h> @@ -41,6 +44,8 @@ #define MAX_DELTA (0xfffffffe) #define MIN_DELTA (16) +static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE; + /* * FIXME: the timer needs some delay to stablize the counter capture */ @@ -48,12 +53,12 @@ static inline uint32_t timer_read(void) { int delay = 100; - __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(1)); + __raw_writel(1, mmp_timer_base + TMR_CVWR(1)); while (delay--) cpu_relax(); - return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1)); + return __raw_readl(mmp_timer_base + TMR_CVWR(1)); } static u32 notrace mmp_read_sched_clock(void) @@ -68,12 +73,12 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) /* * Clear pending interrupt status. */ - __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0)); + __raw_writel(0x01, mmp_timer_base + TMR_ICR(0)); /* * Disable timer 0. */ - __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER); + __raw_writel(0x02, mmp_timer_base + TMR_CER); c->event_handler(c); @@ -90,23 +95,23 @@ static int timer_set_next_event(unsigned long delta, /* * Disable timer 0. */ - __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER); + __raw_writel(0x02, mmp_timer_base + TMR_CER); /* * Clear and enable timer match 0 interrupt. */ - __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0)); - __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0)); + __raw_writel(0x01, mmp_timer_base + TMR_ICR(0)); + __raw_writel(0x01, mmp_timer_base + TMR_IER(0)); /* * Setup new clockevent timer value. */ - __raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0)); + __raw_writel(delta - 1, mmp_timer_base + TMR_TN_MM(0, 0)); /* * Enable timer 0. */ - __raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER); + __raw_writel(0x03, mmp_timer_base + TMR_CER); local_irq_restore(flags); @@ -124,7 +129,7 @@ static void timer_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: /* disable the matching interrupt */ - __raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0)); + __raw_writel(0x00, mmp_timer_base + TMR_IER(0)); break; case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_PERIODIC: @@ -157,27 +162,27 @@ static struct clocksource cksrc = { static void __init timer_config(void) { - uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR); + uint32_t ccr = __raw_readl(mmp_timer_base + TMR_CCR); - __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_CER); /* disable */ + __raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */ ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) : (TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3)); - __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR); + __raw_writel(ccr, mmp_timer_base + TMR_CCR); /* set timer 0 to periodic mode, and timer 1 to free-running mode */ - __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR); + __raw_writel(0x2, mmp_timer_base + TMR_CMR); - __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */ - __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */ - __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0)); + __raw_writel(0x1, mmp_timer_base + TMR_PLCR(0)); /* periodic */ + __raw_writel(0x7, mmp_timer_base + TMR_ICR(0)); /* clear status */ + __raw_writel(0x0, mmp_timer_base + TMR_IER(0)); - __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(1)); /* free-running */ - __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1)); /* clear status */ - __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1)); + __raw_writel(0x0, mmp_timer_base + TMR_PLCR(1)); /* free-running */ + __raw_writel(0x7, mmp_timer_base + TMR_ICR(1)); /* clear status */ + __raw_writel(0x0, mmp_timer_base + TMR_IER(1)); /* enable timer 1 counter */ - __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER); + __raw_writel(0x2, mmp_timer_base + TMR_CER); } static struct irqaction timer_irq = { @@ -203,3 +208,37 @@ void __init timer_init(int irq) clocksource_register_hz(&cksrc, CLOCK_TICK_RATE); clockevents_register_device(&ckevt); } + +#ifdef CONFIG_OF +static struct of_device_id mmp_timer_dt_ids[] = { + { .compatible = "mrvl,mmp-timer", }, + {} +}; + +void __init mmp_dt_init_timer(void) +{ + struct device_node *np; + int irq, ret; + + np = of_find_matching_node(NULL, mmp_timer_dt_ids); + if (!np) { + ret = -ENODEV; + goto out; + } + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + ret = -EINVAL; + goto out; + } + mmp_timer_base = of_iomap(np, 0); + if (!mmp_timer_base) { + ret = -ENOMEM; + goto out; + } + timer_init(irq); + return; +out: + pr_err("Failed to get timer from device tree with error:%d\n", ret); +} +#endif diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c index 3fc9ed21f97..7a7de2b12a6 100644 --- a/arch/arm/mach-mmp/ttc_dkb.c +++ b/arch/arm/mach-mmp/ttc_dkb.c @@ -17,6 +17,8 @@ #include <linux/interrupt.h> #include <linux/i2c/pca953x.h> #include <linux/gpio.h> +#include <linux/mfd/88pm860x.h> +#include <linux/platform_data/mv_usb.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -25,6 +27,7 @@ #include <mach/mfp-pxa910.h> #include <mach/pxa910.h> #include <mach/irqs.h> +#include <mach/regs-usb.h> #include "common.h" @@ -135,8 +138,18 @@ static struct pca953x_platform_data max7312_data[] = { }, }; +static struct pm860x_platform_data ttc_dkb_pm8607_info = { + .irq_base = IRQ_BOARD_START, +}; + static struct i2c_board_info ttc_dkb_i2c_info[] = { { + .type = "88PM860x", + .addr = 0x34, + .platform_data = &ttc_dkb_pm8607_info, + .irq = IRQ_PXA910_PMIC_INT, + }, + { .type = "max7312", .addr = 0x23, .irq = MMP_GPIO_TO_IRQ(80), @@ -144,6 +157,26 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = { }, }; +#ifdef CONFIG_USB_SUPPORT +#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O) + +static char *pxa910_usb_clock_name[] = { + [0] = "U2OCLK", +}; + +static struct mv_usb_platform_data ttc_usb_pdata = { + .clknum = 1, + .clkname = pxa910_usb_clock_name, + .vbus = NULL, + .mode = MV_USB_MODE_OTG, + .otg_force_a_bus_req = 1, + .phy_init = pxa_usb_phy_init, + .phy_deinit = pxa_usb_phy_deinit, + .set_vbus = NULL, +}; +#endif +#endif + static void __init ttc_dkb_init(void) { mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config)); @@ -154,6 +187,21 @@ static void __init ttc_dkb_init(void) /* off-chip devices */ pxa910_add_twsi(0, NULL, ARRAY_AND_SIZE(ttc_dkb_i2c_info)); platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices)); + +#ifdef CONFIG_USB_MV_UDC + pxa168_device_u2o.dev.platform_data = &ttc_usb_pdata; + platform_device_register(&pxa168_device_u2o); +#endif + +#ifdef CONFIG_USB_EHCI_MV_U2O + pxa168_device_u2oehci.dev.platform_data = &ttc_usb_pdata; + platform_device_register(&pxa168_device_u2oehci); +#endif + +#ifdef CONFIG_USB_MV_OTG + pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata; + platform_device_register(&pxa168_device_u2ootg); +#endif } MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform") |