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