| .. | .. |
|---|
| 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> |
|---|
| .. | .. |
|---|
| 29 | 18 | #define MISC_CLK_ENB 0x48 |
|---|
| 30 | 19 | |
|---|
| 31 | 20 | #define OSC_CTRL 0x50 |
|---|
| 32 | | -#define OSC_CTRL_OSC_FREQ_MASK (3<<30) |
|---|
| 33 | | -#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) |
|---|
| 34 | | -#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) |
|---|
| 35 | | -#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) |
|---|
| 36 | | -#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) |
|---|
| 37 | | -#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) |
|---|
| 21 | +#define OSC_CTRL_OSC_FREQ_MASK (3u<<30) |
|---|
| 22 | +#define OSC_CTRL_OSC_FREQ_13MHZ (0u<<30) |
|---|
| 23 | +#define OSC_CTRL_OSC_FREQ_19_2MHZ (1u<<30) |
|---|
| 24 | +#define OSC_CTRL_OSC_FREQ_12MHZ (2u<<30) |
|---|
| 25 | +#define OSC_CTRL_OSC_FREQ_26MHZ (3u<<30) |
|---|
| 26 | +#define OSC_CTRL_MASK (0x3f2u | OSC_CTRL_OSC_FREQ_MASK) |
|---|
| 38 | 27 | |
|---|
| 39 | | -#define OSC_CTRL_PLL_REF_DIV_MASK (3<<28) |
|---|
| 40 | | -#define OSC_CTRL_PLL_REF_DIV_1 (0<<28) |
|---|
| 41 | | -#define OSC_CTRL_PLL_REF_DIV_2 (1<<28) |
|---|
| 42 | | -#define OSC_CTRL_PLL_REF_DIV_4 (2<<28) |
|---|
| 28 | +#define OSC_CTRL_PLL_REF_DIV_MASK (3u<<28) |
|---|
| 29 | +#define OSC_CTRL_PLL_REF_DIV_1 (0u<<28) |
|---|
| 30 | +#define OSC_CTRL_PLL_REF_DIV_2 (1u<<28) |
|---|
| 31 | +#define OSC_CTRL_PLL_REF_DIV_4 (2u<<28) |
|---|
| 43 | 32 | |
|---|
| 44 | 33 | #define OSC_FREQ_DET 0x58 |
|---|
| 45 | | -#define OSC_FREQ_DET_TRIG (1<<31) |
|---|
| 34 | +#define OSC_FREQ_DET_TRIG (1u<<31) |
|---|
| 46 | 35 | |
|---|
| 47 | 36 | #define OSC_FREQ_DET_STATUS 0x5c |
|---|
| 48 | | -#define OSC_FREQ_DET_BUSY (1<<31) |
|---|
| 49 | | -#define OSC_FREQ_DET_CNT_MASK 0xFFFF |
|---|
| 37 | +#define OSC_FREQ_DET_BUSYu (1<<31) |
|---|
| 38 | +#define OSC_FREQ_DET_CNT_MASK 0xFFFFu |
|---|
| 50 | 39 | |
|---|
| 51 | 40 | #define TEGRA20_CLK_PERIPH_BANKS 3 |
|---|
| 52 | 41 | |
|---|
| .. | .. |
|---|
| 140 | 129 | |
|---|
| 141 | 130 | static void __iomem *clk_base; |
|---|
| 142 | 131 | static void __iomem *pmc_base; |
|---|
| 143 | | - |
|---|
| 144 | | -static DEFINE_SPINLOCK(emc_lock); |
|---|
| 145 | 132 | |
|---|
| 146 | 133 | #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \ |
|---|
| 147 | 134 | _clk_num, _gate_flags, _clk_id) \ |
|---|
| .. | .. |
|---|
| 404 | 391 | .lock_delay = 300, |
|---|
| 405 | 392 | .freq_table = pll_x_freq_table, |
|---|
| 406 | 393 | .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE, |
|---|
| 394 | + .pre_rate_change = tegra_cclk_pre_pllx_rate_change, |
|---|
| 395 | + .post_rate_change = tegra_cclk_post_pllx_rate_change, |
|---|
| 407 | 396 | }; |
|---|
| 408 | 397 | |
|---|
| 409 | 398 | static struct tegra_clk_pll_params pll_e_params = { |
|---|
| .. | .. |
|---|
| 471 | 460 | { .con_id = "cdev1", .dt_id = TEGRA20_CLK_CDEV1 }, |
|---|
| 472 | 461 | { .con_id = "cdev2", .dt_id = TEGRA20_CLK_CDEV2 }, |
|---|
| 473 | 462 | { .con_id = "clk_32k", .dt_id = TEGRA20_CLK_CLK_32K }, |
|---|
| 474 | | - { .con_id = "blink", .dt_id = TEGRA20_CLK_BLINK }, |
|---|
| 475 | 463 | { .con_id = "clk_m", .dt_id = TEGRA20_CLK_CLK_M }, |
|---|
| 476 | 464 | { .con_id = "pll_ref", .dt_id = TEGRA20_CLK_PLL_REF }, |
|---|
| 477 | 465 | { .dev_id = "tegra20-i2s.0", .dt_id = TEGRA20_CLK_I2S1 }, |
|---|
| .. | .. |
|---|
| 550 | 538 | [tegra_clk_csi] = { .dt_id = TEGRA20_CLK_CSI, .present = true }, |
|---|
| 551 | 539 | [tegra_clk_isp] = { .dt_id = TEGRA20_CLK_ISP, .present = true }, |
|---|
| 552 | 540 | [tegra_clk_clk_32k] = { .dt_id = TEGRA20_CLK_CLK_32K, .present = true }, |
|---|
| 553 | | - [tegra_clk_blink] = { .dt_id = TEGRA20_CLK_BLINK, .present = true }, |
|---|
| 554 | 541 | [tegra_clk_hclk] = { .dt_id = TEGRA20_CLK_HCLK, .present = true }, |
|---|
| 555 | 542 | [tegra_clk_pclk] = { .dt_id = TEGRA20_CLK_PCLK, .present = true }, |
|---|
| 556 | 543 | [tegra_clk_pll_p_out1] = { .dt_id = TEGRA20_CLK_PLL_P_OUT1, .present = true }, |
|---|
| .. | .. |
|---|
| 717 | 704 | struct clk *clk; |
|---|
| 718 | 705 | |
|---|
| 719 | 706 | /* CCLK */ |
|---|
| 720 | | - clk = tegra_clk_register_super_mux("cclk", cclk_parents, |
|---|
| 707 | + clk = tegra_clk_register_super_cclk("cclk", cclk_parents, |
|---|
| 721 | 708 | ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT, |
|---|
| 722 | | - clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL); |
|---|
| 709 | + clk_base + CCLK_BURST_POLICY, TEGRA20_SUPER_CLK, |
|---|
| 710 | + NULL); |
|---|
| 723 | 711 | clks[TEGRA20_CLK_CCLK] = clk; |
|---|
| 724 | 712 | |
|---|
| 725 | 713 | /* SCLK */ |
|---|
| .. | .. |
|---|
| 771 | 759 | static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" }; |
|---|
| 772 | 760 | static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c", |
|---|
| 773 | 761 | "clk_m" }; |
|---|
| 774 | | -static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" }; |
|---|
| 775 | 762 | |
|---|
| 776 | 763 | static struct tegra_periph_init_data tegra_periph_clk_list[] = { |
|---|
| 777 | 764 | TEGRA_INIT_DATA_MUX("i2s1", i2s1_parents, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S1), |
|---|
| .. | .. |
|---|
| 798 | 785 | TEGRA_INIT_DATA_NODIV("disp2", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, 0, TEGRA20_CLK_DISP2), |
|---|
| 799 | 786 | }; |
|---|
| 800 | 787 | |
|---|
| 801 | | -static void __init tegra20_emc_clk_init(void) |
|---|
| 802 | | -{ |
|---|
| 803 | | - struct clk *clk; |
|---|
| 804 | | - |
|---|
| 805 | | - clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, |
|---|
| 806 | | - ARRAY_SIZE(mux_pllmcp_clkm), |
|---|
| 807 | | - CLK_SET_RATE_NO_REPARENT, |
|---|
| 808 | | - clk_base + CLK_SOURCE_EMC, |
|---|
| 809 | | - 30, 2, 0, &emc_lock); |
|---|
| 810 | | - |
|---|
| 811 | | - clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, |
|---|
| 812 | | - &emc_lock); |
|---|
| 813 | | - clks[TEGRA20_CLK_MC] = clk; |
|---|
| 814 | | - |
|---|
| 815 | | - /* |
|---|
| 816 | | - * Note that 'emc_mux' source and 'emc' rate shouldn't be changed at |
|---|
| 817 | | - * the same time due to a HW bug, this won't happen because we're |
|---|
| 818 | | - * defining 'emc_mux' and 'emc' as distinct clocks. |
|---|
| 819 | | - */ |
|---|
| 820 | | - clk = tegra_clk_register_divider("emc", "emc_mux", |
|---|
| 821 | | - clk_base + CLK_SOURCE_EMC, CLK_IS_CRITICAL, |
|---|
| 822 | | - TEGRA_DIVIDER_INT, 0, 8, 1, &emc_lock); |
|---|
| 823 | | - clks[TEGRA20_CLK_EMC] = clk; |
|---|
| 824 | | -} |
|---|
| 825 | | - |
|---|
| 826 | 788 | static void __init tegra20_periph_clk_init(void) |
|---|
| 827 | 789 | { |
|---|
| 828 | 790 | struct tegra_periph_init_data *data; |
|---|
| .. | .. |
|---|
| 836 | 798 | clks[TEGRA20_CLK_AC97] = clk; |
|---|
| 837 | 799 | |
|---|
| 838 | 800 | /* emc */ |
|---|
| 839 | | - tegra20_emc_clk_init(); |
|---|
| 801 | + clk = tegra20_clk_register_emc(clk_base + CLK_SOURCE_EMC, false); |
|---|
| 802 | + |
|---|
| 803 | + clks[TEGRA20_CLK_EMC] = clk; |
|---|
| 804 | + |
|---|
| 805 | + clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC, |
|---|
| 806 | + NULL); |
|---|
| 807 | + clks[TEGRA20_CLK_MC] = clk; |
|---|
| 840 | 808 | |
|---|
| 841 | 809 | /* dsi */ |
|---|
| 842 | 810 | clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, |
|---|
| .. | .. |
|---|
| 988 | 956 | static void tegra20_cpu_clock_resume(void) |
|---|
| 989 | 957 | { |
|---|
| 990 | 958 | unsigned int reg, policy; |
|---|
| 959 | + u32 misc, base; |
|---|
| 991 | 960 | |
|---|
| 992 | 961 | /* Is CPU complex already running on PLLX? */ |
|---|
| 993 | 962 | reg = readl(clk_base + CCLK_BURST_POLICY); |
|---|
| .. | .. |
|---|
| 1001 | 970 | BUG(); |
|---|
| 1002 | 971 | |
|---|
| 1003 | 972 | if (reg != CCLK_BURST_POLICY_PLLX) { |
|---|
| 1004 | | - /* restore PLLX settings if CPU is on different PLL */ |
|---|
| 1005 | | - writel(tegra20_cpu_clk_sctx.pllx_misc, |
|---|
| 1006 | | - clk_base + PLLX_MISC); |
|---|
| 1007 | | - writel(tegra20_cpu_clk_sctx.pllx_base, |
|---|
| 1008 | | - clk_base + PLLX_BASE); |
|---|
| 973 | + misc = readl_relaxed(clk_base + PLLX_MISC); |
|---|
| 974 | + base = readl_relaxed(clk_base + PLLX_BASE); |
|---|
| 1009 | 975 | |
|---|
| 1010 | | - /* wait for PLL stabilization if PLLX was enabled */ |
|---|
| 1011 | | - if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30)) |
|---|
| 1012 | | - udelay(300); |
|---|
| 976 | + if (misc != tegra20_cpu_clk_sctx.pllx_misc || |
|---|
| 977 | + base != tegra20_cpu_clk_sctx.pllx_base) { |
|---|
| 978 | + /* restore PLLX settings if CPU is on different PLL */ |
|---|
| 979 | + writel(tegra20_cpu_clk_sctx.pllx_misc, |
|---|
| 980 | + clk_base + PLLX_MISC); |
|---|
| 981 | + writel(tegra20_cpu_clk_sctx.pllx_base, |
|---|
| 982 | + clk_base + PLLX_BASE); |
|---|
| 983 | + |
|---|
| 984 | + /* wait for PLL stabilization if PLLX was enabled */ |
|---|
| 985 | + if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30)) |
|---|
| 986 | + udelay(300); |
|---|
| 987 | + } |
|---|
| 1013 | 988 | } |
|---|
| 1014 | 989 | |
|---|
| 1015 | 990 | /* |
|---|
| .. | .. |
|---|
| 1057 | 1032 | { TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0 }, |
|---|
| 1058 | 1033 | { TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0 }, |
|---|
| 1059 | 1034 | { TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0 }, |
|---|
| 1060 | | - { TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 }, |
|---|
| 1061 | | - { TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 }, |
|---|
| 1062 | | - { TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 }, |
|---|
| 1063 | | - { TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1 }, |
|---|
| 1035 | + { TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 0 }, |
|---|
| 1036 | + { TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 0 }, |
|---|
| 1064 | 1037 | { TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 }, |
|---|
| 1065 | 1038 | { TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 }, |
|---|
| 1066 | 1039 | { TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 }, |
|---|
| .. | .. |
|---|
| 1072 | 1045 | { TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0 }, |
|---|
| 1073 | 1046 | { TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0 }, |
|---|
| 1074 | 1047 | { TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0 }, |
|---|
| 1075 | | - { TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0 }, |
|---|
| 1076 | | - { TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 }, |
|---|
| 1077 | 1048 | { TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1078 | 1049 | { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1079 | | - { TEGRA20_CLK_VDE, TEGRA20_CLK_CLK_MAX, 300000000, 0 }, |
|---|
| 1050 | + { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 }, |
|---|
| 1080 | 1051 | /* must be the last entry */ |
|---|
| 1081 | 1052 | { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 }, |
|---|
| 1082 | 1053 | }; |
|---|
| .. | .. |
|---|
| 1116 | 1087 | if (IS_ERR(clk)) |
|---|
| 1117 | 1088 | return clk; |
|---|
| 1118 | 1089 | |
|---|
| 1090 | + hw = __clk_get_hw(clk); |
|---|
| 1091 | + |
|---|
| 1119 | 1092 | /* |
|---|
| 1120 | 1093 | * Tegra20 CDEV1 and CDEV2 clocks are a bit special case, their parent |
|---|
| 1121 | 1094 | * clock is created by the pinctrl driver. It is possible for clk user |
|---|
| .. | .. |
|---|
| 1125 | 1098 | */ |
|---|
| 1126 | 1099 | if (clkspec->args[0] == TEGRA20_CLK_CDEV1 || |
|---|
| 1127 | 1100 | clkspec->args[0] == TEGRA20_CLK_CDEV2) { |
|---|
| 1128 | | - hw = __clk_get_hw(clk); |
|---|
| 1129 | | - |
|---|
| 1130 | 1101 | parent_hw = clk_hw_get_parent(hw); |
|---|
| 1131 | 1102 | if (!parent_hw) |
|---|
| 1103 | + return ERR_PTR(-EPROBE_DEFER); |
|---|
| 1104 | + } |
|---|
| 1105 | + |
|---|
| 1106 | + if (clkspec->args[0] == TEGRA20_CLK_EMC) { |
|---|
| 1107 | + if (!tegra20_clk_emc_driver_available(hw)) |
|---|
| 1132 | 1108 | return ERR_PTR(-EPROBE_DEFER); |
|---|
| 1133 | 1109 | } |
|---|
| 1134 | 1110 | |
|---|
| .. | .. |
|---|
| 1152 | 1128 | } |
|---|
| 1153 | 1129 | |
|---|
| 1154 | 1130 | pmc_base = of_iomap(node, 0); |
|---|
| 1131 | + of_node_put(node); |
|---|
| 1155 | 1132 | if (!pmc_base) { |
|---|
| 1156 | 1133 | pr_err("Can't map pmc registers\n"); |
|---|
| 1157 | 1134 | BUG(); |
|---|
| .. | .. |
|---|
| 1169 | 1146 | tegra_super_clk_gen4_init(clk_base, pmc_base, tegra20_clks, NULL); |
|---|
| 1170 | 1147 | tegra20_periph_clk_init(); |
|---|
| 1171 | 1148 | tegra20_audio_clk_init(); |
|---|
| 1172 | | - tegra_pmc_clk_init(pmc_base, tegra20_clks); |
|---|
| 1173 | 1149 | |
|---|
| 1174 | 1150 | tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX); |
|---|
| 1175 | 1151 | |
|---|