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