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