]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/cavium/cns11xx/econa.c
MFV: Import atf-0.21.
[FreeBSD/FreeBSD.git] / sys / arm / cavium / cns11xx / econa.c
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$");
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
53 static struct econa_softc *econa_softc;
54
55 unsigned int CPU_clock = 200000000;
56 unsigned int AHB_clock;
57 unsigned int APB_clock;
58
59 bs_protos(generic);
60 bs_protos(generic_armv4);
61
62 struct 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
169 bus_space_tag_t obio_tag = &econa_bs_tag;
170
171 static int
172 econa_probe(device_t dev)
173 {
174
175         device_set_desc(dev, "ECONA device bus");
176         return (BUS_PROBE_NOWILDCARD);
177 }
178
179 static void
180 econa_identify(driver_t *drv, device_t parent)
181 {
182
183         BUS_ADD_CHILD(parent, 0, "econaarm", 0);
184 }
185
186 struct arm32_dma_range *
187 bus_dma_get_range(void)
188 {
189
190         return (NULL);
191 }
192
193 int
194 bus_dma_get_range_nb(void)
195 {
196
197         return (0);
198 }
199
200 extern void irq_entry(void);
201
202 static void
203 econa_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
239 struct 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
252 struct 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
299 static void
300 econa_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
314 struct intc_trigger_t {
315         int mode;
316         int level;
317 };
318
319 static 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
347 static inline uint32_t
348 read_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
354 static inline void
355 write_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
361 static inline uint32_t
362 system_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
368 static inline void
369 system_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
377 static inline void
378 econa_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  */
407 static inline void
408 econa_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
437 static void
438 get_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
462 static int
463 econa_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
517 static struct resource *
518 econa_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
565 static struct resource_list *
566 econa_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
573 static int
574 econa_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
591 static int
592 econa_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
609 static int
610 econa_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
617 static int
618 econa_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
625 static int
626 econa_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
648 void
649 arm_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
657 void
658 arm_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
670 int
671 arm_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
685 void
686 cpu_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
701 void
702 power_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
729 unsigned int
730 get_tclk(void)
731 {
732
733         return CPU_clock;
734 }
735
736 static 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
753 static driver_t econa_driver = {
754         "econaarm",
755         econa_methods,
756         sizeof(struct econa_softc),
757 };
758 static devclass_t econa_devclass;
759
760 DRIVER_MODULE(econaarm, nexus, econa_driver, econa_devclass, 0, 0);