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