xref: /f-stack/freebsd/mips/broadcom/bcm_pmu.c (revision 22ce4aff)
1 /*-
2  * Copyright (c) 2016 Landon Fuller <[email protected]>
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 *
bcm_get_pmu(struct bcm_platform * bp)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
bcm_has_pmu(struct bcm_platform * bp)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
bcm_get_uart_clkcfg(struct bcm_platform * bp)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
bcm_get_uart_rclk(struct bcm_platform * bp)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
bcm_get_alpfreq(struct bcm_platform * bp)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
bcm_get_ilpfreq(struct bcm_platform * bp)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
bcm_get_cpufreq(struct bcm_platform * bp)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
bcm_get_sifreq(struct bcm_platform * bp)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 static uint32_t
bcm_pmu_read4(bus_size_t reg,void * ctx)281 bcm_pmu_read4(bus_size_t reg, void *ctx) {
282 	struct bcm_platform *bp = ctx;
283 	return (readl(BCM_SOC_ADDR(bp->pmu_addr, reg)));
284 }
285 
286 static void
bcm_pmu_write4(bus_size_t reg,uint32_t val,void * ctx)287 bcm_pmu_write4(bus_size_t reg, uint32_t val, void *ctx) {
288 	struct bcm_platform *bp = ctx;
289 	writel(BCM_SOC_ADDR(bp->pmu_addr, reg), val);
290 }
291 
292 static uint32_t
bcm_pmu_read_chipst(void * ctx)293 bcm_pmu_read_chipst(void *ctx)
294 {
295 	struct bcm_platform *bp = ctx;
296 	return (readl(BCM_SOC_ADDR(bp->cc_addr, CHIPC_CHIPST)));
297 }
298