diff options
Diffstat (limited to 'arch/arm/mach-imx')
60 files changed, 3283 insertions, 443 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 0519dd7f034..5f7f9c2a34a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -1,10 +1,32 @@ config IMX_HAVE_DMA_V1 bool + +config HAVE_IMX_GPC + bool + +config HAVE_IMX_MMDC + bool + +config HAVE_IMX_SRC + bool + # # ARCH_MX31 and ARCH_MX35 are left for compatibility # Some usages assume that having one of them implies not having (e.g.) ARCH_MX2. # To easily distinguish good and reviewed from unreviewed usages new (and IMHO # more sensible) names are used: SOC_IMX31 and SOC_IMX35 +config ARCH_MX1 + bool + +config MACH_MX21 + bool + +config ARCH_MX25 + bool + +config MACH_MX27 + bool + config ARCH_MX31 bool @@ -13,6 +35,7 @@ config ARCH_MX35 config SOC_IMX1 bool + select ARCH_MX1 select CPU_ARM920T select IMX_HAVE_DMA_V1 select IMX_HAVE_IOMUX_V1 @@ -20,6 +43,7 @@ config SOC_IMX1 config SOC_IMX21 bool + select MACH_MX21 select CPU_ARM926T select ARCH_MXC_AUDMUX_V1 select IMX_HAVE_DMA_V1 @@ -28,6 +52,7 @@ config SOC_IMX21 config SOC_IMX25 bool + select ARCH_MX25 select CPU_ARM926T select ARCH_MXC_AUDMUX_V2 select ARCH_MXC_IOMUX_V3 @@ -35,6 +60,7 @@ config SOC_IMX25 config SOC_IMX27 bool + select MACH_MX27 select CPU_ARM926T select ARCH_MXC_AUDMUX_V1 select IMX_HAVE_DMA_V1 @@ -48,6 +74,7 @@ config SOC_IMX31 select ARCH_MXC_AUDMUX_V2 select ARCH_MX31 select MXC_AVIC + select SMP_ON_UP if SMP config SOC_IMX35 bool @@ -57,9 +84,10 @@ config SOC_IMX35 select HAVE_EPIT select ARCH_MX35 select MXC_AVIC + select SMP_ON_UP if SMP -if ARCH_MX1 +if ARCH_IMX_V4_V5 comment "MX1 platforms:" config MACH_MXLADS @@ -87,30 +115,6 @@ config MACH_APF9328 help Say Yes here if you are using the Armadeus APF9328 development board -endif - -if ARCH_MX2 - -choice - prompt "CPUs:" - default MACH_MX21 - -config MACH_MX21 - bool "i.MX21 support" - help - This enables support for Freescale's MX2 based i.MX21 processor. - -config MACH_MX27 - bool "i.MX27 support" - help - This enables support for Freescale's MX2 based i.MX27 processor. - -endchoice - -endif - -if MACH_MX21 - comment "MX21 platforms:" config MACH_MX21ADS @@ -124,15 +128,12 @@ config MACH_MX21ADS Include support for MX21ADS platform. This includes specific configurations for the board and its peripherals. -endif - -if ARCH_MX25 - comment "MX25 platforms:" config MACH_MX25_3DS bool "Support MX25PDK (3DS) Platform" select SOC_IMX25 + select IMX_HAVE_PLATFORM_FLEXCAN select IMX_HAVE_PLATFORM_FSL_USB2_UDC select IMX_HAVE_PLATFORM_IMX2_WDT select IMX_HAVE_PLATFORM_IMXDI_RTC @@ -174,10 +175,6 @@ config MACH_EUKREA_MBIMXSD25_BASEBOARD endchoice -endif - -if MACH_MX27 - comment "MX27 platforms:" config MACH_MX27ADS @@ -356,7 +353,7 @@ config MACH_IMX27IPCAM endif -if ARCH_MX3 +if ARCH_IMX_V6_V7 comment "MX31 platforms:" @@ -449,6 +446,7 @@ config MACH_MX31_3DS select IMX_HAVE_PLATFORM_IMX_UART select IMX_HAVE_PLATFORM_IPU_CORE select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC select IMX_HAVE_PLATFORM_MXC_NAND select IMX_HAVE_PLATFORM_SPI_IMX select MXC_ULPI if USB_ULPI @@ -485,6 +483,7 @@ config MACH_QONG bool "Support Dave/DENX QongEVB-LITE platform" select SOC_IMX31 select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX2_WDT help Include support for Dave/DENX QongEVB-LITE platform. This includes specific configurations for the board and its peripherals. @@ -605,4 +604,20 @@ config MACH_VPR200 Include support for VPR200 platform. This includes specific configurations for the board and its peripherals. +comment "i.MX6 family:" + +config SOC_IMX6Q + bool "i.MX6 Quad support" + select ARM_GIC + select CACHE_L2X0 + select CPU_V7 + select HAVE_ARM_SCU + select HAVE_IMX_GPC + select HAVE_IMX_MMDC + select HAVE_IMX_SRC + select USE_OF + + help + This enables support for Freescale i.MX6 Quad processor. + endif diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index e9eb36dad88..aba73214c2a 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,16 +1,15 @@ obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o -obj-$(CONFIG_ARCH_MX1) += clock-imx1.o mm-imx1.o -obj-$(CONFIG_MACH_MX21) += clock-imx21.o mm-imx21.o +obj-$(CONFIG_SOC_IMX1) += clock-imx1.o mm-imx1.o +obj-$(CONFIG_SOC_IMX21) += clock-imx21.o mm-imx21.o -obj-$(CONFIG_ARCH_MX25) += clock-imx25.o mm-imx25.o ehci-imx25.o +obj-$(CONFIG_SOC_IMX25) += clock-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o -obj-$(CONFIG_MACH_MX27) += cpu-imx27.o pm-imx27.o -obj-$(CONFIG_MACH_MX27) += clock-imx27.o mm-imx27.o ehci-imx27.o +obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o +obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o -obj-$(CONFIG_SOC_IMX31) += mm-imx31.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o -obj-$(CONFIG_SOC_IMX35) += mm-imx35.o cpu-imx35.o clock-imx35.o ehci-imx35.o -obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o +obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o +obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o # Support for CMOS sensor interface obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o @@ -61,3 +60,14 @@ obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o + +obj-$(CONFIG_DEBUG_LL) += lluart.o +obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o +obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o +obj-$(CONFIG_HAVE_IMX_SRC) += src.o +obj-$(CONFIG_CPU_V7) += head-v7.o +AFLAGS_head-v7.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o +obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o pm-imx6q.o diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot index ebee18b3884..22d85889f62 100644 --- a/arch/arm/mach-imx/Makefile.boot +++ b/arch/arm/mach-imx/Makefile.boot @@ -1,19 +1,23 @@ -zreladdr-$(CONFIG_ARCH_MX1) := 0x08008000 +zreladdr-$(CONFIG_ARCH_MX1) += 0x08008000 params_phys-$(CONFIG_ARCH_MX1) := 0x08000100 initrd_phys-$(CONFIG_ARCH_MX1) := 0x08800000 -zreladdr-$(CONFIG_MACH_MX21) := 0xC0008000 +zreladdr-$(CONFIG_MACH_MX21) += 0xC0008000 params_phys-$(CONFIG_MACH_MX21) := 0xC0000100 initrd_phys-$(CONFIG_MACH_MX21) := 0xC0800000 -zreladdr-$(CONFIG_ARCH_MX25) := 0x80008000 +zreladdr-$(CONFIG_ARCH_MX25) += 0x80008000 params_phys-$(CONFIG_ARCH_MX25) := 0x80000100 initrd_phys-$(CONFIG_ARCH_MX25) := 0x80800000 -zreladdr-$(CONFIG_MACH_MX27) := 0xA0008000 +zreladdr-$(CONFIG_MACH_MX27) += 0xA0008000 params_phys-$(CONFIG_MACH_MX27) := 0xA0000100 initrd_phys-$(CONFIG_MACH_MX27) := 0xA0800000 -zreladdr-$(CONFIG_ARCH_MX3) := 0x80008000 +zreladdr-$(CONFIG_ARCH_MX3) += 0x80008000 params_phys-$(CONFIG_ARCH_MX3) := 0x80000100 initrd_phys-$(CONFIG_ARCH_MX3) := 0x80800000 + +zreladdr-$(CONFIG_SOC_IMX6Q) += 0x10008000 +params_phys-$(CONFIG_SOC_IMX6Q) := 0x10000100 +initrd_phys-$(CONFIG_SOC_IMX6Q) := 0x10800000 diff --git a/arch/arm/mach-imx/cache-l2x0.c b/arch/arm/mach-imx/cache-l2x0.c deleted file mode 100644 index 69d1322add3..00000000000 --- a/arch/arm/mach-imx/cache-l2x0.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2009-2010 Pengutronix - * Sascha Hauer <s.hauer@pengutronix.de> - * Juergen Beisert <j.beisert@pengutronix.de> - * - * 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/err.h> -#include <linux/kernel.h> - -#include <asm/hardware/cache-l2x0.h> - -#include <mach/hardware.h> - -static int mxc_init_l2x0(void) -{ - void __iomem *l2x0_base; - void __iomem *clkctl_base; - - if (!cpu_is_mx31() && !cpu_is_mx35()) - return 0; - -/* - * First of all, we must repair broken chip settings. There are some - * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These - * misconfigured CPUs will run amok immediately when the L2 cache gets enabled. - * Workaraound is to setup the correct register setting prior enabling the - * L2 cache. This should not hurt already working CPUs, as they are using the - * same value. - */ -#define L2_MEM_VAL 0x10 - - clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096); - if (clkctl_base != NULL) { - writel(0x00000515, clkctl_base + L2_MEM_VAL); - iounmap(clkctl_base); - } else { - pr_err("L2 cache: Cannot fix timing. Trying to continue without\n"); - } - - l2x0_base = ioremap(MX3x_L2CC_BASE_ADDR, 4096); - if (IS_ERR(l2x0_base)) { - printk(KERN_ERR "remapping L2 cache area failed with %ld\n", - PTR_ERR(l2x0_base)); - return 0; - } - - l2x0_init(l2x0_base, 0x00030024, 0x00000000); - - return 0; -} -arch_initcall(mxc_init_l2x0); diff --git a/arch/arm/mach-imx/clock-imx25.c b/arch/arm/mach-imx/clock-imx25.c index e63e23504fe..b0fec74c8c9 100644 --- a/arch/arm/mach-imx/clock-imx25.c +++ b/arch/arm/mach-imx/clock-imx25.c @@ -263,6 +263,7 @@ DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL); DEFINE_CLOCK(csi_clk, 0, CCM_CGCR1, 4, get_rate_csi, NULL, &csi_per_clk); DEFINE_CLOCK(can1_clk, 0, CCM_CGCR1, 2, get_rate_ipg, NULL, NULL); DEFINE_CLOCK(can2_clk, 1, CCM_CGCR1, 3, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(iim_clk, 0, CCM_CGCR1, 26, NULL, NULL, NULL); #define _REGISTER_CLOCK(d, n, c) \ { \ @@ -310,6 +311,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) /* i.mx25 has the i.mx35 type sdma */ _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) + _REGISTER_CLOCK(NULL, "iim", iim_clk) }; int __init mx25_clocks_init(void) @@ -334,6 +336,10 @@ int __init mx25_clocks_init(void) /* Clock source for gpt is ahb_div */ __raw_writel(__raw_readl(CRM_BASE+0x64) & ~(1 << 5), CRM_BASE + 0x64); + clk_enable(&iim_clk); + imx_print_silicon_rev("i.MX25", mx25_revision()); + clk_disable(&iim_clk); + mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); return 0; diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c index 6912b821b37..88fe00a146e 100644 --- a/arch/arm/mach-imx/clock-imx27.c +++ b/arch/arm/mach-imx/clock-imx27.c @@ -583,7 +583,7 @@ DEFINE_CLOCK(emi_clk, 0, PCCR1, 19, NULL, NULL, &ahb_clk); DEFINE_CLOCK(dma_clk1, 0, PCCR1, 20, NULL, NULL, &ahb_clk); DEFINE_CLOCK(csi_clk1, 0, PCCR1, 21, NULL, NULL, &ahb_clk); DEFINE_CLOCK(brom_clk, 0, PCCR1, 22, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(ata_clk, 0, PCCR1, 23, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(pata_clk, 0, PCCR1, 23, NULL, NULL, &ahb_clk); DEFINE_CLOCK(wdog_clk, 0, PCCR1, 24, NULL, NULL, &ipg_clk); DEFINE_CLOCK(usb_clk, 0, PCCR1, 25, get_rate_usb, &usb_clk1, &spll_clk); DEFINE_CLOCK(uart6_clk1, 0, PCCR1, 26, NULL, NULL, &ipg_clk); @@ -666,7 +666,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) _REGISTER_CLOCK(NULL, "emi", emi_clk) _REGISTER_CLOCK(NULL, "sahara2", sahara2_clk) - _REGISTER_CLOCK(NULL, "ata", ata_clk) + _REGISTER_CLOCK("pata_imx", NULL, pata_clk) _REGISTER_CLOCK(NULL, "mstick", mstick_clk) _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) _REGISTER_CLOCK(NULL, "gpio", gpio_clk) @@ -751,6 +751,8 @@ int __init mx27_clocks_init(unsigned long fref) clk_enable(&gpio_clk); clk_enable(&emi_clk); clk_enable(&iim_clk); + imx_print_silicon_rev("i.MX27", mx27_revision()); + clk_disable(&iim_clk); #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) clk_enable(&uart1_clk); diff --git a/arch/arm/mach-imx/clock-imx31.c b/arch/arm/mach-imx/clock-imx31.c index d973770b1f9..988a28178d4 100644 --- a/arch/arm/mach-imx/clock-imx31.c +++ b/arch/arm/mach-imx/clock-imx31.c @@ -476,7 +476,7 @@ DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CGR0, 4, NULL, NULL, &perclk_clk); DEFINE_CLOCK(epit1_clk, 0, MXC_CCM_CGR0, 6, NULL, NULL, &perclk_clk); DEFINE_CLOCK(epit2_clk, 1, MXC_CCM_CGR0, 8, NULL, NULL, &perclk_clk); DEFINE_CLOCK(iim_clk, 0, MXC_CCM_CGR0, 10, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ata_clk, 0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(pata_clk, 0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk); DEFINE_CLOCK(sdma_clk1, 0, MXC_CCM_CGR0, 14, NULL, NULL, &ahb_clk); DEFINE_CLOCK(cspi3_clk, 2, MXC_CCM_CGR0, 16, NULL, NULL, &ipg_clk); DEFINE_CLOCK(rng_clk, 0, MXC_CCM_CGR0, 18, NULL, NULL, &ipg_clk); @@ -562,7 +562,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) _REGISTER_CLOCK(NULL, "firi", firi_clk) - _REGISTER_CLOCK(NULL, "ata", ata_clk) + _REGISTER_CLOCK("pata_imx", NULL, pata_clk) _REGISTER_CLOCK(NULL, "rtic", rtic_clk) _REGISTER_CLOCK(NULL, "rng", rng_clk) _REGISTER_CLOCK("imx31-sdma", NULL, sdma_clk1) @@ -611,11 +611,11 @@ int __init mx31_clocks_init(unsigned long fref) clk_enable(&gpt_clk); clk_enable(&emi_clk); clk_enable(&iim_clk); + mx31_revision(); + clk_disable(&iim_clk); clk_enable(&serial_pll_clk); - mx31_read_cpu_rev(); - if (mx31_revision() >= IMX_CHIP_REVISION_2_0) { reg = __raw_readl(MXC_CCM_PMCR1); /* No PLL restart on DVFS switch; enable auto EMI handshake */ diff --git a/arch/arm/mach-imx/clock-imx35.c b/arch/arm/mach-imx/clock-imx35.c index 88b62a071ae..8116f119517 100644 --- a/arch/arm/mach-imx/clock-imx35.c +++ b/arch/arm/mach-imx/clock-imx35.c @@ -354,7 +354,7 @@ static void clk_cgr_disable(struct clk *clk) } DEFINE_CLOCK(asrc_clk, 0, CCM_CGR0, 0, NULL, NULL); -DEFINE_CLOCK(ata_clk, 0, CCM_CGR0, 2, get_rate_ipg, NULL); +DEFINE_CLOCK(pata_clk, 0, CCM_CGR0, 2, get_rate_ipg, NULL); /* DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0, 4, NULL, NULL); */ DEFINE_CLOCK(can1_clk, 0, CCM_CGR0, 6, get_rate_ipg, NULL); DEFINE_CLOCK(can2_clk, 1, CCM_CGR0, 8, get_rate_ipg, NULL); @@ -447,7 +447,7 @@ static struct clk nfc_clk = { static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "asrc", asrc_clk) - _REGISTER_CLOCK(NULL, "ata", ata_clk) + _REGISTER_CLOCK("pata_imx", NULL, pata_clk) _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk) @@ -537,7 +537,8 @@ int __init mx35_clocks_init() __raw_writel(cgr3, CCM_BASE + CCM_CGR3); clk_enable(&iim_clk); - mx35_read_cpu_rev(); + imx_print_silicon_rev("i.MX35", mx35_revision()); + clk_disable(&iim_clk); #ifdef CONFIG_MXC_USE_EPIT epit_timer_init(&epit1_clk, diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c new file mode 100644 index 00000000000..e0b926dfece --- /dev/null +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -0,0 +1,2012 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <asm/div64.h> +#include <asm/mach/map.h> +#include <mach/clock.h> +#include <mach/common.h> +#include <mach/hardware.h> + +#define PLL_BASE IMX_IO_ADDRESS(MX6Q_ANATOP_BASE_ADDR) +#define PLL1_SYS (PLL_BASE + 0x000) +#define PLL2_BUS (PLL_BASE + 0x030) +#define PLL3_USB_OTG (PLL_BASE + 0x010) +#define PLL4_AUDIO (PLL_BASE + 0x070) +#define PLL5_VIDEO (PLL_BASE + 0x0a0) +#define PLL6_MLB (PLL_BASE + 0x0d0) +#define PLL7_USB_HOST (PLL_BASE + 0x020) +#define PLL8_ENET (PLL_BASE + 0x0e0) +#define PFD_480 (PLL_BASE + 0x0f0) +#define PFD_528 (PLL_BASE + 0x100) +#define PLL_NUM_OFFSET 0x010 +#define PLL_DENOM_OFFSET 0x020 + +#define PFD0 7 +#define PFD1 15 +#define PFD2 23 +#define PFD3 31 +#define PFD_FRAC_MASK 0x3f + +#define BM_PLL_BYPASS (0x1 << 16) +#define BM_PLL_ENABLE (0x1 << 13) +#define BM_PLL_POWER_DOWN (0x1 << 12) +#define BM_PLL_LOCK (0x1 << 31) +#define BP_PLL_SYS_DIV_SELECT 0 +#define BM_PLL_SYS_DIV_SELECT (0x7f << 0) +#define BP_PLL_BUS_DIV_SELECT 0 +#define BM_PLL_BUS_DIV_SELECT (0x1 << 0) +#define BP_PLL_USB_DIV_SELECT 0 +#define BM_PLL_USB_DIV_SELECT (0x3 << 0) +#define BP_PLL_AV_DIV_SELECT 0 +#define BM_PLL_AV_DIV_SELECT (0x7f << 0) +#define BP_PLL_ENET_DIV_SELECT 0 +#define BM_PLL_ENET_DIV_SELECT (0x3 << 0) +#define BM_PLL_ENET_EN_PCIE (0x1 << 19) +#define BM_PLL_ENET_EN_SATA (0x1 << 20) + +#define CCM_BASE IMX_IO_ADDRESS(MX6Q_CCM_BASE_ADDR) +#define CCR (CCM_BASE + 0x00) +#define CCDR (CCM_BASE + 0x04) +#define CSR (CCM_BASE + 0x08) +#define CCSR (CCM_BASE + 0x0c) +#define CACRR (CCM_BASE + 0x10) +#define CBCDR (CCM_BASE + 0x14) +#define CBCMR (CCM_BASE + 0x18) +#define CSCMR1 (CCM_BASE + 0x1c) +#define CSCMR2 (CCM_BASE + 0x20) +#define CSCDR1 (CCM_BASE + 0x24) +#define CS1CDR (CCM_BASE + 0x28) +#define CS2CDR (CCM_BASE + 0x2c) +#define CDCDR (CCM_BASE + 0x30) +#define CHSCCDR (CCM_BASE + 0x34) +#define CSCDR2 (CCM_BASE + 0x38) +#define CSCDR3 (CCM_BASE + 0x3c) +#define CSCDR4 (CCM_BASE + 0x40) +#define CWDR (CCM_BASE + 0x44) +#define CDHIPR (CCM_BASE + 0x48) +#define CDCR (CCM_BASE + 0x4c) +#define CTOR (CCM_BASE + 0x50) +#define CLPCR (CCM_BASE + 0x54) +#define CISR (CCM_BASE + 0x58) +#define CIMR (CCM_BASE + 0x5c) +#define CCOSR (CCM_BASE + 0x60) +#define CGPR (CCM_BASE + 0x64) +#define CCGR0 (CCM_BASE + 0x68) +#define CCGR1 (CCM_BASE + 0x6c) +#define CCGR2 (CCM_BASE + 0x70) +#define CCGR3 (CCM_BASE + 0x74) +#define CCGR4 (CCM_BASE + 0x78) +#define CCGR5 (CCM_BASE + 0x7c) +#define CCGR6 (CCM_BASE + 0x80) +#define CCGR7 (CCM_BASE + 0x84) +#define CMEOR (CCM_BASE + 0x88) + +#define CG0 0 +#define CG1 2 +#define CG2 4 +#define CG3 6 +#define CG4 8 +#define CG5 10 +#define CG6 12 +#define CG7 14 +#define CG8 16 +#define CG9 18 +#define CG10 20 +#define CG11 22 +#define CG12 24 +#define CG13 26 +#define CG14 28 +#define CG15 30 + +#define BM_CCSR_PLL1_SW_SEL (0x1 << 2) +#define BM_CCSR_STEP_SEL (0x1 << 8) + +#define BP_CACRR_ARM_PODF 0 +#define BM_CACRR_ARM_PODF (0x7 << 0) + +#define BP_CBCDR_PERIPH2_CLK2_PODF 0 +#define BM_CBCDR_PERIPH2_CLK2_PODF (0x7 << 0) +#define BP_CBCDR_MMDC_CH1_AXI_PODF 3 +#define BM_CBCDR_MMDC_CH1_AXI_PODF (0x7 << 3) +#define BP_CBCDR_AXI_SEL 6 +#define BM_CBCDR_AXI_SEL (0x3 << 6) +#define BP_CBCDR_IPG_PODF 8 +#define BM_CBCDR_IPG_PODF (0x3 << 8) +#define BP_CBCDR_AHB_PODF 10 +#define BM_CBCDR_AHB_PODF (0x7 << 10) +#define BP_CBCDR_AXI_PODF 16 +#define BM_CBCDR_AXI_PODF (0x7 << 16) +#define BP_CBCDR_MMDC_CH0_AXI_PODF 19 +#define BM_CBCDR_MMDC_CH0_AXI_PODF (0x7 << 19) +#define BP_CBCDR_PERIPH_CLK_SEL 25 +#define BM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) +#define BP_CBCDR_PERIPH2_CLK_SEL 26 +#define BM_CBCDR_PERIPH2_CLK_SEL (0x1 << 26) +#define BP_CBCDR_PERIPH_CLK2_PODF 27 +#define BM_CBCDR_PERIPH_CLK2_PODF (0x7 << 27) + +#define BP_CBCMR_GPU2D_AXI_SEL 0 +#define BM_CBCMR_GPU2D_AXI_SEL (0x1 << 0) +#define BP_CBCMR_GPU3D_AXI_SEL 1 +#define BM_CBCMR_GPU3D_AXI_SEL (0x1 << 1) +#define BP_CBCMR_GPU3D_CORE_SEL 4 +#define BM_CBCMR_GPU3D_CORE_SEL (0x3 << 4) +#define BP_CBCMR_GPU3D_SHADER_SEL 8 +#define BM_CBCMR_GPU3D_SHADER_SEL (0x3 << 8) +#define BP_CBCMR_PCIE_AXI_SEL 10 +#define BM_CBCMR_PCIE_AXI_SEL (0x1 << 10) +#define BP_CBCMR_VDO_AXI_SEL 11 +#define BM_CBCMR_VDO_AXI_SEL (0x1 << 11) +#define BP_CBCMR_PERIPH_CLK2_SEL 12 +#define BM_CBCMR_PERIPH_CLK2_SEL (0x3 << 12) +#define BP_CBCMR_VPU_AXI_SEL 14 +#define BM_CBCMR_VPU_AXI_SEL (0x3 << 14) +#define BP_CBCMR_GPU2D_CORE_SEL 16 +#define BM_CBCMR_GPU2D_CORE_SEL (0x3 << 16) +#define BP_CBCMR_PRE_PERIPH_CLK_SEL 18 +#define BM_CBCMR_PRE_PERIPH_CLK_SEL (0x3 << 18) +#define BP_CBCMR_PERIPH2_CLK2_SEL 20 +#define BM_CBCMR_PERIPH2_CLK2_SEL (0x1 << 20) +#define BP_CBCMR_PRE_PERIPH2_CLK_SEL 21 +#define BM_CBCMR_PRE_PERIPH2_CLK_SEL (0x3 << 21) +#define BP_CBCMR_GPU2D_CORE_PODF 23 +#define BM_CBCMR_GPU2D_CORE_PODF (0x7 << 23) +#define BP_CBCMR_GPU3D_CORE_PODF 26 +#define BM_CBCMR_GPU3D_CORE_PODF (0x7 << 26) +#define BP_CBCMR_GPU3D_SHADER_PODF 29 +#define BM_CBCMR_GPU3D_SHADER_PODF (0x7 << 29) + +#define BP_CSCMR1_PERCLK_PODF 0 +#define BM_CSCMR1_PERCLK_PODF (0x3f << 0) +#define BP_CSCMR1_SSI1_SEL 10 +#define BM_CSCMR1_SSI1_SEL (0x3 << 10) +#define BP_CSCMR1_SSI2_SEL 12 +#define BM_CSCMR1_SSI2_SEL (0x3 << 12) +#define BP_CSCMR1_SSI3_SEL 14 +#define BM_CSCMR1_SSI3_SEL (0x3 << 14) +#define BP_CSCMR1_USDHC1_SEL 16 +#define BM_CSCMR1_USDHC1_SEL (0x1 << 16) +#define BP_CSCMR1_USDHC2_SEL 17 +#define BM_CSCMR1_USDHC2_SEL (0x1 << 17) +#define BP_CSCMR1_USDHC3_SEL 18 +#define BM_CSCMR1_USDHC3_SEL (0x1 << 18) +#define BP_CSCMR1_USDHC4_SEL 19 +#define BM_CSCMR1_USDHC4_SEL (0x1 << 19) +#define BP_CSCMR1_EMI_PODF 20 +#define BM_CSCMR1_EMI_PODF (0x7 << 20) +#define BP_CSCMR1_EMI_SLOW_PODF 23 +#define BM_CSCMR1_EMI_SLOW_PODF (0x7 << 23) +#define BP_CSCMR1_EMI_SEL 27 +#define BM_CSCMR1_EMI_SEL (0x3 << 27) +#define BP_CSCMR1_EMI_SLOW_SEL 29 +#define BM_CSCMR1_EMI_SLOW_SEL (0x3 << 29) + +#define BP_CSCMR2_CAN_PODF 2 +#define BM_CSCMR2_CAN_PODF (0x3f << 2) +#define BM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) +#define BM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) +#define BP_CSCMR2_ESAI_SEL 19 +#define BM_CSCMR2_ESAI_SEL (0x3 << 19) + +#define BP_CSCDR1_UART_PODF 0 +#define BM_CSCDR1_UART_PODF (0x3f << 0) +#define BP_CSCDR1_USDHC1_PODF 11 +#define BM_CSCDR1_USDHC1_PODF (0x7 << 11) +#define BP_CSCDR1_USDHC2_PODF 16 +#define BM_CSCDR1_USDHC2_PODF (0x7 << 16) +#define BP_CSCDR1_USDHC3_PODF 19 +#define BM_CSCDR1_USDHC3_PODF (0x7 << 19) +#define BP_CSCDR1_USDHC4_PODF 22 +#define BM_CSCDR1_USDHC4_PODF (0x7 << 22) +#define BP_CSCDR1_VPU_AXI_PODF 25 +#define BM_CSCDR1_VPU_AXI_PODF (0x7 << 25) + +#define BP_CS1CDR_SSI1_PODF 0 +#define BM_CS1CDR_SSI1_PODF (0x3f << 0) +#define BP_CS1CDR_SSI1_PRED 6 +#define BM_CS1CDR_SSI1_PRED (0x7 << 6) +#define BP_CS1CDR_ESAI_PRED 9 +#define BM_CS1CDR_ESAI_PRED (0x7 << 9) +#define BP_CS1CDR_SSI3_PODF 16 +#define BM_CS1CDR_SSI3_PODF (0x3f << 16) +#define BP_CS1CDR_SSI3_PRED 22 +#define BM_CS1CDR_SSI3_PRED (0x7 << 22) +#define BP_CS1CDR_ESAI_PODF 25 +#define BM_CS1CDR_ESAI_PODF (0x7 << 25) + +#define BP_CS2CDR_SSI2_PODF 0 +#define BM_CS2CDR_SSI2_PODF (0x3f << 0) +#define BP_CS2CDR_SSI2_PRED 6 +#define BM_CS2CDR_SSI2_PRED (0x7 << 6) +#define BP_CS2CDR_LDB_DI0_SEL 9 +#define BM_CS2CDR_LDB_DI0_SEL (0x7 << 9) +#define BP_CS2CDR_LDB_DI1_SEL 12 +#define BM_CS2CDR_LDB_DI1_SEL (0x7 << 12) +#define BP_CS2CDR_ENFC_SEL 16 +#define BM_CS2CDR_ENFC_SEL (0x3 << 16) +#define BP_CS2CDR_ENFC_PRED 18 +#define BM_CS2CDR_ENFC_PRED (0x7 << 18) +#define BP_CS2CDR_ENFC_PODF 21 +#define BM_CS2CDR_ENFC_PODF (0x3f << 21) + +#define BP_CDCDR_ASRC_SERIAL_SEL 7 +#define BM_CDCDR_ASRC_SERIAL_SEL (0x3 << 7) +#define BP_CDCDR_ASRC_SERIAL_PODF 9 +#define BM_CDCDR_ASRC_SERIAL_PODF (0x7 << 9) +#define BP_CDCDR_ASRC_SERIAL_PRED 12 +#define BM_CDCDR_ASRC_SERIAL_PRED (0x7 << 12) +#define BP_CDCDR_SPDIF_SEL 20 +#define BM_CDCDR_SPDIF_SEL (0x3 << 20) +#define BP_CDCDR_SPDIF_PODF 22 +#define BM_CDCDR_SPDIF_PODF (0x7 << 22) +#define BP_CDCDR_SPDIF_PRED 25 +#define BM_CDCDR_SPDIF_PRED (0x7 << 25) +#define BP_CDCDR_HSI_TX_PODF 29 +#define BM_CDCDR_HSI_TX_PODF (0x7 << 29) +#define BP_CDCDR_HSI_TX_SEL 28 +#define BM_CDCDR_HSI_TX_SEL (0x1 << 28) + +#define BP_CHSCCDR_IPU1_DI0_SEL 0 +#define BM_CHSCCDR_IPU1_DI0_SEL (0x7 << 0) +#define BP_CHSCCDR_IPU1_DI0_PRE_PODF 3 +#define BM_CHSCCDR_IPU1_DI0_PRE_PODF (0x7 << 3) +#define BP_CHSCCDR_IPU1_DI0_PRE_SEL 6 +#define BM_CHSCCDR_IPU1_DI0_PRE_SEL (0x7 << 6) +#define BP_CHSCCDR_IPU1_DI1_SEL 9 +#define BM_CHSCCDR_IPU1_DI1_SEL (0x7 << 9) +#define BP_CHSCCDR_IPU1_DI1_PRE_PODF 12 +#define BM_CHSCCDR_IPU1_DI1_PRE_PODF (0x7 << 12) +#define BP_CHSCCDR_IPU1_DI1_PRE_SEL 15 +#define BM_CHSCCDR_IPU1_DI1_PRE_SEL (0x7 << 15) + +#define BP_CSCDR2_IPU2_DI0_SEL 0 +#define BM_CSCDR2_IPU2_DI0_SEL (0x7) +#define BP_CSCDR2_IPU2_DI0_PRE_PODF 3 +#define BM_CSCDR2_IPU2_DI0_PRE_PODF (0x7 << 3) +#define BP_CSCDR2_IPU2_DI0_PRE_SEL 6 +#define BM_CSCDR2_IPU2_DI0_PRE_SEL (0x7 << 6) +#define BP_CSCDR2_IPU2_DI1_SEL 9 +#define BM_CSCDR2_IPU2_DI1_SEL (0x7 << 9) +#define BP_CSCDR2_IPU2_DI1_PRE_PODF 12 +#define BM_CSCDR2_IPU2_DI1_PRE_PODF (0x7 << 12) +#define BP_CSCDR2_IPU2_DI1_PRE_SEL 15 +#define BM_CSCDR2_IPU2_DI1_PRE_SEL (0x7 << 15) +#define BP_CSCDR2_ECSPI_CLK_PODF 19 +#define BM_CSCDR2_ECSPI_CLK_PODF (0x3f << 19) + +#define BP_CSCDR3_IPU1_HSP_SEL 9 +#define BM_CSCDR3_IPU1_HSP_SEL (0x3 << 9) +#define BP_CSCDR3_IPU1_HSP_PODF 11 +#define BM_CSCDR3_IPU1_HSP_PODF (0x7 << 11) +#define BP_CSCDR3_IPU2_HSP_SEL 14 +#define BM_CSCDR3_IPU2_HSP_SEL (0x3 << 14) +#define BP_CSCDR3_IPU2_HSP_PODF 16 +#define BM_CSCDR3_IPU2_HSP_PODF (0x7 << 16) + +#define BM_CDHIPR_AXI_PODF_BUSY (0x1 << 0) +#define BM_CDHIPR_AHB_PODF_BUSY (0x1 << 1) +#define BM_CDHIPR_MMDC_CH1_PODF_BUSY (0x1 << 2) +#define BM_CDHIPR_PERIPH2_SEL_BUSY (0x1 << 3) +#define BM_CDHIPR_MMDC_CH0_PODF_BUSY (0x1 << 4) +#define BM_CDHIPR_PERIPH_SEL_BUSY (0x1 << 5) +#define BM_CDHIPR_ARM_PODF_BUSY (0x1 << 16) + +#define BP_CLPCR_LPM 0 +#define BM_CLPCR_LPM (0x3 << 0) +#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) +#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +#define BM_CLPCR_SBYOS (0x1 << 6) +#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) +#define BM_CLPCR_VSTBY (0x1 << 8) +#define BP_CLPCR_STBY_COUNT 9 +#define BM_CLPCR_STBY_COUNT (0x3 << 9) +#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) +#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) +#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) +#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) +#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) +#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) +#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) +#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) +#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) +#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) +#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) + +#define FREQ_480M 480000000 +#define FREQ_528M 528000000 +#define FREQ_594M 594000000 +#define FREQ_650M 650000000 +#define FREQ_1300M 1300000000 + +static struct clk pll1_sys; +static struct clk pll2_bus; +static struct clk pll3_usb_otg; +static struct clk pll4_audio; +static struct clk pll5_video; +static struct clk pll6_mlb; +static struct clk pll7_usb_host; +static struct clk pll8_enet; +static struct clk apbh_dma_clk; +static struct clk arm_clk; +static struct clk ipg_clk; +static struct clk ahb_clk; +static struct clk axi_clk; +static struct clk mmdc_ch0_axi_clk; +static struct clk mmdc_ch1_axi_clk; +static struct clk periph_clk; +static struct clk periph_pre_clk; +static struct clk periph_clk2_clk; +static struct clk periph2_clk; +static struct clk periph2_pre_clk; +static struct clk periph2_clk2_clk; +static struct clk gpu2d_core_clk; +static struct clk gpu3d_core_clk; +static struct clk gpu3d_shader_clk; +static struct clk ipg_perclk; +static struct clk emi_clk; +static struct clk emi_slow_clk; +static struct clk can1_clk; +static struct clk uart_clk; +static struct clk usdhc1_clk; +static struct clk usdhc2_clk; +static struct clk usdhc3_clk; +static struct clk usdhc4_clk; +static struct clk vpu_clk; +static struct clk hsi_tx_clk; +static struct clk ipu1_di0_pre_clk; +static struct clk ipu1_di1_pre_clk; +static struct clk ipu2_di0_pre_clk; +static struct clk ipu2_di1_pre_clk; +static struct clk ipu1_clk; +static struct clk ipu2_clk; +static struct clk ssi1_clk; +static struct clk ssi3_clk; +static struct clk esai_clk; +static struct clk ssi2_clk; +static struct clk spdif_clk; +static struct clk asrc_serial_clk; +static struct clk gpu2d_axi_clk; +static struct clk gpu3d_axi_clk; +static struct clk pcie_clk; +static struct clk vdo_axi_clk; +static struct clk ldb_di0_clk; +static struct clk ldb_di1_clk; +static struct clk ipu1_di0_clk; +static struct clk ipu1_di1_clk; +static struct clk ipu2_di0_clk; +static struct clk ipu2_di1_clk; +static struct clk enfc_clk; +static struct clk dummy_clk = {}; + +static unsigned long external_high_reference; +static unsigned long external_low_reference; +static unsigned long oscillator_reference; + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static struct clk ckil_clk = { + .get_rate = get_low_reference_clock_rate, +}; + +static struct clk ckih_clk = { + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk osc_clk = { + .get_rate = get_oscillator_reference_clock_rate, +}; + +static inline void __iomem *pll_get_reg_addr(struct clk *pll) +{ + if (pll == &pll1_sys) + return PLL1_SYS; + else if (pll == &pll2_bus) + return PLL2_BUS; + else if (pll == &pll3_usb_otg) + return PLL3_USB_OTG; + else if (pll == &pll4_audio) + return PLL4_AUDIO; + else if (pll == &pll5_video) + return PLL5_VIDEO; + else if (pll == &pll6_mlb) + return PLL6_MLB; + else if (pll == &pll7_usb_host) + return PLL7_USB_HOST; + else if (pll == &pll8_enet) + return PLL8_ENET; + else + BUG(); + + return NULL; +} + +static int pll_enable(struct clk *clk) +{ + int timeout = 0x100000; + void __iomem *reg; + u32 val; + + reg = pll_get_reg_addr(clk); + val = readl_relaxed(reg); + val &= ~BM_PLL_BYPASS; + val &= ~BM_PLL_POWER_DOWN; + /* 480MHz PLLs have the opposite definition for power bit */ + if (clk == &pll3_usb_otg || clk == &pll7_usb_host) + val |= BM_PLL_POWER_DOWN; + writel_relaxed(val, reg); + + /* Wait for PLL to lock */ + while (!(readl_relaxed(reg) & BM_PLL_LOCK) && --timeout) + cpu_relax(); + + if (unlikely(!timeout)) + return -EBUSY; + + /* Enable the PLL output now */ + val = readl_relaxed(reg); + val |= BM_PLL_ENABLE; + writel_relaxed(val, reg); + + return 0; +} + +static void pll_disable(struct clk *clk) +{ + void __iomem *reg; + u32 val; + + reg = pll_get_reg_addr(clk); + val = readl_relaxed(reg); + val &= ~BM_PLL_ENABLE; + val |= BM_PLL_BYPASS; + val |= BM_PLL_POWER_DOWN; + if (clk == &pll3_usb_otg || clk == &pll7_usb_host) + val &= ~BM_PLL_POWER_DOWN; + writel_relaxed(val, reg); +} + +static unsigned long pll1_sys_get_rate(struct clk *clk) +{ + u32 div = (readl_relaxed(PLL1_SYS) & BM_PLL_SYS_DIV_SELECT) >> + BP_PLL_SYS_DIV_SELECT; + + return clk_get_rate(clk->parent) * div / 2; +} + +static int pll1_sys_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, div; + + if (rate < FREQ_650M || rate > FREQ_1300M) + return -EINVAL; + + div = rate * 2 / clk_get_rate(clk->parent); + val = readl_relaxed(PLL1_SYS); + val &= ~BM_PLL_SYS_DIV_SELECT; + val |= div << BP_PLL_SYS_DIV_SELECT; + writel_relaxed(val, PLL1_SYS); + + return 0; +} + +static unsigned long pll8_enet_get_rate(struct clk *clk) +{ + u32 div = (readl_relaxed(PLL8_ENET) & BM_PLL_ENET_DIV_SELECT) >> + BP_PLL_ENET_DIV_SELECT; + + switch (div) { + case 0: + return 25000000; + case 1: + return 50000000; + case 2: + return 100000000; + case 3: + return 125000000; + } + + return 0; +} + +static int pll8_enet_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, div; + + switch (rate) { + case 25000000: + div = 0; + break; + case 50000000: + div = 1; + break; + case 100000000: + div = 2; + break; + case 125000000: + div = 3; + break; + default: + return -EINVAL; + } + + val = readl_relaxed(PLL8_ENET); + val &= ~BM_PLL_ENET_DIV_SELECT; + val |= div << BP_PLL_ENET_DIV_SELECT; + writel_relaxed(val, PLL8_ENET); + + return 0; +} + +static unsigned long pll_av_get_rate(struct clk *clk) +{ + void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; + unsigned long parent_rate = clk_get_rate(clk->parent); + u32 mfn = readl_relaxed(reg + PLL_NUM_OFFSET); + u32 mfd = readl_relaxed(reg + PLL_DENOM_OFFSET); + u32 div = (readl_relaxed(reg) & BM_PLL_AV_DIV_SELECT) >> + BP_PLL_AV_DIV_SELECT; + + return (parent_rate * div) + ((parent_rate / mfd) * mfn); +} + +static int pll_av_set_rate(struct clk *clk, unsigned long rate) +{ + void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; + unsigned int parent_rate = clk_get_rate(clk->parent); + u32 val, div; + u32 mfn, mfd = 1000000; + s64 temp64; + + if (rate < FREQ_650M || rate > FREQ_1300M) + return -EINVAL; + + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + val = readl_relaxed(reg); + val &= ~BM_PLL_AV_DIV_SELECT; + val |= div << BP_PLL_AV_DIV_SELECT; + writel_relaxed(val, reg); + writel_relaxed(mfn, reg + PLL_NUM_OFFSET); + writel_relaxed(mfd, reg + PLL_DENOM_OFFSET); + + return 0; +} + +static void __iomem *pll_get_div_reg_bit(struct clk *clk, u32 *bp, u32 *bm) +{ + void __iomem *reg; + + if (clk == &pll2_bus) { + reg = PLL2_BUS; + *bp = BP_PLL_BUS_DIV_SELECT; + *bm = BM_PLL_BUS_DIV_SELECT; + } else if (clk == &pll3_usb_otg) { + reg = PLL3_USB_OTG; + *bp = BP_PLL_USB_DIV_SELECT; + *bm = BM_PLL_USB_DIV_SELECT; + } else if (clk == &pll7_usb_host) { + reg = PLL7_USB_HOST; + *bp = BP_PLL_USB_DIV_SELECT; + *bm = BM_PLL_USB_DIV_SELECT; + } else { + BUG(); + } + + return reg; +} + +static unsigned long pll_get_rate(struct clk *clk) +{ + void __iomem *reg; + u32 div, bp, bm; + + reg = pll_get_div_reg_bit(clk, &bp, &bm); + div = (readl_relaxed(reg) & bm) >> bp; + + return (div == 1) ? clk_get_rate(clk->parent) * 22 : + clk_get_rate(clk->parent) * 20; +} + +static int pll_set_rate(struct clk *clk, unsigned long rate) +{ + void __iomem *reg; + u32 val, div, bp, bm; + + if (rate == FREQ_528M) + div = 1; + else if (rate == FREQ_480M) + div = 0; + else + return -EINVAL; + + reg = pll_get_div_reg_bit(clk, &bp, &bm); + val = readl_relaxed(reg); + val &= ~bm; + val |= div << bp; + writel_relaxed(val, reg); + + return 0; +} + +#define pll2_bus_get_rate pll_get_rate +#define pll2_bus_set_rate pll_set_rate +#define pll3_usb_otg_get_rate pll_get_rate +#define pll3_usb_otg_set_rate pll_set_rate +#define pll7_usb_host_get_rate pll_get_rate +#define pll7_usb_host_set_rate pll_set_rate +#define pll4_audio_get_rate pll_av_get_rate +#define pll4_audio_set_rate pll_av_set_rate +#define pll5_video_get_rate pll_av_get_rate +#define pll5_video_set_rate pll_av_set_rate +#define pll6_mlb_get_rate NULL +#define pll6_mlb_set_rate NULL + +#define DEF_PLL(name) \ + static struct clk name = { \ + .enable = pll_enable, \ + .disable = pll_disable, \ + .get_rate = name##_get_rate, \ + .set_rate = name##_set_rate, \ + .parent = &osc_clk, \ + } + +DEF_PLL(pll1_sys); +DEF_PLL(pll2_bus); +DEF_PLL(pll3_usb_otg); +DEF_PLL(pll4_audio); +DEF_PLL(pll5_video); +DEF_PLL(pll6_mlb); +DEF_PLL(pll7_usb_host); +DEF_PLL(pll8_enet); + +static unsigned long pfd_get_rate(struct clk *clk) +{ + u64 tmp = (u64) clk_get_rate(clk->parent) * 18; + u32 frac, bp_frac; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + bp_frac = clk->enable_shift - 7; + frac = readl_relaxed(clk->enable_reg) >> bp_frac & PFD_FRAC_MASK; + do_div(tmp, frac); + + return tmp; +} + +static int pfd_set_rate(struct clk *clk, unsigned long rate) +{ + u32 val, frac, bp_frac; + u64 tmp = (u64) clk_get_rate(clk->parent) * 18; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + /* + * Round up the divider so that we don't set a rate + * higher than what is requested + */ + tmp += rate / 2; + do_div(tmp, rate); + frac = tmp; + frac = (frac < 12) ? 12 : frac; + frac = (frac > 35) ? 35 : frac; + + /* + * The frac field always starts from 7 bits lower + * position of enable bit + */ + bp_frac = clk->enable_shift - 7; + val = readl_relaxed(clk->enable_reg); + val &= ~(PFD_FRAC_MASK << bp_frac); + val |= frac << bp_frac; + writel_relaxed(val, clk->enable_reg); + + tmp = (u64) clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + + return 0; +} + +static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + + tmp = (u64) clk_get_rate(clk->parent) * 18; + tmp += rate / 2; + do_div(tmp, rate); + frac = tmp; + frac = (frac < 12) ? 12 : frac; + frac = (frac > 35) ? 35 : frac; + tmp = (u64) clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + + return tmp; +} + +static int pfd_enable(struct clk *clk) +{ + u32 val; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + val = readl_relaxed(clk->enable_reg); + val &= ~(1 << clk->enable_shift); + writel_relaxed(val, clk->enable_reg); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + + return 0; +} + +static void pfd_disable(struct clk *clk) +{ + u32 val; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + val = readl_relaxed(clk->enable_reg); + val |= 1 << clk->enable_shift; + writel_relaxed(val, clk->enable_reg); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); +} + +#define DEF_PFD(name, er, es, p) \ + static struct clk name = { \ + .enable_reg = er, \ + .enable_shift = es, \ + .enable = pfd_enable, \ + .disable = pfd_disable, \ + .get_rate = pfd_get_rate, \ + .set_rate = pfd_set_rate, \ + .round_rate = pfd_round_rate, \ + .parent = p, \ + } + +DEF_PFD(pll2_pfd_352m, PFD_528, PFD0, &pll2_bus); +DEF_PFD(pll2_pfd_594m, PFD_528, PFD1, &pll2_bus); +DEF_PFD(pll2_pfd_400m, PFD_528, PFD2, &pll2_bus); +DEF_PFD(pll3_pfd_720m, PFD_480, PFD0, &pll3_usb_otg); +DEF_PFD(pll3_pfd_540m, PFD_480, PFD1, &pll3_usb_otg); +DEF_PFD(pll3_pfd_508m, PFD_480, PFD2, &pll3_usb_otg); +DEF_PFD(pll3_pfd_454m, PFD_480, PFD3, &pll3_usb_otg); + +static unsigned long pll2_200m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk pll2_200m = { + .parent = &pll2_pfd_400m, + .get_rate = pll2_200m_get_rate, +}; + +static unsigned long pll3_120m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 4; +} + +static struct clk pll3_120m = { + .parent = &pll3_usb_otg, + .get_rate = pll3_120m_get_rate, +}; + +static unsigned long pll3_80m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 6; +} + +static struct clk pll3_80m = { + .parent = &pll3_usb_otg, + .get_rate = pll3_80m_get_rate, +}; + +static unsigned long pll3_60m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 8; +} + +static struct clk pll3_60m = { + .parent = &pll3_usb_otg, + .get_rate = pll3_60m_get_rate, +}; + +static int pll1_sw_clk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 val = readl_relaxed(CCSR); + + if (parent == &pll1_sys) { + val &= ~BM_CCSR_PLL1_SW_SEL; + val &= ~BM_CCSR_STEP_SEL; + } else if (parent == &osc_clk) { + val |= BM_CCSR_PLL1_SW_SEL; + val &= ~BM_CCSR_STEP_SEL; + } else if (parent == &pll2_pfd_400m) { + val |= BM_CCSR_PLL1_SW_SEL; + val |= BM_CCSR_STEP_SEL; + } else { + return -EINVAL; + } + + writel_relaxed(val, CCSR); + + return 0; +} + +static struct clk pll1_sw_clk = { + .parent = &pll1_sys, + .set_parent = pll1_sw_clk_set_parent, +}; + +static void calc_pred_podf_dividers(u32 div, u32 *pred, u32 *podf) +{ + u32 min_pred, temp_pred, old_err, err; + + if (div >= 512) { + *pred = 8; + *podf = 64; + } else if (div >= 8) { + min_pred = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pred = 8; temp_pred >= min_pred; temp_pred--) { + err = div % temp_pred; + if (err == 0) { + *pred = temp_pred; + break; + } + err = temp_pred - err; + if (err < old_err) { + old_err = err; + *pred = temp_pred; + } + } + *podf = (div + *pred - 1) / *pred; + } else if (div < 8) { + *pred = div; + *podf = 1; + } +} + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + reg = readl_relaxed(clk->enable_reg); + reg |= 0x3 << clk->enable_shift; + writel_relaxed(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + u32 reg; + reg = readl_relaxed(clk->enable_reg); + reg &= ~(0x3 << clk->enable_shift); + writel_relaxed(reg, clk->enable_reg); +} + +struct divider { + struct clk *clk; + void __iomem *reg; + u32 bp_pred; + u32 bm_pred; + u32 bp_podf; + u32 bm_podf; +}; + +#define DEF_CLK_DIV1(d, c, r, b) \ + static struct divider d = { \ + .clk = c, \ + .reg = r, \ + .bp_podf = BP_##r##_##b##_PODF, \ + .bm_podf = BM_##r##_##b##_PODF, \ + } + +DEF_CLK_DIV1(arm_div, &arm_clk, CACRR, ARM); +DEF_CLK_DIV1(ipg_div, &ipg_clk, CBCDR, IPG); +DEF_CLK_DIV1(ahb_div, &ahb_clk, CBCDR, AHB); +DEF_CLK_DIV1(axi_div, &axi_clk, CBCDR, AXI); +DEF_CLK_DIV1(mmdc_ch0_axi_div, &mmdc_ch0_axi_clk, CBCDR, MMDC_CH0_AXI); +DEF_CLK_DIV1(mmdc_ch1_axi_div, &mmdc_ch1_axi_clk, CBCDR, MMDC_CH1_AXI); +DEF_CLK_DIV1(periph_clk2_div, &periph_clk2_clk, CBCDR, PERIPH_CLK2); +DEF_CLK_DIV1(periph2_clk2_div, &periph2_clk2_clk, CBCDR, PERIPH2_CLK2); +DEF_CLK_DIV1(gpu2d_core_div, &gpu2d_core_clk, CBCMR, GPU2D_CORE); +DEF_CLK_DIV1(gpu3d_core_div, &gpu3d_core_clk, CBCMR, GPU3D_CORE); +DEF_CLK_DIV1(gpu3d_shader_div, &gpu3d_shader_clk, CBCMR, GPU3D_SHADER); +DEF_CLK_DIV1(ipg_perclk_div, &ipg_perclk, CSCMR1, PERCLK); +DEF_CLK_DIV1(emi_div, &emi_clk, CSCMR1, EMI); +DEF_CLK_DIV1(emi_slow_div, &emi_slow_clk, CSCMR1, EMI_SLOW); +DEF_CLK_DIV1(can_div, &can1_clk, CSCMR2, CAN); +DEF_CLK_DIV1(uart_div, &uart_clk, CSCDR1, UART); +DEF_CLK_DIV1(usdhc1_div, &usdhc1_clk, CSCDR1, USDHC1); +DEF_CLK_DIV1(usdhc2_div, &usdhc2_clk, CSCDR1, USDHC2); +DEF_CLK_DIV1(usdhc3_div, &usdhc3_clk, CSCDR1, USDHC3); +DEF_CLK_DIV1(usdhc4_div, &usdhc4_clk, CSCDR1, USDHC4); +DEF_CLK_DIV1(vpu_div, &vpu_clk, CSCDR1, VPU_AXI); +DEF_CLK_DIV1(hsi_tx_div, &hsi_tx_clk, CDCDR, HSI_TX); +DEF_CLK_DIV1(ipu1_di0_pre_div, &ipu1_di0_pre_clk, CHSCCDR, IPU1_DI0_PRE); +DEF_CLK_DIV1(ipu1_di1_pre_div, &ipu1_di1_pre_clk, CHSCCDR, IPU1_DI1_PRE); +DEF_CLK_DIV1(ipu2_di0_pre_div, &ipu2_di0_pre_clk, CSCDR2, IPU2_DI0_PRE); +DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk, CSCDR2, IPU2_DI1_PRE); +DEF_CLK_DIV1(ipu1_div, &ipu1_clk, CSCDR3, IPU1_HSP); +DEF_CLK_DIV1(ipu2_div, &ipu2_clk, CSCDR3, IPU2_HSP); + +#define DEF_CLK_DIV2(d, c, r, b) \ + static struct divider d = { \ + .clk = c, \ + .reg = r, \ + .bp_pred = BP_##r##_##b##_PRED, \ + .bm_pred = BM_##r##_##b##_PRED, \ + .bp_podf = BP_##r##_##b##_PODF, \ + .bm_podf = BM_##r##_##b##_PODF, \ + } + +DEF_CLK_DIV2(ssi1_div, &ssi1_clk, CS1CDR, SSI1); +DEF_CLK_DIV2(ssi3_div, &ssi3_clk, CS1CDR, SSI3); +DEF_CLK_DIV2(esai_div, &esai_clk, CS1CDR, ESAI); +DEF_CLK_DIV2(ssi2_div, &ssi2_clk, CS2CDR, SSI2); +DEF_CLK_DIV2(enfc_div, &enfc_clk, CS2CDR, ENFC); +DEF_CLK_DIV2(spdif_div, &spdif_clk, CDCDR, SPDIF); +DEF_CLK_DIV2(asrc_serial_div, &asrc_serial_clk, CDCDR, ASRC_SERIAL); + +static struct divider *dividers[] = { + &arm_div, + &ipg_div, + &ahb_div, + &axi_div, + &mmdc_ch0_axi_div, + &mmdc_ch1_axi_div, + &periph_clk2_div, + &periph2_clk2_div, + &gpu2d_core_div, + &gpu3d_core_div, + &gpu3d_shader_div, + &ipg_perclk_div, + &emi_div, + &emi_slow_div, + &can_div, + &uart_div, + &usdhc1_div, + &usdhc2_div, + &usdhc3_div, + &usdhc4_div, + &vpu_div, + &hsi_tx_div, + &ipu1_di0_pre_div, + &ipu1_di1_pre_div, + &ipu2_di0_pre_div, + &ipu2_di1_pre_div, + &ipu1_div, + &ipu2_div, + &ssi1_div, + &ssi3_div, + &esai_div, + &ssi2_div, + &enfc_div, + &spdif_div, + &asrc_serial_div, +}; + +static unsigned long ldb_di_clk_get_rate(struct clk *clk) +{ + u32 val = readl_relaxed(CSCMR2); + + val &= (clk == &ldb_di0_clk) ? BM_CSCMR2_LDB_DI0_IPU_DIV : + BM_CSCMR2_LDB_DI1_IPU_DIV; + if (val) + return clk_get_rate(clk->parent) / 7; + else + return clk_get_rate(clk->parent) * 2 / 7; +} + +static int ldb_di_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + u32 val = readl_relaxed(CSCMR2); + + if (rate * 7 <= parent_rate + parent_rate / 20) + val |= BM_CSCMR2_LDB_DI0_IPU_DIV; + else + val &= ~BM_CSCMR2_LDB_DI0_IPU_DIV; + + writel_relaxed(val, CSCMR2); + + return 0; +} + +static unsigned long ldb_di_clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + + if (rate * 7 <= parent_rate + parent_rate / 20) + return parent_rate / 7; + else + return 2 * parent_rate / 7; +} + +static unsigned long _clk_get_rate(struct clk *clk) +{ + struct divider *d; + u32 val, pred, podf; + int i, num; + + if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) + return ldb_di_clk_get_rate(clk); + + num = ARRAY_SIZE(dividers); + for (i = 0; i < num; i++) + if (dividers[i]->clk == clk) { + d = dividers[i]; + break; + } + if (i == num) + return clk_get_rate(clk->parent); + + val = readl_relaxed(d->reg); + pred = ((val & d->bm_pred) >> d->bp_pred) + 1; + podf = ((val & d->bm_podf) >> d->bp_podf) + 1; + + return clk_get_rate(clk->parent) / (pred * podf); +} + +static int clk_busy_wait(struct clk *clk) +{ + int timeout = 0x100000; + u32 bm; + + if (clk == &axi_clk) + bm = BM_CDHIPR_AXI_PODF_BUSY; + else if (clk == &ahb_clk) + bm = BM_CDHIPR_AHB_PODF_BUSY; + else if (clk == &mmdc_ch0_axi_clk) + bm = BM_CDHIPR_MMDC_CH0_PODF_BUSY; + else if (clk == &periph_clk) + bm = BM_CDHIPR_PERIPH_SEL_BUSY; + else if (clk == &arm_clk) + bm = BM_CDHIPR_ARM_PODF_BUSY; + else + return -EINVAL; + + while ((readl_relaxed(CDHIPR) & bm) && --timeout) + cpu_relax(); + + if (unlikely(!timeout)) + return -EBUSY; + + return 0; +} + +static int _clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + struct divider *d; + u32 val, div, max_div, pred = 0, podf; + int i, num; + + if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) + return ldb_di_clk_set_rate(clk, rate); + + num = ARRAY_SIZE(dividers); + for (i = 0; i < num; i++) + if (dividers[i]->clk == clk) { + d = dividers[i]; + break; + } + if (i == num) + return -EINVAL; + + max_div = ((d->bm_pred >> d->bp_pred) + 1) * + ((d->bm_pred >> d->bp_pred) + 1); + + div = parent_rate / rate; + if (div == 0) + div++; + + if ((parent_rate / div != rate) || div > max_div) + return -EINVAL; + + if (d->bm_pred) { + calc_pred_podf_dividers(div, &pred, &podf); + } else { + pred = 1; + podf = div; + } + + val = readl_relaxed(d->reg); + val &= ~(d->bm_pred | d->bm_podf); + val |= (pred - 1) << d->bp_pred | (podf - 1) << d->bp_podf; + writel_relaxed(val, d->reg); + + if (clk == &axi_clk || clk == &ahb_clk || + clk == &mmdc_ch0_axi_clk || clk == &arm_clk) + return clk_busy_wait(clk); + + return 0; +} + +static unsigned long _clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + u32 div_max, pred = 0, podf; + struct divider *d; + int i, num; + + if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) + return ldb_di_clk_round_rate(clk, rate); + + num = ARRAY_SIZE(dividers); + for (i = 0; i < num; i++) + if (dividers[i]->clk == clk) { + d = dividers[i]; + break; + } + if (i == num) + return -EINVAL; + + if (div == 0 || parent_rate % rate) + div++; + + if (d->bm_pred) { + calc_pred_podf_dividers(div, &pred, &podf); + div = pred * podf; + } else { + div_max = (d->bm_podf >> d->bp_podf) + 1; + if (div > div_max) + div = div_max; + } + + return parent_rate / div; +} + +struct multiplexer { + struct clk *clk; + void __iomem *reg; + u32 bp; + u32 bm; + int pnum; + struct clk *parents[]; +}; + +static struct multiplexer axi_mux = { + .clk = &axi_clk, + .reg = CBCDR, + .bp = BP_CBCDR_AXI_SEL, + .bm = BM_CBCDR_AXI_SEL, + .parents = { + &periph_clk, + &pll2_pfd_400m, + &pll3_pfd_540m, + NULL + }, +}; + +static struct multiplexer periph_mux = { + .clk = &periph_clk, + .reg = CBCDR, + .bp = BP_CBCDR_PERIPH_CLK_SEL, + .bm = BM_CBCDR_PERIPH_CLK_SEL, + .parents = { + &periph_pre_clk, + &periph_clk2_clk, + NULL + }, +}; + +static struct multiplexer periph_pre_mux = { + .clk = &periph_pre_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PRE_PERIPH_CLK_SEL, + .bm = BM_CBCMR_PRE_PERIPH_CLK_SEL, + .parents = { + &pll2_bus, + &pll2_pfd_400m, + &pll2_pfd_352m, + &pll2_200m, + NULL + }, +}; + +static struct multiplexer periph_clk2_mux = { + .clk = &periph_clk2_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PERIPH_CLK2_SEL, + .bm = BM_CBCMR_PERIPH_CLK2_SEL, + .parents = { + &pll3_usb_otg, + &osc_clk, + NULL + }, +}; + +static struct multiplexer periph2_mux = { + .clk = &periph2_clk, + .reg = CBCDR, + .bp = BP_CBCDR_PERIPH2_CLK_SEL, + .bm = BM_CBCDR_PERIPH2_CLK_SEL, + .parents = { + &periph2_pre_clk, + &periph2_clk2_clk, + NULL + }, +}; + +static struct multiplexer periph2_pre_mux = { + .clk = &periph2_pre_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PRE_PERIPH2_CLK_SEL, + .bm = BM_CBCMR_PRE_PERIPH2_CLK_SEL, + .parents = { + &pll2_bus, + &pll2_pfd_400m, + &pll2_pfd_352m, + &pll2_200m, + NULL + }, +}; + +static struct multiplexer periph2_clk2_mux = { + .clk = &periph2_clk2_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PERIPH2_CLK2_SEL, + .bm = BM_CBCMR_PERIPH2_CLK2_SEL, + .parents = { + &pll3_usb_otg, + &osc_clk, + NULL + }, +}; + +static struct multiplexer gpu2d_axi_mux = { + .clk = &gpu2d_axi_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU2D_AXI_SEL, + .bm = BM_CBCMR_GPU2D_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer gpu3d_axi_mux = { + .clk = &gpu3d_axi_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU3D_AXI_SEL, + .bm = BM_CBCMR_GPU3D_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer gpu3d_core_mux = { + .clk = &gpu3d_core_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU3D_CORE_SEL, + .bm = BM_CBCMR_GPU3D_CORE_SEL, + .parents = { + &mmdc_ch0_axi_clk, + &pll3_usb_otg, + &pll2_pfd_594m, + &pll2_pfd_400m, + NULL + }, +}; + +static struct multiplexer gpu3d_shader_mux = { + .clk = &gpu3d_shader_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU3D_SHADER_SEL, + .bm = BM_CBCMR_GPU3D_SHADER_SEL, + .parents = { + &mmdc_ch0_axi_clk, + &pll3_usb_otg, + &pll2_pfd_594m, + &pll3_pfd_720m, + NULL + }, +}; + +static struct multiplexer pcie_axi_mux = { + .clk = &pcie_clk, + .reg = CBCMR, + .bp = BP_CBCMR_PCIE_AXI_SEL, + .bm = BM_CBCMR_PCIE_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer vdo_axi_mux = { + .clk = &vdo_axi_clk, + .reg = CBCMR, + .bp = BP_CBCMR_VDO_AXI_SEL, + .bm = BM_CBCMR_VDO_AXI_SEL, + .parents = { + &axi_clk, + &ahb_clk, + NULL + }, +}; + +static struct multiplexer vpu_axi_mux = { + .clk = &vpu_clk, + .reg = CBCMR, + .bp = BP_CBCMR_VPU_AXI_SEL, + .bm = BM_CBCMR_VPU_AXI_SEL, + .parents = { + &axi_clk, + &pll2_pfd_400m, + &pll2_pfd_352m, + NULL + }, +}; + +static struct multiplexer gpu2d_core_mux = { + .clk = &gpu2d_core_clk, + .reg = CBCMR, + .bp = BP_CBCMR_GPU2D_CORE_SEL, + .bm = BM_CBCMR_GPU2D_CORE_SEL, + .parents = { + &axi_clk, + &pll3_usb_otg, + &pll2_pfd_352m, + &pll2_pfd_400m, + NULL + }, +}; + +#define DEF_SSI_MUX(id) \ + static struct multiplexer ssi##id##_mux = { \ + .clk = &ssi##id##_clk, \ + .reg = CSCMR1, \ + .bp = BP_CSCMR1_SSI##id##_SEL, \ + .bm = BM_CSCMR1_SSI##id##_SEL, \ + .parents = { \ + &pll3_pfd_508m, \ + &pll3_pfd_454m, \ + &pll4_audio, \ + NULL \ + }, \ + } + +DEF_SSI_MUX(1); +DEF_SSI_MUX(2); +DEF_SSI_MUX(3); + +#define DEF_USDHC_MUX(id) \ + static struct multiplexer usdhc##id##_mux = { \ + .clk = &usdhc##id##_clk, \ + .reg = CSCMR1, \ + .bp = BP_CSCMR1_USDHC##id##_SEL, \ + .bm = BM_CSCMR1_USDHC##id##_SEL, \ + .parents = { \ + &pll2_pfd_400m, \ + &pll2_pfd_352m, \ + NULL \ + }, \ + } + +DEF_USDHC_MUX(1); +DEF_USDHC_MUX(2); +DEF_USDHC_MUX(3); +DEF_USDHC_MUX(4); + +static struct multiplexer emi_mux = { + .clk = &emi_clk, + .reg = CSCMR1, + .bp = BP_CSCMR1_EMI_SEL, + .bm = BM_CSCMR1_EMI_SEL, + .parents = { + &axi_clk, + &pll3_usb_otg, + &pll2_pfd_400m, + &pll2_pfd_352m, + NULL + }, +}; + +static struct multiplexer emi_slow_mux = { + .clk = &emi_slow_clk, + .reg = CSCMR1, + .bp = BP_CSCMR1_EMI_SLOW_SEL, + .bm = BM_CSCMR1_EMI_SLOW_SEL, + .parents = { + &axi_clk, + &pll3_usb_otg, + &pll2_pfd_400m, + &pll2_pfd_352m, + NULL + }, +}; + +static struct multiplexer esai_mux = { + .clk = &esai_clk, + .reg = CSCMR2, + .bp = BP_CSCMR2_ESAI_SEL, + .bm = BM_CSCMR2_ESAI_SEL, + .parents = { + &pll4_audio, + &pll3_pfd_508m, + &pll3_pfd_454m, + &pll3_usb_otg, + NULL + }, +}; + +#define DEF_LDB_DI_MUX(id) \ + static struct multiplexer ldb_di##id##_mux = { \ + .clk = &ldb_di##id##_clk, \ + .reg = CS2CDR, \ + .bp = BP_CS2CDR_LDB_DI##id##_SEL, \ + .bm = BM_CS2CDR_LDB_DI##id##_SEL, \ + .parents = { \ + &pll5_video, \ + &pll2_pfd_352m, \ + &pll2_pfd_400m, \ + &pll3_pfd_540m, \ + &pll3_usb_otg, \ + NULL \ + }, \ + } + +DEF_LDB_DI_MUX(0); +DEF_LDB_DI_MUX(1); + +static struct multiplexer enfc_mux = { + .clk = &enfc_clk, + .reg = CS2CDR, + .bp = BP_CS2CDR_ENFC_SEL, + .bm = BM_CS2CDR_ENFC_SEL, + .parents = { + &pll2_pfd_352m, + &pll2_bus, + &pll3_usb_otg, + &pll2_pfd_400m, + NULL + }, +}; + +static struct multiplexer spdif_mux = { + .clk = &spdif_clk, + .reg = CDCDR, + .bp = BP_CDCDR_SPDIF_SEL, + .bm = BM_CDCDR_SPDIF_SEL, + .parents = { + &pll4_audio, + &pll3_pfd_508m, + &pll3_pfd_454m, + &pll3_usb_otg, + NULL + }, +}; + +static struct multiplexer asrc_serial_mux = { + .clk = &asrc_serial_clk, + .reg = CDCDR, + .bp = BP_CDCDR_ASRC_SERIAL_SEL, + .bm = BM_CDCDR_ASRC_SERIAL_SEL, + .parents = { + &pll4_audio, + &pll3_pfd_508m, + &pll3_pfd_454m, + &pll3_usb_otg, + NULL + }, +}; + +static struct multiplexer hsi_tx_mux = { + .clk = &hsi_tx_clk, + .reg = CDCDR, + .bp = BP_CDCDR_HSI_TX_SEL, + .bm = BM_CDCDR_HSI_TX_SEL, + .parents = { + &pll3_120m, + &pll2_pfd_400m, + NULL + }, +}; + +#define DEF_IPU_DI_PRE_MUX(r, i, d) \ + static struct multiplexer ipu##i##_di##d##_pre_mux = { \ + .clk = &ipu##i##_di##d##_pre_clk, \ + .reg = r, \ + .bp = BP_##r##_IPU##i##_DI##d##_PRE_SEL, \ + .bm = BM_##r##_IPU##i##_DI##d##_PRE_SEL, \ + .parents = { \ + &mmdc_ch0_axi_clk, \ + &pll3_usb_otg, \ + &pll5_video, \ + &pll2_pfd_352m, \ + &pll2_pfd_400m, \ + &pll3_pfd_540m, \ + NULL \ + }, \ + } + +DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 0); +DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 1); +DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 0); +DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 1); + +#define DEF_IPU_DI_MUX(r, i, d) \ + static struct multiplexer ipu##i##_di##d##_mux = { \ + .clk = &ipu##i##_di##d##_clk, \ + .reg = r, \ + .bp = BP_##r##_IPU##i##_DI##d##_SEL, \ + .bm = BM_##r##_IPU##i##_DI##d##_SEL, \ + .parents = { \ + &ipu##i##_di##d##_pre_clk, \ + &dummy_clk, \ + &dummy_clk, \ + &ldb_di0_clk, \ + &ldb_di1_clk, \ + NULL \ + }, \ + } + +DEF_IPU_DI_MUX(CHSCCDR, 1, 0); +DEF_IPU_DI_MUX(CHSCCDR, 1, 1); +DEF_IPU_DI_MUX(CSCDR2, 2, 0); +DEF_IPU_DI_MUX(CSCDR2, 2, 1); + +#define DEF_IPU_MUX(id) \ + static struct multiplexer ipu##id##_mux = { \ + .clk = &ipu##id##_clk, \ + .reg = CSCDR3, \ + .bp = BP_CSCDR3_IPU##id##_HSP_SEL, \ + .bm = BM_CSCDR3_IPU##id##_HSP_SEL, \ + .parents = { \ + &mmdc_ch0_axi_clk, \ + &pll2_pfd_400m, \ + &pll3_120m, \ + &pll3_pfd_540m, \ + NULL \ + }, \ + } + +DEF_IPU_MUX(1); +DEF_IPU_MUX(2); + +static struct multiplexer *multiplexers[] = { + &axi_mux, + &periph_mux, + &periph_pre_mux, + &periph_clk2_mux, + &periph2_mux, + &periph2_pre_mux, + &periph2_clk2_mux, + &gpu2d_axi_mux, + &gpu3d_axi_mux, + &gpu3d_core_mux, + &gpu3d_shader_mux, + &pcie_axi_mux, + &vdo_axi_mux, + &vpu_axi_mux, + &gpu2d_core_mux, + &ssi1_mux, + &ssi2_mux, + &ssi3_mux, + &usdhc1_mux, + &usdhc2_mux, + &usdhc3_mux, + &usdhc4_mux, + &emi_mux, + &emi_slow_mux, + &esai_mux, + &ldb_di0_mux, + &ldb_di1_mux, + &enfc_mux, + &spdif_mux, + &asrc_serial_mux, + &hsi_tx_mux, + &ipu1_di0_pre_mux, + &ipu1_di0_mux, + &ipu1_di1_pre_mux, + &ipu1_di1_mux, + &ipu2_di0_pre_mux, + &ipu2_di0_mux, + &ipu2_di1_pre_mux, + &ipu2_di1_mux, + &ipu1_mux, + &ipu2_mux, +}; + +static int _clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct multiplexer *m; + int i, num; + u32 val; + + num = ARRAY_SIZE(multiplexers); + for (i = 0; i < num; i++) + if (multiplexers[i]->clk == clk) { + m = multiplexers[i]; + break; + } + if (i == num) + return -EINVAL; + + i = 0; + while (m->parents[i]) { + if (parent == m->parents[i]) + break; + i++; + } + if (!m->parents[i]) + return -EINVAL; + + val = readl_relaxed(m->reg); + val &= ~m->bm; + val |= i << m->bp; + writel_relaxed(val, m->reg); + + if (clk == &periph_clk) + return clk_busy_wait(clk); + + return 0; +} + +#define DEF_NG_CLK(name, p) \ + static struct clk name = { \ + .get_rate = _clk_get_rate, \ + .set_rate = _clk_set_rate, \ + .round_rate = _clk_round_rate, \ + .set_parent = _clk_set_parent, \ + .parent = p, \ + } + +DEF_NG_CLK(periph_clk2_clk, &osc_clk); +DEF_NG_CLK(periph_pre_clk, &pll2_bus); +DEF_NG_CLK(periph_clk, &periph_pre_clk); +DEF_NG_CLK(periph2_clk2_clk, &osc_clk); +DEF_NG_CLK(periph2_pre_clk, &pll2_bus); +DEF_NG_CLK(periph2_clk, &periph2_pre_clk); +DEF_NG_CLK(axi_clk, &periph_clk); +DEF_NG_CLK(emi_clk, &axi_clk); +DEF_NG_CLK(arm_clk, &pll1_sw_clk); +DEF_NG_CLK(ahb_clk, &periph_clk); +DEF_NG_CLK(ipg_clk, &ahb_clk); +DEF_NG_CLK(ipg_perclk, &ipg_clk); +DEF_NG_CLK(ipu1_di0_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(ipu1_di1_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(ipu2_di0_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(ipu2_di1_pre_clk, &pll3_pfd_540m); +DEF_NG_CLK(asrc_serial_clk, &pll3_usb_otg); + +#define DEF_CLK(name, er, es, p, s) \ + static struct clk name = { \ + .enable_reg = er, \ + .enable_shift = es, \ + .enable = _clk_enable, \ + .disable = _clk_disable, \ + .get_rate = _clk_get_rate, \ + .set_rate = _clk_set_rate, \ + .round_rate = _clk_round_rate, \ + .set_parent = _clk_set_parent, \ + .parent = p, \ + .secondary = s, \ + } + +DEF_CLK(aips_tz1_clk, CCGR0, CG0, &ahb_clk, NULL); +DEF_CLK(aips_tz2_clk, CCGR0, CG1, &ahb_clk, NULL); +DEF_CLK(apbh_dma_clk, CCGR0, CG2, &ahb_clk, NULL); +DEF_CLK(asrc_clk, CCGR0, CG3, &pll4_audio, NULL); +DEF_CLK(can1_serial_clk, CCGR0, CG8, &pll3_usb_otg, NULL); +DEF_CLK(can1_clk, CCGR0, CG7, &pll3_usb_otg, &can1_serial_clk); +DEF_CLK(can2_serial_clk, CCGR0, CG10, &pll3_usb_otg, NULL); +DEF_CLK(can2_clk, CCGR0, CG9, &pll3_usb_otg, &can2_serial_clk); +DEF_CLK(ecspi1_clk, CCGR1, CG0, &pll3_60m, NULL); +DEF_CLK(ecspi2_clk, CCGR1, CG1, &pll3_60m, NULL); +DEF_CLK(ecspi3_clk, CCGR1, CG2, &pll3_60m, NULL); +DEF_CLK(ecspi4_clk, CCGR1, CG3, &pll3_60m, NULL); +DEF_CLK(ecspi5_clk, CCGR1, CG4, &pll3_60m, NULL); +DEF_CLK(enet_clk, CCGR1, CG5, &ipg_clk, NULL); +DEF_CLK(esai_clk, CCGR1, CG8, &pll3_usb_otg, NULL); +DEF_CLK(gpt_serial_clk, CCGR1, CG11, &ipg_perclk, NULL); +DEF_CLK(gpt_clk, CCGR1, CG10, &ipg_perclk, &gpt_serial_clk); +DEF_CLK(gpu2d_core_clk, CCGR1, CG12, &pll2_pfd_352m, &gpu2d_axi_clk); +DEF_CLK(gpu3d_core_clk, CCGR1, CG13, &pll2_pfd_594m, &gpu3d_axi_clk); +DEF_CLK(gpu3d_shader_clk, CCGR1, CG13, &pll3_pfd_720m, &gpu3d_axi_clk); +DEF_CLK(hdmi_iahb_clk, CCGR2, CG0, &ahb_clk, NULL); +DEF_CLK(hdmi_isfr_clk, CCGR2, CG2, &pll3_pfd_540m, &hdmi_iahb_clk); +DEF_CLK(i2c1_clk, CCGR2, CG3, &ipg_perclk, NULL); +DEF_CLK(i2c2_clk, CCGR2, CG4, &ipg_perclk, NULL); +DEF_CLK(i2c3_clk, CCGR2, CG5, &ipg_perclk, NULL); +DEF_CLK(iim_clk, CCGR2, CG6, &ipg_clk, NULL); +DEF_CLK(enfc_clk, CCGR2, CG7, &pll2_pfd_352m, NULL); +DEF_CLK(ipu1_clk, CCGR3, CG0, &mmdc_ch0_axi_clk, NULL); +DEF_CLK(ipu1_di0_clk, CCGR3, CG1, &ipu1_di0_pre_clk, NULL); +DEF_CLK(ipu1_di1_clk, CCGR3, CG2, &ipu1_di1_pre_clk, NULL); +DEF_CLK(ipu2_clk, CCGR3, CG3, &mmdc_ch0_axi_clk, NULL); +DEF_CLK(ipu2_di0_clk, CCGR3, CG4, &ipu2_di0_pre_clk, NULL); +DEF_CLK(ipu2_di1_clk, CCGR3, CG5, &ipu2_di1_pre_clk, NULL); +DEF_CLK(ldb_di0_clk, CCGR3, CG6, &pll3_pfd_540m, NULL); +DEF_CLK(ldb_di1_clk, CCGR3, CG7, &pll3_pfd_540m, NULL); +DEF_CLK(hsi_tx_clk, CCGR3, CG8, &pll2_pfd_400m, NULL); +DEF_CLK(mlb_clk, CCGR3, CG9, &pll6_mlb, NULL); +DEF_CLK(mmdc_ch0_ipg_clk, CCGR3, CG12, &ipg_clk, NULL); +DEF_CLK(mmdc_ch0_axi_clk, CCGR3, CG10, &periph_clk, &mmdc_ch0_ipg_clk); +DEF_CLK(mmdc_ch1_ipg_clk, CCGR3, CG13, &ipg_clk, NULL); +DEF_CLK(mmdc_ch1_axi_clk, CCGR3, CG11, &periph2_clk, &mmdc_ch1_ipg_clk); +DEF_CLK(openvg_axi_clk, CCGR3, CG13, &axi_clk, NULL); +DEF_CLK(pwm1_clk, CCGR4, CG8, &ipg_perclk, NULL); +DEF_CLK(pwm2_clk, CCGR4, CG9, &ipg_perclk, NULL); +DEF_CLK(pwm3_clk, CCGR4, CG10, &ipg_perclk, NULL); +DEF_CLK(pwm4_clk, CCGR4, CG11, &ipg_perclk, NULL); +DEF_CLK(gpmi_bch_apb_clk, CCGR4, CG12, &usdhc3_clk, NULL); +DEF_CLK(gpmi_bch_clk, CCGR4, CG13, &usdhc4_clk, &gpmi_bch_apb_clk); +DEF_CLK(gpmi_apb_clk, CCGR4, CG15, &usdhc3_clk, &gpmi_bch_clk); +DEF_CLK(gpmi_io_clk, CCGR4, CG14, &enfc_clk, &gpmi_apb_clk); +DEF_CLK(sdma_clk, CCGR5, CG3, &ahb_clk, NULL); +DEF_CLK(spba_clk, CCGR5, CG6, &ipg_clk, NULL); +DEF_CLK(spdif_clk, CCGR5, CG7, &pll3_usb_otg, &spba_clk); +DEF_CLK(ssi1_clk, CCGR5, CG9, &pll3_pfd_508m, NULL); +DEF_CLK(ssi2_clk, CCGR5, CG10, &pll3_pfd_508m, NULL); +DEF_CLK(ssi3_clk, CCGR5, CG11, &pll3_pfd_508m, NULL); +DEF_CLK(uart_serial_clk, CCGR5, CG13, &pll3_usb_otg, NULL); +DEF_CLK(uart_clk, CCGR5, CG12, &pll3_80m, &uart_serial_clk); +DEF_CLK(usboh3_clk, CCGR6, CG0, &ipg_clk, NULL); +DEF_CLK(usdhc1_clk, CCGR6, CG1, &pll2_pfd_400m, NULL); +DEF_CLK(usdhc2_clk, CCGR6, CG2, &pll2_pfd_400m, NULL); +DEF_CLK(usdhc3_clk, CCGR6, CG3, &pll2_pfd_400m, NULL); +DEF_CLK(usdhc4_clk, CCGR6, CG4, &pll2_pfd_400m, NULL); +DEF_CLK(emi_slow_clk, CCGR6, CG5, &axi_clk, NULL); +DEF_CLK(vdo_axi_clk, CCGR6, CG6, &axi_clk, NULL); +DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, NULL); + +static int pcie_clk_enable(struct clk *clk) +{ + u32 val; + + val = readl_relaxed(PLL8_ENET); + val |= BM_PLL_ENET_EN_PCIE; + writel_relaxed(val, PLL8_ENET); + + return _clk_enable(clk); +} + +static void pcie_clk_disable(struct clk *clk) +{ + u32 val; + + _clk_disable(clk); + + val = readl_relaxed(PLL8_ENET); + val &= BM_PLL_ENET_EN_PCIE; + writel_relaxed(val, PLL8_ENET); +} + +static struct clk pcie_clk = { + .enable_reg = CCGR4, + .enable_shift = CG0, + .enable = pcie_clk_enable, + .disable = pcie_clk_disable, + .set_parent = _clk_set_parent, + .parent = &axi_clk, + .secondary = &pll8_enet, +}; + +static int sata_clk_enable(struct clk *clk) +{ + u32 val; + + val = readl_relaxed(PLL8_ENET); + val |= BM_PLL_ENET_EN_SATA; + writel_relaxed(val, PLL8_ENET); + + return _clk_enable(clk); +} + +static void sata_clk_disable(struct clk *clk) +{ + u32 val; + + _clk_disable(clk); + + val = readl_relaxed(PLL8_ENET); + val &= BM_PLL_ENET_EN_SATA; + writel_relaxed(val, PLL8_ENET); +} + +static struct clk sata_clk = { + .enable_reg = CCGR5, + .enable_shift = CG2, + .enable = sata_clk_enable, + .disable = sata_clk_disable, + .parent = &ipg_clk, + .secondary = &pll8_enet, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + } + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK("2020000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21e8000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21ec000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21f0000.uart", NULL, uart_clk), + _REGISTER_CLOCK("21f4000.uart", NULL, uart_clk), + _REGISTER_CLOCK("2188000.enet", NULL, enet_clk), + _REGISTER_CLOCK("2190000.usdhc", NULL, usdhc1_clk), + _REGISTER_CLOCK("2194000.usdhc", NULL, usdhc2_clk), + _REGISTER_CLOCK("2198000.usdhc", NULL, usdhc3_clk), + _REGISTER_CLOCK("219c000.usdhc", NULL, usdhc4_clk), + _REGISTER_CLOCK("21a0000.i2c", NULL, i2c1_clk), + _REGISTER_CLOCK("21a4000.i2c", NULL, i2c2_clk), + _REGISTER_CLOCK("21a8000.i2c", NULL, i2c3_clk), + _REGISTER_CLOCK("2008000.ecspi", NULL, ecspi1_clk), + _REGISTER_CLOCK("200c000.ecspi", NULL, ecspi2_clk), + _REGISTER_CLOCK("2010000.ecspi", NULL, ecspi3_clk), + _REGISTER_CLOCK("2014000.ecspi", NULL, ecspi4_clk), + _REGISTER_CLOCK("2018000.ecspi", NULL, ecspi5_clk), + _REGISTER_CLOCK("20ec000.sdma", NULL, sdma_clk), + _REGISTER_CLOCK("20bc000.wdog", NULL, dummy_clk), + _REGISTER_CLOCK("20c0000.wdog", NULL, dummy_clk), + _REGISTER_CLOCK(NULL, "ckih", ckih_clk), + _REGISTER_CLOCK(NULL, "ckil_clk", ckil_clk), + _REGISTER_CLOCK(NULL, "aips_tz1_clk", aips_tz1_clk), + _REGISTER_CLOCK(NULL, "aips_tz2_clk", aips_tz2_clk), + _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk), + _REGISTER_CLOCK(NULL, "can2_clk", can2_clk), + _REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_isfr_clk), + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), + _REGISTER_CLOCK(NULL, "mlb_clk", mlb_clk), + _REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk), + _REGISTER_CLOCK(NULL, "pwm1_clk", pwm1_clk), + _REGISTER_CLOCK(NULL, "pwm2_clk", pwm2_clk), + _REGISTER_CLOCK(NULL, "pwm3_clk", pwm3_clk), + _REGISTER_CLOCK(NULL, "pwm4_clk", pwm4_clk), + _REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk), + _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk), + _REGISTER_CLOCK(NULL, "sata_clk", sata_clk), +}; + +int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +{ + u32 val = readl_relaxed(CLPCR); + + val &= ~BM_CLPCR_LPM; + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + val |= 0x1 << BP_CLPCR_LPM; + break; + case STOP_POWER_ON: + val |= 0x2 << BP_CLPCR_LPM; + break; + case WAIT_UNCLOCKED_POWER_OFF: + val |= 0x1 << BP_CLPCR_LPM; + val &= ~BM_CLPCR_VSTBY; + val &= ~BM_CLPCR_SBYOS; + val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + break; + case STOP_POWER_OFF: + val |= 0x2 << BP_CLPCR_LPM; + val |= 0x3 << BP_CLPCR_STBY_COUNT; + val |= BM_CLPCR_VSTBY; + val |= BM_CLPCR_SBYOS; + val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + break; + default: + return -EINVAL; + } + writel_relaxed(val, CLPCR); + + return 0; +} + +static struct map_desc imx6q_clock_desc[] = { + imx_map_entry(MX6Q, CCM, MT_DEVICE), + imx_map_entry(MX6Q, ANATOP, MT_DEVICE), +}; + +int __init mx6q_clocks_init(void) +{ + struct device_node *np; + void __iomem *base; + int i, irq; + + iotable_init(imx6q_clock_desc, ARRAY_SIZE(imx6q_clock_desc)); + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + external_low_reference = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + external_high_reference = rate; + else if (of_device_is_compatible(np, "fsl,imx-osc")) + oscillator_reference = rate; + } + + for (i = 0; i < ARRAY_SIZE(lookups); i++) + clkdev_add(&lookups[i]); + + /* only keep necessary clocks on */ + writel_relaxed(0x3 << CG0 | 0x3 << CG1 | 0x3 << CG2, CCGR0); + writel_relaxed(0x3 << CG8 | 0x3 << CG9 | 0x3 << CG10, CCGR2); + writel_relaxed(0x3 << CG10 | 0x3 << CG12, CCGR3); + writel_relaxed(0x3 << CG4 | 0x3 << CG6 | 0x3 << CG7, CCGR4); + writel_relaxed(0x3 << CG0, CCGR5); + writel_relaxed(0, CCGR6); + writel_relaxed(0, CCGR7); + + clk_enable(&uart_clk); + clk_enable(&mmdc_ch0_axi_clk); + + clk_set_rate(&pll4_audio, FREQ_650M); + clk_set_rate(&pll5_video, FREQ_650M); + clk_set_parent(&ipu1_di0_clk, &ipu1_di0_pre_clk); + clk_set_parent(&ipu1_di0_pre_clk, &pll5_video); + clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594m); + clk_set_rate(&gpu3d_shader_clk, FREQ_594M); + clk_set_parent(&gpu3d_core_clk, &mmdc_ch0_axi_clk); + clk_set_rate(&gpu3d_core_clk, FREQ_528M); + clk_set_parent(&asrc_serial_clk, &pll3_usb_otg); + clk_set_rate(&asrc_serial_clk, 1500000); + clk_set_rate(&enfc_clk, 11000000); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + mxc_timer_init(&gpt_clk, base, irq); + + return 0; +} diff --git a/arch/arm/mach-imx/cpu-imx25.c b/arch/arm/mach-imx/cpu-imx25.c new file mode 100644 index 00000000000..6914bcbf84e --- /dev/null +++ b/arch/arm/mach-imx/cpu-imx25.c @@ -0,0 +1,41 @@ +/* + * MX25 CPU type detection + * + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * Copyright (C) 2011 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/module.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <mach/iim.h> + +static int mx25_cpu_rev = -1; + +static int mx25_read_cpu_rev(void) +{ + u32 rev; + + rev = __raw_readl(MX25_IO_ADDRESS(MX25_IIM_BASE_ADDR + MXC_IIMSREV)); + switch (rev) { + case 0x00: + return IMX_CHIP_REVISION_1_0; + case 0x01: + return IMX_CHIP_REVISION_1_1; + default: + return IMX_CHIP_REVISION_UNKNOWN; + } +} + +int mx25_revision(void) +{ + if (mx25_cpu_rev == -1) + mx25_cpu_rev = mx25_read_cpu_rev(); + + return mx25_cpu_rev; +} +EXPORT_SYMBOL(mx25_revision); diff --git a/arch/arm/mach-imx/cpu-imx27.c b/arch/arm/mach-imx/cpu-imx27.c index 3b117be37bd..ff38e1505f6 100644 --- a/arch/arm/mach-imx/cpu-imx27.c +++ b/arch/arm/mach-imx/cpu-imx27.c @@ -26,12 +26,12 @@ #include <mach/hardware.h> -static int cpu_silicon_rev = -1; -static int cpu_partnumber; +static int mx27_cpu_rev = -1; +static int mx27_cpu_partnumber; #define SYS_CHIP_ID 0x00 /* The offset of CHIP ID register */ -static void query_silicon_parameter(void) +static int mx27_read_cpu_rev(void) { u32 val; /* @@ -42,20 +42,18 @@ static void query_silicon_parameter(void) val = __raw_readl(MX27_IO_ADDRESS(MX27_SYSCTRL_BASE_ADDR + SYS_CHIP_ID)); + mx27_cpu_partnumber = (int)((val >> 12) & 0xFFFF); + switch (val >> 28) { case 0: - cpu_silicon_rev = IMX_CHIP_REVISION_1_0; - break; + return IMX_CHIP_REVISION_1_0; case 1: - cpu_silicon_rev = IMX_CHIP_REVISION_2_0; - break; + return IMX_CHIP_REVISION_2_0; case 2: - cpu_silicon_rev = IMX_CHIP_REVISION_2_1; - break; + return IMX_CHIP_REVISION_2_1; default: - cpu_silicon_rev = IMX_CHIP_REVISION_UNKNOWN; + return IMX_CHIP_REVISION_UNKNOWN; } - cpu_partnumber = (int)((val >> 12) & 0xFFFF); } /* @@ -65,12 +63,12 @@ static void query_silicon_parameter(void) */ int mx27_revision(void) { - if (cpu_silicon_rev == -1) - query_silicon_parameter(); + if (mx27_cpu_rev == -1) + mx27_cpu_rev = mx27_read_cpu_rev(); - if (cpu_partnumber != 0x8821) + if (mx27_cpu_partnumber != 0x8821) return -EINVAL; - return cpu_silicon_rev; + return mx27_cpu_rev; } EXPORT_SYMBOL(mx27_revision); diff --git a/arch/arm/mach-imx/cpu-imx31.c b/arch/arm/mach-imx/cpu-imx31.c index a3780700a88..3f2345f0cda 100644 --- a/arch/arm/mach-imx/cpu-imx31.c +++ b/arch/arm/mach-imx/cpu-imx31.c @@ -13,45 +13,50 @@ #include <linux/io.h> #include <mach/hardware.h> #include <mach/iim.h> +#include <mach/common.h> -unsigned int mx31_cpu_rev; -EXPORT_SYMBOL(mx31_cpu_rev); +static int mx31_cpu_rev = -1; static struct { u8 srev; const char *name; - const char *v; unsigned int rev; -} mx31_cpu_type[] __initdata = { - { .srev = 0x00, .name = "i.MX31(L)", .v = "1.0", .rev = IMX_CHIP_REVISION_1_0 }, - { .srev = 0x10, .name = "i.MX31", .v = "1.1", .rev = IMX_CHIP_REVISION_1_1 }, - { .srev = 0x11, .name = "i.MX31L", .v = "1.1", .rev = IMX_CHIP_REVISION_1_1 }, - { .srev = 0x12, .name = "i.MX31", .v = "1.15", .rev = IMX_CHIP_REVISION_1_1 }, - { .srev = 0x13, .name = "i.MX31L", .v = "1.15", .rev = IMX_CHIP_REVISION_1_1 }, - { .srev = 0x14, .name = "i.MX31", .v = "1.2", .rev = IMX_CHIP_REVISION_1_2 }, - { .srev = 0x15, .name = "i.MX31L", .v = "1.2", .rev = IMX_CHIP_REVISION_1_2 }, - { .srev = 0x28, .name = "i.MX31", .v = "2.0", .rev = IMX_CHIP_REVISION_2_0 }, - { .srev = 0x29, .name = "i.MX31L", .v = "2.0", .rev = IMX_CHIP_REVISION_2_0 }, +} mx31_cpu_type[] = { + { .srev = 0x00, .name = "i.MX31(L)", .rev = IMX_CHIP_REVISION_1_0 }, + { .srev = 0x10, .name = "i.MX31", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x11, .name = "i.MX31L", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x12, .name = "i.MX31", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x13, .name = "i.MX31L", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x14, .name = "i.MX31", .rev = IMX_CHIP_REVISION_1_2 }, + { .srev = 0x15, .name = "i.MX31L", .rev = IMX_CHIP_REVISION_1_2 }, + { .srev = 0x28, .name = "i.MX31", .rev = IMX_CHIP_REVISION_2_0 }, + { .srev = 0x29, .name = "i.MX31L", .rev = IMX_CHIP_REVISION_2_0 }, }; -void __init mx31_read_cpu_rev(void) +static int mx31_read_cpu_rev(void) { u32 i, srev; /* read SREV register from IIM module */ srev = __raw_readl(MX31_IO_ADDRESS(MX31_IIM_BASE_ADDR + MXC_IIMSREV)); + srev &= 0xff; for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++) if (srev == mx31_cpu_type[i].srev) { - printk(KERN_INFO - "CPU identified as %s, silicon rev %s\n", - mx31_cpu_type[i].name, mx31_cpu_type[i].v); - - mx31_cpu_rev = mx31_cpu_type[i].rev; - return; + imx_print_silicon_rev(mx31_cpu_type[i].name, + mx31_cpu_type[i].rev); + return mx31_cpu_type[i].rev; } - mx31_cpu_rev = IMX_CHIP_REVISION_UNKNOWN; + imx_print_silicon_rev("i.MX31", IMX_CHIP_REVISION_UNKNOWN); + return IMX_CHIP_REVISION_UNKNOWN; +} + +int mx31_revision(void) +{ + if (mx31_cpu_rev == -1) + mx31_cpu_rev = mx31_read_cpu_rev(); - printk(KERN_WARNING "Unknown CPU identifier. srev = %02x\n", srev); + return mx31_cpu_rev; } +EXPORT_SYMBOL(mx31_revision); diff --git a/arch/arm/mach-imx/cpu-imx35.c b/arch/arm/mach-imx/cpu-imx35.c index 6637cd819ec..846e46eb8cb 100644 --- a/arch/arm/mach-imx/cpu-imx35.c +++ b/arch/arm/mach-imx/cpu-imx35.c @@ -13,32 +13,30 @@ #include <mach/hardware.h> #include <mach/iim.h> -unsigned int mx35_cpu_rev; -EXPORT_SYMBOL(mx35_cpu_rev); +static int mx35_cpu_rev = -1; -void __init mx35_read_cpu_rev(void) +static int mx35_read_cpu_rev(void) { u32 rev; - char *srev; rev = __raw_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV)); switch (rev) { case 0x00: - mx35_cpu_rev = IMX_CHIP_REVISION_1_0; - srev = "1.0"; - break; + return IMX_CHIP_REVISION_1_0; case 0x10: - mx35_cpu_rev = IMX_CHIP_REVISION_2_0; - srev = "2.0"; - break; + return IMX_CHIP_REVISION_2_0; case 0x11: - mx35_cpu_rev = IMX_CHIP_REVISION_2_1; - srev = "2.1"; - break; + return IMX_CHIP_REVISION_2_1; default: - mx35_cpu_rev = IMX_CHIP_REVISION_UNKNOWN; - srev = "unknown"; + return IMX_CHIP_REVISION_UNKNOWN; } +} + +int mx35_revision(void) +{ + if (mx35_cpu_rev == -1) + mx35_cpu_rev = mx35_read_cpu_rev(); - printk(KERN_INFO "CPU identified as i.MX35, silicon rev %s\n", srev); + return mx35_cpu_rev; } +EXPORT_SYMBOL(mx35_revision); diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h index 7f97a3cdd41..2f727d7c380 100644 --- a/arch/arm/mach-imx/devices-imx27.h +++ b/arch/arm/mach-imx/devices-imx27.h @@ -76,3 +76,7 @@ extern const struct imx_spi_imx_data imx27_cspi_data[]; #define imx27_add_spi_imx0(pdata) imx27_add_cspi(0, pdata) #define imx27_add_spi_imx1(pdata) imx27_add_cspi(1, pdata) #define imx27_add_spi_imx2(pdata) imx27_add_cspi(2, pdata) + +extern const struct imx_pata_imx_data imx27_pata_imx_data; +#define imx27_add_pata_imx() \ + imx_add_pata_imx(&imx27_pata_imx_data) diff --git a/arch/arm/mach-imx/devices-imx31.h b/arch/arm/mach-imx/devices-imx31.h index dbe940d9c53..488e241a6db 100644 --- a/arch/arm/mach-imx/devices-imx31.h +++ b/arch/arm/mach-imx/devices-imx31.h @@ -78,3 +78,7 @@ extern const struct imx_spi_imx_data imx31_cspi_data[]; #define imx31_add_spi_imx0(pdata) imx31_add_cspi(0, pdata) #define imx31_add_spi_imx1(pdata) imx31_add_cspi(1, pdata) #define imx31_add_spi_imx2(pdata) imx31_add_cspi(2, pdata) + +extern const struct imx_pata_imx_data imx31_pata_imx_data; +#define imx31_add_pata_imx() \ + imx_add_pata_imx(&imx31_pata_imx_data) diff --git a/arch/arm/mach-imx/devices-imx35.h b/arch/arm/mach-imx/devices-imx35.h index 234cbd3c18a..7b99ef0bb50 100644 --- a/arch/arm/mach-imx/devices-imx35.h +++ b/arch/arm/mach-imx/devices-imx35.h @@ -81,3 +81,7 @@ extern const struct imx_spi_imx_data imx35_cspi_data[]; imx_add_spi_imx(&imx35_cspi_data[id], pdata) #define imx35_add_spi_imx0(pdata) imx35_add_cspi(0, pdata) #define imx35_add_spi_imx1(pdata) imx35_add_cspi(1, pdata) + +extern const struct imx_pata_imx_data imx35_pata_imx_data; +#define imx35_add_pata_imx() \ + imx_add_pata_imx(&imx35_pata_imx_data) diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c new file mode 100644 index 00000000000..e1537f9e45b --- /dev/null +++ b/arch/arm/mach-imx/gpc.c @@ -0,0 +1,113 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/io.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <asm/hardware/gic.h> + +#define GPC_IMR1 0x008 +#define GPC_PGC_CPU_PDN 0x2a0 + +#define IMR_NUM 4 + +static void __iomem *gpc_base; +static u32 gpc_wake_irqs[IMR_NUM]; +static u32 gpc_saved_imrs[IMR_NUM]; + +void imx_gpc_pre_suspend(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1; + int i; + + /* Tell GPC to power off ARM core when suspend */ + writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN); + + for (i = 0; i < IMR_NUM; i++) { + gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); + writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4); + } +} + +void imx_gpc_post_resume(void) +{ + void __iomem *reg_imr1 = gpc_base + GPC_IMR1; + int i; + + /* Keep ARM core powered on for other low-power modes */ + writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN); + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); +} + +static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) +{ + unsigned int idx = d->irq / 32 - 1; + u32 mask; + + /* Sanity check for SPI irq */ + if (d->irq < 32) + return -EINVAL; + + mask = 1 << d->irq % 32; + gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : + gpc_wake_irqs[idx] & ~mask; + + return 0; +} + +static void imx_gpc_irq_unmask(struct irq_data *d) +{ + void __iomem *reg; + u32 val; + + /* Sanity check for SPI irq */ + if (d->irq < 32) + return; + + reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4; + val = readl_relaxed(reg); + val &= ~(1 << d->irq % 32); + writel_relaxed(val, reg); +} + +static void imx_gpc_irq_mask(struct irq_data *d) +{ + void __iomem *reg; + u32 val; + + /* Sanity check for SPI irq */ + if (d->irq < 32) + return; + + reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4; + val = readl_relaxed(reg); + val |= 1 << (d->irq % 32); + writel_relaxed(val, reg); +} + +void __init imx_gpc_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); + gpc_base = of_iomap(np, 0); + WARN_ON(!gpc_base); + + /* Register GPC as the secondary interrupt controller behind GIC */ + gic_arch_extn.irq_mask = imx_gpc_irq_mask; + gic_arch_extn.irq_unmask = imx_gpc_irq_unmask; + gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake; +} diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S new file mode 100644 index 00000000000..6229efbc70c --- /dev/null +++ b/arch/arm/mach-imx/head-v7.S @@ -0,0 +1,99 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/linkage.h> +#include <linux/init.h> +#include <asm/asm-offsets.h> +#include <asm/hardware/cache-l2x0.h> + + .section ".text.head", "ax" + __CPUINIT + +/* + * The secondary kernel init calls v7_flush_dcache_all before it enables + * the L1; however, the L1 comes out of reset in an undefined state, so + * the clean + invalidate performed by v7_flush_dcache_all causes a bunch + * of cache lines with uninitialized data and uninitialized tags to get + * written out to memory, which does really unpleasant things to the main + * processor. We fix this by performing an invalidate, rather than a + * clean + invalidate, before jumping into the kernel. + * + * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs + * to be called for both secondary cores startup and primary core resume + * procedures. Ideally, it should be moved into arch/arm/mm/cache-v7.S. + */ +ENTRY(v7_invalidate_l1) + mov r0, #0 + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: subs r3, r3, #1 @ Temp-- + mov r5, r3, lsl r1 + mov r6, r2, lsl r0 + orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift) + mcr p15, 0, r5, c7, c6, 2 + bgt 2b + cmp r2, #0 + bgt 1b + dsb + isb + mov pc, lr +ENDPROC(v7_invalidate_l1) + +#ifdef CONFIG_SMP +ENTRY(v7_secondary_startup) + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(v7_secondary_startup) +#endif + +/* + * The following code is located into the .data section. This is to + * allow phys_l2x0_saved_regs to be accessed with a relative load + * as we are running on physical address here. + */ + .data + .align + + .macro pl310_resume + ldr r2, phys_l2x0_saved_regs + ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 + ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value + str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl + mov r1, #0x1 + str r1, [r0, #L2X0_CTRL] @ re-enable L2 + .endm + +ENTRY(v7_cpu_resume) + bl v7_invalidate_l1 + pl310_resume + b cpu_resume +ENDPROC(v7_cpu_resume) + + .globl phys_l2x0_saved_regs +phys_l2x0_saved_regs: + .long 0 diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c new file mode 100644 index 00000000000..89493abd497 --- /dev/null +++ b/arch/arm/mach-imx/hotplug.c @@ -0,0 +1,44 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/errno.h> +#include <asm/cacheflush.h> +#include <mach/common.h> + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ + flush_cache_all(); + imx_enable_cpu(cpu, false); + cpu_do_idle(); + + /* We should never return from idle */ + panic("cpu %d unexpectedly exit from shutdown\n", cpu); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-imx/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c index cf8f8099ebd..82bd4403b45 100644 --- a/arch/arm/mach-imx/iomux-imx31.c +++ b/arch/arm/mach-imx/iomux-imx31.c @@ -17,13 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - +#include <linux/gpio.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/io.h> #include <linux/kernel.h> #include <mach/hardware.h> -#include <mach/gpio.h> #include <mach/iomux-mx3.h> /* diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c new file mode 100644 index 00000000000..d4ab6f29a76 --- /dev/null +++ b/arch/arm/mach-imx/lluart.c @@ -0,0 +1,32 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <asm/page.h> +#include <asm/sizes.h> +#include <asm/mach/map.h> +#include <mach/hardware.h> + +static struct map_desc imx_lluart_desc = { +#ifdef CONFIG_DEBUG_IMX6Q_UART + .virtual = MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR), + .pfn = __phys_to_pfn(MX6Q_UART4_BASE_ADDR), + .length = MX6Q_UART4_SIZE, + .type = MT_DEVICE, +#endif +}; + +void __init imx_lluart_map_io(void) +{ + if (imx_lluart_desc.virtual) + iotable_init(&imx_lluart_desc, 1); +} diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c new file mode 100644 index 00000000000..3a163515d41 --- /dev/null +++ b/arch/arm/mach-imx/localtimer.c @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/clockchips.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <asm/smp_twd.h> + +/* + * Setup the local clock events for a CPU. + */ +int __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "arm,smp-twd"); + if (!twd_base) { + twd_base = of_iomap(np, 0); + WARN_ON(!twd_base); + } + evt->irq = irq_of_parse_and_map(np, 0); + twd_timer_setup(evt); + + return 0; +} diff --git a/arch/arm/mach-imx/mach-apf9328.c b/arch/arm/mach-imx/mach-apf9328.c index a404c89485c..1e486e67dab 100644 --- a/arch/arm/mach-imx/mach-apf9328.c +++ b/arch/arm/mach-imx/mach-apf9328.c @@ -136,6 +136,7 @@ MACHINE_START(APF9328, "Armadeus APF9328") .map_io = mx1_map_io, .init_early = imx1_init_early, .init_irq = mx1_init_irq, + .handle_irq = imx1_handle_irq, .timer = &apf9328_timer, .init_machine = apf9328_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c index ede2710f8b7..c9a9cf67755 100644 --- a/arch/arm/mach-imx/mach-armadillo5x0.c +++ b/arch/arm/mach-imx/mach-armadillo5x0.c @@ -314,25 +314,19 @@ static struct mtd_partition armadillo5x0_nor_flash_partitions[] = { }, }; -static struct physmap_flash_data armadillo5x0_nor_flash_pdata = { +static const struct physmap_flash_data + armadillo5x0_nor_flash_pdata __initconst = { .width = 2, .parts = armadillo5x0_nor_flash_partitions, .nr_parts = ARRAY_SIZE(armadillo5x0_nor_flash_partitions), }; -static struct resource armadillo5x0_nor_flash_resource = { +static const struct resource armadillo5x0_nor_flash_resource __initconst = { .flags = IORESOURCE_MEM, .start = MX31_CS0_BASE_ADDR, .end = MX31_CS0_BASE_ADDR + SZ_64M - 1, }; -static struct platform_device armadillo5x0_nor_flash = { - .name = "physmap-flash", - .id = -1, - .num_resources = 1, - .resource = &armadillo5x0_nor_flash_resource, -}; - /* * FB support */ @@ -514,8 +508,10 @@ static void __init armadillo5x0_init(void) imx31_add_mx3_sdc_fb(&mx3fb_pdata); /* Register NOR Flash */ - mxc_register_device(&armadillo5x0_nor_flash, - &armadillo5x0_nor_flash_pdata); + platform_device_register_resndata(NULL, "physmap-flash", -1, + &armadillo5x0_nor_flash_resource, 1, + &armadillo5x0_nor_flash_pdata, + sizeof(armadillo5x0_nor_flash_pdata)); /* Register NAND Flash */ imx31_add_mxc_nand(&armadillo5x0_nand_board_info); @@ -558,10 +554,11 @@ static struct sys_timer armadillo5x0_timer = { MACHINE_START(ARMADILLO5X0, "Armadillo-500") /* Maintainer: Alberto Panizzo */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &armadillo5x0_timer, .init_machine = armadillo5x0_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-bug.c b/arch/arm/mach-imx/mach-bug.c index f49470553bd..313f62ddc1e 100644 --- a/arch/arm/mach-imx/mach-bug.c +++ b/arch/arm/mach-imx/mach-bug.c @@ -62,6 +62,7 @@ MACHINE_START(BUG, "BugLabs BUGBase") .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &bug_timer, .init_machine = bug_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c index f851fe90368..edb37305257 100644 --- a/arch/arm/mach-imx/mach-cpuimx27.c +++ b/arch/arm/mach-imx/mach-cpuimx27.c @@ -311,10 +311,11 @@ static struct sys_timer eukrea_cpuimx27_timer = { }; MACHINE_START(EUKREA_CPUIMX27, "EUKREA CPUIMX27") - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &eukrea_cpuimx27_timer, .init_machine = eukrea_cpuimx27_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c index 4bd083ba9af..66af2e8f7e5 100644 --- a/arch/arm/mach-imx/mach-cpuimx35.c +++ b/arch/arm/mach-imx/mach-cpuimx35.c @@ -66,7 +66,7 @@ static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = { I2C_BOARD_INFO("tsc2007", 0x48), .type = "tsc2007", .platform_data = &tsc2007_info, - .irq = gpio_to_irq(TSC2007_IRQGPIO), + .irq = IMX_GPIO_TO_IRQ(TSC2007_IRQGPIO), }, }; @@ -194,10 +194,11 @@ struct sys_timer eukrea_cpuimx35_timer = { MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35") /* Maintainer: Eukrea Electromatique */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx35_map_io, .init_early = imx35_init_early, .init_irq = mx35_init_irq, + .handle_irq = imx35_handle_irq, .timer = &eukrea_cpuimx35_timer, .init_machine = eukrea_cpuimx35_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c index 2442d5da883..ab8fbcc472b 100644 --- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c +++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c @@ -163,10 +163,11 @@ static struct sys_timer eukrea_cpuimx25_timer = { MACHINE_START(EUKREA_CPUIMX25SD, "Eukrea CPUIMX25") /* Maintainer: Eukrea Electromatique */ - .boot_params = MX25_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx25_map_io, .init_early = imx25_init_early, .init_irq = mx25_init_irq, + .handle_irq = imx25_handle_irq, .timer = &eukrea_cpuimx25_timer, .init_machine = eukrea_cpuimx25_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c index 6778f8193bc..38eb9e45110 100644 --- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@ -275,10 +275,11 @@ static struct sys_timer visstrim_m10_timer = { }; MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10") - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &visstrim_m10_timer, .init_machine = visstrim_m10_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx27ipcam.c b/arch/arm/mach-imx/mach-imx27ipcam.c index 272f793e924..7052155d055 100644 --- a/arch/arm/mach-imx/mach-imx27ipcam.c +++ b/arch/arm/mach-imx/mach-imx27ipcam.c @@ -71,10 +71,11 @@ static struct sys_timer mx27ipcam_timer = { MACHINE_START(IMX27IPCAM, "Freescale IMX27IPCAM") /* maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &mx27ipcam_timer, .init_machine = mx27ipcam_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx27lite.c b/arch/arm/mach-imx/mach-imx27lite.c index d81a769fe89..8d6a63521f1 100644 --- a/arch/arm/mach-imx/mach-imx27lite.c +++ b/arch/arm/mach-imx/mach-imx27lite.c @@ -77,10 +77,11 @@ static struct sys_timer mx27lite_timer = { }; MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE") - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &mx27lite_timer, .init_machine = mx27lite_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c new file mode 100644 index 00000000000..8bf5fa34948 --- /dev/null +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -0,0 +1,84 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/hardware/gic.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/common.h> +#include <mach/hardware.h> + +static void __init imx6q_init_machine(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + imx6q_pm_init(); +} + +static void __init imx6q_map_io(void) +{ + imx_lluart_map_io(); + imx_scu_map_io(); +} + +static void __init imx6q_gpio_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS - + 32 * 7; /* imx6q gets 7 gpio ports */ + + irq_domain_add_simple(np, gpio_irq_base); + gpio_irq_base += 32; +} + +static const struct of_device_id imx6q_irq_match[] __initconst = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + { .compatible = "fsl,imx6q-gpio", .data = imx6q_gpio_add_irq_domain, }, + { /* sentinel */ } +}; + +static void __init imx6q_init_irq(void) +{ + l2x0_of_init(0, ~0UL); + imx_src_init(); + imx_gpc_init(); + of_irq_init(imx6q_irq_match); +} + +static void __init imx6q_timer_init(void) +{ + mx6q_clocks_init(); +} + +static struct sys_timer imx6q_timer = { + .init = imx6q_timer_init, +}; + +static const char *imx6q_dt_compat[] __initdata = { + "fsl,imx6q-sabreauto", + NULL, +}; + +DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)") + .map_io = imx6q_map_io, + .init_irq = imx6q_init_irq, + .handle_irq = imx6q_handle_irq, + .timer = &imx6q_timer, + .init_machine = imx6q_init_machine, + .dt_compat = imx6q_dt_compat, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c index e472a1d8805..5f37f89e40f 100644 --- a/arch/arm/mach-imx/mach-kzm_arm11_01.c +++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c @@ -36,6 +36,7 @@ #include <mach/clock.h> #include <mach/common.h> +#include <mach/hardware.h> #include <mach/iomux-mx3.h> #include "devices-imx31.h" @@ -271,10 +272,11 @@ static struct sys_timer kzm_timer = { }; MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01") - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = kzm_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &kzm_timer, .init_machine = kzm_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c index 5cd8bee4696..fc49785e734 100644 --- a/arch/arm/mach-imx/mach-mx1ads.c +++ b/arch/arm/mach-imx/mach-mx1ads.c @@ -68,23 +68,16 @@ static const struct imxuart_platform_data uart1_pdata __initconst = { * Physmap flash */ -static struct physmap_flash_data mx1ads_flash_data = { +static const struct physmap_flash_data mx1ads_flash_data __initconst = { .width = 4, /* bankwidth in bytes */ }; -static struct resource flash_resource = { +static const struct resource flash_resource __initconst = { .start = MX1_CS0_PHYS, .end = MX1_CS0_PHYS + SZ_32M - 1, .flags = IORESOURCE_MEM, }; -static struct platform_device flash_device = { - .name = "physmap-flash", - .id = 0, - .resource = &flash_resource, - .num_resources = 1, -}; - /* * I2C */ @@ -125,7 +118,9 @@ static void __init mx1ads_init(void) imx1_add_imx_uart1(&uart1_pdata); /* Physmap flash */ - mxc_register_device(&flash_device, &mx1ads_flash_data); + platform_device_register_resndata(NULL, "physmap-flash", 0, + &flash_resource, 1, + &mx1ads_flash_data, sizeof(mx1ads_flash_data)); /* I2C */ i2c_register_board_info(0, mx1ads_i2c_devices, @@ -145,19 +140,21 @@ struct sys_timer mx1ads_timer = { MACHINE_START(MX1ADS, "Freescale MX1ADS") /* Maintainer: Sascha Hauer, Pengutronix */ - .boot_params = MX1_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx1_map_io, .init_early = imx1_init_early, .init_irq = mx1_init_irq, + .handle_irq = imx1_handle_irq, .timer = &mx1ads_timer, .init_machine = mx1ads_init, MACHINE_END MACHINE_START(MXLADS, "Freescale MXLADS") - .boot_params = MX1_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx1_map_io, .init_early = imx1_init_early, .init_irq = mx1_init_irq, + .handle_irq = imx1_handle_irq, .timer = &mx1ads_timer, .init_machine = mx1ads_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c index d389ecf9b5a..25f84028d05 100644 --- a/arch/arm/mach-imx/mach-mx21ads.c +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -305,10 +305,11 @@ static struct sys_timer mx21ads_timer = { MACHINE_START(MX21ADS, "Freescale i.MX21ADS") /* maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX21_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx21ads_map_io, .init_early = imx21_init_early, .init_irq = mx21_init_irq, + .handle_irq = imx21_handle_irq, .timer = &mx21ads_timer, .init_machine = mx21ads_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c index 7f66a91df36..88dccf12224 100644 --- a/arch/arm/mach-imx/mach-mx25_3ds.c +++ b/arch/arm/mach-imx/mach-mx25_3ds.c @@ -43,6 +43,8 @@ #include "devices-imx25.h" +#define MX25PDK_CAN_PWDN IMX_GPIO_NR(4, 6) + static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; @@ -108,6 +110,11 @@ static iomux_v3_cfg_t mx25pdk_pads[] = { /* I2C1 */ MX25_PAD_I2C1_CLK__I2C1_CLK, MX25_PAD_I2C1_DAT__I2C1_DAT, + + /* CAN1 */ + MX25_PAD_GPIO_A__CAN1_TX, + MX25_PAD_GPIO_B__CAN1_RX, + MX25_PAD_D14__GPIO_4_6, /* CAN_PWDN */ }; static const struct fec_platform_data mx25_fec_pdata __initconst = { @@ -240,6 +247,9 @@ static void __init mx25pdk_init(void) imx25_add_sdhci_esdhc_imx(0, &mx25pdk_esdhc_pdata); imx25_add_imx_i2c0(&mx25_3ds_i2c0_data); + + gpio_request_one(MX25PDK_CAN_PWDN, GPIOF_OUT_INIT_LOW, "can-pwdn"); + imx25_add_flexcan0(NULL); } static void __init mx25pdk_timer_init(void) @@ -253,10 +263,11 @@ static struct sys_timer mx25pdk_timer = { MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)") /* Maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX25_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx25_map_io, .init_early = imx25_init_early, .init_irq = mx25_init_irq, + .handle_irq = imx25_handle_irq, .timer = &mx25pdk_timer, .init_machine = mx25pdk_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c index 6fa6934ab15..ba232d79fa8 100644 --- a/arch/arm/mach-imx/mach-mx27_3ds.c +++ b/arch/arm/mach-imx/mach-mx27_3ds.c @@ -241,7 +241,7 @@ static struct regulator_init_data gpo_init = { }; static struct regulator_consumer_supply vmmc1_consumers[] = { - REGULATOR_SUPPLY("lcd_2v8", NULL), + REGULATOR_SUPPLY("vcore", "spi0.0"), }; static struct regulator_init_data vmmc1_init = { @@ -257,7 +257,7 @@ static struct regulator_init_data vmmc1_init = { }; static struct regulator_consumer_supply vgen_consumers[] = { - REGULATOR_SUPPLY("vdd_lcdio", NULL), + REGULATOR_SUPPLY("vdd", "spi0.0"), }; static struct regulator_init_data vgen_init = { @@ -293,8 +293,7 @@ static struct mc13xxx_platform_data mc13783_pdata = { .num_regulators = ARRAY_SIZE(mx27_3ds_regulators), }, - .flags = MC13783_USE_REGULATOR | MC13783_USE_TOUCHSCREEN | - MC13783_USE_RTC, + .flags = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC, }; /* SPI */ @@ -348,8 +347,6 @@ static const struct imx_fb_platform_data mx27_3ds_fb_data __initconst = { static struct l4f00242t03_pdata mx27_3ds_lcd_pdata = { .reset_gpio = LCD_RESET, .data_enable_gpio = LCD_ENABLE, - .core_supply = "lcd_2v8", - .io_supply = "vdd_lcdio", }; static struct spi_board_info mx27_3ds_spi_devs[] __initdata = { @@ -359,7 +356,7 @@ static struct spi_board_info mx27_3ds_spi_devs[] __initdata = { .bus_num = 1, .chip_select = 0, /* SS0 */ .platform_data = &mc13783_pdata, - .irq = gpio_to_irq(PMIC_INT), + .irq = IMX_GPIO_TO_IRQ(PMIC_INT), .mode = SPI_CS_HIGH, }, { .modalias = "l4f00242t03", @@ -421,10 +418,11 @@ static struct sys_timer mx27pdk_timer = { MACHINE_START(MX27_3DS, "Freescale MX27PDK") /* maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &mx27pdk_timer, .init_machine = mx27pdk_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c index fc26ed71b9e..74dd5731eb6 100644 --- a/arch/arm/mach-imx/mach-mx27ads.c +++ b/arch/arm/mach-imx/mach-mx27ads.c @@ -13,7 +13,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ - +#include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -27,7 +27,6 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <asm/mach/map.h> -#include <mach/gpio.h> #include <mach/iomux-mx27.h> #include "devices-imx27.h" @@ -345,10 +344,11 @@ static void __init mx27ads_map_io(void) MACHINE_START(MX27ADS, "Freescale i.MX27ADS") /* maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27ads_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &mx27ads_timer, .init_machine = mx27ads_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index c20be753092..b8c54b84018 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -285,8 +285,6 @@ static struct mx3fb_platform_data mx3fb_pdata __initdata = { static struct l4f00242t03_pdata mx31_3ds_l4f00242t03_pdata = { .reset_gpio = IOMUX_TO_GPIO(MX31_PIN_LCS1), .data_enable_gpio = IOMUX_TO_GPIO(MX31_PIN_SER_RS), - .core_supply = "lcd_2v8", - .io_supply = "vdd_lcdio", }; /* @@ -411,7 +409,7 @@ static struct regulator_init_data vmmc2_init = { }; static struct regulator_consumer_supply vmmc1_consumers[] = { - REGULATOR_SUPPLY("lcd_2v8", NULL), + REGULATOR_SUPPLY("vcore", "spi0.0"), REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"), }; @@ -428,7 +426,7 @@ static struct regulator_init_data vmmc1_init = { }; static struct regulator_consumer_supply vgen_consumers[] = { - REGULATOR_SUPPLY("vdd_lcdio", NULL), + REGULATOR_SUPPLY("vdd", "spi0.0"), }; static struct regulator_init_data vgen_init = { @@ -494,7 +492,7 @@ static struct mc13xxx_platform_data mc13783_pdata = { .regulators = mx31_3ds_regulators, .num_regulators = ARRAY_SIZE(mx31_3ds_regulators), }, - .flags = MC13783_USE_REGULATOR | MC13783_USE_TOUCHSCREEN, + .flags = MC13XXX_USE_TOUCHSCREEN, }; /* SPI */ @@ -542,7 +540,7 @@ static const struct mxc_nand_platform_data mx31_3ds_nand_board_info __initconst = { .width = 1, .hw_ecc = 1, -#ifdef MACH_MX31_3DS_MXC_NAND_USE_BBT +#ifdef CONFIG_MACH_MX31_3DS_MXC_NAND_USE_BBT .flash_bbt = 1, #endif }; @@ -764,10 +762,11 @@ static void __init mx31_3ds_reserve(void) MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)") /* Maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &mx31_3ds_timer, .init_machine = mx31_3ds_init, .reserve = mx31_3ds_reserve, diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c index 29ca8907a78..9cc1a49053b 100644 --- a/arch/arm/mach-imx/mach-mx31ads.c +++ b/arch/arm/mach-imx/mach-mx31ads.c @@ -535,10 +535,11 @@ static struct sys_timer mx31ads_timer = { MACHINE_START(MX31ADS, "Freescale MX31ADS") /* Maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx31ads_map_io, .init_early = imx31_init_early, .init_irq = mx31ads_init_irq, + .handle_irq = imx31_handle_irq, .timer = &mx31ads_timer, .init_machine = mx31ads_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c index 126913ad106..5defd8e70fc 100644 --- a/arch/arm/mach-imx/mach-mx31lilly.c +++ b/arch/arm/mach-imx/mach-mx31lilly.c @@ -295,10 +295,11 @@ static struct sys_timer mx31lilly_timer = { }; MACHINE_START(LILLY1131, "INCO startec LILLY-1131") - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &mx31lilly_timer, .init_machine = mx31lilly_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c index 4b47fd9fdd8..05f1c71ba40 100644 --- a/arch/arm/mach-imx/mach-mx31lite.c +++ b/arch/arm/mach-imx/mach-mx31lite.c @@ -112,8 +112,7 @@ static const struct spi_imx_master spi1_pdata __initconst = { }; static struct mc13xxx_platform_data mc13783_pdata __initdata = { - .flags = MC13XXX_USE_RTC | - MC13XXX_USE_REGULATOR, + .flags = MC13XXX_USE_RTC, }; static struct spi_board_info mc13783_spi_dev __initdata = { @@ -280,10 +279,11 @@ struct sys_timer mx31lite_timer = { MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM") /* Maintainer: Freescale Semiconductor, Inc. */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx31lite_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &mx31lite_timer, .init_machine = mx31lite_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index b358383120e..07034f44466 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -28,6 +28,10 @@ #include <linux/spi/spi.h> #include <linux/types.h> #include <linux/memblock.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/input.h> #include <linux/usb/otg.h> #include <linux/usb/ulpi.h> @@ -222,7 +226,7 @@ static struct mc13xxx_regulator_init_data moboard_regulators[] = { }, }; -static struct mc13783_led_platform_data moboard_led[] = { +static struct mc13xxx_led_platform_data moboard_led[] = { { .id = MC13783_LED_R1, .name = "coreboard-led-4:red", @@ -255,7 +259,7 @@ static struct mc13783_led_platform_data moboard_led[] = { }, }; -static struct mc13783_leds_platform_data moboard_leds = { +static struct mc13xxx_leds_platform_data moboard_leds = { .num_leds = ARRAY_SIZE(moboard_led), .led = moboard_led, .flags = MC13783_LED_SLEWLIMTC, @@ -264,14 +268,20 @@ static struct mc13783_leds_platform_data moboard_leds = { .tc2_period = MC13783_LED_PERIOD_10MS, }; +static struct mc13xxx_buttons_platform_data moboard_buttons = { + .b1on_flags = MC13783_BUTTON_DBNC_750MS | MC13783_BUTTON_ENABLE | + MC13783_BUTTON_POL_INVERT, + .b1on_key = KEY_POWER, +}; + static struct mc13xxx_platform_data moboard_pmic = { .regulators = { .regulators = moboard_regulators, .num_regulators = ARRAY_SIZE(moboard_regulators), }, .leds = &moboard_leds, - .flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_RTC | - MC13XXX_USE_ADC | MC13XXX_USE_LED, + .buttons = &moboard_buttons, + .flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC, }; static struct spi_board_info moboard_spi_board_info[] __initdata = { @@ -490,6 +500,18 @@ err: } +static void mx31moboard_poweroff(void) +{ + struct clk *clk = clk_get_sys("imx2-wdt.0", NULL); + + if (!IS_ERR(clk)) + clk_enable(clk); + + mxc_iomux_mode(MX31_PIN_WATCHDOG_RST__WATCHDOG_RST); + + __raw_writew(1 << 6 | 1 << 2, MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); +} + static int mx31moboard_baseboard; core_param(mx31moboard_baseboard, mx31moboard_baseboard, int, 0444); @@ -528,6 +550,8 @@ static void __init mx31moboard_init(void) moboard_usbh2_init(); + pm_power_off = mx31moboard_poweroff; + switch (mx31moboard_baseboard) { case MX31NOBOARD: break; @@ -567,11 +591,12 @@ static void __init mx31moboard_reserve(void) MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard") /* Maintainer: Valentin Longchamp, EPFL Mobots group */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .reserve = mx31moboard_reserve, .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &mx31moboard_timer, .init_machine = mx31moboard_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c index b3b9bd8ac2a..7a462025a0f 100644 --- a/arch/arm/mach-imx/mach-mx35_3ds.c +++ b/arch/arm/mach-imx/mach-mx35_3ds.c @@ -217,10 +217,11 @@ struct sys_timer mx35pdk_timer = { MACHINE_START(MX35_3DS, "Freescale MX35PDK") /* Maintainer: Freescale Semiconductor, Inc */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx35_map_io, .init_early = imx35_init_early, .init_irq = mx35_init_irq, + .handle_irq = imx35_handle_irq, .timer = &mx35pdk_timer, .init_machine = mx35_3ds_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mxt_td60.c b/arch/arm/mach-imx/mach-mxt_td60.c index c85876fed66..125c19643b0 100644 --- a/arch/arm/mach-imx/mach-mxt_td60.c +++ b/arch/arm/mach-imx/mach-mxt_td60.c @@ -267,10 +267,11 @@ static struct sys_timer mxt_td60_timer = { MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60") /* maintainer: Maxtrack Industrial */ - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &mxt_td60_timer, .init_machine = mxt_td60_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c index 71083aa1603..26072f4b02e 100644 --- a/arch/arm/mach-imx/mach-pca100.c +++ b/arch/arm/mach-imx/mach-pca100.c @@ -435,10 +435,11 @@ static struct sys_timer pca100_timer = { }; MACHINE_START(PCA100, "phyCARD-i.MX27") - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .init_machine = pca100_init, .timer = &pca100_timer, MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index f45b7cd72c8..efd6b536ef6 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -688,11 +688,12 @@ static void __init pcm037_reserve(void) MACHINE_START(PCM037, "Phytec Phycore pcm037") /* Maintainer: Pengutronix */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .reserve = pcm037_reserve, .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &pcm037_timer, .init_machine = pcm037_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c index 2d6a64bbac4..a17e9c7dfca 100644 --- a/arch/arm/mach-imx/mach-pcm038.c +++ b/arch/arm/mach-imx/mach-pcm038.c @@ -176,7 +176,9 @@ static struct platform_device *platform_devices[] __initdata = { * setup other stuffs to access the sram. */ static void __init pcm038_init_sram(void) { - mx27_setup_weimcs(1, 0x0000d843, 0x22252521, 0x22220a00); + __raw_writel(0x0000d843, MX27_IO_ADDRESS(MX27_WEIM_CSCRxU(1))); + __raw_writel(0x22252521, MX27_IO_ADDRESS(MX27_WEIM_CSCRxL(1))); + __raw_writel(0x22220a00, MX27_IO_ADDRESS(MX27_WEIM_CSCRxA(1))); } static const struct imxi2c_platform_data pcm038_i2c1_data __initconst = { @@ -266,8 +268,7 @@ static struct mc13xxx_platform_data pcm038_pmic = { .regulators = pcm038_regulators, .num_regulators = ARRAY_SIZE(pcm038_regulators), }, - .flags = MC13783_USE_ADC | MC13783_USE_REGULATOR | - MC13783_USE_TOUCHSCREEN, + .flags = MC13XXX_USE_ADC | MC13XXX_USE_TOUCHSCREEN, }; static struct spi_board_info pcm038_spi_board_info[] __initdata = { @@ -349,10 +350,11 @@ static struct sys_timer pcm038_timer = { }; MACHINE_START(PCM038, "phyCORE-i.MX27") - .boot_params = MX27_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx27_map_io, .init_early = imx27_init_early, .init_irq = mx27_init_irq, + .handle_irq = imx27_handle_irq, .timer = &pcm038_timer, .init_machine = pcm038_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c index 660ec3e80cf..7366c2ae3ea 100644 --- a/arch/arm/mach-imx/mach-pcm043.c +++ b/arch/arm/mach-imx/mach-pcm043.c @@ -418,10 +418,11 @@ struct sys_timer pcm043_timer = { MACHINE_START(PCM043, "Phytec Phycore pcm043") /* Maintainer: Pengutronix */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx35_map_io, .init_early = imx35_init_early, .init_irq = mx35_init_irq, + .handle_irq = imx35_handle_irq, .timer = &pcm043_timer, .init_machine = pcm043_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c index 3626f486498..4ff5faf102a 100644 --- a/arch/arm/mach-imx/mach-qong.c +++ b/arch/arm/mach-imx/mach-qong.c @@ -190,7 +190,10 @@ static struct platform_device qong_nand_device = { static void __init qong_init_nand_mtd(void) { /* init CS */ - mx31_setup_weimcs(3, 0x00004f00, 0x20013b31, 0x00020800); + __raw_writel(0x00004f00, MX31_IO_ADDRESS(MX31_WEIM_CSCRxU(3))); + __raw_writel(0x20013b31, MX31_IO_ADDRESS(MX31_WEIM_CSCRxL(3))); + __raw_writel(0x00020800, MX31_IO_ADDRESS(MX31_WEIM_CSCRxA(3))); + mxc_iomux_set_gpr(MUX_SDCTL_CSD1_SEL, true); /* enable pin */ @@ -249,6 +252,7 @@ static void __init qong_init(void) mxc_init_imx_uart(); qong_init_nor_mtd(); qong_init_fpga(); + imx31_add_imx2_wdt(NULL); } static void __init qong_timer_init(void) @@ -262,10 +266,11 @@ static struct sys_timer qong_timer = { MACHINE_START(QONG, "Dave/DENX QongEVB-LITE") /* Maintainer: DENX Software Engineering GmbH */ - .boot_params = MX3x_PHYS_OFFSET + 0x100, + .atag_offset = 0x100, .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, + .handle_irq = imx31_handle_irq, .timer = &qong_timer, .init_machine = qong_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-scb9328.c b/arch/arm/mach-imx/mach-scb9328.c index db2d60470e1..bb6e5b25d8d 100644 --- a/arch/arm/mach-imx/mach-scb9328.c +++ b/arch/arm/mach-imx/mach-scb9328.c @@ -137,10 +137,11 @@ static struct sys_timer scb9328_timer = { MACHINE_START(SCB9328, "Synertronixx scb9328") /* Sascha Hauer */ - .boot_params = 0x08000100, + .atag_offset = 100, .map_io = mx1_map_io, .init_early = imx1_init_early, .init_irq = mx1_init_irq, + .handle_irq = imx1_handle_irq, .timer = &scb9328_timer, .init_machine = scb9328_init, MACHINE_END diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c index 7d8e012a633..69092458f2d 100644 --- a/arch/arm/mach-imx/mach-vpr200.c +++ b/arch/arm/mach-imx/mach-vpr200.c @@ -162,7 +162,7 @@ static struct i2c_board_info vpr200_i2c_devices[] = { }, { I2C_BOARD_INFO("mc13892", 0x08), .platform_data = &vpr200_pmic, - .irq = gpio_to_irq(GPIO_PMIC_INT), + .irq = IMX_GPIO_TO_IRQ(GPIO_PMIC_INT), } }; @@ -319,6 +319,7 @@ MACHINE_START(VPR200, "VPR200") .map_io = mx35_map_io, .init_early = imx35_init_early, .init_irq = mx35_init_irq, + .handle_irq = imx35_handle_irq, .timer = &vpr200_timer, .init_machine = vpr200_board_init, MACHINE_END diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c new file mode 100644 index 00000000000..9f0e82ec339 --- /dev/null +++ b/arch/arm/mach-imx/mm-imx3.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 1999,2000 Arm Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * - add MX31 specific definitions + * + * 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. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/err.h> + +#include <asm/pgtable.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/mach/map.h> + +#include <mach/common.h> +#include <mach/devices-common.h> +#include <mach/hardware.h> +#include <mach/iomux-v3.h> +#include <mach/irqs.h> + +static void imx3_idle(void) +{ + unsigned long reg = 0; + __asm__ __volatile__( + /* disable I and D cache */ + "mrc p15, 0, %0, c1, c0, 0\n" + "bic %0, %0, #0x00001000\n" + "bic %0, %0, #0x00000004\n" + "mcr p15, 0, %0, c1, c0, 0\n" + /* invalidate I cache */ + "mov %0, #0\n" + "mcr p15, 0, %0, c7, c5, 0\n" + /* clear and invalidate D cache */ + "mov %0, #0\n" + "mcr p15, 0, %0, c7, c14, 0\n" + /* WFI */ + "mov %0, #0\n" + "mcr p15, 0, %0, c7, c0, 4\n" + "nop\n" "nop\n" "nop\n" "nop\n" + "nop\n" "nop\n" "nop\n" + /* enable I and D cache */ + "mrc p15, 0, %0, c1, c0, 0\n" + "orr %0, %0, #0x00001000\n" + "orr %0, %0, #0x00000004\n" + "mcr p15, 0, %0, c1, c0, 0\n" + : "=r" (reg)); +} + +static void __iomem *imx3_ioremap(unsigned long phys_addr, size_t size, + unsigned int mtype) +{ + if (mtype == MT_DEVICE) { + /* + * Access all peripherals below 0x80000000 as nonshared device + * on mx3, but leave l2cc alone. Otherwise cache corruptions + * can occur. + */ + if (phys_addr < 0x80000000 && + !addr_in_module(phys_addr, MX3x_L2CC)) + mtype = MT_DEVICE_NONSHARED; + } + + return __arm_ioremap(phys_addr, size, mtype); +} + +void imx3_init_l2x0(void) +{ + void __iomem *l2x0_base; + void __iomem *clkctl_base; + +/* + * First of all, we must repair broken chip settings. There are some + * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These + * misconfigured CPUs will run amok immediately when the L2 cache gets enabled. + * Workaraound is to setup the correct register setting prior enabling the + * L2 cache. This should not hurt already working CPUs, as they are using the + * same value. + */ +#define L2_MEM_VAL 0x10 + + clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096); + if (clkctl_base != NULL) { + writel(0x00000515, clkctl_base + L2_MEM_VAL); + iounmap(clkctl_base); + } else { + pr_err("L2 cache: Cannot fix timing. Trying to continue without\n"); + } + + l2x0_base = ioremap(MX3x_L2CC_BASE_ADDR, 4096); + if (IS_ERR(l2x0_base)) { + printk(KERN_ERR "remapping L2 cache area failed with %ld\n", + PTR_ERR(l2x0_base)); + return; + } + + l2x0_init(l2x0_base, 0x00030024, 0x00000000); +} + +static struct map_desc mx31_io_desc[] __initdata = { + imx_map_entry(MX31, X_MEMC, MT_DEVICE), + imx_map_entry(MX31, AVIC, MT_DEVICE_NONSHARED), + imx_map_entry(MX31, AIPS1, MT_DEVICE_NONSHARED), + imx_map_entry(MX31, AIPS2, MT_DEVICE_NONSHARED), + imx_map_entry(MX31, SPBA0, MT_DEVICE_NONSHARED), +}; + +/* + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory mappings + * for the IO modules. + */ +void __init mx31_map_io(void) +{ + iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc)); +} + +static struct map_desc mx35_io_desc[] __initdata = { + imx_map_entry(MX35, X_MEMC, MT_DEVICE), + imx_map_entry(MX35, AVIC, MT_DEVICE_NONSHARED), + imx_map_entry(MX35, AIPS1, MT_DEVICE_NONSHARED), + imx_map_entry(MX35, AIPS2, MT_DEVICE_NONSHARED), + imx_map_entry(MX35, SPBA0, MT_DEVICE_NONSHARED), +}; + +void __init mx35_map_io(void) +{ + iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc)); +} + +void __init imx31_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX31); + mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); + imx_idle = imx3_idle; + imx_ioremap = imx3_ioremap; +} + +void __init imx35_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX35); + mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); + imx_idle = imx3_idle; + imx_ioremap = imx3_ioremap; +} + +void __init mx31_init_irq(void) +{ + mxc_init_irq(MX31_IO_ADDRESS(MX31_AVIC_BASE_ADDR)); +} + +void __init mx35_init_irq(void) +{ + mxc_init_irq(MX35_IO_ADDRESS(MX35_AVIC_BASE_ADDR)); +} + +static struct sdma_script_start_addrs imx31_to1_sdma_script __initdata = { + .per_2_per_addr = 1677, +}; + +static struct sdma_script_start_addrs imx31_to2_sdma_script __initdata = { + .ap_2_ap_addr = 423, + .ap_2_bp_addr = 829, + .bp_2_ap_addr = 1029, +}; + +static struct sdma_platform_data imx31_sdma_pdata __initdata = { + .fw_name = "sdma-imx31-to2.bin", + .script_addrs = &imx31_to2_sdma_script, +}; + +void __init imx31_soc_init(void) +{ + int to_version = mx31_revision() >> 4; + + imx3_init_l2x0(); + + mxc_register_gpio("imx31-gpio", 0, MX31_GPIO1_BASE_ADDR, SZ_16K, MX31_INT_GPIO1, 0); + mxc_register_gpio("imx31-gpio", 1, MX31_GPIO2_BASE_ADDR, SZ_16K, MX31_INT_GPIO2, 0); + mxc_register_gpio("imx31-gpio", 2, MX31_GPIO3_BASE_ADDR, SZ_16K, MX31_INT_GPIO3, 0); + + if (to_version == 1) { + strncpy(imx31_sdma_pdata.fw_name, "sdma-imx31-to1.bin", + strlen(imx31_sdma_pdata.fw_name)); + imx31_sdma_pdata.script_addrs = &imx31_to1_sdma_script; + } + + imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata); +} + +static struct sdma_script_start_addrs imx35_to1_sdma_script __initdata = { + .ap_2_ap_addr = 642, + .uart_2_mcu_addr = 817, + .mcu_2_app_addr = 747, + .uartsh_2_mcu_addr = 1183, + .per_2_shp_addr = 1033, + .mcu_2_shp_addr = 961, + .ata_2_mcu_addr = 1333, + .mcu_2_ata_addr = 1252, + .app_2_mcu_addr = 683, + .shp_2_per_addr = 1111, + .shp_2_mcu_addr = 892, +}; + +static struct sdma_script_start_addrs imx35_to2_sdma_script __initdata = { + .ap_2_ap_addr = 729, + .uart_2_mcu_addr = 904, + .per_2_app_addr = 1597, + .mcu_2_app_addr = 834, + .uartsh_2_mcu_addr = 1270, + .per_2_shp_addr = 1120, + .mcu_2_shp_addr = 1048, + .ata_2_mcu_addr = 1429, + .mcu_2_ata_addr = 1339, + .app_2_per_addr = 1531, + .app_2_mcu_addr = 770, + .shp_2_per_addr = 1198, + .shp_2_mcu_addr = 979, +}; + +static struct sdma_platform_data imx35_sdma_pdata __initdata = { + .fw_name = "sdma-imx35-to2.bin", + .script_addrs = &imx35_to2_sdma_script, +}; + +void __init imx35_soc_init(void) +{ + int to_version = mx35_revision() >> 4; + + imx3_init_l2x0(); + + /* i.mx35 has the i.mx31 type gpio */ + mxc_register_gpio("imx31-gpio", 0, MX35_GPIO1_BASE_ADDR, SZ_16K, MX35_INT_GPIO1, 0); + mxc_register_gpio("imx31-gpio", 1, MX35_GPIO2_BASE_ADDR, SZ_16K, MX35_INT_GPIO2, 0); + mxc_register_gpio("imx31-gpio", 2, MX35_GPIO3_BASE_ADDR, SZ_16K, MX35_INT_GPIO3, 0); + + if (to_version == 1) { + strncpy(imx35_sdma_pdata.fw_name, "sdma-imx35-to1.bin", + strlen(imx35_sdma_pdata.fw_name)); + imx35_sdma_pdata.script_addrs = &imx35_to1_sdma_script; + } + + imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata); +} diff --git a/arch/arm/mach-imx/mm-imx31.c b/arch/arm/mach-imx/mm-imx31.c deleted file mode 100644 index b7c55e7db00..00000000000 --- a/arch/arm/mach-imx/mm-imx31.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 1999,2000 Arm Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * - add MX31 specific definitions - * - * 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. - */ - -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/err.h> - -#include <asm/pgtable.h> -#include <asm/mach/map.h> - -#include <mach/common.h> -#include <mach/devices-common.h> -#include <mach/hardware.h> -#include <mach/iomux-v3.h> -#include <mach/irqs.h> - -static struct map_desc mx31_io_desc[] __initdata = { - imx_map_entry(MX31, X_MEMC, MT_DEVICE), - imx_map_entry(MX31, AVIC, MT_DEVICE_NONSHARED), - imx_map_entry(MX31, AIPS1, MT_DEVICE_NONSHARED), - imx_map_entry(MX31, AIPS2, MT_DEVICE_NONSHARED), - imx_map_entry(MX31, SPBA0, MT_DEVICE_NONSHARED), -}; - -/* - * This function initializes the memory map. It is called during the - * system startup to create static physical to virtual memory mappings - * for the IO modules. - */ -void __init mx31_map_io(void) -{ - iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc)); -} - -void __init imx31_init_early(void) -{ - mxc_set_cpu_type(MXC_CPU_MX31); - mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); -} - -void __init mx31_init_irq(void) -{ - mxc_init_irq(MX31_IO_ADDRESS(MX31_AVIC_BASE_ADDR)); -} - -static struct sdma_script_start_addrs imx31_to1_sdma_script __initdata = { - .per_2_per_addr = 1677, -}; - -static struct sdma_script_start_addrs imx31_to2_sdma_script __initdata = { - .ap_2_ap_addr = 423, - .ap_2_bp_addr = 829, - .bp_2_ap_addr = 1029, -}; - -static struct sdma_platform_data imx31_sdma_pdata __initdata = { - .fw_name = "sdma-imx31-to2.bin", - .script_addrs = &imx31_to2_sdma_script, -}; - -void __init imx31_soc_init(void) -{ - int to_version = mx31_revision() >> 4; - - mxc_register_gpio("imx31-gpio", 0, MX31_GPIO1_BASE_ADDR, SZ_16K, MX31_INT_GPIO1, 0); - mxc_register_gpio("imx31-gpio", 1, MX31_GPIO2_BASE_ADDR, SZ_16K, MX31_INT_GPIO2, 0); - mxc_register_gpio("imx31-gpio", 2, MX31_GPIO3_BASE_ADDR, SZ_16K, MX31_INT_GPIO3, 0); - - if (to_version == 1) { - strncpy(imx31_sdma_pdata.fw_name, "sdma-imx31-to1.bin", - strlen(imx31_sdma_pdata.fw_name)); - imx31_sdma_pdata.script_addrs = &imx31_to1_sdma_script; - } - - imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata); -} diff --git a/arch/arm/mach-imx/mm-imx35.c b/arch/arm/mach-imx/mm-imx35.c deleted file mode 100644 index f49bac7a1ed..00000000000 --- a/arch/arm/mach-imx/mm-imx35.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 1999,2000 Arm Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * Copyright (C) 2002 Shane Nay (shane@minirl.com) - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * - add MX31 specific definitions - * - * 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. - */ - -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/err.h> - -#include <asm/pgtable.h> -#include <asm/mach/map.h> -#include <asm/hardware/cache-l2x0.h> - -#include <mach/common.h> -#include <mach/devices-common.h> -#include <mach/hardware.h> -#include <mach/iomux-v3.h> -#include <mach/irqs.h> - -static struct map_desc mx35_io_desc[] __initdata = { - imx_map_entry(MX35, X_MEMC, MT_DEVICE), - imx_map_entry(MX35, AVIC, MT_DEVICE_NONSHARED), - imx_map_entry(MX35, AIPS1, MT_DEVICE_NONSHARED), - imx_map_entry(MX35, AIPS2, MT_DEVICE_NONSHARED), - imx_map_entry(MX35, SPBA0, MT_DEVICE_NONSHARED), -}; - -void __init mx35_map_io(void) -{ - iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc)); -} - -void __init imx35_init_early(void) -{ - mxc_set_cpu_type(MXC_CPU_MX35); - mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR)); - mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); -} - -void __init mx35_init_irq(void) -{ - mxc_init_irq(MX35_IO_ADDRESS(MX35_AVIC_BASE_ADDR)); -} - -static struct sdma_script_start_addrs imx35_to1_sdma_script __initdata = { - .ap_2_ap_addr = 642, - .uart_2_mcu_addr = 817, - .mcu_2_app_addr = 747, - .uartsh_2_mcu_addr = 1183, - .per_2_shp_addr = 1033, - .mcu_2_shp_addr = 961, - .ata_2_mcu_addr = 1333, - .mcu_2_ata_addr = 1252, - .app_2_mcu_addr = 683, - .shp_2_per_addr = 1111, - .shp_2_mcu_addr = 892, -}; - -static struct sdma_script_start_addrs imx35_to2_sdma_script __initdata = { - .ap_2_ap_addr = 729, - .uart_2_mcu_addr = 904, - .per_2_app_addr = 1597, - .mcu_2_app_addr = 834, - .uartsh_2_mcu_addr = 1270, - .per_2_shp_addr = 1120, - .mcu_2_shp_addr = 1048, - .ata_2_mcu_addr = 1429, - .mcu_2_ata_addr = 1339, - .app_2_per_addr = 1531, - .app_2_mcu_addr = 770, - .shp_2_per_addr = 1198, - .shp_2_mcu_addr = 979, -}; - -static struct sdma_platform_data imx35_sdma_pdata __initdata = { - .fw_name = "sdma-imx35-to2.bin", - .script_addrs = &imx35_to2_sdma_script, -}; - -void __init imx35_soc_init(void) -{ - int to_version = mx35_revision() >> 4; - - /* i.mx35 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX35_GPIO1_BASE_ADDR, SZ_16K, MX35_INT_GPIO1, 0); - mxc_register_gpio("imx31-gpio", 1, MX35_GPIO2_BASE_ADDR, SZ_16K, MX35_INT_GPIO2, 0); - mxc_register_gpio("imx31-gpio", 2, MX35_GPIO3_BASE_ADDR, SZ_16K, MX35_INT_GPIO3, 0); - - if (to_version == 1) { - strncpy(imx35_sdma_pdata.fw_name, "sdma-imx35-to1.bin", - strlen(imx35_sdma_pdata.fw_name)); - imx35_sdma_pdata.script_addrs = &imx35_to1_sdma_script; - } - - imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata); -} diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c new file mode 100644 index 00000000000..c461e98496c --- /dev/null +++ b/arch/arm/mach-imx/mmdc.c @@ -0,0 +1,72 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> + +#define MMDC_MAPSR 0x404 +#define BP_MMDC_MAPSR_PSD 0 +#define BP_MMDC_MAPSR_PSS 4 + +static int __devinit imx_mmdc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + void __iomem *mmdc_base, *reg; + u32 val; + int timeout = 0x400; + + mmdc_base = of_iomap(np, 0); + WARN_ON(!mmdc_base); + + reg = mmdc_base + MMDC_MAPSR; + + /* Enable automatic power saving */ + val = readl_relaxed(reg); + val &= ~(1 << BP_MMDC_MAPSR_PSD); + writel_relaxed(val, reg); + + /* Ensure it's successfully enabled */ + while (!(readl_relaxed(reg) & 1 << BP_MMDC_MAPSR_PSS) && --timeout) + cpu_relax(); + + if (unlikely(!timeout)) { + pr_warn("%s: failed to enable automatic power saving\n", + __func__); + return -EBUSY; + } + + return 0; +} + +static struct of_device_id imx_mmdc_dt_ids[] = { + { .compatible = "fsl,imx6q-mmdc", }, + { /* sentinel */ } +}; + +static struct platform_driver imx_mmdc_driver = { + .driver = { + .name = "imx-mmdc", + .owner = THIS_MODULE, + .of_match_table = imx_mmdc_dt_ids, + }, + .probe = imx_mmdc_probe, +}; + +static int __init imx_mmdc_init(void) +{ + return platform_driver_register(&imx_mmdc_driver); +} +postcore_initcall(imx_mmdc_init); diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c new file mode 100644 index 00000000000..ab98c6fec9e --- /dev/null +++ b/arch/arm/mach-imx/platsmp.c @@ -0,0 +1,85 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/smp.h> +#include <asm/page.h> +#include <asm/smp_scu.h> +#include <asm/hardware/gic.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <mach/hardware.h> + +static void __iomem *scu_base; + +static struct map_desc scu_io_desc __initdata = { + /* .virtual and .pfn are run-time assigned */ + .length = SZ_4K, + .type = MT_DEVICE, +}; + +void __init imx_scu_map_io(void) +{ + unsigned long base; + + /* Get SCU base */ + asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base)); + + scu_io_desc.virtual = IMX_IO_P2V(base); + scu_io_desc.pfn = __phys_to_pfn(base); + iotable_init(&scu_io_desc, 1); + + scu_base = IMX_IO_ADDRESS(base); +} + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + imx_set_cpu_jump(cpu, v7_secondary_startup); + imx_enable_cpu(cpu, true); + return 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + int i, ncores; + + ncores = scu_get_core_count(scu_base); + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +void imx_smp_prepare(void) +{ + scu_enable(scu_base); +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + imx_smp_prepare(); +} diff --git a/arch/arm/mach-imx/pm-imx27.c b/arch/arm/mach-imx/pm-imx27.c index acf17691d2c..e455d2f855b 100644 --- a/arch/arm/mach-imx/pm-imx27.c +++ b/arch/arm/mach-imx/pm-imx27.c @@ -11,7 +11,7 @@ #include <linux/suspend.h> #include <linux/io.h> #include <mach/system.h> -#include <mach/mx27.h> +#include <mach/hardware.h> static int mx27_suspend_enter(suspend_state_t state) { diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c new file mode 100644 index 00000000000..f20f191d7cc --- /dev/null +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -0,0 +1,70 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/suspend.h> +#include <asm/cacheflush.h> +#include <asm/proc-fns.h> +#include <asm/suspend.h> +#include <asm/hardware/cache-l2x0.h> +#include <mach/common.h> +#include <mach/hardware.h> + +extern unsigned long phys_l2x0_saved_regs; + +static int imx6q_suspend_finish(unsigned long val) +{ + cpu_do_idle(); + return 0; +} + +static int imx6q_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + imx6q_set_lpm(STOP_POWER_OFF); + imx_gpc_pre_suspend(); + imx_set_cpu_jump(0, v7_cpu_resume); + /* Zzz ... */ + cpu_suspend(0, imx6q_suspend_finish); + imx_smp_prepare(); + imx_gpc_post_resume(); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct platform_suspend_ops imx6q_pm_ops = { + .enter = imx6q_pm_enter, + .valid = suspend_valid_only_mem, +}; + +void __init imx6q_pm_init(void) +{ + /* + * The l2x0 core code provides an infrastucture to save and restore + * l2x0 registers across suspend/resume cycle. But because imx6q + * retains L2 content during suspend and needs to resume L2 before + * MMU is enabled, it can only utilize register saving support and + * have to take care of restoring on its own. So we save physical + * address of the data structure used by l2x0 core to save registers, + * and later restore the necessary ones in imx6q resume entry. + */ + phys_l2x0_saved_regs = __pa(&l2x0_saved_regs); + + suspend_set_ops(&imx6q_pm_ops); +} diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c new file mode 100644 index 00000000000..36cacbd0dcc --- /dev/null +++ b/arch/arm/mach-imx/src.c @@ -0,0 +1,49 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * 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 <linux/init.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <asm/unified.h> + +#define SRC_SCR 0x000 +#define SRC_GPR1 0x020 +#define BP_SRC_SCR_CORE1_RST 14 +#define BP_SRC_SCR_CORE1_ENABLE 22 + +static void __iomem *src_base; + +void imx_enable_cpu(int cpu, bool enable) +{ + u32 mask, val; + + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_SCR); +} + +void imx_set_cpu_jump(int cpu, void *jump_addr) +{ + writel_relaxed(BSYM(virt_to_phys(jump_addr)), + src_base + SRC_GPR1 + cpu * 8); +} + +void __init imx_src_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src"); + src_base = of_iomap(np, 0); + WARN_ON(!src_base); +} |