econa.c revision 295832
1/*-
2 * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com>
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 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 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/arm/cavium/cns11xx/econa.c 295832 2016-02-20 01:32:58Z jhibbits $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/types.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/module.h>
37#include <sys/rman.h>
38#include <vm/vm.h>
39#include <vm/vm_kern.h>
40#include <vm/pmap.h>
41#include <vm/vm_page.h>
42#include <vm/vm_extern.h>
43
44#define	_ARM32_BUS_DMA_PRIVATE
45#include <machine/armreg.h>
46#include <machine/bus.h>
47#include <machine/intr.h>
48#include <machine/resource.h>
49
50#include "econa_reg.h"
51#include "econa_var.h"
52
53static struct econa_softc *econa_softc;
54
55unsigned int CPU_clock = 200000000;
56unsigned int AHB_clock;
57unsigned int APB_clock;
58
59bus_space_tag_t obio_tag;
60
61static int
62econa_probe(device_t dev)
63{
64
65	device_set_desc(dev, "ECONA device bus");
66	return (BUS_PROBE_NOWILDCARD);
67}
68
69static void
70econa_identify(driver_t *drv, device_t parent)
71{
72
73	BUS_ADD_CHILD(parent, 0, "econaarm", 0);
74}
75
76struct arm32_dma_range *
77bus_dma_get_range(void)
78{
79
80	return (NULL);
81}
82
83int
84bus_dma_get_range_nb(void)
85{
86
87	return (0);
88}
89
90extern void irq_entry(void);
91
92static void
93econa_add_child(device_t dev, int prio, const char *name, int unit,
94    bus_addr_t addr, bus_size_t size,
95    int irq0, int irq1,
96    int irq2, int irq3, int irq4)
97{
98	device_t kid;
99	struct econa_ivar *ivar;
100
101	kid = device_add_child_ordered(dev, prio, name, unit);
102	if (kid == NULL) {
103		printf("Can't add child %s%d ordered\n", name, unit);
104		return;
105	}
106	ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
107	if (ivar == NULL) {
108		device_delete_child(dev, kid);
109		return;
110	}
111	device_set_ivars(kid, ivar);
112	resource_list_init(&ivar->resources);
113	if (irq0 != -1)
114		bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1);
115	if (irq1 != 0)
116		bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1);
117	if (irq2 != 0)
118		bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1);
119	if (irq3 != 0)
120		bus_set_resource(kid, SYS_RES_IRQ, 3, irq3, 1);
121	if (irq4 != 0)
122		bus_set_resource(kid, SYS_RES_IRQ, 4, irq4, 1);
123
124	if (addr != 0)
125		bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size);
126
127}
128
129struct cpu_devs
130{
131	const char *name;
132	int unit;
133	bus_addr_t mem_base;
134	bus_size_t mem_len;
135	int irq0;
136	int irq1;
137	int irq2;
138	int irq3;
139	int irq4;
140};
141
142struct cpu_devs econarm_devs[] =
143{
144	{
145		"econa_ic", 0,
146		ECONA_IO_BASE + ECONA_PIC_BASE, ECONA_PIC_SIZE,
147		0
148	},
149	{
150		"system", 0,
151		ECONA_IO_BASE + ECONA_SYSTEM_BASE, ECONA_SYSTEM_SIZE,
152		0
153	},
154	{
155		"uart", 0,
156		ECONA_IO_BASE + ECONA_UART_BASE, ECONA_UART_SIZE,
157		ECONA_IRQ_UART
158	},
159	{
160		"timer", 0,
161		ECONA_IO_BASE + ECONA_TIMER_BASE, ECONA_TIMER_SIZE,
162		ECONA_IRQ_TIMER_1, ECONA_IRQ_TIMER_2
163	},
164	{
165		"ohci", 0,
166		ECONA_OHCI_VBASE, ECONA_OHCI_SIZE,
167		ECONA_IRQ_OHCI
168		},
169	{
170		"ehci", 0,
171		ECONA_EHCI_VBASE, ECONA_EHCI_SIZE,
172		ECONA_IRQ_EHCI
173	},
174	{
175		"cfi", 0,
176		ECONA_CFI_VBASE, ECONA_CFI_SIZE,
177		0
178	},
179	{
180		"ece", 0,
181		ECONA_IO_BASE + ECONA_NET_BASE, ECONA_NET_SIZE,
182		ECONA_IRQ_STATUS,
183		ECONA_IRQ_TSTC, ECONA_IRQ_FSRC,
184		ECONA_IRQ_TSQE, ECONA_IRQ_FSQF,
185	},
186	{	0, 0, 0, 0, 0, 0, 0, 0, 0 }
187};
188
189static void
190econa_cpu_add_builtin_children(device_t dev, struct econa_softc *sc)
191{
192	int i;
193	struct cpu_devs *walker;
194
195	for (i = 0, walker = econarm_devs; walker->name; i++, walker++) {
196		econa_add_child(dev, i, walker->name, walker->unit,
197		    walker->mem_base, walker->mem_len,
198		    walker->irq0,walker->irq1, walker->irq2,
199		    walker->irq3, walker->irq4);
200	}
201
202}
203
204struct intc_trigger_t {
205	int mode;
206	int level;
207};
208
209static struct intc_trigger_t intc_trigger_table[] = {
210	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
211	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
212	{INTC_EDGE_TRIGGER, INTC_FALLING_EDGE},
213	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
214	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
215	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
216	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
217	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
218	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
219	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
220	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
221	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
222	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
223	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
224	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
225	{INTC_EDGE_TRIGGER, INTC_FALLING_EDGE},
226	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
227	{INTC_TRIGGER_UNKNOWN, INTC_TRIGGER_UNKNOWN},
228	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_HIGH},
229	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
230	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
231	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
232	{INTC_EDGE_TRIGGER, INTC_RISING_EDGE},
233	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
234	{INTC_LEVEL_TRIGGER, INTC_ACTIVE_LOW},
235};
236
237static inline uint32_t
238read_4(struct econa_softc *sc, bus_size_t off)
239{
240
241	return bus_space_read_4(sc->ec_st, sc->ec_sys_sh, off);
242}
243
244static inline void
245write_4(struct econa_softc *sc, bus_size_t off, uint32_t val)
246{
247
248	return bus_space_write_4(sc->ec_st, sc->ec_sys_sh, off, val);
249}
250
251static inline uint32_t
252system_read_4(struct econa_softc *sc, bus_size_t off)
253{
254
255	return bus_space_read_4(sc->ec_st, sc->ec_system_sh, off);
256}
257
258static inline void
259system_write_4(struct econa_softc *sc, bus_size_t off, uint32_t val)
260{
261
262	return bus_space_write_4(sc->ec_st, sc->ec_system_sh, off, val);
263}
264
265
266
267static inline void
268econa_set_irq_mode(struct econa_softc * sc, unsigned int irq,
269		   unsigned int mode)
270{
271	unsigned int val;
272
273	if ((mode != INTC_LEVEL_TRIGGER) && (mode != INTC_EDGE_TRIGGER))
274		return;
275
276	val =	read_4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET);
277
278	if (mode == INTC_LEVEL_TRIGGER) {
279		if (val & (1UL << irq)) {
280			val &= ~(1UL << irq);
281			write_4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET,
282			    val);
283		}
284	} else {
285		if (!(val & (1UL << irq))) {
286			val |= (1UL << irq);
287			write_4(sc, INTC_INTERRUPT_TRIGGER_MODE_REG_OFFSET,
288			    val);
289		}
290	}
291}
292
293/*
294 * Configure interrupt trigger level to be Active High/Low
295 * or Rising/Falling Edge
296 */
297static inline void
298econa_set_irq_level(struct econa_softc * sc,
299    unsigned int irq, unsigned int level)
300{
301	unsigned int val;
302
303	if ((level != INTC_ACTIVE_HIGH) &&
304	    (level != INTC_ACTIVE_LOW) &&
305	    (level != INTC_RISING_EDGE) &&
306	    (level != INTC_FALLING_EDGE)) {
307		return;
308	}
309
310	val = read_4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET);
311
312	if ((level == INTC_ACTIVE_HIGH) || (level == INTC_RISING_EDGE)) {
313		if (val & (1UL << irq)) {
314			val &= ~(1UL << irq);
315			write_4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET,
316			    val);
317		}
318	} else {
319		if (!(val & (1UL << irq))) {
320			val |= (1UL << irq);
321			write_4(sc, INTC_INTERRUPT_TRIGGER_LEVEL_REG_OFFSET,
322			    val);
323		}
324	}
325}
326
327static void
328get_system_clock(void)
329{
330	uint32_t sclock = system_read_4(econa_softc, SYSTEM_CLOCK);
331
332	sclock = (sclock >> 6) & 0x03;
333
334	switch (sclock) {
335	case 0:
336		CPU_clock = 175000000;
337		break;
338	case 1:
339		CPU_clock = 200000000;
340		break;
341	case 2:
342		CPU_clock = 225000000;
343		break;
344	case 3:
345		CPU_clock = 250000000;
346		break;
347	}
348	AHB_clock = CPU_clock >> 1;
349	APB_clock = AHB_clock >> 1;
350}
351
352static int
353econa_attach(device_t dev)
354{
355	struct econa_softc *sc = device_get_softc(dev);
356	int i;
357
358	obio_tag = arm_base_bs_tag;
359
360	econa_softc = sc;
361	sc->ec_st = arm_base_bs_tag;
362	sc->ec_sh = ECONA_IO_BASE;
363	sc->dev = dev;
364	if (bus_space_subregion(sc->ec_st, sc->ec_sh, ECONA_PIC_BASE,
365	    ECONA_PIC_SIZE, &sc->ec_sys_sh) != 0)
366		panic("Unable to map IRQ registers");
367
368	if (bus_space_subregion(sc->ec_st, sc->ec_sh, ECONA_SYSTEM_BASE,
369	    ECONA_SYSTEM_SIZE, &sc->ec_system_sh) != 0)
370		panic("Unable to map IRQ registers");
371
372	sc->ec_irq_rman.rm_type = RMAN_ARRAY;
373	sc->ec_irq_rman.rm_descr = "ECONA IRQs";
374	sc->ec_mem_rman.rm_type = RMAN_ARRAY;
375	sc->ec_mem_rman.rm_descr = "ECONA Memory";
376	if (rman_init(&sc->ec_irq_rman) != 0 ||
377	    rman_manage_region(&sc->ec_irq_rman, 0, 31) != 0)
378		panic("econa_attach: failed to set up IRQ rman");
379	if (rman_init(&sc->ec_mem_rman) != 0 ||
380	    rman_manage_region(&sc->ec_mem_rman, 0,
381	    ~0) != 0)
382		panic("econa_attach: failed to set up memory rman");
383
384	write_4(sc, INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET, 0xffffffff);
385
386	write_4(sc, INTC_INTERRUPT_MASK_REG_OFFSET, 0xffffffff);
387
388	write_4(sc, INTC_FIQ_MODE_SELECT_REG_OFFSET, 0);
389
390	/*initialize irq*/
391	for (i = 0; i < 32; i++) {
392		if (intc_trigger_table[i].mode != INTC_TRIGGER_UNKNOWN) {
393			econa_set_irq_mode(sc,i, intc_trigger_table[i].mode);
394			econa_set_irq_level(sc, i, intc_trigger_table[i].level);
395		}
396	}
397
398	get_system_clock();
399
400	econa_cpu_add_builtin_children(dev, sc);
401
402	bus_generic_probe(dev);
403	bus_generic_attach(dev);
404	enable_interrupts(PSR_I | PSR_F);
405
406	return (0);
407}
408
409static struct resource *
410econa_alloc_resource(device_t dev, device_t child, int type, int *rid,
411    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
412{
413	struct econa_softc *sc = device_get_softc(dev);
414	struct resource_list_entry *rle;
415	struct econa_ivar *ivar = device_get_ivars(child);
416	struct resource_list *rl = &ivar->resources;
417
418	if (device_get_parent(child) != dev)
419		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
420			   type, rid, start, end, count, flags));
421
422	rle = resource_list_find(rl, type, *rid);
423	if (rle == NULL) {
424		return (NULL);
425	}
426	if (rle->res)
427		panic("Resource rid %d type %d already in use", *rid, type);
428	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
429		start = rle->start;
430		count = ulmax(count, rle->count);
431		end = ulmax(rle->end, start + count - 1);
432	}
433	switch (type)
434	{
435	case SYS_RES_IRQ:
436		rle->res = rman_reserve_resource(&sc->ec_irq_rman,
437		    start, end, count, flags, child);
438		break;
439	case SYS_RES_MEMORY:
440		rle->res = rman_reserve_resource(&sc->ec_mem_rman,
441		    start, end, count, flags, child);
442		if (rle->res != NULL) {
443			rman_set_bustag(rle->res, arm_base_bs_tag);
444			rman_set_bushandle(rle->res, start);
445		}
446		break;
447	}
448	if (rle->res) {
449		rle->start = rman_get_start(rle->res);
450		rle->end = rman_get_end(rle->res);
451		rle->count = count;
452		rman_set_rid(rle->res, *rid);
453	}
454	return (rle->res);
455}
456
457static struct resource_list *
458econa_get_resource_list(device_t dev, device_t child)
459{
460	struct econa_ivar *ivar;
461	ivar = device_get_ivars(child);
462	return (&(ivar->resources));
463}
464
465static int
466econa_release_resource(device_t dev, device_t child, int type,
467    int rid, struct resource *r)
468{
469	struct resource_list *rl;
470	struct resource_list_entry *rle;
471
472	rl = econa_get_resource_list(dev, child);
473	if (rl == NULL)
474		return (EINVAL);
475	rle = resource_list_find(rl, type, rid);
476	if (rle == NULL)
477		return (EINVAL);
478	rman_release_resource(r);
479	rle->res = NULL;
480	return (0);
481}
482
483static int
484econa_setup_intr(device_t dev, device_t child,
485    struct resource *ires, int flags, driver_filter_t *filt,
486    driver_intr_t *intr, void *arg, void **cookiep)
487{
488	int error;
489
490	if (rman_get_start(ires) == ECONA_IRQ_SYSTEM && filt == NULL)
491		panic("All system interrupt ISRs must be FILTER");
492
493	error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
494	    filt, intr, arg, cookiep);
495	if (error)
496		return (error);
497
498	return (0);
499}
500
501static int
502econa_teardown_intr(device_t dev, device_t child, struct resource *res,
503    void *cookie)
504{
505
506	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
507}
508
509static int
510econa_activate_resource(device_t bus, device_t child, int type, int rid,
511    struct resource *r)
512{
513
514	return (rman_activate_resource(r));
515}
516
517static int
518econa_print_child(device_t dev, device_t child)
519{
520	struct econa_ivar *ivars;
521	struct resource_list *rl;
522	int retval = 0;
523
524	ivars = device_get_ivars(child);
525	rl = &ivars->resources;
526
527	retval += bus_print_child_header(dev, child);
528
529	retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
530	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
531	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
532	if (device_get_flags(dev))
533		retval += printf(" flags %#x", device_get_flags(dev));
534
535	retval += bus_print_child_footer(dev, child);
536
537	return (retval);
538}
539
540void
541arm_mask_irq(uintptr_t nb)
542{
543	unsigned int value;
544
545	value = read_4(econa_softc,INTC_INTERRUPT_MASK_REG_OFFSET) | 1<<nb;
546	write_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET, value);
547}
548
549void
550arm_unmask_irq(uintptr_t nb)
551{
552	unsigned int value;
553
554	value = read_4(econa_softc,
555	    INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET) | (1 << nb);
556	write_4(econa_softc,
557	    INTC_INTERRUPT_CLEAR_EDGE_TRIGGER_REG_OFFSET, value);
558	value = read_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET)& ~(1 << nb);
559	write_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET, value);
560}
561
562int
563arm_get_next_irq(int x)
564{
565	int irq;
566
567	irq = read_4(econa_softc, INTC_INTERRUPT_STATUS_REG_OFFSET) &
568	    ~(read_4(econa_softc, INTC_INTERRUPT_MASK_REG_OFFSET));
569
570	if (irq!=0) {
571		return (ffs(irq) - 1);
572	}
573
574	return (-1);
575}
576
577void
578cpu_reset(void)
579{
580	uint32_t control;
581
582	control = system_read_4(econa_softc, RESET_CONTROL);
583	control |= GLOBAL_RESET;
584	system_write_4(econa_softc, RESET_CONTROL, control);
585	control = system_read_4(econa_softc, RESET_CONTROL);
586	control &= (~(GLOBAL_RESET));
587	system_write_4(econa_softc, RESET_CONTROL, control);
588	while (1);
589}
590
591
592
593void
594power_on_network_interface(void)
595{
596	uint32_t cfg_reg;
597	int ii;
598
599	cfg_reg =  system_read_4(econa_softc, RESET_CONTROL);
600	cfg_reg |= NET_INTERFACE_RESET;
601	/* set reset bit to HIGH active; */
602	system_write_4(econa_softc, RESET_CONTROL, cfg_reg);
603
604	/*pulse delay */
605	for (ii = 0; ii < 0xFFF; ii++)
606		DELAY(100);
607	/* set reset bit to LOW active; */
608	cfg_reg =  system_read_4(econa_softc, RESET_CONTROL);
609	cfg_reg &= ~(NET_INTERFACE_RESET);
610	system_write_4(econa_softc, RESET_CONTROL, cfg_reg);
611
612	/*pulse delay */
613	for (ii = 0; ii < 0xFFF; ii++)
614		DELAY(100);
615	cfg_reg = system_read_4(econa_softc, RESET_CONTROL);
616	cfg_reg |= NET_INTERFACE_RESET;
617	/* set reset bit to HIGH active; */
618	system_write_4(econa_softc, RESET_CONTROL, cfg_reg);
619}
620
621unsigned int
622get_tclk(void)
623{
624
625	return CPU_clock;
626}
627
628static device_method_t econa_methods[] = {
629	DEVMETHOD(device_probe,		econa_probe),
630	DEVMETHOD(device_attach,		econa_attach),
631	DEVMETHOD(device_identify,		econa_identify),
632	DEVMETHOD(bus_alloc_resource,		econa_alloc_resource),
633	DEVMETHOD(bus_setup_intr,		econa_setup_intr),
634	DEVMETHOD(bus_teardown_intr,		econa_teardown_intr),
635	DEVMETHOD(bus_activate_resource,	econa_activate_resource),
636	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
637	DEVMETHOD(bus_get_resource_list,	econa_get_resource_list),
638	DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
639	DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
640	DEVMETHOD(bus_release_resource,	econa_release_resource),
641	DEVMETHOD(bus_print_child,		econa_print_child),
642	{0, 0},
643};
644
645static driver_t econa_driver = {
646	"econaarm",
647	econa_methods,
648	sizeof(struct econa_softc),
649};
650static devclass_t econa_devclass;
651
652DRIVER_MODULE(econaarm, nexus, econa_driver, econa_devclass, 0, 0);
653