summary refs log tree commit diff
path: root/arch/arm/mach-imx
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-09 14:38:28 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-09 14:38:28 -0800
commit6cd94d5e57ab97ddd672b707ab4bb639672c1727 (patch)
treeb1b301b16433d4deab6bd52e81d04a7b58c239d3 /arch/arm/mach-imx
parent6c9e92476bc924ede6d6d2f0bfed2c06ae148d29 (diff)
parent842f7d2c4d392c0571cf72e3eaca26742bebbd1e (diff)
downloadlinux-6cd94d5e57ab97ddd672b707ab4bb639672c1727.tar.gz
Merge tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform changes from Arnd Bergmann:
 "New and updated SoC support, notable changes include:

   - bcm:
        brcmstb SMP support
        initial iproc/cygnus support
   - exynos:
        Exynos4415 SoC support
        PMU and suspend support for Exynos5420
        PMU support for Exynos3250
        pm related maintenance
   - imx:
        new LS1021A SoC support
        vybrid 610 global timer support
   - integrator:
        convert to using multiplatform configuration
   - mediatek:
        earlyprintk support for mt8127/mt8135
   - meson:
        meson8 soc and l2 cache controller support
   - mvebu:
        Armada 38x CPU hotplug support
        drop support for prerelease Armada 375 Z1 stepping
        extended suspend support, now works on Armada 370/XP
   - omap:
        hwmod related maintenance
        prcm cleanup
   - pxa:
        initial pxa27x DT handling
   - rockchip:
        SMP support for rk3288
        add cpu frequency scaling support
   - shmobile:
        r8a7740 power domain support
        various small restart, timer, pci apmu changes
   - sunxi:
        Allwinner A80 (sun9i) earlyprintk support
   - ux500:
        power domain support

  Overall, a significant chunk of changes, coming mostly from the usual
  suspects: omap, shmobile, samsung and mvebu, all of which already
  contain a lot of platform specific code in arch/arm"

* tag 'soc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (187 commits)
  ARM: mvebu: use the cpufreq-dt platform_data for independent clocks
  soc: integrator: Add terminating entry for integrator_cm_match
  ARM: mvebu: add SDRAM controller description for Armada XP
  ARM: mvebu: adjust mbus controller description on Armada 370/XP
  ARM: mvebu: add suspend/resume DT information for Armada XP GP
  ARM: mvebu: synchronize secondary CPU clocks on resume
  ARM: mvebu: make sure MMU is disabled in armada_370_xp_cpu_resume
  ARM: mvebu: Armada XP GP specific suspend/resume code
  ARM: mvebu: reserve the first 10 KB of each memory bank for suspend/resume
  ARM: mvebu: implement suspend/resume support for Armada XP
  clk: mvebu: add suspend/resume for gatable clocks
  bus: mvebu-mbus: provide a mechanism to save SDRAM window configuration
  bus: mvebu-mbus: suspend/resume support
  clocksource: time-armada-370-xp: add suspend/resume support
  irqchip: armada-370-xp: Add suspend/resume support
  ARM: add lolevel debug support for asm9260
  ARM: add mach-asm9260
  ARM: EXYNOS: use u8 for val[] in struct exynos_pmu_conf
  power: reset: imx-snvs-poweroff: add power off driver for i.mx6
  ARM: imx: temporarily remove CONFIG_SOC_FSL from LS1021A
  ...
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r--arch/arm/mach-imx/Kconfig31
-rw-r--r--arch/arm/mach-imx/Makefile6
-rw-r--r--arch/arm/mach-imx/anatop.c34
-rw-r--r--arch/arm/mach-imx/clk-cpu.c107
-rw-r--r--arch/arm/mach-imx/clk-imx51-imx53.c14
-rw-r--r--arch/arm/mach-imx/clk-vf610.c21
-rw-r--r--arch/arm/mach-imx/clk.h4
-rw-r--r--arch/arm/mach-imx/common.h2
-rw-r--r--arch/arm/mach-imx/mach-imx53.c2
-rw-r--r--arch/arm/mach-imx/mach-imx6sx.c51
-rw-r--r--arch/arm/mach-imx/mach-ls1021a.c22
-rw-r--r--arch/arm/mach-imx/mmdc.c17
-rw-r--r--arch/arm/mach-imx/mxc.h2
-rw-r--r--arch/arm/mach-imx/platsmp.c33
-rw-r--r--arch/arm/mach-imx/pm-imx6.c10
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S14
16 files changed, 345 insertions, 25 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 11b2957f792b..e8627e04e1e6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -633,12 +633,41 @@ config SOC_VF610
 	bool "Vybrid Family VF610 support"
 	select ARM_GIC
 	select PINCTRL_VF610
