summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvisa <visa@openbsd.org>2016-10-07 04:08:30 +0000
committervisa <visa@openbsd.org>2016-10-07 04:08:30 +0000
commit6804564bfc5f72ad2679074e2c915418e11a400f (patch)
treed5f24569cb28ee65997f1391e0155d9b1d1f0c37
parentAdd simple regress test for vxlan(4) and etherip(4). (diff)
downloadwireguard-openbsd-6804564bfc5f72ad2679074e2c915418e11a400f.tar.xz
wireguard-openbsd-6804564bfc5f72ad2679074e2c915418e11a400f.zip
Add an initial framebuffer driver for the RS780E chipset on loongson,
ported from sparc64. For now, it works without hardware acceleration, but otherwise it is usable enough as a console and with X. Diff from Miod's hoard
-rw-r--r--sys/arch/loongson/dev/radeonfb.c729
-rw-r--r--sys/arch/loongson/loongson/wscons_machdep.c140
2 files changed, 818 insertions, 51 deletions
diff --git a/sys/arch/loongson/dev/radeonfb.c b/sys/arch/loongson/dev/radeonfb.c
new file mode 100644
index 00000000000..680317b8dc7
--- /dev/null
+++ b/sys/arch/loongson/dev/radeonfb.c
@@ -0,0 +1,729 @@
+/* $OpenBSD: radeonfb.c,v 1.1 2016/10/07 04:08:30 visa Exp $ */
+
+/*
+ * Copyright (c) 2009 Mark Kettenis.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/pciio.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+
+#define RADEON_PCI_MEM 0x10
+#define RADEON_PCI_MMIO 0x18
+
+#define RADEON_CRTC_OFFSET 0x0224
+
+#define RADEON_RBBM_STATUS 0x0e40
+#define RADEON_RBBM_FIFOCNT_MASK 0x0000007f
+#define RADEON_RBBM_ACTIVE 0x80000000
+
+#define RADEON_SRC_Y_X 0x1434
+#define RADEON_DST_Y_X 0x1438
+#define RADEON_DST_HEIGHT_WIDTH 0x143c
+
+#define RADEON_DP_GUI_MASTER_CNTL 0x146c
+#define RADEON_GMC_DST_8BPP 0x00000200
+#define RADEON_GMC_DST_16BPP 0x00000400
+#define RADEON_GMC_DST_32BPP 0x00000600
+#define RADEON_GMC_BRUSH_NONE 0x000000e0
+#define RADEON_GMC_BRUSH_SOLID_COLOR 0x000000d0
+#define RADEON_GMC_SRC_DATATYPE_COLOR 0x00003000
+#define RADEON_GMC_SRC_SOURCE_MEMORY 0x02000000
+#define RADEON_ROP3_S 0x00cc0000
+#define RADEON_ROP3_P 0x00f00000
+#define RADEON_GMC_CLR_CMP_CNTL_DIS 0x10000000
+
+#define RADEON_DP_BRUSH_BKGD_CLR 0x1478
+#define RADEON_DP_BRUSH_FRGD_CLR 0x147c
+
+#define RADEON_DP_CNTL 0x16c0
+#define RADEON_DST_X_LEFT_TO_RIGHT 0x00000001
+#define RADEON_DST_Y_TOP_TO_BOTTOM 0x00000002
+#define RADEON_DP_WRITE_MASK 0x16cc
+
+#define RADEON_DEFAULT_PITCH_OFFSET 0x16e0
+#define RADEON_DEFAULT_SC_BOTTOM_RIGHT 0x16e8
+
+#define RADEON_WAIT_UNTIL 0x1720
+#define RADEON_WAIT_2D_IDLECLEAN 0x00010000
+#define RADEON_WAIT_3D_IDLECLEAN 0x00020000
+#define RADEON_WAIT_HOST_IDLECLEAN 0x00040000
+
+#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c
+#define RADEON_RB3D_DC_FLUSH_ALL 0x0000000f
+#define RADEON_RB3D_DC_BUSY 0x80000000
+
+#define RADEON_COORDS(x, y) ((y << 16) | (x))
+
+#ifdef APERTURE
+extern int allowaperture;
+#endif
+
+struct radeonfb_softc;
+
+/* minimal frame buffer information, suitable for early console */
+struct radeonfb {
+ struct radeonfb_softc *sc;
+ struct rasops_info ri;
+
+ bus_space_tag_t fbt;
+ bus_space_handle_t fbh;
+
+ bus_space_tag_t mmiot;
+ bus_space_handle_t mmioh;
+ bus_size_t memoff;
+
+ struct wsscreen_descr wsd;
+};
+
+struct radeonfb_softc {
+ struct device sc_dev;
+ struct radeonfb *sc_fb;
+ struct radeonfb sc_fb_store;
+
+ struct wsscreen_list sc_wsl;
+ struct wsscreen_descr *sc_scrlist[1];
+ int sc_nscr;
+
+ bus_addr_t sc_membase;
+ bus_size_t sc_memsize;
+
+ bus_addr_t sc_mmiobase;
+ bus_size_t sc_mmiosize;
+
+ pcitag_t sc_pcitag;
+
+ int sc_mode;
+};
+
+int radeonfb_alloc_screen(void *, const struct wsscreen_descr *, void **,
+ int *, int *, long *);
+void radeonfb_free_screen(void *, void *);
+int radeonfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
+int radeonfb_list_font(void *, struct wsdisplay_font *);
+int radeonfb_load_font(void *, void *, struct wsdisplay_font *);
+paddr_t radeonfb_mmap(void *, off_t, int);
+int radeonfb_show_screen(void *, void *, int, void (*)(void *, int, int),
+ void *);
+
+struct wsdisplay_accessops radeonfb_accessops = {
+ .ioctl = radeonfb_ioctl,
+ .mmap = radeonfb_mmap,
+ .alloc_screen = radeonfb_alloc_screen,
+ .free_screen = radeonfb_free_screen,
+ .show_screen = radeonfb_show_screen,
+ .load_font = radeonfb_load_font,
+ .list_font = radeonfb_list_font
+};
+
+int radeonfb_match(struct device *, void *, void *);
+void radeonfb_attach(struct device *, struct device *, void *);
+
+const struct cfattach radeonfb_ca = {
+ sizeof(struct radeonfb_softc), radeonfb_match, radeonfb_attach
+};
+
+struct cfdriver radeonfb_cd = {
+ NULL, "radeonfb", DV_DULL
+};
+
+int radeonfb_copycols(void *, int, int, int, int);
+int radeonfb_erasecols(void *, int, int, int, long);
+int radeonfb_copyrows(void *, int, int, int);
+int radeonfb_eraserows(void *, int, int, long);
+
+int radeonfb_setup(struct radeonfb *);
+void radeonfb_wait_fifo(struct radeonfb *, int);
+void radeonfb_wait(struct radeonfb *);
+void radeonfb_copyrect(struct radeonfb *, int, int, int, int, int, int);
+void radeonfb_fillrect(struct radeonfb *, int, int, int, int, int);
+
+static struct radeonfb radeonfbcn;
+
+const struct pci_matchid radeonfb_devices[] = {
+ { PCI_VENDOR_ATI, 0x9615 }
+};
+
+int
+radeonfb_match(struct device *parent, void *cf, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ return pci_matchbyid(pa, radeonfb_devices, nitems(radeonfb_devices));
+}
+
+void
+radeonfb_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)self;
+ struct pci_attach_args *pa = aux;
+ struct wsemuldisplaydev_attach_args waa;
+ bus_space_tag_t fbt, mmiot;
+ bus_space_handle_t fbh, mmioh;
+#if 0
+ bus_size_t fbsize, mmiosize;
+#endif
+ struct radeonfb *fb;
+ int console;
+
+ sc->sc_pcitag = pa->pa_tag;
+
+ if (pci_mapreg_map(pa, RADEON_PCI_MEM, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_LINEAR, &fbt, &fbh,
+ &sc->sc_membase, &sc->sc_memsize, 0)) {
+ printf(": can't map video memory\n");
+ return;
+ }
+
+ if (pci_mapreg_map(pa, RADEON_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
+ &mmiot, &mmioh, &sc->sc_mmiobase,
+ &sc->sc_mmiosize, 0)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ console = radeonfbcn.ri.ri_hw != NULL;
+
+ if (console)
+ fb = &radeonfbcn;
+ else
+ fb = &sc->sc_fb_store;
+
+ fb->sc = sc;
+ fb->fbt = fbt;
+ fb->fbh = fbh;
+ fb->mmiot = mmiot;
+ fb->mmioh = mmioh;
+ sc->sc_fb = fb;
+
+ if (!console) {
+ if (radeonfb_setup(fb) != 0) {
+ printf(": can't setup frame buffer\n");
+ return;
+ }
+ }
+
+ printf(": %dx%dx%d frame buffer\n",
+ fb->ri.ri_width, fb->ri.ri_height, fb->ri.ri_depth);
+
+ sc->sc_scrlist[0] = &fb->wsd;
+ sc->sc_wsl.nscreens = 1;
+ sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
+
+ waa.console = console;
+ waa.scrdata = &sc->sc_wsl;
+ waa.accessops = &radeonfb_accessops;
+ waa.accesscookie = sc;
+ waa.defaultscreens = 0;
+
+ sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
+
+ config_found(self, &waa, wsemuldisplaydevprint);
+}
+
+/*
+ * wsdisplay accessops
+ */
+
+int
+radeonfb_alloc_screen(void *v, const struct wsscreen_descr *type,
+ void **cookiep, int *curxp, int *curyp, long *attrp)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)v;
+ struct rasops_info *ri = &sc->sc_fb->ri;
+
+ if (sc->sc_nscr > 0)
+ return ENOMEM;
+
+ *cookiep = ri;
+ *curxp = *curyp = 0;
+ ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
+ sc->sc_nscr++;
+
+ return 0;
+}
+
+void
+radeonfb_free_screen(void *v, void *cookie)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)v;
+
+ sc->sc_nscr--;
+}
+
+int
+radeonfb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)v;
+ struct radeonfb *fb = sc->sc_fb;
+ struct rasops_info *ri = &fb->ri;
+ struct wsdisplay_fbinfo *wdf;
+#if 0
+ struct pcisel *sel;
+#endif
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_RADEONFB;
+ break;
+ case WSDISPLAYIO_SMODE:
+ sc->sc_mode = *(u_int *)data;
+ if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
+ /* Clear screen. */
+ radeonfb_setup(fb);
+ radeonfb_fillrect(fb, 0, 0, ri->ri_width,
+ ri->ri_height, ri->ri_devcmap[WSCOL_BLACK]);
+ }
+ break;
+ case WSDISPLAYIO_GINFO:
+ wdf = (struct wsdisplay_fbinfo *)data;
+ wdf->width = ri->ri_width;
+ wdf->height = ri->ri_height;
+ wdf->depth = ri->ri_depth;
+ wdf->cmsize = 0;
+ break;
+ case WSDISPLAYIO_LINEBYTES:
+ *(u_int *)data = ri->ri_stride;
+ break;
+
+#if 0
+ case WSDISPLAYIO_GPCIID:
+ sel = (struct pcisel *)data;
+ sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
+ sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
+ sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
+ break;
+#endif
+
+ case WSDISPLAYIO_SVIDEO:
+ case WSDISPLAYIO_GVIDEO:
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+radeonfb_show_screen(void *v, void *cookie, int waitok,
+ void (*cb)(void *, int, int), void *cbarg)
+{
+ return 0;
+}
+
+paddr_t
+radeonfb_mmap(void *v, off_t off, int prot)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)v;
+ struct radeonfb *fb = sc->sc_fb;
+
+ if ((off & PAGE_MASK) != 0)
+ return -1;
+
+ switch (sc->sc_mode) {
+ case WSDISPLAYIO_MODE_MAPPED:
+#ifdef APERTURE
+ if (allowaperture == 0)
+ return (-1);
+#endif
+
+ if (sc->sc_mmiosize == 0)
+ return (-1);
+
+ if (off >= sc->sc_membase &&
+ off < (sc->sc_membase + sc->sc_memsize))
+ return (bus_space_mmap(fb->fbt,
+ sc->sc_membase, off - sc->sc_membase,
+ prot, BUS_SPACE_MAP_LINEAR));
+
+ if (off >= sc->sc_mmiobase &&
+ off < (sc->sc_mmiobase + sc->sc_mmiosize))
+ return (bus_space_mmap(fb->mmiot,
+ sc->sc_mmiobase, off - sc->sc_mmiobase,
+ prot, BUS_SPACE_MAP_LINEAR));
+ break;
+
+ case WSDISPLAYIO_MODE_DUMBFB:
+ /*
+ * Don't allow mmap if the frame buffer area is not page aligned.
+ * XXX we should reprogram it to a page aligned boundary at attach
+ * XXX time if this isn't the case.
+ */
+ if ((fb->memoff % PAGE_SIZE) != 0)
+ return (-1);
+
+ if (off >= 0 && off < sc->sc_memsize / 2) {
+ bus_addr_t base = sc->sc_membase + fb->memoff;
+
+ return (bus_space_mmap(fb->fbt, base, off,
+ prot, BUS_SPACE_MAP_LINEAR));
+ }
+ break;
+ }
+
+ return (-1);
+}
+
+int
+radeonfb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)v;
+ struct rasops_info *ri = &sc->sc_fb->ri;
+
+ return rasops_load_font(ri, emulcookie, font);
+}
+
+int
+radeonfb_list_font(void *v, struct wsdisplay_font *font)
+{
+ struct radeonfb_softc *sc = (struct radeonfb_softc *)v;
+ struct rasops_info *ri = &sc->sc_fb->ri;
+
+ return rasops_list_font(ri, font);
+}
+
+/*
+ * Accelerated routines.
+ */
+
+int
+radeonfb_copycols(void *cookie, int row, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct radeonfb *fb = ri->ri_hw;
+
+ num *= ri->ri_font->fontwidth;
+ src *= ri->ri_font->fontwidth;
+ dst *= ri->ri_font->fontwidth;
+ row *= ri->ri_font->fontheight;
+
+ radeonfb_copyrect(fb, ri->ri_xorigin + src, ri->ri_yorigin + row,
+ ri->ri_xorigin + dst, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight);
+
+ return 0;
+}
+
+int
+radeonfb_erasecols(void *cookie, int row, int col, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct radeonfb *fb = ri->ri_hw;
+ int bg, fg;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ row *= ri->ri_font->fontheight;
+ col *= ri->ri_font->fontwidth;
+ num *= ri->ri_font->fontwidth;
+
+ radeonfb_fillrect(fb, ri->ri_xorigin + col, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
+
+ return 0;
+}
+
+int
+radeonfb_copyrows(void *cookie, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct radeonfb *fb = ri->ri_hw;
+
+ num *= ri->ri_font->fontheight;
+ src *= ri->ri_font->fontheight;
+ dst *= ri->ri_font->fontheight;
+
+ radeonfb_copyrect(fb, ri->ri_xorigin, ri->ri_yorigin + src,
+ ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
+
+ return 0;
+}
+
+int
+radeonfb_eraserows(void *cookie, int row, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct radeonfb *fb = ri->ri_hw;
+ int bg, fg;
+ int x, y, w;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
+ num = ri->ri_height;
+ x = y = 0;
+ w = ri->ri_width;
+ } else {
+ num *= ri->ri_font->fontheight;
+ x = ri->ri_xorigin;
+ y = ri->ri_yorigin + row * ri->ri_font->fontheight;
+ w = ri->ri_emuwidth;
+ }
+ radeonfb_fillrect(fb, x, y, w, num, ri->ri_devcmap[bg]);
+
+ return 0;
+}
+
+void
+radeonfb_wait_fifo(struct radeonfb *fb, int n)
+{
+ int i;
+
+ for (i = 1000000; i != 0; i--) {
+ if ((bus_space_read_4(fb->mmiot, fb->mmioh,
+ RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK) >= n)
+ break;
+ DELAY(1);
+ }
+}
+
+void
+radeonfb_wait(struct radeonfb *fb)
+{
+ int i;
+
+ radeonfb_wait_fifo(fb, 64);
+
+ for (i = 1000000; i != 0; i--) {
+ if ((bus_space_read_4(fb->mmiot, fb->mmioh,
+ RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) == 0)
+ break;
+ DELAY(1);
+ }
+
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_RB3D_DSTCACHE_CTLSTAT, RADEON_RB3D_DC_FLUSH_ALL);
+
+ for (i = 1000000; i != 0; i--) {
+ if ((bus_space_read_4(fb->mmiot, fb->mmioh,
+ RADEON_RB3D_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY) == 0)
+ break;
+ DELAY(1);
+ }
+}
+
+void
+radeonfb_copyrect(struct radeonfb *fb, int sx, int sy, int dx, int dy,
+ int w, int h)
+{
+ uint32_t gmc;
+ uint32_t dir;
+
+ radeonfb_wait_fifo(fb, 1);
+ bus_space_write_4(fb->mmiot, fb->mmioh, RADEON_WAIT_UNTIL,
+ RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN);
+
+ if (dy < sy) {
+ dir = RADEON_DST_Y_TOP_TO_BOTTOM;
+ } else {
+ sy += h - 1;
+ dy += h - 1;
+ dir = 0;
+ }
+ if (dx < sx) {
+ dir |= RADEON_DST_X_LEFT_TO_RIGHT;
+ } else {
+ sx += w - 1;
+ dx += w - 1;
+ }
+
+ radeonfb_wait_fifo(fb, 6);
+
+ gmc = RADEON_GMC_DST_16BPP;
+ gmc |= RADEON_GMC_BRUSH_NONE;
+ gmc |= RADEON_GMC_SRC_DATATYPE_COLOR;
+ gmc |= RADEON_GMC_SRC_SOURCE_MEMORY;
+ gmc |= RADEON_ROP3_S;
+ gmc |= RADEON_GMC_CLR_CMP_CNTL_DIS;
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DP_GUI_MASTER_CNTL, gmc);
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DP_WRITE_MASK, 0xffffffff);
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DP_CNTL, dir);
+
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_SRC_Y_X, RADEON_COORDS(sx, sy));
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DST_Y_X, RADEON_COORDS(dx, dy));
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DST_HEIGHT_WIDTH, RADEON_COORDS(w, h));
+
+ radeonfb_wait(fb);
+}
+
+void
+radeonfb_fillrect(struct radeonfb *fb, int x, int y, int w, int h, int color)
+{
+ uint32_t gmc;
+
+ radeonfb_wait_fifo(fb, 1);
+ bus_space_write_4(fb->mmiot, fb->mmioh, RADEON_WAIT_UNTIL,
+ RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN);
+
+ radeonfb_wait_fifo(fb, 6);
+
+ gmc = RADEON_GMC_DST_16BPP;
+ gmc |= RADEON_GMC_BRUSH_SOLID_COLOR;
+ gmc |= RADEON_GMC_SRC_DATATYPE_COLOR;
+ gmc |= RADEON_ROP3_P;
+ gmc |= RADEON_GMC_CLR_CMP_CNTL_DIS;
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DP_GUI_MASTER_CNTL, gmc);
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DP_BRUSH_FRGD_CLR, color);
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DP_WRITE_MASK, 0xffffffff);
+ bus_space_write_4(fb->mmiot, fb->mmioh, RADEON_DP_CNTL,
+ RADEON_DST_Y_TOP_TO_BOTTOM | RADEON_DST_X_LEFT_TO_RIGHT);
+
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DST_Y_X, RADEON_COORDS(x, y));
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DST_HEIGHT_WIDTH, RADEON_COORDS(w, h));
+
+ radeonfb_wait(fb);
+}
+
+/*
+ * Frame buffer initialization.
+ */
+
+int
+radeonfb_setup(struct radeonfb *fb)
+{
+ struct rasops_info *ri;
+ uint width, height, bpp;
+
+ /*
+ * The firmware sets up the framebuffer such that at starts at
+ * an offset from the start of video memory.
+ */
+ fb->memoff =
+ bus_space_read_4(fb->mmiot, fb->mmioh, RADEON_CRTC_OFFSET);
+
+ width = 800; /* XXX */
+ height = 600; /* XXX */
+ bpp = 16;
+
+ ri = &fb->ri;
+ ri->ri_width = width;
+ ri->ri_height = height;
+ ri->ri_depth = bpp;
+ ri->ri_stride = (ri->ri_width * ri->ri_depth) / 8;
+ ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR;
+ ri->ri_bits = (void *)(bus_space_vaddr(fb->fbt, fb->fbh) + fb->memoff);
+ ri->ri_hw = fb;
+
+ ri->ri_rnum = 5;
+ ri->ri_rpos = 11;
+ ri->ri_gnum = 6;
+ ri->ri_gpos = 5;
+ ri->ri_bnum = 5;
+ ri->ri_bpos = 0;
+
+ radeonfb_wait_fifo(fb, 2);
+ bus_space_write_4(fb->mmiot, fb->mmioh, RADEON_DEFAULT_PITCH_OFFSET,
+ ((ri->ri_stride >> 6) << 22) | (fb->memoff >> 10));
+ bus_space_write_4(fb->mmiot, fb->mmioh,
+ RADEON_DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff);
+
+ rasops_init(ri, 160, 160);
+
+ strlcpy(fb->wsd.name, "std", sizeof(fb->wsd.name));
+ fb->wsd.ncols = ri->ri_cols;
+ fb->wsd.nrows = ri->ri_rows;
+ fb->wsd.textops = &ri->ri_ops;
+ fb->wsd.fontwidth = ri->ri_font->fontwidth;
+ fb->wsd.fontheight = ri->ri_font->fontheight;
+ fb->wsd.capabilities = ri->ri_caps;
+
+#if 0
+ ri->ri_ops.copyrows = radeonfb_copyrows;
+ ri->ri_ops.copycols = radeonfb_copycols;
+ ri->ri_ops.eraserows = radeonfb_eraserows;
+ ri->ri_ops.erasecols = radeonfb_erasecols;
+#endif
+
+ return 0;
+}
+
+/*
+ * Early console code
+ */
+
+int radeonfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
+
+int
+radeonfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, pcitag_t tag,
+ pcireg_t id)
+{
+ long defattr;
+ struct rasops_info *ri;
+ pcireg_t bar;
+ int rc;
+
+ /* filter out unrecognized devices */
+ switch (id) {
+ default:
+ return ENODEV;
+ case PCI_ID_CODE(PCI_VENDOR_ATI, 0x9615):
+ break;
+ }
+
+ bar = pci_conf_read_early(tag, RADEON_PCI_MEM);
+ if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
+ return EINVAL;
+ radeonfbcn.fbt = memt;
+ rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
+ BUS_SPACE_MAP_LINEAR, &radeonfbcn.fbh);
+ if (rc != 0)
+ return rc;
+
+ bar = pci_conf_read_early(tag, RADEON_PCI_MMIO);
+ if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
+ return EINVAL;
+ radeonfbcn.mmiot = memt;
+ rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
+ BUS_SPACE_MAP_LINEAR, &radeonfbcn.mmioh);
+ if (rc != 0)
+ return rc;
+
+ rc = radeonfb_setup(&radeonfbcn);
+ if (rc != 0)
+ return rc;
+
+ ri = &radeonfbcn.ri;
+ ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
+ wsdisplay_cnattach(&radeonfbcn.wsd, ri, 0, 0, defattr);
+
+ return 0;
+}
diff --git a/sys/arch/loongson/loongson/wscons_machdep.c b/sys/arch/loongson/loongson/wscons_machdep.c
index 232082e4080..2c78f028854 100644
--- a/sys/arch/loongson/loongson/wscons_machdep.c
+++ b/sys/arch/loongson/loongson/wscons_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wscons_machdep.c,v 1.11 2014/03/27 22:16:03 miod Exp $ */
+/* $OpenBSD: wscons_machdep.c,v 1.12 2016/10/07 04:08:30 visa Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -62,6 +62,8 @@
#if NWSDISPLAY > 0
#include <dev/wscons/wsdisplayvar.h>
#endif
+#include "radeonfb.h"
+extern int radeonfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
#include "sisfb.h"
extern int sisfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
#include "smfb.h"
@@ -85,12 +87,14 @@ extern int smfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
cons_decl(ws);
+#include <machine/pmon.h>
+
void
wscnprobe(struct consdev *cp)
{
pcitag_t tag;
pcireg_t id, class;
- int maj, dev;
+ int maj, dev, bus, maxbus;
cp->cn_pri = CN_DEAD;
@@ -106,24 +110,37 @@ wscnprobe(struct consdev *cp)
}
/*
+ * Loongson 3A systems have their video board on the second bus.
+ *
+ * XXX We might need a pci_maxdevs_early() routine if more systems
+ * XXX end up needing more than one bus to be walked.
+ */
+ if (loongson_ver >= 0x3a)
+ maxbus = 2;
+ else
+ maxbus = 1;
+
+ /*
* Look for a suitable video device.
*/
- for (dev = 0; dev < 32; dev++) {
- tag = pci_make_tag_early(0, dev, 0);
- id = pci_conf_read_early(tag, PCI_ID_REG);
- if (id == 0 || PCI_VENDOR(id) == PCI_VENDOR_INVALID)
- continue;
-
- class = pci_conf_read_early(tag, PCI_CLASS_REG);
- if (!DEVICE_IS_VGA_PCI(class) &&
- !(PCI_CLASS(class) == PCI_CLASS_DISPLAY &&
- PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_MISC))
- continue;
-
- cp->cn_dev = makedev(maj, 0);
- cp->cn_pri = CN_MIDPRI;
- break;
+ for (bus = 0; bus < maxbus; bus++) {
+ for (dev = 0; dev < 32; dev++) {
+ tag = pci_make_tag_early(bus, dev, 0);
+ id = pci_conf_read_early(tag, PCI_ID_REG);
+ if (id == 0 || PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ continue;
+
+ class = pci_conf_read_early(tag, PCI_CLASS_REG);
+ if (!DEVICE_IS_VGA_PCI(class) &&
+ !(PCI_CLASS(class) == PCI_CLASS_DISPLAY &&
+ PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_MISC))
+ continue;
+
+ cp->cn_dev = makedev(maj, 0);
+ cp->cn_pri = CN_MIDPRI;
+ return;
+ }
}
}
@@ -133,7 +150,7 @@ wscninit(struct consdev *cp)
static int initted;
pcitag_t tag;
pcireg_t id, class;
- int dev, rc;
+ int dev, bus, maxbus, rc;
extern struct consdev pmoncons;
if (initted)
@@ -144,49 +161,70 @@ static int initted;
cn_tab = &pmoncons; /* to be able to panic */
/*
- * Look for a suitable video device.
+ * Loongson 3A systems have their video board on the second bus.
+ *
+ * XXX We might need a pci_maxdevs_early() routine if more systems
+ * XXX end up needing more than one bus to be walked.
*/
+ if (loongson_ver >= 0x3a)
+ maxbus = 2;
+ else
+ maxbus = 1;
- for (dev = 0; dev < 32; dev++) {
- tag = pci_make_tag_early(0, dev, 0);
- id = pci_conf_read_early(tag, PCI_ID_REG);
- if (id == 0 || PCI_VENDOR(id) == PCI_VENDOR_INVALID)
- continue;
-
- class = pci_conf_read_early(tag, PCI_CLASS_REG);
- if (!DEVICE_IS_VGA_PCI(class) &&
- !(PCI_CLASS(class) == PCI_CLASS_DISPLAY &&
- PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_MISC))
- continue;
-
- /*
- * Try to configure this device as glass console.
- */
-
- rc = ENXIO;
+ /*
+ * Look for a suitable video device.
+ */
- /* bitmapped frame buffer won't be of PREHISTORIC class */
- if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
+ for (bus = 0; bus < maxbus; bus++) {
+ for (dev = 0; dev < 32; dev++) {
+ tag = pci_make_tag_early(bus, dev, 0);
+ id = pci_conf_read_early(tag, PCI_ID_REG);
+ if (id == 0 || PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+ continue;
+
+ class = pci_conf_read_early(tag, PCI_CLASS_REG);
+ if (!DEVICE_IS_VGA_PCI(class) &&
+ !(PCI_CLASS(class) == PCI_CLASS_DISPLAY &&
+ PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_MISC))
+ continue;
+
+ /*
+ * Try to configure this device as glass console.
+ */
+
+ rc = ENXIO;
+
+ /*
+ * Bitmapped frame buffer won't be of PREHISTORIC
+ * class.
+ */
+ if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
+#if NRADEONFB > 0
+ if (rc != 0)
+ rc = radeonfb_cnattach(early_mem_t,
+ early_io_t, tag, id);
+#endif
#if NSISFB > 0
- if (rc != 0 && early_io_t != NULL)
- rc = sisfb_cnattach(early_mem_t,
- early_io_t, tag, id);
+ if (rc != 0 && early_io_t != NULL)
+ rc = sisfb_cnattach(early_mem_t,
+ early_io_t, tag, id);
#endif
#if NSMFB > 0
- if (rc != 0 && early_io_t != NULL)
- rc = smfb_cnattach(early_mem_t,
- early_io_t, tag, id);
+ if (rc != 0 && early_io_t != NULL)
+ rc = smfb_cnattach(early_mem_t,
+ early_io_t, tag, id);
#endif
}
#if NVGA > 0
- if (rc != 0 && early_io_t != NULL) {
- /* thanks $DEITY the pci_chipset_tag_t arg is ignored */
- rc = vga_pci_cnattach(early_io_t,
- early_mem_t, NULL, 0, dev, 0);
- }
+ if (rc != 0 && early_io_t != NULL) {
+ /* thanks $DEITY the pci_chipset_tag_t arg is ignored */
+ rc = vga_pci_cnattach(early_io_t,
+ early_mem_t, NULL, 0, dev, 0);
+ }
#endif
- if (rc == 0)
- goto setup_kbd;
+ if (rc == 0)
+ goto setup_kbd;
+ }
}
cn_tab = cp;