diff options
| author | Olof Johansson <olof@lixom.net> | 2014-07-13 00:19:21 -0400 |
|---|---|---|
| committer | Olof Johansson <olof@lixom.net> | 2014-07-13 00:19:21 -0400 |
| commit | cacadb4ff969a82628d47db87b5a531be466b134 (patch) | |
| tree | b006cfae86bd141db07ba212b6d6d4b81f3e51a9 | |
| parent | 363d4ddc17320ad0906778924d40ba5955ccf194 (diff) | |
| parent | bed7118988ef48063c72f67cc2701c72663b3870 (diff) | |
Merge tag 'samsung-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into fixes
Merge "Samsung fixes-3 for 3.16" from Kukjin Kim:
Samsung fixes-3 for v3.16
- update the parent for Auudss clock because kernel will be hang
during late boot if the parent clock is disabled in bootloader.
- enable clk handing in power domain because while power domain
on/off, its regarding clock source will be reset and it causes
a problem so need to handle it.
- add mux clocks to be used by power domain for exynos5420-mfc
during power domain on/off and property in device tree also.
- register cpuidle only for exynos4210 and exynos5250 because a
system failure will be happened on other exynos SoCs.
* tag 'samsung-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
ARM: EXYNOS: Register cpuidle device only on exynos4210 and 5250
ARM: dts: Add clock property for mfc_pd in exynos5420
clk: exynos5420: Add IDs for clocks used in PD mfc
ARM: EXYNOS: Add support for clock handling in power domain
ARM: dts: Update the parent for Audss clocks in Exynos5420
Signed-off-by: Olof Johansson <olof@lixom.net>
| -rw-r--r-- | Documentation/devicetree/bindings/arm/exynos/power_domain.txt | 20 | ||||
| -rw-r--r-- | arch/arm/boot/dts/exynos5420.dtsi | 5 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/exynos.c | 6 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/pm_domains.c | 61 | ||||
| -rw-r--r-- | drivers/clk/samsung/clk-exynos5420.c | 6 | ||||
| -rw-r--r-- | include/dt-bindings/clock/exynos5420.h | 2 |
6 files changed, 92 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt index 5216b419016a..8b4f7b7fe88b 100644 --- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt +++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt | |||
| @@ -9,6 +9,18 @@ Required Properties: | |||
| 9 | - reg: physical base address of the controller and length of memory mapped | 9 | - reg: physical base address of the controller and length of memory mapped |
| 10 | region. | 10 | region. |
| 11 | 11 | ||
| 12 | Optional Properties: | ||
| 13 | - clocks: List of clock handles. The parent clocks of the input clocks to the | ||
| 14 | devices in this power domain are set to oscclk before power gating | ||
| 15 | and restored back after powering on a domain. This is required for | ||
| 16 | all domains which are powered on and off and not required for unused | ||
| 17 | domains. | ||
| 18 | - clock-names: The following clocks can be specified: | ||
| 19 | - oscclk: Oscillator clock. | ||
| 20 | - pclkN, clkN: Pairs of parent of input clock and input clock to the | ||
| 21 | devices in this power domain. Maximum of 4 pairs (N = 0 to 3) | ||
| 22 | are supported currently. | ||
| 23 | |||
| 12 | Node of a device using power domains must have a samsung,power-domain property | 24 | Node of a device using power domains must have a samsung,power-domain property |
| 13 | defined with a phandle to respective power domain. | 25 | defined with a phandle to respective power domain. |
| 14 | 26 | ||
| @@ -19,6 +31,14 @@ Example: | |||
| 19 | reg = <0x10023C00 0x10>; | 31 | reg = <0x10023C00 0x10>; |
| 20 | }; | 32 | }; |
| 21 | 33 | ||
| 34 | mfc_pd: power-domain@10044060 { | ||
| 35 | compatible = "samsung,exynos4210-pd"; | ||
| 36 | reg = <0x10044060 0x20>; | ||
| 37 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>, | ||
| 38 | <&clock CLK_MOUT_USER_ACLK333>; | ||
| 39 | clock-names = "oscclk", "pclk0", "clk0"; | ||
| 40 | }; | ||
| 41 | |||
| 22 | Example of the node using power domain: | 42 | Example of the node using power domain: |
| 23 | 43 | ||
| 24 | node { | 44 | node { |
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index e38532271ef9..15957227ffda 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi | |||
| @@ -167,7 +167,7 @@ | |||
| 167 | compatible = "samsung,exynos5420-audss-clock"; | 167 | compatible = "samsung,exynos5420-audss-clock"; |
| 168 | reg = <0x03810000 0x0C>; | 168 | reg = <0x03810000 0x0C>; |
| 169 | #clock-cells = <1>; | 169 | #clock-cells = <1>; |
| 170 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_FOUT_EPLL>, | 170 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MAU_EPLL>, |
| 171 | <&clock CLK_SCLK_MAUDIO0>, <&clock CLK_SCLK_MAUPCM0>; | 171 | <&clock CLK_SCLK_MAUDIO0>, <&clock CLK_SCLK_MAUPCM0>; |
| 172 | clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; | 172 | clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; |
| 173 | }; | 173 | }; |
| @@ -260,6 +260,9 @@ | |||
| 260 | mfc_pd: power-domain@10044060 { | 260 | mfc_pd: power-domain@10044060 { |
| 261 | compatible = "samsung,exynos4210-pd"; | 261 | compatible = "samsung,exynos4210-pd"; |
| 262 | reg = <0x10044060 0x20>; | 262 | reg = <0x10044060 0x20>; |
| 263 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>, | ||
| 264 | <&clock CLK_MOUT_USER_ACLK333>; | ||
| 265 | clock-names = "oscclk", "pclk0", "clk0"; | ||
| 263 | }; | 266 | }; |
| 264 | 267 | ||
| 265 | disp_pd: power-domain@100440C0 { | 268 | disp_pd: power-domain@100440C0 { |
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 95cad252eb1b..46d893fcbe85 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c | |||
| @@ -173,10 +173,8 @@ static struct platform_device exynos_cpuidle = { | |||
| 173 | 173 | ||
| 174 | void __init exynos_cpuidle_init(void) | 174 | void __init exynos_cpuidle_init(void) |
| 175 | { | 175 | { |
| 176 | if (soc_is_exynos5440()) | 176 | if (soc_is_exynos4210() || soc_is_exynos5250()) |
| 177 | return; | 177 | platform_device_register(&exynos_cpuidle); |
| 178 | |||
| 179 | platform_device_register(&exynos_cpuidle); | ||
| 180 | } | 178 | } |
| 181 | 179 | ||
| 182 | void __init exynos_cpufreq_init(void) | 180 | void __init exynos_cpufreq_init(void) |
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index fe6570ebbdde..797cb134bfff 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/pm_domain.h> | 19 | #include <linux/pm_domain.h> |
| 20 | #include <linux/clk.h> | ||
| 20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 21 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
| 22 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
| @@ -24,6 +25,8 @@ | |||
| 24 | 25 | ||
| 25 | #include "regs-pmu.h" | 26 | #include "regs-pmu.h" |
| 26 | 27 | ||
| 28 | #define MAX_CLK_PER_DOMAIN 4 | ||
| 29 | |||
| 27 | /* | 30 | /* |
| 28 | * Exynos specific wrapper around the generic power domain | 31 | * Exynos specific wrapper around the generic power domain |
| 29 | */ | 32 | */ |
| @@ -32,6 +35,9 @@ struct exynos_pm_domain { | |||
| 32 | char const *name; | 35 | char const *name; |
| 33 | bool is_off; | 36 | bool is_off; |
| 34 | struct generic_pm_domain pd; | 37 | struct generic_pm_domain pd; |
| 38 | struct clk *oscclk; | ||
| 39 | struct clk *clk[MAX_CLK_PER_DOMAIN]; | ||
| 40 | struct clk *pclk[MAX_CLK_PER_DOMAIN]; | ||
| 35 | }; | 41 | }; |
| 36 | 42 | ||
| 37 | static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) | 43 | static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) |
| @@ -44,6 +50,19 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) | |||
| 44 | pd = container_of(domain, struct exynos_pm_domain, pd); | 50 | pd = container_of(domain, struct exynos_pm_domain, pd); |
| 45 | base = pd->base; | 51 | base = pd->base; |
| 46 | 52 | ||
| 53 | /* Set oscclk before powering off a domain*/ | ||
| 54 | if (!power_on) { | ||
| 55 | int i; | ||
| 56 | |||
| 57 | for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { | ||
| 58 | if (IS_ERR(pd->clk[i])) | ||
| 59 | break; | ||
| 60 | if (clk_set_parent(pd->clk[i], pd->oscclk)) | ||
| 61 | pr_err("%s: error setting oscclk as parent to clock %d\n", | ||
| 62 | pd->name, i); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 47 | pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; | 66 | pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; |
| 48 | __raw_writel(pwr, base); | 67 | __raw_writel(pwr, base); |
| 49 | 68 | ||
| @@ -60,6 +79,20 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) | |||
| 60 | cpu_relax(); | 79 | cpu_relax(); |
| 61 | usleep_range(80, 100); | 80 | usleep_range(80, 100); |
| 62 | } | 81 | } |
| 82 | |||
| 83 | /* Restore clocks after powering on a domain*/ | ||
| 84 | if (power_on) { | ||
| 85 | int i; | ||
| 86 | |||
| 87 | for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { | ||
| 88 | if (IS_ERR(pd->clk[i])) | ||
| 89 | break; | ||
| 90 | if (clk_set_parent(pd->clk[i], pd->pclk[i])) | ||
| 91 | pr_err("%s: error setting parent to clock%d\n", | ||
| 92 | pd->name, i); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 63 | return 0; | 96 | return 0; |
| 64 | } | 97 | } |
| 65 | 98 | ||
| @@ -152,9 +185,11 @@ static __init int exynos4_pm_init_power_domain(void) | |||
| 152 | 185 | ||
| 153 | for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { | 186 | for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { |
| 154 | struct exynos_pm_domain *pd; | 187 | struct exynos_pm_domain *pd; |
| 155 | int on; | 188 | int on, i; |
| 189 | struct device *dev; | ||
| 156 | 190 | ||
| 157 | pdev = of_find_device_by_node(np); | 191 | pdev = of_find_device_by_node(np); |
| 192 | dev = &pdev->dev; | ||
| 158 | 193 | ||
| 159 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | 194 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); |
| 160 | if (!pd) { | 195 | if (!pd) { |
| @@ -170,6 +205,30 @@ static __init int exynos4_pm_init_power_domain(void) | |||
| 170 | pd->pd.power_on = exynos_pd_power_on; | 205 | pd->pd.power_on = exynos_pd_power_on; |
| 171 | pd->pd.of_node = np; | 206 | pd->pd.of_node = np; |
| 172 | 207 | ||
| 208 | pd->oscclk = clk_get(dev, "oscclk"); | ||
| 209 | if (IS_ERR(pd->oscclk)) | ||
| 210 | goto no_clk; | ||
| 211 | |||
| 212 | for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { | ||
| 213 | char clk_name[8]; | ||
| 214 | |||
| 215 | snprintf(clk_name, sizeof(clk_name), "clk%d", i); | ||
| 216 | pd->clk[i] = clk_get(dev, clk_name); | ||
| 217 | if (IS_ERR(pd->clk[i])) | ||
| 218 | break; | ||
| 219 | snprintf(clk_name, sizeof(clk_name), "pclk%d", i); | ||
| 220 | pd->pclk[i] = clk_get(dev, clk_name); | ||
| 221 | if (IS_ERR(pd->pclk[i])) { | ||
| 222 | clk_put(pd->clk[i]); | ||
| 223 | pd->clk[i] = ERR_PTR(-EINVAL); | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | if (IS_ERR(pd->clk[0])) | ||
| 229 | clk_put(pd->oscclk); | ||
| 230 | |||
| 231 | no_clk: | ||
| 173 | platform_set_drvdata(pdev, pd); | 232 | platform_set_drvdata(pdev, pd); |
| 174 | 233 | ||
| 175 | on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN; | 234 | on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN; |
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 9d7d7eed03fd..f74f882f7f29 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c | |||
| @@ -631,7 +631,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = { | |||
| 631 | SRC_TOP4, 16, 1), | 631 | SRC_TOP4, 16, 1), |
| 632 | MUX(0, "mout_user_aclk266", mout_user_aclk266_p, SRC_TOP4, 20, 1), | 632 | MUX(0, "mout_user_aclk266", mout_user_aclk266_p, SRC_TOP4, 20, 1), |
| 633 | MUX(0, "mout_user_aclk166", mout_user_aclk166_p, SRC_TOP4, 24, 1), | 633 | MUX(0, "mout_user_aclk166", mout_user_aclk166_p, SRC_TOP4, 24, 1), |
| 634 | MUX(0, "mout_user_aclk333", mout_user_aclk333_p, SRC_TOP4, 28, 1), | 634 | MUX(CLK_MOUT_USER_ACLK333, "mout_user_aclk333", mout_user_aclk333_p, |
| 635 | SRC_TOP4, 28, 1), | ||
| 635 | 636 | ||
| 636 | MUX(0, "mout_user_aclk400_disp1", mout_user_aclk400_disp1_p, | 637 | MUX(0, "mout_user_aclk400_disp1", mout_user_aclk400_disp1_p, |
| 637 | SRC_TOP5, 0, 1), | 638 | SRC_TOP5, 0, 1), |
| @@ -684,7 +685,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = { | |||
| 684 | SRC_TOP11, 12, 1), | 685 | SRC_TOP11, 12, 1), |
| 685 | MUX(0, "mout_sw_aclk266", mout_sw_aclk266_p, SRC_TOP11, 20, 1), | 686 | MUX(0, "mout_sw_aclk266", mout_sw_aclk266_p, SRC_TOP11, 20, 1), |
| 686 | MUX(0, "mout_sw_aclk166", mout_sw_aclk166_p, SRC_TOP11, 24, 1), | 687 | MUX(0, "mout_sw_aclk166", mout_sw_aclk166_p, SRC_TOP11, 24, 1), |
| 687 | MUX(0, "mout_sw_aclk333", mout_sw_aclk333_p, SRC_TOP11, 28, 1), | 688 | MUX(CLK_MOUT_SW_ACLK333, "mout_sw_aclk333", mout_sw_aclk333_p, |
| 689 | SRC_TOP11, 28, 1), | ||
| 688 | 690 | ||
| 689 | MUX(0, "mout_sw_aclk400_disp1", mout_sw_aclk400_disp1_p, | 691 | MUX(0, "mout_sw_aclk400_disp1", mout_sw_aclk400_disp1_p, |
| 690 | SRC_TOP12, 4, 1), | 692 | SRC_TOP12, 4, 1), |
diff --git a/include/dt-bindings/clock/exynos5420.h b/include/dt-bindings/clock/exynos5420.h index 97dcb89d37d3..3fc08ff24fa9 100644 --- a/include/dt-bindings/clock/exynos5420.h +++ b/include/dt-bindings/clock/exynos5420.h | |||
| @@ -203,6 +203,8 @@ | |||
| 203 | #define CLK_MOUT_G3D 641 | 203 | #define CLK_MOUT_G3D 641 |
| 204 | #define CLK_MOUT_VPLL 642 | 204 | #define CLK_MOUT_VPLL 642 |
| 205 | #define CLK_MOUT_MAUDIO0 643 | 205 | #define CLK_MOUT_MAUDIO0 643 |
| 206 | #define CLK_MOUT_USER_ACLK333 644 | ||
| 207 | #define CLK_MOUT_SW_ACLK333 645 | ||
| 206 | 208 | ||
| 207 | /* divider clocks */ | 209 | /* divider clocks */ |
| 208 | #define CLK_DOUT_PIXEL 768 | 210 | #define CLK_DOUT_PIXEL 768 |
