Home | History | Annotate | Line # | Download | only in loongson
gdium_machdep.c revision 1.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(struct device *, 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(struct device *dev, void *aux)
    238 {
    239 	prop_dictionary_t dict;
    240 	static int gkey_chain_pos = 0;
    241 	static struct device *lastparent = NULL;
    242 
    243 	if (dev->dv_parent != lastparent && gkey_chain_pos != 0)
    244 		return;
    245 
    246 	switch (gkey_chain_pos) {
    247 	case 0:	/* bonito at mainbus */
    248 		if (device_is_a(dev, "bonito"))
    249 			goto advance;
    250 		break;
    251 	case 1:	/* pci at bonito */
    252 		if (device_is_a(dev, "pci"))
    253 			goto advance;
    254 		break;
    255 	case 2:	/* ehci at pci dev 15 */
    256 		if (device_is_a(dev, "ehci")) {
    257 			struct pci_attach_args *paa = aux;
    258 			if (paa->pa_device == 15)
    259 				goto advance;
    260 		}
    261 		break;
    262 	case 3:	/* usb at ehci */
    263 		if (device_is_a(dev, "usb"))
    264 			goto advance;
    265 		break;
    266 	case 4:	/* uhub at usb */
    267 		if (device_is_a(dev, "uhub"))
    268 			goto advance;
    269 		break;
    270 	case 5:	/* umass at uhub port 3 */
    271 		if (device_is_a(dev, "umass")) {
    272 			struct usb_attach_arg *uaa = aux;
    273 			if (uaa->port == 3)
    274 				goto advance;
    275 		}
    276 		break;
    277 	case 6:	/* scsibus at umass */
    278 		if (device_is_a(dev, "scsibus"))
    279 			goto advance;
    280 		break;
    281 	case 7:	/* sd at scsibus */
    282 		if (booted_device == NULL)
    283 			booted_device = dev;
    284 		break;
    285 	}
    286 
    287 	if (device_is_a(dev, "genfb") || device_is_a(dev, "voyagerfb")) {
    288 		dict = device_properties(dev);
    289 		/*
    290 		 * this is a hack
    291 		 * is_console needs to be checked against reality
    292 		 */
    293 		prop_dictionary_set_bool(dict, "is_console", 1);
    294 		prop_dictionary_set_uint32(dict, "width", 1024);
    295 		prop_dictionary_set_uint32(dict, "height", 600);
    296 		prop_dictionary_set_uint32(dict, "depth", 16);
    297 		prop_dictionary_set_uint32(dict, "linebytes", 2048);
    298 		if (fb_addr != 0)
    299 			prop_dictionary_set_uint32(dict, "address", fb_addr);
    300 	}
    301 
    302 	return;
    303 
    304 advance:
    305 	gkey_chain_pos++;
    306 	lastparent = dev;
    307 }
    308 
    309 void
    310 gdium_powerdown()
    311 {
    312 	REGVAL(BONITO_GPIODATA) |= 0x00000002;
    313 	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
    314 }
    315 
    316 void
    317 gdium_reset()
    318 {
    319 	REGVAL(BONITO_GPIODATA) &= ~0x00000002;
    320 	REGVAL(BONITO_GPIOIE) &= ~0x00000002;
    321 }
    322 
    323 /*
    324  * Early console code
    325  */
    326 
    327 int
    328 gdium_cnattach(bus_space_tag_t memt, bus_space_tag_t iot,
    329     pci_chipset_tag_t pc, pcitag_t tag, pcireg_t id)
    330 {
    331 	struct rasops_info * const ri = &gdium_console_screen.scr_ri;
    332 	long defattr;
    333 	pcireg_t reg;
    334 
    335 
    336 	/* filter out unrecognized devices */
    337 	switch (id) {
    338 	default:
    339 		return ENODEV;
    340 	case PCI_ID_CODE(PCI_VENDOR_SILMOTION, PCI_PRODUCT_SILMOTION_SM502):
    341 		break;
    342 	}
    343 
    344 	wsfont_init();
    345 
    346 	/* set up rasops */
    347 	ri->ri_width = 1024;
    348 	ri->ri_height = 600;
    349 	ri->ri_depth = 16;
    350 	ri->ri_stride = 0x800;
    351 
    352 	/* read the mapping register for the frame buffer */
    353 	reg = pci_conf_read(pc, tag, PCI_MAPREG_START);
    354 	fb_addr = reg;
    355 
    356 	ri->ri_bits = (char *)MIPS_PHYS_TO_KSEG1(BONITO_PCILO_BASE + reg);
    357 	ri->ri_flg = RI_CENTER | RI_NO_AUTO;
    358 
    359 	memset(ri->ri_bits, 0, 0x200000);
    360 
    361 	/* use as much of the screen as the font permits */
    362 	rasops_init(ri, 30, 80);
    363 
    364 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
    365 	    ri->ri_width / ri->ri_font->fontwidth);
    366 
    367 	gdium_stdscreen.nrows = ri->ri_rows;
    368 	gdium_stdscreen.ncols = ri->ri_cols;
    369 	gdium_stdscreen.textops = &ri->ri_ops;
    370 	gdium_stdscreen.capabilities = ri->ri_caps;
    371 
    372 	ri->ri_ops.allocattr(ri, 0, ri->ri_rows - 1, 0, &defattr);
    373 
    374 	wsdisplay_preattach(&gdium_stdscreen, ri, 0, 0, defattr);
    375 
    376 	return 0;
    377 
    378 }
    379