.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2014 MundoReader S.L. |
---|
3 | 4 | * Author: Heiko Stuebner <heiko@sntech.de> |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (c) 2015 Rockchip Electronics Co. Ltd. |
---|
6 | 7 | * Author: Xing Zheng <zhengxing@rock-chips.com> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | 8 | */ |
---|
18 | 9 | |
---|
19 | 10 | #include <asm/div64.h> |
---|
.. | .. |
---|
122 | 113 | |
---|
123 | 114 | return 0; |
---|
124 | 115 | } |
---|
| 116 | +EXPORT_SYMBOL(rockchip_pll_clk_adaptive_scaling); |
---|
125 | 117 | |
---|
126 | 118 | int rockchip_pll_clk_rate_to_scale(struct clk *clk, unsigned long rate) |
---|
127 | 119 | { |
---|
.. | .. |
---|
145 | 137 | |
---|
146 | 138 | return -EINVAL; |
---|
147 | 139 | } |
---|
| 140 | +EXPORT_SYMBOL(rockchip_pll_clk_rate_to_scale); |
---|
148 | 141 | |
---|
149 | 142 | int rockchip_pll_clk_scale_to_rate(struct clk *clk, unsigned int scale) |
---|
150 | 143 | { |
---|
.. | .. |
---|
168 | 161 | |
---|
169 | 162 | return -EINVAL; |
---|
170 | 163 | } |
---|
| 164 | +EXPORT_SYMBOL(rockchip_pll_clk_scale_to_rate); |
---|
171 | 165 | |
---|
172 | 166 | static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void) |
---|
173 | 167 | { |
---|
.. | .. |
---|
338 | 332 | return rate_table; |
---|
339 | 333 | } |
---|
340 | 334 | |
---|
| 335 | +static struct rockchip_pll_rate_table * |
---|
| 336 | +rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll, |
---|
| 337 | + unsigned long fin_hz, |
---|
| 338 | + unsigned long fout_hz) |
---|
| 339 | +{ |
---|
| 340 | + struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get(); |
---|
| 341 | + u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ; |
---|
| 342 | + u64 fout_min = 37 * MHZ, fout_max = 4500 * MHZ; |
---|
| 343 | + u32 p, m, s; |
---|
| 344 | + u64 fvco, fref, fout, ffrac; |
---|
| 345 | + |
---|
| 346 | + if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) |
---|
| 347 | + return NULL; |
---|
| 348 | + |
---|
| 349 | + if (fout_hz > fout_max || fout_hz < fout_min) |
---|
| 350 | + return NULL; |
---|
| 351 | + |
---|
| 352 | + if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) { |
---|
| 353 | + for (s = 0; s <= 6; s++) { |
---|
| 354 | + fvco = (u64)fout_hz << s; |
---|
| 355 | + if (fvco < fvco_min || fvco > fvco_max) |
---|
| 356 | + continue; |
---|
| 357 | + for (p = 2; p <= 4; p++) { |
---|
| 358 | + for (m = 64; m <= 1023; m++) { |
---|
| 359 | + if (fvco == m * fin_hz / p) { |
---|
| 360 | + rate_table->p = p; |
---|
| 361 | + rate_table->m = m; |
---|
| 362 | + rate_table->s = s; |
---|
| 363 | + rate_table->k = 0; |
---|
| 364 | + return rate_table; |
---|
| 365 | + } |
---|
| 366 | + } |
---|
| 367 | + } |
---|
| 368 | + } |
---|
| 369 | + pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
| 370 | + } else { |
---|
| 371 | + for (s = 0; s <= 6; s++) { |
---|
| 372 | + fvco = (u64)fout_hz << s; |
---|
| 373 | + if (fvco < fvco_min || fvco > fvco_max) |
---|
| 374 | + continue; |
---|
| 375 | + for (p = 1; p <= 4; p++) { |
---|
| 376 | + for (m = 64; m <= 1023; m++) { |
---|
| 377 | + if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) { |
---|
| 378 | + rate_table->p = p; |
---|
| 379 | + rate_table->m = m; |
---|
| 380 | + rate_table->s = s; |
---|
| 381 | + fref = fin_hz / p; |
---|
| 382 | + ffrac = fvco - (m * fref); |
---|
| 383 | + fout = ffrac * 65536; |
---|
| 384 | + rate_table->k = fout / fref; |
---|
| 385 | + return rate_table; |
---|
| 386 | + } |
---|
| 387 | + } |
---|
| 388 | + } |
---|
| 389 | + } |
---|
| 390 | + pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
| 391 | + } |
---|
| 392 | + return NULL; |
---|
| 393 | +} |
---|
| 394 | + |
---|
341 | 395 | static const struct rockchip_pll_rate_table *rockchip_get_pll_settings( |
---|
342 | 396 | struct rockchip_clk_pll *pll, unsigned long rate) |
---|
343 | 397 | { |
---|
.. | .. |
---|
358 | 412 | |
---|
359 | 413 | if (pll->type == pll_rk3066) |
---|
360 | 414 | return rockchip_rk3066_pll_clk_set_by_auto(pll, 24 * MHZ, rate); |
---|
| 415 | + else if (pll->type == pll_rk3588 || pll->type == pll_rk3588_core) |
---|
| 416 | + return rockchip_rk3588_pll_clk_set_by_auto(pll, 24 * MHZ, rate); |
---|
361 | 417 | else |
---|
362 | 418 | return rockchip_pll_clk_set_by_auto(pll, 24 * MHZ, rate); |
---|
363 | 419 | } |
---|
.. | .. |
---|
591 | 647 | static int rockchip_rk3036_pll_enable(struct clk_hw *hw) |
---|
592 | 648 | { |
---|
593 | 649 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 650 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 651 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
594 | 652 | |
---|
595 | 653 | writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0), |
---|
596 | 654 | pll->reg_base + RK3036_PLLCON(1)); |
---|
597 | 655 | rockchip_rk3036_pll_wait_lock(pll); |
---|
| 656 | + |
---|
| 657 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); |
---|
598 | 658 | |
---|
599 | 659 | return 0; |
---|
600 | 660 | } |
---|
.. | .. |
---|
602 | 662 | static void rockchip_rk3036_pll_disable(struct clk_hw *hw) |
---|
603 | 663 | { |
---|
604 | 664 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 665 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 666 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 667 | + |
---|
| 668 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); |
---|
605 | 669 | |
---|
606 | 670 | writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN, |
---|
607 | 671 | RK3036_PLLCON1_PWRDOWN, 0), |
---|
.. | .. |
---|
616 | 680 | return !(pllcon & RK3036_PLLCON1_PWRDOWN); |
---|
617 | 681 | } |
---|
618 | 682 | |
---|
619 | | -static void rockchip_rk3036_pll_init(struct clk_hw *hw) |
---|
| 683 | +static int rockchip_rk3036_pll_init(struct clk_hw *hw) |
---|
620 | 684 | { |
---|
621 | 685 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
622 | 686 | const struct rockchip_pll_rate_table *rate; |
---|
.. | .. |
---|
624 | 688 | unsigned long drate; |
---|
625 | 689 | |
---|
626 | 690 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
627 | | - return; |
---|
| 691 | + return 0; |
---|
628 | 692 | |
---|
629 | 693 | drate = clk_hw_get_rate(hw); |
---|
630 | 694 | rate = rockchip_get_pll_settings(pll, drate); |
---|
631 | 695 | |
---|
632 | 696 | /* when no rate setting for the current rate, rely on clk_set_rate */ |
---|
633 | 697 | if (!rate) |
---|
634 | | - return; |
---|
| 698 | + return 0; |
---|
635 | 699 | |
---|
636 | 700 | rockchip_rk3036_pll_get_params(pll, &cur); |
---|
637 | 701 | |
---|
.. | .. |
---|
653 | 717 | if (!parent) { |
---|
654 | 718 | pr_warn("%s: parent of %s not available\n", |
---|
655 | 719 | __func__, __clk_get_name(hw->clk)); |
---|
656 | | - return; |
---|
| 720 | + return 0; |
---|
657 | 721 | } |
---|
658 | 722 | |
---|
659 | 723 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", |
---|
660 | 724 | __func__, __clk_get_name(hw->clk)); |
---|
661 | 725 | rockchip_rk3036_pll_set_params(pll, rate); |
---|
662 | 726 | } |
---|
| 727 | + |
---|
| 728 | + return 0; |
---|
663 | 729 | } |
---|
664 | 730 | |
---|
665 | 731 | static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = { |
---|
.. | .. |
---|
865 | 931 | return !(pllcon & RK3066_PLLCON3_PWRDOWN); |
---|
866 | 932 | } |
---|
867 | 933 | |
---|
868 | | -static void rockchip_rk3066_pll_init(struct clk_hw *hw) |
---|
| 934 | +static int rockchip_rk3066_pll_init(struct clk_hw *hw) |
---|
869 | 935 | { |
---|
870 | 936 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
871 | 937 | const struct rockchip_pll_rate_table *rate; |
---|
.. | .. |
---|
873 | 939 | unsigned long drate; |
---|
874 | 940 | |
---|
875 | 941 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
876 | | - return; |
---|
| 942 | + return 0; |
---|
877 | 943 | |
---|
878 | 944 | drate = clk_hw_get_rate(hw); |
---|
879 | 945 | rate = rockchip_get_pll_settings(pll, drate); |
---|
880 | 946 | |
---|
881 | 947 | /* when no rate setting for the current rate, rely on clk_set_rate */ |
---|
882 | 948 | if (!rate) |
---|
883 | | - return; |
---|
| 949 | + return 0; |
---|
884 | 950 | |
---|
885 | 951 | rockchip_rk3066_pll_get_params(pll, &cur); |
---|
886 | 952 | |
---|
.. | .. |
---|
893 | 959 | __func__, clk_hw_get_name(hw)); |
---|
894 | 960 | rockchip_rk3066_pll_set_params(pll, rate); |
---|
895 | 961 | } |
---|
| 962 | + |
---|
| 963 | + return 0; |
---|
896 | 964 | } |
---|
897 | 965 | |
---|
898 | 966 | static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { |
---|
.. | .. |
---|
1131 | 1199 | return !(pllcon & RK3399_PLLCON3_PWRDOWN); |
---|
1132 | 1200 | } |
---|
1133 | 1201 | |
---|
1134 | | -static void rockchip_rk3399_pll_init(struct clk_hw *hw) |
---|
| 1202 | +static int rockchip_rk3399_pll_init(struct clk_hw *hw) |
---|
1135 | 1203 | { |
---|
1136 | 1204 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
1137 | 1205 | const struct rockchip_pll_rate_table *rate; |
---|
.. | .. |
---|
1139 | 1207 | unsigned long drate; |
---|
1140 | 1208 | |
---|
1141 | 1209 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
1142 | | - return; |
---|
| 1210 | + return 0; |
---|
1143 | 1211 | |
---|
1144 | 1212 | drate = clk_hw_get_rate(hw); |
---|
1145 | 1213 | rate = rockchip_get_pll_settings(pll, drate); |
---|
1146 | 1214 | |
---|
1147 | 1215 | /* when no rate setting for the current rate, rely on clk_set_rate */ |
---|
1148 | 1216 | if (!rate) |
---|
1149 | | - return; |
---|
| 1217 | + return 0; |
---|
1150 | 1218 | |
---|
1151 | 1219 | rockchip_rk3399_pll_get_params(pll, &cur); |
---|
1152 | 1220 | |
---|
.. | .. |
---|
1168 | 1236 | if (!parent) { |
---|
1169 | 1237 | pr_warn("%s: parent of %s not available\n", |
---|
1170 | 1238 | __func__, __clk_get_name(hw->clk)); |
---|
1171 | | - return; |
---|
| 1239 | + return 0; |
---|
1172 | 1240 | } |
---|
1173 | 1241 | |
---|
1174 | 1242 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", |
---|
1175 | 1243 | __func__, __clk_get_name(hw->clk)); |
---|
1176 | 1244 | rockchip_rk3399_pll_set_params(pll, rate); |
---|
1177 | 1245 | } |
---|
| 1246 | + |
---|
| 1247 | + return 0; |
---|
1178 | 1248 | } |
---|
1179 | 1249 | |
---|
1180 | 1250 | static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = { |
---|
.. | .. |
---|
1192 | 1262 | .disable = rockchip_rk3399_pll_disable, |
---|
1193 | 1263 | .is_enabled = rockchip_rk3399_pll_is_enabled, |
---|
1194 | 1264 | .init = rockchip_rk3399_pll_init, |
---|
| 1265 | +}; |
---|
| 1266 | + |
---|
| 1267 | +/** |
---|
| 1268 | + * PLL used in RK3588 |
---|
| 1269 | + */ |
---|
| 1270 | + |
---|
| 1271 | +#define RK3588_PLLCON(i) (i * 0x4) |
---|
| 1272 | +#define RK3588_PLLCON0_M_MASK 0x3ff |
---|
| 1273 | +#define RK3588_PLLCON0_M_SHIFT 0 |
---|
| 1274 | +#define RK3588_PLLCON1_P_MASK 0x3f |
---|
| 1275 | +#define RK3588_PLLCON1_P_SHIFT 0 |
---|
| 1276 | +#define RK3588_PLLCON1_S_MASK 0x7 |
---|
| 1277 | +#define RK3588_PLLCON1_S_SHIFT 6 |
---|
| 1278 | +#define RK3588_PLLCON2_K_MASK 0xffff |
---|
| 1279 | +#define RK3588_PLLCON2_K_SHIFT 0 |
---|
| 1280 | +#define RK3588_PLLCON1_PWRDOWN BIT(13) |
---|
| 1281 | +#define RK3588_PLLCON6_LOCK_STATUS BIT(15) |
---|
| 1282 | + |
---|
| 1283 | +static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll) |
---|
| 1284 | +{ |
---|
| 1285 | + u32 pllcon; |
---|
| 1286 | + int ret; |
---|
| 1287 | + |
---|
| 1288 | + /* |
---|
| 1289 | + * Lock time typical 250, max 500 input clock cycles @24MHz |
---|
| 1290 | + * So define a very safe maximum of 1000us, meaning 24000 cycles. |
---|
| 1291 | + */ |
---|
| 1292 | + ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6), |
---|
| 1293 | + pllcon, |
---|
| 1294 | + pllcon & RK3588_PLLCON6_LOCK_STATUS, |
---|
| 1295 | + 0, 1000); |
---|
| 1296 | + if (ret) |
---|
| 1297 | + pr_err("%s: timeout waiting for pll to lock\n", __func__); |
---|
| 1298 | + |
---|
| 1299 | + return ret; |
---|
| 1300 | +} |
---|
| 1301 | + |
---|
| 1302 | +static long rockchip_rk3588_pll_round_rate(struct clk_hw *hw, |
---|
| 1303 | + unsigned long drate, unsigned long *prate) |
---|
| 1304 | +{ |
---|
| 1305 | + if ((drate < 37 * MHZ) || (drate > 4500 * MHZ)) |
---|
| 1306 | + return -EINVAL; |
---|
| 1307 | + else |
---|
| 1308 | + return drate; |
---|
| 1309 | +} |
---|
| 1310 | + |
---|
| 1311 | +static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll, |
---|
| 1312 | + struct rockchip_pll_rate_table *rate) |
---|
| 1313 | +{ |
---|
| 1314 | + u32 pllcon; |
---|
| 1315 | + |
---|
| 1316 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0)); |
---|
| 1317 | + rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) |
---|
| 1318 | + & RK3588_PLLCON0_M_MASK); |
---|
| 1319 | + |
---|
| 1320 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1321 | + rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) |
---|
| 1322 | + & RK3588_PLLCON1_P_MASK); |
---|
| 1323 | + rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) |
---|
| 1324 | + & RK3588_PLLCON1_S_MASK); |
---|
| 1325 | + |
---|
| 1326 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2)); |
---|
| 1327 | + rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) |
---|
| 1328 | + & RK3588_PLLCON2_K_MASK); |
---|
| 1329 | +} |
---|
| 1330 | + |
---|
| 1331 | +static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, |
---|
| 1332 | + unsigned long prate) |
---|
| 1333 | +{ |
---|
| 1334 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1335 | + struct rockchip_pll_rate_table cur; |
---|
| 1336 | + u64 rate64 = prate, postdiv; |
---|
| 1337 | + |
---|
| 1338 | + if (pll->sel && pll->scaling) |
---|
| 1339 | + return pll->scaling; |
---|
| 1340 | + |
---|
| 1341 | + rockchip_rk3588_pll_get_params(pll, &cur); |
---|
| 1342 | + if (cur.p == 0) |
---|
| 1343 | + return prate; |
---|
| 1344 | + |
---|
| 1345 | + rate64 *= cur.m; |
---|
| 1346 | + do_div(rate64, cur.p); |
---|
| 1347 | + |
---|
| 1348 | + if (cur.k) { |
---|
| 1349 | + /* fractional mode */ |
---|
| 1350 | + u64 frac_rate64 = prate * cur.k; |
---|
| 1351 | + |
---|
| 1352 | + postdiv = cur.p; |
---|
| 1353 | + postdiv *= 65536; |
---|
| 1354 | + do_div(frac_rate64, postdiv); |
---|
| 1355 | + rate64 += frac_rate64; |
---|
| 1356 | + } |
---|
| 1357 | + rate64 = rate64 >> cur.s; |
---|
| 1358 | + |
---|
| 1359 | + return (unsigned long)rate64; |
---|
| 1360 | +} |
---|
| 1361 | + |
---|
| 1362 | +static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll, |
---|
| 1363 | + const struct rockchip_pll_rate_table *rate) |
---|
| 1364 | +{ |
---|
| 1365 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 1366 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 1367 | + struct rockchip_pll_rate_table cur; |
---|
| 1368 | + int rate_change_remuxed = 0; |
---|
| 1369 | + int cur_parent; |
---|
| 1370 | + int ret; |
---|
| 1371 | + |
---|
| 1372 | + pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n", |
---|
| 1373 | + __func__, rate->rate, rate->p, rate->m, rate->s, rate->k); |
---|
| 1374 | + |
---|
| 1375 | + rockchip_rk3588_pll_get_params(pll, &cur); |
---|
| 1376 | + cur.rate = 0; |
---|
| 1377 | + |
---|
| 1378 | + if (pll->type == pll_rk3588) { |
---|
| 1379 | + cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); |
---|
| 1380 | + if (cur_parent == PLL_MODE_NORM) { |
---|
| 1381 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); |
---|
| 1382 | + rate_change_remuxed = 1; |
---|
| 1383 | + } |
---|
| 1384 | + } |
---|
| 1385 | + |
---|
| 1386 | + /* set pll power down */ |
---|
| 1387 | + writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, |
---|
| 1388 | + RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1389 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1390 | + |
---|
| 1391 | + /* update pll values */ |
---|
| 1392 | + writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, |
---|
| 1393 | + RK3588_PLLCON0_M_SHIFT), |
---|
| 1394 | + pll->reg_base + RK3588_PLLCON(0)); |
---|
| 1395 | + |
---|
| 1396 | + writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, |
---|
| 1397 | + RK3588_PLLCON1_P_SHIFT) | |
---|
| 1398 | + HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, |
---|
| 1399 | + RK3588_PLLCON1_S_SHIFT), |
---|
| 1400 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1401 | + |
---|
| 1402 | + writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, |
---|
| 1403 | + RK3588_PLLCON2_K_SHIFT), |
---|
| 1404 | + pll->reg_base + RK3588_PLLCON(2)); |
---|
| 1405 | + |
---|
| 1406 | + /* set pll power up */ |
---|
| 1407 | + writel(HIWORD_UPDATE(0, |
---|
| 1408 | + RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1409 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1410 | + |
---|
| 1411 | + /* wait for the pll to lock */ |
---|
| 1412 | + ret = rockchip_rk3588_pll_wait_lock(pll); |
---|
| 1413 | + if (ret) { |
---|
| 1414 | + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", |
---|
| 1415 | + __func__); |
---|
| 1416 | + rockchip_rk3588_pll_set_params(pll, &cur); |
---|
| 1417 | + } |
---|
| 1418 | + |
---|
| 1419 | + if ((pll->type == pll_rk3588) && rate_change_remuxed) |
---|
| 1420 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); |
---|
| 1421 | + |
---|
| 1422 | + return ret; |
---|
| 1423 | +} |
---|
| 1424 | + |
---|
| 1425 | +static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate, |
---|
| 1426 | + unsigned long prate) |
---|
| 1427 | +{ |
---|
| 1428 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1429 | + const struct rockchip_pll_rate_table *rate; |
---|
| 1430 | + unsigned long old_rate = rockchip_rk3588_pll_recalc_rate(hw, prate); |
---|
| 1431 | + int ret; |
---|
| 1432 | + |
---|
| 1433 | + pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", |
---|
| 1434 | + __func__, __clk_get_name(hw->clk), old_rate, drate, prate); |
---|
| 1435 | + |
---|
| 1436 | + /* Get required rate settings from table */ |
---|
| 1437 | + rate = rockchip_get_pll_settings(pll, drate); |
---|
| 1438 | + if (!rate) { |
---|
| 1439 | + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, |
---|
| 1440 | + drate, __clk_get_name(hw->clk)); |
---|
| 1441 | + return -EINVAL; |
---|
| 1442 | + } |
---|
| 1443 | + |
---|
| 1444 | + ret = rockchip_rk3588_pll_set_params(pll, rate); |
---|
| 1445 | + if (ret) |
---|
| 1446 | + pll->scaling = 0; |
---|
| 1447 | + |
---|
| 1448 | + return ret; |
---|
| 1449 | +} |
---|
| 1450 | + |
---|
| 1451 | +static int rockchip_rk3588_pll_enable(struct clk_hw *hw) |
---|
| 1452 | +{ |
---|
| 1453 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1454 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 1455 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 1456 | + |
---|
| 1457 | + writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1458 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1459 | + rockchip_rk3588_pll_wait_lock(pll); |
---|
| 1460 | + |
---|
| 1461 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); |
---|
| 1462 | + |
---|
| 1463 | + return 0; |
---|
| 1464 | +} |
---|
| 1465 | + |
---|
| 1466 | +static void rockchip_rk3588_pll_disable(struct clk_hw *hw) |
---|
| 1467 | +{ |
---|
| 1468 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1469 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 1470 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 1471 | + |
---|
| 1472 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); |
---|
| 1473 | + |
---|
| 1474 | + writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, |
---|
| 1475 | + RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1476 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1477 | +} |
---|
| 1478 | + |
---|
| 1479 | +static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw) |
---|
| 1480 | +{ |
---|
| 1481 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1482 | + u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1483 | + |
---|
| 1484 | + return !(pllcon & RK3588_PLLCON1_PWRDOWN); |
---|
| 1485 | +} |
---|
| 1486 | + |
---|
| 1487 | +static int rockchip_rk3588_pll_init(struct clk_hw *hw) |
---|
| 1488 | +{ |
---|
| 1489 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1490 | + |
---|
| 1491 | + if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
| 1492 | + return 0; |
---|
| 1493 | + |
---|
| 1494 | + return 0; |
---|
| 1495 | +} |
---|
| 1496 | + |
---|
| 1497 | +static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = { |
---|
| 1498 | + .recalc_rate = rockchip_rk3588_pll_recalc_rate, |
---|
| 1499 | + .enable = rockchip_rk3588_pll_enable, |
---|
| 1500 | + .disable = rockchip_rk3588_pll_disable, |
---|
| 1501 | + .is_enabled = rockchip_rk3588_pll_is_enabled, |
---|
| 1502 | +}; |
---|
| 1503 | + |
---|
| 1504 | +static const struct clk_ops rockchip_rk3588_pll_clk_ops = { |
---|
| 1505 | + .recalc_rate = rockchip_rk3588_pll_recalc_rate, |
---|
| 1506 | + .round_rate = rockchip_rk3588_pll_round_rate, |
---|
| 1507 | + .set_rate = rockchip_rk3588_pll_set_rate, |
---|
| 1508 | + .enable = rockchip_rk3588_pll_enable, |
---|
| 1509 | + .disable = rockchip_rk3588_pll_disable, |
---|
| 1510 | + .is_enabled = rockchip_rk3588_pll_is_enabled, |
---|
| 1511 | + .init = rockchip_rk3588_pll_init, |
---|
1195 | 1512 | }; |
---|
1196 | 1513 | |
---|
1197 | 1514 | #ifdef CONFIG_ROCKCHIP_CLK_COMPENSATION |
---|
.. | .. |
---|
1236 | 1553 | frac_mask = RK3399_PLLCON2_FRAC_MASK; |
---|
1237 | 1554 | frac_shift = RK3399_PLLCON2_FRAC_SHIFT; |
---|
1238 | 1555 | break; |
---|
| 1556 | + case pll_rk3588: |
---|
| 1557 | + pllcon0 = RK3588_PLLCON(0); |
---|
| 1558 | + pllcon2 = RK3588_PLLCON(2); |
---|
| 1559 | + fbdiv_mask = RK3588_PLLCON0_M_MASK; |
---|
| 1560 | + frac_mask = RK3588_PLLCON2_K_MASK; |
---|
| 1561 | + frac_shift = RK3588_PLLCON2_K_SHIFT; |
---|
| 1562 | + break; |
---|
1239 | 1563 | default: |
---|
1240 | 1564 | return -EINVAL; |
---|
1241 | 1565 | } |
---|
.. | .. |
---|
1248 | 1572 | fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
1249 | 1573 | } |
---|
1250 | 1574 | |
---|
1251 | | - /* |
---|
1252 | | - * delta frac frac ppm |
---|
1253 | | - * -------------- = (fbdiv + ----------) * --------- |
---|
1254 | | - * 1 << 24 1 << 24 1000000 |
---|
1255 | | - * |
---|
1256 | | - */ |
---|
1257 | | - m = div64_u64((uint64_t)frac * ppm, 1000000); |
---|
1258 | | - n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv; |
---|
| 1575 | + switch (pll->type) { |
---|
| 1576 | + case pll_rk3036: |
---|
| 1577 | + case pll_rk3328: |
---|
| 1578 | + case pll_rk3066: |
---|
| 1579 | + case pll_rk3399: |
---|
| 1580 | + /* |
---|
| 1581 | + * delta frac frac ppm |
---|
| 1582 | + * -------------- = (fbdiv + ----------) * --------- |
---|
| 1583 | + * 1 << 24 1 << 24 1000000 |
---|
| 1584 | + * |
---|
| 1585 | + */ |
---|
| 1586 | + m = div64_u64((uint64_t)frac * ppm, 1000000); |
---|
| 1587 | + n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv; |
---|
1259 | 1588 | |
---|
1260 | | - fracdiv = negative ? frac - (m + n) : frac + (m + n); |
---|
| 1589 | + fracdiv = negative ? frac - (m + n) : frac + (m + n); |
---|
1261 | 1590 | |
---|
1262 | | - if (!frac || fracdiv > frac_mask) |
---|
| 1591 | + if (!frac || fracdiv > frac_mask) |
---|
| 1592 | + return -EINVAL; |
---|
| 1593 | + |
---|
| 1594 | + pllcon = readl_relaxed(pll->reg_base + pllcon2); |
---|
| 1595 | + pllcon &= ~(frac_mask << frac_shift); |
---|
| 1596 | + pllcon |= fracdiv << frac_shift; |
---|
| 1597 | + writel_relaxed(pllcon, pll->reg_base + pllcon2); |
---|
| 1598 | + break; |
---|
| 1599 | + case pll_rk3588: |
---|
| 1600 | + m = div64_u64((uint64_t)frac * ppm, 100000); |
---|
| 1601 | + n = div64_u64((uint64_t)ppm * 65535 * fbdiv, 100000); |
---|
| 1602 | + |
---|
| 1603 | + fracdiv = negative ? frac - (div64_u64(m + n, 10)) : frac + (div64_u64(m + n, 10)); |
---|
| 1604 | + |
---|
| 1605 | + if (!frac || fracdiv > frac_mask) |
---|
| 1606 | + return -EINVAL; |
---|
| 1607 | + |
---|
| 1608 | + writel_relaxed(HIWORD_UPDATE(fracdiv, frac_mask, frac_shift), |
---|
| 1609 | + pll->reg_base + pllcon2); |
---|
| 1610 | + break; |
---|
| 1611 | + default: |
---|
1263 | 1612 | return -EINVAL; |
---|
1264 | | - |
---|
1265 | | - pllcon = readl_relaxed(pll->reg_base + pllcon2); |
---|
1266 | | - pllcon &= ~(frac_mask << frac_shift); |
---|
1267 | | - pllcon |= fracdiv << frac_shift; |
---|
1268 | | - writel_relaxed(pllcon, pll->reg_base + pllcon2); |
---|
| 1613 | + } |
---|
1269 | 1614 | |
---|
1270 | 1615 | return 0; |
---|
1271 | 1616 | } |
---|
.. | .. |
---|
1285 | 1630 | unsigned long flags, u8 clk_pll_flags) |
---|
1286 | 1631 | { |
---|
1287 | 1632 | const char *pll_parents[3]; |
---|
1288 | | - struct clk_init_data init = {}; |
---|
| 1633 | + struct clk_init_data init; |
---|
1289 | 1634 | struct rockchip_clk_pll *pll; |
---|
1290 | 1635 | struct clk_mux *pll_mux; |
---|
1291 | 1636 | struct clk *pll_clk, *mux_clk; |
---|
.. | .. |
---|
1316 | 1661 | pll_mux->flags = 0; |
---|
1317 | 1662 | pll_mux->lock = &ctx->lock; |
---|
1318 | 1663 | pll_mux->hw.init = &init; |
---|
1319 | | - |
---|
1320 | | - if (pll_type == pll_rk3036 || |
---|
1321 | | - pll_type == pll_rk3066 || |
---|
1322 | | - pll_type == pll_rk3328 || |
---|
1323 | | - pll_type == pll_rk3399) |
---|
1324 | | - pll_mux->flags |= CLK_MUX_HIWORD_MASK; |
---|
| 1664 | + pll_mux->flags |= CLK_MUX_HIWORD_MASK; |
---|
1325 | 1665 | |
---|
1326 | 1666 | /* the actual muxing is xin24m, pll-output, xin32k */ |
---|
1327 | 1667 | pll_parents[0] = parent_names[0]; |
---|
.. | .. |
---|
1345 | 1685 | init.name = pll_name; |
---|
1346 | 1686 | |
---|
1347 | 1687 | #ifndef CONFIG_ROCKCHIP_LOW_PERFORMANCE |
---|
1348 | | - /* keep all plls untouched for now */ |
---|
1349 | | - init.flags = flags | CLK_IGNORE_UNUSED; |
---|
| 1688 | + if (clk_pll_flags & ROCKCHIP_PLL_ALLOW_POWER_DOWN) |
---|
| 1689 | + init.flags = flags; |
---|
| 1690 | + else |
---|
| 1691 | + /* keep all plls untouched for now */ |
---|
| 1692 | + init.flags = flags | CLK_IGNORE_UNUSED; |
---|
1350 | 1693 | #else |
---|
1351 | 1694 | init.flags = flags; |
---|
1352 | 1695 | #endif |
---|
.. | .. |
---|
1374 | 1717 | switch (pll_type) { |
---|
1375 | 1718 | case pll_rk3036: |
---|
1376 | 1719 | case pll_rk3328: |
---|
1377 | | - if (!pll->rate_table || IS_ERR(ctx->grf)) |
---|
| 1720 | + if (!pll->rate_table) |
---|
1378 | 1721 | init.ops = &rockchip_rk3036_pll_clk_norate_ops; |
---|
1379 | 1722 | else |
---|
1380 | 1723 | init.ops = &rockchip_rk3036_pll_clk_ops; |
---|
.. | .. |
---|
1393 | 1736 | init.ops = &rockchip_rk3399_pll_clk_norate_ops; |
---|
1394 | 1737 | else |
---|
1395 | 1738 | init.ops = &rockchip_rk3399_pll_clk_ops; |
---|
| 1739 | + break; |
---|
| 1740 | +#endif |
---|
| 1741 | +#ifdef CONFIG_ROCKCHIP_PLL_RK3588 |
---|
| 1742 | + case pll_rk3588: |
---|
| 1743 | + case pll_rk3588_core: |
---|
| 1744 | + if (!pll->rate_table) |
---|
| 1745 | + init.ops = &rockchip_rk3588_pll_clk_norate_ops; |
---|
| 1746 | + else |
---|
| 1747 | + init.ops = &rockchip_rk3588_pll_clk_ops; |
---|
| 1748 | + init.flags = flags; |
---|
1396 | 1749 | break; |
---|
1397 | 1750 | #endif |
---|
1398 | 1751 | default: |
---|
.. | .. |
---|
1619 | 1972 | #ifdef CONFIG_DEBUG_FS |
---|
1620 | 1973 | #include <linux/debugfs.h> |
---|
1621 | 1974 | |
---|
| 1975 | +#ifndef MODULE |
---|
1622 | 1976 | static int boost_summary_show(struct seq_file *s, void *data) |
---|
1623 | 1977 | { |
---|
1624 | 1978 | struct rockchip_clk_pll *pll = (struct rockchip_clk_pll *)s->private; |
---|
.. | .. |
---|
1736 | 2090 | return 0; |
---|
1737 | 2091 | } |
---|
1738 | 2092 | late_initcall(boost_debug_init); |
---|
| 2093 | +#endif /* MODULE */ |
---|
1739 | 2094 | #endif /* CONFIG_DEBUG_FS */ |
---|
1740 | 2095 | #endif /* CONFIG_ROCKCHIP_CLK_BOOST */ |
---|