.. | .. |
---|
| 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 u32 |
---|
| 336 | +rockchip_rk3588_pll_frac_get(u32 m, u32 p, u32 s, u64 fin_hz, u64 fvco) |
---|
| 337 | +{ |
---|
| 338 | + u64 fref, fout, ffrac; |
---|
| 339 | + u32 k = 0; |
---|
| 340 | + |
---|
| 341 | + fref = fin_hz / p; |
---|
| 342 | + ffrac = fvco - (m * fref); |
---|
| 343 | + fout = ffrac * 65536; |
---|
| 344 | + k = fout / fref; |
---|
| 345 | + if (k > 32767) { |
---|
| 346 | + fref = fin_hz / p; |
---|
| 347 | + ffrac = ((m + 1) * fref) - fvco; |
---|
| 348 | + fout = ffrac * 65536; |
---|
| 349 | + k = ((fout * 10 / fref) + 7) / 10; |
---|
| 350 | + if (k > 32767) |
---|
| 351 | + k = 0; |
---|
| 352 | + else |
---|
| 353 | + k = ~k + 1; |
---|
| 354 | + } |
---|
| 355 | + return k; |
---|
| 356 | +} |
---|
| 357 | + |
---|
| 358 | +static struct rockchip_pll_rate_table * |
---|
| 359 | +rockchip_rk3588_pll_frac_by_auto(unsigned long fin_hz, unsigned long fout_hz) |
---|
| 360 | +{ |
---|
| 361 | + struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get(); |
---|
| 362 | + u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ; |
---|
| 363 | + u32 p, m, s, k; |
---|
| 364 | + u64 fvco; |
---|
| 365 | + |
---|
| 366 | + for (s = 0; s <= 6; s++) { |
---|
| 367 | + fvco = (u64)fout_hz << s; |
---|
| 368 | + if (fvco < fvco_min || fvco > fvco_max) |
---|
| 369 | + continue; |
---|
| 370 | + for (p = 1; p <= 4; p++) { |
---|
| 371 | + for (m = 64; m <= 1023; m++) { |
---|
| 372 | + if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) { |
---|
| 373 | + k = rockchip_rk3588_pll_frac_get(m, p, s, |
---|
| 374 | + (u64)fin_hz, |
---|
| 375 | + fvco); |
---|
| 376 | + if (!k) |
---|
| 377 | + continue; |
---|
| 378 | + rate_table->p = p; |
---|
| 379 | + rate_table->s = s; |
---|
| 380 | + rate_table->k = k; |
---|
| 381 | + if (k > 32767) |
---|
| 382 | + rate_table->m = m + 1; |
---|
| 383 | + else |
---|
| 384 | + rate_table->m = m; |
---|
| 385 | + return rate_table; |
---|
| 386 | + } |
---|
| 387 | + } |
---|
| 388 | + } |
---|
| 389 | + } |
---|
| 390 | + return NULL; |
---|
| 391 | +} |
---|
| 392 | + |
---|
| 393 | +static struct rockchip_pll_rate_table * |
---|
| 394 | +rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll, |
---|
| 395 | + unsigned long fin_hz, |
---|
| 396 | + unsigned long fout_hz) |
---|
| 397 | +{ |
---|
| 398 | + struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get(); |
---|
| 399 | + u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ; |
---|
| 400 | + u64 fout_min = 37 * MHZ, fout_max = 4500 * MHZ; |
---|
| 401 | + u32 p, m, s; |
---|
| 402 | + u64 fvco; |
---|
| 403 | + |
---|
| 404 | + if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) |
---|
| 405 | + return NULL; |
---|
| 406 | + |
---|
| 407 | + if (fout_hz > fout_max || fout_hz < fout_min) |
---|
| 408 | + return NULL; |
---|
| 409 | + |
---|
| 410 | + if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) { |
---|
| 411 | + for (s = 0; s <= 6; s++) { |
---|
| 412 | + fvco = (u64)fout_hz << s; |
---|
| 413 | + if (fvco < fvco_min || fvco > fvco_max) |
---|
| 414 | + continue; |
---|
| 415 | + for (p = 2; p <= 4; p++) { |
---|
| 416 | + for (m = 64; m <= 1023; m++) { |
---|
| 417 | + if (fvco == m * fin_hz / p) { |
---|
| 418 | + rate_table->p = p; |
---|
| 419 | + rate_table->m = m; |
---|
| 420 | + rate_table->s = s; |
---|
| 421 | + rate_table->k = 0; |
---|
| 422 | + return rate_table; |
---|
| 423 | + } |
---|
| 424 | + } |
---|
| 425 | + } |
---|
| 426 | + } |
---|
| 427 | + pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
| 428 | + } else { |
---|
| 429 | + rate_table = rockchip_rk3588_pll_frac_by_auto(fin_hz, fout_hz); |
---|
| 430 | + if (!rate_table) |
---|
| 431 | + pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
| 432 | + else |
---|
| 433 | + return rate_table; |
---|
| 434 | + } |
---|
| 435 | + return NULL; |
---|
| 436 | +} |
---|
| 437 | + |
---|
341 | 438 | static const struct rockchip_pll_rate_table *rockchip_get_pll_settings( |
---|
342 | 439 | struct rockchip_clk_pll *pll, unsigned long rate) |
---|
343 | 440 | { |
---|
.. | .. |
---|
358 | 455 | |
---|
359 | 456 | if (pll->type == pll_rk3066) |
---|
360 | 457 | return rockchip_rk3066_pll_clk_set_by_auto(pll, 24 * MHZ, rate); |
---|
| 458 | + else if (pll->type == pll_rk3588 || pll->type == pll_rk3588_core) |
---|
| 459 | + return rockchip_rk3588_pll_clk_set_by_auto(pll, 24 * MHZ, rate); |
---|
361 | 460 | else |
---|
362 | 461 | return rockchip_pll_clk_set_by_auto(pll, 24 * MHZ, rate); |
---|
363 | 462 | } |
---|
.. | .. |
---|
591 | 690 | static int rockchip_rk3036_pll_enable(struct clk_hw *hw) |
---|
592 | 691 | { |
---|
593 | 692 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 693 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 694 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
594 | 695 | |
---|
595 | 696 | writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0), |
---|
596 | 697 | pll->reg_base + RK3036_PLLCON(1)); |
---|
597 | 698 | rockchip_rk3036_pll_wait_lock(pll); |
---|
| 699 | + |
---|
| 700 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); |
---|
598 | 701 | |
---|
599 | 702 | return 0; |
---|
600 | 703 | } |
---|
.. | .. |
---|
602 | 705 | static void rockchip_rk3036_pll_disable(struct clk_hw *hw) |
---|
603 | 706 | { |
---|
604 | 707 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 708 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 709 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 710 | + |
---|
| 711 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); |
---|
605 | 712 | |
---|
606 | 713 | writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN, |
---|
607 | 714 | RK3036_PLLCON1_PWRDOWN, 0), |
---|
.. | .. |
---|
616 | 723 | return !(pllcon & RK3036_PLLCON1_PWRDOWN); |
---|
617 | 724 | } |
---|
618 | 725 | |
---|
619 | | -static void rockchip_rk3036_pll_init(struct clk_hw *hw) |
---|
| 726 | +static int rockchip_rk3036_pll_init(struct clk_hw *hw) |
---|
620 | 727 | { |
---|
621 | 728 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
622 | 729 | const struct rockchip_pll_rate_table *rate; |
---|
.. | .. |
---|
624 | 731 | unsigned long drate; |
---|
625 | 732 | |
---|
626 | 733 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
627 | | - return; |
---|
| 734 | + return 0; |
---|
628 | 735 | |
---|
629 | 736 | drate = clk_hw_get_rate(hw); |
---|
630 | 737 | rate = rockchip_get_pll_settings(pll, drate); |
---|
631 | 738 | |
---|
632 | 739 | /* when no rate setting for the current rate, rely on clk_set_rate */ |
---|
633 | 740 | if (!rate) |
---|
634 | | - return; |
---|
| 741 | + return 0; |
---|
635 | 742 | |
---|
636 | 743 | rockchip_rk3036_pll_get_params(pll, &cur); |
---|
637 | 744 | |
---|
.. | .. |
---|
653 | 760 | if (!parent) { |
---|
654 | 761 | pr_warn("%s: parent of %s not available\n", |
---|
655 | 762 | __func__, __clk_get_name(hw->clk)); |
---|
656 | | - return; |
---|
| 763 | + return 0; |
---|
657 | 764 | } |
---|
658 | 765 | |
---|
659 | 766 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", |
---|
660 | 767 | __func__, __clk_get_name(hw->clk)); |
---|
661 | 768 | rockchip_rk3036_pll_set_params(pll, rate); |
---|
662 | 769 | } |
---|
| 770 | + |
---|
| 771 | + return 0; |
---|
663 | 772 | } |
---|
664 | 773 | |
---|
665 | 774 | static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = { |
---|
.. | .. |
---|
865 | 974 | return !(pllcon & RK3066_PLLCON3_PWRDOWN); |
---|
866 | 975 | } |
---|
867 | 976 | |
---|
868 | | -static void rockchip_rk3066_pll_init(struct clk_hw *hw) |
---|
| 977 | +static int rockchip_rk3066_pll_init(struct clk_hw *hw) |
---|
869 | 978 | { |
---|
870 | 979 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
871 | 980 | const struct rockchip_pll_rate_table *rate; |
---|
.. | .. |
---|
873 | 982 | unsigned long drate; |
---|
874 | 983 | |
---|
875 | 984 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
876 | | - return; |
---|
| 985 | + return 0; |
---|
877 | 986 | |
---|
878 | 987 | drate = clk_hw_get_rate(hw); |
---|
879 | 988 | rate = rockchip_get_pll_settings(pll, drate); |
---|
880 | 989 | |
---|
881 | 990 | /* when no rate setting for the current rate, rely on clk_set_rate */ |
---|
882 | 991 | if (!rate) |
---|
883 | | - return; |
---|
| 992 | + return 0; |
---|
884 | 993 | |
---|
885 | 994 | rockchip_rk3066_pll_get_params(pll, &cur); |
---|
886 | 995 | |
---|
.. | .. |
---|
893 | 1002 | __func__, clk_hw_get_name(hw)); |
---|
894 | 1003 | rockchip_rk3066_pll_set_params(pll, rate); |
---|
895 | 1004 | } |
---|
| 1005 | + |
---|
| 1006 | + return 0; |
---|
896 | 1007 | } |
---|
897 | 1008 | |
---|
898 | 1009 | static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { |
---|
.. | .. |
---|
1131 | 1242 | return !(pllcon & RK3399_PLLCON3_PWRDOWN); |
---|
1132 | 1243 | } |
---|
1133 | 1244 | |
---|
1134 | | -static void rockchip_rk3399_pll_init(struct clk_hw *hw) |
---|
| 1245 | +static int rockchip_rk3399_pll_init(struct clk_hw *hw) |
---|
1135 | 1246 | { |
---|
1136 | 1247 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
1137 | 1248 | const struct rockchip_pll_rate_table *rate; |
---|
.. | .. |
---|
1139 | 1250 | unsigned long drate; |
---|
1140 | 1251 | |
---|
1141 | 1252 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
1142 | | - return; |
---|
| 1253 | + return 0; |
---|
1143 | 1254 | |
---|
1144 | 1255 | drate = clk_hw_get_rate(hw); |
---|
1145 | 1256 | rate = rockchip_get_pll_settings(pll, drate); |
---|
1146 | 1257 | |
---|
1147 | 1258 | /* when no rate setting for the current rate, rely on clk_set_rate */ |
---|
1148 | 1259 | if (!rate) |
---|
1149 | | - return; |
---|
| 1260 | + return 0; |
---|
1150 | 1261 | |
---|
1151 | 1262 | rockchip_rk3399_pll_get_params(pll, &cur); |
---|
1152 | 1263 | |
---|
.. | .. |
---|
1168 | 1279 | if (!parent) { |
---|
1169 | 1280 | pr_warn("%s: parent of %s not available\n", |
---|
1170 | 1281 | __func__, __clk_get_name(hw->clk)); |
---|
1171 | | - return; |
---|
| 1282 | + return 0; |
---|
1172 | 1283 | } |
---|
1173 | 1284 | |
---|
1174 | 1285 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", |
---|
1175 | 1286 | __func__, __clk_get_name(hw->clk)); |
---|
1176 | 1287 | rockchip_rk3399_pll_set_params(pll, rate); |
---|
1177 | 1288 | } |
---|
| 1289 | + |
---|
| 1290 | + return 0; |
---|
1178 | 1291 | } |
---|
1179 | 1292 | |
---|
1180 | 1293 | static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = { |
---|
.. | .. |
---|
1194 | 1307 | .init = rockchip_rk3399_pll_init, |
---|
1195 | 1308 | }; |
---|
1196 | 1309 | |
---|
| 1310 | +/** |
---|
| 1311 | + * PLL used in RK3588 |
---|
| 1312 | + */ |
---|
| 1313 | + |
---|
| 1314 | +#define RK3588_PLLCON(i) (i * 0x4) |
---|
| 1315 | +#define RK3588_PLLCON0_M_MASK 0x3ff |
---|
| 1316 | +#define RK3588_PLLCON0_M_SHIFT 0 |
---|
| 1317 | +#define RK3588_PLLCON1_P_MASK 0x3f |
---|
| 1318 | +#define RK3588_PLLCON1_P_SHIFT 0 |
---|
| 1319 | +#define RK3588_PLLCON1_S_MASK 0x7 |
---|
| 1320 | +#define RK3588_PLLCON1_S_SHIFT 6 |
---|
| 1321 | +#define RK3588_PLLCON2_K_MASK 0xffff |
---|
| 1322 | +#define RK3588_PLLCON2_K_SHIFT 0 |
---|
| 1323 | +#define RK3588_PLLCON1_PWRDOWN BIT(13) |
---|
| 1324 | +#define RK3588_PLLCON6_LOCK_STATUS BIT(15) |
---|
| 1325 | + |
---|
| 1326 | +static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll) |
---|
| 1327 | +{ |
---|
| 1328 | + u32 pllcon; |
---|
| 1329 | + int ret; |
---|
| 1330 | + |
---|
| 1331 | + /* |
---|
| 1332 | + * Lock time typical 250, max 500 input clock cycles @24MHz |
---|
| 1333 | + * So define a very safe maximum of 1000us, meaning 24000 cycles. |
---|
| 1334 | + */ |
---|
| 1335 | + ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6), |
---|
| 1336 | + pllcon, |
---|
| 1337 | + pllcon & RK3588_PLLCON6_LOCK_STATUS, |
---|
| 1338 | + 0, 1000); |
---|
| 1339 | + if (ret) |
---|
| 1340 | + pr_err("%s: timeout waiting for pll to lock\n", __func__); |
---|
| 1341 | + |
---|
| 1342 | + return ret; |
---|
| 1343 | +} |
---|
| 1344 | + |
---|
| 1345 | +static long rockchip_rk3588_pll_round_rate(struct clk_hw *hw, |
---|
| 1346 | + unsigned long drate, unsigned long *prate) |
---|
| 1347 | +{ |
---|
| 1348 | + if ((drate < 37 * MHZ) || (drate > 4500 * MHZ)) |
---|
| 1349 | + return -EINVAL; |
---|
| 1350 | + else |
---|
| 1351 | + return drate; |
---|
| 1352 | +} |
---|
| 1353 | + |
---|
| 1354 | +static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll, |
---|
| 1355 | + struct rockchip_pll_rate_table *rate) |
---|
| 1356 | +{ |
---|
| 1357 | + u32 pllcon; |
---|
| 1358 | + |
---|
| 1359 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0)); |
---|
| 1360 | + rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) |
---|
| 1361 | + & RK3588_PLLCON0_M_MASK); |
---|
| 1362 | + |
---|
| 1363 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1364 | + rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) |
---|
| 1365 | + & RK3588_PLLCON1_P_MASK); |
---|
| 1366 | + rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) |
---|
| 1367 | + & RK3588_PLLCON1_S_MASK); |
---|
| 1368 | + |
---|
| 1369 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2)); |
---|
| 1370 | + rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) |
---|
| 1371 | + & RK3588_PLLCON2_K_MASK); |
---|
| 1372 | +} |
---|
| 1373 | + |
---|
| 1374 | +static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, |
---|
| 1375 | + unsigned long prate) |
---|
| 1376 | +{ |
---|
| 1377 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1378 | + struct rockchip_pll_rate_table cur; |
---|
| 1379 | + u64 rate64 = prate, postdiv; |
---|
| 1380 | + |
---|
| 1381 | + if (pll->sel && pll->scaling) |
---|
| 1382 | + return pll->scaling; |
---|
| 1383 | + |
---|
| 1384 | + rockchip_rk3588_pll_get_params(pll, &cur); |
---|
| 1385 | + if (cur.p == 0) |
---|
| 1386 | + return prate; |
---|
| 1387 | + |
---|
| 1388 | + rate64 *= cur.m; |
---|
| 1389 | + do_div(rate64, cur.p); |
---|
| 1390 | + |
---|
| 1391 | + if (cur.k & BIT(15)) { |
---|
| 1392 | + /* fractional mode */ |
---|
| 1393 | + u64 frac_rate64; |
---|
| 1394 | + |
---|
| 1395 | + cur.k = (~(cur.k - 1)) & RK3588_PLLCON2_K_MASK; |
---|
| 1396 | + frac_rate64 = prate * cur.k; |
---|
| 1397 | + postdiv = cur.p; |
---|
| 1398 | + postdiv *= 65536; |
---|
| 1399 | + do_div(frac_rate64, postdiv); |
---|
| 1400 | + rate64 -= frac_rate64; |
---|
| 1401 | + } else { |
---|
| 1402 | + /* fractional mode */ |
---|
| 1403 | + u64 frac_rate64 = prate * cur.k; |
---|
| 1404 | + |
---|
| 1405 | + postdiv = cur.p; |
---|
| 1406 | + postdiv *= 65536; |
---|
| 1407 | + do_div(frac_rate64, postdiv); |
---|
| 1408 | + rate64 += frac_rate64; |
---|
| 1409 | + } |
---|
| 1410 | + rate64 = rate64 >> cur.s; |
---|
| 1411 | + |
---|
| 1412 | + return (unsigned long)rate64; |
---|
| 1413 | +} |
---|
| 1414 | + |
---|
| 1415 | +static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll, |
---|
| 1416 | + const struct rockchip_pll_rate_table *rate) |
---|
| 1417 | +{ |
---|
| 1418 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 1419 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 1420 | + struct rockchip_pll_rate_table cur; |
---|
| 1421 | + int rate_change_remuxed = 0; |
---|
| 1422 | + int cur_parent; |
---|
| 1423 | + int ret; |
---|
| 1424 | + |
---|
| 1425 | + pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n", |
---|
| 1426 | + __func__, rate->rate, rate->p, rate->m, rate->s, rate->k); |
---|
| 1427 | + |
---|
| 1428 | + rockchip_rk3588_pll_get_params(pll, &cur); |
---|
| 1429 | + cur.rate = 0; |
---|
| 1430 | + |
---|
| 1431 | + if (pll->type == pll_rk3588) { |
---|
| 1432 | + cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); |
---|
| 1433 | + if (cur_parent == PLL_MODE_NORM) { |
---|
| 1434 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); |
---|
| 1435 | + rate_change_remuxed = 1; |
---|
| 1436 | + } |
---|
| 1437 | + } |
---|
| 1438 | + |
---|
| 1439 | + /* set pll power down */ |
---|
| 1440 | + writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, |
---|
| 1441 | + RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1442 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1443 | + |
---|
| 1444 | + /* update pll values */ |
---|
| 1445 | + writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, |
---|
| 1446 | + RK3588_PLLCON0_M_SHIFT), |
---|
| 1447 | + pll->reg_base + RK3588_PLLCON(0)); |
---|
| 1448 | + |
---|
| 1449 | + writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, |
---|
| 1450 | + RK3588_PLLCON1_P_SHIFT) | |
---|
| 1451 | + HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, |
---|
| 1452 | + RK3588_PLLCON1_S_SHIFT), |
---|
| 1453 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1454 | + |
---|
| 1455 | + writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, |
---|
| 1456 | + RK3588_PLLCON2_K_SHIFT), |
---|
| 1457 | + pll->reg_base + RK3588_PLLCON(2)); |
---|
| 1458 | + |
---|
| 1459 | + /* set pll power up */ |
---|
| 1460 | + writel(HIWORD_UPDATE(0, |
---|
| 1461 | + RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1462 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1463 | + |
---|
| 1464 | + /* wait for the pll to lock */ |
---|
| 1465 | + ret = rockchip_rk3588_pll_wait_lock(pll); |
---|
| 1466 | + if (ret) { |
---|
| 1467 | + pr_warn("%s: pll update unsuccessful, trying to restore old params\n", |
---|
| 1468 | + __func__); |
---|
| 1469 | + rockchip_rk3588_pll_set_params(pll, &cur); |
---|
| 1470 | + } |
---|
| 1471 | + |
---|
| 1472 | + if ((pll->type == pll_rk3588) && rate_change_remuxed) |
---|
| 1473 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); |
---|
| 1474 | + |
---|
| 1475 | + return ret; |
---|
| 1476 | +} |
---|
| 1477 | + |
---|
| 1478 | +static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate, |
---|
| 1479 | + unsigned long prate) |
---|
| 1480 | +{ |
---|
| 1481 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1482 | + const struct rockchip_pll_rate_table *rate; |
---|
| 1483 | + unsigned long old_rate = rockchip_rk3588_pll_recalc_rate(hw, prate); |
---|
| 1484 | + int ret; |
---|
| 1485 | + |
---|
| 1486 | + pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n", |
---|
| 1487 | + __func__, __clk_get_name(hw->clk), old_rate, drate, prate); |
---|
| 1488 | + |
---|
| 1489 | + /* Get required rate settings from table */ |
---|
| 1490 | + rate = rockchip_get_pll_settings(pll, drate); |
---|
| 1491 | + if (!rate) { |
---|
| 1492 | + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, |
---|
| 1493 | + drate, __clk_get_name(hw->clk)); |
---|
| 1494 | + return -EINVAL; |
---|
| 1495 | + } |
---|
| 1496 | + |
---|
| 1497 | + ret = rockchip_rk3588_pll_set_params(pll, rate); |
---|
| 1498 | + if (ret) |
---|
| 1499 | + pll->scaling = 0; |
---|
| 1500 | + |
---|
| 1501 | + return ret; |
---|
| 1502 | +} |
---|
| 1503 | + |
---|
| 1504 | +static int rockchip_rk3588_pll_enable(struct clk_hw *hw) |
---|
| 1505 | +{ |
---|
| 1506 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1507 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 1508 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 1509 | + |
---|
| 1510 | + writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1511 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1512 | + rockchip_rk3588_pll_wait_lock(pll); |
---|
| 1513 | + |
---|
| 1514 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); |
---|
| 1515 | + |
---|
| 1516 | + return 0; |
---|
| 1517 | +} |
---|
| 1518 | + |
---|
| 1519 | +static void rockchip_rk3588_pll_disable(struct clk_hw *hw) |
---|
| 1520 | +{ |
---|
| 1521 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1522 | + const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; |
---|
| 1523 | + struct clk_mux *pll_mux = &pll->pll_mux; |
---|
| 1524 | + |
---|
| 1525 | + pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); |
---|
| 1526 | + |
---|
| 1527 | + writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, |
---|
| 1528 | + RK3588_PLLCON1_PWRDOWN, 0), |
---|
| 1529 | + pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1530 | +} |
---|
| 1531 | + |
---|
| 1532 | +static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw) |
---|
| 1533 | +{ |
---|
| 1534 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1535 | + u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1536 | + |
---|
| 1537 | + return !(pllcon & RK3588_PLLCON1_PWRDOWN); |
---|
| 1538 | +} |
---|
| 1539 | + |
---|
| 1540 | +static int rockchip_rk3588_pll_init(struct clk_hw *hw) |
---|
| 1541 | +{ |
---|
| 1542 | + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); |
---|
| 1543 | + |
---|
| 1544 | + if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) |
---|
| 1545 | + return 0; |
---|
| 1546 | + |
---|
| 1547 | + return 0; |
---|
| 1548 | +} |
---|
| 1549 | + |
---|
| 1550 | +static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = { |
---|
| 1551 | + .recalc_rate = rockchip_rk3588_pll_recalc_rate, |
---|
| 1552 | + .enable = rockchip_rk3588_pll_enable, |
---|
| 1553 | + .disable = rockchip_rk3588_pll_disable, |
---|
| 1554 | + .is_enabled = rockchip_rk3588_pll_is_enabled, |
---|
| 1555 | +}; |
---|
| 1556 | + |
---|
| 1557 | +static const struct clk_ops rockchip_rk3588_pll_clk_ops = { |
---|
| 1558 | + .recalc_rate = rockchip_rk3588_pll_recalc_rate, |
---|
| 1559 | + .round_rate = rockchip_rk3588_pll_round_rate, |
---|
| 1560 | + .set_rate = rockchip_rk3588_pll_set_rate, |
---|
| 1561 | + .enable = rockchip_rk3588_pll_enable, |
---|
| 1562 | + .disable = rockchip_rk3588_pll_disable, |
---|
| 1563 | + .is_enabled = rockchip_rk3588_pll_is_enabled, |
---|
| 1564 | + .init = rockchip_rk3588_pll_init, |
---|
| 1565 | +}; |
---|
| 1566 | + |
---|
1197 | 1567 | #ifdef CONFIG_ROCKCHIP_CLK_COMPENSATION |
---|
1198 | 1568 | int rockchip_pll_clk_compensation(struct clk *clk, int ppm) |
---|
1199 | 1569 | { |
---|
1200 | 1570 | struct clk *parent = clk_get_parent(clk); |
---|
1201 | 1571 | struct rockchip_clk_pll *pll; |
---|
1202 | | - static u32 frac, fbdiv; |
---|
| 1572 | + static u32 frac, fbdiv, s, p; |
---|
1203 | 1573 | bool negative; |
---|
1204 | 1574 | u32 pllcon, pllcon0, pllcon2, fbdiv_mask, frac_mask, frac_shift; |
---|
1205 | 1575 | u64 fracdiv, m, n; |
---|
.. | .. |
---|
1236 | 1606 | frac_mask = RK3399_PLLCON2_FRAC_MASK; |
---|
1237 | 1607 | frac_shift = RK3399_PLLCON2_FRAC_SHIFT; |
---|
1238 | 1608 | break; |
---|
| 1609 | + case pll_rk3588: |
---|
| 1610 | + pllcon0 = RK3588_PLLCON(0); |
---|
| 1611 | + pllcon2 = RK3588_PLLCON(2); |
---|
| 1612 | + fbdiv_mask = RK3588_PLLCON0_M_MASK; |
---|
| 1613 | + frac_mask = RK3588_PLLCON2_K_MASK; |
---|
| 1614 | + frac_shift = RK3588_PLLCON2_K_SHIFT; |
---|
| 1615 | + break; |
---|
1239 | 1616 | default: |
---|
1240 | 1617 | return -EINVAL; |
---|
1241 | 1618 | } |
---|
.. | .. |
---|
1243 | 1620 | negative = !!(ppm & BIT(31)); |
---|
1244 | 1621 | ppm = negative ? ~ppm + 1 : ppm; |
---|
1245 | 1622 | |
---|
1246 | | - if (!frac) { |
---|
1247 | | - frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask; |
---|
1248 | | - fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
1249 | | - } |
---|
| 1623 | + switch (pll->type) { |
---|
| 1624 | + case pll_rk3036: |
---|
| 1625 | + case pll_rk3328: |
---|
| 1626 | + case pll_rk3066: |
---|
| 1627 | + case pll_rk3399: |
---|
| 1628 | + /* |
---|
| 1629 | + * delta frac frac ppm |
---|
| 1630 | + * -------------- = (fbdiv + ----------) * --------- |
---|
| 1631 | + * 1 << 24 1 << 24 1000000 |
---|
| 1632 | + * |
---|
| 1633 | + */ |
---|
| 1634 | + if (!frac) { |
---|
| 1635 | + frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask; |
---|
| 1636 | + fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
| 1637 | + } |
---|
| 1638 | + m = div64_u64((uint64_t)frac * ppm, 1000000); |
---|
| 1639 | + n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv; |
---|
1250 | 1640 | |
---|
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; |
---|
| 1641 | + fracdiv = negative ? frac - (m + n) : frac + (m + n); |
---|
1259 | 1642 | |
---|
1260 | | - fracdiv = negative ? frac - (m + n) : frac + (m + n); |
---|
| 1643 | + if (!frac || fracdiv > frac_mask) |
---|
| 1644 | + return -EINVAL; |
---|
1261 | 1645 | |
---|
1262 | | - if (!frac || fracdiv > frac_mask) |
---|
| 1646 | + pllcon = readl_relaxed(pll->reg_base + pllcon2); |
---|
| 1647 | + pllcon &= ~(frac_mask << frac_shift); |
---|
| 1648 | + pllcon |= fracdiv << frac_shift; |
---|
| 1649 | + writel_relaxed(pllcon, pll->reg_base + pllcon2); |
---|
| 1650 | + break; |
---|
| 1651 | + case pll_rk3588: |
---|
| 1652 | + if (!fbdiv) { |
---|
| 1653 | + frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask; |
---|
| 1654 | + fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
| 1655 | + } |
---|
| 1656 | + if (!frac) { |
---|
| 1657 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1658 | + s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) |
---|
| 1659 | + & RK3588_PLLCON1_S_MASK); |
---|
| 1660 | + p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) |
---|
| 1661 | + & RK3588_PLLCON1_P_MASK); |
---|
| 1662 | + m = div64_u64((uint64_t)clk_get_rate(clk) * ppm, 24000000); |
---|
| 1663 | + n = div64_u64((uint64_t)m * 65536 * p * (1 << s), 1000000); |
---|
| 1664 | + |
---|
| 1665 | + if (n > 32767) |
---|
| 1666 | + return -EINVAL; |
---|
| 1667 | + fracdiv = negative ? ~n + 1 : n; |
---|
| 1668 | + } else if (frac & BIT(15)) { |
---|
| 1669 | + frac = (~(frac - 1)) & RK3588_PLLCON2_K_MASK; |
---|
| 1670 | + m = div64_u64((uint64_t)frac * ppm, 100000); |
---|
| 1671 | + n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000); |
---|
| 1672 | + if (negative) { |
---|
| 1673 | + fracdiv = frac + (div64_u64(m + n, 10)); |
---|
| 1674 | + if (fracdiv > 32767) |
---|
| 1675 | + return -EINVAL; |
---|
| 1676 | + fracdiv = ~fracdiv + 1; |
---|
| 1677 | + } else { |
---|
| 1678 | + s = div64_u64(m + n, 10); |
---|
| 1679 | + if (frac >= s) { |
---|
| 1680 | + fracdiv = frac - s; |
---|
| 1681 | + if (fracdiv > 32767) |
---|
| 1682 | + return -EINVAL; |
---|
| 1683 | + fracdiv = ~fracdiv + 1; |
---|
| 1684 | + } else { |
---|
| 1685 | + fracdiv = s - frac; |
---|
| 1686 | + if (fracdiv > 32767) |
---|
| 1687 | + return -EINVAL; |
---|
| 1688 | + } |
---|
| 1689 | + } |
---|
| 1690 | + } else { |
---|
| 1691 | + m = div64_u64((uint64_t)frac * ppm, 100000); |
---|
| 1692 | + n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000); |
---|
| 1693 | + if (!negative) { |
---|
| 1694 | + fracdiv = frac + (div64_u64(m + n, 10)); |
---|
| 1695 | + if (fracdiv > 32767) |
---|
| 1696 | + return -EINVAL; |
---|
| 1697 | + } else { |
---|
| 1698 | + s = div64_u64(m + n, 10); |
---|
| 1699 | + if (frac >= s) { |
---|
| 1700 | + fracdiv = frac - s; |
---|
| 1701 | + if (fracdiv > 32767) |
---|
| 1702 | + return -EINVAL; |
---|
| 1703 | + } else { |
---|
| 1704 | + fracdiv = s - frac; |
---|
| 1705 | + if (fracdiv > 32767) |
---|
| 1706 | + return -EINVAL; |
---|
| 1707 | + fracdiv = ~fracdiv + 1; |
---|
| 1708 | + } |
---|
| 1709 | + } |
---|
| 1710 | + } |
---|
| 1711 | + |
---|
| 1712 | + writel_relaxed(HIWORD_UPDATE(fracdiv, frac_mask, frac_shift), |
---|
| 1713 | + pll->reg_base + pllcon2); |
---|
| 1714 | + break; |
---|
| 1715 | + default: |
---|
1263 | 1716 | 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); |
---|
| 1717 | + } |
---|
1269 | 1718 | |
---|
1270 | 1719 | return 0; |
---|
1271 | 1720 | } |
---|
.. | .. |
---|
1285 | 1734 | unsigned long flags, u8 clk_pll_flags) |
---|
1286 | 1735 | { |
---|
1287 | 1736 | const char *pll_parents[3]; |
---|
1288 | | - struct clk_init_data init = {}; |
---|
| 1737 | + struct clk_init_data init; |
---|
1289 | 1738 | struct rockchip_clk_pll *pll; |
---|
1290 | 1739 | struct clk_mux *pll_mux; |
---|
1291 | 1740 | struct clk *pll_clk, *mux_clk; |
---|
.. | .. |
---|
1316 | 1765 | pll_mux->flags = 0; |
---|
1317 | 1766 | pll_mux->lock = &ctx->lock; |
---|
1318 | 1767 | 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; |
---|
| 1768 | + pll_mux->flags |= CLK_MUX_HIWORD_MASK; |
---|
1325 | 1769 | |
---|
1326 | 1770 | /* the actual muxing is xin24m, pll-output, xin32k */ |
---|
1327 | 1771 | pll_parents[0] = parent_names[0]; |
---|
.. | .. |
---|
1345 | 1789 | init.name = pll_name; |
---|
1346 | 1790 | |
---|
1347 | 1791 | #ifndef CONFIG_ROCKCHIP_LOW_PERFORMANCE |
---|
1348 | | - /* keep all plls untouched for now */ |
---|
1349 | | - init.flags = flags | CLK_IGNORE_UNUSED; |
---|
| 1792 | + if (clk_pll_flags & ROCKCHIP_PLL_ALLOW_POWER_DOWN) |
---|
| 1793 | + init.flags = flags; |
---|
| 1794 | + else |
---|
| 1795 | + /* keep all plls untouched for now */ |
---|
| 1796 | + init.flags = flags | CLK_IGNORE_UNUSED; |
---|
1350 | 1797 | #else |
---|
1351 | 1798 | init.flags = flags; |
---|
1352 | 1799 | #endif |
---|
.. | .. |
---|
1374 | 1821 | switch (pll_type) { |
---|
1375 | 1822 | case pll_rk3036: |
---|
1376 | 1823 | case pll_rk3328: |
---|
1377 | | - if (!pll->rate_table || IS_ERR(ctx->grf)) |
---|
| 1824 | + if (!pll->rate_table) |
---|
1378 | 1825 | init.ops = &rockchip_rk3036_pll_clk_norate_ops; |
---|
1379 | 1826 | else |
---|
1380 | 1827 | init.ops = &rockchip_rk3036_pll_clk_ops; |
---|
.. | .. |
---|
1393 | 1840 | init.ops = &rockchip_rk3399_pll_clk_norate_ops; |
---|
1394 | 1841 | else |
---|
1395 | 1842 | init.ops = &rockchip_rk3399_pll_clk_ops; |
---|
| 1843 | + break; |
---|
| 1844 | +#endif |
---|
| 1845 | +#ifdef CONFIG_ROCKCHIP_PLL_RK3588 |
---|
| 1846 | + case pll_rk3588: |
---|
| 1847 | + case pll_rk3588_core: |
---|
| 1848 | + if (!pll->rate_table) |
---|
| 1849 | + init.ops = &rockchip_rk3588_pll_clk_norate_ops; |
---|
| 1850 | + else |
---|
| 1851 | + init.ops = &rockchip_rk3588_pll_clk_ops; |
---|
| 1852 | + init.flags = flags; |
---|
1396 | 1853 | break; |
---|
1397 | 1854 | #endif |
---|
1398 | 1855 | default: |
---|
.. | .. |
---|
1419 | 1876 | return mux_clk; |
---|
1420 | 1877 | |
---|
1421 | 1878 | err_pll: |
---|
| 1879 | + kfree(pll->rate_table); |
---|
1422 | 1880 | clk_unregister(mux_clk); |
---|
1423 | 1881 | mux_clk = pll_clk; |
---|
1424 | 1882 | err_mux: |
---|
.. | .. |
---|
1619 | 2077 | #ifdef CONFIG_DEBUG_FS |
---|
1620 | 2078 | #include <linux/debugfs.h> |
---|
1621 | 2079 | |
---|
| 2080 | +#ifndef MODULE |
---|
1622 | 2081 | static int boost_summary_show(struct seq_file *s, void *data) |
---|
1623 | 2082 | { |
---|
1624 | 2083 | struct rockchip_clk_pll *pll = (struct rockchip_clk_pll *)s->private; |
---|
.. | .. |
---|
1736 | 2195 | return 0; |
---|
1737 | 2196 | } |
---|
1738 | 2197 | late_initcall(boost_debug_init); |
---|
| 2198 | +#endif /* MODULE */ |
---|
1739 | 2199 | #endif /* CONFIG_DEBUG_FS */ |
---|
1740 | 2200 | #endif /* CONFIG_ROCKCHIP_CLK_BOOST */ |
---|