-	select VF_PIT_TIMER
 	select PL310_ERRATA_769419 if CACHE_L2X0
 
 	help
 	  This enable support for Freescale Vybrid VF610 processor.
 
+choice
+	prompt "Clocksource for scheduler clock"
+	depends on SOC_VF610
+	default VF_USE_ARM_GLOBAL_TIMER
+
+	config VF_USE_ARM_GLOBAL_TIMER
+		bool "Use ARM Global Timer"
+		select ARM_GLOBAL_TIMER
+		select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+		help
+		  Use the ARM Global Timer as clocksource
+
+	config VF_USE_PIT_TIMER
+		bool "Use PIT timer"
+		select VF_PIT_TIMER
+		help
+		  Use SoC Periodic Interrupt Timer (PIT) as clocksource
+
+endchoice
+
+config SOC_LS1021A
+	bool "Freescale LS1021A support"
+	select ARM_GIC
+	select HAVE_ARM_ARCH_TIMER
+	select PCI_DOMAINS if PCI
+	select ZONE_DMA if ARM_LPAE
+
+	help
+	  This enable support for Freescale LS1021A processor.
+
 endif
 
 source "arch/arm/mach-imx/devices/Kconfig"
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 6e4fcd8339cd..f5ac685a29fc 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-
 obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o
 
 imx5-pm-$(CONFIG_PM) += pm-imx5.o
-obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y)
+obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y)
 
 obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
 			    clk-pfd.o clk-busy.o clk.o \
@@ -89,7 +89,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
 obj-$(CONFIG_HAVE_IMX_SRC) += src.o
-ifdef CONFIG_SOC_IMX6
+ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
 AFLAGS_headsmp.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
@@ -110,4 +110,6 @@ obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
 
 obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o
 
+obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
+
 obj-y += devices/
diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c
index 8259a625a920..7f262fe4ba77 100644
--- a/arch/arm/mach-imx/anatop.c
+++ b/arch/arm/mach-imx/anatop.c
@@ -30,8 +30,11 @@
 #define ANADIG_DIGPROG_IMX6SL	0x280
 
 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG	0x40000
+#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN	0x8
 #define BM_ANADIG_REG_CORE_FET_ODRIVE		0x20000000
 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	0x1000
+/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
+#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS	0x2000
 #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x80000
 #define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x100000
 
@@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable)
 		BM_ANADIG_REG_CORE_FET_ODRIVE);
 }
 
+static inline void imx_anatop_enable_2p5_pulldown(bool enable)
+{
+	regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR),
+		BM_ANADIG_REG_2P5_ENABLE_PULLDOWN);
+}
+
+static inline void imx_anatop_disconnect_high_snvs(bool enable)
+{
+	regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR),
+		BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS);
+}
+
 void imx_anatop_pre_suspend(void)
 {
-	imx_anatop_enable_weak2p5(true);
+	if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
+		imx_anatop_enable_2p5_pulldown(true);
+	else
+		imx_anatop_enable_weak2p5(true);
+
 	imx_anatop_enable_fet_odrive(true);
+
+	if (cpu_is_imx6sl())
+		imx_anatop_disconnect_high_snvs(true);
 }
 
 void imx_anatop_post_resume(void)
 {
+	if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
+		imx_anatop_enable_2p5_pulldown(false);
+	else
+		imx_anatop_enable_weak2p5(false);
+
 	imx_anatop_enable_fet_odrive(false);
-	imx_anatop_enable_weak2p5(false);
+
+	if (cpu_is_imx6sl())
+		imx_anatop_disconnect_high_snvs(false);
+
 }
 
 static void imx_anatop_usb_chrg_detect_disable(void)
