summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-02-18 22:45:29 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-02-18 22:45:29 +0000
commit4dd9d5102940ca2439f6ab9db5e6fb304f43c8fd (patch)
treed0dbede127d76bb875674a0d1a18af8b63e60758
parent191806e7af1fae237f2dfbb722ab4c3753d5fc7a (diff)
Add a master driver for the VoyagerGX SM502 chip found on the Gdium, which is
not only a framebuffer. Allow smfb to attach either at pci or at voyager. Add gpio@voyager and gdiumiic@gpio, a derivative of the MI gpioiic driver. This allows us to get lmtemp@iic on the Lemote; the next step being to write a driver for the i2c todclock chip found on the same bus.
-rw-r--r--sys/arch/loongson/conf/GENERIC33
-rw-r--r--sys/arch/loongson/conf/RAMDISK25
-rw-r--r--sys/arch/loongson/conf/files.loongson17
-rw-r--r--sys/arch/loongson/dev/gdiumiic.c355
-rw-r--r--sys/arch/loongson/dev/glxpcib.c3
-rw-r--r--sys/arch/loongson/dev/smfb.c126
-rw-r--r--sys/arch/loongson/dev/smfbreg.h12
-rw-r--r--sys/arch/loongson/dev/voyager.c260
-rw-r--r--sys/arch/loongson/dev/voyagerreg.h38
-rw-r--r--sys/arch/loongson/dev/voyagervar.h27
10 files changed, 810 insertions, 86 deletions
diff --git a/sys/arch/loongson/conf/GENERIC b/sys/arch/loongson/conf/GENERIC
index 27ba3c0085e..546609457ad 100644
--- a/sys/arch/loongson/conf/GENERIC
+++ b/sys/arch/loongson/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.8 2010/02/12 08:14:00 miod Exp $
+# $OpenBSD: GENERIC,v 1.9 2010/02/18 22:45:26 miod Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -34,20 +34,33 @@ clock0 at mainbus0
# Main local buses
bonito* at mainbus0
pci* at bonito?
-glxpcib* at pci?
+# Lemote Fuloong 2F and Lemote Yeeloong devices
+glxpcib* at pci?
isa0 at glxpcib?
mcclock0 at isa? port 0x70
-pckbc0 at isa?
-pckbd* at pckbc?
-wskbd* at pckbd? mux 1
-pmsi* at pckbc?
-wsmouse* at pmsi? mux 0
-com0 at isa? port 0x2f8 irq 3
-
+pckbc0 at isa? # Yeeloong only
+pckbd* at pckbc? # Yeeloong only
+wskbd* at pckbd? mux 1 # Yeeloong only
+pmsi* at pckbc? # Yeeloong only
+wsmouse* at pmsi? mux 0 # Yeeloong only
+com0 at isa? port 0x2f8 irq 3 # Fuloong 2F only
pciide* at pci?
wd* at pciide? flags 0x0000
-smfb* at pci?
+smfb* at pci? # Yeeloong only
+
+# Gdium Liberty specific devices
+voyager* at pci?
+gpio0 at voyager?
+gdiumiic0 at gpio0 offset 6 mask 0x81 # pins 6 and 13
+gdiumiic0 at gpio0 offset 46 mask 0x03 # pins 46 and 47
+iic0 at gdiumiic0
+lmtemp0 at iic0 # National Semiconductor LM75
+#gdiumiic1 at gpio0 offset 41 mask 0x03 # pins 41 and 42
+#iic* at voyager?
+#ohci* at voyager?
+smfb* at voyager?
+
wsdisplay* at smfb?
# USB Controllers
diff --git a/sys/arch/loongson/conf/RAMDISK b/sys/arch/loongson/conf/RAMDISK
index dd840abb2fd..c914357733f 100644
--- a/sys/arch/loongson/conf/RAMDISK
+++ b/sys/arch/loongson/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.6 2010/02/12 19:57:52 otto Exp $
+# $OpenBSD: RAMDISK,v 1.7 2010/02/18 22:45:26 miod Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -46,20 +46,25 @@ clock0 at mainbus0
# Main local buses
bonito* at mainbus0
pci* at bonito?
-glxpcib* at pci?
+# Lemote Fuloong 2F and Lemote Yeeloong devices
+glxpcib* at pci?
isa0 at glxpcib?
mcclock0 at isa? port 0x70
-pckbc0 at isa?
-pckbd* at pckbc?
-wskbd* at pckbd? mux 1
-pmsi* at pckbc?
-wsmouse* at pmsi? mux 0
-com0 at isa? port 0x2f8 irq 3
-
+pckbc0 at isa? # Yeeloong only
+pckbd* at pckbc? # Yeeloong only
+wskbd* at pckbd? mux 1 # Yeeloong only
+pmsi* at pckbc? # Yeeloong only
+wsmouse* at pmsi? mux 0 # Yeeloong only
+com0 at isa? port 0x2f8 irq 3 # Fuloong 2F only
pciide* at pci?
wd* at pciide? flags 0x0000
-smfb* at pci?
+smfb* at pci? # Yeeloong only
+
+# Gdium Liberty specific devices
+voyager* at pci?
+smfb* at voyager?
+
wsdisplay* at smfb?
# USB Controllers
diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson
index f7d56de48bc..23eb91de37d 100644
--- a/sys/arch/loongson/conf/files.loongson
+++ b/sys/arch/loongson/conf/files.loongson
@@ -1,4 +1,4 @@
-# $OpenBSD: files.loongson,v 1.2 2010/02/05 20:51:20 miod Exp $
+# $OpenBSD: files.loongson,v 1.3 2010/02/18 22:45:26 miod Exp $
# Standard stanzas config(8) can't run without
maxpartitions 16
@@ -73,7 +73,18 @@ attach mcclock at isa with mcclock_isa
file arch/loongson/dev/mcclock.c mcclock
file arch/loongson/dev/mcclock_isa.c mcclock_isa
-# Silicon Motion SM712 frame buffer
+# Silicon Motion SM502 master device
+device voyager {}: gpiobus
+attach voyager at pci
+file arch/loongson/dev/voyager.c voyager
+
+# SM502 specific I2C bus bit-banging
+device gdiumiic: i2cbus, i2c_bitbang
+attach gdiumiic at gpio
+file arch/loongson/dev/gdiumiic.c gdiumiic
+
+# Silicon Motion SM502/SM712 frame buffer
device smfb: wsemuldisplaydev, rasops16
-attach smfb at pci
+attach smfb at pci with smfb_pci
+attach smfb at voyager with smfb_voyager
file arch/loongson/dev/smfb.c smfb needs-flag
diff --git a/sys/arch/loongson/dev/gdiumiic.c b/sys/arch/loongson/dev/gdiumiic.c
new file mode 100644
index 00000000000..4120b19ff97
--- /dev/null
+++ b/sys/arch/loongson/dev/gdiumiic.c
@@ -0,0 +1,355 @@
+/* $OpenBSD: gdiumiic.c,v 1.1 2010/02/18 22:45:28 miod Exp $ */
+
+/*
+ * Copyright (c) 2010 Miodrag Vallat.
+ * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
+ *
+ * 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.
+ */
+
+/*
+ * I2C bus bit-banging through GPIO pins.
+ *
+ * Derived from /sys/dev/gpio/gpioiic.c, with SDA and SCL pin order
+ * exchanged, and knowledge of bus contents added.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/gpio.h>
+#include <sys/rwlock.h>
+
+#include <dev/gpio/gpiovar.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/i2c_bitbang.h>
+
+#define GPIOIIC_PIN_SDA 1
+#define GPIOIIC_PIN_SCL 0
+#define GPIOIIC_NPINS 2
+
+#define GPIOIIC_SDA 0x02
+#define GPIOIIC_SCL 0x01
+
+struct gdiumiic_softc {
+ struct device sc_dev;
+
+ void * sc_gpio;
+ struct gpio_pinmap sc_map;
+ int __map[GPIOIIC_NPINS];
+
+ struct i2c_controller sc_i2c_tag;
+ struct rwlock sc_i2c_lock;
+
+ int sc_sda;
+ int sc_scl;
+};
+
+int gdiumiic_match(struct device *, void *, void *);
+void gdiumiic_attach(struct device *, struct device *, void *);
+int gdiumiic_detach(struct device *, int);
+
+int gdiumiic_i2c_acquire_bus(void *, int);
+void gdiumiic_i2c_release_bus(void *, int);
+int gdiumiic_i2c_send_start(void *, int);
+int gdiumiic_i2c_send_stop(void *, int);
+int gdiumiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
+int gdiumiic_i2c_read_byte(void *, u_int8_t *, int);
+int gdiumiic_i2c_write_byte(void *, u_int8_t, int);
+
+void gdiumiic_bb_set_bits(void *, u_int32_t);
+void gdiumiic_bb_set_dir(void *, u_int32_t);
+u_int32_t gdiumiic_bb_read_bits(void *);
+
+int gdiumiic_bustype(struct gpio_attach_args *);
+void gdiumiic_sensors_scan(struct device *,
+ struct i2cbus_attach_args *, void *);
+
+struct cfattach gdiumiic_ca = {
+ sizeof(struct gdiumiic_softc),
+ gdiumiic_match,
+ gdiumiic_attach,
+ gdiumiic_detach
+};
+
+struct cfdriver gdiumiic_cd = {
+ NULL, "gdiumiic", DV_DULL
+};
+
+static const struct i2c_bitbang_ops gdiumiic_bbops = {
+ gdiumiic_bb_set_bits,
+ gdiumiic_bb_set_dir,
+ gdiumiic_bb_read_bits,
+ { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 }
+};
+
+#define GDIUMIIC_BUSTYPE_SENSORS 0
+#define GDIUMIIC_BUSTYPE_VIDCTRL 1
+
+int
+gdiumiic_bustype(struct gpio_attach_args *ga)
+{
+ extern int gdium_revision;
+
+ /*
+ * Hardware pin connections depend upon the motherboard revision.
+ * XXX magic numbers (should match kernel configuration)
+ */
+ switch (gdium_revision) {
+ case 0:
+ if (ga->ga_offset == 46 && ga->ga_mask == 0x03)
+ return GDIUMIIC_BUSTYPE_SENSORS;
+ break;
+ default:
+ if (ga->ga_offset == 6 && ga->ga_mask == 0x81)
+ return GDIUMIIC_BUSTYPE_SENSORS;
+ break;
+ }
+
+ if (ga->ga_offset == 41 && ga->ga_mask == 0x03)
+ return GDIUMIIC_BUSTYPE_VIDCTRL;
+
+ return -1;
+
+}
+
+int
+gdiumiic_match(struct device *parent, void *match, void *aux)
+{
+ struct cfdata *cf = match;
+ struct gpio_attach_args *ga = aux;
+
+ if (ga->ga_offset == -1 || gdiumiic_bustype(ga) < 0)
+ return 0;
+
+ return (strcmp(cf->cf_driver->cd_name, "gdiumiic") == 0);
+}
+
+void
+gdiumiic_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gdiumiic_softc *sc = (struct gdiumiic_softc *)self;
+ struct gpio_attach_args *ga = aux;
+ struct i2cbus_attach_args iba;
+ int caps;
+
+ /* Check that we have enough pins */
+ if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
+ printf(": invalid pin mask\n");
+ return;
+ }
+
+ /* Map pins */
+ sc->sc_gpio = ga->ga_gpio;
+ sc->sc_map.pm_map = sc->__map;
+ if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
+ &sc->sc_map)) {
+ printf(": can't map pins\n");
+ return;
+ }
+
+ /* Configure SDA pin */
+ caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA);
+ if (!(caps & GPIO_PIN_OUTPUT)) {
+ printf(": SDA pin is unable to drive output\n");
+ goto fail;
+ }
+ if (!(caps & GPIO_PIN_INPUT)) {
+ printf(": SDA pin is unable to read input\n");
+ goto fail;
+ }
+ printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]);
+ sc->sc_sda = GPIO_PIN_OUTPUT;
+#if 0
+ if (caps & GPIO_PIN_OPENDRAIN) {
+ printf(" open-drain");
+ sc->sc_sda |= GPIO_PIN_OPENDRAIN;
+ } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
+ printf(" push-pull tri-state");
+ sc->sc_sda |= GPIO_PIN_PUSHPULL;
+ }
+ if (caps & GPIO_PIN_PULLUP) {
+ printf(" pull-up");
+ sc->sc_sda |= GPIO_PIN_PULLUP;
+ }
+#endif
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda);
+
+ /* Configure SCL pin */
+ caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL);
+ if (!(caps & GPIO_PIN_OUTPUT)) {
+ printf(": SCL pin is unable to drive output\n");
+ goto fail;
+ }
+ printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]);
+ sc->sc_scl = GPIO_PIN_OUTPUT;
+#if 0
+ if (caps & GPIO_PIN_OPENDRAIN) {
+ printf(" open-drain");
+ sc->sc_scl |= GPIO_PIN_OPENDRAIN;
+ if (caps & GPIO_PIN_PULLUP) {
+ printf(" pull-up");
+ sc->sc_scl |= GPIO_PIN_PULLUP;
+ }
+ } else if (caps & GPIO_PIN_PUSHPULL) {
+ printf(" push-pull");
+ sc->sc_scl |= GPIO_PIN_PUSHPULL;
+ }
+#endif
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl);
+
+ printf("\n");
+
+ /* Attach I2C bus */
+ rw_init(&sc->sc_i2c_lock, "iiclk");
+ sc->sc_i2c_tag.ic_cookie = sc;
+ sc->sc_i2c_tag.ic_acquire_bus = gdiumiic_i2c_acquire_bus;
+ sc->sc_i2c_tag.ic_release_bus = gdiumiic_i2c_release_bus;
+ sc->sc_i2c_tag.ic_send_start = gdiumiic_i2c_send_start;
+ sc->sc_i2c_tag.ic_send_stop = gdiumiic_i2c_send_stop;
+ sc->sc_i2c_tag.ic_initiate_xfer = gdiumiic_i2c_initiate_xfer;
+ sc->sc_i2c_tag.ic_read_byte = gdiumiic_i2c_read_byte;
+ sc->sc_i2c_tag.ic_write_byte = gdiumiic_i2c_write_byte;
+
+ bzero(&iba, sizeof(iba));
+ iba.iba_name = "iic";
+ iba.iba_tag = &sc->sc_i2c_tag;
+ if (gdiumiic_bustype(ga) == GDIUMIIC_BUSTYPE_SENSORS)
+ iba.iba_bus_scan = gdiumiic_sensors_scan;
+ config_found(self, &iba, iicbus_print);
+
+ return;
+
+fail:
+ gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
+}
+
+int
+gdiumiic_detach(struct device *self, int flags)
+{
+ return (0);
+}
+
+int
+gdiumiic_i2c_acquire_bus(void *cookie, int flags)
+{
+ struct gdiumiic_softc *sc = cookie;
+
+ if (cold || (flags & I2C_F_POLL))
+ return (0);
+
+ return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
+}
+
+void
+gdiumiic_i2c_release_bus(void *cookie, int flags)
+{
+ struct gdiumiic_softc *sc = cookie;
+
+ if (cold || (flags & I2C_F_POLL))
+ return;
+
+ rw_exit(&sc->sc_i2c_lock);
+}
+
+int
+gdiumiic_i2c_send_start(void *cookie, int flags)
+{
+ return (i2c_bitbang_send_start(cookie, flags, &gdiumiic_bbops));
+}
+
+int
+gdiumiic_i2c_send_stop(void *cookie, int flags)
+{
+ return (i2c_bitbang_send_stop(cookie, flags, &gdiumiic_bbops));
+}
+
+int
+gdiumiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
+{
+ return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gdiumiic_bbops));
+}
+
+int
+gdiumiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags)
+{
+ return (i2c_bitbang_read_byte(cookie, bytep, flags, &gdiumiic_bbops));
+}
+
+int
+gdiumiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags)
+{
+ return (i2c_bitbang_write_byte(cookie, byte, flags, &gdiumiic_bbops));
+}
+
+void
+gdiumiic_bb_set_bits(void *cookie, u_int32_t bits)
+{
+ struct gdiumiic_softc *sc = cookie;
+
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
+ bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
+ gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL,
+ bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
+}
+
+void
+gdiumiic_bb_set_dir(void *cookie, u_int32_t bits)
+{
+ struct gdiumiic_softc *sc = cookie;
+ int sda = sc->sc_sda;
+
+ sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
+ sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
+#if 0
+ if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA))
+ sda |= GPIO_PIN_TRISTATE;
+#endif
+ if (sc->sc_sda != sda) {
+ sc->sc_sda = sda;
+ gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
+ sc->sc_sda);
+ }
+}
+
+u_int32_t
+gdiumiic_bb_read_bits(void *cookie)
+{
+ struct gdiumiic_softc *sc = cookie;
+
+ return (gpio_pin_read(sc->sc_gpio, &sc->sc_map,
+ GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0);
+}
+
+/*
+ * Attach devices to the first (sensors + RTC) i2c bus.
+ *
+ * Note that the i2c scan performed by the MI i2c code will fail to
+ * identify our lm75 chip correctly.
+ */
+void
+gdiumiic_sensors_scan(struct device *iicdev, struct i2cbus_attach_args *iba,
+ void *arg)
+{
+ struct i2c_attach_args ia;
+ /* not worth #define'ing _I2C_PRIVATE for */
+ extern int iic_print(void *, const char *);
+
+ bzero(&ia, sizeof ia);
+ ia.ia_tag = iba->iba_tag;
+ ia.ia_addr = 0x48;
+ ia.ia_size = 1;
+ ia.ia_name = "lm75";
+ config_found(iicdev, &ia, iic_print);
+}
diff --git a/sys/arch/loongson/dev/glxpcib.c b/sys/arch/loongson/dev/glxpcib.c
index f3049b9f2b9..1d77c31cd74 100644
--- a/sys/arch/loongson/dev/glxpcib.c
+++ b/sys/arch/loongson/dev/glxpcib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: glxpcib.c,v 1.3 2010/02/05 22:19:24 miod Exp $ */
+/* $OpenBSD: glxpcib.c,v 1.4 2010/02/18 22:45:28 miod Exp $ */
/*
* Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org>
@@ -183,6 +183,7 @@ glxpcib_attach(struct device *parent, struct device *self, void *aux)
struct glxpcib_softc *sc = (struct glxpcib_softc *)self;
struct timecounter *tc = &sc->sc_timecounter;
#if NGPIO > 0
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
u_int64_t wa, ga;
struct gpiobus_attach_args gba;
int i, gpio = 0;
diff --git a/sys/arch/loongson/dev/smfb.c b/sys/arch/loongson/dev/smfb.c
index 281e7ccf93e..7bb9ace4430 100644
--- a/sys/arch/loongson/dev/smfb.c
+++ b/sys/arch/loongson/dev/smfb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smfb.c,v 1.4 2010/02/05 20:56:49 miod Exp $ */
+/* $OpenBSD: smfb.c,v 1.5 2010/02/18 22:45:28 miod Exp $ */
/*
* Copyright (c) 2009, 2010 Miodrag Vallat.
@@ -17,8 +17,7 @@
*/
/*
- * Routines for early console with video memory at fixed address.
- * And eventually the whole driver as well.
+ * Minimal SiliconMotion SM502 and SM712 frame buffer driver.
*/
#include <sys/param.h>
@@ -38,6 +37,8 @@
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
+#include <loongson/dev/voyagerreg.h>
+#include <loongson/dev/voyagervar.h>
#include <loongson/dev/smfbreg.h>
#define DPR_READ(fb, reg) (fb)->dpr[(reg) / 4]
@@ -76,11 +77,17 @@ struct smfb_softc {
int sc_nscr;
};
-int smfb_match(struct device *, void *, void *);
-void smfb_attach(struct device *, struct device *, void *);
+int smfb_pci_match(struct device *, void *, void *);
+void smfb_pci_attach(struct device *, struct device *, void *);
+int smfb_voyager_match(struct device *, void *, void *);
+void smfb_voyager_attach(struct device *, struct device *, void *);
-const struct cfattach smfb_ca = {
- sizeof(struct smfb_softc), smfb_match, smfb_attach
+const struct cfattach smfb_pci_ca = {
+ sizeof(struct smfb_softc), smfb_pci_match, smfb_pci_attach
+};
+
+const struct cfattach smfb_voyager_ca = {
+ sizeof(struct smfb_softc), smfb_voyager_match, smfb_voyager_attach
};
struct cfdriver smfb_cd = {
@@ -117,41 +124,37 @@ 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);
+
+void smfb_attach_common(struct smfb_softc *, int);
static struct smfb smfbcn;
+const struct pci_matchid smfb_devices[] = {
+ { PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712 }
+};
+
int
-smfb_is5xx(pcireg_t id)
+smfb_pci_match(struct device *parent, void *vcf, void *aux)
{
- 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;
- }
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ return pci_matchbyid(pa, smfb_devices, nitems(smfb_devices));
}
int
-smfb_match(struct device *parent, void *vcf, void *aux)
+smfb_voyager_match(struct device *parent, void *vcf, void *aux)
{
- struct pci_attach_args *pa = (struct pci_attach_args *)aux;
- int is5xx = smfb_is5xx(pa->pa_id);
+ struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
+ struct cfdata *cf = (struct cfdata *)vcf;
- return is5xx < 0 ? 0 : 1;
+ return strcmp(vaa->vaa_name, cf->cf_driver->cd_name) == 0;
}
void
-smfb_attach(struct device *parent, struct device *self, void *aux)
+smfb_pci_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, 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,
@@ -160,14 +163,29 @@ 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);
- }
- }
+ smfb_attach_common(sc, 0);
+}
+
+void
+smfb_voyager_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct smfb_softc *sc = (struct smfb_softc *)self;
+ struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
+
+ sc->sc_memt = vaa->vaa_fbt;
+ sc->sc_memh = vaa->vaa_fbh;
+ sc->sc_regt = vaa->vaa_mmiot;
+ sc->sc_regh = vaa->vaa_mmioh;
+
+ smfb_attach_common(sc, 1);
+}
+
+void
+smfb_attach_common(struct smfb_softc *sc, int is5xx)
+{
+ struct wsemuldisplaydev_attach_args waa;
+ vaddr_t fbbase, regbase;
+ int console;
console = smfbcn.ri.ri_hw != NULL;
@@ -178,7 +196,7 @@ smfb_attach(struct device *parent, struct device *self, void *aux)
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 (sc->sc_regh != 0) {
+ if (is5xx) {
regbase = (vaddr_t)bus_space_vaddr(sc->sc_regt,
sc->sc_regh);
} else {
@@ -190,6 +208,7 @@ smfb_attach(struct device *parent, struct device *self, void *aux)
}
}
+ /* XXX print resolution */
printf("\n");
sc->sc_scrlist[0] = &sc->sc_fb->wsd;
@@ -327,14 +346,10 @@ smfb_setup(struct smfb *fb, vaddr_t fbbase, vaddr_t regbase)
fb->wsd.capabilities = ri->ri_caps;
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;
- }
+ fb->dpr = (volatile uint32_t *)(regbase + SM5XX_DPR_BASE);
+ fb->mmio = NULL;
+ fb->regs = (volatile uint32_t *)(regbase + SM5XX_MMIO_BASE);
+ accel = 1;
} else {
fb->dpr = (volatile uint32_t *)(fbbase + SM7XX_DPR_BASE);
fb->mmio = (volatile uint8_t *)(fbbase + SM7XX_MMIO_BASE);
@@ -507,9 +522,9 @@ smfb_wait(struct smfb *fb)
i = 10000;
while (i-- != 0) {
if (fb->is5xx) {
- reg = REG_READ(fb, REG_SYSTEM_CONTROL);
- if ((reg & (RSC_FIFO_EMPTY | RSC_STATUS_BUSY)) ==
- RSC_FIFO_EMPTY)
+ reg = REG_READ(fb, VOYAGER_SYSTEM_CONTROL);
+ if ((reg & (VSC_FIFO_EMPTY | VSC_STATUS_BUSY)) ==
+ VSC_FIFO_EMPTY)
return 0;
} else {
fb->mmio[0x3c4] = 0x16;
@@ -540,9 +555,16 @@ smfb_cnattach(bus_space_tag_t memt, pcitag_t tag, pcireg_t id)
int rc, is5xx;
/* filter out unrecognized devices */
- is5xx = smfb_is5xx(id);
- if (is5xx < 0)
+ switch(id) {
+ default:
return ENODEV;
+ case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM712):
+ is5xx = 0;
+ break;
+ case PCI_ID_CODE(PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM501):
+ is5xx = 1;
+ break;
+ }
smfbcn.is5xx = is5xx;
@@ -551,11 +573,13 @@ smfb_cnattach(bus_space_tag_t memt, pcitag_t tag, pcireg_t id)
return EINVAL;
fbbase = memt->bus_base + PCI_MAPREG_MEM_ADDR(bar);
- 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);
+ if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
+ return EINVAL;
+ regbase = memt->bus_base + PCI_MAPREG_MEM_ADDR(bar);
+ } else {
+ regbase = 0;
}
rc = smfb_setup(&smfbcn, fbbase, regbase);
diff --git a/sys/arch/loongson/dev/smfbreg.h b/sys/arch/loongson/dev/smfbreg.h
index 3b05235d6a6..92cbd81b120 100644
--- a/sys/arch/loongson/dev/smfbreg.h
+++ b/sys/arch/loongson/dev/smfbreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smfbreg.h,v 1.3 2010/02/09 05:39:39 miod Exp $ */
+/* $OpenBSD: smfbreg.h,v 1.4 2010/02/18 22:45:28 miod Exp $ */
/*
* Copyright (c) 2009, 2010 Miodrag Vallat.
@@ -70,13 +70,3 @@
*/
#define SM7XX_MMIO_BASE 0x00700000
-
-/*
- * Generic registers (SM5xx only)
- */
-
-#define SM5XX_REG_BASE 0x00000000
-
-#define REG_SYSTEM_CONTROL 0x00
-#define RSC_FIFO_EMPTY 0x00100000
-#define RSC_STATUS_BUSY 0x00080000
diff --git a/sys/arch/loongson/dev/voyager.c b/sys/arch/loongson/dev/voyager.c
new file mode 100644
index 00000000000..a72681e81ec
--- /dev/null
+++ b/sys/arch/loongson/dev/voyager.c
@@ -0,0 +1,260 @@
+/* $OpenBSD: voyager.c,v 1.1 2010/02/18 22:45:28 miod Exp $ */
+
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * Silicon Motion SM501/SM502 (VoyagerGX) master driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <dev/gpio/gpiovar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <loongson/dev/voyagerreg.h>
+#include <loongson/dev/voyagervar.h>
+
+struct voyager_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_fbt;
+ bus_space_handle_t sc_fbh;
+ bus_size_t sc_fbsize;
+
+ bus_space_tag_t sc_mmiot;
+ bus_space_handle_t sc_mmioh;
+ bus_size_t sc_mmiosize;
+
+ struct gpio_chipset_tag sc_gpio_tag;
+ gpio_pin_t sc_gpio_pins[VOYAGER_NGPIO];
+};
+
+int voyager_match(struct device *, void *, void *);
+void voyager_attach(struct device *, struct device *, void *);
+
+const struct cfattach voyager_ca = {
+ sizeof(struct voyager_softc), voyager_match, voyager_attach
+};
+
+struct cfdriver voyager_cd = {
+ NULL, "voyager", DV_DULL
+};
+
+void voyager_attach_gpio(struct voyager_softc *);
+int voyager_print(void *, const char *);
+int voyager_search(struct device *, void *, void *);
+
+const struct pci_matchid voyager_devices[] = {
+ /*
+ * 502 shares the same device ID as 501, but uses a different
+ * revision number.
+ */
+ { PCI_VENDOR_SMI, PCI_PRODUCT_SMI_SM501 }
+};
+
+int
+voyager_match(struct device *parent, void *vcf, void *aux)
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ return pci_matchbyid(pa, voyager_devices, nitems(voyager_devices));
+}
+
+void
+voyager_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct voyager_softc *sc = (struct voyager_softc *)self;
+ struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+ if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_LINEAR, &sc->sc_fbt, &sc->sc_fbh,
+ NULL, &sc->sc_fbsize, 0) != 0) {
+ printf(": can't map frame buffer\n");
+ return;
+ }
+
+ if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_LINEAR, &sc->sc_mmiot, &sc->sc_mmioh,
+ NULL, &sc->sc_mmiosize, 0) != 0) {
+ printf(": can't map mmio\n");
+ bus_space_unmap(sc->sc_fbt, sc->sc_fbh, sc->sc_fbsize);
+ return;
+ }
+
+ printf("\n");
+
+ /*
+ * Attach GPIO devices.
+ */
+ voyager_attach_gpio(sc);
+
+ /*
+ * Attach child devices.
+ */
+ config_search(voyager_search, self, pa);
+}
+
+int
+voyager_print(void *args, const char *parentname)
+{
+ struct voyager_attach_args *vaa = (struct voyager_attach_args *)args;
+
+ if (parentname != NULL)
+ printf("%s at %s", vaa->vaa_name, parentname);
+
+ return UNCONF;
+}
+
+int
+voyager_search(struct device *parent, void *vcf, void *args)
+{
+ struct voyager_softc *sc = (struct voyager_softc *)parent;
+ struct cfdata *cf = (struct cfdata *)vcf;
+ struct pci_attach_args *pa = (struct pci_attach_args *)args;
+ struct voyager_attach_args vaa;
+
+ /*
+ * Caller should have attached gpio already. If it didn't, bail
+ * out here.
+ */
+ if (strcmp(cf->cf_driver->cd_name, "gpio") == 0)
+ return 0;
+
+ vaa.vaa_name = cf->cf_driver->cd_name;
+ vaa.vaa_pa = pa;
+ vaa.vaa_fbt = sc->sc_fbt;
+ vaa.vaa_fbh = sc->sc_fbh;
+ vaa.vaa_mmiot = sc->sc_mmiot;
+ vaa.vaa_mmioh = sc->sc_mmioh;
+
+ if (cf->cf_attach->ca_match(parent, cf, &vaa) == 0)
+ return 0;
+
+ config_attach(parent, cf, &vaa, voyager_print);
+ return 1;
+}
+
+/*
+ * GPIO support code
+ */
+
+int voyager_gpio_pin_read(void *, int);
+void voyager_gpio_pin_write(void *, int, int);
+void voyager_gpio_pin_ctl(void *, int, int);
+
+static const struct gpio_chipset_tag voyager_gpio_tag = {
+ .gp_pin_read = voyager_gpio_pin_read,
+ .gp_pin_write = voyager_gpio_pin_write,
+ .gp_pin_ctl = voyager_gpio_pin_ctl
+};
+
+int
+voyager_gpio_pin_read(void *cookie, int pin)
+{
+ struct voyager_softc *sc = (struct voyager_softc *)cookie;
+ bus_addr_t reg;
+ int32_t data, mask;
+
+ if (pin >= 32) {
+ pin -= 32;
+ reg = VOYAGER_GPIO_DATA_HIGH;
+ } else {
+ reg = VOYAGER_GPIO_DATA_LOW;
+ }
+ mask = 1 << pin;
+
+ data = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, reg);
+ return data & mask ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
+}
+
+void
+voyager_gpio_pin_write(void *cookie, int pin, int val)
+{
+ struct voyager_softc *sc = (struct voyager_softc *)cookie;
+ bus_addr_t reg;
+ int32_t data, mask;
+
+ if (pin >= 32) {
+ pin -= 32;
+ reg = VOYAGER_GPIO_DATA_HIGH;
+ } else {
+ reg = VOYAGER_GPIO_DATA_LOW;
+ }
+ mask = 1 << pin;
+ data = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, reg);
+ if (val)
+ data |= mask;
+ else
+ data &= ~mask;
+ bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, reg, data);
+}
+
+void
+voyager_gpio_pin_ctl(void *cookie, int pin, int flags)
+{
+ struct voyager_softc *sc = (struct voyager_softc *)cookie;
+ bus_addr_t reg;
+ int32_t data, mask;
+
+ if (pin >= 32) {
+ pin -= 32;
+ reg = VOYAGER_GPIO_DIR_HIGH;
+ } else {
+ reg = VOYAGER_GPIO_DIR_LOW;
+ }
+ mask = 1 << pin;
+ data = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh, reg);
+ if (ISSET(flags, GPIO_PIN_OUTPUT))
+ data |= mask;
+ else
+ data &= ~mask;
+ bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, reg, data);
+}
+
+void
+voyager_attach_gpio(struct voyager_softc *sc)
+{
+ struct gpiobus_attach_args gba;
+ int pin;
+
+ bcopy(&voyager_gpio_tag, &sc->sc_gpio_tag, sizeof voyager_gpio_tag);
+ sc->sc_gpio_tag.gp_cookie = sc;
+
+ for (pin = 0; pin < VOYAGER_NGPIO; pin++) {
+ sc->sc_gpio_pins[pin].pin_num = pin;
+ sc->sc_gpio_pins[pin].pin_caps =
+ GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+ sc->sc_gpio_pins[pin].pin_state =
+ voyager_gpio_pin_read(sc, pin);
+ }
+
+ gba.gba_name = "gpio";
+ gba.gba_gc = &sc->sc_gpio_tag;
+ gba.gba_pins = sc->sc_gpio_pins;
+ gba.gba_npins = VOYAGER_NGPIO;
+
+ config_found(&sc->sc_dev, &gba, voyager_print);
+}
diff --git a/sys/arch/loongson/dev/voyagerreg.h b/sys/arch/loongson/dev/voyagerreg.h
new file mode 100644
index 00000000000..4a56a51d88c
--- /dev/null
+++ b/sys/arch/loongson/dev/voyagerreg.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: voyagerreg.h,v 1.1 2010/02/18 22:45:28 miod Exp $ */
+
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+/*
+ * Silicon Motion SM501/SM502 registers
+ */
+
+#define SM5XX_MMIO_BASE 0x00000000
+
+#define VOYAGER_SYSTEM_CONTROL 0x00
+#define VSC_FIFO_EMPTY 0x00100000
+#define VSC_STATUS_BUSY 0x00080000
+
+/*
+ * GPIO
+ */
+
+#define VOYAGER_NGPIO (32 + 32)
+
+#define VOYAGER_GPIO_DATA_LOW 0x00010000
+#define VOYAGER_GPIO_DATA_HIGH 0x00010004
+#define VOYAGER_GPIO_DIR_LOW 0x00010008
+#define VOYAGER_GPIO_DIR_HIGH 0x0001000c
diff --git a/sys/arch/loongson/dev/voyagervar.h b/sys/arch/loongson/dev/voyagervar.h
new file mode 100644
index 00000000000..6e4e38f43ec
--- /dev/null
+++ b/sys/arch/loongson/dev/voyagervar.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: voyagervar.h,v 1.1 2010/02/18 22:45:28 miod Exp $ */
+
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+struct voyager_attach_args {
+ const char *vaa_name;
+
+ struct pci_attach_args *vaa_pa;
+ bus_space_tag_t vaa_fbt;
+ bus_space_handle_t vaa_fbh;
+ bus_space_tag_t vaa_mmiot;
+ bus_space_handle_t vaa_mmioh;
+};