xref: /trueos/sys/arm/samsung/s3c2xx0/s3c24x0.c (revision f3fa4bdf8b98edb697d801e65b8b2bd542f15787)
1 /*	$NetBSD: s3c2410.c,v 1.4 2003/08/27 03:46:05 bsh Exp $ */
2 
3 /*
4  * Copyright (c) 2003  Genetec corporation.  All rights reserved.
5  * Written by Hiroyuki Bessho for Genetec corporation.
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  * 3. The name of Genetec corporation may not be used to endorse
16  *    or promote products derived from this software without specific prior
17  *    written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORP.
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/reboot.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/bus.h>
42 
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45 
46 #include <machine/armreg.h>
47 #include <machine/cpu.h>
48 #include <machine/bus.h>
49 
50 #include <machine/cpufunc.h>
51 #include <machine/intr.h>
52 #include <arm/samsung/s3c2xx0/s3c2410reg.h>
53 #include <arm/samsung/s3c2xx0/s3c2440reg.h>
54 #include <arm/samsung/s3c2xx0/s3c24x0var.h>
55 #include <sys/rman.h>
56 
57 #define S3C2XX0_XTAL_CLK 12000000
58 
59 bus_space_tag_t s3c2xx0_bs_tag;
60 
61 #define IPL_LEVELS 13
62 u_int irqmasks[IPL_LEVELS];
63 
64 static struct {
65 	uint32_t	idcode;
66 	const char	*name;
67 	s3c2xx0_cpu	cpu;
68 } s3c2x0_cpu_id[] = {
69 	{ CHIPID_S3C2410A, "S3C2410A", CPU_S3C2410 },
70 	{ CHIPID_S3C2440A, "S3C2440A", CPU_S3C2440 },
71 	{ CHIPID_S3C2442B, "S3C2442B", CPU_S3C2440 },
72 
73 	{ 0, NULL }
74 };
75 
76 static struct {
77 	const char *name;
78 	int prio;
79 	int unit;
80 	struct {
81 		int type;
82 		u_long start;
83 		u_long count;
84 	} res[2];
85 } s3c24x0_children[] = {
86 	{ "rtc", 0, -1, {
87 		{ SYS_RES_IOPORT, S3C24X0_RTC_PA_BASE, S3C24X0_RTC_SIZE },
88 		{ 0 },
89 	} },
90 	{ "timer", 0, -1, { { 0 }, } },
91 	{ "uart", 1, 0, {
92 		{ SYS_RES_IRQ, S3C24X0_INT_UART0, 1 },
93 		{ SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(0),
94 		  S3C24X0_UART_BASE(1) - S3C24X0_UART_BASE(0) },
95 	} },
96 	{ "uart", 1, 1, {
97 		{ SYS_RES_IRQ, S3C24X0_INT_UART1, 1 },
98 		{ SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(1),
99 		  S3C24X0_UART_BASE(2) - S3C24X0_UART_BASE(1) },
100 	} },
101 	{ "uart", 1, 2, {
102 		{ SYS_RES_IRQ, S3C24X0_INT_UART2, 1 },
103 		{ SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(2),
104 		  S3C24X0_UART_BASE(3) - S3C24X0_UART_BASE(2) },
105 	} },
106 	{ "ohci", 0, -1, {
107 		{ SYS_RES_IRQ, S3C24X0_INT_USBH, 0 },
108 		{ SYS_RES_IOPORT, S3C24X0_USBHC_PA_BASE, S3C24X0_USBHC_SIZE },
109 	} },
110 	{ NULL },
111 };
112 
113 
114 /* prototypes */
115 static device_t s3c24x0_add_child(device_t, int, const char *, int);
116 
117 static int	s3c24x0_probe(device_t);
118 static int	s3c24x0_attach(device_t);
119 static void	s3c24x0_identify(driver_t *, device_t);
120 static int	s3c24x0_setup_intr(device_t, device_t, struct resource *, int,
121         driver_filter_t *, driver_intr_t *, void *, void **);
122 static int	s3c24x0_teardown_intr(device_t, device_t, struct resource *,
123 	void *);
124 static int	s3c24x0_config_intr(device_t, int, enum intr_trigger,
125 	enum intr_polarity);
126 static struct resource *s3c24x0_alloc_resource(device_t, device_t, int, int *,
127         u_long, u_long, u_long, u_int);
128 static int s3c24x0_activate_resource(device_t, device_t, int, int,
129         struct resource *);
130 static int s3c24x0_release_resource(device_t, device_t, int, int,
131         struct resource *);
132 static struct resource_list *s3c24x0_get_resource_list(device_t, device_t);
133 
134 static void s3c24x0_identify_cpu(device_t);
135 
136 static device_method_t s3c24x0_methods[] = {
137 	DEVMETHOD(device_probe, s3c24x0_probe),
138 	DEVMETHOD(device_attach, s3c24x0_attach),
139 	DEVMETHOD(device_identify, s3c24x0_identify),
140 	DEVMETHOD(bus_setup_intr, s3c24x0_setup_intr),
141 	DEVMETHOD(bus_teardown_intr, s3c24x0_teardown_intr),
142 	DEVMETHOD(bus_config_intr, s3c24x0_config_intr),
143 	DEVMETHOD(bus_alloc_resource, s3c24x0_alloc_resource),
144 	DEVMETHOD(bus_activate_resource, s3c24x0_activate_resource),
145 	DEVMETHOD(bus_release_resource,	s3c24x0_release_resource),
146 	DEVMETHOD(bus_get_resource_list,s3c24x0_get_resource_list),
147 	DEVMETHOD(bus_set_resource,	bus_generic_rl_set_resource),
148 	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
149 	{0, 0},
150 };
151 
152 static driver_t s3c24x0_driver = {
153 	"s3c24x0",
154 	s3c24x0_methods,
155 	sizeof(struct s3c24x0_softc),
156 };
157 static devclass_t s3c24x0_devclass;
158 
159 DRIVER_MODULE(s3c24x0, nexus, s3c24x0_driver, s3c24x0_devclass, 0, 0);
160 
161 struct s3c2xx0_softc *s3c2xx0_softc = NULL;
162 
163 static device_t
s3c24x0_add_child(device_t bus,int prio,const char * name,int unit)164 s3c24x0_add_child(device_t bus, int prio, const char *name, int unit)
165 {
166 	device_t child;
167 	struct s3c2xx0_ivar *ivar;
168 
169 	child = device_add_child_ordered(bus, prio, name, unit);
170 	if (child == NULL)
171 		return (NULL);
172 
173 	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
174 	if (ivar == NULL) {
175 		device_delete_child(bus, child);
176 		printf("Can't add alloc ivar\n");
177 		return (NULL);
178 	}
179 	device_set_ivars(child, ivar);
180 	resource_list_init(&ivar->resources);
181 
182 	return (child);
183 }
184 
185 static void
s3c24x0_enable_ext_intr(unsigned int irq)186 s3c24x0_enable_ext_intr(unsigned int irq)
187 {
188 	uint32_t reg, value;
189 	int offset;
190 
191 	if (irq <= 7) {
192 		reg = GPIO_PFCON;
193 		offset = irq * 2;
194 	} else if (irq <= 23) {
195 		reg = GPIO_PGCON;
196 		offset = (irq - 8) * 2;
197 	} else
198 		return;
199 
200 	/* Make the pin an interrupt source */
201 	value = bus_space_read_4(s3c2xx0_softc->sc_iot,
202 	    s3c2xx0_softc->sc_gpio_ioh, reg);
203 	value &= ~(3 << offset);
204 	value |= 2 << offset;
205 	bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
206 	    reg, value);
207 }
208 
209 static int
s3c24x0_setup_intr(device_t dev,device_t child,struct resource * ires,int flags,driver_filter_t * filt,driver_intr_t * intr,void * arg,void ** cookiep)210 s3c24x0_setup_intr(device_t dev, device_t child,
211         struct resource *ires,  int flags, driver_filter_t *filt,
212 	driver_intr_t *intr, void *arg, void **cookiep)
213 {
214 	int error, irq;
215 
216 	error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt,
217 	    intr, arg, cookiep);
218 	if (error != 0)
219 		return (error);
220 
221 	for (irq = rman_get_start(ires); irq <= rman_get_end(ires); irq++) {
222 		if (irq >= S3C24X0_EXTIRQ_MIN && irq <= S3C24X0_EXTIRQ_MAX) {
223 			/* Enable the external interrupt pin */
224 			s3c24x0_enable_ext_intr(irq - S3C24X0_EXTIRQ_MIN);
225 		}
226 	}
227 	return (0);
228 }
229 
230 static int
s3c24x0_teardown_intr(device_t dev,device_t child,struct resource * res,void * cookie)231 s3c24x0_teardown_intr(device_t dev, device_t child, struct resource *res,
232 	void *cookie)
233 {
234 	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
235 }
236 
237 static int
s3c24x0_config_intr(device_t dev,int irq,enum intr_trigger trig,enum intr_polarity pol)238 s3c24x0_config_intr(device_t dev, int irq, enum intr_trigger trig,
239 	enum intr_polarity pol)
240 {
241 	uint32_t mask, reg, value;
242 	int offset;
243 
244 	/* Only external interrupts can be configured */
245 	if (irq < S3C24X0_EXTIRQ_MIN || irq > S3C24X0_EXTIRQ_MAX)
246 		return (EINVAL);
247 
248 	/* There is no standard trigger or polarity for the bus */
249 	if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM)
250 		return (EINVAL);
251 
252 	irq -= S3C24X0_EXTIRQ_MIN;
253 
254 	/* Get the bits to set */
255 	mask = 0;
256 	if (pol == INTR_POLARITY_LOW) {
257 		mask = 2;
258 	} else if (pol == INTR_POLARITY_HIGH) {
259 		mask = 4;
260 	}
261 	if (trig == INTR_TRIGGER_LEVEL) {
262 		mask >>= 2;
263 	}
264 
265 	/* Get the register to set */
266 	if (irq <= 7) {
267 		reg = GPIO_EXTINT(0);
268 		offset = irq * 4;
269 	} else if (irq <= 15) {
270 		reg = GPIO_EXTINT(1);
271 		offset = (irq - 8) * 4;
272 	} else if (irq <= 23) {
273 		reg = GPIO_EXTINT(2);
274 		offset = (irq - 16) * 4;
275 	} else {
276 		return (EINVAL);
277 	}
278 
279 	/* Set the new signaling method */
280 	value = bus_space_read_4(s3c2xx0_softc->sc_iot,
281 	    s3c2xx0_softc->sc_gpio_ioh, reg);
282 	value &= ~(7 << offset);
283 	value |= mask << offset;
284 	bus_space_write_4(s3c2xx0_softc->sc_iot,
285 	    s3c2xx0_softc->sc_gpio_ioh, reg, value);
286 
287 	return (0);
288 }
289 
290 static struct resource *
s3c24x0_alloc_resource(device_t bus,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags)291 s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid,
292         u_long start, u_long end, u_long count, u_int flags)
293 {
294 	struct resource_list_entry *rle;
295 	struct s3c2xx0_ivar *ivar = device_get_ivars(child);
296 	struct resource_list *rl = &ivar->resources;
297 	struct resource *res = NULL;
298 
299 	if (device_get_parent(child) != bus)
300 		return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
301 		    type, rid, start, end, count, flags));
302 
303 	rle = resource_list_find(rl, type, *rid);
304 	if (rle != NULL) {
305 		/* There is a resource list. Use it */
306 		if (rle->res)
307 			panic("Resource rid %d type %d already in use", *rid,
308 			    type);
309 		if (start == 0UL && end == ~0UL) {
310 			start = rle->start;
311 			count = ulmax(count, rle->count);
312 			end = ulmax(rle->end, start + count - 1);
313 		}
314 		/*
315 		 * When allocating an irq with children irq's really
316 		 * allocate the children as it is those we are interested
317 		 * in receiving, not the parent.
318 		 */
319 		if (type == SYS_RES_IRQ && start == end) {
320 			switch (start) {
321 			case S3C24X0_INT_ADCTC:
322 				start = S3C24X0_INT_TC;
323 				end = S3C24X0_INT_ADC;
324 				break;
325 #ifdef S3C2440_INT_CAM
326 			case S3C2440_INT_CAM:
327 				start = S3C2440_INT_CAM_C;
328 				end = S3C2440_INT_CAM_P;
329 				break;
330 #endif
331 			default:
332 				break;
333 			}
334 			count = end - start + 1;
335 		}
336 	}
337 
338 	switch (type) {
339 	case SYS_RES_IRQ:
340 		res = rman_reserve_resource(
341 		    &s3c2xx0_softc->s3c2xx0_irq_rman, start, end,
342 		    count, flags, child);
343 		break;
344 
345 	case SYS_RES_IOPORT:
346 	case SYS_RES_MEMORY:
347 		res = rman_reserve_resource(
348 		    &s3c2xx0_softc->s3c2xx0_mem_rman,
349 		    start, end, count, flags, child);
350 		if (res == NULL)
351 			panic("Unable to map address space %#lX-%#lX", start,
352 			    end);
353 
354 		rman_set_bustag(res, s3c2xx0_bs_tag);
355 		rman_set_bushandle(res, start);
356 		if (flags & RF_ACTIVE) {
357 			if (bus_activate_resource(child, type, *rid, res)) {
358 				rman_release_resource(res);
359 				return (NULL);
360 			}
361 		}
362 		break;
363 	}
364 
365 	if (res != NULL) {
366 		rman_set_rid(res, *rid);
367 		if (rle != NULL) {
368 			rle->res = res;
369 			rle->start = rman_get_start(res);
370 			rle->end = rman_get_end(res);
371 			rle->count = count;
372 		}
373 	}
374 
375 	return (res);
376 }
377 
378 static int
s3c24x0_activate_resource(device_t bus,device_t child,int type,int rid,struct resource * r)379 s3c24x0_activate_resource(device_t bus, device_t child, int type, int rid,
380         struct resource *r)
381 {
382 	bus_space_handle_t p;
383 	int error;
384 
385 	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
386 		error = bus_space_map(rman_get_bustag(r),
387 		    rman_get_bushandle(r), rman_get_size(r), 0, &p);
388 		if (error)
389 			return (error);
390 		rman_set_bushandle(r, p);
391 	}
392 	return (rman_activate_resource(r));
393 }
394 
395 static int
s3c24x0_release_resource(device_t bus,device_t child,int type,int rid,struct resource * r)396 s3c24x0_release_resource(device_t bus, device_t child, int type, int rid,
397         struct resource *r)
398 {
399 	struct s3c2xx0_ivar *ivar = device_get_ivars(child);
400 	struct resource_list *rl = &ivar->resources;
401 	struct resource_list_entry *rle;
402 
403 	if (rl == NULL)
404 		return (EINVAL);
405 
406 	rle = resource_list_find(rl, type, rid);
407 	if (rle == NULL)
408 		return (EINVAL);
409 
410 	rman_release_resource(r);
411 	rle->res = NULL;
412 
413 	return 0;
414 }
415 
416 static struct resource_list *
s3c24x0_get_resource_list(device_t dev,device_t child)417 s3c24x0_get_resource_list(device_t dev, device_t child)
418 {
419 	struct s3c2xx0_ivar *ivar;
420 
421 	ivar = device_get_ivars(child);
422 	return (&(ivar->resources));
423 }
424 
425 void
s3c24x0_identify(driver_t * driver,device_t parent)426 s3c24x0_identify(driver_t *driver, device_t parent)
427 {
428 
429 	BUS_ADD_CHILD(parent, 0, "s3c24x0", 0);
430 }
431 
432 int
s3c24x0_probe(device_t dev)433 s3c24x0_probe(device_t dev)
434 {
435 	return (BUS_PROBE_NOWILDCARD);
436 }
437 
438 int
s3c24x0_attach(device_t dev)439 s3c24x0_attach(device_t dev)
440 {
441 	struct s3c24x0_softc *sc = device_get_softc(dev);
442 	bus_space_tag_t iot;
443 	device_t child;
444 	unsigned int i, j;
445 	u_long irqmax;
446 
447 	s3c2xx0_bs_tag = arm_base_bs_tag;
448 	s3c2xx0_softc = &(sc->sc_sx);
449 	sc->sc_sx.sc_iot = iot = s3c2xx0_bs_tag;
450 	s3c2xx0_softc->s3c2xx0_irq_rman.rm_type = RMAN_ARRAY;
451 	s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs";
452 	s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY;
453 	s3c2xx0_softc->s3c2xx0_mem_rman.rm_descr = "S3C24X0 Device Registers";
454 	/* Manage the registor memory space */
455 	if ((rman_init(&s3c2xx0_softc->s3c2xx0_mem_rman) != 0) ||
456 	    (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
457 	      S3C24X0_DEV_VA_OFFSET,
458 	      S3C24X0_DEV_VA_OFFSET + S3C24X0_DEV_VA_SIZE) != 0) ||
459 	    (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
460 	      S3C24X0_DEV_START, S3C24X0_DEV_STOP) != 0))
461 		panic("s3c24x0_attach: failed to set up register rman");
462 
463 	/* These are needed for things without a proper device to attach to */
464 	sc->sc_sx.sc_intctl_ioh = S3C24X0_INTCTL_BASE;
465 	sc->sc_sx.sc_gpio_ioh = S3C24X0_GPIO_BASE;
466 	sc->sc_sx.sc_clkman_ioh = S3C24X0_CLKMAN_BASE;
467 	sc->sc_sx.sc_wdt_ioh = S3C24X0_WDT_BASE;
468 	sc->sc_timer_ioh = S3C24X0_TIMER_BASE;
469 
470 	/*
471 	 * Identify the CPU
472 	 */
473 	s3c24x0_identify_cpu(dev);
474 
475 	/*
476 	 * Manage the interrupt space.
477 	 * We need to put this after s3c24x0_identify_cpu as the avaliable
478 	 * interrupts change depending on which CPU we have.
479 	 */
480 	if (sc->sc_sx.sc_cpu == CPU_S3C2410)
481 		irqmax = S3C2410_SUBIRQ_MAX;
482 	else
483 		irqmax = S3C2440_SUBIRQ_MAX;
484 	if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
485 	    rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
486 	    irqmax) != 0 ||
487 	    rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman,
488 	    S3C24X0_EXTIRQ_MIN, S3C24X0_EXTIRQ_MAX))
489 		panic("s3c24x0_attach: failed to set up IRQ rman");
490 
491 	/* calculate current clock frequency */
492 	s3c24x0_clock_freq(&sc->sc_sx);
493 	device_printf(dev, "fclk %d MHz hclk %d MHz pclk %d MHz\n",
494 	       sc->sc_sx.sc_fclk / 1000000, sc->sc_sx.sc_hclk / 1000000,
495 	       sc->sc_sx.sc_pclk / 1000000);
496 
497 	/*
498 	 * Attach children devices
499 	 */
500 
501 	for (i = 0; s3c24x0_children[i].name != NULL; i++) {
502 		child = s3c24x0_add_child(dev, s3c24x0_children[i].prio,
503 		    s3c24x0_children[i].name, s3c24x0_children[i].unit);
504 		for (j = 0; j < sizeof(s3c24x0_children[i].res) /
505 		     sizeof(s3c24x0_children[i].res[0]) &&
506 		     s3c24x0_children[i].res[j].type != 0; j++) {
507 			bus_set_resource(child,
508 			    s3c24x0_children[i].res[j].type, 0,
509 			    s3c24x0_children[i].res[j].start,
510 			    s3c24x0_children[i].res[j].count);
511 		}
512 	}
513 
514 	bus_generic_probe(dev);
515 	bus_generic_attach(dev);
516 
517 	return (0);
518 }
519 
520 static void
s3c24x0_identify_cpu(device_t dev)521 s3c24x0_identify_cpu(device_t dev)
522 {
523 	struct s3c24x0_softc *sc = device_get_softc(dev);
524 	uint32_t idcode;
525 	int i;
526 
527 	idcode = bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_gpio_ioh,
528 	    GPIO_GSTATUS1);
529 
530 	for (i = 0; s3c2x0_cpu_id[i].name != NULL; i++) {
531 		if (s3c2x0_cpu_id[i].idcode == idcode)
532 			break;
533 	}
534 	if (s3c2x0_cpu_id[i].name == NULL)
535 		panic("Unknown CPU detected ((Chip ID: %#X)", idcode);
536 	device_printf(dev, "Found %s CPU (Chip ID: %#X)\n",
537 	    s3c2x0_cpu_id[i].name, idcode);
538 	sc->sc_sx.sc_cpu = s3c2x0_cpu_id[i].cpu;
539 }
540 
541 /*
542  * fill sc_pclk, sc_hclk, sc_fclk from values of clock controller register.
543  *
544  * s3c24{1,4}0_clock_freq2() is meant to be called from kernel startup routines.
545  * s3c24x0_clock_freq() is for after kernel initialization is done.
546  *
547  * Because they can be called before bus_space is available we need to use
548  * volatile pointers rather than bus_space_read.
549  */
550 void
s3c2410_clock_freq2(vm_offset_t clkman_base,int * fclk,int * hclk,int * pclk)551 s3c2410_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk)
552 {
553 	uint32_t pllcon, divn;
554 	unsigned int mdiv, pdiv, sdiv;
555 	unsigned int f, h, p;
556 
557 	pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
558 	divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
559 
560 	mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
561 	pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
562 	sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
563 
564 	f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
565 	h = f;
566 	if (divn & S3C2410_CLKDIVN_HDIVN)
567 		h /= 2;
568 	p = h;
569 	if (divn & CLKDIVN_PDIVN)
570 		p /= 2;
571 
572 	if (fclk) *fclk = f;
573 	if (hclk) *hclk = h;
574 	if (pclk) *pclk = p;
575 }
576 
577 void
s3c2440_clock_freq2(vm_offset_t clkman_base,int * fclk,int * hclk,int * pclk)578 s3c2440_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk)
579 {
580 	uint32_t pllcon, divn, camdivn;
581 	unsigned int mdiv, pdiv, sdiv;
582 	unsigned int f, h, p;
583 
584 	pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
585 	divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
586 	camdivn = *(volatile uint32_t *)(clkman_base + S3C2440_CLKMAN_CAMDIVN);
587 
588 	mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
589 	pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
590 	sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
591 
592 	f = (2 * (mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
593 	h = f;
594 	switch((divn >> 1) & 3) {
595 	case 0:
596 		break;
597 	case 1:
598 		h /= 2;
599 		break;
600 	case 2:
601 		if ((camdivn & S3C2440_CAMDIVN_HCLK4_HALF) ==
602 		    S3C2440_CAMDIVN_HCLK4_HALF)
603 			h /= 8;
604 		else
605 			h /= 4;
606 		break;
607 	case 3:
608 		if ((camdivn & S3C2440_CAMDIVN_HCLK3_HALF) ==
609 		    S3C2440_CAMDIVN_HCLK3_HALF)
610 			h /= 6;
611 		else
612 			h /= 3;
613 		break;
614 	}
615 	p = h;
616 	if (divn & CLKDIVN_PDIVN)
617 		p /= 2;
618 
619 	if (fclk) *fclk = f;
620 	if (hclk) *hclk = h;
621 	if (pclk) *pclk = p;
622 }
623 
624 void
s3c24x0_clock_freq(struct s3c2xx0_softc * sc)625 s3c24x0_clock_freq(struct s3c2xx0_softc *sc)
626 {
627 	vm_offset_t va;
628 
629 	va = sc->sc_clkman_ioh;
630 	switch(sc->sc_cpu) {
631 	case CPU_S3C2410:
632 		s3c2410_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk,
633 		    &sc->sc_pclk);
634 		break;
635 	case CPU_S3C2440:
636 		s3c2440_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk,
637 		    &sc->sc_pclk);
638 		break;
639 	}
640 }
641 
642 void
cpu_reset(void)643 cpu_reset(void)
644 {
645 	(void) disable_interrupts(PSR_I|PSR_F);
646 
647 	bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_wdt_ioh, WDT_WTCON,
648 	    WTCON_ENABLE | WTCON_CLKSEL_16 | WTCON_ENRST);
649 	for(;;);
650 }
651 
652 void
s3c24x0_sleep(int mode __unused)653 s3c24x0_sleep(int mode __unused)
654 {
655 	int reg;
656 
657 	reg = bus_space_read_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh,
658 	    CLKMAN_CLKCON);
659 	bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh,
660 	    CLKMAN_CLKCON, reg | CLKCON_IDLE);
661 }
662 
663 
664 int
arm_get_next_irq(int last __unused)665 arm_get_next_irq(int last __unused)
666 {
667 	uint32_t intpnd;
668 	int irq, subirq;
669 
670 	if ((irq = bus_space_read_4(s3c2xx0_bs_tag,
671 	    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTOFFSET)) != 0) {
672 
673 		/* Clear the pending bit */
674 		intpnd = bus_space_read_4(s3c2xx0_bs_tag,
675 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTPND);
676 		bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh,
677 		    INTCTL_SRCPND, intpnd);
678 		bus_space_write_4(s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh,
679 		    INTCTL_INTPND, intpnd);
680 
681 		switch (irq) {
682 		case S3C24X0_INT_ADCTC:
683 		case S3C24X0_INT_UART0:
684 		case S3C24X0_INT_UART1:
685 		case S3C24X0_INT_UART2:
686 			/* Find the sub IRQ */
687 			subirq = 0x7ff;
688 			subirq &= bus_space_read_4(s3c2xx0_bs_tag,
689 			    s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND);
690 			subirq &= ~(bus_space_read_4(s3c2xx0_bs_tag,
691 			    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK));
692 			if (subirq == 0)
693 				return (irq);
694 
695 			subirq = ffs(subirq) - 1;
696 
697 			/* Clear the sub irq pending bit */
698 			bus_space_write_4(s3c2xx0_bs_tag,
699 			    s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND,
700 			    (1 << subirq));
701 
702 			/*
703 			 * Return the parent IRQ for UART
704 			 * as it is all we ever need
705 			 */
706 			if (subirq <= 8)
707 				return (irq);
708 
709 			return (S3C24X0_SUBIRQ_MIN + subirq);
710 
711 		case S3C24X0_INT_0:
712 		case S3C24X0_INT_1:
713 		case S3C24X0_INT_2:
714 		case S3C24X0_INT_3:
715 			/* There is a 1:1 mapping to the IRQ we are handling */
716 			return S3C24X0_INT_EXT(irq);
717 
718 		case S3C24X0_INT_4_7:
719 		case S3C24X0_INT_8_23:
720 			/* Find the external interrupt being called */
721 			subirq = 0x7fffff;
722 			subirq &= bus_space_read_4(s3c2xx0_bs_tag,
723 			    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND);
724 			subirq &= ~bus_space_read_4(s3c2xx0_bs_tag,
725 			    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
726 			if (subirq == 0)
727 				return (irq);
728 
729 			subirq = ffs(subirq) - 1;
730 
731 			/* Clear the external irq pending bit */
732 			bus_space_write_4(s3c2xx0_bs_tag,
733 			    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND,
734 			    (1 << subirq));
735 
736 			return S3C24X0_INT_EXT(subirq);
737 		}
738 
739 		return (irq);
740 	}
741 	return (-1);
742 }
743 
744 void
arm_mask_irq(uintptr_t irq)745 arm_mask_irq(uintptr_t irq)
746 {
747 	u_int32_t mask;
748 
749 	if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
750 		/* External interrupt 0..3 are directly mapped to irq 0..3 */
751 		irq -= S3C24X0_EXTIRQ_MIN;
752 	}
753 	if (irq < S3C24X0_SUBIRQ_MIN) {
754 		mask = bus_space_read_4(s3c2xx0_bs_tag,
755 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
756 		mask |= (1 << irq);
757 		bus_space_write_4(s3c2xx0_bs_tag,
758 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
759 	} else if (irq < S3C24X0_EXTIRQ_MIN) {
760 		mask = bus_space_read_4(s3c2xx0_bs_tag,
761 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
762 		mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN));
763 		bus_space_write_4(s3c2xx0_bs_tag,
764 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
765 	} else {
766 		mask = bus_space_read_4(s3c2xx0_bs_tag,
767 		    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
768 		mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN));
769 		bus_space_write_4(s3c2xx0_bs_tag,
770 		    s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
771 	}
772 }
773 
774 void
arm_unmask_irq(uintptr_t irq)775 arm_unmask_irq(uintptr_t irq)
776 {
777 	u_int32_t mask;
778 
779 	if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
780 		/* External interrupt 0..3 are directly mapped to irq 0..3 */
781 		irq -= S3C24X0_EXTIRQ_MIN;
782 	}
783 	if (irq < S3C24X0_SUBIRQ_MIN) {
784 		mask = bus_space_read_4(s3c2xx0_bs_tag,
785 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
786 		mask &= ~(1 << irq);
787 		bus_space_write_4(s3c2xx0_bs_tag,
788 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
789 	} else if (irq < S3C24X0_EXTIRQ_MIN) {
790 		mask = bus_space_read_4(s3c2xx0_bs_tag,
791 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
792 		mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN));
793 		bus_space_write_4(s3c2xx0_bs_tag,
794 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
795 	} else {
796 		mask = bus_space_read_4(s3c2xx0_bs_tag,
797 		    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
798 		mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN));
799 		bus_space_write_4(s3c2xx0_bs_tag,
800 		    s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
801 	}
802 }
803