| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 5 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 6 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 11 | | - * more details. |
|---|
| 12 | | - * |
|---|
| 13 | | - * You should have received a copy of the GNU General Public License |
|---|
| 14 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 15 | 4 | */ |
|---|
| 16 | 5 | |
|---|
| 17 | 6 | #include <linux/io.h> |
|---|
| .. | .. |
|---|
| 162 | 151 | |
|---|
| 163 | 152 | static DEFINE_SPINLOCK(cml_lock); |
|---|
| 164 | 153 | static DEFINE_SPINLOCK(pll_d_lock); |
|---|
| 165 | | -static DEFINE_SPINLOCK(emc_lock); |
|---|
| 166 | 154 | |
|---|
| 167 | 155 | #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \ |
|---|
| 168 | 156 | _clk_num, _gate_flags, _clk_id) \ |
|---|
| .. | .. |
|---|
| 511 | 499 | .freq_table = pll_x_freq_table, |
|---|
| 512 | 500 | .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_DCCON | |
|---|
| 513 | 501 | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, |
|---|
| 502 | + .pre_rate_change = tegra_cclk_pre_pllx_rate_change, |
|---|
| 503 | + .post_rate_change = tegra_cclk_post_pllx_rate_change, |
|---|
| 514 | 504 | }; |
|---|
| 515 | 505 | |
|---|
| 516 | 506 | static struct tegra_clk_pll_params pll_e_params __ro_after_init = { |
|---|
| .. | .. |
|---|
| 581 | 571 | { .con_id = "audio3_2x", .dt_id = TEGRA30_CLK_AUDIO3_2X }, |
|---|
| 582 | 572 | { .con_id = "audio4_2x", .dt_id = TEGRA30_CLK_AUDIO4_2X }, |
|---|
| 583 | 573 | { .con_id = "spdif_2x", .dt_id = TEGRA30_CLK_SPDIF_2X }, |
|---|
| 584 | | - { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA30_CLK_EXTERN1 }, |
|---|
| 585 | | - { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA30_CLK_EXTERN2 }, |
|---|
| 586 | | - { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA30_CLK_EXTERN3 }, |
|---|
| 587 | | - { .con_id = "blink", .dt_id = TEGRA30_CLK_BLINK }, |
|---|
| 574 | + { .con_id = "extern1", .dt_id = TEGRA30_CLK_EXTERN1 }, |
|---|
| 575 | + { .con_id = "extern2", .dt_id = TEGRA30_CLK_EXTERN2 }, |
|---|
| 576 | + { .con_id = "extern3", .dt_id = TEGRA30_CLK_EXTERN3 }, |
|---|
| 588 | 577 | { .con_id = "cclk_g", .dt_id = TEGRA30_CLK_CCLK_G }, |
|---|
| 589 | 578 | { .con_id = "cclk_lp", .dt_id = TEGRA30_CLK_CCLK_LP }, |
|---|
| 590 | 579 | { .con_id = "sclk", .dt_id = TEGRA30_CLK_SCLK }, |
|---|
| .. | .. |
|---|
| 593 | 582 | { .con_id = "twd", .dt_id = TEGRA30_CLK_TWD }, |
|---|
| 594 | 583 | { .con_id = "emc", .dt_id = TEGRA30_CLK_EMC }, |
|---|
| 595 | 584 | { .con_id = "clk_32k", .dt_id = TEGRA30_CLK_CLK_32K }, |
|---|
| 596 | | - { .con_id = "clk_m_div2", .dt_id = TEGRA30_CLK_CLK_M_DIV2 }, |
|---|
| 597 | | - { .con_id = "clk_m_div4", .dt_id = TEGRA30_CLK_CLK_M_DIV4 }, |
|---|
| 585 | + { .con_id = "osc", .dt_id = TEGRA30_CLK_OSC }, |
|---|
| 586 | + { .con_id = "osc_div2", .dt_id = TEGRA30_CLK_OSC_DIV2 }, |
|---|
| 587 | + { .con_id = "osc_div4", .dt_id = TEGRA30_CLK_OSC_DIV4 }, |
|---|
| 598 | 588 | { .con_id = "cml0", .dt_id = TEGRA30_CLK_CML0 }, |
|---|
| 599 | 589 | { .con_id = "cml1", .dt_id = TEGRA30_CLK_CML1 }, |
|---|
| 600 | 590 | { .con_id = "clk_m", .dt_id = TEGRA30_CLK_CLK_M }, |
|---|
| .. | .. |
|---|
| 695 | 685 | static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { |
|---|
| 696 | 686 | [tegra_clk_clk_32k] = { .dt_id = TEGRA30_CLK_CLK_32K, .present = true }, |
|---|
| 697 | 687 | [tegra_clk_clk_m] = { .dt_id = TEGRA30_CLK_CLK_M, .present = true }, |
|---|
| 698 | | - [tegra_clk_clk_m_div2] = { .dt_id = TEGRA30_CLK_CLK_M_DIV2, .present = true }, |
|---|
| 699 | | - [tegra_clk_clk_m_div4] = { .dt_id = TEGRA30_CLK_CLK_M_DIV4, .present = true }, |
|---|
| 688 | + [tegra_clk_osc] = { .dt_id = TEGRA30_CLK_OSC, .present = true }, |
|---|
| 689 | + [tegra_clk_osc_div2] = { .dt_id = TEGRA30_CLK_OSC_DIV2, .present = true }, |
|---|
| 690 | + [tegra_clk_osc_div4] = { .dt_id = TEGRA30_CLK_OSC_DIV4, .present = true }, |
|---|
| 700 | 691 | [tegra_clk_pll_ref] = { .dt_id = TEGRA30_CLK_PLL_REF, .present = true }, |
|---|
| 701 | 692 | [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA30_CLK_SPDIF_IN_SYNC, .present = true }, |
|---|
| 702 | 693 | [tegra_clk_i2s0_sync] = { .dt_id = TEGRA30_CLK_I2S0_SYNC, .present = true }, |
|---|
| .. | .. |
|---|
| 723 | 714 | [tegra_clk_audio3_2x] = { .dt_id = TEGRA30_CLK_AUDIO3_2X, .present = true }, |
|---|
| 724 | 715 | [tegra_clk_audio4_2x] = { .dt_id = TEGRA30_CLK_AUDIO4_2X, .present = true }, |
|---|
| 725 | 716 | [tegra_clk_spdif_2x] = { .dt_id = TEGRA30_CLK_SPDIF_2X, .present = true }, |
|---|
| 726 | | - [tegra_clk_clk_out_1] = { .dt_id = TEGRA30_CLK_CLK_OUT_1, .present = true }, |
|---|
| 727 | | - [tegra_clk_clk_out_2] = { .dt_id = TEGRA30_CLK_CLK_OUT_2, .present = true }, |
|---|
| 728 | | - [tegra_clk_clk_out_3] = { .dt_id = TEGRA30_CLK_CLK_OUT_3, .present = true }, |
|---|
| 729 | | - [tegra_clk_blink] = { .dt_id = TEGRA30_CLK_BLINK, .present = true }, |
|---|
| 730 | | - [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_1_MUX, .present = true }, |
|---|
| 731 | | - [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_2_MUX, .present = true }, |
|---|
| 732 | | - [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_3_MUX, .present = true }, |
|---|
| 733 | 717 | [tegra_clk_hclk] = { .dt_id = TEGRA30_CLK_HCLK, .present = true }, |
|---|
| 734 | 718 | [tegra_clk_pclk] = { .dt_id = TEGRA30_CLK_PCLK, .present = true }, |
|---|
| 735 | 719 | [tegra_clk_i2s0] = { .dt_id = TEGRA30_CLK_I2S0, .present = true }, |
|---|
| .. | .. |
|---|
| 819 | 803 | [tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true }, |
|---|
| 820 | 804 | [tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true }, |
|---|
| 821 | 805 | [tegra_clk_cec] = { .dt_id = TEGRA30_CLK_CEC, .present = true }, |
|---|
| 822 | | - [tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = true }, |
|---|
| 806 | + [tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = false }, |
|---|
| 823 | 807 | }; |
|---|
| 824 | 808 | |
|---|
| 825 | 809 | static const char *pll_e_parents[] = { "pll_ref", "pll_p" }; |
|---|
| .. | .. |
|---|
| 944 | 928 | clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL); |
|---|
| 945 | 929 | |
|---|
| 946 | 930 | /* CCLKG */ |
|---|
| 947 | | - clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, |
|---|
| 931 | + clk = tegra_clk_register_super_cclk("cclk_g", cclk_g_parents, |
|---|
| 948 | 932 | ARRAY_SIZE(cclk_g_parents), |
|---|
| 949 | 933 | CLK_SET_RATE_PARENT, |
|---|
| 950 | 934 | clk_base + CCLKG_BURST_POLICY, |
|---|
| 951 | | - 0, 4, 0, 0, NULL); |
|---|
| 935 | + 0, NULL); |
|---|
| 952 | 936 | clks[TEGRA30_CLK_CCLK_G] = clk; |
|---|
| 953 | 937 | |
|---|
| 954 | 938 | /* |
|---|
| .. | .. |
|---|
| 1006 | 990 | static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p", |
|---|
| 1007 | 991 | "clk_m" }; |
|---|
| 1008 | 992 | static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" }; |
|---|
| 1009 | | -static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" }; |
|---|
| 1010 | 993 | static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p", |
|---|
| 1011 | 994 | "clk_m" }; |
|---|
| 1012 | 995 | static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" }; |
|---|
| .. | .. |
|---|
| 1055 | 1038 | clks[TEGRA30_CLK_AFI] = clk; |
|---|
| 1056 | 1039 | |
|---|
| 1057 | 1040 | /* emc */ |
|---|
| 1058 | | - clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, |
|---|
| 1059 | | - ARRAY_SIZE(mux_pllmcp_clkm), |
|---|
| 1060 | | - CLK_SET_RATE_NO_REPARENT, |
|---|
| 1061 | | - clk_base + CLK_SOURCE_EMC, |
|---|
| 1062 | | - 30, 2, 0, &emc_lock); |
|---|
| 1041 | + clk = tegra20_clk_register_emc(clk_base + CLK_SOURCE_EMC, true); |
|---|
| 1063 | 1042 | |
|---|
| 1064 | | - clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, |
|---|
| 1065 | | - &emc_lock); |
|---|
| 1043 | + clks[TEGRA30_CLK_EMC] = clk; |
|---|
| 1044 | + |
|---|
| 1045 | + clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC, |
|---|
| 1046 | + NULL); |
|---|
| 1066 | 1047 | clks[TEGRA30_CLK_MC] = clk; |
|---|
| 1067 | 1048 | |
|---|
| 1068 | 1049 | /* cml0 */ |
|---|
| .. | .. |
|---|
| 1148 | 1129 | |
|---|
| 1149 | 1130 | cpu_rst_status = readl(clk_base + |
|---|
| 1150 | 1131 | TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); |
|---|
| 1151 | | - cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || |
|---|
| 1152 | | - tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || |
|---|
| 1153 | | - tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); |
|---|
| 1132 | + cpu_pwr_status = tegra_pmc_cpu_is_powered(1) || |
|---|
| 1133 | + tegra_pmc_cpu_is_powered(2) || |
|---|
| 1134 | + tegra_pmc_cpu_is_powered(3); |
|---|
| 1154 | 1135 | |
|---|
| 1155 | 1136 | if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) |
|---|
| 1156 | 1137 | return false; |
|---|
| .. | .. |
|---|
| 1178 | 1159 | static void tegra30_cpu_clock_resume(void) |
|---|
| 1179 | 1160 | { |
|---|
| 1180 | 1161 | unsigned int reg, policy; |
|---|
| 1162 | + u32 misc, base; |
|---|
| 1181 | 1163 | |
|---|
| 1182 | 1164 | /* Is CPU complex already running on PLLX? */ |
|---|
| 1183 | 1165 | reg = readl(clk_base + CLK_RESET_CCLK_BURST); |
|---|
| .. | .. |
|---|
| 1191 | 1173 | BUG(); |
|---|
| 1192 | 1174 | |
|---|
| 1193 | 1175 | if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { |
|---|
| 1194 | | - /* restore PLLX settings if CPU is on different PLL */ |
|---|
| 1195 | | - writel(tegra30_cpu_clk_sctx.pllx_misc, |
|---|
| 1196 | | - clk_base + CLK_RESET_PLLX_MISC); |
|---|
| 1197 | | - writel(tegra30_cpu_clk_sctx.pllx_base, |
|---|
| 1198 | | - clk_base + CLK_RESET_PLLX_BASE); |
|---|
| 1176 | + misc = readl_relaxed(clk_base + CLK_RESET_PLLX_MISC); |
|---|
| 1177 | + base = readl_relaxed(clk_base + CLK_RESET_PLLX_BASE); |
|---|
| 1199 | 1178 | |
|---|
| 1200 | | - /* wait for PLL stabilization if PLLX was enabled */ |
|---|
| 1201 | | - if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) |
|---|
| 1202 | | - udelay(300); |
|---|
| 1179 | + if (misc != tegra30_cpu_clk_sctx.pllx_misc || |
|---|
| 1180 | + base != tegra30_cpu_clk_sctx.pllx_base) { |
|---|
| 1181 | + /* restore PLLX settings if CPU is on different PLL */ |
|---|
| 1182 | + writel(tegra30_cpu_clk_sctx.pllx_misc, |
|---|
| 1183 | + clk_base + CLK_RESET_PLLX_MISC); |
|---|
| 1184 | + writel(tegra30_cpu_clk_sctx.pllx_base, |
|---|
| 1185 | + clk_base + CLK_RESET_PLLX_BASE); |
|---|
| 1186 | + |
|---|
| 1187 | + /* wait for PLL stabilization if PLLX was enabled */ |
|---|
| 1188 | + if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) |
|---|
| 1189 | + udelay(300); |
|---|
| 1190 | + } |
|---|
| 1203 | 1191 | } |
|---|
| 1204 | 1192 | |
|---|
| 1205 | 1193 | /* |
|---|
| .. | .. |
|---|
| 1235 | 1223 | { TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0 }, |
|---|
| 1236 | 1224 | { TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0 }, |
|---|
| 1237 | 1225 | { TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0 }, |
|---|
| 1238 | | - { TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1 }, |
|---|
| 1239 | | - { TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1 }, |
|---|
| 1240 | | - { TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1 }, |
|---|
| 1241 | | - { TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0 }, |
|---|
| 1242 | | - { TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1 }, |
|---|
| 1243 | | - { TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1 }, |
|---|
| 1226 | + { TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 0 }, |
|---|
| 1227 | + { TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 0 }, |
|---|
| 1244 | 1228 | { TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, |
|---|
| 1245 | 1229 | { TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, |
|---|
| 1246 | 1230 | { TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0 }, |
|---|
| .. | .. |
|---|
| 1259 | 1243 | { TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0 }, |
|---|
| 1260 | 1244 | { TEGRA30_CLK_PLL_C, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, |
|---|
| 1261 | 1245 | { TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0 }, |
|---|
| 1262 | | - { TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0 }, |
|---|
| 1263 | | - { TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0 }, |
|---|
| 1264 | 1246 | { TEGRA30_CLK_TWD, TEGRA30_CLK_CLK_MAX, 0, 1 }, |
|---|
| 1265 | 1247 | { TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1266 | 1248 | { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1267 | 1249 | { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1268 | 1250 | { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, |
|---|
| 1269 | | - { TEGRA30_CLK_VDE, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, |
|---|
| 1251 | + { TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1270 | 1252 | { TEGRA30_CLK_SPDIF_IN_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 }, |
|---|
| 1271 | 1253 | { TEGRA30_CLK_I2S0_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 }, |
|---|
| 1272 | 1254 | { TEGRA30_CLK_I2S1_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 }, |
|---|
| .. | .. |
|---|
| 1315 | 1297 | { "pll_a", &pll_a_params, tegra_clk_pll_a, "pll_p_out1" }, |
|---|
| 1316 | 1298 | }; |
|---|
| 1317 | 1299 | |
|---|
| 1300 | +static struct clk *tegra30_clk_src_onecell_get(struct of_phandle_args *clkspec, |
|---|
| 1301 | + void *data) |
|---|
| 1302 | +{ |
|---|
| 1303 | + struct clk_hw *hw; |
|---|
| 1304 | + struct clk *clk; |
|---|
| 1305 | + |
|---|
| 1306 | + clk = of_clk_src_onecell_get(clkspec, data); |
|---|
| 1307 | + if (IS_ERR(clk)) |
|---|
| 1308 | + return clk; |
|---|
| 1309 | + |
|---|
| 1310 | + hw = __clk_get_hw(clk); |
|---|
| 1311 | + |
|---|
| 1312 | + if (clkspec->args[0] == TEGRA30_CLK_EMC) { |
|---|
| 1313 | + if (!tegra20_clk_emc_driver_available(hw)) |
|---|
| 1314 | + return ERR_PTR(-EPROBE_DEFER); |
|---|
| 1315 | + } |
|---|
| 1316 | + |
|---|
| 1317 | + return clk; |
|---|
| 1318 | +} |
|---|
| 1319 | + |
|---|
| 1318 | 1320 | static void __init tegra30_clock_init(struct device_node *np) |
|---|
| 1319 | 1321 | { |
|---|
| 1320 | 1322 | struct device_node *node; |
|---|
| .. | .. |
|---|
| 1354 | 1356 | tegra_audio_clk_init(clk_base, pmc_base, tegra30_clks, |
|---|
| 1355 | 1357 | tegra30_audio_plls, |
|---|
| 1356 | 1358 | ARRAY_SIZE(tegra30_audio_plls), 24000000); |
|---|
| 1357 | | - tegra_pmc_clk_init(pmc_base, tegra30_clks); |
|---|
| 1358 | 1359 | |
|---|
| 1359 | 1360 | tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX); |
|---|
| 1360 | 1361 | |
|---|
| 1361 | | - tegra_add_of_provider(np, of_clk_src_onecell_get); |
|---|
| 1362 | + tegra_add_of_provider(np, tegra30_clk_src_onecell_get); |
|---|
| 1362 | 1363 | tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); |
|---|
| 1363 | 1364 | |
|---|
| 1364 | 1365 | tegra_clk_apply_init_table = tegra30_clock_apply_init_table; |
|---|