From 64990a431469a58b2949aca5be9d69e220d53892 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 23 Aug 2013 19:20:34 +0800 Subject: [PATCH 01/31] ARM: imx6q: Add pll4_audio_div to clock tree There's a pll4_audio_div clock, an extra divider for pll4, missing in current clock tree, thus add it. Signed-off-by: Nicolin Chen Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/clock/imx6q-clock.txt | 1 + arch/arm/mach-imx/clk-imx6q.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt index 5a90a724b520..e8b1baae9ae4 100644 --- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt @@ -215,6 +215,7 @@ clocks and IDs. cko2 200 cko 201 vdoa 202 + pll4_audio_div 203 Examples: diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 9181a241d3a8..913ad85ad621 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -182,7 +182,7 @@ static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; 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", "periph", "pll3_pfd1_540m", }; -static const char *audio_sels[] = { "pll4_post_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; +static const char *audio_sels[] = { "pll4_audio_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", }; @@ -196,7 +196,7 @@ static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di 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_post_div", }; +static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_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[] = { "pll2_pfd2_396m", "pll3_usb_otg", "axi", "pll2_pfd0_352m", }; @@ -205,7 +205,7 @@ 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_div", "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", - "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_post_div", }; + "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", }; static const char *cko2_sels[] = { "mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1", "gpu2d_axi", "dummy", "ecspi_root", "gpu3d_axi", @@ -251,7 +251,7 @@ enum mx6q_clks { 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, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, - spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, clk_max + spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, clk_max }; static struct clk *clk[clk_max]; @@ -359,6 +359,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) 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[pll4_audio_div] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &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); From 7f6ac89c1d1e0c654ea02c8c2dd0ee8e1ce2795f Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 3 Sep 2013 12:26:24 +0800 Subject: [PATCH 02/31] ARM: imx6sl: add imx6sl iomux-gpr field define Add imx6sl iomux-gpr register field define in "imx6q-iomuxc-gpr.h" header file, which is not fully define all iomux-gpr registers and fields, only add fec related macro define. Signed-off-by: Fugang Duan Signed-off-by: Shawn Guo --- include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index b6bdcd66c07d..7086b2248c8f 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -363,4 +363,9 @@ #define IMX6Q_GPR13_SATA_TX_LVL_1_240_V (0x1f << 2) #define IMX6Q_GPR13_SATA_MPLL_CLK_EN BIT(1) #define IMX6Q_GPR13_SATA_TX_EDGE_RATE BIT(0) + +/* For imx6sl iomux gpr register field define */ +#define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK (0x3 << 17) +#define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK (0x1 << 14) + #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */ From a9aec30dcf2aae5929bc43ada552a33c8d737967 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 4 Sep 2013 10:58:17 +0800 Subject: [PATCH 03/31] ARM: imx6sl: config iomux-gpr1 to select clock for fec Config iomux-gpr1 to select clock source for fec system clock. Clear gpr1[14], gpr1[18-17] bit to select the fec clock source from internal anatop PLL. Signed-off-by: Fugang Duan Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mach-imx6sl.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index c70bd7c64974..21cde21daf9b 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -10,16 +10,37 @@ #include #include #include +#include +#include +#include #include #include #include "common.h" +static void __init imx6sl_fec_init(void) +{ + struct regmap *gpr; + + /* set FEC clock from internal PLL clock source */ + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sl-iomuxc-gpr"); + if (!IS_ERR(gpr)) { + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK, 0); + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK, 0); + } else { + pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); + } +} + static void __init imx6sl_init_machine(void) { mxc_arch_reset_init_dt(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + imx6sl_fec_init(); } static void __init imx6sl_init_irq(void) From 4c1dd3e5edc1619199b4a42618169ac3ac457cb5 Mon Sep 17 00:00:00 2001 From: Michael Opdenacker Date: Wed, 4 Sep 2013 07:04:39 +0200 Subject: [PATCH 04/31] ARM: imx: remove IRQF_DISABLED This flag is a NOOP since 2.6.35 and can be removed. This is an update for 3.11 of a patch already sent for 3.10 Signed-off-by: Michael Opdenacker Acked-by: Sascha Hauer Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 2 +- arch/arm/mach-imx/epit.c | 2 +- arch/arm/mach-imx/mach-armadillo5x0.c | 3 +-- arch/arm/mach-imx/mach-mx31_3ds.c | 2 +- arch/arm/mach-imx/mach-pcm037.c | 3 +-- arch/arm/mach-imx/mx31lilly-db.c | 3 +-- arch/arm/mach-imx/time.c | 2 +- 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 29a8af6922a8..9f67338ac2ee 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -24,7 +24,7 @@ config MXC_IRQ_PRIOR help Select this if you want to use prioritized IRQ handling. This feature prevents higher priority ISR to be interrupted - by lower priority IRQ even IRQF_DISABLED flag is not set. + by lower priority IRQ. This may be useful in embedded applications, where are strong requirements for timing. Say N here, unless you have a specialized requirement. diff --git a/arch/arm/mach-imx/epit.c b/arch/arm/mach-imx/epit.c index e02de188ae83..074b1a81ba76 100644 --- a/arch/arm/mach-imx/epit.c +++ b/arch/arm/mach-imx/epit.c @@ -171,7 +171,7 @@ static irqreturn_t epit_timer_interrupt(int irq, void *dev_id) static struct irqaction epit_timer_irq = { .name = "i.MX EPIT Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = epit_timer_interrupt, }; diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c index 368a6e3f5926..58b864a3fc20 100644 --- a/arch/arm/mach-imx/mach-armadillo5x0.c +++ b/arch/arm/mach-imx/mach-armadillo5x0.c @@ -404,8 +404,7 @@ static int armadillo5x0_sdhc1_init(struct device *dev, /* When supported the trigger type have to be BOTH */ ret = request_irq(gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK)), - detect_irq, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, + detect_irq, IRQF_TRIGGER_FALLING, "sdhc-detect", data); if (ret) diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index 1ed916175d41..50044a21b388 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -311,7 +311,7 @@ static int mx31_3ds_sdhc1_init(struct device *dev, } ret = request_irq(gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1)), - detect_irq, IRQF_DISABLED | + detect_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "sdhc1-detect", data); if (ret) { diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index bc0261e99d39..45303bd62902 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -371,8 +371,7 @@ static int pcm970_sdhc1_init(struct device *dev, irq_handler_t detect_irq, #endif ret = request_irq(gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_SCK6)), detect_irq, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, - "sdhc-detect", data); + IRQF_TRIGGER_FALLING, "sdhc-detect", data); if (ret) goto err_gpio_free_2; diff --git a/arch/arm/mach-imx/mx31lilly-db.c b/arch/arm/mach-imx/mx31lilly-db.c index d4361b80c5fb..649fe49ce85e 100644 --- a/arch/arm/mach-imx/mx31lilly-db.c +++ b/arch/arm/mach-imx/mx31lilly-db.c @@ -130,8 +130,7 @@ static int mxc_mmc1_init(struct device *dev, gpio_direction_input(gpio_wp); ret = request_irq(gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1)), - detect_irq, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, + detect_irq, IRQF_TRIGGER_FALLING, "MMC detect", data); if (ret) goto exit_free_wp; diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index cd46529e9eaa..9b6638aadeaa 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -250,7 +250,7 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id) static struct irqaction mxc_timer_irq = { .name = "i.MX Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = mxc_timer_interrupt, }; From c7c3eac6277bc60fb4472a16c5af5d54afc83596 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 12 May 2013 17:22:17 +0800 Subject: [PATCH 05/31] ARM: imx: add low-level debug for vybrid Add low-level debug support for vybrid, so that earlyprintk can be enabled for debugging early boot issue. Signed-off-by: Shawn Guo --- arch/arm/Kconfig.debug | 8 ++++++++ arch/arm/include/debug/vf.S | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 arch/arm/include/debug/vf.S diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 9762c84b4198..d597c6b8488b 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -386,6 +386,13 @@ choice when u-boot hands over to the kernel, the system silently crashes, with no serial output at all. + config DEBUG_VF_UART + bool "Vybrid UART" + depends on SOC_VF610 + help + Say Y here if you want kernel low-level debugging support + on Vybrid based platforms. + config DEBUG_NOMADIK_UART bool "Kernel low-level debugging messages via NOMADIK UART" depends on ARCH_NOMADIK @@ -906,6 +913,7 @@ config DEBUG_LL_INCLUDE default "debug/tegra.S" if DEBUG_TEGRA_UART default "debug/ux500.S" if DEBUG_UX500_UART default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT + default "debug/vf.S" if DEBUG_VF_UART default "debug/vt8500.S" if DEBUG_VT8500_UART0 default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1 default "mach/debug-macro.S" diff --git a/arch/arm/include/debug/vf.S b/arch/arm/include/debug/vf.S new file mode 100644 index 000000000000..ba12cc44b2cb --- /dev/null +++ b/arch/arm/include/debug/vf.S @@ -0,0 +1,26 @@ +/* + * Copyright 2013 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 version 2 as + * published by the Free Software Foundation. + * + */ + + .macro addruart, rp, rv, tmp + ldr \rp, =0x40028000 @ physical + ldr \rv, =0xfe028000 @ virtual + .endm + + .macro senduart, rd, rx + strb \rd, [\rx, #0x7] @ Data Register + .endm + + .macro busyuart, rd, rx +1001: ldrb \rd, [\rx, #0x4] @ Status Register 1 + tst \rd, #1 << 6 @ TC + beq 1001b @ wait until transmit done + .endm + + .macro waituart,rd,rx + .endm From bfefdff8f91aa0a9ff1291d18d54498af276a6e5 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 13 Aug 2013 13:54:02 +0800 Subject: [PATCH 06/31] ARM: imx: add soc revision helper functions Similar to what we do for cpu type, the patch adds helper functions imx_set_soc_revision() and imx_get_soc_revision() to maintain imx_soc_revision in cpu.c. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 2 ++ arch/arm/mach-imx/cpu.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 28e8ca0871e8..6ac25f68a6bc 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -77,6 +77,8 @@ extern int imx6q_revision(void); extern int mx53_display_revision(void); extern void imx_set_aips(void __iomem *); extern int mxc_device_init(void); +void imx_set_soc_revision(unsigned int rev); +unsigned int imx_get_soc_revision(void); enum mxc_cpu_pwr_mode { WAIT_CLOCKED, /* wfi only */ diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index e70e3acbf9bd..51f6c51ca878 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c @@ -8,11 +8,23 @@ unsigned int __mxc_cpu_type; EXPORT_SYMBOL(__mxc_cpu_type); +static unsigned int imx_soc_revision; + void mxc_set_cpu_type(unsigned int type) { __mxc_cpu_type = type; } +void imx_set_soc_revision(unsigned int rev) +{ + imx_soc_revision = rev; +} + +unsigned int imx_get_soc_revision(void) +{ + return imx_soc_revision; +} + void imx_print_silicon_rev(const char *cpu, int srev) { if (srev == IMX_CHIP_REVISION_UNKNOWN) From 3f75978b3742157853618c5c6dd4a5f49aa950b1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 13 Aug 2013 14:10:29 +0800 Subject: [PATCH 07/31] ARM: imx6q: use common soc revision helpers It calls imx_set_soc_revision() to set up soc revision in imx6q_init_revision(), and replaces all the occurrences of imx6q_revision() with common helper imx_get_soc_revision(). Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 5 +++-- arch/arm/mach-imx/common.h | 1 - arch/arm/mach-imx/mach-imx6q.c | 13 ++++--------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 913ad85ad621..c68156621cc8 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -300,7 +300,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) 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) { + if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { post_div_table[1].div = 1; post_div_table[2].div = 1; video_div_table[1].div = 1; @@ -574,7 +574,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk_register_clkdev(clk[pll4_post_div], "pll4_post_div", NULL); clk_register_clkdev(clk[pll4_audio], "pll4_audio", NULL); - if ((imx6q_revision() != IMX_CHIP_REVISION_1_0) || cpu_is_imx6dl()) { + if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) || + cpu_is_imx6dl()) { clk_set_parent(clk[ldb_di0_sel], clk[pll5_video_div]); clk_set_parent(clk[ldb_di1_sel], clk[pll5_video_div]); } diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 6ac25f68a6bc..cac12870efb3 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -73,7 +73,6 @@ extern void mxc_restart(enum reboot_mode, const char *); extern void mxc_arch_reset_init(void __iomem *); extern void mxc_arch_reset_init_dt(void); 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); diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 3be0fa0e9796..f260aad9850b 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -38,16 +38,10 @@ #include "cpuidle.h" #include "hardware.h" -static u32 chip_revision; - -int imx6q_revision(void) -{ - return chip_revision; -} - static void __init imx6q_init_revision(void) { u32 rev = imx_anatop_get_digprog(); + u32 chip_revision; switch (rev & 0xff) { case 0: @@ -64,6 +58,7 @@ static void __init imx6q_init_revision(void) } mxc_set_cpu_type(rev >> 16 & 0xff); + imx_set_soc_revision(chip_revision); } static void imx6q_restart(enum reboot_mode mode, const char *cmd) @@ -191,7 +186,7 @@ static void __init imx6q_1588_init(void) static void __init imx6q_init_machine(void) { imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", - imx6q_revision()); + imx_get_soc_revision()); imx6q_enet_phy_init(); @@ -270,7 +265,7 @@ static void __init imx6q_init_late(void) * WAIT mode is broken on TO 1.0 and 1.1, so there is no point * to run cpuidle on them. */ - if (imx6q_revision() > IMX_CHIP_REVISION_1_1) + if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) imx6q_cpuidle_init(); if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) { From f1c6f314727c7595e249c7da3933ba2bc6219e58 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 13 Aug 2013 14:59:43 +0800 Subject: [PATCH 08/31] ARM: imx: add a common function to initialize revision from anatop The patch creates a common function imx_init_revision_from_anatop() by merging imx6q_init_revision() and imx_anatop_get_digprog(), so that any SoC that encodes revision info in anatop can use it to initialize revision. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/anatop.c | 27 +++++++++++++++++++++------ arch/arm/mach-imx/common.h | 2 +- arch/arm/mach-imx/mach-imx6q.c | 25 +------------------------ 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index ad3b755abb78..b2d600f14937 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -16,6 +16,7 @@ #include #include #include "common.h" +#include "hardware.h" #define REG_SET 0x4 #define REG_CLR 0x8 @@ -76,21 +77,35 @@ static void imx_anatop_usb_chrg_detect_disable(void) BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); } -u32 imx_anatop_get_digprog(void) +void __init imx_init_revision_from_anatop(void) { struct device_node *np; void __iomem *anatop_base; - static u32 digprog; - - if (digprog) - return digprog; + unsigned int revision; + u32 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); + iounmap(anatop_base); - return digprog; + switch (digprog & 0xff) { + case 0: + revision = IMX_CHIP_REVISION_1_0; + break; + case 1: + revision = IMX_CHIP_REVISION_1_1; + break; + case 2: + revision = IMX_CHIP_REVISION_1_2; + break; + default: + revision = IMX_CHIP_REVISION_UNKNOWN; + } + + mxc_set_cpu_type(digprog >> 16 & 0xff); + imx_set_soc_revision(revision); } void __init imx_anatop_init(void) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index cac12870efb3..d0191152807d 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -78,6 +78,7 @@ extern void imx_set_aips(void __iomem *); extern int mxc_device_init(void); void imx_set_soc_revision(unsigned int rev); unsigned int imx_get_soc_revision(void); +void imx_init_revision_from_anatop(void); enum mxc_cpu_pwr_mode { WAIT_CLOCKED, /* wfi only */ @@ -134,7 +135,6 @@ 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 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/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index f260aad9850b..1bdd0be429b9 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -38,29 +38,6 @@ #include "cpuidle.h" #include "hardware.h" -static void __init imx6q_init_revision(void) -{ - u32 rev = imx_anatop_get_digprog(); - u32 chip_revision; - - switch (rev & 0xff) { - case 0: - chip_revision = IMX_CHIP_REVISION_1_0; - break; - case 1: - chip_revision = IMX_CHIP_REVISION_1_1; - break; - case 2: - chip_revision = IMX_CHIP_REVISION_1_2; - break; - default: - chip_revision = IMX_CHIP_REVISION_UNKNOWN; - } - - mxc_set_cpu_type(rev >> 16 & 0xff); - imx_set_soc_revision(chip_revision); -} - static void imx6q_restart(enum reboot_mode mode, const char *cmd) { struct device_node *np; @@ -282,7 +259,7 @@ static void __init imx6q_map_io(void) static void __init imx6q_init_irq(void) { - imx6q_init_revision(); + imx_init_revision_from_anatop(); imx_init_l2cache(); imx_src_init(); imx_gpc_init(); From d8ce823fb34e6b50b1d9cb804c1067546eab9cee Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 13 Aug 2013 16:54:05 +0800 Subject: [PATCH 09/31] ARM: imx: use imx_init_revision_from_anatop() on imx6sl Add imx6sl support into imx_init_revision_from_anatop(), so that it can be used to initialize cpu type and revision on imx6sl. Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sl.dtsi | 4 +++- arch/arm/mach-imx/anatop.c | 6 +++++- arch/arm/mach-imx/mach-imx6sl.c | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi index c46651e4d966..177d9e791a01 100644 --- a/arch/arm/boot/dts/imx6sl.dtsi +++ b/arch/arm/boot/dts/imx6sl.dtsi @@ -380,7 +380,9 @@ }; anatop: anatop@020c8000 { - compatible = "fsl,imx6sl-anatop", "syscon", "simple-bus"; + compatible = "fsl,imx6sl-anatop", + "fsl,imx6q-anatop", + "syscon", "simple-bus"; reg = <0x020c8000 0x1000>; interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index b2d600f14937..4a40bbb46183 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -27,6 +27,7 @@ #define ANADIG_USB1_CHRG_DETECT 0x1b0 #define ANADIG_USB2_CHRG_DETECT 0x210 #define ANADIG_DIGPROG 0x260 +#define ANADIG_DIGPROG_IMX6SL 0x280 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 @@ -83,11 +84,14 @@ void __init imx_init_revision_from_anatop(void) void __iomem *anatop_base; unsigned int revision; u32 digprog; + u16 offset = ANADIG_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); + if (of_device_is_compatible(np, "fsl,imx6sl-anatop")) + offset = ANADIG_DIGPROG_IMX6SL; + digprog = readl_relaxed(anatop_base + offset); iounmap(anatop_base); switch (digprog & 0xff) { diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index 21cde21daf9b..4ce9ae58ed0c 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -45,6 +45,7 @@ static void __init imx6sl_init_machine(void) static void __init imx6sl_init_irq(void) { + imx_init_revision_from_anatop(); imx_init_l2cache(); imx_src_init(); imx_gpc_init(); From a28875462bd493fc1bb041c21f811b4a0577a497 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 13 Aug 2013 16:59:28 +0800 Subject: [PATCH 10/31] ARM: imx6: report soc info via soc device The patch enables soc bus infrastructure and adds a function imx_soc_device_init() to report soc info via soc device interface for imx6qdl and imx6sl. With the support, user space can get soc related info by looking at sysfs like below. $ cat /sys/devices/soc0/machine Freescale i.MX6 Quad SABRE Smart Device Board $ cat /sys/devices/soc0/family Freescale i.MX $ cat /sys/devices/soc0/soc_id i.MX6Q $ cat /sys/devices/soc0/revision 1.2 Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 1 + arch/arm/mach-imx/common.h | 1 + arch/arm/mach-imx/cpu.c | 81 +++++++++++++++++++++++++++++++++ arch/arm/mach-imx/mach-imx6q.c | 8 +++- arch/arm/mach-imx/mach-imx6sl.c | 8 +++- arch/arm/mach-imx/mxc.h | 1 + 6 files changed, 98 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 9f67338ac2ee..e0179158aec6 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -11,6 +11,7 @@ config ARCH_MXC select GENERIC_IRQ_CHIP select MIGHT_HAVE_CACHE_L2X0 if ARCH_MULTI_V6_V7 select MULTI_IRQ_HANDLER + select SOC_BUS select SPARSE_IRQ select USE_OF help diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index d0191152807d..f9d01142a4f6 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -79,6 +79,7 @@ extern int mxc_device_init(void); void imx_set_soc_revision(unsigned int rev); unsigned int imx_get_soc_revision(void); void imx_init_revision_from_anatop(void); +struct device *imx_soc_device_init(void); enum mxc_cpu_pwr_mode { WAIT_CLOCKED, /* wfi only */ diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index 51f6c51ca878..fae2c9a78744 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c @@ -1,6 +1,9 @@ #include #include +#include +#include +#include #include "hardware.h" #include "common.h" @@ -56,3 +59,81 @@ void __init imx_set_aips(void __iomem *base) reg = __raw_readl(base + 0x50) & 0x00FFFFFF; __raw_writel(reg, base + 0x50); } + +struct device * __init imx_soc_device_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device_node *root; + const char *soc_id; + int ret; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return NULL; + + soc_dev_attr->family = "Freescale i.MX"; + + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", &soc_dev_attr->machine); + of_node_put(root); + if (ret) + goto free_soc; + + switch (__mxc_cpu_type) { + case MXC_CPU_MX1: + soc_id = "i.MX1"; + break; + case MXC_CPU_MX21: + soc_id = "i.MX21"; + break; + case MXC_CPU_MX25: + soc_id = "i.MX25"; + break; + case MXC_CPU_MX27: + soc_id = "i.MX27"; + break; + case MXC_CPU_MX31: + soc_id = "i.MX31"; + break; + case MXC_CPU_MX35: + soc_id = "i.MX35"; + break; + case MXC_CPU_MX51: + soc_id = "i.MX51"; + break; + case MXC_CPU_MX53: + soc_id = "i.MX53"; + break; + case MXC_CPU_IMX6SL: + soc_id = "i.MX6SL"; + break; + case MXC_CPU_IMX6DL: + soc_id = "i.MX6DL"; + break; + case MXC_CPU_IMX6Q: + soc_id = "i.MX6Q"; + break; + default: + soc_id = "Unknown"; + } + soc_dev_attr->soc_id = soc_id; + + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", + (imx_soc_revision >> 4) & 0xf, + imx_soc_revision & 0xf); + if (!soc_dev_attr->revision) + goto free_soc; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) + goto free_rev; + + return soc_device_to_device(soc_dev); + +free_rev: + kfree(soc_dev_attr->revision); +free_soc: + kfree(soc_dev_attr); + return NULL; +} diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 1bdd0be429b9..049e36edc143 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -162,12 +162,18 @@ static void __init imx6q_1588_init(void) static void __init imx6q_init_machine(void) { + struct device *parent; + imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", imx_get_soc_revision()); + parent = imx_soc_device_init(); + if (parent == NULL) + pr_warn("failed to initialize soc device\n"); + imx6q_enet_phy_init(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); imx_anatop_init(); imx6q_pm_init(); diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index 4ce9ae58ed0c..f01aaabd3254 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -36,9 +36,15 @@ static void __init imx6sl_fec_init(void) static void __init imx6sl_init_machine(void) { + struct device *parent; + mxc_arch_reset_init_dt(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + parent = imx_soc_device_init(); + if (parent == NULL) + pr_warn("failed to initialize soc device\n"); + + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); imx6sl_fec_init(); } diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 8629e5be7ecd..99e03ea9bf79 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -34,6 +34,7 @@ #define MXC_CPU_MX35 35 #define MXC_CPU_MX51 51 #define MXC_CPU_MX53 53 +#define MXC_CPU_IMX6SL 0x60 #define MXC_CPU_IMX6DL 0x61 #define MXC_CPU_IMX6Q 0x63 From 7655fe53f4d39379d3f619e1ed49c79aba4d319b Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 25 Sep 2013 21:30:42 +0800 Subject: [PATCH 11/31] ARM: imx: remove stale mx53_display_revision() declaration The mx53_display_revision() declaration in common.h is stale and used nowhere, so remove it. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index f9d01142a4f6..d04ed7e8d8d3 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -73,7 +73,6 @@ extern void mxc_restart(enum reboot_mode, const char *); extern void mxc_arch_reset_init(void __iomem *); extern void mxc_arch_reset_init_dt(void); extern int mx53_revision(void); -extern int mx53_display_revision(void); extern void imx_set_aips(void __iomem *); extern int mxc_device_init(void); void imx_set_soc_revision(unsigned int rev); From bf22172158cd6dcc5be6dc286ff5c33794dd0ae8 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 16 Sep 2013 08:20:52 +0000 Subject: [PATCH 12/31] ARM: imx: Add LVDS general-purpose clocks to i.MX6Q The i.MX6 has two general-purpose LVDS clocks that can be driven from a variety of sources. This patch adds a mux and a gate for both of these clocks. Signed-off-by: Sean Cross Signed-off-by: Shawn Guo --- .../devicetree/bindings/clock/imx6q-clock.txt | 4 ++++ arch/arm/mach-imx/clk-imx6q.c | 20 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt index e8b1baae9ae4..6aab72bf67ea 100644 --- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt @@ -216,6 +216,10 @@ clocks and IDs. cko 201 vdoa 202 pll4_audio_div 203 + lvds1_sel 204 + lvds2_sel 205 + lvds1_gate 206 + lvds2_gate 207 Examples: diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index c68156621cc8..e8e5bad82b30 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -217,6 +217,11 @@ static const char *cko2_sels[] = { "uart_serial", "spdif", "asrc", "hsi_tx", }; static const char *cko_sels[] = { "cko1", "cko2", }; +static const char *lvds_sels[] = { + "dummy", "dummy", "dummy", "dummy", "dummy", "dummy", + "pll4_audio", "pll5_video", "pll8_mlb", "enet_ref", + "pcie_ref", "sata_ref", +}; enum mx6q_clks { dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, @@ -251,7 +256,8 @@ enum mx6q_clks { 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, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, - spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, clk_max + spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, + lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max }; static struct clk *clk[clk_max]; @@ -342,6 +348,18 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock); + clk[lvds1_sel] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); + clk[lvds2_sel] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); + + /* + * lvds1_gate and lvds2_gate are pseudo-gates. Both can be + * independently configured as clock inputs or outputs. We treat + * the "output_enable" bit as a gate, even though it's really just + * enabling clock output. + */ + clk[lvds1_gate] = imx_clk_gate("lvds1_gate", "dummy", base + 0x160, 10); + clk[lvds2_gate] = imx_clk_gate("lvds2_gate", "dummy", base + 0x160, 11); + /* name parent_name reg idx */ clk[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); clk[pll2_pfd1_594m] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); From 74b8031307c5d33d36742c26dd0921991bd5a255 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 26 Sep 2013 10:45:35 +0800 Subject: [PATCH 13/31] ARM: imx6q: clock and Kconfig update for PCIe support Update imx6q clock initialization and Kconfig for PCIe support. Signed-off-by: Sean Cross Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 2 ++ arch/arm/mach-imx/clk-imx6q.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e0179158aec6..270f78667dc6 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -802,6 +802,8 @@ config SOC_IMX6Q select HAVE_IMX_SRC select HAVE_SMP select MFD_SYSCON + select MIGHT_HAVE_PCI + select PCI_DOMAINS if PCI select PINCTRL select PINCTRL_IMX6Q select PL310_ERRATA_588369 if CACHE_PL310 diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index e8e5bad82b30..07bc0d8b573f 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -623,6 +623,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) if (ret) pr_warn("failed to set up CLKO: %d\n", ret); + /* All existing boards with PCIe use LVDS1 */ + if (IS_ENABLED(CONFIG_PCI_IMX6)) + clk_set_parent(clk[lvds1_sel], clk[sata_ref]); + /* Set initial power mode */ imx6q_set_lpm(WAIT_CLOCKED); From e39c3368aa182066b30d45e852956b6e9c915f53 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 28 Sep 2013 17:27:06 -0300 Subject: [PATCH 14/31] ARM: imx_v6_v7_defconfig: Add SPDIF support Generated by doing: make imx_v6_v7_defconfig Manually selected the IMX_SPDIF driver make savedefconfig cp defconfig arch/arm/configs/imx_v6_v7_defconfig Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/imx_v6_v7_defconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 5d488c24b132..d513294683c9 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -132,7 +132,6 @@ CONFIG_TOUCHSCREEN_MC13783=y CONFIG_INPUT_MISC=y CONFIG_INPUT_MMA8450=y CONFIG_SERIO_SERPORT=m -CONFIG_VT_HW_CONSOLE_BINDING=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_IMX=y @@ -188,6 +187,7 @@ CONFIG_SND_SOC_PHYCORE_AC97=y CONFIG_SND_SOC_EUKREA_TLV320=y CONFIG_SND_SOC_IMX_WM8962=y CONFIG_SND_SOC_IMX_SGTL5000=y +CONFIG_SND_SOC_IMX_SPDIF=y CONFIG_SND_SOC_IMX_MC13783=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y @@ -195,7 +195,6 @@ CONFIG_USB_EHCI_MXC=y CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_HOST=y -CONFIG_USB_PHY=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MXS_PHY=y CONFIG_MMC=y From 15233e1db2b3adc955b9d8812e6849cfbd5bb529 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 28 Sep 2013 17:27:07 -0300 Subject: [PATCH 15/31] ARM: imx_v6_v7_defconfig: Add CHIPIDEA_UDC support Generated by doing: make imx_v6_v7_defconfig Manually selected the CHIPIDEA_UDC driver make savedefconfig cp defconfig arch/arm/configs/imx_v6_v7_defconfig Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/imx_v6_v7_defconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index d513294683c9..137fdb05eaa1 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -194,9 +194,13 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MXS_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=m +CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y @@ -245,7 +249,6 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y CONFIG_TMPFS=y -CONFIG_CONFIGFS_FS=m CONFIG_JFFS2_FS=y CONFIG_UBIFS_FS=y CONFIG_NFS_FS=y From 1ddd35be8b71855329c4c7e8910b00fd2bc0f6dc Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 30 Sep 2013 14:04:51 +0200 Subject: [PATCH 16/31] ARM: imx: Include linux/err.h The IS_ERR() macro is defined in the linux/err.h header file, so include it explicitly. Signed-off-by: Thierry Reding Signed-off-by: Shawn Guo --- arch/arm/mach-imx/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index fae2c9a78744..ba3b498a67ec 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c @@ -1,4 +1,4 @@ - +#include #include #include #include From a4de29044d1887543dd35a75ac666eac431e8765 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 30 Sep 2013 11:22:30 -0300 Subject: [PATCH 17/31] ARM: mxs_defconfig: Add CHIPIDEA_UDC support Generated by doing: make mxs_defconfig Manually selected the CHIPIDEA_UDC driver make savedefconfig cp defconfig arch/arm/configs/mxs_defconfig Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/mxs_defconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 4555c025629a..2d0c3695d5d0 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -76,7 +76,6 @@ CONFIG_INPUT_EVDEV=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_TSC2007=m # CONFIG_SERIO is not set -CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_DEVPTS_MULTIPLE_INSTANCES=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set @@ -115,9 +114,12 @@ CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y -CONFIG_USB_PHY=y CONFIG_USB_MXS_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=m +CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y CONFIG_MMC_UNSAFE_RESUME=y CONFIG_MMC_MXS=y From bfcc7bcef55dd9db82758f3ac755714a59db9529 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 1 Oct 2013 00:21:12 -0300 Subject: [PATCH 18/31] ARM: mach-imx: clk-imx51-imx53: Retrieve base address and irq from dt As mx53 is a dt-only SoC, we should retrieve the gpt base address and irq from the device tree, instead of using the old MX53_IO_ADDRESS method. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx51-imx53.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index ceaac9cd7b42..ce37af26ff8c 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include "crm-regs-imx5.h" #include "clk.h" @@ -472,8 +475,9 @@ CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init_dt); static void __init mx53_clocks_init(struct device_node *np) { - int i; + int i, irq; unsigned long r; + void __iomem *base; clk[pll1_sw] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); clk[pll2_sw] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); @@ -559,14 +563,17 @@ static void __init mx53_clocks_init(struct device_node *np) clk_set_rate(clk[esdhc_a_podf], 200000000); clk_set_rate(clk[esdhc_b_podf], 200000000); - /* System timer */ - mxc_timer_init(MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), MX53_INT_GPT); - clk_prepare_enable(clk[iim_gate]); imx_print_silicon_rev("i.MX53", mx53_revision()); clk_disable_unprepare(clk[iim_gate]); r = clk_round_rate(clk[usboh3_per_gate], 54000000); clk_set_rate(clk[usboh3_per_gate], r); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx53-gpt"); + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + mxc_timer_init(base, irq); } CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init); From 823b2fe25a96715ceed9f689869e702c4dd3907a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 1 Oct 2013 00:21:13 -0300 Subject: [PATCH 19/31] ARM: mach-imx: mm-imx5: Retrieve tzic base address from dt As mx53 is a dt-only SoC, we should retrieve the tzic base address from the device tree, instead of using the old MX53_IO_ADDRESS method. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mm-imx5.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index eb3cce38c70d..2cafcf00000b 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -100,7 +101,14 @@ void __init mx51_init_irq(void) void __init mx53_init_irq(void) { - tzic_init_irq(MX53_IO_ADDRESS(MX53_TZIC_BASE_ADDR)); + struct device_node *np; + void __iomem *base; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx53-tzic"); + base = of_iomap(np, 0); + WARN_ON(!base); + + tzic_init_irq(base); } static struct sdma_platform_data imx51_sdma_pdata __initdata = { From 6fc6c93eb6d07cb622c2ec2e956875c00ef47df3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 1 Oct 2013 00:21:14 -0300 Subject: [PATCH 20/31] ARM: mach-imx: mm-imx5: Retrieve iomuxc base address from dt As mx53 is a dt-only SoC, we should retrieve the iomuxc base address from the device tree, instead of using the old MX53_IO_ADDRESS method. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mm-imx5.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index 2cafcf00000b..d1d52600f458 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -89,8 +89,15 @@ void __init imx51_init_early(void) void __init imx53_init_early(void) { + struct device_node *np; + void __iomem *base; + mxc_set_cpu_type(MXC_CPU_MX53); - mxc_iomux_v3_init(MX53_IO_ADDRESS(MX53_IOMUXC_BASE_ADDR)); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx53-iomuxc"); + base = of_iomap(np, 0); + WARN_ON(!base); + mxc_iomux_v3_init(base); imx_src_init(); } From 87a84b69824d7fd63b20f3bc98d75c0238b8e7d0 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 6 Oct 2013 16:47:46 +0800 Subject: [PATCH 21/31] ARM: imx: replace imx6q_restart() with mxc_restart() The imx6q_restart() works fine with normal reboot but will run into problem with emergency reboot like sysrq-b. In that case, of_iomap() gets called from interrupt context and hence triggers the BUG_ON in __get_vm_area_node(). Actually, since commit c1e31d1 (ARM: imx: create mxc_arch_reset_init_dt() for DT boot), imx6q/dl should try to use mxc_restart() by calling mxc_arch_reset_init_dt() beforehand, where things like of_iomap() can be done. The patch updates mxc_restart() a little bit to get it work for imx6q/dl and kill imx6q_restart() completely. Reported-by: Nathan Lynch Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 4 ++++ arch/arm/mach-imx/mach-imx6q.c | 35 +++------------------------------- arch/arm/mach-imx/system.c | 5 +++++ 3 files changed, 12 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index d04ed7e8d8d3..2413bfbc42f9 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -126,7 +126,11 @@ static inline void imx_smp_prepare(void) {} static inline void imx_scu_standby_enable(void) {} #endif extern void imx_src_init(void); +#ifdef CONFIG_HAVE_IMX_SRC extern void imx_src_prepare_restart(void); +#else +static inline void imx_src_prepare_restart(void) {} +#endif extern void imx_gpc_init(void); extern void imx_gpc_pre_suspend(void); extern void imx_gpc_post_resume(void); diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 049e36edc143..0f9f24116daa 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -38,36 +37,6 @@ #include "cpuidle.h" #include "hardware.h" -static void imx6q_restart(enum reboot_mode mode, const char *cmd) -{ - struct device_node *np; - void __iomem *wdog_base; - - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-wdt"); - wdog_base = of_iomap(np, 0); - if (!wdog_base) - goto soft; - - imx_src_prepare_restart(); - - /* enable wdog */ - writew_relaxed(1 << 2, wdog_base); - /* write twice to ensure the request will not get ignored */ - writew_relaxed(1 << 2, wdog_base); - - /* wait for reset to assert ... */ - mdelay(500); - - pr_err("Watchdog reset failed to assert reset\n"); - - /* delay to allow the serial port to show the message */ - mdelay(50); - -soft: - /* we'll take a jump through zero as a poor second */ - soft_restart(0); -} - /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ static int ksz9021rn_phy_fixup(struct phy_device *phydev) { @@ -167,6 +136,8 @@ static void __init imx6q_init_machine(void) imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", imx_get_soc_revision()); + mxc_arch_reset_init_dt(); + parent = imx_soc_device_init(); if (parent == NULL) pr_warn("failed to initialize soc device\n"); @@ -285,5 +256,5 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") .init_machine = imx6q_init_machine, .init_late = imx6q_init_late, .dt_compat = imx6q_dt_compat, - .restart = imx6q_restart, + .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c index 80c177c36c5f..e6edcd38b282 100644 --- a/arch/arm/mach-imx/system.c +++ b/arch/arm/mach-imx/system.c @@ -42,6 +42,9 @@ void mxc_restart(enum reboot_mode mode, const char *cmd) { unsigned int wcr_enable; + if (cpu_is_imx6q() || cpu_is_imx6dl()) + imx_src_prepare_restart(); + if (wdog_clk) clk_enable(wdog_clk); @@ -52,6 +55,8 @@ void mxc_restart(enum reboot_mode mode, const char *cmd) /* Assert SRS signal */ __raw_writew(wcr_enable, wdog_base); + /* write twice to ensure the request will not get ignored */ + __raw_writew(wcr_enable, wdog_base); /* wait for reset to assert... */ mdelay(500); From a0fb706e11160e23c01136e9b603954be490e9ab Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 9 Oct 2013 00:10:39 -0300 Subject: [PATCH 22/31] ARM: mxs_defconfig: Turn off CONFIG_DEBUG_GPIO Having CONFIG_DEBUG_GPIO=y leads to several debug messages polluting kernel log: [ 0.580325] of_get_named_gpio_flags: can't parse gpios property of node '/regulators/3p3v[0]' [ 0.581185] 3P3V: 3300 mV [ 0.584827] of_get_named_gpio_flags exited with status 124 [ 0.585852] vddio-sd0: 3300 mV [ 0.590023] of_get_named_gpio_flags exited with status 79 [ 0.590770] fec-3v3: 3300 mV [ 0.594805] of_get_named_gpio_flags exited with status 105 [ 0.595491] usb0_vbus: 5000 mV [ 0.599687] of_get_named_gpio_flags exited with status 104 [ 0.600380] usb1_vbus: 5000 mV [ 0.604463] of_get_named_gpio_flags exited with status 126 [ 0.605153] lcd-3v3: 3300 mV [ 0.608970] of_get_named_gpio_flags exited with status 77 Turn this option off, as these messages are not really useful for normal usage. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/mxs_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 2d0c3695d5d0..6150108e15de 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -90,7 +90,6 @@ CONFIG_I2C_MXS=y CONFIG_SPI=y CONFIG_SPI_GPIO=m CONFIG_SPI_MXS=y -CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y From 94425a1916dfef0d1511bfb75d305a7aca1c0102 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 9 Oct 2013 18:02:03 -0300 Subject: [PATCH 23/31] ARM: imx_v6_v7_defconfig: Enable LEDS_GPIO related options Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/imx_v6_v7_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 137fdb05eaa1..7e4b17618078 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -207,6 +207,13 @@ CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_GPIO=y CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y CONFIG_RTC_DRV_MC13XXX=y From 85920f3960fbc9e8f63b61ac13cb4d3d44c56a17 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 9 Oct 2013 20:40:27 -0300 Subject: [PATCH 24/31] ARM: imx_v6_v7_defconfig: Select CONFIG_PROVE_LOCKING This is very useful for detecting 'circular locking dependency' issues. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/imx_v6_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 7e4b17618078..8d0c5a018ed7 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -270,6 +270,7 @@ CONFIG_NLS_ISO8859_15=m CONFIG_NLS_UTF8=y CONFIG_MAGIC_SYSRQ=y # CONFIG_SCHED_DEBUG is not set +CONFIG_PROVE_LOCKING=y # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_FTRACE is not set # CONFIG_ARM_UNWIND is not set From fcd75f921dfa21a745869090c512ce4c6f2f0477 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 9 Oct 2013 15:29:14 +0800 Subject: [PATCH 25/31] ARM: imx: do not return from imx_cpu_die() call When imx_cpu_die() is being called, the cpu should never return from the call but just in WFI and wait for hardware to take it down. So let's do cpu_do_idle() repeatly in the call. Doing this help improve the relibility of hotplug operation. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/hotplug.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 3daf1ed90579..b35e99cc5e5b 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -52,7 +52,9 @@ void imx_cpu_die(unsigned int cpu) * the register being cleared to kill the cpu. */ imx_set_cpu_arg(cpu, ~0); - cpu_do_idle(); + + while (1) + cpu_do_idle(); } int imx_cpu_kill(unsigned int cpu) From 6050d181a4fd4abb745506a6e565d55f1f9df964 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 9 Oct 2013 15:54:31 +0800 Subject: [PATCH 26/31] ARM: imx: reset core along with enable/disable operation From hotplug stress test result, resetting core during enable/disable operation can improve cpu hotplug stability. So let's set SRC reset bit in imx_enable_cpu() for the core when its enable bit is accessed. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/src.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 10a6b1a8c5ac..4754373e7e7d 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -91,6 +91,7 @@ void imx_enable_cpu(int cpu, bool enable) spin_lock(&scr_lock); val = readl_relaxed(src_base + SRC_SCR); val = enable ? val | mask : val & ~mask; + val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); writel_relaxed(val, src_base + SRC_SCR); spin_unlock(&scr_lock); } From 803648db201f6c5f45e74a646f8f17bdeeb7b7e6 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 16 Oct 2013 21:05:35 +0800 Subject: [PATCH 27/31] ARM: imx: drop extern with function prototypes in common.h Since commit 70dc8a4 (checkpatch: warn when using extern with function prototypes in .h files), we will get checkpatch warning when updating common.h following the existing convention which has extern for function prototypes. Let's change the convention to not use extern with function prototypes in this header. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 168 ++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 2413bfbc42f9..ddcbd90b4edf 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -18,63 +18,63 @@ struct pt_regs; struct clk; enum mxc_cpu_pwr_mode; -extern void mx1_map_io(void); -extern void mx21_map_io(void); -extern void mx25_map_io(void); -extern void mx27_map_io(void); -extern void mx31_map_io(void); -extern void mx35_map_io(void); -extern void mx51_map_io(void); -extern void mx53_map_io(void); -extern void imx1_init_early(void); -extern void imx21_init_early(void); -extern void imx25_init_early(void); -extern void imx27_init_early(void); -extern void imx31_init_early(void); -extern void imx35_init_early(void); -extern void imx51_init_early(void); -extern void imx53_init_early(void); -extern void mxc_init_irq(void __iomem *); -extern void tzic_init_irq(void __iomem *); -extern void mx1_init_irq(void); -extern void mx21_init_irq(void); -extern void mx25_init_irq(void); -extern void mx27_init_irq(void); -extern void mx31_init_irq(void); -extern void mx35_init_irq(void); -extern void mx51_init_irq(void); -extern void mx53_init_irq(void); -extern void imx1_soc_init(void); -extern void imx21_soc_init(void); -extern void imx25_soc_init(void); -extern void imx27_soc_init(void); -extern void imx31_soc_init(void); -extern void imx35_soc_init(void); -extern void imx51_soc_init(void); -extern void imx51_init_late(void); -extern void imx53_init_late(void); -extern void epit_timer_init(void __iomem *base, int irq); -extern void mxc_timer_init(void __iomem *, int); -extern int mx1_clocks_init(unsigned long fref); -extern int mx21_clocks_init(unsigned long lref, unsigned long fref); -extern int mx25_clocks_init(void); -extern int mx27_clocks_init(unsigned long fref); -extern int mx31_clocks_init(unsigned long fref); -extern int mx35_clocks_init(void); -extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, +void mx1_map_io(void); +void mx21_map_io(void); +void mx25_map_io(void); +void mx27_map_io(void); +void mx31_map_io(void); +void mx35_map_io(void); +void mx51_map_io(void); +void mx53_map_io(void); +void imx1_init_early(void); +void imx21_init_early(void); +void imx25_init_early(void); +void imx27_init_early(void); +void imx31_init_early(void); +void imx35_init_early(void); +void imx51_init_early(void); +void imx53_init_early(void); +void mxc_init_irq(void __iomem *); +void tzic_init_irq(void __iomem *); +void mx1_init_irq(void); +void mx21_init_irq(void); +void mx25_init_irq(void); +void mx27_init_irq(void); +void mx31_init_irq(void); +void mx35_init_irq(void); +void mx51_init_irq(void); +void mx53_init_irq(void); +void imx1_soc_init(void); +void imx21_soc_init(void); +void imx25_soc_init(void); +void imx27_soc_init(void); +void imx31_soc_init(void); +void imx35_soc_init(void); +void imx51_soc_init(void); +void imx51_init_late(void); +void imx53_init_late(void); +void epit_timer_init(void __iomem *base, int irq); +void mxc_timer_init(void __iomem *, int); +int mx1_clocks_init(unsigned long fref); +int mx21_clocks_init(unsigned long lref, unsigned long fref); +int mx25_clocks_init(void); +int mx27_clocks_init(unsigned long fref); +int mx31_clocks_init(unsigned long fref); +int mx35_clocks_init(void); +int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); -extern int mx25_clocks_init_dt(void); -extern int mx27_clocks_init_dt(void); -extern int mx31_clocks_init_dt(void); -extern struct platform_device *mxc_register_gpio(char *name, int id, +int mx25_clocks_init_dt(void); +int mx27_clocks_init_dt(void); +int mx31_clocks_init_dt(void); +struct platform_device *mxc_register_gpio(char *name, int id, resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); -extern void mxc_set_cpu_type(unsigned int type); -extern void mxc_restart(enum reboot_mode, const char *); -extern void mxc_arch_reset_init(void __iomem *); -extern void mxc_arch_reset_init_dt(void); -extern int mx53_revision(void); -extern void imx_set_aips(void __iomem *); -extern int mxc_device_init(void); +void mxc_set_cpu_type(unsigned int type); +void mxc_restart(enum reboot_mode, const char *); +void mxc_arch_reset_init(void __iomem *); +void mxc_arch_reset_init_dt(void); +int mx53_revision(void); +void imx_set_aips(void __iomem *); +int mxc_device_init(void); void imx_set_soc_revision(unsigned int rev); unsigned int imx_get_soc_revision(void); void imx_init_revision_from_anatop(void); @@ -95,8 +95,8 @@ enum mx3_cpu_pwr_mode { MX3_SLEEP, }; -extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode); -extern void imx_print_silicon_rev(const char *cpu, int srev); +void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode); +void imx_print_silicon_rev(const char *cpu, int srev); void avic_handle_irq(struct pt_regs *); void tzic_handle_irq(struct pt_regs *); @@ -110,57 +110,57 @@ void tzic_handle_irq(struct pt_regs *); #define imx51_handle_irq tzic_handle_irq #define imx53_handle_irq tzic_handle_irq -extern void imx_enable_cpu(int cpu, bool enable); -extern void imx_set_cpu_jump(int cpu, void *jump_addr); -extern u32 imx_get_cpu_arg(int cpu); -extern void imx_set_cpu_arg(int cpu, u32 arg); -extern void v7_cpu_resume(void); +void imx_enable_cpu(int cpu, bool enable); +void imx_set_cpu_jump(int cpu, void *jump_addr); +u32 imx_get_cpu_arg(int cpu); +void imx_set_cpu_arg(int cpu, u32 arg); +void v7_cpu_resume(void); #ifdef CONFIG_SMP -extern void v7_secondary_startup(void); -extern void imx_scu_map_io(void); -extern void imx_smp_prepare(void); -extern void imx_scu_standby_enable(void); +void v7_secondary_startup(void); +void imx_scu_map_io(void); +void imx_smp_prepare(void); +void imx_scu_standby_enable(void); #else static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} static inline void imx_scu_standby_enable(void) {} #endif -extern void imx_src_init(void); +void imx_src_init(void); #ifdef CONFIG_HAVE_IMX_SRC -extern void imx_src_prepare_restart(void); +void imx_src_prepare_restart(void); #else static inline void imx_src_prepare_restart(void) {} #endif -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 int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); -extern void imx6q_set_chicken_bit(void); +void imx_gpc_init(void); +void imx_gpc_pre_suspend(void); +void imx_gpc_post_resume(void); +void imx_gpc_mask_all(void); +void imx_gpc_restore_all(void); +void imx_anatop_init(void); +void imx_anatop_pre_suspend(void); +void imx_anatop_post_resume(void); +int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +void imx6q_set_chicken_bit(void); -extern void imx_cpu_die(unsigned int cpu); -extern int imx_cpu_kill(unsigned int cpu); +void imx_cpu_die(unsigned int cpu); +int imx_cpu_kill(unsigned int cpu); #ifdef CONFIG_PM -extern void imx6q_pm_init(void); -extern void imx5_pm_init(void); +void imx6q_pm_init(void); +void imx5_pm_init(void); #else static inline void imx6q_pm_init(void) {} static inline void imx5_pm_init(void) {} #endif #ifdef CONFIG_NEON -extern int mx51_neon_fixup(void); +int mx51_neon_fixup(void); #else static inline int mx51_neon_fixup(void) { return 0; } #endif #ifdef CONFIG_CACHE_L2X0 -extern void imx_init_l2cache(void); +void imx_init_l2cache(void); #else static inline void imx_init_l2cache(void) {} #endif From 9e8147bb5ec5d1dda2141da70f96b98985a306cb Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 25 Sep 2013 23:09:36 +0800 Subject: [PATCH 28/31] ARM: imx6q: move low-power code out of clock driver The LPM (Low Power Mode) code that currently sits in imx6q clock driver will be reused by imx6sl. Let's move it into pm-imx6q.c, so that we can keep clock driver SoC specific and reuse pm-imx6q.c on imx6sl. In order to avoid adding another ioremap for CCM block, imx6q_pm_set_ccm_base() is created to let clock driver set up ccm_base for pm code. During the move, the unused CCGR macros get removed. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 156 +--------------------------------- arch/arm/mach-imx/common.h | 2 + arch/arm/mach-imx/pm-imx6q.c | 152 +++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 154 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 07bc0d8b573f..d756d91fd741 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -25,155 +24,6 @@ #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 -#define CCGR2 0x70 -#define CCGR3 0x74 -#define CCGR4 0x78 -#define CCGR5 0x7c -#define CCGR6 0x80 -#define CCGR7 0x84 - -#define CLPCR 0x54 -#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 CGPR 0x64 -#define BM_CGPR_CHICKEN_BIT (0x1 << 17) - -static void __iomem *ccm_base; - -void imx6q_set_chicken_bit(void) -{ - u32 val = readl_relaxed(ccm_base + CGPR); - - val |= BM_CGPR_CHICKEN_BIT; - 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); - - 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; - val |= BM_CLPCR_ARM_CLK_DIS_ON_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; - break; - case STOP_POWER_OFF: - val |= 0x2 << BP_CLPCR_LPM; - 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; - } - - writel_relaxed(val, ccm_base + CLPCR); - - return 0; -} - static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; @@ -384,7 +234,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) np = ccm_node; base = of_iomap(np, 0); WARN_ON(!base); - ccm_base = base; + + imx6q_pm_set_ccm_base(base); /* name reg shift width parent_names num_parents */ clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); @@ -627,9 +478,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[lvds1_sel], clk[sata_ref]); - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); base = of_iomap(np, 0); WARN_ON(!base); diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index ddcbd90b4edf..fde6661ef70d 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -147,9 +147,11 @@ int imx_cpu_kill(unsigned int cpu); #ifdef CONFIG_PM void imx6q_pm_init(void); +void imx6q_pm_set_ccm_base(void __iomem *base); void imx5_pm_init(void); #else static inline void imx6q_pm_init(void) {} +static inline void imx6q_pm_set_ccm_base(void __iomem *base) {} static inline void imx5_pm_init(void) {} #endif diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index 204942749e21..461a895a1388 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -10,9 +10,11 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include #include #include #include +#include #include #include #include @@ -22,6 +24,146 @@ #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 CLPCR 0x54 +#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 CGPR 0x64 +#define BM_CGPR_CHICKEN_BIT (0x1 << 17) + +static void __iomem *ccm_base; + +void imx6q_set_chicken_bit(void) +{ + u32 val = readl_relaxed(ccm_base + CGPR); + + val |= BM_CGPR_CHICKEN_BIT; + 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); + + 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; + val |= BM_CLPCR_ARM_CLK_DIS_ON_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; + break; + case STOP_POWER_OFF: + val |= 0x2 << BP_CLPCR_LPM; + 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; + } + + writel_relaxed(val, ccm_base + CLPCR); + + return 0; +} + static int imx6q_suspend_finish(unsigned long val) { cpu_do_idle(); @@ -55,7 +197,17 @@ static const struct platform_suspend_ops imx6q_pm_ops = { .valid = suspend_valid_only_mem, }; +void __init imx6q_pm_set_ccm_base(void __iomem *base) +{ + ccm_base = base; +} + void __init imx6q_pm_init(void) { + WARN_ON(!ccm_base); + + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + suspend_set_ops(&imx6q_pm_ops); } From 1d674a73c59211cc33cb9c2954659033d8458fa9 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 9 Oct 2013 20:31:28 +0800 Subject: [PATCH 29/31] ARM: imx6q: call WB and RBC configuration from imx6q_pm_enter() The WB and RBC configuration calls are currently made from imx6q_set_lpm() for WAIT_CLOCKED and WAIT_UNCLOCKED mode with a simple state tracking. This becomes unnecessary since we can make the calls from imx6q_pm_enter() directly now for suspend. More importantly, the current call of imx6q_enable_wb() from imx6q_set_lpm() is buggy. The CLPCR register bits configured by imx6q_enable_wb() will get lost, because imx6q_set_lpm() caches the same register and write it back at the end of the function. That's why the imx6dl suspend/resume does not work currently - the wakeup from suspend triggers a reset on imx6dl. Moves the WB and RBC calls into imx6q_pm_enter() to save the state tracking and fixes above bug, so that suspend/resume can start working on imx6dl. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/pm-imx6q.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index 461a895a1388..fb7d90d36672 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -67,10 +67,7 @@ void imx6q_set_chicken_bit(void) 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 @@ -98,17 +95,11 @@ static void imx6q_enable_rbc(bool enable) /* 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); @@ -121,8 +112,6 @@ static void imx6q_enable_wb(bool enable) 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) @@ -132,8 +121,6 @@ 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; @@ -152,8 +139,6 @@ 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; @@ -175,6 +160,8 @@ static int imx6q_pm_enter(suspend_state_t state) switch (state) { case PM_SUSPEND_MEM: imx6q_set_lpm(STOP_POWER_OFF); + imx6q_enable_wb(true); + imx6q_enable_rbc(true); imx_gpc_pre_suspend(); imx_anatop_pre_suspend(); imx_set_cpu_jump(0, v7_cpu_resume); @@ -183,6 +170,8 @@ static int imx6q_pm_enter(suspend_state_t state) imx_smp_prepare(); imx_anatop_post_resume(); imx_gpc_post_resume(); + imx6q_enable_rbc(false); + imx6q_enable_wb(false); imx6q_set_lpm(WAIT_CLOCKED); break; default: From d48866fefdac239a4e02777e712aad60db9ee8a8 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 16 Oct 2013 19:52:00 +0800 Subject: [PATCH 30/31] ARM: imx: ensure dsm_request signal is not asserted when setting LPM There is a defect in imx6 LPM design. When SW tries to enter low power mode with following sequence, the chip will enter low power mode before A9 CPU execute WFI instruction: 1. Set CCM_CLPCR[1:0] to 2'b00; 2. ARM CPU enters WFI; 3. ARM CPU wakeup from an interrupt event, which is masked by GPC or not visible to GPC, such as interrupt from local timer; 4. Set CCM_CLPCR[1:0] to 2'b01 or 2'b10; 5. ARM CPU execute WFI. Before the last step, the chip will enter WAIT mode if CCM_CLPCR[1:0] is set to 2'b01, or enter STOP mode if CCM_CLPCR[1:0] is set to 2'b10. The patch implements a recommended workaround for this issue. 1. SW triggers irq #32(IOMUX) to be always pending manually by setting IOMUX_GPR1_GINT bit; 2. SW should then unmask it in GPC before setting CCM LPM; 3. SW should mask it right after CCM LPM is set (bit0-1 of CCM_CLPCR). Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 3 +++ arch/arm/mach-imx/gpc.c | 4 ++-- arch/arm/mach-imx/pm-imx6q.c | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index fde6661ef70d..7cbe22d0c6e9 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -13,6 +13,7 @@ #include +struct irq_data; struct platform_device; struct pt_regs; struct clk; @@ -136,6 +137,8 @@ void imx_gpc_pre_suspend(void); void imx_gpc_post_resume(void); void imx_gpc_mask_all(void); void imx_gpc_restore_all(void); +void imx_gpc_irq_mask(struct irq_data *d); +void imx_gpc_irq_unmask(struct irq_data *d); void imx_anatop_init(void); void imx_anatop_pre_suspend(void); void imx_anatop_post_resume(void); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 44a65e9ff1fc..586e0171a652 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -90,7 +90,7 @@ void imx_gpc_restore_all(void) writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); } -static void imx_gpc_irq_unmask(struct irq_data *d) +void imx_gpc_irq_unmask(struct irq_data *d) { void __iomem *reg; u32 val; @@ -105,7 +105,7 @@ static void imx_gpc_irq_unmask(struct irq_data *d) writel_relaxed(val, reg); } -static void imx_gpc_irq_mask(struct irq_data *d) +void imx_gpc_irq_mask(struct irq_data *d) { void __iomem *reg; u32 val; diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index fb7d90d36672..f303b56f087c 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -13,8 +13,12 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include #include @@ -116,6 +120,7 @@ static void imx6q_enable_wb(bool enable) int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) { + struct irq_desc *iomuxc_irq_desc; u32 val = readl_relaxed(ccm_base + CLPCR); val &= ~BM_CLPCR_LPM; @@ -144,7 +149,16 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) return -EINVAL; } + /* + * Unmask the always pending IOMUXC interrupt #32 as wakeup source to + * deassert dsm_request signal, so that we can ensure dsm_request + * is not asserted when we're going to write CLPCR register to set LPM. + * After setting up LPM bits, we need to mask this wakeup source. + */ + iomuxc_irq_desc = irq_to_desc(32); + imx_gpc_irq_unmask(&iomuxc_irq_desc->irq_data); writel_relaxed(val, ccm_base + CLPCR); + imx_gpc_irq_mask(&iomuxc_irq_desc->irq_data); return 0; } @@ -193,8 +207,20 @@ void __init imx6q_pm_set_ccm_base(void __iomem *base) void __init imx6q_pm_init(void) { + struct regmap *gpr; + WARN_ON(!ccm_base); + /* + * Force IOMUXC irq pending, so that the interrupt to GPC can be + * used to deassert dsm_request signal when the signal gets + * asserted unexpectedly. + */ + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) + regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, + IMX6Q_GPR1_GINT); + /* Set initial power mode */ imx6q_set_lpm(WAIT_CLOCKED); From 9ba64fe3eb461b95bf11436a13db0d9c79465514 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 17 Oct 2013 10:07:09 +0800 Subject: [PATCH 31/31] ARM: imx: enable suspend for imx6sl The imx6sl low power mode implementation inherits imx6q/dl one, and pm-imx6q.c can just work for imx6sl with some minor updates. Let's enable imx6sl suspend support by reusing pm-imx6q.c and use cpu_is_imxXX() to handle the those minor differences between imx6sl and imx6q/dl. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 ++ arch/arm/mach-imx/clk-imx6sl.c | 3 +++ arch/arm/mach-imx/mach-imx6sl.c | 3 +++ arch/arm/mach-imx/mxc.h | 5 +++++ arch/arm/mach-imx/pm-imx6q.c | 9 ++++++++- 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 5383c589ad71..bbe1f5bb799c 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -102,6 +102,8 @@ obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o +# i.MX6SL reuses pm-imx6q.c +obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o endif # i.MX5 based machines diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index a5c3c5d21aee..c0c4ef55e35b 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c @@ -127,6 +127,9 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) base = of_iomap(np, 0); WARN_ON(!base); + /* Reuse imx6q pm code */ + imx6q_pm_set_ccm_base(base); + /* name reg shift width parent_names num_parents */ clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index f01aaabd3254..2f952e3fcf89 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -47,6 +47,9 @@ static void __init imx6sl_init_machine(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); imx6sl_fec_init(); + imx_anatop_init(); + /* Reuse imx6q pm code */ + imx6q_pm_init(); } static void __init imx6sl_init_irq(void) diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 99e03ea9bf79..b08ab3ad4a6d 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -153,6 +153,11 @@ extern unsigned int __mxc_cpu_type; #endif #ifndef __ASSEMBLY__ +static inline bool cpu_is_imx6sl(void) +{ + return __mxc_cpu_type == MXC_CPU_IMX6SL; +} + static inline bool cpu_is_imx6dl(void) { return __mxc_cpu_type == MXC_CPU_IMX6DL; diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index f303b56f087c..aecd9f8037e0 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -144,6 +144,12 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) val |= 0x3 << BP_CLPCR_STBY_COUNT; val |= BM_CLPCR_VSTBY; val |= BM_CLPCR_SBYOS; + if (cpu_is_imx6sl()) { + val |= BM_CLPCR_BYPASS_PMIC_READY; + val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; + } else { + val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + } break; default: return -EINVAL; @@ -181,7 +187,8 @@ static int imx6q_pm_enter(suspend_state_t state) imx_set_cpu_jump(0, v7_cpu_resume); /* Zzz ... */ cpu_suspend(0, imx6q_suspend_finish); - imx_smp_prepare(); + if (cpu_is_imx6q() || cpu_is_imx6dl()) + imx_smp_prepare(); imx_anatop_post_resume(); imx_gpc_post_resume(); imx6q_enable_rbc(false);