diff --git a/arch/arm/mach-imx/clk-cpu.c b/arch/arm/mach-imx/clk-cpu.c
new file mode 100644
index 000000000000..aa1c345e2a19
--- /dev/null
+++ b/arch/arm/mach-imx/clk-cpu.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix
+ *
+ * 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.
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+
+struct clk_cpu {
+	struct clk_hw	hw;
+	struct clk	*div;
+	struct clk	*mux;
+	struct clk	*pll;
+	struct clk	*step;
+};
+
+static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw)
+{
+	return container_of(hw, struct clk_cpu, hw);
+}
+
+static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
+					 unsigned long parent_rate)
+{
+	struct clk_cpu *cpu = to_clk_cpu(hw);
+
+	return clk_get_rate(cpu->div);
+}
+
+static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
+			       unsigned long *prate)
+{
+	struct clk_cpu *cpu = to_clk_cpu(hw);
+
+	return clk_round_rate(cpu->pll, rate);
+}
+
+static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_cpu *cpu = to_clk_cpu(hw);
+	int ret;
+
+	/* switch to PLL bypass clock */
+	ret = clk_set_parent(cpu->mux, cpu->step);
+	if (ret)
+		return ret;
+
+	/* reprogram PLL */
+	ret = clk_set_rate(cpu->pll, rate);
+	if (ret) {
+		clk_set_parent(cpu->mux, cpu->pll);
+		return ret;
+	}
+	/* switch back to PLL clock */
+	clk_set_parent(cpu->mux, cpu->pll);
+
+	/* Ensure the divider is what we expect */
+	clk_set_rate(cpu->div, rate);
+
+	return 0;
+}
+
+static const struct clk_ops clk_cpu_ops = {
+	.recalc_rate	= clk_cpu_recalc_rate,
+	.round_rate	= clk_cpu_round_rate,
+	.set_rate	= clk_cpu_set_rate,
+};
+
+struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+		struct clk *div, struct clk *mux, struct clk *pll,
+		struct clk *step)
+{
+	struct clk_cpu *cpu;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
+	if (!cpu)
+		return ERR_PTR(-ENOMEM);
+
+	cpu->div = div;
+	cpu->mux = mux;
+	cpu->pll = pll;
+	cpu->step = step;
+
+	init.name = name;
+	init.ops = &clk_cpu_ops;
+	init.flags = 0;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	cpu->hw.init = &init;
+
+	clk = clk_register(NULL, &cpu->hw);
+	if (IS_ERR(clk))
+		kfree(cpu);
+
+	return clk;
+}
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c
index 72d65214223e..0f7e536147cb 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/arch/arm/mach-imx/clk-imx51-imx53.c
@@ -125,6 +125,8 @@ static const char *mx53_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", "pll4_sw",
 static const char *spdif_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "spdif_xtal_sel", };
 static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", };
 static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", };
+static const char *step_sels[] = { "lp_apm", };
+static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" };
 
 static struct clk *clk[IMX5_CLK_END];
 static struct clk_onecell_data clk_data;
@@ -193,7 +195,9 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
 	clk[IMX5_CLK_USB_PHY_PODF]	= imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3);
 	clk[IMX5_CLK_USB_PHY_SEL]	= imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1,
 						usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));
-	clk[IMX5_CLK_CPU_PODF]		= imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3);
+	clk[IMX5_CLK_STEP_SEL]		= imx_clk_mux("step_sel", MXC_CCM_CCSR, 7, 2, step_sels, ARRAY_SIZE(step_sels));
+	clk[IMX5_CLK_CPU_PODF_SEL]	= imx_clk_mux("cpu_podf_sel", MXC_CCM_CCSR, 2, 1, cpu_podf_sels, ARRAY_SIZE(cpu_podf_sels));
+	clk[IMX5_CLK_CPU_PODF]		= imx_clk_divider("cpu_podf", "cpu_podf_sel", MXC_CCM_CACRR, 0, 3);
 	clk[IMX5_CLK_DI_PRED]		= imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3);
 	clk[IMX5_CLK_IIM_GATE]		= imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30);
 	clk[IMX5_CLK_UART1_IPG_GATE]	= imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6);
@@ -537,6 +541,11 @@ static void __init mx53_clocks_init(struct device_node *np)
 	clk[IMX5_CLK_CKO2]		= imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24);
 	clk[IMX5_CLK_SPDIF_XTAL_SEL]	= imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2,
 						mx53_spdif_xtal_sel, ARRAY_SIZE(mx53_spdif_xtal_sel));
+	clk[IMX5_CLK_ARM]		= imx_clk_cpu("arm", "cpu_podf",
+						clk[IMX5_CLK_CPU_PODF],
+						clk[IMX5_CLK_CPU_PODF_SEL],
+						clk[IMX5_CLK_PLL1_SW],
+						clk[IMX5_CLK_STEP_SEL]);
 
 	imx_check_clocks(clk, ARRAY_SIZE(clk));
 
