1*416b0bebSmacallan /* $NetBSD: uni-n.c,v 1.13 2022/12/28 07:18:29 macallan Exp $ */
298735d6cSmacallan
398735d6cSmacallan /*-
498735d6cSmacallan * Copyright (C) 2005 Michael Lorenz.
598735d6cSmacallan *
698735d6cSmacallan * Redistribution and use in source and binary forms, with or without
798735d6cSmacallan * modification, are permitted provided that the following conditions
898735d6cSmacallan * are met:
998735d6cSmacallan * 1. Redistributions of source code must retain the above copyright
1098735d6cSmacallan * notice, this list of conditions and the following disclaimer.
1198735d6cSmacallan * 2. Redistributions in binary form must reproduce the above copyright
1298735d6cSmacallan * notice, this list of conditions and the following disclaimer in the
1398735d6cSmacallan * documentation and/or other materials provided with the distribution.
1498735d6cSmacallan * 3. The name of the author may not be used to endorse or promote products
1598735d6cSmacallan * derived from this software without specific prior written permission.
1698735d6cSmacallan *
1798735d6cSmacallan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1898735d6cSmacallan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1998735d6cSmacallan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2098735d6cSmacallan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2198735d6cSmacallan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2298735d6cSmacallan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2398735d6cSmacallan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2498735d6cSmacallan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2598735d6cSmacallan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2698735d6cSmacallan * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2798735d6cSmacallan */
2898735d6cSmacallan
2998735d6cSmacallan /*
3098735d6cSmacallan * a driver to match the uni_n node in OF's device tree and attach its children
3198735d6cSmacallan */
3298735d6cSmacallan
3398735d6cSmacallan #include <sys/cdefs.h>
34*416b0bebSmacallan __KERNEL_RCSID(0, "$NetBSD: uni-n.c,v 1.13 2022/12/28 07:18:29 macallan Exp $");
3598735d6cSmacallan
3698735d6cSmacallan #include <sys/param.h>
3798735d6cSmacallan #include <sys/systm.h>
3898735d6cSmacallan #include <sys/kernel.h>
3998735d6cSmacallan #include <sys/device.h>
4098735d6cSmacallan
4198735d6cSmacallan #include <dev/ofw/openfirm.h>
42dd732ee7Smacallan #include <dev/ofw/ofw_pci.h>
4398735d6cSmacallan
4498735d6cSmacallan #include <machine/autoconf.h>
4598735d6cSmacallan
46653b75ceSmacallan #include "fcu.h"
47653b75ceSmacallan
4805b09539Smatt static void uni_n_attach(device_t, device_t, void *);
4905b09539Smatt static int uni_n_match(device_t, cfdata_t, void *);
5098735d6cSmacallan static int uni_n_print(void *, const char *);
5198735d6cSmacallan
5298735d6cSmacallan struct uni_n_softc {
53319ca643Smacallan device_t sc_dev;
54dd732ee7Smacallan struct powerpc_bus_space sc_memt;
5598735d6cSmacallan int sc_node;
5698735d6cSmacallan };
5798735d6cSmacallan
58319ca643Smacallan CFATTACH_DECL_NEW(uni_n, sizeof(struct uni_n_softc),
5998735d6cSmacallan uni_n_match, uni_n_attach, NULL, NULL);
6098735d6cSmacallan
61653b75ceSmacallan #if NFCU > 0
62653b75ceSmacallan /* storage for CPUID SEEPROM contents found on some G5 */
63653b75ceSmacallan static uint8_t eeprom[2][160];
64653b75ceSmacallan #endif
65653b75ceSmacallan
66*416b0bebSmacallan static const char *skiplist[] = {
67*416b0bebSmacallan "openpic",
68*416b0bebSmacallan "chrp,open-pic",
69*416b0bebSmacallan "open-pic",
70*416b0bebSmacallan "mpic",
71*416b0bebSmacallan "dart",
72*416b0bebSmacallan "u3-dart",
73*416b0bebSmacallan "u4-dart",
74*416b0bebSmacallan NULL
75*416b0bebSmacallan };
76*416b0bebSmacallan
7798735d6cSmacallan int
uni_n_match(device_t parent,cfdata_t cf,void * aux)7805b09539Smatt uni_n_match(device_t parent, cfdata_t cf, void *aux)
7998735d6cSmacallan {
8098735d6cSmacallan struct confargs *ca = aux;
8198735d6cSmacallan char compat[32];
82dd732ee7Smacallan if ((strcmp(ca->ca_name, "uni-n") != 0) &&
83cf0535baSmacallan (strcmp(ca->ca_name, "u4") != 0) &&
84cf0535baSmacallan (strcmp(ca->ca_name, "u3") != 0))
8598735d6cSmacallan return 0;
8698735d6cSmacallan
8798735d6cSmacallan memset(compat, 0, sizeof(compat));
88dd732ee7Smacallan #if 0
8998735d6cSmacallan OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
9098735d6cSmacallan if (strcmp(compat, "uni-north") != 0)
9198735d6cSmacallan return 0;
92dd732ee7Smacallan #endif
9398735d6cSmacallan return 1;
9498735d6cSmacallan }
9598735d6cSmacallan
9698735d6cSmacallan /*
9798735d6cSmacallan * Attach all the sub-devices we can find
9898735d6cSmacallan */
9998735d6cSmacallan void
uni_n_attach(device_t parent,device_t self,void * aux)10005b09539Smatt uni_n_attach(device_t parent, device_t self, void *aux)
10198735d6cSmacallan {
10205b09539Smatt struct uni_n_softc *sc = device_private(self);
10398735d6cSmacallan struct confargs *our_ca = aux;
10498735d6cSmacallan struct confargs ca;
10598735d6cSmacallan int node, child, namelen;
106653b75ceSmacallan #if NFCU > 0
107653b75ceSmacallan int cpuid;
108653b75ceSmacallan #endif
10998735d6cSmacallan u_int reg[20];
11098735d6cSmacallan int intr[6];
11198735d6cSmacallan char name[32];
11298735d6cSmacallan
113319ca643Smacallan sc->sc_dev = self;
114dd732ee7Smacallan node = our_ca->ca_node;
11598735d6cSmacallan sc->sc_node = node;
116653b75ceSmacallan printf(" address 0x%08x\n",
117653b75ceSmacallan our_ca->ca_reg[our_ca->ca_nreg > 8 ? 1 : 0]);
118653b75ceSmacallan
119653b75ceSmacallan #if NFCU > 0
120653b75ceSmacallan /*
121653b75ceSmacallan * zero out eeprom blocks, then see if we have valid data
122*416b0bebSmacallan * doing this here because the EEPROMs are dangling from our i2c bus
123653b75ceSmacallan * but we can get all the data just from looking at the properties
124653b75ceSmacallan */
125653b75ceSmacallan memset(eeprom, 0, sizeof(eeprom));
126653b75ceSmacallan cpuid = OF_finddevice("/u3/i2c/cpuid@a0");
127653b75ceSmacallan OF_getprop(cpuid, "cpuid", eeprom[0], sizeof(eeprom[0]));
128653b75ceSmacallan if (eeprom[0][1] != 0)
129653b75ceSmacallan aprint_normal_dev(self, "found EEPROM data for CPU 0\n");
130*416b0bebSmacallan
131653b75ceSmacallan cpuid = OF_finddevice("/u3/i2c/cpuid@a2");
132653b75ceSmacallan OF_getprop(cpuid, "cpuid", eeprom[1], sizeof(eeprom[1]));
133653b75ceSmacallan if (eeprom[1][1] != 0)
134653b75ceSmacallan aprint_normal_dev(self, "found EEPROM data for CPU 1\n");
135653b75ceSmacallan #endif
13698735d6cSmacallan
137dd732ee7Smacallan memset(&sc->sc_memt, 0, sizeof(struct powerpc_bus_space));
138dd732ee7Smacallan sc->sc_memt.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE;
139dd732ee7Smacallan if (ofwoea_map_space(RANGE_TYPE_MACIO, RANGE_MEM, node, &sc->sc_memt,
140dd732ee7Smacallan "uni-n mem-space") != 0) {
141dd732ee7Smacallan panic("Can't init uni-n mem tag");
142dd732ee7Smacallan }
143dd732ee7Smacallan
1443944ff70Sthorpej devhandle_t selfh = device_handle(self);
14598735d6cSmacallan for (child = OF_child(node); child; child = OF_peer(child)) {
146*416b0bebSmacallan if (of_compatible(child, skiplist)) continue;
14798735d6cSmacallan namelen = OF_getprop(child, "name", name, sizeof(name));
14898735d6cSmacallan if (namelen < 0)
14998735d6cSmacallan continue;
15098735d6cSmacallan if (namelen >= sizeof(name))
15198735d6cSmacallan continue;
15298735d6cSmacallan
15398735d6cSmacallan name[namelen] = 0;
15498735d6cSmacallan ca.ca_name = name;
15598735d6cSmacallan ca.ca_node = child;
156dd732ee7Smacallan ca.ca_tag = &sc->sc_memt;
15798735d6cSmacallan ca.ca_nreg = OF_getprop(child, "reg", reg, sizeof(reg));
15898735d6cSmacallan ca.ca_nintr = OF_getprop(child, "AAPL,interrupts", intr,
15998735d6cSmacallan sizeof(intr));
16098735d6cSmacallan if (ca.ca_nintr == -1)
16198735d6cSmacallan ca.ca_nintr = OF_getprop(child, "interrupts", intr,
16298735d6cSmacallan sizeof(intr));
16398735d6cSmacallan
16498735d6cSmacallan ca.ca_reg = reg;
16598735d6cSmacallan ca.ca_intr = intr;
1662685996bSthorpej config_found(self, &ca, uni_n_print,
1673944ff70Sthorpej CFARGS(.devhandle = devhandle_from_of(selfh, child)));
16898735d6cSmacallan }
16998735d6cSmacallan }
17098735d6cSmacallan
17198735d6cSmacallan int
uni_n_print(void * aux,const char * uni_n)172454af1c0Sdsl uni_n_print(void *aux, const char *uni_n)
17398735d6cSmacallan {
17498735d6cSmacallan struct confargs *ca = aux;
17598735d6cSmacallan if (uni_n)
17698735d6cSmacallan aprint_normal("%s at %s", ca->ca_name, uni_n);
17798735d6cSmacallan
17898735d6cSmacallan if (ca->ca_nreg > 0)
17998735d6cSmacallan aprint_normal(" address 0x%x", ca->ca_reg[0]);
18098735d6cSmacallan
18198735d6cSmacallan return UNCONF;
18298735d6cSmacallan }
183653b75ceSmacallan
184653b75ceSmacallan #if NFCU > 0
185653b75ceSmacallan int
get_cpuid(int cpu,uint8_t * buf)186653b75ceSmacallan get_cpuid(int cpu, uint8_t *buf)
187653b75ceSmacallan {
188653b75ceSmacallan if ((cpu < 0) || (cpu > 1)) return -1;
189653b75ceSmacallan if (eeprom[cpu][1] == 0) return 0;
190653b75ceSmacallan memcpy(buf, eeprom[cpu], sizeof(eeprom[cpu]));
191653b75ceSmacallan return sizeof(eeprom[cpu]);
192653b75ceSmacallan }
193653b75ceSmacallan #endif
194