xref: /netbsd-src/sys/arch/evbmips/loongson/gdium_machdep.c (revision 230b95665bbd3a9d1a53658a36b1053f8382a519)
1 /*	$OpenBSD: gdium_machdep.c,v 1.6 2010/05/08 21:59:56 miod 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 #include <sys/types.h>
27 
28 #include <evbmips/loongson/autoconf.h>
29 #include <evbmips/loongson/loongson_intr.h>
30 
31 #include <dev/pci/pcireg.h>
32 #include <dev/pci/pcivar.h>
33 #include <dev/pci/pcidevs.h>
34 
35 #include <mips/bonito/bonitoreg.h>
36 #include <mips/bonito/bonitovar.h>
37 
38 #include <dev/wscons/wsconsio.h>
39 #include <dev/wscons/wsdisplayvar.h>
40 #include <dev/rasops/rasops.h>
41 #include <dev/wsfont/wsfont.h>
42 #include <dev/wscons/wsdisplay_vconsvar.h>
43 
44 int	gdium_revision = 0;
45 static pcireg_t fb_addr = 0;
46 
47 void	gdium_attach_hook(device_t, device_t, struct pcibus_attach_args *);
48 void	gdium_device_register(device_t, void *);
49 int	gdium_intr_map(int, int, int, pci_intr_handle_t *);
50 void	gdium_powerdown(void);
51 void	gdium_reset(void);
52 
53 const struct bonito_config gdium_bonito = {
54 	.bc_adbase = 11,
55 
56 	.bc_gpioIE = LOONGSON_INTRMASK_GPIO,
57 	.bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR |
58 	    LOONGSON_INTRMASK_PCI_PARERR,
59 	.bc_intSteer = 0,
60 	.bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR |
61 	    LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR,
62 
63 	.bc_attach_hook = gdium_attach_hook,
64 };
65 
66 
67 const struct platform gdium_platform = {
68 	.system_type = LOONGSON_GDIUM,
69 	.vendor = "EMTEC",
70 	.product = "Gdium",
71 
72 	.bonito_config = &gdium_bonito,
73 	.isa_chipset = NULL,
74 	.legacy_io_ranges = NULL,
75 	.bonito_mips_intr = MIPS_INT_MASK_4,
76 	.isa_mips_intr = 0,
77 	.isa_intr = NULL,
78 	.p_pci_intr_map = gdium_intr_map,
79 	.irq_map = loongson2f_irqmap,
80 
81 	.setup = NULL,
82 	.device_register = gdium_device_register,
83 
84 	.powerdown = gdium_powerdown,
85 	.reset = gdium_reset
86 };
87 
88 static struct vcons_screen gdium_console_screen;
89 
90 static struct wsscreen_descr gdium_stdscreen = {
91 	.name = "std",
92 };
93 
94 void
95 gdium_attach_hook(device_t parent, device_t self,
96     struct pcibus_attach_args *pba)
97 {
98 	pci_chipset_tag_t pc = pba->pba_pc;
99 	pcireg_t id;
100 	pcitag_t tag;
101 #ifdef notyet
102 	int bar;
103 #endif
104 #if 0
105 	pcireg_t reg;
106 	int dev, func;
107 #endif
108 
109 	if (pba->pba_bus != 0)
110 		return;
111 
112 #ifdef notyet
113 	/*
114 	 * Clear all BAR of the mini PCI slot; PMON did not initialize
115 	 * it, and we do not want it to conflict with anything.
116 	 */
117 	tag = pci_make_tag(pc, 0, 13, 0);
118 	for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 4)
119 		pci_conf_write(pc, tag, bar, 0);
120 #else
121 	/*
122 	 * Force a non conflicting BAR for the wireless controller,
123 	 * until proper resource configuration code is added to
124 	 * bonito (work in progress).
125 	 */
126 	tag = pci_make_tag(pc, 0, 13, 0);
127 	pci_conf_write(pc, tag, PCI_MAPREG_START, 0x06228000);
128 #endif
129 
130 	/*
131 	 * Figure out which motherboard we are running on.
132 	 * Might not be good enough...
133 	 */
134 	tag = pci_make_tag(pc, 0, 17, 0);
135 	id = pci_conf_read(pc, tag, PCI_ID_REG);
136 	if (id == PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
137 		gdium_revision = 1;
138 
139 #if 0
140 	/*
141 	 * Tweak the usb controller capabilities.
142 	 */
143 	for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
144 		tag = pci_make_tag(pc, 0, dev, 0);
145 		id = pci_conf_read(pc, tag, PCI_ID_REG);
146 		if (id != PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
147 			continue;
148 		if (gdium_revision != 0) {
149 			reg = pci_conf_read(pc, tag, 0xe0);
150 			/* enable ports 1 and 2 */
151 			reg |= 0x00000003;
152 			pci_conf_write(pc, tag, 0xe0, reg);
153 		} else {
154 			for (func = 0; func < 2; func++) {
155 				tag = pci_make_tag(pc, 0, dev, func);
156 				id = pci_conf_read(pc, tag, PCI_ID_REG);
157 				if (PCI_VENDOR(id) != PCI_VENDOR_NEC)
158 					continue;
159 				if (PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB &&
160 				    PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB2)
161 					continue;
162 
163 				reg = pci_conf_read(pc, tag, 0xe0);
164 				/* enable ports 1 and 3, disable port 2 */
165 				reg &= ~0x00000007;
166 				reg |= 0x00000005;
167 				pci_conf_write(pc, tag, 0xe0, reg);
168 				pci_conf_write(pc, tag, 0xe4, 0x00000020);
169 			}
170 		}
171 	}
172 #endif
173 }
174 
175 int
176 gdium_intr_map(int dev, int fn, int pin, pci_intr_handle_t *ihp)
177 {
178 	switch (dev) {
179 	/* mini-PCI slot */
180 	case 13:	/* C D A B */
181 		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA + (pin + 1) % 4);
182 		return 0;
183 	/* Frame buffer */
184 	case 14:
185 		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA);
186 		return 0;
187 	/* USB */
188 	case 15:
189 		if (gdium_revision == 0)
190 			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
191 			    (pin - 1));
192 		else
193 			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIB);
194 		return 0;
195 	/* Ethernet */
196 	case 16:
197 		*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCID);
198 		return 0;
199 	/* USB, not present in old motherboard revision */
200 	case 17:
201 		if (gdium_revision != 0) {
202 			*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIC);
203 			return 0;
204 		} else
205 			break;
206 	default:
207 		break;
208 	}
209 
210 	return 1;
211 }
212 
213 /*
214  * Due to PMON limitations on the Gdium Liberty, we do not get boot device
215  * information from PMON.
216  *
217  * Because of this, we always pretend the G-Key port is the boot device.
218  *
219  * Note that, unlike on the Lemote machines, other USB devices gets a fixed
220  * numbering (USB0 and USB1).
221  */
222 
223 extern struct cfdriver bonito_cd;
224 extern struct cfdriver pci_cd;
225 extern struct cfdriver ehci_cd;
226 extern struct cfdriver usb_cd;
227 extern struct cfdriver uhub_cd;
228 extern struct cfdriver umass_cd;
229 extern struct cfdriver scsibus_cd;
230 extern struct cfdriver sd_cd;
231 
232 #include <dev/pci/pcivar.h>
233 #include <dev/usb/usb.h>
234 #include <dev/usb/usbdi.h>
235 
236 void
237 gdium_device_register(device_t dev, void *aux)
238 {
239 	prop_dictionary_t dict;
240 	static int gkey_chain_pos = 0;
241 	static device_t lastparent = NULL;
242 
243 	if (device_is_a(dev, "genfb") || device_is_a(dev, "voyagerfb")) {
244 		dict = device_properties(dev);
245 		/*
246 		 * this is a hack
247 		 * is_console needs to be checked against reality
248 		 */
249 		prop_dictionary_set_bool(dict, "is_console", 1);
250 		prop_dictionary_set_uint32(dict, "width", 1024);
251 		prop_dictionary_set_uint32(dict, "height", 600);
252 		prop_dictionary_set_uint32(dict, "depth", 16);
253 		prop_dictionary_set_uint32(dict, "linebytes", 2048);
254 		if (fb_addr != 0)
255 			prop_dictionary_set_uint32(dict, "address", fb_addr);
256 	}
257 	if (device_parent(dev) != lastparent && gkey_chain_pos != 0)
258 		return;
259 
260 	switch (gkey_chain_pos) {
261 	case 0:	/* bonito at mainbus */
262 		if (device_is_a(dev, "bonito"))
263 			goto advance;
264 		break;
265 	case 1:	/* pci at bonito */
266 		if (device_is_a(dev, "pci"))
267 			goto advance;
268 		break;
269 	case 2:	/* ehci at pci dev 15 */
270 		if (device_is_a(dev, "ehci")) {
271 			struct pci_attach_args *paa = aux;
272 			if (paa->pa_device == 15)
273 				goto advance;
274 		}
275 		break;
276 	case 3:	/* usb at ehci */
277 		if (device_is_a(dev, "usb"))
278 			goto advance;
279 		break;
280 	case 4:	/* uhub at usb */
281 		if (device_is_a(dev, "uhub"))
282 			goto advance;
283 		break;
284 	case 5:	/* umass at uhub port 3 */
285 		if (device_is_a(dev, "umass")) {
286 			struct usb_attach_arg *uaa = aux;
287 			if (uaa->port == 3)
288 				goto advance;
289 		}
290 		break;
291 	case 6:	/* scsibus at umass */
292 		if (device_is_a(dev, "scsibus"))
293 			goto advance;
294 		break;
295 	case 7:	/* sd at scsibus */
296 		if (booted_device == NULL)
297 			booted_device = dev;
298 		break;
299 	}
300 
301 	return;
302 
303 advance:
304 	gkey_chain_pos++;
305 	lastparent = dev;
306 }
307 
308 void
309 gdium_powerdown(void)
310 {
311 	REGVAL(BONITO_GPIODATA) |= 0x00000002;
312 	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
313 	printf("Powering down...\n");
314 	while(1) delay(1000);
315 }
316 
317 void
318 gdium_reset(void)
319 {
320 	REGVAL(BONITO_GPIODATA) &= ~0x00000002;
321 	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
322 }
323 
324 /*
325  * Early console code
326  */
327 
328 int
329 gdium_cnattach(bus_space_tag_t memt, bus_space_tag_t iot,
330     pci_chipset_tag_t pc, pcitag_t tag, pcireg_t id)
331 {
332 	struct rasops_info * const ri = &gdium_console_screen.scr_ri;
333 	long defattr;
334 	pcireg_t reg;
335 
336 
337 	/* filter out unrecognized devices */
338 	switch (id) {
339 	default:
340 		return ENODEV;
341 	case PCI_ID_CODE(PCI_VENDOR_SILMOTION, PCI_PRODUCT_SILMOTION_SM502):
342 		break;
343 	}
344 
345 	wsfont_init();
346 
347 	/* set up rasops */
348 	ri->ri_width = 1024;
349 	ri->ri_height = 600;
350 	ri->ri_depth = 16;
351 	ri->ri_stride = 0x800;
352 
353 	/* read the mapping register for the frame buffer */
354 	reg = pci_conf_read(pc, tag, PCI_MAPREG_START);
355 	fb_addr = reg;
356 
357 	ri->ri_bits = (char *)MIPS_PHYS_TO_KSEG1(BONITO_PCILO_BASE + reg);
358 	ri->ri_flg = RI_CENTER | RI_NO_AUTO;
359 
360 	memset(ri->ri_bits, 0, 0x200000);
361 
362 	/* use as much of the screen as the font permits */
363 	rasops_init(ri, 30, 80);
364 
365 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
366 	    ri->ri_width / ri->ri_font->fontwidth);
367 
368 	gdium_stdscreen.nrows = ri->ri_rows;
369 	gdium_stdscreen.ncols = ri->ri_cols;
370 	gdium_stdscreen.textops = &ri->ri_ops;
371 	gdium_stdscreen.capabilities = ri->ri_caps;
372 
373 	ri->ri_ops.allocattr(ri, 0, ri->ri_rows - 1, 0, &defattr);
374 
375 	wsdisplay_preattach(&gdium_stdscreen, ri, 0, 0, defattr);
376 
377 	return 0;
378 
379 }
380