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 }
Cache object: 77ba62d339831463b5177d0c50fae7d7
|