@@ -551,6 +560,9 @@ static void __init mx53_clocks_init(struct device_node *np)
 	/* move can bus clk to 24MHz */
 	clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]);
 
+	/* make sure step clock is running from 24MHz */
+	clk_set_parent(clk[IMX5_CLK_STEP_SEL], clk[IMX5_CLK_LP_APM]);
+
 	clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
 	imx_print_silicon_rev("i.MX53", mx53_revision());
 	clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c
index 409637254594..5937ddee1a99 100644
--- a/arch/arm/mach-imx/clk-vf610.c
+++ b/arch/arm/mach-imx/clk-vf610.c
@@ -120,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = {
 	VF610_CLK_DDR_SEL,
 };
 
+static struct clk * __init vf610_get_fixed_clock(
+				struct device_node *ccm_node, const char *name)
+{
+	struct clk *clk = of_clk_get_by_name(ccm_node, name);
+
+	/* Backward compatibility if device tree is missing clks assignments */
+	if (IS_ERR(clk))
+		clk = imx_obtain_fixed_clock(name, 0);
+	return clk;
+};
+
 static void __init vf610_clocks_init(struct device_node *ccm_node)
 {
 	struct device_node *np;
@@ -130,13 +141,13 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
 	clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000);
 	clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000);
 
-	clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0);
-	clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0);
-	clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0);
-	clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0);
+	clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc");
+	clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc");
+	clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext");
+	clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext");
 
 	/* Clock source from external clock via LVDs PAD */
-	clk[VF610_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+	clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(ccm_node, "anaclk1");
 
 	clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2);
 
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index 4cdf8b6a74e8..5ef82e2f8fc5 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name,
 			CLK_SET_RATE_PARENT, mult, div);
 }
 
+struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+		struct clk *div, struct clk *mux, struct clk *pll,
+		struct clk *step);
+
 #endif
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 3d383cb5e6d1..cfcdb623d78f 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -115,6 +115,7 @@ void imx_anatop_post_resume(void);
 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
 void imx6q_set_int_mem_clk_lpm(bool enable);
 void imx6sl_set_wait_clk(bool enter);
+int imx_mmdc_get_ddr_type(void);
 
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
@@ -156,5 +157,6 @@ static inline void imx_init_l2cache(void) {}
 #endif
 
 extern struct smp_operations imx_smp_ops;
+extern struct smp_operations ls1021a_smp_ops;
 
 #endif
diff --git a/arch/arm/mach-imx/mach-imx53.c b/arch/arm/mach-imx/mach-imx53.c
index 18b5c5c136db..86316a979297 100644
--- a/arch/arm/mach-imx/mach-imx53.c
+++ b/arch/arm/mach-imx/mach-imx53.c
@@ -40,6 +40,8 @@ static void __init imx53_dt_init(void)
 static void __init imx53_init_late(void)
 {
 	imx53_pm_init();
+
+	platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
 }
 
 static const char * const imx53_dt_board_compat[] __initconst = {
diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c
index 4111c0fa8d09..7a96c6577234 100644
--- a/arch/arm/mach-imx/mach-imx6sx.c
+++ b/arch/arm/mach-imx/mach-imx6sx.c
@@ -8,12 +8,62 @@
 
 #include <linux/irqchip.h>
 #include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include "common.h"
 #include "cpuidle.h"
 
+static int ar8031_phy_fixup(struct phy_device *dev)
+{
+	u16 val;
+
+	/* Set RGMII IO voltage to 1.8V */
+	phy_write(dev, 0x1d, 0x1f);
+	phy_write(dev, 0x1e, 0x8);
+
+	/* introduce tx clock delay */
+	phy_write(dev, 0x1d, 0x5);
+	val = phy_read(dev, 0x1e);
+	val |= 0x0100;
+	phy_write(dev, 0x1e, val);
+
+	return 0;
+}
+
+#define PHY_ID_AR8031   0x004dd074
+static void __init imx6sx_enet_phy_init(void)
+{
+	if (IS_BUILTIN(CONFIG_PHYLIB))
+		phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
+					   ar8031_phy_fixup);
+}
+
+static void __init imx6sx_enet_clk_sel(void)
+{
+	struct regmap *gpr;
+
+	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr");
+	if (!IS_ERR(gpr)) {
+		regmap_update_bits(gpr, IOMUXC_GPR1,
+				   IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0);
+		regmap_update_bits(gpr, IOMUXC_GPR1,
+				   IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0);
+	} else {
+		pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n");
+	}
+}
+
+static inline void imx6sx_enet_init(void)
+{
+	imx6sx_enet_phy_init();
+	imx6sx_enet_clk_sel();
+}
+
 static void __init imx6sx_init_machine(void)
 {
 	struct device *parent;
@@ -24,6 +74,7 @@ static void __init imx6sx_init_machine(void)
 
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
 
+	imx6sx_enet_init();
 	imx_anatop_init();
 	imx6sx_pm_init();
 }
