xref: /openbsd-src/sys/arch/loongson/loongson/gdium_machdep.c (revision 68cc39830aa48a2182a4a2976238be1f40888669)
1 /*	$OpenBSD: gdium_machdep.c,v 1.9 2023/04/13 02:19:05 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Gdium Liberty specific code and configuration data.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 
27 #include <machine/autoconf.h>
28 
29 #include <dev/pci/pcireg.h>
30 #include <dev/pci/pcivar.h>
31 #include <dev/pci/pcidevs.h>
32 
33 #include <loongson/dev/bonitoreg.h>
34 #include <loongson/dev/bonitovar.h>
35 #include <loongson/dev/bonito_irq.h>
36 
37 int	gdium_revision = 0;
38 
39 void	gdium_attach_hook(pci_chipset_tag_t);
40 void	gdium_device_register(struct device *, void *);
41 int	gdium_intr_map(int, int, int);
42 void	gdium_powerdown(void);
43 void	gdium_reset(void);
44 void	gdium_setup(void);
45 
46 const struct bonito_config gdium_bonito = {
47 	.bc_adbase = 11,
48 
49 	.bc_gpioIE = LOONGSON_INTRMASK_GPIO,
50 	.bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR |
51 	    LOONGSON_INTRMASK_PCI_PARERR,
52 	.bc_intSteer = 0,
53 	.bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR |
54 	    LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR,
55 
56 	.bc_attach_hook = gdium_attach_hook,
57 	.bc_intr_map = gdium_intr_map
58 };
59 
60 const struct platform gdium_platform = {
61 	.system_type = LOONGSON_GDIUM,
62 	.vendor = "EMTEC",
63 	.product = "Gdium",
64 
65 	.bonito_config = &gdium_bonito,
66 	.isa_chipset = NULL,
67 	.legacy_io_ranges = NULL,
68 
69 	.setup = gdium_setup,
70 	.device_register = gdium_device_register,
71 
72 	.powerdown = gdium_powerdown,
73 	.reset = gdium_reset
74 };
75 
76 void
gdium_attach_hook(pci_chipset_tag_t pc)77 gdium_attach_hook(pci_chipset_tag_t pc)
78 {
79 	pcireg_t id;
80 	pcitag_t tag;
81 #ifdef notyet
82 	int bar;
83 #endif
84 #if 0
85 	pcireg_t reg;
86 	int dev, func;
87 #endif
88 
89 #ifdef notyet
90 	/*
91 	 * Clear all BAR of the mini PCI slot; PMON did not initialize
92 	 * it, and we do not want it to conflict with anything.
93 	 */
94 	tag = pci_make_tag(pc, 0, 13, 0);
95 	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 4)
96 		pci_conf_write(pc, tag, bar, 0);
97 #else
98 	/*
99 	 * Force a non conflicting BAR for the wireless controller,
100 	 * until proper resource configuration code is added to
101 	 * bonito (work in progress).
102 	 */
103 	tag = pci_make_tag(pc, 0, 13, 0);
104 	pci_conf_write(pc, tag, PCI_MAPREG_START, 0x06228000);
105 #endif
106 
107 	/*
108 	 * Figure out which motherboard we are running on.
109 	 * Might not be good enough...
110 	 */
111 	tag = pci_make_tag(pc, 0, 17, 0);
112 	id = pci_conf_read(pc, tag, PCI_ID_REG);
113 	if (id == PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
114 		gdium_revision = 1;
115 
116 #if 0
117 	/*
118 	 * Tweak the usb controller capabilities.
119 	 */
120 	for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
121 		tag = pci_make_tag(pc, 0, dev, 0);
122 		id = pci_conf_read(pc, tag, PCI_ID_REG);
123 		if (id != PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
124 			continue;
125 		if (gdium_revision != 0) {
126 			reg = pci_conf_read(pc, tag, 0xe0);
127 			/* enable ports 1 and 2 */
128 			reg |= 0x00000003;
129 			pci_conf_write(pc, tag, 0xe0, reg);
130 		} else {
131 			for (func = 0; func < 2; func++) {
132 				tag = pci_make_tag(pc, 0, dev, func);
133 				id = pci_conf_read(pc, tag, PCI_ID_REG);
134 				if (PCI_VENDOR(id) != PCI_VENDOR_NEC)
135 					continue;
136 				if (PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB &&
137 				    PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB2)
138 					continue;
139 
140 				reg = pci_conf_read(pc, tag, 0xe0);
141 				/* enable ports 1 and 3, disable port 2 */
142 				reg &= ~0x00000007;
143 				reg |= 0x00000005;
144 				pci_conf_write(pc, tag, 0xe0, reg);
145 				pci_conf_write(pc, tag, 0xe4, 0x00000020);
146 			}
147 		}
148 	}
149 #endif
150 }
151 
152 int
gdium_intr_map(int dev,int fn,int pin)153 gdium_intr_map(int dev, int fn, int pin)
154 {
155 	switch (dev) {
156 	/* mini-PCI slot */
157 	case 13:	/* C D A B */
158 		return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA + (pin + 1) % 4);
159 	/* Frame buffer */
160 	case 14:
161 		return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA);
162 	/* USB */
163 	case 15:
164 		if (gdium_revision == 0)
165 			return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
166 			    (pin - 1));
167 		else
168 			return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIB);
169 	/* Ethernet */
170 	case 16:
171 		return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCID);
172 	/* USB, not present in old motherboard revision */
173 	case 17:
174 		if (gdium_revision != 0)
175 			return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIC);
176 		else
177 			break;
178 	default:
179 		break;
180 	}
181 
182 	return -1;
183 }
184 
185 /*
186  * Due to PMON limitations on the Gdium Liberty, we do not get boot device
187  * information from PMON.
188  *
189  * Because of this, we always pretend the G-Key port is the boot device.
190  *
191  * Note that, unlike on the Lemote machines, other USB devices gets a fixed
192  * numbering (USB0 and USB1).
193  */
194 
195 extern struct cfdriver bonito_cd;
196 extern struct cfdriver pci_cd;
197 extern struct cfdriver ehci_cd;
198 extern struct cfdriver usb_cd;
199 extern struct cfdriver uhub_cd;
200 extern struct cfdriver umass_cd;
201 extern struct cfdriver scsibus_cd;
202 extern struct cfdriver sd_cd;
203 
204 #include <dev/usb/usb.h>
205 #include <dev/usb/usbdi.h>
206 
207 void
gdium_device_register(struct device * dev,void * aux)208 gdium_device_register(struct device *dev, void *aux)
209 {
210 	struct cfdriver *cf = dev->dv_cfdata->cf_driver;
211 	static int gkey_chain_pos = 0;
212 	static struct device *lastparent = NULL;
213 
214 	if (dev->dv_parent != lastparent && gkey_chain_pos != 0)
215 		return;
216 
217 	switch (gkey_chain_pos) {
218 	case 0:	/* bonito at mainbus */
219 		if (cf == &bonito_cd)
220 			goto advance;
221 		break;
222 	case 1:	/* pci at bonito */
223 		if (cf == &pci_cd)
224 			goto advance;
225 		break;
226 	case 2:	/* ehci at pci dev 15 */
227 		if (cf == &ehci_cd) {
228 			struct pci_attach_args *paa = aux;
229 			if (paa->pa_device == 15)
230 				goto advance;
231 		}
232 		break;
233 	case 3:	/* usb at ehci */
234 		if (cf == &usb_cd)
235 			goto advance;
236 		break;
237 	case 4:	/* uhub at usb */
238 		if (cf == &uhub_cd)
239 			goto advance;
240 		break;
241 	case 5:	/* umass at uhub port 3 */
242 		if (cf == &umass_cd) {
243 			struct usb_attach_arg *uaa = aux;
244 			if (uaa->port == 3)
245 				goto advance;
246 		}
247 		break;
248 	case 6:	/* scsibus at umass */
249 		if (cf == &scsibus_cd)
250 			goto advance;
251 		break;
252 	case 7:	/* sd at scsibus */
253 		bootdv = dev;
254 		break;
255 	}
256 
257 	return;
258 
259 advance:
260 	gkey_chain_pos++;
261 	lastparent = dev;
262 }
263 
264 void
gdium_powerdown()265 gdium_powerdown()
266 {
267 	REGVAL(BONITO_GPIODATA) |= 0x00000002;
268 	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
269 }
270 
271 void
gdium_reset()272 gdium_reset()
273 {
274 	REGVAL(BONITO_GPIODATA) &= ~0x00000002;
275 	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
276 }
277 
278 void
gdium_setup()279 gdium_setup()
280 {
281 	bonito_early_setup();
282 }
283