diff options
author | Peter De Schrijver <pdeschrijver@nvidia.com> | 2013-09-06 07:37:37 -0400 |
---|---|---|
committer | Peter De Schrijver <pdeschrijver@nvidia.com> | 2013-11-26 11:46:21 -0500 |
commit | 04edb099a4a7e774a98b241dc016957922cbfb44 (patch) | |
tree | 02b71767543bb4051a202222055be01556346e0d | |
parent | 5bb9d26700c3db54d5a4346c3b6621b8889f3813 (diff) |
clk: tegra: move some PLLC and PLLXC init to clk-pll.c
VCO min clipping, dynamic ramp setup and IDDQ init can be done in the
respective PLL clk_register functions if the parent is already registered.
This is done for other some PLLs already.
Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
-rw-r--r-- | drivers/clk/tegra/clk-pll.c | 95 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-tegra114.c | 109 |
2 files changed, 111 insertions, 93 deletions
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 25734348242f..8f51147185db 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c | |||
@@ -773,6 +773,48 @@ static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, | |||
773 | return 1; | 773 | return 1; |
774 | } | 774 | } |
775 | 775 | ||
776 | static unsigned long _clip_vco_min(unsigned long vco_min, | ||
777 | unsigned long parent_rate) | ||
778 | { | ||
779 | return DIV_ROUND_UP(vco_min, parent_rate) * parent_rate; | ||
780 | } | ||
781 | |||
782 | static int _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params, | ||
783 | void __iomem *clk_base, | ||
784 | unsigned long parent_rate) | ||
785 | { | ||
786 | u32 val; | ||
787 | u32 step_a, step_b; | ||
788 | |||
789 | switch (parent_rate) { | ||
790 | case 12000000: | ||
791 | case 13000000: | ||
792 | case 26000000: | ||
793 | step_a = 0x2B; | ||
794 | step_b = 0x0B; | ||
795 | break; | ||
796 | case 16800000: | ||
797 | step_a = 0x1A; | ||
798 | step_b = 0x09; | ||
799 | break; | ||
800 | case 19200000: | ||
801 | step_a = 0x12; | ||
802 | step_b = 0x08; | ||
803 | break; | ||
804 | default: | ||
805 | pr_err("%s: Unexpected reference rate %lu\n", | ||
806 | __func__, parent_rate); | ||
807 | WARN_ON(1); | ||
808 | return -EINVAL; | ||
809 | } | ||
810 | |||
811 | val = step_a << pll_params->stepa_shift; | ||
812 | val |= step_b << pll_params->stepb_shift; | ||
813 | writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg); | ||
814 | |||
815 | return 0; | ||
816 | } | ||
817 | |||
776 | static int clk_pll_iddq_enable(struct clk_hw *hw) | 818 | static int clk_pll_iddq_enable(struct clk_hw *hw) |
777 | { | 819 | { |
778 | struct tegra_clk_pll *pll = to_clk_pll(hw); | 820 | struct tegra_clk_pll *pll = to_clk_pll(hw); |
@@ -1423,11 +1465,39 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, | |||
1423 | spinlock_t *lock) | 1465 | spinlock_t *lock) |
1424 | { | 1466 | { |
1425 | struct tegra_clk_pll *pll; | 1467 | struct tegra_clk_pll *pll; |
1426 | struct clk *clk; | 1468 | struct clk *clk, *parent; |
1469 | unsigned long parent_rate; | ||
1470 | int err; | ||
1471 | u32 val, val_iddq; | ||
1472 | |||
1473 | parent = __clk_lookup(parent_name); | ||
1474 | if (IS_ERR(parent)) { | ||
1475 | WARN(1, "parent clk %s of %s must be registered first\n", | ||
1476 | name, parent_name); | ||
1477 | return ERR_PTR(-EINVAL); | ||
1478 | } | ||
1427 | 1479 | ||
1428 | if (!pll_params->pdiv_tohw) | 1480 | if (!pll_params->pdiv_tohw) |
1429 | return ERR_PTR(-EINVAL); | 1481 | return ERR_PTR(-EINVAL); |
1430 | 1482 | ||
1483 | parent_rate = __clk_get_rate(parent); | ||
1484 | |||
1485 | pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); | ||
1486 | |||
1487 | err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate); | ||
1488 | if (err) | ||
1489 | return ERR_PTR(err); | ||
1490 | |||
1491 | val = readl_relaxed(clk_base + pll_params->base_reg); | ||
1492 | val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg); | ||
1493 | |||
1494 | if (val & PLL_BASE_ENABLE) | ||
1495 | WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx)); | ||
1496 | else { | ||
1497 | val_iddq |= BIT(pll_params->iddq_bit_idx); | ||
1498 | writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg); | ||
1499 | } | ||
1500 | |||
1431 | pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; | 1501 | pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; |
1432 | pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, | 1502 | pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, |
1433 | freq_table, lock); | 1503 | freq_table, lock); |
@@ -1455,6 +1525,9 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, | |||
1455 | struct clk *clk; | 1525 | struct clk *clk; |
1456 | 1526 | ||
1457 | pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC; | 1527 | pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC; |
1528 | |||
1529 | pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); | ||
1530 | |||
1458 | pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, | 1531 | pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, |
1459 | freq_table, lock); | 1532 | freq_table, lock); |
1460 | if (IS_ERR(pll)) | 1533 | if (IS_ERR(pll)) |
@@ -1498,11 +1571,23 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, | |||
1498 | spinlock_t *lock) | 1571 | spinlock_t *lock) |
1499 | { | 1572 | { |
1500 | struct tegra_clk_pll *pll; | 1573 | struct tegra_clk_pll *pll; |
1501 | struct clk *clk; | 1574 | struct clk *clk, *parent; |
1575 | unsigned long parent_rate; | ||
1502 | 1576 | ||
1503 | if (!pll_params->pdiv_tohw) | 1577 | if (!pll_params->pdiv_tohw) |
1504 | return ERR_PTR(-EINVAL); | 1578 | return ERR_PTR(-EINVAL); |
1505 | 1579 | ||
1580 | parent = __clk_lookup(parent_name); | ||
1581 | if (IS_ERR(parent)) { | ||
1582 | WARN(1, "parent clk %s of %s must be registered first\n", | ||
1583 | name, parent_name); | ||
1584 | return ERR_PTR(-EINVAL); | ||
1585 | } | ||
1586 | |||
1587 | parent_rate = __clk_get_rate(parent); | ||
1588 | |||
1589 | pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); | ||
1590 | |||
1506 | pll_flags |= TEGRA_PLL_BYPASS; | 1591 | pll_flags |= TEGRA_PLL_BYPASS; |
1507 | pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; | 1592 | pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; |
1508 | pll_flags |= TEGRA_PLLM; | 1593 | pll_flags |= TEGRA_PLLM; |
@@ -1543,14 +1628,16 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, | |||
1543 | return ERR_PTR(-EINVAL); | 1628 | return ERR_PTR(-EINVAL); |
1544 | } | 1629 | } |
1545 | 1630 | ||
1631 | parent_rate = __clk_get_rate(parent); | ||
1632 | |||
1633 | pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); | ||
1634 | |||
1546 | pll_flags |= TEGRA_PLL_BYPASS; | 1635 | pll_flags |= TEGRA_PLL_BYPASS; |
1547 | pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, | 1636 | pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, |
1548 | freq_table, lock); | 1637 | freq_table, lock); |
1549 | if (IS_ERR(pll)) | 1638 | if (IS_ERR(pll)) |
1550 | return ERR_CAST(pll); | 1639 | return ERR_CAST(pll); |
1551 | 1640 | ||
1552 | parent_rate = __clk_get_rate(parent); | ||
1553 | |||
1554 | /* | 1641 | /* |
1555 | * Most of PLLC register fields are shadowed, and can not be read | 1642 | * Most of PLLC register fields are shadowed, and can not be read |
1556 | * directly from PLL h/w. Hence, actual PLLC boot state is unknown. | 1643 | * directly from PLL h/w. Hence, actual PLLC boot state is unknown. |
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 9729af823eaf..fa562e3e8f19 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c | |||
@@ -1077,63 +1077,6 @@ static __init void tegra114_utmi_param_configure(void __iomem *clk_base) | |||
1077 | writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); | 1077 | writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); |
1078 | } | 1078 | } |
1079 | 1079 | ||
1080 | static void __init _clip_vco_min(struct tegra_clk_pll_params *pll_params) | ||
1081 | { | ||
1082 | pll_params->vco_min = | ||
1083 | DIV_ROUND_UP(pll_params->vco_min, pll_ref_freq) * pll_ref_freq; | ||
1084 | } | ||
1085 | |||
1086 | static int __init _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params, | ||
1087 | void __iomem *clk_base) | ||
1088 | { | ||
1089 | u32 val; | ||
1090 | u32 step_a, step_b; | ||
1091 | |||
1092 | switch (pll_ref_freq) { | ||
1093 | case 12000000: | ||
1094 | case 13000000: | ||
1095 | case 26000000: | ||
1096 | step_a = 0x2B; | ||
1097 | step_b = 0x0B; | ||
1098 | break; | ||
1099 | case 16800000: | ||
1100 | step_a = 0x1A; | ||
1101 | step_b = 0x09; | ||
1102 | break; | ||
1103 | case 19200000: | ||
1104 | step_a = 0x12; | ||
1105 | step_b = 0x08; | ||
1106 | break; | ||
1107 | default: | ||
1108 | pr_err("%s: Unexpected reference rate %lu\n", | ||
1109 | __func__, pll_ref_freq); | ||
1110 | WARN_ON(1); | ||
1111 | return -EINVAL; | ||
1112 | } | ||
1113 | |||
1114 | val = step_a << pll_params->stepa_shift; | ||
1115 | val |= step_b << pll_params->stepb_shift; | ||
1116 | writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg); | ||
1117 | |||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | static void __init _init_iddq(struct tegra_clk_pll_params *pll_params, | ||
1122 | void __iomem *clk_base) | ||
1123 | { | ||
1124 | u32 val, val_iddq; | ||
1125 | |||
1126 | val = readl_relaxed(clk_base + pll_params->base_reg); | ||
1127 | val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg); | ||
1128 | |||
1129 | if (val & BIT(30)) | ||
1130 | WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx)); | ||
1131 | else { | ||
1132 | val_iddq |= BIT(pll_params->iddq_bit_idx); | ||
1133 | writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg); | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | static void __init tegra114_pll_init(void __iomem *clk_base, | 1080 | static void __init tegra114_pll_init(void __iomem *clk_base, |
1138 | void __iomem *pmc) | 1081 | void __iomem *pmc) |
1139 | { | 1082 | { |
@@ -1141,28 +1084,23 @@ static void __init tegra114_pll_init(void __iomem *clk_base, | |||
1141 | struct clk *clk; | 1084 | struct clk *clk; |
1142 | 1085 | ||
1143 | /* PLLC */ | 1086 | /* PLLC */ |
1144 | _clip_vco_min(&pll_c_params); | 1087 | clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, |
1145 | if (_setup_dynamic_ramp(&pll_c_params, clk_base) >= 0) { | 1088 | pmc, 0, 0, &pll_c_params, TEGRA_PLL_USE_LOCK, |
1146 | _init_iddq(&pll_c_params, clk_base); | 1089 | pll_c_freq_table, NULL); |
1147 | clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, | 1090 | clk_register_clkdev(clk, "pll_c", NULL); |
1148 | pmc, 0, 0, &pll_c_params, TEGRA_PLL_USE_LOCK, | 1091 | clks[TEGRA114_CLK_PLL_C] = clk; |
1149 | pll_c_freq_table, NULL); | 1092 | |
1150 | clk_register_clkdev(clk, "pll_c", NULL); | 1093 | /* PLLC_OUT1 */ |
1151 | clks[TEGRA114_CLK_PLL_C] = clk; | 1094 | clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", |
1152 | 1095 | clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | |
1153 | /* PLLC_OUT1 */ | 1096 | 8, 8, 1, NULL); |
1154 | clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", | 1097 | clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", |
1155 | clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | 1098 | clk_base + PLLC_OUT, 1, 0, |
1156 | 8, 8, 1, NULL); | 1099 | CLK_SET_RATE_PARENT, 0, NULL); |
1157 | clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", | 1100 | clk_register_clkdev(clk, "pll_c_out1", NULL); |
1158 | clk_base + PLLC_OUT, 1, 0, | 1101 | clks[TEGRA114_CLK_PLL_C_OUT1] = clk; |
1159 | CLK_SET_RATE_PARENT, 0, NULL); | ||
1160 | clk_register_clkdev(clk, "pll_c_out1", NULL); | ||
1161 | clks[TEGRA114_CLK_PLL_C_OUT1] = clk; | ||
1162 | } | ||
1163 | 1102 | ||
1164 | /* PLLC2 */ | 1103 | /* PLLC2 */ |
1165 | _clip_vco_min(&pll_c2_params); | ||
1166 | clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, 0, | 1104 | clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, 0, |
1167 | &pll_c2_params, TEGRA_PLL_USE_LOCK, | 1105 | &pll_c2_params, TEGRA_PLL_USE_LOCK, |
1168 | pll_cx_freq_table, NULL); | 1106 | pll_cx_freq_table, NULL); |
@@ -1170,7 +1108,6 @@ static void __init tegra114_pll_init(void __iomem *clk_base, | |||
1170 | clks[TEGRA114_CLK_PLL_C2] = clk; | 1108 | clks[TEGRA114_CLK_PLL_C2] = clk; |
1171 | 1109 | ||
1172 | /* PLLC3 */ | 1110 | /* PLLC3 */ |
1173 | _clip_vco_min(&pll_c3_params); | ||
1174 | clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, 0, | 1111 | clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, 0, |
1175 | &pll_c3_params, TEGRA_PLL_USE_LOCK, | 1112 | &pll_c3_params, TEGRA_PLL_USE_LOCK, |
1176 | pll_cx_freq_table, NULL); | 1113 | pll_cx_freq_table, NULL); |
@@ -1232,7 +1169,6 @@ static void __init tegra114_pll_init(void __iomem *clk_base, | |||
1232 | clks[TEGRA114_CLK_PLL_P_OUT4] = clk; | 1169 | clks[TEGRA114_CLK_PLL_P_OUT4] = clk; |
1233 | 1170 | ||
1234 | /* PLLM */ | 1171 | /* PLLM */ |
1235 | _clip_vco_min(&pll_m_params); | ||
1236 | clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, | 1172 | clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, |
1237 | CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, | 1173 | CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, |
1238 | &pll_m_params, TEGRA_PLL_USE_LOCK, | 1174 | &pll_m_params, TEGRA_PLL_USE_LOCK, |
@@ -1255,15 +1191,11 @@ static void __init tegra114_pll_init(void __iomem *clk_base, | |||
1255 | CLK_SET_RATE_PARENT, 1, 1); | 1191 | CLK_SET_RATE_PARENT, 1, 1); |
1256 | 1192 | ||
1257 | /* PLLX */ | 1193 | /* PLLX */ |
1258 | _clip_vco_min(&pll_x_params); | 1194 | clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, |
1259 | if (_setup_dynamic_ramp(&pll_x_params, clk_base) >= 0) { | 1195 | pmc, CLK_IGNORE_UNUSED, 0, &pll_x_params, |
1260 | _init_iddq(&pll_x_params, clk_base); | 1196 | TEGRA_PLL_USE_LOCK, pll_x_freq_table, NULL); |
1261 | clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, | 1197 | clk_register_clkdev(clk, "pll_x", NULL); |
1262 | pmc, CLK_IGNORE_UNUSED, 0, &pll_x_params, | 1198 | clks[TEGRA114_CLK_PLL_X] = clk; |
1263 | TEGRA_PLL_USE_LOCK, pll_x_freq_table, NULL); | ||
1264 | clk_register_clkdev(clk, "pll_x", NULL); | ||
1265 | clks[TEGRA114_CLK_PLL_X] = clk; | ||
1266 | } | ||
1267 | 1199 | ||
1268 | /* PLLX_OUT0 */ | 1200 | /* PLLX_OUT0 */ |
1269 | clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", | 1201 | clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", |
@@ -1356,7 +1288,6 @@ static void __init tegra114_pll_init(void __iomem *clk_base, | |||
1356 | clks[TEGRA114_CLK_PLL_A_OUT0] = clk; | 1288 | clks[TEGRA114_CLK_PLL_A_OUT0] = clk; |
1357 | 1289 | ||
1358 | /* PLLRE */ | 1290 | /* PLLRE */ |
1359 | _clip_vco_min(&pll_re_vco_params); | ||
1360 | clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, | 1291 | clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, |
1361 | 0, 0, &pll_re_vco_params, TEGRA_PLL_USE_LOCK, | 1292 | 0, 0, &pll_re_vco_params, TEGRA_PLL_USE_LOCK, |
1362 | NULL, &pll_re_lock, pll_ref_freq); | 1293 | NULL, &pll_re_lock, pll_ref_freq); |