diff --git a/arch/arm/mach-imx/mach-ls1021a.c b/arch/arm/mach-imx/mach-ls1021a.c
new file mode 100644
index 000000000000..b89c858ebfd6
--- /dev/null
+++ b/arch/arm/mach-imx/mach-ls1021a.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * 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 <asm/mach/arch.h>
+
+#include "common.h"
+
+static const char * const ls1021a_dt_compat[] __initconst = {
+	"fsl,ls1021a",
+	NULL,
+};
+
+DT_MACHINE_START(LS1021A, "Freescale LS1021A")
+	.smp		= smp_ops(ls1021a_smp_ops),
+	.dt_compat	= ls1021a_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index 7a9686ad994c..3729d90cfa46 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -21,6 +21,12 @@
 #define BP_MMDC_MAPSR_PSD	0
 #define BP_MMDC_MAPSR_PSS	4
 
+#define MMDC_MDMISC		0x18
+#define BM_MMDC_MDMISC_DDR_TYPE	0x18
+#define BP_MMDC_MDMISC_DDR_TYPE	0x3
+
+static int ddr_type;
+
 static int imx_mmdc_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev)
 	mmdc_base = of_iomap(np, 0);
 	WARN_ON(!mmdc_base);
 
+	reg = mmdc_base + MMDC_MDMISC;
+	/* Get ddr type */
+	val = readl_relaxed(reg);
+	ddr_type = (val & BM_MMDC_MDMISC_DDR_TYPE) >>
+		 BP_MMDC_MDMISC_DDR_TYPE;
+
 	reg = mmdc_base + MMDC_MAPSR;
 
 	/* Enable automatic power saving */
@@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev)
 	return 0;
 }
 
+int imx_mmdc_get_ddr_type(void)
+{
+	return ddr_type;
+}
+
 static struct of_device_id imx_mmdc_dt_ids[] = {
 	{ .compatible = "fsl,imx6q-mmdc", },
 	{ /* sentinel */ }
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 17a41ca65acf..4c1343df2ba4 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -55,6 +55,8 @@
 #define IMX_CHIP_REVISION_3_3		0x33
 #define IMX_CHIP_REVISION_UNKNOWN	0xff
 
+#define IMX_DDR_TYPE_LPDDR2		1
+
 #ifndef __ASSEMBLY__
 extern unsigned int __mxc_cpu_type;
 #endif
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 771bd25c1025..7f270015fe58 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -11,7 +11,10 @@
  */
 
 #include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
 #include <linux/smp.h>
+
 #include <asm/cacheflush.h>
 #include <asm/page.h>
 #include <asm/smp_scu.h>
@@ -94,3 +97,33 @@ struct smp_operations  imx_smp_ops __initdata = {
 	.cpu_kill		= imx_cpu_kill,
 #endif
 };
+
+#define DCFG_CCSR_SCRATCHRW1	0x200
+
+static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	return 0;
+}
+
+static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
+{
+	struct device_node *np;
+	void __iomem *dcfg_base;
+	unsigned long paddr;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
+	dcfg_base = of_iomap(np, 0);
+	BUG_ON(!dcfg_base);
+
+	paddr = virt_to_phys(secondary_startup);
+	writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1);
+
+	iounmap(dcfg_base);
+}
+
+struct smp_operations  ls1021a_smp_ops __initdata = {
+	.smp_prepare_cpus	= ls1021a_smp_prepare_cpus,
+	.smp_boot_secondary	= ls1021a_boot_secondary,
+};
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index d815d1ba27a5..5d2c1bd5f5ef 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -88,7 +88,7 @@ struct imx6_pm_base {
 };
 
 struct imx6_pm_socdata {
-	u32 cpu_type;
+	u32 ddr_type;
 	const char *mmdc_compat;
 	const char *src_compat;
 	const char *iomuxc_compat;
@@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
 };
 
 static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
