9
9
#include <linux/clkdev.h>
10
10
#include <linux/of.h>
11
11
#include <linux/of_address.h>
12
+ #include <linux/syscore_ops.h>
12
13
#include <linux/delay.h>
13
14
#include <linux/export.h>
14
15
#include <linux/mutex.h>
15
16
#include <linux/clk/tegra.h>
16
17
#include <dt-bindings/clock/tegra210-car.h>
17
18
#include <dt-bindings/reset/tegra210-car.h>
18
- #include <linux/iopoll.h>
19
19
#include <linux/sizes.h>
20
20
#include <soc/tegra/pmc.h>
21
21
221
221
#define CLK_M_DIVISOR_SHIFT 2
222
222
#define CLK_M_DIVISOR_MASK 0x3
223
223
224
+ #define CLK_MASK_ARM 0x44
225
+ #define MISC_CLK_ENB 0x48
226
+
224
227
#define RST_DFLL_DVCO 0x2f4
225
228
#define DVFS_DFLL_RESET_SHIFT 0
226
229
227
230
#define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8
228
231
#define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac
232
+ #define CPU_SOFTRST_CTRL 0x380
229
233
230
234
#define LVL2_CLK_GATE_OVRA 0xf8
231
235
#define LVL2_CLK_GATE_OVRC 0x3a0
@@ -2826,6 +2830,7 @@ static int tegra210_enable_pllu(void)
2826
2830
struct tegra_clk_pll_freq_table * fentry ;
2827
2831
struct tegra_clk_pll pllu ;
2828
2832
u32 reg ;
2833
+ int ret ;
2829
2834
2830
2835
for (fentry = pll_u_freq_table ; fentry -> input_rate ; fentry ++ ) {
2831
2836
if (fentry -> input_rate == pll_ref_freq )
@@ -2854,9 +2859,14 @@ static int tegra210_enable_pllu(void)
2854
2859
reg |= PLL_ENABLE ;
2855
2860
writel (reg , clk_base + PLLU_BASE );
2856
2861
2857
- readl_relaxed_poll_timeout_atomic (clk_base + PLLU_BASE , reg ,
2858
- reg & PLL_BASE_LOCK , 2 , 1000 );
2859
- if (!(reg & PLL_BASE_LOCK )) {
2862
+ /*
2863
+ * During clocks resume, same PLLU init and enable sequence get
2864
+ * executed. So, readx_poll_timeout_atomic can't be used here as it
2865
+ * uses ktime_get() and timekeeping resume doesn't happen by that
2866
+ * time. So, using tegra210_wait_for_mask for PLL LOCK.
2867
+ */
2868
+ ret = tegra210_wait_for_mask (& pllu , PLLU_BASE , PLL_BASE_LOCK );
2869
+ if (ret ) {
2860
2870
pr_err ("Timed out waiting for PLL_U to lock\n" );
2861
2871
return - ETIMEDOUT ;
2862
2872
}
@@ -3326,6 +3336,77 @@ static void tegra210_disable_cpu_clock(u32 cpu)
3326
3336
}
3327
3337
3328
3338
#ifdef CONFIG_PM_SLEEP
3339
+ #define car_readl (_base , _off ) readl_relaxed(clk_base + (_base) + ((_off) * 4))
3340
+ #define car_writel (_val , _base , _off ) \
3341
+ writel_relaxed(_val, clk_base + (_base) + ((_off) * 4))
3342
+
3343
+ static u32 spare_reg_ctx , misc_clk_enb_ctx , clk_msk_arm_ctx ;
3344
+ static u32 cpu_softrst_ctx [3 ];
3345
+
3346
+ static int tegra210_clk_suspend (void )
3347
+ {
3348
+ unsigned int i ;
3349
+
3350
+ clk_save_context ();
3351
+
3352
+ /*
3353
+ * Save the bootloader configured clock registers SPARE_REG0,
3354
+ * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL.
3355
+ */
3356
+ spare_reg_ctx = readl_relaxed (clk_base + SPARE_REG0 );
3357
+ misc_clk_enb_ctx = readl_relaxed (clk_base + MISC_CLK_ENB );
3358
+ clk_msk_arm_ctx = readl_relaxed (clk_base + CLK_MASK_ARM );
3359
+
3360
+ for (i = 0 ; i < ARRAY_SIZE (cpu_softrst_ctx ); i ++ )
3361
+ cpu_softrst_ctx [i ] = car_readl (CPU_SOFTRST_CTRL , i );
3362
+
3363
+ tegra_clk_periph_suspend ();
3364
+ return 0 ;
3365
+ }
3366
+
3367
+ static void tegra210_clk_resume (void )
3368
+ {
3369
+ unsigned int i ;
3370
+
3371
+ tegra_clk_osc_resume (clk_base );
3372
+
3373
+ /*
3374
+ * Restore the bootloader configured clock registers SPARE_REG0,
3375
+ * MISC_CLK_ENB, CLK_MASK_ARM, CPU_SOFTRST_CTRL from saved context.
3376
+ */
3377
+ writel_relaxed (spare_reg_ctx , clk_base + SPARE_REG0 );
3378
+ writel_relaxed (misc_clk_enb_ctx , clk_base + MISC_CLK_ENB );
3379
+ writel_relaxed (clk_msk_arm_ctx , clk_base + CLK_MASK_ARM );
3380
+
3381
+ for (i = 0 ; i < ARRAY_SIZE (cpu_softrst_ctx ); i ++ )
3382
+ car_writel (cpu_softrst_ctx [i ], CPU_SOFTRST_CTRL , i );
3383
+
3384
+ /*
3385
+ * Tegra clock programming sequence recommends peripheral clock to
3386
+ * be enabled prior to changing its clock source and divider to
3387
+ * prevent glitchless frequency switch.
3388
+ * So, enable all peripheral clocks before restoring their source
3389
+ * and dividers.
3390
+ */
3391
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_L , clk_base + CLK_OUT_ENB_L );
3392
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_H , clk_base + CLK_OUT_ENB_H );
3393
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_U , clk_base + CLK_OUT_ENB_U );
3394
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_V , clk_base + CLK_OUT_ENB_V );
3395
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_W , clk_base + CLK_OUT_ENB_W );
3396
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_X , clk_base + CLK_OUT_ENB_X );
3397
+ writel_relaxed (TEGRA210_CLK_ENB_VLD_MSK_Y , clk_base + CLK_OUT_ENB_Y );
3398
+
3399
+ /* wait for all writes to happen to have all the clocks enabled */
3400
+ fence_udelay (2 , clk_base );
3401
+
3402
+ /* restore PLLs and all peripheral clock rates */
3403
+ tegra210_init_pllu ();
3404
+ clk_restore_context ();
3405
+
3406
+ /* restore saved context of peripheral clocks and reset state */
3407
+ tegra_clk_periph_resume ();
3408
+ }
3409
+
3329
3410
static void tegra210_cpu_clock_suspend (void )
3330
3411
{
3331
3412
/* switch coresite to clk_m, save off original source */
@@ -3341,6 +3422,11 @@ static void tegra210_cpu_clock_resume(void)
3341
3422
}
3342
3423
#endif
3343
3424
3425
+ static struct syscore_ops tegra_clk_syscore_ops = {
3426
+ .suspend = tegra210_clk_suspend ,
3427
+ .resume = tegra210_clk_resume ,
3428
+ };
3429
+
3344
3430
static struct tegra_cpu_car_ops tegra210_cpu_car_ops = {
3345
3431
.wait_for_reset = tegra210_wait_cpu_in_reset ,
3346
3432
.disable_clock = tegra210_disable_cpu_clock ,
@@ -3625,5 +3711,7 @@ static void __init tegra210_clock_init(struct device_node *np)
3625
3711
tegra210_mbist_clk_init ();
3626
3712
3627
3713
tegra_cpu_car_ops = & tegra210_cpu_car_ops ;
3714
+
3715
+ register_syscore_ops (& tegra_clk_syscore_ops );
3628
3716
}
3629
3717
CLK_OF_DECLARE (tegra210 , "nvidia,tegra210-car" , tegra210_clock_init );
0 commit comments