aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2016-09-09 04:09:05 -0400
committerSylwester Nawrocki <s.nawrocki@samsung.com>2016-09-09 11:35:13 -0400
commitbe95d2c7d918b2b7b973378a1e92bdc6559c21f9 (patch)
tree9888fb20a27881c24d85743b18b5787ddd2b763e /drivers/clk
parentc17a6163647a20d22fa03c00ba8714492b0311c6 (diff)
clk: samsung: Add support for EPLL on exynos5410
This patch adds code instantiating the EPLL, which is used as the audio subsystem's root clock. The requirement to specify the external root clock in clocks property is documented. Having the consumer 'clocks' property ensures proper initialization order by explicitly specifying dependencies in DT. It prevents situations when the SoC's clock controller driver has initialized, the external oscillator clock is not yet registered and setting clock frequencies through assigned-clock-rates property doesn't work properly due to unknown external oscillator frequency. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/samsung/clk-exynos5410.c30
-rw-r--r--drivers/clk/samsung/clk-pll.c102
-rw-r--r--drivers/clk/samsung/clk-pll.h1
3 files changed, 131 insertions, 2 deletions
diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c
index eefed92a59aa..fc471a49e8f4 100644
--- a/drivers/clk/samsung/clk-exynos5410.c
+++ b/drivers/clk/samsung/clk-exynos5410.c
@@ -14,6 +14,7 @@
14#include <linux/clk-provider.h> 14#include <linux/clk-provider.h>
15#include <linux/of.h> 15#include <linux/of.h>
16#include <linux/of_address.h> 16#include <linux/of_address.h>
17#include <linux/clk.h>
17 18
18#include "clk.h" 19#include "clk.h"
19 20
@@ -21,6 +22,8 @@
21#define APLL_CON0 0x100 22#define APLL_CON0 0x100
22#define CPLL_LOCK 0x10020 23#define CPLL_LOCK 0x10020
23#define CPLL_CON0 0x10120 24#define CPLL_CON0 0x10120
25#define EPLL_LOCK 0x10040
26#define EPLL_CON0 0x10130
24#define MPLL_LOCK 0x4000 27#define MPLL_LOCK 0x4000
25#define MPLL_CON0 0x4100 28#define MPLL_CON0 0x4100
26#define BPLL_LOCK 0x20010 29#define BPLL_LOCK 0x20010
@@ -58,7 +61,7 @@
58 61
59/* list of PLLs */ 62/* list of PLLs */
60enum exynos5410_plls { 63enum exynos5410_plls {
61 apll, cpll, mpll, 64 apll, cpll, epll, mpll,
62 bpll, kpll, 65 bpll, kpll,
63 nr_plls /* number of PLLs */ 66 nr_plls /* number of PLLs */
64}; 67};
@@ -67,6 +70,7 @@ enum exynos5410_plls {
67PNAME(apll_p) = { "fin_pll", "fout_apll", }; 70PNAME(apll_p) = { "fin_pll", "fout_apll", };
68PNAME(bpll_p) = { "fin_pll", "fout_bpll", }; 71PNAME(bpll_p) = { "fin_pll", "fout_bpll", };
69PNAME(cpll_p) = { "fin_pll", "fout_cpll" }; 72PNAME(cpll_p) = { "fin_pll", "fout_cpll" };
73PNAME(epll_p) = { "fin_pll", "fout_epll" };
70PNAME(mpll_p) = { "fin_pll", "fout_mpll", }; 74PNAME(mpll_p) = { "fin_pll", "fout_mpll", };
71PNAME(kpll_p) = { "fin_pll", "fout_kpll", }; 75PNAME(kpll_p) = { "fin_pll", "fout_kpll", };
72 76
@@ -95,6 +99,8 @@ static const struct samsung_mux_clock exynos5410_mux_clks[] __initconst = {
95 MUX(0, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1), 99 MUX(0, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1),
96 MUX(0, "sclk_bpll_muxed", bpll_user_p, SRC_TOP2, 24, 1), 100 MUX(0, "sclk_bpll_muxed", bpll_user_p, SRC_TOP2, 24, 1),
97 101
102 MUX(0, "sclk_epll", epll_p, SRC_TOP2, 12, 1),
103
98 MUX(0, "sclk_cpll", cpll_p, SRC_TOP2, 8, 1), 104 MUX(0, "sclk_cpll", cpll_p, SRC_TOP2, 8, 1),
99 105
100 MUX(0, "sclk_mpll_bpll", mpll_bpll_p, SRC_TOP1, 20, 1), 106 MUX(0, "sclk_mpll_bpll", mpll_bpll_p, SRC_TOP1, 20, 1),
@@ -219,11 +225,26 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = {
219 GATE(CLK_USBD301, "usbd301", "aclk200_fsys", GATE_IP_FSYS, 20, 0, 0), 225 GATE(CLK_USBD301, "usbd301", "aclk200_fsys", GATE_IP_FSYS, 20, 0, 0),
220}; 226};
221 227
222static const struct samsung_pll_clock exynos5410_plls[nr_plls] __initconst = { 228static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = {
229 PLL_36XX_RATE(400000000U, 200, 3, 2, 0),
230 PLL_36XX_RATE(333000000U, 111, 2, 2, 0),
231 PLL_36XX_RATE(300000000U, 100, 2, 2, 0),
232 PLL_36XX_RATE(266000000U, 266, 3, 3, 0),
233 PLL_36XX_RATE(200000000U, 200, 3, 3, 0),
234 PLL_36XX_RATE(192000000U, 192, 3, 3, 0),
235 PLL_36XX_RATE(166000000U, 166, 3, 3, 0),
236 PLL_36XX_RATE(133000000U, 266, 3, 4, 0),
237 PLL_36XX_RATE(100000000U, 200, 3, 4, 0),
238 PLL_36XX_RATE(66000000U, 176, 2, 5, 0),
239};
240
241static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = {
223 [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK, 242 [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK,
224 APLL_CON0, NULL), 243 APLL_CON0, NULL),
225 [cpll] = PLL(pll_35xx, CLK_FOUT_CPLL, "fout_cpll", "fin_pll", CPLL_LOCK, 244 [cpll] = PLL(pll_35xx, CLK_FOUT_CPLL, "fout_cpll", "fin_pll", CPLL_LOCK,
226 CPLL_CON0, NULL), 245 CPLL_CON0, NULL),
246 [epll] = PLL(pll_2650x, CLK_FOUT_EPLL, "fout_epll", "fin_pll", EPLL_LOCK,
247 EPLL_CON0, NULL),
227 [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", MPLL_LOCK, 248 [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", MPLL_LOCK,
228 MPLL_CON0, NULL), 249 MPLL_CON0, NULL),
229 [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", BPLL_LOCK, 250 [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", BPLL_LOCK,
@@ -247,6 +268,11 @@ static const struct samsung_cmu_info cmu __initconst = {
247/* register exynos5410 clocks */ 268/* register exynos5410 clocks */
248static void __init exynos5410_clk_init(struct device_node *np) 269static void __init exynos5410_clk_init(struct device_node *np)
249{ 270{
271 struct clk *xxti = of_clk_get(np, 0);
272
273 if (!IS_ERR(xxti) && clk_get_rate(xxti) == 24 * MHZ)
274 exynos5410_plls[epll].rate_table = exynos5410_pll2550x_24mhz_tbl;
275
250 samsung_cmu_register_one(np, &cmu); 276 samsung_cmu_register_one(np, &cmu);
251 277
252 pr_debug("Exynos5410: clock setup completed.\n"); 278 pr_debug("Exynos5410: clock setup completed.\n");
diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c
index b5ab055957d2..9617825daabb 100644
--- a/drivers/clk/samsung/clk-pll.c
+++ b/drivers/clk/samsung/clk-pll.c
@@ -1018,6 +1018,102 @@ static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1018}; 1018};
1019 1019
1020/* 1020/*
1021 * PLL2650x Clock Type
1022 */
1023
1024/* Maximum lock time can be 3000 * PDIV cycles */
1025#define PLL2650X_LOCK_FACTOR 3000
1026
1027#define PLL2650X_M_MASK 0x1ff
1028#define PLL2650X_P_MASK 0x3f
1029#define PLL2650X_S_MASK 0x7
1030#define PLL2650X_K_MASK 0xffff
1031#define PLL2650X_LOCK_STAT_MASK 0x1
1032#define PLL2650X_M_SHIFT 16
1033#define PLL2650X_P_SHIFT 8
1034#define PLL2650X_S_SHIFT 0
1035#define PLL2650X_K_SHIFT 0
1036#define PLL2650X_LOCK_STAT_SHIFT 29
1037#define PLL2650X_PLL_ENABLE_SHIFT 31
1038
1039static unsigned long samsung_pll2650x_recalc_rate(struct clk_hw *hw,
1040 unsigned long parent_rate)
1041{
1042 struct samsung_clk_pll *pll = to_clk_pll(hw);
1043 u64 fout = parent_rate;
1044 u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
1045 s16 kdiv;
1046
1047 pll_con0 = readl_relaxed(pll->con_reg);
1048 mdiv = (pll_con0 >> PLL2650X_M_SHIFT) & PLL2650X_M_MASK;
1049 pdiv = (pll_con0 >> PLL2650X_P_SHIFT) & PLL2650X_P_MASK;
1050 sdiv = (pll_con0 >> PLL2650X_S_SHIFT) & PLL2650X_S_MASK;
1051
1052 pll_con1 = readl_relaxed(pll->con_reg + 4);
1053 kdiv = (s16)((pll_con1 >> PLL2650X_K_SHIFT) & PLL2650X_K_MASK);
1054
1055 fout *= (mdiv << 16) + kdiv;
1056 do_div(fout, (pdiv << sdiv));
1057 fout >>= 16;
1058
1059 return (unsigned long)fout;
1060}
1061
1062static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
1063 unsigned long prate)
1064{
1065 struct samsung_clk_pll *pll = to_clk_pll(hw);
1066 const struct samsung_pll_rate_table *rate;
1067 u32 con0, con1;
1068
1069 /* Get required rate settings from table */
1070 rate = samsung_get_pll_settings(pll, drate);
1071 if (!rate) {
1072 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1073 drate, clk_hw_get_name(hw));
1074 return -EINVAL;
1075 }
1076
1077 con0 = readl_relaxed(pll->con_reg);
1078 con1 = readl_relaxed(pll->con_reg + 4);
1079
1080 /* Set PLL lock time. */
1081 writel_relaxed(rate->pdiv * PLL2650X_LOCK_FACTOR, pll->lock_reg);
1082
1083 /* Change PLL PMS values */
1084 con0 &= ~((PLL2650X_M_MASK << PLL2650X_M_SHIFT) |
1085 (PLL2650X_P_MASK << PLL2650X_P_SHIFT) |
1086 (PLL2650X_S_MASK << PLL2650X_S_SHIFT));
1087 con0 |= (rate->mdiv << PLL2650X_M_SHIFT) |
1088 (rate->pdiv << PLL2650X_P_SHIFT) |
1089 (rate->sdiv << PLL2650X_S_SHIFT);
1090 con0 |= (1 << PLL2650X_PLL_ENABLE_SHIFT);
1091 writel_relaxed(con0, pll->con_reg);
1092
1093 con1 &= ~(PLL2650X_K_MASK << PLL2650X_K_SHIFT);
1094 con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
1095 writel_relaxed(con1, pll->con_reg + 4);
1096
1097 do {
1098 cpu_relax();
1099 con0 = readl_relaxed(pll->con_reg);
1100 } while (!(con0 & (PLL2650X_LOCK_STAT_MASK
1101 << PLL2650X_LOCK_STAT_SHIFT)));
1102
1103 return 0;
1104}
1105
1106static const struct clk_ops samsung_pll2650x_clk_ops = {
1107 .recalc_rate = samsung_pll2650x_recalc_rate,
1108 .round_rate = samsung_pll_round_rate,
1109 .set_rate = samsung_pll2650x_set_rate,
1110};
1111
1112static const struct clk_ops samsung_pll2650x_clk_min_ops = {
1113 .recalc_rate = samsung_pll2650x_recalc_rate,
1114};
1115
1116/*
1021 * PLL2650XX Clock Type 1117 * PLL2650XX Clock Type
1022 */ 1118 */
1023 1119
@@ -1227,6 +1323,12 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1227 else 1323 else
1228 init.ops = &samsung_pll2550xx_clk_ops; 1324 init.ops = &samsung_pll2550xx_clk_ops;
1229 break; 1325 break;
1326 case pll_2650x:
1327 if (!pll->rate_table)
1328 init.ops = &samsung_pll2650x_clk_min_ops;
1329 else
1330 init.ops = &samsung_pll2650x_clk_ops;
1331 break;
1230 case pll_2650xx: 1332 case pll_2650xx:
1231 if (!pll->rate_table) 1333 if (!pll->rate_table)
1232 init.ops = &samsung_pll2650xx_clk_min_ops; 1334 init.ops = &samsung_pll2650xx_clk_min_ops;
diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h
index df4ad8a51050..a1ca0233cb4b 100644
--- a/drivers/clk/samsung/clk-pll.h
+++ b/drivers/clk/samsung/clk-pll.h
@@ -33,6 +33,7 @@ enum samsung_pll_type {
33 pll_s3c2440_mpll, 33 pll_s3c2440_mpll,
34 pll_2550x, 34 pll_2550x,
35 pll_2550xx, 35 pll_2550xx,
36 pll_2650x,
36 pll_2650xx, 37 pll_2650xx,
37 pll_1450x, 38 pll_1450x,
38 pll_1451x, 39 pll_1451x,