]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/broadcom/bcm_pmu.c
dts: Import files from Linux 5.1
[FreeBSD/FreeBSD.git] / sys / mips / broadcom / bcm_pmu.c
1 /*-
2  * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <dev/bhnd/bhnd.h>
32
33 #include <dev/bhnd/cores/chipc/chipcreg.h>
34
35 #include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h>
36
37 #include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
38 #include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
39
40 #include "bcm_machdep.h"
41
42 static struct bhnd_pmu_query    *bcm_get_pmu(struct bcm_platform *bp);
43 static bool                      bcm_has_pmu(struct bcm_platform *bp);
44
45 static uint32_t                  bcm_pmu_read4(bus_size_t reg, void *ctx);
46 static void                      bcm_pmu_write4(bus_size_t reg, uint32_t val,
47                                      void *ctx);
48 static uint32_t                  bcm_pmu_read_chipst(void *ctx);
49
50 const struct bhnd_pmu_io bcm_pmu_soc_io = {
51         .rd4            = bcm_pmu_read4,
52         .wr4            = bcm_pmu_write4,
53         .rd_chipst      = bcm_pmu_read_chipst
54 };
55
56 /**
57  * Supported UART clock sources.
58  */
59 typedef enum {
60         BCM_UART_RCLK_PLL_T1    = 0,    /**< UART uses PLL m2 (mii/uart/mipsref) with no divisor */
61         BCM_UART_RCLK_ALP       = 1,    /**< UART uses ALP rclk with no divisor */
62         BCM_UART_RCLK_EXT       = 2,    /**< UART uses 1.8423 MHz external clock */
63         BCM_UART_RCLK_SI        = 3,    /**< UART uses backplane clock with divisor of two */
64         BCM_UART_RCLK_FIXED     = 4,    /**< UART uses fixed 88Mhz backplane clock with a divisor of 48 */
65 } bcm_uart_clksrc;
66
67 /**
68  * UART clock configuration.
69  */
70 struct bcm_uart_clkcfg {
71         bcm_uart_clksrc         src;    /**< clock source */
72         uint32_t                div;    /**< clock divisor */
73         uint32_t                freq;   /**< clock frequency (Hz) */
74 };
75
76 #define BCM_UART_RCLK_PLL_T1_DIV        1
77 #define BCM_UART_RCLK_ALP_DIV           1
78 #define BCM_UART_RCLK_EXT_HZ            1842300         /* 1.8423MHz */
79 #define BCM_UART_RCLK_EXT_DIV           1
80 #define BCM_UART_RCLK_FIXED_HZ          88000000        /* 88MHz */
81 #define BCM_UART_RCLK_FIXED_DIV         48
82
83 /* Fetch PLL type from ChipCommon capability flags */
84 #define BCM_PMU_PLL_TYPE(_bp)   \
85         CHIPC_GET_BITS(_bp->cc_caps, CHIPC_CAP_PLL)
86
87 /**
88  * Return the PMU instance, or NULL if no PMU.
89  */
90 static struct bhnd_pmu_query *
91 bcm_get_pmu(struct bcm_platform *bp)
92 {
93         if (!bcm_has_pmu(bp))
94                 return (NULL);
95         return (&bp->pmu);
96 }
97
98 /**
99  * Return true if a PMU is available, false otherwise.
100  */
101 static bool
102 bcm_has_pmu(struct bcm_platform *bp)
103 {
104         return (bp->pmu_addr != 0);
105 }
106
107 /**
108  * Determine the UART clock source for @p bp and return the
109  * corresponding clock configuration, if any.
110  */
111 static struct bcm_uart_clkcfg
112 bcm_get_uart_clkcfg(struct bcm_platform *bp)
113 {
114         struct bcm_uart_clkcfg   cfg;
115         struct bhnd_core_info   *cc_id;
116
117         cc_id = &bp->cc_id;
118
119         /* These tests are ordered by precedence. */
120
121         /* PLL M2 clock source? */
122         if (!bcm_has_pmu(bp) && BCM_PMU_PLL_TYPE(bp) == CHIPC_PLL_TYPE1) {
123                 uint32_t n, m;
124         
125                 n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
126                 m = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_M2);
127
128                 cfg = (struct bcm_uart_clkcfg) {
129                         BCM_UART_RCLK_PLL_T1,
130                         BCM_UART_RCLK_PLL_T1_DIV,
131                         bhnd_pwrctl_clock_rate(BCM_PMU_PLL_TYPE(bp), n, m)
132                 };
133         
134                 return (cfg);
135         }
136
137         /* ALP clock source? */
138         if (cc_id->hwrev != 15 && cc_id->hwrev >= 11) {
139                 cfg = (struct bcm_uart_clkcfg) {
140                         BCM_UART_RCLK_ALP,
141                         BCM_UART_RCLK_ALP_DIV,
142                         bcm_get_alpfreq(bp)
143                 };
144                 return (cfg);
145         }
146
147         /* External clock? */
148         if (CHIPC_HWREV_HAS_CORECTRL(cc_id->hwrev)) {
149                 uint32_t        corectrl, uclksel;
150                 bool            uintclk0;
151
152                 /* Fetch UART clock support flag */ 
153                 uclksel = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_UCLKSEL);
154
155                 /* Is UART using internal clock? */
156                 corectrl = BCM_CHIPC_READ_4(bp, CHIPC_CORECTRL);
157                 uintclk0 = CHIPC_GET_FLAG(corectrl, CHIPC_UARTCLKO);
158
159                 if (uintclk0 && uclksel == CHIPC_CAP_UCLKSEL_UINTCLK) {
160                         cfg = (struct bcm_uart_clkcfg) {
161                                 BCM_UART_RCLK_EXT,
162                                 BCM_UART_RCLK_EXT_DIV,
163                                 BCM_UART_RCLK_EXT_HZ
164                         };
165                         return (cfg);
166                 }
167         }
168
169         /* UART uses backplane clock? */
170         if (cc_id->hwrev == 15 || (cc_id->hwrev >= 3 && cc_id->hwrev <= 10)) {
171                 cfg = (struct bcm_uart_clkcfg) {
172                         BCM_UART_RCLK_SI,
173                         BCM_CHIPC_READ_4(bp, CHIPC_CLKDIV) & CHIPC_CLKD_UART,
174                         bcm_get_sifreq(bp)
175                 };
176
177                 return (cfg);
178         }
179
180         /* UART uses fixed clock? */
181         if (cc_id->hwrev <= 2) {
182                 cfg = (struct bcm_uart_clkcfg) {
183                         BCM_UART_RCLK_FIXED,
184                         BCM_UART_RCLK_FIXED_DIV,
185                         BCM_UART_RCLK_FIXED_HZ
186                 };
187
188                 return (cfg);
189         }
190
191         /* All cases must be accounted for above */
192         panic("unreachable - no clock config");
193 }
194
195 /**
196  * Return the UART reference clock frequency (in Hz).
197  */
198 u_int
199 bcm_get_uart_rclk(struct bcm_platform *bp)
200 {
201         struct bcm_uart_clkcfg cfg;
202
203         cfg = bcm_get_uart_clkcfg(bp);
204         return (cfg.freq / cfg.div);
205 }
206
207 /** ALP clock frequency (in Hz) */
208 uint64_t
209 bcm_get_alpfreq(struct bcm_platform *bp) {
210         if (!bcm_has_pmu(bp))
211                 return (BHND_PMU_ALP_CLOCK);
212
213         return (bhnd_pmu_alp_clock(bcm_get_pmu(bp)));
214 }
215
216 /** ILP clock frequency (in Hz) */
217 uint64_t
218 bcm_get_ilpfreq(struct bcm_platform *bp) {
219         if (!bcm_has_pmu(bp))
220                 return (BHND_PMU_ILP_CLOCK);
221
222         return (bhnd_pmu_ilp_clock(bcm_get_pmu(bp)));
223 }
224
225 /** CPU clock frequency (in Hz) */
226 uint64_t
227 bcm_get_cpufreq(struct bcm_platform *bp)
228 {
229         uint32_t                 fixed_hz;
230         uint32_t                 n, m;
231         bus_size_t               mreg;
232         uint8_t                  pll_type;
233
234         /* PMU support */
235         if (bcm_has_pmu(bp))
236                 return (bhnd_pmu_cpu_clock(bcm_get_pmu(bp)));
237
238         /*
239          * PWRCTL support
240          */
241         pll_type = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_PLL);
242         mreg = bhnd_pwrctl_cpu_clkreg_m(&bp->cid, pll_type, &fixed_hz);
243         if (mreg == 0)
244                 return (fixed_hz);
245
246         n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
247         m = BCM_CHIPC_READ_4(bp, mreg);
248
249         return (bhnd_pwrctl_cpu_clock_rate(&bp->cid, pll_type, n, m));
250         
251 }
252
253 /** Backplane clock frequency (in Hz) */
254 uint64_t
255 bcm_get_sifreq(struct bcm_platform *bp)
256 {
257         uint32_t                 fixed_hz;
258         uint32_t                 n, m;
259         bus_size_t               mreg;
260         uint8_t                  pll_type;
261
262         /* PMU support */
263         if (bcm_has_pmu(bp))
264                 return (bhnd_pmu_si_clock(bcm_get_pmu(bp)));
265
266         /*
267          * PWRCTL support
268          */
269         pll_type = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_PLL);
270         mreg = bhnd_pwrctl_si_clkreg_m(&bp->cid, pll_type, &fixed_hz);
271         if (mreg == 0)
272                 return (fixed_hz);
273
274         n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
275         m = BCM_CHIPC_READ_4(bp, mreg);
276
277         return (bhnd_pwrctl_si_clock_rate(&bp->cid, pll_type, n, m));
278 }
279
280
281 static uint32_t
282 bcm_pmu_read4(bus_size_t reg, void *ctx) {
283         struct bcm_platform *bp = ctx;
284         return (readl(BCM_SOC_ADDR(bp->pmu_addr, reg)));
285 }
286
287 static void
288 bcm_pmu_write4(bus_size_t reg, uint32_t val, void *ctx) {
289         struct bcm_platform *bp = ctx;
290         writel(BCM_SOC_ADDR(bp->pmu_addr, reg), val);
291 }
292
293 static uint32_t
294 bcm_pmu_read_chipst(void *ctx)
295 {
296         struct bcm_platform *bp = ctx;
297         return (readl(BCM_SOC_ADDR(bp->cc_addr, CHIPC_CHIPST)));
298 }