1*f82ca6eeSskrll /* $NetBSD: iomd.c,v 1.24 2022/09/27 06:36:42 skrll Exp $ */
27d4a1addSreinoud
37d4a1addSreinoud /*
47d4a1addSreinoud * Copyright (c) 1996-1997 Mark Brinicombe.
57d4a1addSreinoud * Copyright (c) 1997 Causality Limited
67d4a1addSreinoud * All rights reserved.
77d4a1addSreinoud *
87d4a1addSreinoud * Redistribution and use in source and binary forms, with or without
97d4a1addSreinoud * modification, are permitted provided that the following conditions
107d4a1addSreinoud * are met:
117d4a1addSreinoud * 1. Redistributions of source code must retain the above copyright
127d4a1addSreinoud * notice, this list of conditions and the following disclaimer.
137d4a1addSreinoud * 2. Redistributions in binary form must reproduce the above copyright
147d4a1addSreinoud * notice, this list of conditions and the following disclaimer in the
157d4a1addSreinoud * documentation and/or other materials provided with the distribution.
167d4a1addSreinoud * 3. All advertising materials mentioning features or use of this software
177d4a1addSreinoud * must display the following acknowledgement:
187d4a1addSreinoud * This product includes software developed by Mark Brinicombe.
197d4a1addSreinoud * 4. The name of the company nor the name of the author may be used to
207d4a1addSreinoud * endorse or promote products derived from this software without specific
217d4a1addSreinoud * prior written permission.
227d4a1addSreinoud *
237d4a1addSreinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
247d4a1addSreinoud * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
257d4a1addSreinoud * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
267d4a1addSreinoud * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
277d4a1addSreinoud * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
287d4a1addSreinoud * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
297d4a1addSreinoud * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
307d4a1addSreinoud * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
317d4a1addSreinoud * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
327d4a1addSreinoud * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
337d4a1addSreinoud * SUCH DAMAGE.
347d4a1addSreinoud *
357d4a1addSreinoud * RiscBSD kernel project
367d4a1addSreinoud *
377d4a1addSreinoud * iomd.c
387d4a1addSreinoud *
397d4a1addSreinoud * Probing and configuration for the IOMD
407d4a1addSreinoud *
417d4a1addSreinoud * Created : 10/10/95
427d4a1addSreinoud * Updated : 18/03/01 for rpckbd as part of the wscons project
437d4a1addSreinoud */
447d4a1addSreinoud
4508716eaeSlukem #include <sys/cdefs.h>
46*f82ca6eeSskrll __KERNEL_RCSID(0, "$NetBSD: iomd.c,v 1.24 2022/09/27 06:36:42 skrll Exp $");
4708716eaeSlukem
487d4a1addSreinoud #include <sys/param.h>
497d4a1addSreinoud #include <sys/systm.h>
507d4a1addSreinoud #include <sys/kernel.h>
517d4a1addSreinoud #include <sys/conf.h>
527d4a1addSreinoud #include <sys/device.h>
53ed9977b1Sdyoung #include <sys/bus.h>
547d4a1addSreinoud #include <machine/cpu.h>
5528466919Sthorpej #include <machine/intr.h>
567d4a1addSreinoud #include <arm/iomd/iomdreg.h>
577d4a1addSreinoud #include <arm/iomd/iomdvar.h>
587d4a1addSreinoud
597d4a1addSreinoud #include "iomd.h"
607d4a1addSreinoud
617d4a1addSreinoud /*
627d4a1addSreinoud * IOMD device.
637d4a1addSreinoud *
647d4a1addSreinoud * This probes and attaches the top level IOMD device.
657d4a1addSreinoud * It then configures any children of the IOMD device.
667d4a1addSreinoud */
677d4a1addSreinoud
687d4a1addSreinoud /*
697d4a1addSreinoud * IOMD softc structure.
707d4a1addSreinoud *
717d4a1addSreinoud * Contains the device node, bus space tag, handle and address
727d4a1addSreinoud * and the IOMD id.
737d4a1addSreinoud */
747d4a1addSreinoud
757d4a1addSreinoud struct iomd_softc {
76e0f866efSskrll device_t sc_dev; /* device node */
777d4a1addSreinoud bus_space_tag_t sc_iot; /* bus tag */
787d4a1addSreinoud bus_space_handle_t sc_ioh; /* bus handle */
797d4a1addSreinoud int sc_id; /* IOMD id */
807d4a1addSreinoud };
817d4a1addSreinoud
82e0f866efSskrll static int iomdmatch(device_t parent, cfdata_t cf, void *aux);
83e0f866efSskrll static void iomdattach(device_t parent, device_t self, void *aux);
84758ec341Sbjh21 static int iomdprint(void *aux, const char *iomdbus);
857d4a1addSreinoud
86e0f866efSskrll CFATTACH_DECL_NEW(iomd, sizeof(struct iomd_softc),
87bd5bb465Sthorpej iomdmatch, iomdattach, NULL, NULL);
887d4a1addSreinoud
897d4a1addSreinoud extern struct bus_space iomd_bs_tag;
907d4a1addSreinoud
917d4a1addSreinoud int iomd_found;
929ea87d7dSskrll uint32_t iomd_base = IOMD_BASE;
937d4a1addSreinoud
947d4a1addSreinoud /* following flag is used in iomd_irq.s ... has to be cleaned up one day ! */
959ea87d7dSskrll uint32_t arm7500_ioc_found = 0;
967d4a1addSreinoud
977d4a1addSreinoud
987d4a1addSreinoud /* Declare prototypes */
997d4a1addSreinoud
1007d4a1addSreinoud /*
1017d4a1addSreinoud * int iomdprint(void *aux, const char *name)
1027d4a1addSreinoud *
1037d4a1addSreinoud * print configuration info for children
1047d4a1addSreinoud */
1057d4a1addSreinoud
1067d4a1addSreinoud static int
iomdprint(void * aux,const char * name)107758ec341Sbjh21 iomdprint(void *aux, const char *name)
1087d4a1addSreinoud {
1097d4a1addSreinoud /* union iomd_attach_args *ia = aux;*/
1107d4a1addSreinoud
111758ec341Sbjh21 return QUIET;
1127d4a1addSreinoud }
1137d4a1addSreinoud
1147d4a1addSreinoud /*
115e0f866efSskrll * int iomdmatch(device_t parent, cfdata_t cf, void *aux)
1167d4a1addSreinoud *
1177d4a1addSreinoud * Just return ok for this if it is device 0
1187d4a1addSreinoud */
1197d4a1addSreinoud
1207d4a1addSreinoud static int
iomdmatch(device_t parent,cfdata_t cf,void * aux)121e0f866efSskrll iomdmatch(device_t parent, cfdata_t cf, void *aux)
1227d4a1addSreinoud {
123758ec341Sbjh21
1247d4a1addSreinoud if (iomd_found)
1257d4a1addSreinoud return 0;
1267d4a1addSreinoud return 1;
1277d4a1addSreinoud }
1287d4a1addSreinoud
1297d4a1addSreinoud
1307d4a1addSreinoud /*
131e0f866efSskrll * void iomdattach(device_t parent, device_t dev, void *aux)
1327d4a1addSreinoud *
1337d4a1addSreinoud * Map the IOMD and identify it.
1347d4a1addSreinoud * Then configure the child devices based on the IOMD ID.
1357d4a1addSreinoud */
1367d4a1addSreinoud
1377d4a1addSreinoud static void
iomdattach(device_t parent,device_t self,void * aux)138e0f866efSskrll iomdattach(device_t parent, device_t self, void *aux)
1397d4a1addSreinoud {
140e0f866efSskrll struct iomd_softc *sc = device_private(self);
1417d4a1addSreinoud /* struct mainbus_attach_args *mb = aux;*/
1427d4a1addSreinoud int refresh;
1437d4a1addSreinoud #if 0
144bd4a91a8Sbjh21 int i, tmp;
1457d4a1addSreinoud #endif
1467d4a1addSreinoud union iomd_attach_args ia;
1477d4a1addSreinoud bus_space_tag_t iot;
1487d4a1addSreinoud bus_space_handle_t ioh;
1497d4a1addSreinoud
1507d4a1addSreinoud /* There can be only 1 IOMD. */
1517d4a1addSreinoud iomd_found = 1;
1527d4a1addSreinoud
153e0f866efSskrll sc->sc_dev = self;
1547d4a1addSreinoud iot = sc->sc_iot = &iomd_bs_tag;
1557d4a1addSreinoud
1567d4a1addSreinoud /* Map the IOMD */
1577d4a1addSreinoud if (bus_space_map(iot, (int) iomd_base, IOMD_SIZE, 0, &ioh))
158bb9f3ca9Sskrll panic("%s: Cannot map registers", device_xname(self));
1597d4a1addSreinoud
1607d4a1addSreinoud sc->sc_ioh = ioh;
1617d4a1addSreinoud
1627d4a1addSreinoud /* Get the ID */
1637d4a1addSreinoud sc->sc_id = bus_space_read_1(iot, ioh, IOMD_ID0)
1647d4a1addSreinoud | (bus_space_read_1(iot, ioh, IOMD_ID1) << 8);
165e0f866efSskrll aprint_normal(": ");
1667d4a1addSreinoud
1677d4a1addSreinoud /* Identify it and get the DRAM refresh rate */
1687d4a1addSreinoud switch (sc->sc_id) {
1697d4a1addSreinoud case ARM7500_IOC_ID:
170e0f866efSskrll aprint_normal("ARM7500 IOMD ");
1717d4a1addSreinoud refresh = bus_space_read_1(iot, ioh, IOMD_REFCR) & 0x0f;
1727d4a1addSreinoud arm7500_ioc_found = 1;
1737d4a1addSreinoud break;
1747d4a1addSreinoud case ARM7500FE_IOC_ID:
175e0f866efSskrll aprint_normal("ARM7500FE IOMD ");
1767d4a1addSreinoud refresh = bus_space_read_1(iot, ioh, IOMD_REFCR) & 0x0f;
1777d4a1addSreinoud arm7500_ioc_found = 1;
1787d4a1addSreinoud break;
1797d4a1addSreinoud case RPC600_IOMD_ID:
180e0f866efSskrll aprint_normal("IOMD20 ");
1817d4a1addSreinoud refresh = bus_space_read_1(iot, ioh, IOMD_VREFCR) & 0x09;
1827d4a1addSreinoud arm7500_ioc_found = 0;
1837d4a1addSreinoud break;
1847d4a1addSreinoud default:
185e0f866efSskrll aprint_normal("Unknown IOMD ID=%04x ", sc->sc_id);
1867d4a1addSreinoud refresh = -1;
1877d4a1addSreinoud arm7500_ioc_found = 0; /* just in case */
1887d4a1addSreinoud break;
1897d4a1addSreinoud }
190e0f866efSskrll aprint_normal("version %d\n", bus_space_read_1(iot, ioh, IOMD_VERSION));
1917d4a1addSreinoud
1927d4a1addSreinoud /* Report the DRAM refresh rate */
193bb9f3ca9Sskrll aprint_normal("%s: ", device_xname(self));
194e0f866efSskrll aprint_normal("DRAM refresh=");
1957d4a1addSreinoud switch (refresh) {
1967d4a1addSreinoud case 0x0:
197e0f866efSskrll aprint_normal("off");
1987d4a1addSreinoud break;
1997d4a1addSreinoud case 0x1:
200e0f866efSskrll aprint_normal("16us");
2017d4a1addSreinoud break;
2027d4a1addSreinoud case 0x2:
203e0f866efSskrll aprint_normal("32us");
2047d4a1addSreinoud break;
2057d4a1addSreinoud case 0x4:
206e0f866efSskrll aprint_normal("64us");
2077d4a1addSreinoud break;
2087d4a1addSreinoud case 0x8:
209e0f866efSskrll aprint_normal("128us");
2107d4a1addSreinoud break;
2117d4a1addSreinoud default:
212e0f866efSskrll aprint_normal("unknown [%02x]", refresh);
2137d4a1addSreinoud break;
2147d4a1addSreinoud }
2157d4a1addSreinoud
216e0f866efSskrll aprint_normal("\n");
2177d4a1addSreinoud #if 0
2187d4a1addSreinoud /*
2197d4a1addSreinoud * No point in reporting this as it may get changed when devices are
2207d4a1addSreinoud * attached
2217d4a1addSreinoud */
222bd4a91a8Sbjh21 tmp = bus_space_read_1(iot, ioh, IOMD_IOTCR);
223bb9f3ca9Sskrll aprint_normal("%s: I/O timings: combo %c, NPCCS1/2 %c", device_xname(self),
224bd4a91a8Sbjh21 'A' + ((tmp >>2) & 3), 'A' + (tmp & 3));
225bd4a91a8Sbjh21 tmp = bus_space_read_1(iot, ioh, IOMD_ECTCR);
226e0f866efSskrll aprint_normal(", EASI ");
227bd4a91a8Sbjh21 for (i = 0; i < 8; i++, tmp >>= 1)
228e0f866efSskrll aprint_normal("%c", 'A' + ((tmp & 1) << 2));
229bd4a91a8Sbjh21 tmp = bus_space_read_1(iot, ioh, IOMD_DMATCR);
230e0f866efSskrll aprint_normal(", DMA ");
231bd4a91a8Sbjh21 for (i = 0; i < 4; i++, tmp >>= 2)
232e0f866efSskrll aprint_normal("%c", 'A' + (tmp & 3));
233e0f866efSskrll aprint_normal("\n");
234bd4a91a8Sbjh21 #endif
2357d4a1addSreinoud
2367d4a1addSreinoud /* Set up the external DMA channels */
2374cbd24b2Swiz /* XXX - this should be machine dependent not IOMD dependent */
2387d4a1addSreinoud switch (sc->sc_id) {
2397d4a1addSreinoud case ARM7500_IOC_ID:
2407d4a1addSreinoud case ARM7500FE_IOC_ID:
2417d4a1addSreinoud break;
2427d4a1addSreinoud case RPC600_IOMD_ID:
2437d4a1addSreinoud /* DMA channels 2 & 3 are external */
2447d4a1addSreinoud bus_space_write_1(iot, ioh, IOMD_DMAEXT, 0x0c);
2457d4a1addSreinoud break;
2467d4a1addSreinoud }
2477d4a1addSreinoud
2487d4a1addSreinoud /* Configure the child devices */
2497d4a1addSreinoud
2507d4a1addSreinoud /* Attach clock device */
2517d4a1addSreinoud
2527d4a1addSreinoud ia.ia_clk.ca_name = "clk";
2537d4a1addSreinoud ia.ia_clk.ca_iot = iot;
2547d4a1addSreinoud ia.ia_clk.ca_ioh = ioh;
255c7fb772bSthorpej config_found(self, &ia, iomdprint, CFARGS_NONE);
2567d4a1addSreinoud
2577d4a1addSreinoud /* Attach kbd device when configured */
258df8ccd8dSbjh21 if (bus_space_subregion(iot, ioh, IOMD_KBDDAT, 8, &ia.ia_kbd.ka_ioh))
259bb9f3ca9Sskrll panic("%s: Cannot map kbd registers", device_xname(self));
2607d4a1addSreinoud ia.ia_kbd.ka_name = "kbd";
2617d4a1addSreinoud ia.ia_kbd.ka_iot = iot;
2627d4a1addSreinoud ia.ia_kbd.ka_rxirq = IRQ_KBDRX;
2637d4a1addSreinoud ia.ia_kbd.ka_txirq = IRQ_KBDTX;
264c7fb772bSthorpej config_found(self, &ia, iomdprint, CFARGS_NONE);
2657d4a1addSreinoud
2667d4a1addSreinoud /* Attach iic device */
2677d4a1addSreinoud
268df8ccd8dSbjh21 if (bus_space_subregion(iot, ioh, IOMD_IOCR, 4, &ia.ia_iic.ia_ioh))
269bb9f3ca9Sskrll panic("%s: Cannot map iic registers", device_xname(self));
2707d4a1addSreinoud ia.ia_iic.ia_name = "iic";
2717d4a1addSreinoud ia.ia_iic.ia_iot = iot;
2727d4a1addSreinoud ia.ia_iic.ia_irq = -1;
273c7fb772bSthorpej config_found(self, &ia, iomdprint, CFARGS_NONE);
2747d4a1addSreinoud
2757d4a1addSreinoud switch (sc->sc_id) {
2767d4a1addSreinoud case ARM7500_IOC_ID:
2777d4a1addSreinoud case ARM7500FE_IOC_ID:
278d79f4782Swiz /* Attach opms device */
2797d4a1addSreinoud
280df8ccd8dSbjh21 if (bus_space_subregion(iot, ioh, IOMD_MSDATA, 8,
281ed4b80b1Sbjh21 &ia.ia_opms.pa_ioh))
282bb9f3ca9Sskrll panic("%s: Cannot map opms registers", device_xname(self));
283d79f4782Swiz ia.ia_opms.pa_name = "opms";
284d79f4782Swiz ia.ia_opms.pa_iot = iot;
285d79f4782Swiz ia.ia_opms.pa_irq = IRQ_MSDRX;
286c7fb772bSthorpej config_found(self, &ia, iomdprint, CFARGS_NONE);
2877d4a1addSreinoud break;
2887d4a1addSreinoud case RPC600_IOMD_ID:
2897d4a1addSreinoud /* Attach (ws)qms device */
2907d4a1addSreinoud
291df8ccd8dSbjh21 if (bus_space_subregion(iot, ioh, IOMD_MOUSEX, 8,
292ed4b80b1Sbjh21 &ia.ia_qms.qa_ioh))
293bb9f3ca9Sskrll panic("%s: Cannot map qms registers", device_xname(self));
2947d4a1addSreinoud
2957d4a1addSreinoud if (bus_space_map(iot, IO_MOUSE_BUTTONS, 4, 0, &ia.ia_qms.qa_ioh_but))
296bb9f3ca9Sskrll panic("%s: Cannot map registers", device_xname(self));
2977d4a1addSreinoud ia.ia_qms.qa_name = "qms";
2987d4a1addSreinoud ia.ia_qms.qa_iot = iot;
2997d4a1addSreinoud ia.ia_qms.qa_irq = IRQ_VSYNC;
300c7fb772bSthorpej config_found(self, &ia, iomdprint, CFARGS_NONE);
3017d4a1addSreinoud break;
3027d4a1addSreinoud }
3037d4a1addSreinoud }
3047d4a1addSreinoud
3057d4a1addSreinoud /* End of iomd.c */
306