video: ivybridge: Use mtrr_set_next_var() for graphics memory
[platform/kernel/u-boot.git] / drivers / timer / tegra-timer.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <timer.h>
10
11 #include <asm/io.h>
12 #include <asm/arch/clock.h>
13 #include <asm/arch/tegra.h>
14
15 #define TEGRA_OSC_CLK_ENB_L_SET         (NV_PA_CLK_RST_BASE + 0x320)
16 #define TEGRA_OSC_SET_CLK_ENB_TMR       BIT(5)
17
18 #define TEGRA_TIMER_USEC_CNTR           (NV_PA_TMRUS_BASE + 0)
19 #define TEGRA_TIMER_USEC_CFG            (NV_PA_TMRUS_BASE + 4)
20
21 #define TEGRA_TIMER_RATE                1000000 /* 1 MHz */
22
23 /*
24  * On pre-DM stage timer should be left configured by
25  * previous bootloader for correct 1MHz clock.
26  * In the case of reset default value is set to 1/13 of
27  * CLK_M which should be decent enough to safely
28  * get to DM stage.
29  */
30 u64 notrace timer_early_get_count(void)
31 {
32         /* At this stage raw timer is used */
33         return readl(TEGRA_TIMER_USEC_CNTR);
34 }
35
36 unsigned long notrace timer_early_get_rate(void)
37 {
38         return TEGRA_TIMER_RATE;
39 }
40
41 ulong timer_get_boot_us(void)
42 {
43         return timer_early_get_count();
44 }
45
46 /*
47  * At moment of calling get_count, timer driver is already
48  * probed and is configured to have precise 1MHz clock.
49  * Tegra timer has a step of 1 microsecond which removes
50  * need of using adjusments involving uc_priv->clock_rate.
51  */
52 static notrace u64 tegra_timer_get_count(struct udevice *dev)
53 {
54         u32 val = timer_early_get_count();
55         return timer_conv_64(val);
56 }
57
58 static int tegra_timer_probe(struct udevice *dev)
59 {
60         struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
61         u32 usec_config, value;
62
63         /* Timer rate has to be set unconditionally */
64         uc_priv->clock_rate = TEGRA_TIMER_RATE;
65
66         /*
67          * Configure microsecond timers to have 1MHz clock
68          * Config register is 0xqqww, where qq is "dividend", ww is "divisor"
69          * Uses n+1 scheme
70          */
71         switch (clock_get_rate(CLOCK_ID_CLK_M)) {
72         case 12000000:
73                 usec_config = 0x000b; /* (11+1)/(0+1) */
74                 break;
75         case 12800000:
76                 usec_config = 0x043f; /* (63+1)/(4+1) */
77                 break;
78         case 13000000:
79                 usec_config = 0x000c; /* (12+1)/(0+1) */
80                 break;
81         case 16800000:
82                 usec_config = 0x0453; /* (83+1)/(4+1) */
83                 break;
84         case 19200000:
85                 usec_config = 0x045f; /* (95+1)/(4+1) */
86                 break;
87         case 26000000:
88                 usec_config = 0x0019; /* (25+1)/(0+1) */
89                 break;
90         case 38400000:
91                 usec_config = 0x04bf; /* (191+1)/(4+1) */
92                 break;
93         case 48000000:
94                 usec_config = 0x002f; /* (47+1)/(0+1) */
95                 break;
96         default:
97                 return -EINVAL;
98         }
99
100         /* Enable clock to timer hardware */
101         value = readl_relaxed(TEGRA_OSC_CLK_ENB_L_SET);
102         writel_relaxed(value | TEGRA_OSC_SET_CLK_ENB_TMR,
103                        TEGRA_OSC_CLK_ENB_L_SET);
104
105         writel_relaxed(usec_config, TEGRA_TIMER_USEC_CFG);
106
107         return 0;
108 }
109
110 static const struct timer_ops tegra_timer_ops = {
111         .get_count = tegra_timer_get_count,
112 };
113
114 static const struct udevice_id tegra_timer_ids[] = {
115         { .compatible = "nvidia,tegra20-timer" },
116         { .compatible = "nvidia,tegra30-timer" },
117         { .compatible = "nvidia,tegra114-timer" },
118         { .compatible = "nvidia,tegra124-timer" },
119         { .compatible = "nvidia,tegra210-timer" },
120         { }
121 };
122
123 U_BOOT_DRIVER(tegra_timer) = {
124         .name           = "tegra_timer",
125         .id             = UCLASS_TIMER,
126         .of_match       = tegra_timer_ids,
127         .probe          = tegra_timer_probe,
128         .ops            = &tegra_timer_ops,
129         .flags          = DM_FLAG_PRE_RELOC,
130 };