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 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 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 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 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 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 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