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