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