#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/types.h>
#include <mips/cpuregs.h>
#include <evbmips/loongson/autoconf.h>
#include <evbmips/loongson/loongson_intr.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <mips/bonito/bonitoreg.h>
#include <mips/bonito/bonitovar.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <dev/wsfont/wsfont.h>
#include <dev/wscons/wsdisplay_vconsvar.h>
int gdium_revision = 0;
static pcireg_t fb_addr = 0;
void gdium_attach_hook(device_t, device_t, struct pcibus_attach_args *);
void gdium_device_register(device_t, void *);
int gdium_intr_map(int, int, int, pci_intr_handle_t *);
void gdium_powerdown(void);
void gdium_reset(void);
const struct bonito_config gdium_bonito = {
.bc_adbase = 11,
.bc_gpioIE = LOONGSON_INTRMASK_GPIO,
.bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR |
LOONGSON_INTRMASK_PCI_PARERR,
.bc_intSteer = 0,
.bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR |
LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR,
.bc_attach_hook = gdium_attach_hook,
};
const struct platform gdium_platform = {
.system_type = LOONGSON_GDIUM,
.vendor = "EMTEC",
.product = "Gdium",
.bonito_config = &gdium_bonito,
.isa_chipset = NULL,
.legacy_io_ranges = NULL,
.bonito_mips_intr = MIPS_INT_MASK_4,
.isa_mips_intr = 0,
.isa_intr = NULL,
.p_pci_intr_map = gdium_intr_map,
.irq_map = loongson2f_irqmap,
.setup = NULL,
.device_register = gdium_device_register,
.powerdown = gdium_powerdown,
.reset = gdium_reset
};
static struct vcons_screen gdium_console_screen;
static struct wsscreen_descr gdium_stdscreen = {
.name = "std",
};
void
gdium_attach_hook(device_t parent, device_t self,
struct pcibus_attach_args *pba)
{
pci_chipset_tag_t pc = pba->pba_pc;
pcireg_t id;
pcitag_t tag;
#ifdef notyet
int bar;
#endif
#if 0
pcireg_t reg;
int dev, func;
#endif
if (pba->pba_bus != 0)
return;
#ifdef notyet
tag = pci_make_tag(pc, 0, 13, 0);
for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 4)
pci_conf_write(pc, tag, bar, 0);
#else
tag = pci_make_tag(pc, 0, 13, 0);
pci_conf_write(pc, tag, PCI_MAPREG_START, 0x06228000);
#endif
tag = pci_make_tag(pc, 0, 17, 0);
id = pci_conf_read(pc, tag, PCI_ID_REG);
if (id == PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
gdium_revision = 1;
#if 0
for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
tag = pci_make_tag(pc, 0, dev, 0);
id = pci_conf_read(pc, tag, PCI_ID_REG);
if (id != PCI_ID_CODE(PCI_VENDOR_NEC, PCI_PRODUCT_NEC_USB))
continue;
if (gdium_revision != 0) {
reg = pci_conf_read(pc, tag, 0xe0);
reg |= 0x00000003;
pci_conf_write(pc, tag, 0xe0, reg);
} else {
for (func = 0; func < 2; func++) {
tag = pci_make_tag(pc, 0, dev, func);
id = pci_conf_read(pc, tag, PCI_ID_REG);
if (PCI_VENDOR(id) != PCI_VENDOR_NEC)
continue;
if (PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB &&
PCI_PRODUCT(id) != PCI_PRODUCT_NEC_USB2)
continue;
reg = pci_conf_read(pc, tag, 0xe0);
reg &= ~0x00000007;
reg |= 0x00000005;
pci_conf_write(pc, tag, 0xe0, reg);
pci_conf_write(pc, tag, 0xe4, 0x00000020);
}
}
}
#endif
}
int
gdium_intr_map(int dev, int fn, int pin, pci_intr_handle_t *ihp)
{
switch (dev) {
case 13:
*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA + (pin + 1) % 4);
return 0;
case 14:
*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA);
return 0;
case 15:
if (gdium_revision == 0)
*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
(pin - 1));
else
*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIB);
return 0;
case 16:
*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCID);
return 0;
case 17:
if (gdium_revision != 0) {
*ihp = BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIC);
return 0;
} else
break;
default:
break;
}
return 1;
}
extern struct cfdriver bonito_cd;
extern struct cfdriver pci_cd;
extern struct cfdriver ehci_cd;
extern struct cfdriver usb_cd;
extern struct cfdriver uhub_cd;
extern struct cfdriver umass_cd;
extern struct cfdriver scsibus_cd;
extern struct cfdriver sd_cd;
#include <dev/pci/pcivar.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
void
gdium_device_register(device_t dev, void *aux)
{
prop_dictionary_t dict;
static int gkey_chain_pos = 0;
static device_t lastparent = NULL;
if (device_is_a(dev, "genfb") || device_is_a(dev, "voyagerfb")) {
dict = device_properties(dev);
prop_dictionary_set_bool(dict, "is_console", 1);
prop_dictionary_set_uint32(dict, "width", 1024);
prop_dictionary_set_uint32(dict, "height", 600);
prop_dictionary_set_uint32(dict, "depth", 16);
prop_dictionary_set_uint32(dict, "linebytes", 2048);
if (fb_addr != 0)
prop_dictionary_set_uint32(dict, "address", fb_addr);
}
if (device_parent(dev) != lastparent && gkey_chain_pos != 0)
return;
switch (gkey_chain_pos) {
case 0:
if (device_is_a(dev, "bonito"))
goto advance;
break;
case 1:
if (device_is_a(dev, "pci"))
goto advance;
break;
case 2:
if (device_is_a(dev, "ehci")) {
struct pci_attach_args *paa = aux;
if (paa->pa_device == 15)
goto advance;
}
break;
case 3:
if (device_is_a(dev, "usb"))
goto advance;
break;
case 4:
if (device_is_a(dev, "uhub"))
goto advance;
break;
case 5:
if (device_is_a(dev, "umass")) {
struct usb_attach_arg *uaa = aux;
if (uaa->uaa_port == 3)
goto advance;
}
break;
case 6:
if (device_is_a(dev, "scsibus"))
goto advance;
break;
case 7:
if (booted_device == NULL)
booted_device = dev;
break;
}
return;
advance:
gkey_chain_pos++;
lastparent = dev;
}
void
gdium_powerdown(void)
{
REGVAL(BONITO_GPIODATA) |= 0x00000002;
REGVAL(BONITO_GPIOIE) &= ~0x00000002;
printf("Powering down...\n");
while(1) delay(1000);
}
void
gdium_reset(void)
{
REGVAL(BONITO_GPIODATA) &= ~0x00000002;
REGVAL(BONITO_GPIOIE) &= ~0x00000002;
}
int
gdium_cnattach(bus_space_tag_t memt, bus_space_tag_t iot,
pci_chipset_tag_t pc, pcitag_t tag, pcireg_t id)
{
struct rasops_info * const ri = &gdium_console_screen.scr_ri;
long defattr;
pcireg_t reg;
switch (id) {
default:
return ENODEV;
case PCI_ID_CODE(PCI_VENDOR_SILMOTION, PCI_PRODUCT_SILMOTION_SM502):
break;
}
wsfont_init();
ri->ri_width = 1024;
ri->ri_height = 600;
ri->ri_depth = 16;
ri->ri_stride = 0x800;
reg = pci_conf_read(pc, tag, PCI_MAPREG_START);
fb_addr = reg;
ri->ri_bits = (char *)MIPS_PHYS_TO_KSEG1(BONITO_PCILO_BASE + reg);
ri->ri_flg = RI_CENTER | RI_NO_AUTO;
memset(ri->ri_bits, 0, 0x200000);
rasops_init(ri, 30, 80);
rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
ri->ri_width / ri->ri_font->fontwidth);
gdium_stdscreen.nrows = ri->ri_rows;
gdium_stdscreen.ncols = ri->ri_cols;
gdium_stdscreen.textops = &ri->ri_ops;
gdium_stdscreen.capabilities = ri->ri_caps;
ri->ri_ops.allocattr(ri, 0, ri->ri_rows - 1, 0, &defattr);
wsdisplay_preattach(&gdium_stdscreen, ri, 0, 0, defattr);
return 0;
}