.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2012-2014 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> |
---|
.. | .. |
---|
20 | 9 | #include <linux/clkdev.h> |
---|
21 | 10 | #include <linux/of.h> |
---|
22 | 11 | #include <linux/of_address.h> |
---|
| 12 | +#include <linux/syscore_ops.h> |
---|
23 | 13 | #include <linux/delay.h> |
---|
24 | 14 | #include <linux/export.h> |
---|
25 | 15 | #include <linux/mutex.h> |
---|
26 | 16 | #include <linux/clk/tegra.h> |
---|
27 | 17 | #include <dt-bindings/clock/tegra210-car.h> |
---|
28 | 18 | #include <dt-bindings/reset/tegra210-car.h> |
---|
29 | | -#include <linux/iopoll.h> |
---|
| 19 | +#include <linux/sizes.h> |
---|
30 | 20 | #include <soc/tegra/pmc.h> |
---|
31 | 21 | |
---|
32 | 22 | #include "clk.h" |
---|
.. | .. |
---|
43 | 33 | #define CLK_SOURCE_CSITE 0x1d4 |
---|
44 | 34 | #define CLK_SOURCE_EMC 0x19c |
---|
45 | 35 | #define CLK_SOURCE_SOR1 0x410 |
---|
| 36 | +#define CLK_SOURCE_SOR0 0x414 |
---|
46 | 37 | #define CLK_SOURCE_LA 0x1f8 |
---|
47 | 38 | #define CLK_SOURCE_SDMMC2 0x154 |
---|
48 | 39 | #define CLK_SOURCE_SDMMC4 0x164 |
---|
| 40 | +#define CLK_SOURCE_EMC_DLL 0x664 |
---|
49 | 41 | |
---|
50 | 42 | #define PLLC_BASE 0x80 |
---|
51 | 43 | #define PLLC_OUT 0x84 |
---|
.. | .. |
---|
230 | 222 | #define CLK_M_DIVISOR_SHIFT 2 |
---|
231 | 223 | #define CLK_M_DIVISOR_MASK 0x3 |
---|
232 | 224 | |
---|
| 225 | +#define CLK_MASK_ARM 0x44 |
---|
| 226 | +#define MISC_CLK_ENB 0x48 |
---|
| 227 | + |
---|
233 | 228 | #define RST_DFLL_DVCO 0x2f4 |
---|
234 | 229 | #define DVFS_DFLL_RESET_SHIFT 0 |
---|
235 | 230 | |
---|
| 231 | +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X_SET 0x284 |
---|
| 232 | +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_X_CLR 0x288 |
---|
| 233 | +#define CLK_OUT_ENB_X_CLK_ENB_EMC_DLL BIT(14) |
---|
| 234 | + |
---|
236 | 235 | #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8 |
---|
237 | 236 | #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac |
---|
| 237 | +#define CPU_SOFTRST_CTRL 0x380 |
---|
238 | 238 | |
---|
239 | 239 | #define LVL2_CLK_GATE_OVRA 0xf8 |
---|
240 | 240 | #define LVL2_CLK_GATE_OVRC 0x3a0 |
---|
.. | .. |
---|
308 | 308 | static DEFINE_SPINLOCK(pll_e_lock); |
---|
309 | 309 | static DEFINE_SPINLOCK(pll_re_lock); |
---|
310 | 310 | static DEFINE_SPINLOCK(pll_u_lock); |
---|
| 311 | +static DEFINE_SPINLOCK(sor0_lock); |
---|
311 | 312 | static DEFINE_SPINLOCK(sor1_lock); |
---|
312 | 313 | static DEFINE_SPINLOCK(emc_lock); |
---|
313 | 314 | static DEFINE_MUTEX(lvl2_ovr_lock); |
---|
.. | .. |
---|
317 | 318 | [5] = 38400000, |
---|
318 | 319 | [8] = 12000000, |
---|
319 | 320 | }; |
---|
320 | | - |
---|
321 | | -static const char *mux_pllmcp_clkm[] = { |
---|
322 | | - "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb", "pll_mb", |
---|
323 | | - "pll_p", |
---|
324 | | -}; |
---|
325 | | -#define mux_pllmcp_clkm_idx NULL |
---|
326 | 321 | |
---|
327 | 322 | #define PLL_ENABLE (1 << 30) |
---|
328 | 323 | |
---|
.. | .. |
---|
558 | 553 | writel_relaxed(val, clk_base + SATA_PLL_CFG0); |
---|
559 | 554 | } |
---|
560 | 555 | EXPORT_SYMBOL_GPL(tegra210_set_sata_pll_seq_sw); |
---|
| 556 | + |
---|
| 557 | +void tegra210_clk_emc_dll_enable(bool flag) |
---|
| 558 | +{ |
---|
| 559 | + u32 offset = flag ? CLK_RST_CONTROLLER_CLK_OUT_ENB_X_SET : |
---|
| 560 | + CLK_RST_CONTROLLER_CLK_OUT_ENB_X_CLR; |
---|
| 561 | + |
---|
| 562 | + writel_relaxed(CLK_OUT_ENB_X_CLK_ENB_EMC_DLL, clk_base + offset); |
---|
| 563 | +} |
---|
| 564 | +EXPORT_SYMBOL_GPL(tegra210_clk_emc_dll_enable); |
---|
| 565 | + |
---|
| 566 | +void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value) |
---|
| 567 | +{ |
---|
| 568 | + writel_relaxed(emc_dll_src_value, clk_base + CLK_SOURCE_EMC_DLL); |
---|
| 569 | +} |
---|
| 570 | +EXPORT_SYMBOL_GPL(tegra210_clk_emc_dll_update_setting); |
---|
| 571 | + |
---|
| 572 | +void tegra210_clk_emc_update_setting(u32 emc_src_value) |
---|
| 573 | +{ |
---|
| 574 | + writel_relaxed(emc_src_value, clk_base + CLK_SOURCE_EMC); |
---|
| 575 | +} |
---|
| 576 | +EXPORT_SYMBOL_GPL(tegra210_clk_emc_update_setting); |
---|
561 | 577 | |
---|
562 | 578 | static void tegra210_generic_mbist_war(struct tegra210_domain_mbist_war *mbist) |
---|
563 | 579 | { |
---|
.. | .. |
---|
994 | 1010 | pllre->params->defaults_set = true; |
---|
995 | 1011 | |
---|
996 | 1012 | if (val & PLL_ENABLE) { |
---|
997 | | - pr_warn("PLL_RE already enabled. Postponing set full defaults\n"); |
---|
998 | | - |
---|
999 | 1013 | /* |
---|
1000 | 1014 | * PLL is ON: check if defaults already set, then set those |
---|
1001 | 1015 | * that can be updated in flight. |
---|
.. | .. |
---|
1015 | 1029 | _pll_misc_chk_default(clk_base, pllre->params, 0, val, |
---|
1016 | 1030 | ~mask & PLLRE_MISC0_WRITE_MASK); |
---|
1017 | 1031 | |
---|
1018 | | - /* Enable lock detect */ |
---|
| 1032 | + /* The PLL doesn't work if it's in IDDQ. */ |
---|
1019 | 1033 | val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]); |
---|
| 1034 | + if (val & PLLRE_MISC0_IDDQ) |
---|
| 1035 | + pr_warn("unexpected IDDQ bit set for enabled clock\n"); |
---|
| 1036 | + |
---|
| 1037 | + /* Enable lock detect */ |
---|
1020 | 1038 | val &= ~mask; |
---|
1021 | 1039 | val |= PLLRE_MISC0_DEFAULT_VALUE & mask; |
---|
1022 | 1040 | writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]); |
---|
1023 | 1041 | udelay(1); |
---|
| 1042 | + |
---|
| 1043 | + if (!pllre->params->defaults_set) |
---|
| 1044 | + pr_warn("PLL_RE already enabled. Postponing set full defaults\n"); |
---|
1024 | 1045 | |
---|
1025 | 1046 | return; |
---|
1026 | 1047 | } |
---|
.. | .. |
---|
2309 | 2330 | [tegra_clk_i2c2] = { .dt_id = TEGRA210_CLK_I2C2, .present = true }, |
---|
2310 | 2331 | [tegra_clk_uartc_8] = { .dt_id = TEGRA210_CLK_UARTC, .present = true }, |
---|
2311 | 2332 | [tegra_clk_mipi_cal] = { .dt_id = TEGRA210_CLK_MIPI_CAL, .present = true }, |
---|
2312 | | - [tegra_clk_emc] = { .dt_id = TEGRA210_CLK_EMC, .present = true }, |
---|
2313 | 2333 | [tegra_clk_usb2] = { .dt_id = TEGRA210_CLK_USB2, .present = true }, |
---|
2314 | 2334 | [tegra_clk_bsev] = { .dt_id = TEGRA210_CLK_BSEV, .present = true }, |
---|
2315 | 2335 | [tegra_clk_uartd_8] = { .dt_id = TEGRA210_CLK_UARTD, .present = true }, |
---|
.. | .. |
---|
2356 | 2376 | [tegra_clk_dpaux] = { .dt_id = TEGRA210_CLK_DPAUX, .present = true }, |
---|
2357 | 2377 | [tegra_clk_dpaux1] = { .dt_id = TEGRA210_CLK_DPAUX1, .present = true }, |
---|
2358 | 2378 | [tegra_clk_sor0] = { .dt_id = TEGRA210_CLK_SOR0, .present = true }, |
---|
2359 | | - [tegra_clk_sor0_lvds] = { .dt_id = TEGRA210_CLK_SOR0_LVDS, .present = true }, |
---|
| 2379 | + [tegra_clk_sor0_out] = { .dt_id = TEGRA210_CLK_SOR0_OUT, .present = true }, |
---|
2360 | 2380 | [tegra_clk_sor1] = { .dt_id = TEGRA210_CLK_SOR1, .present = true }, |
---|
2361 | | - [tegra_clk_sor1_src] = { .dt_id = TEGRA210_CLK_SOR1_SRC, .present = true }, |
---|
| 2381 | + [tegra_clk_sor1_out] = { .dt_id = TEGRA210_CLK_SOR1_OUT, .present = true }, |
---|
2362 | 2382 | [tegra_clk_gpu] = { .dt_id = TEGRA210_CLK_GPU, .present = true }, |
---|
2363 | 2383 | [tegra_clk_pll_g_ref] = { .dt_id = TEGRA210_CLK_PLL_G_REF, .present = true, }, |
---|
2364 | 2384 | [tegra_clk_uartb_8] = { .dt_id = TEGRA210_CLK_UARTB, .present = true }, |
---|
.. | .. |
---|
2370 | 2390 | [tegra_clk_fuse_burn] = { .dt_id = TEGRA210_CLK_FUSE_BURN, .present = true }, |
---|
2371 | 2391 | [tegra_clk_clk_32k] = { .dt_id = TEGRA210_CLK_CLK_32K, .present = true }, |
---|
2372 | 2392 | [tegra_clk_clk_m] = { .dt_id = TEGRA210_CLK_CLK_M, .present = true }, |
---|
2373 | | - [tegra_clk_clk_m_div2] = { .dt_id = TEGRA210_CLK_CLK_M_DIV2, .present = true }, |
---|
2374 | | - [tegra_clk_clk_m_div4] = { .dt_id = TEGRA210_CLK_CLK_M_DIV4, .present = true }, |
---|
| 2393 | + [tegra_clk_osc] = { .dt_id = TEGRA210_CLK_OSC, .present = true }, |
---|
| 2394 | + [tegra_clk_osc_div2] = { .dt_id = TEGRA210_CLK_OSC_DIV2, .present = true }, |
---|
| 2395 | + [tegra_clk_osc_div4] = { .dt_id = TEGRA210_CLK_OSC_DIV4, .present = true }, |
---|
2375 | 2396 | [tegra_clk_pll_ref] = { .dt_id = TEGRA210_CLK_PLL_REF, .present = true }, |
---|
2376 | 2397 | [tegra_clk_pll_c] = { .dt_id = TEGRA210_CLK_PLL_C, .present = true }, |
---|
2377 | 2398 | [tegra_clk_pll_c_out1] = { .dt_id = TEGRA210_CLK_PLL_C_OUT1, .present = true }, |
---|
.. | .. |
---|
2416 | 2437 | [tegra_clk_audio3] = { .dt_id = TEGRA210_CLK_AUDIO3, .present = true }, |
---|
2417 | 2438 | [tegra_clk_audio4] = { .dt_id = TEGRA210_CLK_AUDIO4, .present = true }, |
---|
2418 | 2439 | [tegra_clk_spdif] = { .dt_id = TEGRA210_CLK_SPDIF, .present = true }, |
---|
2419 | | - [tegra_clk_clk_out_1] = { .dt_id = TEGRA210_CLK_CLK_OUT_1, .present = true }, |
---|
2420 | | - [tegra_clk_clk_out_2] = { .dt_id = TEGRA210_CLK_CLK_OUT_2, .present = true }, |
---|
2421 | | - [tegra_clk_clk_out_3] = { .dt_id = TEGRA210_CLK_CLK_OUT_3, .present = true }, |
---|
2422 | | - [tegra_clk_blink] = { .dt_id = TEGRA210_CLK_BLINK, .present = true }, |
---|
2423 | 2440 | [tegra_clk_xusb_gate] = { .dt_id = TEGRA210_CLK_XUSB_GATE, .present = true }, |
---|
2424 | 2441 | [tegra_clk_xusb_host_src_8] = { .dt_id = TEGRA210_CLK_XUSB_HOST_SRC, .present = true }, |
---|
2425 | 2442 | [tegra_clk_xusb_falcon_src_8] = { .dt_id = TEGRA210_CLK_XUSB_FALCON_SRC, .present = true }, |
---|
.. | .. |
---|
2451 | 2468 | [tegra_clk_audio3_mux] = { .dt_id = TEGRA210_CLK_AUDIO3_MUX, .present = true }, |
---|
2452 | 2469 | [tegra_clk_audio4_mux] = { .dt_id = TEGRA210_CLK_AUDIO4_MUX, .present = true }, |
---|
2453 | 2470 | [tegra_clk_spdif_mux] = { .dt_id = TEGRA210_CLK_SPDIF_MUX, .present = true }, |
---|
2454 | | - [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_1_MUX, .present = true }, |
---|
2455 | | - [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_2_MUX, .present = true }, |
---|
2456 | | - [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA210_CLK_CLK_OUT_3_MUX, .present = true }, |
---|
2457 | 2471 | [tegra_clk_maud] = { .dt_id = TEGRA210_CLK_MAUD, .present = true }, |
---|
2458 | 2472 | [tegra_clk_mipibif] = { .dt_id = TEGRA210_CLK_MIPIBIF, .present = true }, |
---|
2459 | 2473 | [tegra_clk_qspi] = { .dt_id = TEGRA210_CLK_QSPI, .present = true }, |
---|
.. | .. |
---|
2496 | 2510 | { .con_id = "clk_m", .dt_id = TEGRA210_CLK_CLK_M }, |
---|
2497 | 2511 | { .con_id = "pll_ref", .dt_id = TEGRA210_CLK_PLL_REF }, |
---|
2498 | 2512 | { .con_id = "clk_32k", .dt_id = TEGRA210_CLK_CLK_32K }, |
---|
2499 | | - { .con_id = "clk_m_div2", .dt_id = TEGRA210_CLK_CLK_M_DIV2 }, |
---|
2500 | | - { .con_id = "clk_m_div4", .dt_id = TEGRA210_CLK_CLK_M_DIV4 }, |
---|
| 2513 | + { .con_id = "osc", .dt_id = TEGRA210_CLK_OSC }, |
---|
| 2514 | + { .con_id = "osc_div2", .dt_id = TEGRA210_CLK_OSC_DIV2 }, |
---|
| 2515 | + { .con_id = "osc_div4", .dt_id = TEGRA210_CLK_OSC_DIV4 }, |
---|
2501 | 2516 | { .con_id = "pll_c", .dt_id = TEGRA210_CLK_PLL_C }, |
---|
2502 | 2517 | { .con_id = "pll_c_out1", .dt_id = TEGRA210_CLK_PLL_C_OUT1 }, |
---|
2503 | 2518 | { .con_id = "pll_c2", .dt_id = TEGRA210_CLK_PLL_C2 }, |
---|
.. | .. |
---|
2539 | 2554 | { .con_id = "audio4", .dt_id = TEGRA210_CLK_AUDIO4 }, |
---|
2540 | 2555 | { .con_id = "spdif", .dt_id = TEGRA210_CLK_SPDIF }, |
---|
2541 | 2556 | { .con_id = "spdif_2x", .dt_id = TEGRA210_CLK_SPDIF_2X }, |
---|
2542 | | - { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA210_CLK_EXTERN1 }, |
---|
2543 | | - { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA210_CLK_EXTERN2 }, |
---|
2544 | | - { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA210_CLK_EXTERN3 }, |
---|
2545 | | - { .con_id = "blink", .dt_id = TEGRA210_CLK_BLINK }, |
---|
| 2557 | + { .con_id = "extern1", .dt_id = TEGRA210_CLK_EXTERN1 }, |
---|
| 2558 | + { .con_id = "extern2", .dt_id = TEGRA210_CLK_EXTERN2 }, |
---|
| 2559 | + { .con_id = "extern3", .dt_id = TEGRA210_CLK_EXTERN3 }, |
---|
2546 | 2560 | { .con_id = "cclk_g", .dt_id = TEGRA210_CLK_CCLK_G }, |
---|
2547 | 2561 | { .con_id = "cclk_lp", .dt_id = TEGRA210_CLK_CCLK_LP }, |
---|
2548 | 2562 | { .con_id = "sclk", .dt_id = TEGRA210_CLK_SCLK }, |
---|
.. | .. |
---|
2556 | 2570 | { .con_id = "pll_c4_out2", .dt_id = TEGRA210_CLK_PLL_C4_OUT2 }, |
---|
2557 | 2571 | { .con_id = "pll_c4_out3", .dt_id = TEGRA210_CLK_PLL_C4_OUT3 }, |
---|
2558 | 2572 | { .con_id = "dpaux", .dt_id = TEGRA210_CLK_DPAUX }, |
---|
2559 | | - { .con_id = "sor0", .dt_id = TEGRA210_CLK_SOR0 }, |
---|
2560 | 2573 | }; |
---|
2561 | 2574 | |
---|
2562 | 2575 | static struct tegra_audio_clk_info tegra210_audio_plls[] = { |
---|
.. | .. |
---|
2830 | 2843 | struct tegra_clk_pll_freq_table *fentry; |
---|
2831 | 2844 | struct tegra_clk_pll pllu; |
---|
2832 | 2845 | u32 reg; |
---|
| 2846 | + int ret; |
---|
2833 | 2847 | |
---|
2834 | 2848 | for (fentry = pll_u_freq_table; fentry->input_rate; fentry++) { |
---|
2835 | 2849 | if (fentry->input_rate == pll_ref_freq) |
---|
.. | .. |
---|
2846 | 2860 | reg = readl_relaxed(clk_base + pllu.params->ext_misc_reg[0]); |
---|
2847 | 2861 | reg &= ~BIT(pllu.params->iddq_bit_idx); |
---|
2848 | 2862 | writel_relaxed(reg, clk_base + pllu.params->ext_misc_reg[0]); |
---|
2849 | | - udelay(5); |
---|
| 2863 | + fence_udelay(5, clk_base); |
---|
2850 | 2864 | |
---|
2851 | 2865 | reg = readl_relaxed(clk_base + PLLU_BASE); |
---|
2852 | 2866 | reg &= ~GENMASK(20, 0); |
---|
.. | .. |
---|
2854 | 2868 | reg |= fentry->n << 8; |
---|
2855 | 2869 | reg |= fentry->p << 16; |
---|
2856 | 2870 | writel(reg, clk_base + PLLU_BASE); |
---|
2857 | | - udelay(1); |
---|
| 2871 | + fence_udelay(1, clk_base); |
---|
2858 | 2872 | reg |= PLL_ENABLE; |
---|
2859 | 2873 | writel(reg, clk_base + PLLU_BASE); |
---|
2860 | 2874 | |
---|
2861 | | - readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg, |
---|
2862 | | - reg & PLL_BASE_LOCK, 2, 1000); |
---|
2863 | | - if (!(reg & PLL_BASE_LOCK)) { |
---|
| 2875 | + /* |
---|
| 2876 | + * During clocks resume, same PLLU init and enable sequence get |
---|
| 2877 | + * executed. So, readx_poll_timeout_atomic can't be used here as it |
---|
| 2878 | + * uses ktime_get() and timekeeping resume doesn't happen by that |
---|
| 2879 | + * time. So, using tegra210_wait_for_mask for PLL LOCK. |
---|
| 2880 | + */ |
---|
| 2881 | + ret = tegra210_wait_for_mask(&pllu, PLLU_BASE, PLL_BASE_LOCK); |
---|
| 2882 | + if (ret) { |
---|
2864 | 2883 | pr_err("Timed out waiting for PLL_U to lock\n"); |
---|
2865 | 2884 | return -ETIMEDOUT; |
---|
2866 | 2885 | } |
---|
.. | .. |
---|
2900 | 2919 | reg = readl_relaxed(clk_base + XUSB_PLL_CFG0); |
---|
2901 | 2920 | reg &= ~XUSB_PLL_CFG0_PLLU_LOCK_DLY_MASK; |
---|
2902 | 2921 | writel_relaxed(reg, clk_base + XUSB_PLL_CFG0); |
---|
2903 | | - udelay(1); |
---|
| 2922 | + fence_udelay(1, clk_base); |
---|
2904 | 2923 | |
---|
2905 | 2924 | reg = readl_relaxed(clk_base + PLLU_HW_PWRDN_CFG0); |
---|
2906 | 2925 | reg |= PLLU_HW_PWRDN_CFG0_SEQ_ENABLE; |
---|
2907 | 2926 | writel_relaxed(reg, clk_base + PLLU_HW_PWRDN_CFG0); |
---|
2908 | | - udelay(1); |
---|
| 2927 | + fence_udelay(1, clk_base); |
---|
2909 | 2928 | |
---|
2910 | 2929 | reg = readl_relaxed(clk_base + PLLU_BASE); |
---|
2911 | 2930 | reg &= ~PLLU_BASE_CLKENABLE_USB; |
---|
.. | .. |
---|
2920 | 2939 | return 0; |
---|
2921 | 2940 | } |
---|
2922 | 2941 | |
---|
2923 | | -static const char * const sor1_out_parents[] = { |
---|
2924 | | - /* |
---|
2925 | | - * Bit 0 of the mux selects sor1_pad_clkout, irrespective of bit 1, so |
---|
2926 | | - * the sor1_pad_clkout parent appears twice in the list below. This is |
---|
2927 | | - * merely to support clk_get_parent() if firmware happened to set |
---|
2928 | | - * these bits to 0b11. While not an invalid setting, code should |
---|
2929 | | - * always set the bits to 0b01 to select sor1_pad_clkout. |
---|
2930 | | - */ |
---|
2931 | | - "sor_safe", "sor1_pad_clkout", "sor1", "sor1_pad_clkout", |
---|
| 2942 | +/* |
---|
| 2943 | + * The SOR hardware blocks are driven by two clocks: a module clock that is |
---|
| 2944 | + * used to access registers and a pixel clock that is sourced from the same |
---|
| 2945 | + * pixel clock that also drives the head attached to the SOR. The module |
---|
| 2946 | + * clock is typically called sorX (with X being the SOR instance) and the |
---|
| 2947 | + * pixel clock is called sorX_out. The source for the SOR pixel clock is |
---|
| 2948 | + * referred to as the "parent" clock. |
---|
| 2949 | + * |
---|
| 2950 | + * On Tegra186 and newer, clocks are provided by the BPMP. Unfortunately the |
---|
| 2951 | + * BPMP implementation for the SOR clocks doesn't exactly match the above in |
---|
| 2952 | + * some aspects. For example, the SOR module is really clocked by the pad or |
---|
| 2953 | + * sor_safe clocks, but BPMP models the sorX clock as being sourced by the |
---|
| 2954 | + * pixel clocks. Conversely the sorX_out clock is sourced by the sor_safe or |
---|
| 2955 | + * pad clocks on BPMP. |
---|
| 2956 | + * |
---|
| 2957 | + * In order to allow the display driver to deal with all SoC generations in |
---|
| 2958 | + * a unified way, implement the BPMP semantics in this driver. |
---|
| 2959 | + */ |
---|
| 2960 | + |
---|
| 2961 | +static const char * const sor0_parents[] = { |
---|
| 2962 | + "pll_d_out0", |
---|
| 2963 | +}; |
---|
| 2964 | + |
---|
| 2965 | +static const char * const sor0_out_parents[] = { |
---|
| 2966 | + "sor_safe", "sor0_pad_clkout", |
---|
2932 | 2967 | }; |
---|
2933 | 2968 | |
---|
2934 | 2969 | static const char * const sor1_parents[] = { |
---|
.. | .. |
---|
2937 | 2972 | |
---|
2938 | 2973 | static u32 sor1_parents_idx[] = { 0, 2, 5, 6 }; |
---|
2939 | 2974 | |
---|
| 2975 | +static const struct clk_div_table mc_div_table_tegra210[] = { |
---|
| 2976 | + { .val = 0, .div = 2 }, |
---|
| 2977 | + { .val = 1, .div = 4 }, |
---|
| 2978 | + { .val = 2, .div = 1 }, |
---|
| 2979 | + { .val = 3, .div = 2 }, |
---|
| 2980 | + { .val = 0, .div = 0 }, |
---|
| 2981 | +}; |
---|
| 2982 | + |
---|
| 2983 | +static void tegra210_clk_register_mc(const char *name, |
---|
| 2984 | + const char *parent_name) |
---|
| 2985 | +{ |
---|
| 2986 | + struct clk *clk; |
---|
| 2987 | + |
---|
| 2988 | + clk = clk_register_divider_table(NULL, name, parent_name, |
---|
| 2989 | + CLK_IS_CRITICAL, |
---|
| 2990 | + clk_base + CLK_SOURCE_EMC, |
---|
| 2991 | + 15, 2, CLK_DIVIDER_READ_ONLY, |
---|
| 2992 | + mc_div_table_tegra210, &emc_lock); |
---|
| 2993 | + clks[TEGRA210_CLK_MC] = clk; |
---|
| 2994 | +} |
---|
| 2995 | + |
---|
| 2996 | +static const char * const sor1_out_parents[] = { |
---|
| 2997 | + /* |
---|
| 2998 | + * Bit 0 of the mux selects sor1_pad_clkout, irrespective of bit 1, so |
---|
| 2999 | + * the sor1_pad_clkout parent appears twice in the list below. This is |
---|
| 3000 | + * merely to support clk_get_parent() if firmware happened to set |
---|
| 3001 | + * these bits to 0b11. While not an invalid setting, code should |
---|
| 3002 | + * always set the bits to 0b01 to select sor1_pad_clkout. |
---|
| 3003 | + */ |
---|
| 3004 | + "sor_safe", "sor1_pad_clkout", "sor1_out", "sor1_pad_clkout", |
---|
| 3005 | +}; |
---|
| 3006 | + |
---|
2940 | 3007 | static struct tegra_periph_init_data tegra210_periph[] = { |
---|
| 3008 | + /* |
---|
| 3009 | + * On Tegra210, the sor0 clock doesn't have a mux it bitfield 31:29, |
---|
| 3010 | + * but it is hardwired to the pll_d_out0 clock. |
---|
| 3011 | + */ |
---|
| 3012 | + TEGRA_INIT_DATA_TABLE("sor0", NULL, NULL, sor0_parents, |
---|
| 3013 | + CLK_SOURCE_SOR0, 29, 0x0, 0, 0, 0, 0, |
---|
| 3014 | + 0, 182, 0, tegra_clk_sor0, NULL, 0, |
---|
| 3015 | + &sor0_lock), |
---|
| 3016 | + TEGRA_INIT_DATA_TABLE("sor0_out", NULL, NULL, sor0_out_parents, |
---|
| 3017 | + CLK_SOURCE_SOR0, 14, 0x1, 0, 0, 0, 0, |
---|
| 3018 | + 0, 0, TEGRA_PERIPH_NO_GATE, tegra_clk_sor0_out, |
---|
| 3019 | + NULL, 0, &sor0_lock), |
---|
2941 | 3020 | TEGRA_INIT_DATA_TABLE("sor1", NULL, NULL, sor1_parents, |
---|
2942 | 3021 | CLK_SOURCE_SOR1, 29, 0x7, 0, 0, 8, 1, |
---|
2943 | | - TEGRA_DIVIDER_ROUND_UP, 183, 0, tegra_clk_sor1, |
---|
2944 | | - sor1_parents_idx, 0, &sor1_lock), |
---|
| 3022 | + TEGRA_DIVIDER_ROUND_UP, 183, 0, |
---|
| 3023 | + tegra_clk_sor1, sor1_parents_idx, 0, |
---|
| 3024 | + &sor1_lock), |
---|
| 3025 | + TEGRA_INIT_DATA_TABLE("sor1_out", NULL, NULL, sor1_out_parents, |
---|
| 3026 | + CLK_SOURCE_SOR1, 14, 0x3, 0, 0, 0, 0, |
---|
| 3027 | + 0, 0, TEGRA_PERIPH_NO_GATE, |
---|
| 3028 | + tegra_clk_sor1_out, NULL, 0, &sor1_lock), |
---|
2945 | 3029 | }; |
---|
2946 | 3030 | |
---|
2947 | 3031 | static const char * const la_parents[] = { |
---|
.. | .. |
---|
2949 | 3033 | }; |
---|
2950 | 3034 | |
---|
2951 | 3035 | static struct tegra_clk_periph tegra210_la = |
---|
2952 | | - TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, 0); |
---|
| 3036 | + TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, NULL); |
---|
2953 | 3037 | |
---|
2954 | | -static __init void tegra210_periph_clk_init(void __iomem *clk_base, |
---|
| 3038 | +static __init void tegra210_periph_clk_init(struct device_node *np, |
---|
| 3039 | + void __iomem *clk_base, |
---|
2955 | 3040 | void __iomem *pmc_base) |
---|
2956 | 3041 | { |
---|
2957 | 3042 | struct clk *clk; |
---|
.. | .. |
---|
2974 | 3059 | 1, 17, 207); |
---|
2975 | 3060 | clks[TEGRA210_CLK_DPAUX1] = clk; |
---|
2976 | 3061 | |
---|
2977 | | - clk = clk_register_mux_table(NULL, "sor1_out", sor1_out_parents, |
---|
2978 | | - ARRAY_SIZE(sor1_out_parents), 0, |
---|
2979 | | - clk_base + CLK_SOURCE_SOR1, 14, 0x3, |
---|
2980 | | - 0, NULL, &sor1_lock); |
---|
2981 | | - clks[TEGRA210_CLK_SOR1_OUT] = clk; |
---|
2982 | | - |
---|
2983 | 3062 | /* pll_d_dsi_out */ |
---|
2984 | 3063 | clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, |
---|
2985 | 3064 | clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); |
---|
.. | .. |
---|
2997 | 3076 | periph_clk_enb_refcnt); |
---|
2998 | 3077 | clks[TEGRA210_CLK_DSIB] = clk; |
---|
2999 | 3078 | |
---|
| 3079 | + /* csi_tpg */ |
---|
| 3080 | + clk = clk_register_gate(NULL, "csi_tpg", "pll_d", |
---|
| 3081 | + CLK_SET_RATE_PARENT, clk_base + PLLD_BASE, |
---|
| 3082 | + 23, 0, &pll_d_lock); |
---|
| 3083 | + clk_register_clkdev(clk, "csi_tpg", NULL); |
---|
| 3084 | + clks[TEGRA210_CLK_CSI_TPG] = clk; |
---|
| 3085 | + |
---|
3000 | 3086 | /* la */ |
---|
3001 | 3087 | clk = tegra_clk_register_periph("la", la_parents, |
---|
3002 | 3088 | ARRAY_SIZE(la_parents), &tegra210_la, clk_base, |
---|
3003 | 3089 | CLK_SOURCE_LA, 0); |
---|
3004 | 3090 | clks[TEGRA210_CLK_LA] = clk; |
---|
3005 | | - |
---|
3006 | | - /* emc mux */ |
---|
3007 | | - clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, |
---|
3008 | | - ARRAY_SIZE(mux_pllmcp_clkm), 0, |
---|
3009 | | - clk_base + CLK_SOURCE_EMC, |
---|
3010 | | - 29, 3, 0, &emc_lock); |
---|
3011 | | - |
---|
3012 | | - clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, |
---|
3013 | | - &emc_lock); |
---|
3014 | | - clks[TEGRA210_CLK_MC] = clk; |
---|
3015 | 3091 | |
---|
3016 | 3092 | /* cml0 */ |
---|
3017 | 3093 | clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, |
---|
.. | .. |
---|
3055 | 3131 | } |
---|
3056 | 3132 | |
---|
3057 | 3133 | tegra_periph_clk_init(clk_base, pmc_base, tegra210_clks, &pll_p_params); |
---|
| 3134 | + |
---|
| 3135 | + /* emc */ |
---|
| 3136 | + clk = tegra210_clk_register_emc(np, clk_base); |
---|
| 3137 | + clks[TEGRA210_CLK_EMC] = clk; |
---|
| 3138 | + |
---|
| 3139 | + /* mc */ |
---|
| 3140 | + tegra210_clk_register_mc("mc", "emc"); |
---|
3058 | 3141 | } |
---|
3059 | 3142 | |
---|
3060 | 3143 | static void __init tegra210_pll_init(void __iomem *clk_base, |
---|
.. | .. |
---|
3114 | 3197 | CLK_SET_RATE_PARENT, 1, 1); |
---|
3115 | 3198 | clk_register_clkdev(clk, "pll_m_ud", NULL); |
---|
3116 | 3199 | clks[TEGRA210_CLK_PLL_M_UD] = clk; |
---|
| 3200 | + |
---|
| 3201 | + /* PLLMB_UD */ |
---|
| 3202 | + clk = clk_register_fixed_factor(NULL, "pll_mb_ud", "pll_mb", |
---|
| 3203 | + CLK_SET_RATE_PARENT, 1, 1); |
---|
| 3204 | + clk_register_clkdev(clk, "pll_mb_ud", NULL); |
---|
| 3205 | + clks[TEGRA210_CLK_PLL_MB_UD] = clk; |
---|
| 3206 | + |
---|
| 3207 | + /* PLLP_UD */ |
---|
| 3208 | + clk = clk_register_fixed_factor(NULL, "pll_p_ud", "pll_p", |
---|
| 3209 | + 0, 1, 1); |
---|
| 3210 | + clks[TEGRA210_CLK_PLL_P_UD] = clk; |
---|
3117 | 3211 | |
---|
3118 | 3212 | /* PLLU_VCO */ |
---|
3119 | 3213 | if (!tegra210_init_pllu()) { |
---|
.. | .. |
---|
3292 | 3386 | } |
---|
3293 | 3387 | |
---|
3294 | 3388 | #ifdef CONFIG_PM_SLEEP |
---|
| 3389 | +#define car_readl(_base, _off) readl_relaxed(clk_base + (_base) + ((_off) * 4)) |
---|
| 3390 | +#define car_writel(_val, _base, _off) \ |
---|
| 3391 | + writel_relaxed(_val, clk_base + (_base) + ((_off) * 4)) |
---|
| 3392 | + |
---|
| 3393 | +static u32 spare_reg_ctx, misc_clk_enb_ctx, clk_msk_arm_ctx; |
---|
| 3394 | +static u32 cpu_softrst_ctx[3]; |
---|
| 3395 | + |
---|
| 3396 | +static int tegra210_clk_suspend(void) |
---|
| 3397 | +{ |
---|
| 3398 | + unsigned int i; |
---|
| 3399 | + |
---|
| 3400 | + clk_save_context(); |
---|
| 3401 | + |
---|
| 3402 | + /* |
---|
| 3403 | + * Save the bootloader configured clock registers SPARE_REG0, |
---|
| 3404 | + * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL. |
---|
| 3405 | + */ |
---|
| 3406 | + spare_reg_ctx = readl_relaxed(clk_base + SPARE_REG0); |
---|
| 3407 | + misc_clk_enb_ctx = readl_relaxed(clk_base + MISC_CLK_ENB); |
---|
| 3408 | + clk_msk_arm_ctx = readl_relaxed(clk_base + CLK_MASK_ARM); |
---|
| 3409 | + |
---|
| 3410 | + for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++) |
---|
| 3411 | + cpu_softrst_ctx[i] = car_readl(CPU_SOFTRST_CTRL, i); |
---|
| 3412 | + |
---|
| 3413 | + tegra_clk_periph_suspend(); |
---|
| 3414 | + return 0; |
---|
| 3415 | +} |
---|
| 3416 | + |
---|
| 3417 | +static void tegra210_clk_resume(void) |
---|
| 3418 | +{ |
---|
| 3419 | + unsigned int i; |
---|
| 3420 | + |
---|
| 3421 | + tegra_clk_osc_resume(clk_base); |
---|
| 3422 | + |
---|
| 3423 | + /* |
---|
| 3424 | + * Restore the bootloader configured clock registers SPARE_REG0, |
---|
| 3425 | + * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context. |
---|
| 3426 | + */ |
---|
| 3427 | + writel_relaxed(spare_reg_ctx, clk_base + SPARE_REG0); |
---|
| 3428 | + writel_relaxed(misc_clk_enb_ctx, clk_base + MISC_CLK_ENB); |
---|
| 3429 | + writel_relaxed(clk_msk_arm_ctx, clk_base + CLK_MASK_ARM); |
---|
| 3430 | + |
---|
| 3431 | + for (i = 0; i < ARRAY_SIZE(cpu_softrst_ctx); i++) |
---|
| 3432 | + car_writel(cpu_softrst_ctx[i], CPU_SOFTRST_CTRL, i); |
---|
| 3433 | + |
---|
| 3434 | + /* |
---|
| 3435 | + * Tegra clock programming sequence recommends peripheral clock to |
---|
| 3436 | + * be enabled prior to changing its clock source and divider to |
---|
| 3437 | + * prevent glitchless frequency switch. |
---|
| 3438 | + * So, enable all peripheral clocks before restoring their source |
---|
| 3439 | + * and dividers. |
---|
| 3440 | + */ |
---|
| 3441 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_L, clk_base + CLK_OUT_ENB_L); |
---|
| 3442 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_H, clk_base + CLK_OUT_ENB_H); |
---|
| 3443 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_U, clk_base + CLK_OUT_ENB_U); |
---|
| 3444 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_V, clk_base + CLK_OUT_ENB_V); |
---|
| 3445 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_W, clk_base + CLK_OUT_ENB_W); |
---|
| 3446 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_X, clk_base + CLK_OUT_ENB_X); |
---|
| 3447 | + writel_relaxed(TEGRA210_CLK_ENB_VLD_MSK_Y, clk_base + CLK_OUT_ENB_Y); |
---|
| 3448 | + |
---|
| 3449 | + /* wait for all writes to happen to have all the clocks enabled */ |
---|
| 3450 | + fence_udelay(2, clk_base); |
---|
| 3451 | + |
---|
| 3452 | + /* restore PLLs and all peripheral clock rates */ |
---|
| 3453 | + tegra210_init_pllu(); |
---|
| 3454 | + clk_restore_context(); |
---|
| 3455 | + |
---|
| 3456 | + /* restore saved context of peripheral clocks and reset state */ |
---|
| 3457 | + tegra_clk_periph_resume(); |
---|
| 3458 | +} |
---|
| 3459 | + |
---|
3295 | 3460 | static void tegra210_cpu_clock_suspend(void) |
---|
3296 | 3461 | { |
---|
3297 | 3462 | /* switch coresite to clk_m, save off original source */ |
---|
.. | .. |
---|
3306 | 3471 | clk_base + CLK_SOURCE_CSITE); |
---|
3307 | 3472 | } |
---|
3308 | 3473 | #endif |
---|
| 3474 | + |
---|
| 3475 | +static struct syscore_ops tegra_clk_syscore_ops = { |
---|
| 3476 | +#ifdef CONFIG_PM_SLEEP |
---|
| 3477 | + .suspend = tegra210_clk_suspend, |
---|
| 3478 | + .resume = tegra210_clk_resume, |
---|
| 3479 | +#endif |
---|
| 3480 | +}; |
---|
3309 | 3481 | |
---|
3310 | 3482 | static struct tegra_cpu_car_ops tegra210_cpu_car_ops = { |
---|
3311 | 3483 | .wait_for_reset = tegra210_wait_cpu_in_reset, |
---|
.. | .. |
---|
3326 | 3498 | { TEGRA210_CLK_UARTB, TEGRA210_CLK_PLL_P, 408000000, 0 }, |
---|
3327 | 3499 | { TEGRA210_CLK_UARTC, TEGRA210_CLK_PLL_P, 408000000, 0 }, |
---|
3328 | 3500 | { TEGRA210_CLK_UARTD, TEGRA210_CLK_PLL_P, 408000000, 0 }, |
---|
3329 | | - { TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 1 }, |
---|
3330 | | - { TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 1 }, |
---|
3331 | | - { TEGRA210_CLK_EXTERN1, TEGRA210_CLK_PLL_A_OUT0, 0, 1 }, |
---|
3332 | | - { TEGRA210_CLK_CLK_OUT_1_MUX, TEGRA210_CLK_EXTERN1, 0, 1 }, |
---|
3333 | | - { TEGRA210_CLK_CLK_OUT_1, TEGRA210_CLK_CLK_MAX, 0, 1 }, |
---|
| 3501 | + { TEGRA210_CLK_PLL_A, TEGRA210_CLK_CLK_MAX, 564480000, 0 }, |
---|
| 3502 | + { TEGRA210_CLK_PLL_A_OUT0, TEGRA210_CLK_CLK_MAX, 11289600, 0 }, |
---|
3334 | 3503 | { TEGRA210_CLK_I2S0, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, |
---|
3335 | 3504 | { TEGRA210_CLK_I2S1, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, |
---|
3336 | 3505 | { TEGRA210_CLK_I2S2, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, |
---|
.. | .. |
---|
3342 | 3511 | { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 }, |
---|
3343 | 3512 | { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, |
---|
3344 | 3513 | { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, |
---|
3345 | | - { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 }, |
---|
3346 | 3514 | { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 }, |
---|
3347 | 3515 | { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 }, |
---|
3348 | 3516 | { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 }, |
---|
.. | .. |
---|
3529 | 3697 | } |
---|
3530 | 3698 | |
---|
3531 | 3699 | pmc_base = of_iomap(node, 0); |
---|
| 3700 | + of_node_put(node); |
---|
3532 | 3701 | if (!pmc_base) { |
---|
3533 | 3702 | pr_err("Can't map pmc registers\n"); |
---|
3534 | 3703 | WARN_ON(1); |
---|
.. | .. |
---|
3558 | 3727 | if (!clks) |
---|
3559 | 3728 | return; |
---|
3560 | 3729 | |
---|
3561 | | - value = clk_readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT; |
---|
| 3730 | + value = readl(clk_base + SPARE_REG0) >> CLK_M_DIVISOR_SHIFT; |
---|
3562 | 3731 | clk_m_div = (value & CLK_M_DIVISOR_MASK) + 1; |
---|
3563 | 3732 | |
---|
3564 | 3733 | if (tegra_osc_clk_init(clk_base, tegra210_clks, tegra210_input_freq, |
---|
.. | .. |
---|
3568 | 3737 | |
---|
3569 | 3738 | tegra_fixed_clk_init(tegra210_clks); |
---|
3570 | 3739 | tegra210_pll_init(clk_base, pmc_base); |
---|
3571 | | - tegra210_periph_clk_init(clk_base, pmc_base); |
---|
| 3740 | + tegra210_periph_clk_init(np, clk_base, pmc_base); |
---|
3572 | 3741 | tegra_audio_clk_init(clk_base, pmc_base, tegra210_clks, |
---|
3573 | 3742 | tegra210_audio_plls, |
---|
3574 | 3743 | ARRAY_SIZE(tegra210_audio_plls), 24576000); |
---|
3575 | | - tegra_pmc_clk_init(pmc_base, tegra210_clks); |
---|
3576 | 3744 | |
---|
3577 | 3745 | /* For Tegra210, PLLD is the only source for DSIA & DSIB */ |
---|
3578 | | - value = clk_readl(clk_base + PLLD_BASE); |
---|
| 3746 | + value = readl(clk_base + PLLD_BASE); |
---|
3579 | 3747 | value &= ~BIT(25); |
---|
3580 | | - clk_writel(value, clk_base + PLLD_BASE); |
---|
| 3748 | + writel(value, clk_base + PLLD_BASE); |
---|
3581 | 3749 | |
---|
3582 | 3750 | tegra_clk_apply_init_table = tegra210_clock_apply_init_table; |
---|
3583 | 3751 | |
---|
.. | .. |
---|
3592 | 3760 | tegra210_mbist_clk_init(); |
---|
3593 | 3761 | |
---|
3594 | 3762 | tegra_cpu_car_ops = &tegra210_cpu_car_ops; |
---|
| 3763 | + |
---|
| 3764 | + register_syscore_ops(&tegra_clk_syscore_ops); |
---|
3595 | 3765 | } |
---|
3596 | 3766 | CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init); |
---|