diff options
Diffstat (limited to 'arch/arm/mach-imx')
| -rw-r--r-- | arch/arm/mach-imx/Kconfig | 10 | ||||
| -rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/mach-imx/anatop.c | 103 | ||||
| -rw-r--r-- | arch/arm/mach-imx/clk-imx51-imx53.c | 75 | ||||
| -rw-r--r-- | arch/arm/mach-imx/clk-imx6q.c | 126 | ||||
| -rw-r--r-- | arch/arm/mach-imx/clk.h | 17 | ||||
| -rw-r--r-- | arch/arm/mach-imx/common.h | 10 | ||||
| -rw-r--r-- | arch/arm/mach-imx/gpc.c | 23 | ||||
| -rw-r--r-- | arch/arm/mach-imx/mach-imx6q.c | 72 | ||||
| -rw-r--r-- | arch/arm/mach-imx/mm-imx1.c | 2 | ||||
| -rw-r--r-- | arch/arm/mach-imx/mxc.h | 11 | ||||
| -rw-r--r-- | arch/arm/mach-imx/platsmp.c | 4 | ||||
| -rw-r--r-- | arch/arm/mach-imx/pm-imx6q.c | 4 | ||||
| -rw-r--r-- | arch/arm/mach-imx/src.c | 66 | 
14 files changed, 443 insertions, 81 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 2ebc97e16b9..78f795d73cb 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -65,6 +65,9 @@ config IRAM_ALLOC  	bool  	select GENERIC_ALLOCATOR +config HAVE_IMX_ANATOP +	bool +  config HAVE_IMX_GPC  	bool @@ -73,6 +76,7 @@ config HAVE_IMX_MMDC  config HAVE_IMX_SRC  	def_bool y if SMP +	select ARCH_HAS_RESET_CONTROLLER  config IMX_HAVE_IOMUX_V1  	bool @@ -115,6 +119,8 @@ config SOC_IMX25  config SOC_IMX27  	bool +	select ARCH_HAS_CPUFREQ +	select ARCH_HAS_OPP  	select COMMON_CLK  	select CPU_ARM926T  	select IMX_HAVE_IOMUX_V1 @@ -142,6 +148,7 @@ config SOC_IMX35  config SOC_IMX5  	bool  	select ARCH_HAS_CPUFREQ +	select ARCH_HAS_OPP  	select ARCH_MXC_IOMUX_V3  	select COMMON_CLK  	select CPU_V7 @@ -783,7 +790,7 @@ config	SOC_IMX53  	  This enables support for Freescale i.MX53 processor.  config SOC_IMX6Q -	bool "i.MX6 Quad support" +	bool "i.MX6 Quad/DualLite support"  	select ARCH_HAS_CPUFREQ  	select ARCH_HAS_OPP  	select ARM_CPU_SUSPEND if PM @@ -796,6 +803,7 @@ config SOC_IMX6Q  	select HAVE_ARM_SCU if SMP  	select HAVE_ARM_TWD if LOCAL_TIMERS  	select HAVE_CAN_FLEXCAN if CAN +	select HAVE_IMX_ANATOP  	select HAVE_IMX_GPC  	select HAVE_IMX_MMDC  	select HAVE_IMX_SRC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index fbe60a14534..930958973f8 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_MACH_EUKREA_CPUIMX35SD) += mach-cpuimx35.o  obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o  obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o +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 diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c new file mode 100644 index 00000000000..0cfa07dd9aa --- /dev/null +++ b/arch/arm/mach-imx/anatop.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include "common.h" + +#define REG_SET		0x4 +#define REG_CLR		0x8 + +#define ANADIG_REG_2P5		0x130 +#define ANADIG_REG_CORE		0x140 +#define ANADIG_ANA_MISC0	0x150 +#define ANADIG_USB1_CHRG_DETECT	0x1b0 +#define ANADIG_USB2_CHRG_DETECT	0x210 +#define ANADIG_DIGPROG		0x260 + +#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG	0x40000 +#define BM_ANADIG_REG_CORE_FET_ODRIVE		0x20000000 +#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	0x1000 +#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x80000 +#define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x100000 + +static struct regmap *anatop; + +static void imx_anatop_enable_weak2p5(bool enable) +{ +	u32 reg, val; + +	regmap_read(anatop, ANADIG_ANA_MISC0, &val); + +	/* can only be enabled when stop_mode_config is clear. */ +	reg = ANADIG_REG_2P5; +	reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ? +		REG_SET : REG_CLR; +	regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG); +} + +static void imx_anatop_enable_fet_odrive(bool enable) +{ +	regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR), +		BM_ANADIG_REG_CORE_FET_ODRIVE); +} + +void imx_anatop_pre_suspend(void) +{ +	imx_anatop_enable_weak2p5(true); +	imx_anatop_enable_fet_odrive(true); +} + +void imx_anatop_post_resume(void) +{ +	imx_anatop_enable_fet_odrive(false); +	imx_anatop_enable_weak2p5(false); +} + +void imx_anatop_usb_chrg_detect_disable(void) +{ +	regmap_write(anatop, ANADIG_USB1_CHRG_DETECT, +		BM_ANADIG_USB_CHRG_DETECT_EN_B +		| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); +	regmap_write(anatop, ANADIG_USB2_CHRG_DETECT, +		BM_ANADIG_USB_CHRG_DETECT_EN_B | +		BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); +} + +u32 imx_anatop_get_digprog(void) +{ +	struct device_node *np; +	void __iomem *anatop_base; +	static u32 digprog; + +	if (digprog) +		return digprog; + +	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); +	anatop_base = of_iomap(np, 0); +	WARN_ON(!anatop_base); +	digprog = readl_relaxed(anatop_base + ANADIG_DIGPROG); + +	return digprog; +} + +void __init imx_anatop_init(void) +{ +	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); +	if (IS_ERR(anatop)) { +		pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); +		return; +	} +} diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 2bc623b414c..6fc486b6a3c 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -45,16 +45,40 @@ static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "  static const char *mx53_ldb_di1_sel[] = { "pll3_sw", "pll4_sw", };  static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", };  static const char *mx53_tve_ext_sel[] = { "pll4_sw", "ckih1", }; -static const char *tve_sel[] = { "tve_pred", "tve_ext_sel", }; +static const char *mx51_tve_sel[] = { "tve_pred", "tve_ext_sel", };  static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", }; +static const char *gpu3d_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb" }; +static const char *gpu2d_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb" };  static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", };  static const char *mx53_can_sel[] = { "ipg", "ckih1", "ckih2", "lp_apm", }; +static const char *mx53_cko1_sel[] = { +	"cpu_podf", "pll1_sw", "pll2_sw", "pll3_sw", +	"emi_slow_podf", "pll4_sw", "nfc_podf", "dummy", +	"di_pred", "dummy", "dummy", "ahb", +	"ipg", "per_root", "ckil", "dummy",}; +static const char *mx53_cko2_sel[] = { +	"dummy"/* dptc_core */, "dummy"/* dptc_perich */, +	"dummy", "esdhc_a_podf", +	"usboh3_podf", "dummy"/* wrck_clk_root */, +	"ecspi_podf", "dummy"/* pll1_ref_clk */, +	"esdhc_b_podf", "dummy"/* ddr_clk_root */, +	"dummy"/* arm_axi_clk_root */, "dummy"/* usb_phy_out */, +	"vpu_sel", "ipu_sel", +	"osc", "ckih1", +	"dummy", "esdhc_c_sel", +	"ssi1_root_podf", "ssi2_root_podf", +	"dummy", "dummy", +	"dummy"/* lpsr_clk_root */, "dummy"/* pgc_clk_root */, +	"dummy"/* tve_out */, "usb_phy_sel", +	"tve_sel", "lp_apm", +	"uart_root", "dummy"/* spdif0_clk_root */, +	"dummy", "dummy", };  enum imx5_clks {  	dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred,  	uart_root, esdhc_a_pred, esdhc_b_pred, esdhc_c_s, esdhc_d_s,  	emi_sel, emi_slow_podf, nfc_podf, ecspi_pred, ecspi_podf, usboh3_pred, -	usboh3_podf, usb_phy_pred, usb_phy_podf, cpu_podf, di_pred, tve_di, +	usboh3_podf, usb_phy_pred, usb_phy_podf, cpu_podf, di_pred, tve_di_unused,  	tve_s, uart1_ipg_gate, uart1_per_gate, uart2_ipg_gate,  	uart2_per_gate, uart3_ipg_gate, uart3_per_gate, i2c1_gate, i2c2_gate,  	gpt_ipg_gate, pwm1_ipg_gate, pwm1_hf_gate, pwm2_ipg_gate, pwm2_hf_gate, @@ -83,7 +107,10 @@ enum imx5_clks {  	ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate,  	epit1_ipg_gate, epit1_hf_gate, epit2_ipg_gate, epit2_hf_gate,  	can_sel, can1_serial_gate, can1_ipg_gate, -	owire_gate, +	owire_gate, gpu3d_s, gpu2d_s, gpu3d_gate, gpu2d_gate, garb_gate, +	cko1_sel, cko1_podf, cko1, +	cko2_sel, cko2_podf, cko2, +	srtc_gate, pata_gate,  	clk_max  }; @@ -160,8 +187,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  				usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));  	clk[cpu_podf] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3);  	clk[di_pred] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3); -	clk[tve_di] = imx_clk_fixed("tve_di", 65000000); /* FIXME */ -	clk[tve_s] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1, tve_sel, ARRAY_SIZE(tve_sel));  	clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30);  	clk[uart1_ipg_gate] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6);  	clk[uart1_per_gate] = imx_clk_gate2("uart1_per_gate", "uart_root", MXC_CCM_CCGR1, 8); @@ -200,6 +225,11 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  	clk[nfc_gate] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20);  	clk[ipu_di0_gate] = imx_clk_gate2("ipu_di0_gate", "ipu_di0_sel", MXC_CCM_CCGR6, 10);  	clk[ipu_di1_gate] = imx_clk_gate2("ipu_di1_gate", "ipu_di1_sel", MXC_CCM_CCGR6, 12); +	clk[gpu3d_s] = imx_clk_mux("gpu3d_sel", MXC_CCM_CBCMR, 4, 2, gpu3d_sel, ARRAY_SIZE(gpu3d_sel)); +	clk[gpu2d_s] = imx_clk_mux("gpu2d_sel", MXC_CCM_CBCMR, 16, 2, gpu2d_sel, ARRAY_SIZE(gpu2d_sel)); +	clk[gpu3d_gate] = imx_clk_gate2("gpu3d_gate", "gpu3d_sel", MXC_CCM_CCGR5, 2); +	clk[garb_gate] = imx_clk_gate2("garb_gate", "axi_a", MXC_CCM_CCGR5, 4); +	clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "gpu2d_sel", MXC_CCM_CCGR6, 14);  	clk[vpu_s] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel));  	clk[vpu_gate] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6);  	clk[vpu_reference_gate] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); @@ -235,6 +265,8 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  	clk[epit2_ipg_gate] = imx_clk_gate2("epit2_ipg_gate", "ipg", MXC_CCM_CCGR2, 6);  	clk[epit2_hf_gate] = imx_clk_gate2("epit2_hf_gate", "per_root", MXC_CCM_CCGR2, 8);  	clk[owire_gate] = imx_clk_gate2("owire_gate", "per_root", MXC_CCM_CCGR2, 22); +	clk[srtc_gate] = imx_clk_gate2("srtc_gate", "per_root", MXC_CCM_CCGR4, 28); +	clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", MXC_CCM_CCGR4, 0);  	for (i = 0; i < ARRAY_SIZE(clk); i++)  		if (IS_ERR(clk[i])) @@ -286,7 +318,6 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,  	clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.0");  	clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1");  	clk_register_clkdev(clk[dummy], NULL, "imx-keypad"); -	clk_register_clkdev(clk[tve_gate], NULL, "imx-tve.0");  	clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx-tve.0");  	clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL);  	clk_register_clkdev(clk[epit1_ipg_gate], "ipg", "imx-epit.0"); @@ -331,8 +362,10 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,  				mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));  	clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,  				mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel)); -	clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, -				mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel)); +	clk[tve_ext_sel] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, +				mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel), CLK_SET_RATE_PARENT); +	clk[tve_s] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1, +				mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel));  	clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30);  	clk[tve_pred] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3);  	clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); @@ -420,23 +453,23 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,  	clk[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX53_DPLL3_BASE);  	clk[pll4_sw] = imx_clk_pllv2("pll4_sw", "osc", MX53_DPLL4_BASE); -	clk[ldb_di1_sel] = imx_clk_mux("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1, -				mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel));  	clk[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); -	clk[ldb_di1_div] = imx_clk_divider("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1); +	clk[ldb_di1_div] = imx_clk_divider_flags("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1, 0); +	clk[ldb_di1_sel] = imx_clk_mux_flags("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1, +				mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel), CLK_SET_RATE_PARENT);  	clk[di_pll4_podf] = imx_clk_divider("di_pll4_podf", "pll4_sw", MXC_CCM_CDCDR, 16, 3); -	clk[ldb_di0_sel] = imx_clk_mux("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1, -				mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel));  	clk[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); -	clk[ldb_di0_div] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1); +	clk[ldb_di0_div] = imx_clk_divider_flags("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1, 0); +	clk[ldb_di0_sel] = imx_clk_mux_flags("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1, +				mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel), CLK_SET_RATE_PARENT);  	clk[ldb_di0_gate] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28);  	clk[ldb_di1_gate] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30);  	clk[ipu_di0_sel] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,  				mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));  	clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,  				mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel)); -	clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, -				mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel)); +	clk[tve_ext_sel] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, +				mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);  	clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);  	clk[tve_pred] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3);  	clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); @@ -453,6 +486,16 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,  	clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 6);  	clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22); +	clk[cko1_sel] = imx_clk_mux("cko1_sel", MXC_CCM_CCOSR, 0, 4, +				mx53_cko1_sel, ARRAY_SIZE(mx53_cko1_sel)); +	clk[cko1_podf] = imx_clk_divider("cko1_podf", "cko1_sel", MXC_CCM_CCOSR, 4, 3); +	clk[cko1] = imx_clk_gate2("cko1", "cko1_podf", MXC_CCM_CCOSR, 7); + +	clk[cko2_sel] = imx_clk_mux("cko2_sel", MXC_CCM_CCOSR, 16, 5, +				mx53_cko2_sel, ARRAY_SIZE(mx53_cko2_sel)); +	clk[cko2_podf] = imx_clk_divider("cko2_podf", "cko2_sel", MXC_CCM_CCOSR, 21, 3); +	clk[cko2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24); +  	for (i = 0; i < ARRAY_SIZE(clk); i++)  		if (IS_ERR(clk[i]))  			pr_err("i.MX53 clk %d: register failed with %ld\n", diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index d38e54f5b6d..15125900308 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -14,6 +14,7 @@  #include <linux/types.h>  #include <linux/clk.h>  #include <linux/clkdev.h> +#include <linux/delay.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/of.h> @@ -22,6 +23,12 @@  #include "clk.h"  #include "common.h" +#include "hardware.h" + +#define CCR				0x0 +#define BM_CCR_WB_COUNT			(0x7 << 16) +#define BM_CCR_RBC_BYPASS_COUNT		(0x3f << 21) +#define BM_CCR_RBC_EN			(0x1 << 27)  #define CCGR0				0x68  #define CCGR1				0x6c @@ -67,6 +74,67 @@ void imx6q_set_chicken_bit(void)  	writel_relaxed(val, ccm_base + CGPR);  } +static void imx6q_enable_rbc(bool enable) +{ +	u32 val; +	static bool last_rbc_mode; + +	if (last_rbc_mode == enable) +		return; +	/* +	 * need to mask all interrupts in GPC before +	 * operating RBC configurations +	 */ +	imx_gpc_mask_all(); + +	/* configure RBC enable bit */ +	val = readl_relaxed(ccm_base + CCR); +	val &= ~BM_CCR_RBC_EN; +	val |= enable ? BM_CCR_RBC_EN : 0; +	writel_relaxed(val, ccm_base + CCR); + +	/* configure RBC count */ +	val = readl_relaxed(ccm_base + CCR); +	val &= ~BM_CCR_RBC_BYPASS_COUNT; +	val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; +	writel(val, ccm_base + CCR); + +	/* +	 * need to delay at least 2 cycles of CKIL(32K) +	 * due to hardware design requirement, which is +	 * ~61us, here we use 65us for safe +	 */ +	udelay(65); + +	/* restore GPC interrupt mask settings */ +	imx_gpc_restore_all(); + +	last_rbc_mode = enable; +} + +static void imx6q_enable_wb(bool enable) +{ +	u32 val; +	static bool last_wb_mode; + +	if (last_wb_mode == enable) +		return; + +	/* configure well bias enable bit */ +	val = readl_relaxed(ccm_base + CLPCR); +	val &= ~BM_CLPCR_WB_PER_AT_LPM; +	val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; +	writel_relaxed(val, ccm_base + CLPCR); + +	/* configure well bias count */ +	val = readl_relaxed(ccm_base + CCR); +	val &= ~BM_CCR_WB_COUNT; +	val |= enable ? BM_CCR_WB_COUNT : 0; +	writel_relaxed(val, ccm_base + CCR); + +	last_wb_mode = enable; +} +  int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)  {  	u32 val = readl_relaxed(ccm_base + CLPCR); @@ -74,6 +142,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)  	val &= ~BM_CLPCR_LPM;  	switch (mode) {  	case WAIT_CLOCKED: +		imx6q_enable_wb(false); +		imx6q_enable_rbc(false);  		break;  	case WAIT_UNCLOCKED:  		val |= 0x1 << BP_CLPCR_LPM; @@ -92,6 +162,8 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)  		val |= 0x3 << BP_CLPCR_STBY_COUNT;  		val |= BM_CLPCR_VSTBY;  		val |= BM_CLPCR_SBYOS; +		imx6q_enable_wb(true); +		imx6q_enable_rbc(true);  		break;  	default:  		return -EINVAL; @@ -109,29 +181,29 @@ static const char *periph_clk2_sels[]	= { "pll3_usb_otg", "osc", };  static const char *periph_sels[]	= { "periph_pre", "periph_clk2", };  static const char *periph2_sels[]	= { "periph2_pre", "periph2_clk2", };  static const char *axi_sels[]		= { "periph", "pll2_pfd2_396m", "pll3_pfd1_540m", }; -static const char *audio_sels[]	= { "pll4_audio", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; +static const char *audio_sels[]	= { "pll4_post_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", };  static const char *gpu_axi_sels[]	= { "axi", "ahb", };  static const char *gpu2d_core_sels[]	= { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", };  static const char *gpu3d_core_sels[]	= { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", };  static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd9_720m", };  static const char *ipu_sels[]		= { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };  static const char *ldb_di_sels[]	= { "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", }; -static const char *ipu_di_pre_sels[]	= { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *ipu_di_pre_sels[]	= { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };  static const char *ipu1_di0_sels[]	= { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *ipu1_di1_sels[]	= { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *ipu2_di0_sels[]	= { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *ipu2_di1_sels[]	= { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };  static const char *hsi_tx_sels[]	= { "pll3_120m", "pll2_pfd2_396m", };  static const char *pcie_axi_sels[]	= { "axi", "ahb", }; -static const char *ssi_sels[]		= { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio", }; +static const char *ssi_sels[]		= { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_post_div", };  static const char *usdhc_sels[]	= { "pll2_pfd2_396m", "pll2_pfd0_352m", };  static const char *enfc_sels[]	= { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", };  static const char *emi_sels[]		= { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", };  static const char *vdo_axi_sels[]	= { "axi", "ahb", };  static const char *vpu_axi_sels[]	= { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", }; -static const char *cko1_sels[]	= { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video", +static const char *cko1_sels[]	= { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div",  				    "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", -				    "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio", }; +				    "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_post_div", };  enum mx6q_clks {  	dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, @@ -165,7 +237,7 @@ enum mx6q_clks {  	pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg,  	ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5,  	sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, -	usbphy2_gate, clk_max +	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, clk_max  };  static struct clk *clk[clk_max]; @@ -182,6 +254,21 @@ static struct clk_div_table clk_enet_ref_table[] = {  	{ .val = 3, .div = 4, },  }; +static struct clk_div_table post_div_table[] = { +	{ .val = 2, .div = 1, }, +	{ .val = 1, .div = 2, }, +	{ .val = 0, .div = 4, }, +	{ } +}; + +static struct clk_div_table video_div_table[] = { +	{ .val = 0, .div = 1, }, +	{ .val = 1, .div = 2, }, +	{ .val = 2, .div = 1, }, +	{ .val = 3, .div = 4, }, +	{ } +}; +  int __init mx6q_clocks_init(void)  {  	struct device_node *np; @@ -208,6 +295,14 @@ int __init mx6q_clocks_init(void)  	base = of_iomap(np, 0);  	WARN_ON(!base); +	/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ +	if (cpu_is_imx6q() && imx6q_revision() == IMX_CHIP_REVISION_1_0) { +		post_div_table[1].div = 1; +		post_div_table[2].div = 1; +		video_div_table[1].div = 1; +		video_div_table[2].div = 1; +	}; +  	/*                   type                               name         parent_name  base     div_mask */  	clk[pll1_sys]      = imx_clk_pllv3(IMX_PLLV3_SYS,	"pll1_sys",	"osc", base,        0x7f);  	clk[pll2_bus]      = imx_clk_pllv3(IMX_PLLV3_GENERIC,	"pll2_bus",	"osc", base + 0x30, 0x1); @@ -260,6 +355,10 @@ int __init mx6q_clocks_init(void)  	clk[pll3_60m]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);  	clk[twd]       = imx_clk_fixed_factor("twd",       "arm",            1, 2); +	clk[pll4_post_div] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); +	clk[pll5_post_div] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); +	clk[pll5_video_div] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); +  	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm");  	base = of_iomap(np, 0);  	WARN_ON(!base); @@ -283,8 +382,8 @@ int __init mx6q_clocks_init(void)  	clk[gpu3d_shader_sel] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));  	clk[ipu1_sel]         = imx_clk_mux("ipu1_sel",         base + 0x3c, 9,  2, ipu_sels,          ARRAY_SIZE(ipu_sels));  	clk[ipu2_sel]         = imx_clk_mux("ipu2_sel",         base + 0x3c, 14, 2, ipu_sels,          ARRAY_SIZE(ipu_sels)); -	clk[ldb_di0_sel]      = imx_clk_mux("ldb_di0_sel",      base + 0x2c, 9,  3, ldb_di_sels,       ARRAY_SIZE(ldb_di_sels)); -	clk[ldb_di1_sel]      = imx_clk_mux("ldb_di1_sel",      base + 0x2c, 12, 3, ldb_di_sels,       ARRAY_SIZE(ldb_di_sels)); +	clk[ldb_di0_sel]      = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9,  3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); +	clk[ldb_di1_sel]      = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels,      ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);  	clk[ipu1_di0_pre_sel] = imx_clk_mux("ipu1_di0_pre_sel", base + 0x34, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));  	clk[ipu1_di1_pre_sel] = imx_clk_mux("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels));  	clk[ipu2_di0_pre_sel] = imx_clk_mux("ipu2_di0_pre_sel", base + 0x38, 6,  3, ipu_di_pre_sels,   ARRAY_SIZE(ipu_di_pre_sels)); @@ -332,9 +431,9 @@ int __init mx6q_clocks_init(void)  	clk[ipu1_podf]        = imx_clk_divider("ipu1_podf",        "ipu1_sel",          base + 0x3c, 11, 3);  	clk[ipu2_podf]        = imx_clk_divider("ipu2_podf",        "ipu2_sel",          base + 0x3c, 16, 3);  	clk[ldb_di0_div_3_5]  = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); -	clk[ldb_di0_podf]     = imx_clk_divider("ldb_di0_podf",     "ldb_di0_div_3_5",       base + 0x20, 10, 1); +	clk[ldb_di0_podf]     = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0);  	clk[ldb_di1_div_3_5]  = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); -	clk[ldb_di1_podf]     = imx_clk_divider("ldb_di1_podf",     "ldb_di1_div_3_5",   base + 0x20, 11, 1); +	clk[ldb_di1_podf]     = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0);  	clk[ipu1_di0_pre]     = imx_clk_divider("ipu1_di0_pre",     "ipu1_di0_pre_sel",  base + 0x34, 3,  3);  	clk[ipu1_di1_pre]     = imx_clk_divider("ipu1_di1_pre",     "ipu1_di1_pre_sel",  base + 0x34, 12, 3);  	clk[ipu2_di0_pre]     = imx_clk_divider("ipu2_di0_pre",     "ipu2_di0_pre_sel",  base + 0x38, 3,  3); @@ -448,6 +547,11 @@ int __init mx6q_clocks_init(void)  	clk_register_clkdev(clk[cko1], "cko1", NULL);  	clk_register_clkdev(clk[arm], NULL, "cpu0"); +	if (imx6q_revision() != IMX_CHIP_REVISION_1_0) { +		clk_set_parent(clk[ldb_di0_sel], clk[pll5_video_div]); +		clk_set_parent(clk[ldb_di1_sel], clk[pll5_video_div]); +	} +  	/*  	 * The gpmi needs 100MHz frequency in the EDO/Sync mode,  	 * We can not get the 100MHz from the pll2_pfd0_352m. diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 9d1f3b99d1d..d9d9d9c66df 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -59,6 +59,14 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent,  			reg, shift, width, 0, &imx_ccm_lock);  } +static inline struct clk *imx_clk_divider_flags(const char *name, +		const char *parent, void __iomem *reg, u8 shift, u8 width, +		unsigned long flags) +{ +	return clk_register_divider(NULL, name, parent, flags, +			reg, shift, width, 0, &imx_ccm_lock); +} +  static inline struct clk *imx_clk_gate(const char *name, const char *parent,  		void __iomem *reg, u8 shift)  { @@ -73,6 +81,15 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,  			width, 0, &imx_ccm_lock);  } +static inline struct clk *imx_clk_mux_flags(const char *name, +		void __iomem *reg, u8 shift, u8 width, const char **parents, +		int num_parents, unsigned long flags) +{ +	return clk_register_mux(NULL, name, parents, num_parents, +			flags, reg, shift, width, 0, +			&imx_ccm_lock); +} +  static inline struct clk *imx_clk_fixed_factor(const char *name,  		const char *parent, unsigned int mult, unsigned int div)  { diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 9fea2522d7a..4cba7dbb079 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -1,5 +1,5 @@  /* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.   */  /* @@ -74,6 +74,7 @@ extern void mxc_set_cpu_type(unsigned int type);  extern void mxc_restart(char, const char *);  extern void mxc_arch_reset_init(void __iomem *);  extern int mx53_revision(void); +extern int imx6q_revision(void);  extern int mx53_display_revision(void);  extern void imx_set_aips(void __iomem *);  extern int mxc_device_init(void); @@ -128,6 +129,13 @@ extern void imx_src_prepare_restart(void);  extern void imx_gpc_init(void);  extern void imx_gpc_pre_suspend(void);  extern void imx_gpc_post_resume(void); +extern void imx_gpc_mask_all(void); +extern void imx_gpc_restore_all(void); +extern void imx_anatop_init(void); +extern void imx_anatop_pre_suspend(void); +extern void imx_anatop_post_resume(void); +extern void imx_anatop_usb_chrg_detect_disable(void); +extern u32 imx_anatop_get_digprog(void);  extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);  extern void imx6q_set_chicken_bit(void); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 02b61cdf39b..44a65e9ff1f 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -69,6 +69,27 @@ static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)  	return 0;  } +void imx_gpc_mask_all(void) +{ +	void __iomem *reg_imr1 = gpc_base + GPC_IMR1; +	int i; + +	for (i = 0; i < IMR_NUM; i++) { +		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); +		writel_relaxed(~0, reg_imr1 + i * 4); +	} + +} + +void imx_gpc_restore_all(void) +{ +	void __iomem *reg_imr1 = gpc_base + GPC_IMR1; +	int i; + +	for (i = 0; i < IMR_NUM; i++) +		writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); +} +  static void imx_gpc_irq_unmask(struct irq_data *d)  {  	void __iomem *reg; diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 99502eeefdf..5536fd81379 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -38,38 +38,32 @@  #include "cpuidle.h"  #include "hardware.h" -#define IMX6Q_ANALOG_DIGPROG	0x260 +static u32 chip_revision; -static int imx6q_revision(void) +int imx6q_revision(void)  { -	struct device_node *np; -	void __iomem *base; -	static u32 rev; +	return chip_revision; +} -	if (!rev) { -		np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); -		if (!np) -			return IMX_CHIP_REVISION_UNKNOWN; -		base = of_iomap(np, 0); -		if (!base) { -			of_node_put(np); -			return IMX_CHIP_REVISION_UNKNOWN; -		} -		rev =  readl_relaxed(base + IMX6Q_ANALOG_DIGPROG); -		iounmap(base); -		of_node_put(np); -	} +static void __init imx6q_init_revision(void) +{ +	u32 rev = imx_anatop_get_digprog();  	switch (rev & 0xff) {  	case 0: -		return IMX_CHIP_REVISION_1_0; +		chip_revision = IMX_CHIP_REVISION_1_0; +		break;  	case 1: -		return IMX_CHIP_REVISION_1_1; +		chip_revision = IMX_CHIP_REVISION_1_1; +		break;  	case 2: -		return IMX_CHIP_REVISION_1_2; +		chip_revision = IMX_CHIP_REVISION_1_2; +		break;  	default: -		return IMX_CHIP_REVISION_UNKNOWN; +		chip_revision = IMX_CHIP_REVISION_UNKNOWN;  	} + +	mxc_set_cpu_type(rev >> 16 & 0xff);  }  static void imx6q_restart(char mode, const char *cmd) @@ -164,29 +158,7 @@ static void __init imx6q_1588_init(void)  }  static void __init imx6q_usb_init(void)  { -	struct regmap *anatop; - -#define HW_ANADIG_USB1_CHRG_DETECT		0x000001b0 -#define HW_ANADIG_USB2_CHRG_DETECT		0x00000210 - -#define BM_ANADIG_USB_CHRG_DETECT_EN_B		0x00100000 -#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B	0x00080000 - -	anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); -	if (!IS_ERR(anatop)) { -		/* -		 * The external charger detector needs to be disabled, -		 * or the signal at DP will be poor -		 */ -		regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT, -				BM_ANADIG_USB_CHRG_DETECT_EN_B -				| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); -		regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT, -				BM_ANADIG_USB_CHRG_DETECT_EN_B | -				BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); -	} else { -		pr_warn("failed to find fsl,imx6q-anatop regmap\n"); -	} +	imx_anatop_usb_chrg_detect_disable();  }  static void __init imx6q_init_machine(void) @@ -196,6 +168,7 @@ static void __init imx6q_init_machine(void)  	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +	imx_anatop_init();  	imx6q_pm_init();  	imx6q_usb_init();  	imx6q_1588_init(); @@ -282,6 +255,7 @@ static void __init imx6q_map_io(void)  static void __init imx6q_init_irq(void)  { +	imx6q_init_revision();  	l2x0_of_init(0, ~0UL);  	imx_src_init();  	imx_gpc_init(); @@ -292,15 +266,17 @@ static void __init imx6q_timer_init(void)  {  	mx6q_clocks_init();  	clocksource_of_init(); -	imx_print_silicon_rev("i.MX6Q", imx6q_revision()); +	imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", +			      imx6q_revision());  }  static const char *imx6q_dt_compat[] __initdata = { +	"fsl,imx6dl",  	"fsl,imx6q",  	NULL,  }; -DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)") +DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")  	.smp		= smp_ops(imx_smp_ops),  	.map_io		= imx6q_map_io,  	.init_irq	= imx6q_init_irq, diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c index 7a146671e65..3c609c52d3e 100644 --- a/arch/arm/mach-imx/mm-imx1.c +++ b/arch/arm/mach-imx/mm-imx1.c @@ -51,6 +51,8 @@ void __init mx1_init_irq(void)  void __init imx1_soc_init(void)  { +	mxc_device_init(); +  	mxc_register_gpio("imx1-gpio", 0, MX1_GPIO1_BASE_ADDR, SZ_256,  						MX1_GPIO_INT_PORTA, 0);  	mxc_register_gpio("imx1-gpio", 1, MX1_GPIO2_BASE_ADDR, SZ_256, diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 7dce17a9fe6..8629e5be7ec 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -34,6 +34,8 @@  #define MXC_CPU_MX35		35  #define MXC_CPU_MX51		51  #define MXC_CPU_MX53		53 +#define MXC_CPU_IMX6DL		0x61 +#define MXC_CPU_IMX6Q		0x63  #define IMX_CHIP_REVISION_1_0		0x10  #define IMX_CHIP_REVISION_1_1		0x11 @@ -150,6 +152,15 @@ extern unsigned int __mxc_cpu_type;  #endif  #ifndef __ASSEMBLY__ +static inline bool cpu_is_imx6dl(void) +{ +	return __mxc_cpu_type == MXC_CPU_IMX6DL; +} + +static inline bool cpu_is_imx6q(void) +{ +	return __mxc_cpu_type == MXC_CPU_IMX6Q; +}  struct cpu_op {  	u32 cpu_rate; diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 77e9a25ed0f..4a69305db65 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -68,8 +68,8 @@ static void __init imx_smp_init_cpus(void)  	ncores = scu_get_core_count(scu_base); -	for (i = 0; i < ncores; i++) -		set_cpu_possible(i, true); +	for (i = ncores; i < NR_CPUS; i++) +		set_cpu_possible(i, false);  }  void imx_smp_prepare(void) diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index 5faba7a3c95..204942749e2 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -1,5 +1,5 @@  /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2013 Freescale Semiconductor, Inc.   * Copyright 2011 Linaro Ltd.   *   * The code contained herein is licensed under the GNU General Public @@ -34,10 +34,12 @@ static int imx6q_pm_enter(suspend_state_t state)  	case PM_SUSPEND_MEM:  		imx6q_set_lpm(STOP_POWER_OFF);  		imx_gpc_pre_suspend(); +		imx_anatop_pre_suspend();  		imx_set_cpu_jump(0, v7_cpu_resume);  		/* Zzz ... */  		cpu_suspend(0, imx6q_suspend_finish);  		imx_smp_prepare(); +		imx_anatop_post_resume();  		imx_gpc_post_resume();  		imx6q_set_lpm(WAIT_CLOCKED);  		break; diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 97d08688948..10a6b1a8c5a 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -14,6 +14,7 @@  #include <linux/io.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/reset-controller.h>  #include <linux/smp.h>  #include <asm/smp_plat.h>  #include "common.h" @@ -21,10 +22,65 @@  #define SRC_SCR				0x000  #define SRC_GPR1			0x020  #define BP_SRC_SCR_WARM_RESET_ENABLE	0 +#define BP_SRC_SCR_SW_GPU_RST		1 +#define BP_SRC_SCR_SW_VPU_RST		2 +#define BP_SRC_SCR_SW_IPU1_RST		3 +#define BP_SRC_SCR_SW_OPEN_VG_RST	4 +#define BP_SRC_SCR_SW_IPU2_RST		12  #define BP_SRC_SCR_CORE1_RST		14  #define BP_SRC_SCR_CORE1_ENABLE		22  static void __iomem *src_base; +static DEFINE_SPINLOCK(scr_lock); + +static const int sw_reset_bits[5] = { +	BP_SRC_SCR_SW_GPU_RST, +	BP_SRC_SCR_SW_VPU_RST, +	BP_SRC_SCR_SW_IPU1_RST, +	BP_SRC_SCR_SW_OPEN_VG_RST, +	BP_SRC_SCR_SW_IPU2_RST +}; + +static int imx_src_reset_module(struct reset_controller_dev *rcdev, +		unsigned long sw_reset_idx) +{ +	unsigned long timeout; +	unsigned long flags; +	int bit; +	u32 val; + +	if (!src_base) +		return -ENODEV; + +	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits)) +		return -EINVAL; + +	bit = 1 << sw_reset_bits[sw_reset_idx]; + +	spin_lock_irqsave(&scr_lock, flags); +	val = readl_relaxed(src_base + SRC_SCR); +	val |= bit; +	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock_irqrestore(&scr_lock, flags); + +	timeout = jiffies + msecs_to_jiffies(1000); +	while (readl(src_base + SRC_SCR) & bit) { +		if (time_after(jiffies, timeout)) +			return -ETIME; +		cpu_relax(); +	} + +	return 0; +} + +static struct reset_control_ops imx_src_ops = { +	.reset = imx_src_reset_module, +}; + +static struct reset_controller_dev imx_reset_controller = { +	.ops = &imx_src_ops, +	.nr_resets = ARRAY_SIZE(sw_reset_bits), +};  void imx_enable_cpu(int cpu, bool enable)  { @@ -32,9 +88,11 @@ void imx_enable_cpu(int cpu, bool enable)  	cpu = cpu_logical_map(cpu);  	mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); +	spin_lock(&scr_lock);  	val = readl_relaxed(src_base + SRC_SCR);  	val = enable ? val | mask : val & ~mask;  	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock(&scr_lock);  }  void imx_set_cpu_jump(int cpu, void *jump_addr) @@ -61,9 +119,11 @@ void imx_src_prepare_restart(void)  	u32 val;  	/* clear enable bits of secondary cores */ +	spin_lock(&scr_lock);  	val = readl_relaxed(src_base + SRC_SCR);  	val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);  	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock(&scr_lock);  	/* clear persistent entry register of primary core */  	writel_relaxed(0, src_base + SRC_GPR1); @@ -80,11 +140,17 @@ void __init imx_src_init(void)  	src_base = of_iomap(np, 0);  	WARN_ON(!src_base); +	imx_reset_controller.of_node = np; +	if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) +		reset_controller_register(&imx_reset_controller); +  	/*  	 * force warm reset sources to generate cold reset  	 * for a more reliable restart  	 */ +	spin_lock(&scr_lock);  	val = readl_relaxed(src_base + SRC_SCR);  	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);  	writel_relaxed(val, src_base + SRC_SCR); +	spin_unlock(&scr_lock);  }  |