gdium_machdep.c revision 1.4.6.2 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