sb_scd.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009 Neelkanth Natu
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/mips/sibyte/sb_scd.c 330897 2018-03-14 03:19:51Z eadler $");
31
32#include <sys/param.h>
33#include <sys/kernel.h>
34#include <sys/systm.h>
35#include <sys/module.h>
36#include <sys/bus.h>
37#include <sys/cpuset.h>
38
39#include <machine/resource.h>
40#include <machine/hwfunc.h>
41
42#include "sb_scd.h"
43
44/*
45 * We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit
46 * processor. It has some registers that must be accessed using 64-bit load
47 * and store instructions.
48 *
49 * We use the mips_ld() and mips_sd() functions to do this for us.
50 */
51#define	sb_store64(addr, val)	mips3_sd((uint64_t *)(uintptr_t)(addr), (val))
52#define	sb_load64(addr)		mips3_ld((uint64_t *)(uintptr_t)(addr))
53
54/*
55 * System Control and Debug (SCD) unit on the Sibyte ZBbus.
56 */
57
58/*
59 * Extract the value starting at bit position 'b' for 'n' bits from 'x'.
60 */
61#define	GET_VAL_64(x, b, n)	(((x) >> (b)) & ((1ULL << (n)) - 1))
62
63#define	SYSREV_ADDR		MIPS_PHYS_TO_KSEG1(0x10020000)
64#define	SYSREV_NUM_PROCESSORS(x) GET_VAL_64((x), 24, 4)
65
66#define	SYSCFG_ADDR		MIPS_PHYS_TO_KSEG1(0x10020008)
67#define SYSCFG_PLLDIV(x)	GET_VAL_64((x), 7, 5)
68
69#define	ZBBUS_CYCLE_COUNT_ADDR	MIPS_PHYS_TO_KSEG1(0x10030000)
70
71#define	INTSRC_MASK_ADDR(cpu)	\
72	(MIPS_PHYS_TO_KSEG1(0x10020028) | ((cpu) << 13))
73
74#define	INTSRC_MAP_ADDR(cpu, intsrc)	\
75	(MIPS_PHYS_TO_KSEG1(0x10020200) | ((cpu) << 13)) + (intsrc * 8)
76
77#define	MAILBOX_SET_ADDR(cpu)	\
78	(MIPS_PHYS_TO_KSEG1(0x100200C8) | ((cpu) << 13))
79
80#define	MAILBOX_CLEAR_ADDR(cpu)	\
81	(MIPS_PHYS_TO_KSEG1(0x100200D0) | ((cpu) << 13))
82
83static uint64_t
84sb_read_syscfg(void)
85{
86
87	return (sb_load64(SYSCFG_ADDR));
88}
89
90static void
91sb_write_syscfg(uint64_t val)
92{
93
94	sb_store64(SYSCFG_ADDR, val);
95}
96
97uint64_t
98sb_zbbus_cycle_count(void)
99{
100
101	return (sb_load64(ZBBUS_CYCLE_COUNT_ADDR));
102}
103
104uint64_t
105sb_cpu_speed(void)
106{
107	int plldiv;
108	const uint64_t MHZ = 1000000;
109
110	plldiv = SYSCFG_PLLDIV(sb_read_syscfg());
111	if (plldiv == 0) {
112		printf("PLL_DIV is 0 - assuming 6 (300MHz).\n");
113		plldiv = 6;
114	}
115
116	return (plldiv * 50 * MHZ);
117}
118
119void
120sb_system_reset(void)
121{
122	uint64_t syscfg;
123
124	const uint64_t SYSTEM_RESET = 1ULL << 60;
125	const uint64_t EXT_RESET = 1ULL << 59;
126	const uint64_t SOFT_RESET = 1ULL << 58;
127
128	syscfg = sb_read_syscfg();
129	syscfg &= ~SOFT_RESET;
130	syscfg |= SYSTEM_RESET | EXT_RESET;
131	sb_write_syscfg(syscfg);
132}
133
134void
135sb_disable_intsrc(int cpu, int src)
136{
137	int regaddr;
138	uint64_t val;
139
140	regaddr = INTSRC_MASK_ADDR(cpu);
141
142	val = sb_load64(regaddr);
143	val |= 1ULL << src;
144	sb_store64(regaddr, val);
145}
146
147void
148sb_enable_intsrc(int cpu, int src)
149{
150	int regaddr;
151	uint64_t val;
152
153	regaddr = INTSRC_MASK_ADDR(cpu);
154
155	val = sb_load64(regaddr);
156	val &= ~(1ULL << src);
157	sb_store64(regaddr, val);
158}
159
160void
161sb_write_intsrc_mask(int cpu, uint64_t val)
162{
163	int regaddr;
164
165	regaddr = INTSRC_MASK_ADDR(cpu);
166	sb_store64(regaddr, val);
167}
168
169uint64_t
170sb_read_intsrc_mask(int cpu)
171{
172	int regaddr;
173	uint64_t val;
174
175	regaddr = INTSRC_MASK_ADDR(cpu);
176	val = sb_load64(regaddr);
177
178	return (val);
179}
180
181void
182sb_write_intmap(int cpu, int intsrc, int intrnum)
183{
184	int regaddr;
185
186	regaddr = INTSRC_MAP_ADDR(cpu, intsrc);
187	sb_store64(regaddr, intrnum);
188}
189
190int
191sb_read_intmap(int cpu, int intsrc)
192{
193	int regaddr;
194
195	regaddr = INTSRC_MAP_ADDR(cpu, intsrc);
196	return (sb_load64(regaddr) & 0x7);
197}
198
199int
200sb_route_intsrc(int intsrc)
201{
202	int intrnum;
203
204	KASSERT(intsrc >= 0 && intsrc < NUM_INTSRC,
205		("Invalid interrupt source number (%d)", intsrc));
206
207	/*
208	 * Interrupt 5 is used by sources internal to the CPU (e.g. timer).
209	 * Use a deterministic mapping for the remaining sources.
210	 */
211#ifdef SMP
212	KASSERT(platform_ipi_intrnum() == 4,
213		("Unexpected interrupt number used for IPI"));
214	intrnum = intsrc % 4;
215#else
216	intrnum = intsrc % 5;
217#endif
218
219	return (intrnum);
220}
221
222#ifdef SMP
223static uint64_t
224sb_read_sysrev(void)
225{
226
227	return (sb_load64(SYSREV_ADDR));
228}
229
230void
231sb_set_mailbox(int cpu, uint64_t val)
232{
233	int regaddr;
234
235	regaddr = MAILBOX_SET_ADDR(cpu);
236	sb_store64(regaddr, val);
237}
238
239void
240sb_clear_mailbox(int cpu, uint64_t val)
241{
242	int regaddr;
243
244	regaddr = MAILBOX_CLEAR_ADDR(cpu);
245	sb_store64(regaddr, val);
246}
247
248void
249platform_cpu_mask(cpuset_t *mask)
250{
251	int i, s;
252
253	CPU_ZERO(mask);
254	s = SYSREV_NUM_PROCESSORS(sb_read_sysrev());
255	for (i = 0; i < s; i++)
256		CPU_SET(i, mask);
257}
258#endif	/* SMP */
259
260#define	SCD_PHYSADDR	0x10000000
261#define	SCD_SIZE	0x00060000
262
263static int
264scd_probe(device_t dev)
265{
266
267	device_set_desc(dev, "Broadcom/Sibyte System Control and Debug");
268	return (0);
269}
270
271static int
272scd_attach(device_t dev)
273{
274	int rid;
275	struct resource *res;
276
277	if (bootverbose)
278		device_printf(dev, "attached.\n");
279
280	rid = 0;
281	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, SCD_PHYSADDR,
282				 SCD_PHYSADDR + SCD_SIZE - 1, SCD_SIZE, 0);
283	if (res == NULL)
284		panic("Cannot allocate resource for system control and debug.");
285
286	return (0);
287}
288
289static device_method_t scd_methods[] ={
290	/* Device interface */
291	DEVMETHOD(device_probe,		scd_probe),
292	DEVMETHOD(device_attach,	scd_attach),
293	DEVMETHOD(device_detach,	bus_generic_detach),
294	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
295	DEVMETHOD(device_suspend,	bus_generic_suspend),
296	DEVMETHOD(device_resume,	bus_generic_resume),
297
298	{ 0, 0 }
299};
300
301static driver_t scd_driver = {
302	"scd",
303	scd_methods
304};
305
306static devclass_t scd_devclass;
307
308DRIVER_MODULE(scd, zbbus, scd_driver, scd_devclass, 0, 0);
309