sb_scd.c revision 203697
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 203697 2010-02-09 06:24:43Z 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	INTSRC_MASK_ADDR(cpu)	\
60	(MIPS_PHYS_TO_KSEG1(0x10020028) | ((cpu) << 13))
61
62#define	INTSRC_MAP_ADDR(cpu, intsrc)	\
63	(MIPS_PHYS_TO_KSEG1(0x10020200) | ((cpu) << 13)) + (intsrc * 8)
64
65#define	MAILBOX_SET_ADDR(cpu)	\
66	(MIPS_PHYS_TO_KSEG1(0x100200C8) | ((cpu) << 13))
67
68#define	MAILBOX_CLEAR_ADDR(cpu)	\
69	(MIPS_PHYS_TO_KSEG1(0x100200D0) | ((cpu) << 13))
70
71static uint64_t
72sb_read_syscfg(void)
73{
74
75	return (sb_load64(SYSCFG_ADDR));
76}
77
78static void
79sb_write_syscfg(uint64_t val)
80{
81
82	sb_store64(SYSCFG_ADDR, val);
83}
84
85uint64_t
86sb_cpu_speed(void)
87{
88	int plldiv;
89	const uint64_t MHZ = 1000000;
90
91	plldiv = SYSCFG_PLLDIV(sb_read_syscfg());
92	if (plldiv == 0) {
93		printf("PLL_DIV is 0 - assuming 6 (300MHz).\n");
94		plldiv = 6;
95	}
96
97	return (plldiv * 50 * MHZ);
98}
99
100void
101sb_system_reset(void)
102{
103	uint64_t syscfg;
104
105	const uint64_t SYSTEM_RESET = 1ULL << 60;
106	const uint64_t EXT_RESET = 1ULL << 59;
107	const uint64_t SOFT_RESET = 1ULL << 58;
108
109	syscfg = sb_read_syscfg();
110	syscfg &= ~SOFT_RESET;
111	syscfg |= SYSTEM_RESET | EXT_RESET;
112	sb_write_syscfg(syscfg);
113}
114
115void
116sb_disable_intsrc(int cpu, int src)
117{
118	uint32_t regaddr;
119	uint64_t val;
120
121	regaddr = INTSRC_MASK_ADDR(cpu);
122
123	val = sb_load64(regaddr);
124	val |= 1ULL << src;
125	sb_store64(regaddr, val);
126}
127
128void
129sb_enable_intsrc(int cpu, int src)
130{
131	uint32_t regaddr;
132	uint64_t val;
133
134	regaddr = INTSRC_MASK_ADDR(cpu);
135
136	val = sb_load64(regaddr);
137	val &= ~(1ULL << src);
138	sb_store64(regaddr, val);
139}
140
141void
142sb_write_intsrc_mask(int cpu, uint64_t val)
143{
144	uint32_t regaddr;
145
146	regaddr = INTSRC_MASK_ADDR(cpu);
147	sb_store64(regaddr, val);
148}
149
150uint64_t
151sb_read_intsrc_mask(int cpu)
152{
153	uint32_t regaddr;
154	uint64_t val;
155
156	regaddr = INTSRC_MASK_ADDR(cpu);
157	val = sb_load64(regaddr);
158
159	return (val);
160}
161
162void
163sb_write_intmap(int cpu, int intsrc, int intrnum)
164{
165	uint32_t regaddr;
166
167	regaddr = INTSRC_MAP_ADDR(cpu, intsrc);
168	sb_store64(regaddr, intrnum);
169}
170
171int
172sb_read_intmap(int cpu, int intsrc)
173{
174	uint32_t regaddr;
175
176	regaddr = INTSRC_MAP_ADDR(cpu, intsrc);
177	return (sb_load64(regaddr) & 0x7);
178}
179
180int
181sb_route_intsrc(int intsrc)
182{
183	int intrnum;
184
185	KASSERT(intsrc >= 0 && intsrc < NUM_INTSRC,
186		("Invalid interrupt source number (%d)", intsrc));
187
188	/*
189	 * Interrupt 5 is used by sources internal to the CPU (e.g. timer).
190	 * Use a deterministic mapping for the remaining sources.
191	 */
192#ifdef SMP
193	KASSERT(platform_ipi_intrnum() == 4,
194		("Unexpected interrupt number used for IPI"));
195	intrnum = intsrc % 4;
196#else
197	intrnum = intsrc % 5;
198#endif
199
200	return (intrnum);
201}
202
203#ifdef SMP
204static uint64_t
205sb_read_sysrev(void)
206{
207
208	return (sb_load64(SYSREV_ADDR));
209}
210
211void
212sb_set_mailbox(int cpu, uint64_t val)
213{
214	uint32_t regaddr;
215
216	regaddr = MAILBOX_SET_ADDR(cpu);
217	sb_store64(regaddr, val);
218}
219
220void
221sb_clear_mailbox(int cpu, uint64_t val)
222{
223	uint32_t regaddr;
224
225	regaddr = MAILBOX_CLEAR_ADDR(cpu);
226	sb_store64(regaddr, val);
227}
228
229int
230platform_num_processors(void)
231{
232
233	return (SYSREV_NUM_PROCESSORS(sb_read_sysrev()));
234}
235#endif	/* SMP */
236
237#define	SCD_PHYSADDR	0x10000000
238#define	SCD_SIZE	0x00060000
239
240static int
241scd_probe(device_t dev)
242{
243
244	device_set_desc(dev, "Broadcom/Sibyte System Control and Debug");
245	return (0);
246}
247
248static int
249scd_attach(device_t dev)
250{
251	int rid;
252	struct resource *res;
253
254	if (bootverbose)
255		device_printf(dev, "attached.\n");
256
257	rid = 0;
258	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, SCD_PHYSADDR,
259				 SCD_PHYSADDR + SCD_SIZE - 1, SCD_SIZE, 0);
260	if (res == NULL)
261		panic("Cannot allocate resource for system control and debug.");
262
263	return (0);
264}
265
266static device_method_t scd_methods[] ={
267	/* Device interface */
268	DEVMETHOD(device_probe,		scd_probe),
269	DEVMETHOD(device_attach,	scd_attach),
270	DEVMETHOD(device_detach,	bus_generic_detach),
271	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
272	DEVMETHOD(device_suspend,	bus_generic_suspend),
273	DEVMETHOD(device_resume,	bus_generic_resume),
274
275	{ 0, 0 }
276};
277
278static driver_t scd_driver = {
279	"scd",
280	scd_methods
281};
282
283static devclass_t scd_devclass;
284
285DRIVER_MODULE(scd, zbbus, scd_driver, scd_devclass, 0, 0);
286