summaryrefslogtreecommitdiff
path: root/sys/arch/loongson
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-02-05 20:56:50 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-02-05 20:56:50 +0000
commit07bcb3014276af325b0b715a2a0d4a44a450680c (patch)
tree321f4c704e8088138b7478941d725bcc616608e9 /sys/arch/loongson
parent337bd5c79ac9110887dfadf361b306cab914ee1d (diff)
Blind support for SM501 model. This should give the Gdium Liberty a working,
accelerated console. No regression on Lemote Yeelong.
Diffstat (limited to 'sys/arch/loongson')
-rw-r--r--sys/arch/loongson/dev/smfb.c157
-rw-r--r--sys/arch/loongson/dev/smfbreg.h24
2 files changed, 135 insertions, 46 deletions
diff --git a/sys/arch/loongson/dev/smfb.c b/sys/arch/loongson/dev/smfb.c
index 49509a51f05..281e7ccf93e 100644
--- a/sys/arch/loongson/dev/smfb.c
+++ b/sys/arch/loongson/dev/smfb.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: smfb.c,v 1.3 2010/02/05 20:53:24 miod Exp $ */
+/* $OpenBSD: smfb.c,v 1.4 2010/02/05 20:56:49 miod Exp $ */
/*
- * Copyright (c) 2009 Miodrag Vallat.
+ * Copyright (c) 2009, 2010 Miodrag Vallat.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -43,13 +43,18 @@
#define DPR_READ(fb, reg) (fb)->dpr[(reg) / 4]
#define DPR_WRITE(fb, reg, val) (fb)->dpr[(reg) / 4] = (val)
+#define REG_READ(fb, reg) (fb)->regs[(reg) / 4]
+#define REG_WRITE(fb, reg, val) (fb)->regs[(reg) / 4] = (val)
+
struct smfb_softc;
/* minimal frame buffer information, suitable for early console */
struct smfb {
struct smfb_softc *sc;
struct rasops_info ri;
+ int is5xx;
+ volatile uint32_t *regs;
volatile uint32_t *dpr;
volatile uint8_t *mmio;
struct wsscreen_descr wsd;
@@ -63,6 +68,9 @@ struct smfb_softc {
bus_space_tag_t sc_memt;
bus_space_handle_t sc_memh;
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_regh;
+
struct wsscreen_list sc_wsl;
struct wsscreen_descr *sc_scrlist[1];
int sc_nscr;
@@ -99,7 +107,7 @@ struct wsdisplay_accessops smfb_accessops = {
NULL /* burner */
};
-int smfb_setup(struct smfb *, vaddr_t);
+int smfb_setup(struct smfb *, vaddr_t, vaddr_t);
void smfb_copyrect(struct smfb *, int, int, int, int, int, int);
void smfb_fillrect(struct smfb *, int, int, int, int, int);
@@ -109,19 +117,30 @@ int smfb_do_cursor(struct rasops_info *);
int smfb_erasecols(void *, int, int, int, long);
int smfb_eraserows(void *, int, int, long);
int smfb_wait(struct smfb *);
+int smfb_is5xx(pcireg_t);
static struct smfb smfbcn;
-const struct pci_matchid smfb_devices[] = {
- { PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712 }
-};
+int
+smfb_is5xx(pcireg_t id)
+{
+ switch(id) {
+ default:
+ return -1;
+ case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712):
+ return 0;
+ case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM501):
+ return 1;
+ }
+}
int
smfb_match(struct device *parent, void *vcf, void *aux)
{
- struct pci_attach_args *paa = (struct pci_attach_args *)aux;
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+ int is5xx = smfb_is5xx(pa->pa_id);
- return pci_matchbyid(paa, smfb_devices, nitems(smfb_devices));
+ return is5xx < 0 ? 0 : 1;
}
void
@@ -130,8 +149,9 @@ smfb_attach(struct device *parent, struct device *self, void *aux)
struct smfb_softc *sc = (struct smfb_softc *)self;
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
struct wsemuldisplaydev_attach_args waa;
- vaddr_t fbbase;
+ vaddr_t fbbase, regbase;
int console;
+ int is5xx = smfb_is5xx(pa->pa_id);
if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM,
BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
@@ -140,6 +160,15 @@ smfb_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ if (is5xx) {
+ if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04,
+ PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_LINEAR, &sc->sc_regt, &sc->sc_regh,
+ NULL, NULL, 0) != 0) {
+ printf(": can't map registers\n%s", self->dv_xname);
+ }
+ }
+
console = smfbcn.ri.ri_hw != NULL;
if (console) {
@@ -147,8 +176,15 @@ smfb_attach(struct device *parent, struct device *self, void *aux)
sc->sc_fb->sc = sc;
} else {
sc->sc_fb = &sc->sc_fb_store;
+ sc->sc_fb->is5xx = is5xx;
fbbase = (vaddr_t)bus_space_vaddr(sc->sc_memt, sc->sc_memh);
- if (smfb_setup(sc->sc_fb, fbbase) != 0) {
+ if (sc->sc_regh != 0) {
+ regbase = (vaddr_t)bus_space_vaddr(sc->sc_regt,
+ sc->sc_regh);
+ } else {
+ regbase = 0;
+ }
+ if (smfb_setup(sc->sc_fb, fbbase, regbase) != 0) {
printf(": can't setup frame buffer\n");
return;
}
@@ -256,9 +292,10 @@ smfb_mmap(void *v, off_t offset, int prot)
*/
int
-smfb_setup(struct smfb *fb, vaddr_t fbbase)
+smfb_setup(struct smfb *fb, vaddr_t fbbase, vaddr_t regbase)
{
struct rasops_info *ri;
+ int accel = 0;
ri = &fb->ri;
ri->ri_width = 1024;
@@ -289,30 +326,49 @@ smfb_setup(struct smfb *fb, vaddr_t fbbase)
fb->wsd.fontheight = ri->ri_font->fontheight;
fb->wsd.capabilities = ri->ri_caps;
- fb->dpr = (volatile uint32_t *)(fbbase + DPR_BASE);
- fb->mmio = (volatile uint8_t *)(fbbase + MMIO_BASE);
+ if (fb->is5xx) {
+ if (regbase != 0) {
+ fb->dpr = (volatile uint32_t *)
+ (regbase + SM5XX_DPR_BASE);
+ fb->mmio = NULL;
+ fb->regs = (volatile uint32_t *)
+ (regbase + SM5XX_REG_BASE);
+ accel = 1;
+ }
+ } else {
+ fb->dpr = (volatile uint32_t *)(fbbase + SM7XX_DPR_BASE);
+ fb->mmio = (volatile uint8_t *)(fbbase + SM7XX_MMIO_BASE);
+ fb->regs = NULL;
+ accel = 1;
+ }
/*
- * Setup 2D acceleration
+ * Setup 2D acceleration whenever possible
*/
- smfb_wait(fb);
-
- DPR_WRITE(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0));
- /* use of width both times is intentional */
- DPR_WRITE(fb, DPR_PITCH, DPR_COORDS(ri->ri_width, ri->ri_width));
- DPR_WRITE(fb, DPR_SRC_WINDOW, DPR_COORDS(ri->ri_width, ri->ri_width));
- DPR_WRITE(fb, DPR_BYTE_BIT_MASK, 0xffffffff);
- DPR_WRITE(fb, DPR_COLOR_COMPARE_MASK, 0);
- DPR_WRITE(fb, DPR_COLOR_COMPARE, 0);
- DPR_WRITE(fb, DPR_SRC_BASE, 0);
- DPR_WRITE(fb, DPR_DST_BASE, 0);
- DPR_READ(fb, DPR_DST_BASE);
-
- ri->ri_ops.copycols = smfb_copycols;
- ri->ri_ops.copyrows = smfb_copyrows;
- ri->ri_ops.erasecols = smfb_erasecols;
- ri->ri_ops.eraserows = smfb_eraserows;
+ if (accel) {
+ if (smfb_wait(fb) != 0)
+ accel = 0;
+ }
+ if (accel) {
+ DPR_WRITE(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0));
+ /* use of width both times is intentional */
+ DPR_WRITE(fb, DPR_PITCH,
+ DPR_COORDS(ri->ri_width, ri->ri_width));
+ DPR_WRITE(fb, DPR_SRC_WINDOW,
+ DPR_COORDS(ri->ri_width, ri->ri_width));
+ DPR_WRITE(fb, DPR_BYTE_BIT_MASK, 0xffffffff);
+ DPR_WRITE(fb, DPR_COLOR_COMPARE_MASK, 0);
+ DPR_WRITE(fb, DPR_COLOR_COMPARE, 0);
+ DPR_WRITE(fb, DPR_SRC_BASE, 0);
+ DPR_WRITE(fb, DPR_DST_BASE, 0);
+ DPR_READ(fb, DPR_DST_BASE);
+
+ ri->ri_ops.copycols = smfb_copycols;
+ ri->ri_ops.copyrows = smfb_copyrows;
+ ri->ri_ops.erasecols = smfb_erasecols;
+ ri->ri_ops.eraserows = smfb_eraserows;
+ }
return 0;
}
@@ -445,16 +501,23 @@ smfb_eraserows(void *cookie, int row, int num, long attr)
int
smfb_wait(struct smfb *fb)
{
- uint8_t reg;
+ uint32_t reg;
int i;
i = 10000;
while (i-- != 0) {
- fb->mmio[0x3c4] = 0x16;
- (void)fb->mmio[0x3c4]; /* posted write */
- reg = fb->mmio[0x3c5];
- if ((reg & 0x18) == 0x10)
- return 0;
+ if (fb->is5xx) {
+ reg = REG_READ(fb, REG_SYSTEM_CONTROL);
+ if ((reg & (RSC_FIFO_EMPTY | RSC_STATUS_BUSY)) ==
+ RSC_FIFO_EMPTY)
+ return 0;
+ } else {
+ fb->mmio[0x3c4] = 0x16;
+ (void)fb->mmio[0x3c4]; /* posted write */
+ reg = fb->mmio[0x3c5];
+ if ((reg & 0x18) == 0x10)
+ return 0;
+ }
delay(1);
}
@@ -472,16 +535,30 @@ smfb_cnattach(bus_space_tag_t memt, pcitag_t tag, pcireg_t id)
{
long defattr;
struct rasops_info *ri;
- vaddr_t fbbase;
+ vaddr_t fbbase, regbase;
pcireg_t bar;
- int rc;
+ int rc, is5xx;
+
+ /* filter out unrecognized devices */
+ is5xx = smfb_is5xx(id);
+ if (is5xx < 0)
+ return ENODEV;
+
+ smfbcn.is5xx = is5xx;
bar = pci_conf_read_early(tag, PCI_MAPREG_START);
if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
return EINVAL;
fbbase = memt->bus_base + PCI_MAPREG_MEM_ADDR(bar);
- rc = smfb_setup(&smfbcn, fbbase);
+ regbase = 0;
+ if (smfbcn.is5xx) {
+ bar = pci_conf_read_early(tag, PCI_MAPREG_START + 0x04);
+ if (PCI_MAPREG_TYPE(bar) == PCI_MAPREG_TYPE_MEM)
+ regbase = memt->bus_base + PCI_MAPREG_MEM_ADDR(bar);
+ }
+
+ rc = smfb_setup(&smfbcn, fbbase, regbase);
if (rc != 0)
return rc;
diff --git a/sys/arch/loongson/dev/smfbreg.h b/sys/arch/loongson/dev/smfbreg.h
index 5551e746e1e..49a457926e9 100644
--- a/sys/arch/loongson/dev/smfbreg.h
+++ b/sys/arch/loongson/dev/smfbreg.h
@@ -1,7 +1,7 @@
-/* $OpenBSD: smfbreg.h,v 1.1 2009/12/25 21:12:02 miod Exp $ */
+/* $OpenBSD: smfbreg.h,v 1.2 2010/02/05 20:56:49 miod Exp $ */
/*
- * Copyright (c) 2009 Miodrag Vallat.
+ * Copyright (c) 2009, 2010 Miodrag Vallat.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,7 +26,9 @@
#define DPR_COORDS(x, y) (((x) << 16) | (y))
-#define DPR_BASE 0x00408000
+#define SM5XX_DPR_BASE 0x00100000
+#define SM7XX_DPR_BASE 0x00408000
+
#define DPR_SRC_COORDS 0x00
#define DPR_DST_COORDS 0x04
#define DPR_SPAN_COORDS 0x08
@@ -61,10 +63,20 @@
* VPR (Video Parameter Registers)
*/
-#define VPR_BASE 0x0040c000
+#define SM7XX_VPR_BASE 0x0040c000
+
+/*
+ * MMIO (SM7XX only)
+ */
+
+#define SM7XX_MMIO_BASE 0x00700000
/*
- * MMIO
+ * Generic registers (SM5xx only)
*/
-#define MMIO_BASE 0x00700000
+#define SM5XX_REG_BASE 0x00000000
+
+#define REG_SYSTEM_CONTROL 0x00
+#define RSC_FIFO_EMPTY 0x00080000
+#define RSC_STATUS_BUSY 0x00040000