-	.cpu_type = MXC_CPU_IMX6Q,
 	.mmdc_compat = "fsl,imx6q-mmdc",
 	.src_compat = "fsl,imx6q-src",
 	.iomuxc_compat = "fsl,imx6q-iomuxc",
@@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
 };
 
 static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
-	.cpu_type = MXC_CPU_IMX6DL,
 	.mmdc_compat = "fsl,imx6q-mmdc",
 	.src_compat = "fsl,imx6q-src",
 	.iomuxc_compat = "fsl,imx6dl-iomuxc",
@@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
 };
 
 static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
-	.cpu_type = MXC_CPU_IMX6SL,
 	.mmdc_compat = "fsl,imx6sl-mmdc",
 	.src_compat = "fsl,imx6sl-src",
 	.iomuxc_compat = "fsl,imx6sl-iomuxc",
@@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
 };
 
 static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
-	.cpu_type = MXC_CPU_IMX6SX,
 	.mmdc_compat = "fsl,imx6sx-mmdc",
 	.src_compat = "fsl,imx6sx-src",
 	.iomuxc_compat = "fsl,imx6sx-iomuxc",
@@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
 struct imx6_cpu_pm_info {
 	phys_addr_t pbase; /* The physical address of pm_info. */
 	phys_addr_t resume_addr; /* The physical resume address for asm code */
-	u32 cpu_type;
+	u32 ddr_type;
 	u32 pm_info_size; /* Size of pm_info. */
 	struct imx6_pm_base mmdc_base;
 	struct imx6_pm_base src_base;
@@ -521,7 +517,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
 		goto pl310_cache_map_failed;
 	}
 
-	pm_info->cpu_type = socdata->cpu_type;
+	pm_info->ddr_type = imx_mmdc_get_ddr_type();
 	pm_info->mmdc_io_num = socdata->mmdc_io_num;
 	mmdc_offset_array = socdata->mmdc_io_offset;
 
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index ca4ea2daf25b..b99987b023fa 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -45,7 +45,7 @@
  */
 #define PM_INFO_PBASE_OFFSET			0x0
 #define PM_INFO_RESUME_ADDR_OFFSET		0x4
-#define PM_INFO_CPU_TYPE_OFFSET			0x8
+#define PM_INFO_DDR_TYPE_OFFSET			0x8
 #define PM_INFO_PM_INFO_SIZE_OFFSET		0xC
 #define PM_INFO_MX6Q_MMDC_P_OFFSET		0x10
 #define PM_INFO_MX6Q_MMDC_V_OFFSET		0x14
@@ -110,7 +110,7 @@
 	ldreq	r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
 	ldrne	r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
 
-	cmp 	r3, #MXC_CPU_IMX6SL
+	cmp	r3, #IMX_DDR_TYPE_LPDDR2
 	bne	4f
 
 	/* reset read FIFO, RST_RD_FIFO */
@@ -151,7 +151,7 @@
 ENTRY(imx6_suspend)
 	ldr	r1, [r0, #PM_INFO_PBASE_OFFSET]
 	ldr	r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
-	ldr	r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
+	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
 	ldr	r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
 
 	/*
@@ -209,8 +209,8 @@ poll_dvfs_set:
 	ldr	r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
 	ldr	r8, =PM_INFO_MMDC_IO_VAL_OFFSET
 	add	r8, r8, r0
-	/* i.MX6SL's last 3 IOs need special setting */
-	cmp	r3, #MXC_CPU_IMX6SL
+	/* LPDDR2's last 3 IOs need special setting */
+	cmp	r3, #IMX_DDR_TYPE_LPDDR2
 	subeq	r7, r7, #0x3
 set_mmdc_io_lpm:
 	ldr	r9, [r8], #0x8
@@ -218,7 +218,7 @@ set_mmdc_io_lpm:
 	subs	r7, r7, #0x1
 	bne	set_mmdc_io_lpm
 
-	cmp 	r3, #MXC_CPU_IMX6SL
+	cmp 	r3, #IMX_DDR_TYPE_LPDDR2
 	bne	set_mmdc_io_lpm_done
 	ldr	r6, =0x1000
 	ldr	r9, [r8], #0x8
@@ -324,7 +324,7 @@ resume:
 	str	r7, [r11, #MX6Q_SRC_GPR1]
 	str	r7, [r11, #MX6Q_SRC_GPR2]
 
-	ldr	r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
+	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
 	mov	r5, #0x1
 	resume_mmdc