Module Name:    src
Committed By:   mlelstv
Date:           Tue Jan 21 14:52:07 UTC 2014

Modified Files:
        src/sys/dev/pci: files.pci
Added Files:
        src/sys/dev/pci: igma.c igmareg.h igmavar.h
        src/sys/dev/pci/igma: igmafb.c

Log Message:
wscons driver for Intel Graphics Media Accelerator.
Initial commit that already works for a couple of Notebooks
based on G35, G45, Sandy Bridge and Ivy Bridge chips.

Despite the word 'Accelerator' there is nothing acclerated yet.


To generate a diff of this commit:
cvs rdiff -u -r1.367 -r1.368 src/sys/dev/pci/files.pci
cvs rdiff -u -r0 -r1.1 src/sys/dev/pci/igma.c src/sys/dev/pci/igmareg.h \
    src/sys/dev/pci/igmavar.h
cvs rdiff -u -r0 -r1.1 src/sys/dev/pci/igma/igmafb.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/files.pci
diff -u src/sys/dev/pci/files.pci:1.367 src/sys/dev/pci/files.pci:1.368
--- src/sys/dev/pci/files.pci:1.367	Wed Sep 18 14:30:45 2013
+++ src/sys/dev/pci/files.pci	Tue Jan 21 14:52:07 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: files.pci,v 1.367 2013/09/18 14:30:45 macallan Exp $
+#	$NetBSD: files.pci,v 1.368 2014/01/21 14:52:07 mlelstv Exp $
 #
 # Config file and device description for machine-independent PCI code.
 # Included by ports that need it.  Requires that the SCSI files be
@@ -1128,6 +1128,12 @@ device	lynxfb: wsemuldisplaydev, rasops1
 attach	lynxfb at pci
 file	dev/pci/lynxfb.c	lynxfb needs-flag
 
+include "dev/pci/igma/files.igma"
+# Intel GMA
+device	igma: igmabus, i2cbus, i2c_bitbang, ddc_read_edid, edid
+attach	igma at pci
+file	dev/pci/igma.c		igma
+
 # 3Dfx Voodoo Graphics
 defflag	opt_tdvfb.h		TDVFB_CONSOLE
 device	tdvfb: wsemuldisplaydev, rasops16, rasops32, vcons, videomode

Added files:

Index: src/sys/dev/pci/igma.c
diff -u /dev/null src/sys/dev/pci/igma.c:1.1
--- /dev/null	Tue Jan 21 14:52:07 2014
+++ src/sys/dev/pci/igma.c	Tue Jan 21 14:52:07 2014
@@ -0,0 +1,642 @@
+/*	$NetBSD: igma.c,v 1.1 2014/01/21 14:52:07 mlelstv Exp $	*/
+
+/*
+ * Copyright (c) 2014 Michael van Elst
+ *
+ * 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.
+ */
+
+/*
+ * Intel Graphic Media Accelerator
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: igma.c,v 1.1 2014/01/21 14:52:07 mlelstv Exp $");
+
+#include "vga.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/bus.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pciio.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/i2c_bitbang.h>
+#include <dev/i2c/ddcvar.h>
+
+#include <dev/videomode/videomode.h>
+#include <dev/videomode/edidvar.h>
+
+#include <dev/wscons/wsdisplayvar.h>
+
+#if NVGA > 0
+#include <dev/ic/mc6845reg.h>
+#include <dev/ic/pcdisplayvar.h>
+#include <dev/ic/vgareg.h>
+#include <dev/ic/vgavar.h>
+#endif
+
+#include <dev/pci/igmareg.h>
+#include <dev/pci/igmavar.h>
+
+#include "igmafb.h"
+
+struct igma_softc;
+struct igma_i2c {
+	kmutex_t		ii_lock;
+	struct igma_softc	*ii_sc;
+	bus_addr_t		ii_reg;
+	struct i2c_controller	ii_i2c;
+	const char		*ii_name;
+	u_int32_t		ii_dir;
+};
+
+struct igma_softc {
+	device_t		sc_dev;
+	struct igma_chip        sc_chip;
+	struct igma_i2c		sc_ii[GMBUS_NUM_PORTS];
+};
+
+static int igma_match(device_t, cfdata_t, void *);
+static void igma_attach(device_t, device_t, void *);
+static int igma_print(void *, const char *);
+
+static void igma_i2c_attach(struct igma_softc *);
+
+CFATTACH_DECL_NEW(igma, sizeof(struct igma_softc),
+    igma_match, igma_attach, NULL, NULL);
+
+static int igma_i2c_acquire_bus(void *, int);
+static void igma_i2c_release_bus(void *, int);
+static int igma_i2c_send_start(void *, int);
+static int igma_i2c_send_stop(void *, int);
+static int igma_i2c_initiate_xfer(void *, i2c_addr_t, int);
+static int igma_i2c_read_byte(void *, uint8_t *, int);
+static int igma_i2c_write_byte(void *, uint8_t, int);
+static void igma_i2cbb_set_bits(void *, uint32_t);
+static void igma_i2cbb_set_dir(void *, uint32_t);
+static uint32_t igma_i2cbb_read(void *);
+
+static void igma_reg_barrier(const struct igma_chip *, int);
+static u_int32_t igma_reg_read(const struct igma_chip *, int);
+static void igma_reg_write(const struct igma_chip *, int, u_int32_t);
+static u_int8_t igma_vga_read(const struct igma_chip *, int);
+static void igma_vga_write(const struct igma_chip *, int , u_int8_t);
+#if 0
+static u_int8_t igma_crtc_read(const struct igma_chip *, int);
+static void igma_crtc_write(const struct igma_chip *, int, u_int8_t);
+#endif
+
+static const struct i2c_bitbang_ops igma_i2cbb_ops = {
+	igma_i2cbb_set_bits,
+	igma_i2cbb_set_dir,
+	igma_i2cbb_read,
+	{ 1, 2, 0, 1 }
+};
+
+static const struct igma_chip_ops igma_bus_ops = {
+	igma_reg_barrier,
+	igma_reg_read,
+	igma_reg_write,
+	igma_vga_read,
+	igma_vga_write,
+#if 0
+	igma_crtc_read,
+	igma_crtc_write,
+#endif
+};
+
+static struct igma_product {
+        u_int16_t product;
+	int gentype;
+	int num_pipes;
+} const igma_products[] = {
+	/* i830 */
+	{ PCI_PRODUCT_INTEL_82830MP_IV,           200,2 },
+	/* i845g */
+	{ PCI_PRODUCT_INTEL_82845G_IGD,           200,2 },
+	/* i85x */
+	{ PCI_PRODUCT_INTEL_82855GM_IGD,          200,2 },
+// 0x358e ?
+	/* i865g */
+	{ PCI_PRODUCT_INTEL_82865_IGD,            200,2 },
+	/* i915g */
+	{ PCI_PRODUCT_INTEL_82915G_IGD,           200,2 },
+	{ PCI_PRODUCT_INTEL_E7221_IGD,            200,2 },
+	/* i915gm */
+	{ PCI_PRODUCT_INTEL_82915GM_IGD,          300,2 },
+	/* i945g */
+	{ PCI_PRODUCT_INTEL_82945P_IGD,           300,2 },
+	/* i945gm */
+	{ PCI_PRODUCT_INTEL_82945GM_IGD,          300,2 },
+	{ PCI_PRODUCT_INTEL_82945GM_IGD_1,        300,2 },
+	{ PCI_PRODUCT_INTEL_82945GME_IGD,         300,2 },
+	/* i965g */
+	{ PCI_PRODUCT_INTEL_82946GZ_IGD,          300,2 },
+	{ PCI_PRODUCT_INTEL_82G35_IGD,            300,2 },
+	{ PCI_PRODUCT_INTEL_82G35_IGD_1,          300,2 },
+	{ PCI_PRODUCT_INTEL_82965Q_IGD,           300,2 },
+	{ PCI_PRODUCT_INTEL_82965Q_IGD_1,         300,2 },
+	{ PCI_PRODUCT_INTEL_82965G_IGD,           300,2 },
+	{ PCI_PRODUCT_INTEL_82965G_IGD_1,         300,2 },
+	/* g33 */
+	{ PCI_PRODUCT_INTEL_82G33_IGD,            300,2 },
+	{ PCI_PRODUCT_INTEL_82G33_IGD_1,          300,2 },
+	{ PCI_PRODUCT_INTEL_82Q33_IGD,            300,2 },
+	{ PCI_PRODUCT_INTEL_82Q33_IGD_1,          300,2 },
+	{ PCI_PRODUCT_INTEL_82Q35_IGD,            300,2 },
+	{ PCI_PRODUCT_INTEL_82Q35_IGD_1,          300,2 },
+	/* pineview */
+	{ PCI_PRODUCT_INTEL_PINEVIEW_IGD,         350,2 },
+	{ PCI_PRODUCT_INTEL_PINEVIEW_M_IGD,       350,2 },
+	/* i965gm */
+	{ PCI_PRODUCT_INTEL_82965PM_IGD,          400,2 },
+	{ PCI_PRODUCT_INTEL_82965PM_IGD_1,        400,2 },
+	{ PCI_PRODUCT_INTEL_82965GME_IGD,         400,2 },
+	/* gm45 */
+	{ PCI_PRODUCT_INTEL_82GM45_IGD,           450,2 },
+	{ PCI_PRODUCT_INTEL_82GM45_IGD_1,         450,2 },
+	/* g45 */
+	{ PCI_PRODUCT_INTEL_82IGD_E_IGD,          450,2 },
+	{ PCI_PRODUCT_INTEL_82Q45_IGD,            450,2 },
+	{ PCI_PRODUCT_INTEL_82G45_IGD,            450,2 },
+	{ PCI_PRODUCT_INTEL_82G41_IGD,            450,2 },
+	{ PCI_PRODUCT_INTEL_82B43_IGD,            450,2 },
+// 0x2e92 ?
+	/* ironlake d */
+	{ PCI_PRODUCT_INTEL_IRONLAKE_D_IGD,       500,2 },
+	/* ironlake m */
+	{ PCI_PRODUCT_INTEL_IRONLAKE_M_IGD,       500,2 },
+	/* sandy bridge */
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_IGD,      600,2 },
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_IGD_1,    600,2 },
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_IGD_2,    600,2 },
+	/* sandy bridge m */
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_M_IGD,    600,2 },
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_M_IGD_1,  600,2 },
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_M_IGD_2,  600,2 },
+	/* sandy bridge s */
+	{ PCI_PRODUCT_INTEL_SANDYBRIDGE_S_IGD,    600,2 },
+	/* ivy bridge */
+	{ PCI_PRODUCT_INTEL_IVYBRIDGE_IGD,        700,3 },
+	{ PCI_PRODUCT_INTEL_IVYBRIDGE_IGD_1,      700,3 },
+	/* ivy bridge m */
+	{ PCI_PRODUCT_INTEL_IVYBRIDGE_M_IGD,      700,3 },
+	{ PCI_PRODUCT_INTEL_IVYBRIDGE_M_IGD_1,    700,3 },
+	/* ivy bridge s */
+	{ PCI_PRODUCT_INTEL_IVYBRIDGE_S_IGD,      700,3 },
+	{ PCI_PRODUCT_INTEL_IVYBRIDGE_S_IGD_1,    700,3 },
+#if 0
+	/* valleyview d */
+	/* valleyview m */
+	{ PCI_PRODUCT_INTEL_HASWELL_IGD_1,        800,3 },
+	/* haswell d */
+	{ PCI_PRODUCT_INTEL_HASWELL_IGD,          800,3 },
+	{ PCI_PRODUCT_INTEL_HASWELL_IGD_1,        800,3 },
+	/* haswell m */
+	/* broadwell d */
+	/* broadwell m */
+#endif
+};
+
+static int
+igma_newpch_match(const struct pci_attach_args *pa)
+{
+	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
+		return 0;
+	switch (0xff00 & PCI_PRODUCT(pa->pa_id)) {
+	case 0x3b00: /* ibex peak */
+	case 0x1c00: /* cougar point */
+	case 0x1e00: /* panther point */
+	case 0x8c00: /* lynx point */
+	case 0x9c00: /* lynx point lp */
+		return 1;
+	}
+
+	return 0;
+}
+
+static const struct igma_product *
+igma_lookup(const struct pci_attach_args *pa)
+{ 
+        const struct igma_product *ip;
+	int i;
+
+	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
+		return NULL;
+	for (i=0; i < __arraycount(igma_products); ++i) {
+		ip = &igma_products[i];
+                if (PCI_PRODUCT(pa->pa_id) == ip->product)
+                        return ip;
+        }
+        return NULL;
+}
+
+static void
+igma_product_to_chip(const struct pci_attach_args *pa, struct igma_chip *cd)
+{
+	const struct igma_product *ip;
+	struct pci_attach_args PA;
+
+	ip = igma_lookup(pa);
+	KASSERT(ip != NULL);
+
+	cd->ops = &igma_bus_ops;
+	cd->num_gmbus = 6;
+	cd->num_pipes = ip->num_pipes;
+	cd->quirks = 0;
+	cd->backlight_factor = 1;
+
+	cd->gpio_offset = OLD_GPIOA;
+	cd->vga_cntrl = PCH_VGA_CNTRL;
+	cd->backlight_cntrl = OLD_BLC_PWM_CTL;
+	cd->backlight_cntrl2 = OLD_BLC_PWM_CTL2;
+
+	PA = *pa;
+	if (pci_find_device(&PA, igma_newpch_match)) {
+		cd->gpio_offset = PCH_GPIOA;
+		cd->vga_cntrl = CPU_VGA_CNTRL;
+		cd->backlight_cntrl = CPU_BLC_PWM_CTL;
+		cd->backlight_cntrl2 = CPU_BLC_PWM_CTL2;
+	}
+
+	switch (ip->gentype) {
+	case 200:
+		cd->backlight_factor = 2;
+		break;
+	case 300:
+	case 350:
+		cd->backlight_factor = 2;
+		cd->quirks |= IGMA_PFITDISABLE_QUIRK;
+		break;
+	case 450:
+		cd->pri_cntrl = PRI_CTRL_NOTRICKLE;
+		cd->quirks  |= IGMA_PLANESTART_QUIRK;
+		break;
+	default:
+		cd->pri_cntrl = 0;
+		break;
+	}
+}
+
+static void
+igma_adjust_chip(struct igma_softc *sc, struct igma_chip *cd)
+{
+	const struct igma_chip_ops *co = cd->ops;
+	u_int32_t reg;
+
+	reg = co->read_reg(cd, cd->vga_cntrl);
+	if (reg & VGA_PIPE_B_SELECT)
+		cd->use_pipe = 1;
+}
+
+static int
+igma_print(void *aux, const char *pnp)
+{
+	if (pnp)
+		aprint_normal("drm at %s", pnp);
+	return (UNCONF);
+}
+
+static int
+igma_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+	const struct igma_product *ip;
+
+	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
+		return 0;
+
+	ip = igma_lookup(pa);
+	if (ip != NULL)
+		return 100;
+
+	return 0;
+}
+
+static void
+igma_attach(device_t parent, device_t self, void *aux)
+{
+	struct igma_softc *sc = device_private(self);
+	const struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+	struct igma_attach_args iaa;
+	bus_space_tag_t gttmmt, gmt, regt;
+	bus_space_handle_t gttmmh, gmh, regh;
+	bus_addr_t gttmmb, gmb;
+
+	pci_aprint_devinfo(pa, NULL);
+
+	sc->sc_dev = self;
+
+	/* Initialize according to chip type */
+	igma_product_to_chip(pa, &sc->sc_chip);
+
+	if (pci_mapreg_map(pa, PCI_BAR0, PCI_MAPREG_TYPE_MEM,
+			BUS_SPACE_MAP_LINEAR,
+			&gttmmt, &gttmmh, &gttmmb, NULL)) {
+		aprint_error_dev(sc->sc_dev, "unable to map GTTMM\n");
+		return;
+	}
+	sc->sc_chip.mmiot = gttmmt;
+	if (bus_space_subregion(gttmmt, gttmmh, 0, 2*1024*1024,
+			&sc->sc_chip.mmioh)) {
+		aprint_error_dev(sc->sc_dev, "unable to submap MMIO\n");
+		return;
+	}
+	sc->sc_chip.gttt = gttmmt;
+	if (bus_space_subregion(gttmmt, gttmmh, 2*1024*1024, 2*1024*1024,
+			&sc->sc_chip.gtth)) {
+		aprint_error_dev(sc->sc_dev, "unable to submap GTT\n");
+		return;
+	}
+
+	if (pci_mapreg_map(pa, PCI_BAR2, PCI_MAPREG_TYPE_MEM,
+			BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE,
+			&gmt, &gmh, &gmb, NULL)) {
+		aprint_error_dev(sc->sc_dev, "unable to map aperture\n");
+		return;
+	}
+	sc->sc_chip.gmt = gmt;
+	sc->sc_chip.gmh = gmh;
+	sc->sc_chip.gmb = gmb;
+
+	if (pci_mapreg_map(pa, PCI_BAR4, PCI_MAPREG_TYPE_IO, 0,
+			&regt, &regh, NULL, NULL)) {
+		aprint_error_dev(sc->sc_dev, "unable to map IO registers\n");
+		return;
+	}
+
+#if NVGA > 0
+	iaa.iaa_console = vga_cndetach() ? true : false;
+	/* Hack */
+	if (iaa.iaa_console)
+		wsdisplay_cndetach();
+#else
+	iaa.iaa_console = 0;
+#endif
+	sc->sc_chip.vgat = regt;
+	if (bus_space_map(regt, 0x3c0, 0x10, 0, &sc->sc_chip.vgah)) {
+		aprint_error_dev(sc->sc_dev, "unable to map VGA registers\n");
+		return;
+	}
+
+	/* Check hardware for more information */
+	igma_adjust_chip(sc, &sc->sc_chip);
+
+	aprint_normal("%s: VGA_CNTRL: 0x%x\n",device_xname(sc->sc_dev),
+		sc->sc_chip.vga_cntrl);
+	aprint_normal("%s: GPIO_OFFSET: 0x%x\n",device_xname(sc->sc_dev),
+		sc->sc_chip.gpio_offset);
+	aprint_normal("%s: BACKLIGHT_CTRL: 0x%x\n",device_xname(sc->sc_dev),
+		sc->sc_chip.backlight_cntrl);
+	aprint_normal("%s: BACKLIGHT_CTRL2: 0x%x\n",device_xname(sc->sc_dev),
+		sc->sc_chip.backlight_cntrl2);
+
+#if NIGMAFB > 0
+	strcpy(iaa.iaa_name, "igmafb");
+	iaa.iaa_chip = sc->sc_chip;
+	config_found_ia(sc->sc_dev, "igmabus", &iaa, igma_print);
+#endif
+
+	igma_i2c_attach(sc);
+}
+
+static void
+igma_i2c_attach(struct igma_softc *sc)
+{
+	struct igma_i2c *ii;
+	int i;
+#if 0
+	struct i2cbus_attach_args iba;
+#endif
+
+	for (i=0; i<sc->sc_chip.num_gmbus; ++i) {
+		ii = &sc->sc_ii[i];
+		ii->ii_sc = sc;
+
+		/* XXX */
+		ii->ii_reg = sc->sc_chip.gpio_offset - PCH_GPIOA;
+		switch (i) {
+		case 0:
+			ii->ii_reg += PCH_GPIOB;
+			ii->ii_name = "ssc";
+			break;
+		case 1:
+			ii->ii_reg += PCH_GPIOA;
+			ii->ii_name = "vga";
+			break;
+		case 2:
+			ii->ii_reg += PCH_GPIOC;
+			ii->ii_name = "panel";
+			break;
+		case 3:
+			ii->ii_reg += PCH_GPIOD;
+			ii->ii_name = "dpc";
+			break;
+		case 4:
+			ii->ii_reg += PCH_GPIOE;
+			ii->ii_name = "dpb";
+			break;
+		case 5:
+			ii->ii_reg += PCH_GPIOF;
+			ii->ii_name = "dpd";
+			break;
+		default:
+			panic("don't know GMBUS %d\n",i);
+		}
+
+		mutex_init(&ii->ii_lock, MUTEX_DEFAULT, IPL_NONE);
+
+		ii->ii_i2c.ic_cookie = ii;
+		ii->ii_i2c.ic_acquire_bus = igma_i2c_acquire_bus;
+		ii->ii_i2c.ic_release_bus = igma_i2c_release_bus;
+		ii->ii_i2c.ic_send_start = igma_i2c_send_start;
+		ii->ii_i2c.ic_send_stop = igma_i2c_send_stop;
+		ii->ii_i2c.ic_initiate_xfer = igma_i2c_initiate_xfer;
+		ii->ii_i2c.ic_read_byte = igma_i2c_read_byte;
+		ii->ii_i2c.ic_write_byte = igma_i2c_write_byte;
+		ii->ii_i2c.ic_exec = NULL;
+
+#if 0
+		iba.iba_type = I2C_TYPE_SMBUS;
+		iba.iba_tag = &ii->ii_i2c;
+		config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
+#endif
+	}
+}
+
+/*
+ * I2C interface
+ */
+
+static int
+igma_i2c_acquire_bus(void *cookie, int flags)
+{
+	struct igma_i2c *ii = cookie;
+	mutex_enter(&ii->ii_lock);
+	return 0;
+}
+
+static void
+igma_i2c_release_bus(void *cookie, int flags)
+{
+	struct igma_i2c *ii = cookie;
+	mutex_exit(&ii->ii_lock);
+}
+
+static int
+igma_i2c_send_start(void *cookie, int flags)
+{
+	return i2c_bitbang_send_start(cookie, flags, &igma_i2cbb_ops);
+}
+
+static int
+igma_i2c_send_stop(void *cookie, int flags)
+{
+	return i2c_bitbang_send_stop(cookie, flags, &igma_i2cbb_ops);
+}
+
+static int
+igma_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
+{
+	return i2c_bitbang_initiate_xfer(cookie, addr, flags, &igma_i2cbb_ops);
+}
+
+static int
+igma_i2c_read_byte(void *cookie, uint8_t *valp, int flags)
+{
+	return i2c_bitbang_read_byte(cookie, valp, flags, &igma_i2cbb_ops);
+}
+
+static int
+igma_i2c_write_byte(void *cookie, uint8_t val, int flags)
+{
+	return i2c_bitbang_write_byte(cookie, val, flags, &igma_i2cbb_ops);
+}
+
+static void
+igma_i2cbb_set_bits(void *cookie, uint32_t bits)
+{
+	struct igma_i2c *ii = cookie;
+	struct igma_softc *sc = ii->ii_sc;
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	uint32_t reg;
+
+	reg = co->read_reg(cd, ii->ii_reg);
+	reg &= GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE;
+
+	if ((bits | ii->ii_dir) & 1)
+		/* make data input, signal is pulled high */
+		reg |= GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
+        else
+		/* make data output, signal is driven low */
+		reg |= GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK
+			| GPIO_DATA_VAL_MASK;
+
+	if (bits & 2)
+		/* make clock input, signal is pulled high */
+		reg |= GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
+	else
+		/* make clock output, signal is driven low */
+		reg |= GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK
+			| GPIO_CLOCK_VAL_MASK;
+
+	co->write_reg(cd, ii->ii_reg, reg);
+#if 1
+	reg = co->read_reg(cd, ii->ii_reg);
+#else
+	co->barrier(cd, ii->ii_reg);
+#endif
+}
+
+static void
+igma_i2cbb_set_dir(void *cookie, uint32_t bits)
+{
+	struct igma_i2c *ii = cookie;
+
+	ii->ii_dir = bits;
+}
+
+static uint32_t
+igma_i2cbb_read(void *cookie)
+{
+	struct igma_i2c *ii = cookie;
+	struct igma_softc *sc = ii->ii_sc;
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	uint32_t reg;
+	int sda, scl;
+
+	reg = co->read_reg(cd, ii->ii_reg);
+
+	sda = reg & GPIO_DATA_VAL_IN;
+	scl = reg & GPIO_CLOCK_VAL_IN;
+
+	reg = (sda ? 1 : 0) | (scl ? 2 : 0);
+	return reg;
+}
+
+static void
+igma_reg_barrier(const struct igma_chip *cd, int r)
+{
+	bus_space_barrier(cd->mmiot, cd->mmioh, r, sizeof(u_int32_t),
+		BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+}
+
+static u_int32_t
+igma_reg_read(const struct igma_chip *cd, int r)
+{
+	return bus_space_read_4(cd->mmiot, cd->mmioh, r);
+}
+
+static void
+igma_reg_write(const struct igma_chip *cd, int r, u_int32_t v)
+{
+	bus_space_write_4(cd->mmiot, cd->mmioh, r, v);
+}
+
+static u_int8_t
+igma_vga_read(const struct igma_chip *cd, int r)
+{
+	bus_space_write_1(cd->vgat, cd->vgah, 0x4, r | 0x20);
+	return bus_space_read_1(cd->vgat, cd->vgah, 0x5);
+}
+
+static void
+igma_vga_write(const struct igma_chip *cd, int r, u_int8_t v)
+{
+	bus_space_write_1(cd->vgat, cd->vgah, 0x4, r | 0x20);
+	bus_space_write_1(cd->vgat, cd->vgah, 0x5, v);
+}
+
+#if 0
+static u_int8_t
+igma_crtc_read(const struct igma_chip *cd, int r)
+{
+	bus_space_write_1(cd->crtct, cd->crtch, 0x4, r);
+	return bus_space_read_1(cd->crtct, cd->crtch, 0x5);
+}
+
+static void
+igma_crtc_write(const struct igma_chip *cd, int r, u_int8_t v)
+{
+	bus_space_write_1(cd->crtct, cd->crtch, 0x4, r);
+	bus_space_write_1(cd->crtct, cd->crtch, 0x5, v);
+}
+#endif
Index: src/sys/dev/pci/igmareg.h
diff -u /dev/null src/sys/dev/pci/igmareg.h:1.1
--- /dev/null	Tue Jan 21 14:52:07 2014
+++ src/sys/dev/pci/igmareg.h	Tue Jan 21 14:52:07 2014
@@ -0,0 +1,197 @@
+/*	$NetBSD: igmareg.h,v 1.1 2014/01/21 14:52:07 mlelstv Exp $	*/
+
+/*
+ * Copyright (c) 2014 Michael van Elst
+ *
+ * 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.
+ */
+
+#ifndef IGMAREG_H
+#define IGMAREG_H
+
+/* North display */
+
+#define CPU_VGA_CNTRL   0x41000
+#define PCH_VGA_CNTRL   0x71400
+#define   VGA_CNTRL_DISABLE     (1L << 31)
+#define   VGA_2X_MODE           (1L << 29)
+#define   VGA_PIPE_B_SELECT     (1L << 29)
+
+#define PF_WINPOS(i)    (0x68070+i*0x800)
+#define   PF_WINPOS_VAL(x,y) ((x) << 16 | (y))
+#define PF_WINSZ(i)     (0x68074+i*0x800)
+#define   PF_WINSZ_VAL(w,h)      ((w) << 16 | (h))
+#define   PF_WINSZ_GET_WIDTH(r)  (((r) >> 16) & 0x1fff)
+#define   PF_WINSZ_GET_HEIGHT(r) (((r) >>  0) & 0xfff)
+#define PF_CTRL(i)      (0x68080+i*0x800)
+#define PF_CTRL_I965    (0x61230)
+#define   PF_ENABLE            (1L << 31)
+
+#define PIPE_HTOTAL(i)   (0x60000+i*0x1000)
+#define   PIPE_HOTAL_VAL(t,a)       (((t)-1) << 16 | ((a)-1))
+#define   PIPE_HTOTAL_GET_TOTAL(r)  ((((r) >> 16) & 0x1fff)+1)
+#define   PIPE_HTOTAL_GET_ACTIVE(r) ((((r) >> 0) & 0x1fff)+1)
+#define PIPE_HBLANK(i)   (0x60004+i*0x1000)
+#define   PIPE_HBLANK_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define PIPE_HSYNC(i)    (0x60008+i*0x1000)
+#define   PIPE_HSYNC_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define PIPE_VTOTAL(i)   (0x6000c+i*0x1000)
+#define   PIPE_VTOTAL_VAL(t,a)      (((t)-1) << 16 | ((a)-1))
+#define   PIPE_VTOTAL_GET_TOTAL(r)  ((((r) >> 16) & 0xfff)+1)
+#define   PIPE_VTOTAL_GET_ACTIVE(r) ((((r) >> 0) & 0xfff)+1)
+#define PIPE_VBLANK(i)   (0x60010+i*0x1000)
+#define   PIPE_VBLANK_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define PIPE_VSYNC(i)    (0x60014+i*0x1000)
+#define   PIPE_VSYNC_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define PIPE_SRCSZ(i)    (0x6001c+i*0x1000)
+#define   PIPE_SRCSZ_VAL(w,h) (((w)-1) << 16 | ((h)-1))
+#define PIPE_VSHIFT(i)   (0x60028+i*0x1000)
+#define PIPE_DATAM1(i)   (0x60030+i*0x1000)
+#define PIPE_DATAM2(i)   (0x60034+i*0x1000)
+#define PIPE_DATAN1(i)   (0x60038+i*0x1000)
+#define PIPE_DATAN2(i)   (0x6003c+i*0x1000)
+#define PIPE_DPLINKM1(i) (0x60040+i*0x1000)
+#define PIPE_DPLINKM2(i) (0x60044+i*0x1000)
+#define PIPE_DPLINKN1(i) (0x60048+i*0x1000)
+#define PIPE_DPLINKN2(i) (0x6004c+i*0x1000)
+#define PIPE_CONF(i)     (0x70080+i*0x1000)
+#define   PIPE_CONF_ENABLE     (1L << 31)
+#define   PIPE_CONF_STATE      (1L << 30)
+#define   PIPE_CONF_GAMMA8     (0L << 24)
+#define   PIPE_CONF_GAMMA10    (1L << 24)
+#define   PIPE_CONF_GAMMA12    (2L << 24)
+#define   PIPE_CONF_PFPD       (0L << 21)
+#define   PIPE_CONF_PFID       (1L << 21)
+#define   PIPE_CONF_IFID       (3L << 21)
+#define   PIPE_CONF_IFID_DBL   (4L << 21)
+#define   PIPE_CONF_PFID_DBL   (5L << 21)
+#define   PIPE_CONF_POWERSAVE  (1L << 20)
+#define   PIPE_CONF_MSA1       (0L << 18)
+#define   PIPE_CONF_MSA2       (1L << 18)
+#define   PIPE_CONF_MSA3       (2L << 18)
+#define   PIPE_CONF_MSA4       (3L << 18)
+#define   PIPE_CONF_ROT0       (0L << 14)
+#define   PIPE_CONF_ROT90      (1L << 14)
+#define   PIPE_CONF_ROT180     (2L << 14)
+#define   PIPE_CONF_ROT270     (3L << 14)
+#define   PIPE_CONF_CE         (1L << 13)
+#define   PIPE_CONF_8BPP       (0L << 5)
+#define   PIPE_CONF_6BPP       (2L << 5)
+#define   PIPE_CONF_DITHER     (4L << 2)
+#define   PIPE_CONF_DITHERST1  (5L << 2)
+#define   PIPE_CONF_DITHERST2  (6L << 2)
+#define   PIPE_CONF_DITHERT    (7L << 2)
+#define CUR_CNTR(i)      (0x70080+i*0x1000)
+#define CUR_BASE(i)      (0x70084+i*0x1000)
+#define PRI_CTRL(i)      (0x70180+i*0x1000)
+#define   PRI_CTRL_ENABLE     (1L << 31)
+#define   PRI_CTRL_GAMMA      (1L << 30)
+#define   PRI_CTRL_IND8       (2L << 26)
+#define   PRI_CTRL_BGR565     (5L << 26)
+#define   PRI_CTRL_BGR        (6L << 26)
+#define   PRI_CTRL_RGB10      (8L << 26)
+#define   PRI_CTRL_BGR10      (10L << 26)
+#define   PRI_CTRL_RGBFP      (12L << 26)
+#define   PRI_CTRL_RGB        (14L << 26)
+#define   PRI_CTRL_PIXFMTMSK  (31L << 26)
+#define   PRI_CTRL_CSC        (1L << 24)
+#define   PRI_CTRL_ROT180     (1L << 15)
+#define   PRI_CTRL_NOTRICKLE  (1L << 14)
+#define   PRI_CTRL_TILED      (1L << 10)
+#define   PRI_CTRL_ASYNC      (1L << 9)
+#define PRI_LINOFF(i)    (0x70184+i*0x1000)
+#define PRI_STRIDE(i)    (0x70188+i*0x1000)
+#define PRI_SURF(i)      (0x7019c+i*0x1000)
+#define PRI_TILEOFF(i)   (0x701a4+i*0x1000)
+#define FDI_TX_CTL(i)    (0x60100+i*0x1000)
+
+#define FW_BLC_SELF     (0x20e0)
+#define FW_BLC_SELF_EN  (1L << 15)
+
+/* South display */
+
+#define DREF_CTL        (0xc6200)
+#define RAWCLK_FREQ     (0xc6204)
+#define DPLL_SEL        (0xc7000)
+
+#define DAC_CTL         (0xe1100)
+#define HDMI_CTL        (0xe1140)
+#define HDMI_BUF_CTL    (0xfd024)
+#define LVDS_CTL        (0xe1180)
+#define PCH_DP_CTL(i)	(0xe4100+i*0x100)
+
+#define PCH_DPLL_CTL(i)    (0xc6014+i*0x0008)
+#define PCH_DPLL_FP0(i)    (0xc6040+i*0x0008)
+#define PCH_DPLL_FP1(i)    (0xc6044+i*0x0008)
+#define TRANS_HTOTAL(i)    (0xe0000+i*0x1000)
+#define   TRANS_HOTAL_VAL(t,a) (((t)-1) << 16 | ((a)-1))
+#define TRANS_HBLANK(i)    (0xe0004+i*0x1000)
+#define   TRANS_HBLANK_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define TRANS_HSYNC(i)     (0xe0008+i*0x1000)
+#define   TRANS_HSYNC_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define TRANS_VTOTAL(i)    (0xe000c+i*0x1000)
+#define   TRANS_VTOTAL_VAL(t,a) (((t)-1) << 16 | ((a)-1))
+#define TRANS_VBLANK(i)    (0xe0010+i*0x1000)
+#define   TRANS_VBLANK_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define TRANS_VSYNC(i)     (0xe0014+i*0x1000)
+#define   TRANS_VSYNC_VAL(e,s) (((e)-1) << 16 | ((s)-1))
+#define TRANS_CONF(i)      (0xf0008+i*0x1000)
+#define FDI_RX_CTL(i)      (0xf000c+i*0x1000)
+
+#define OLD_BLC_PWM_CTL2   (0x61250)
+#define OLD_BLC_PWM_CTL    (0x61254)
+#define   BLM_PWM_ENABLE          (1L << 31)
+#define   BLM_PIPE(p)             ((p) << 29)
+#define   BLM_PHASEIN_INTST       (1L << 26)
+#define   BLM_PHASEIN_ENABLE      (1L << 25)
+#define   BLM_PHASEIN_INTEN       (1L << 24)
+#define   BLM_PHASEIN_TIME(t)     ((t) << 16)
+#define   BLM_PHASEIN_COUNT(c)    ((c) << 8)
+#define   BLM_PHASEIN_INCR(i)     ((i) << 0)
+#define CPU_BLC_PWM_CTL2   (0x48250)
+#define CPU_BLC_PWM_CTL    (0x48254)
+#define HSW_BLC_PWM_CTL    (0x48350)
+#define   BACKLIGHT_VAL(f,l,v)    ((f) << 17 | (l) << 16 | (v))
+#define   BACKLIGHT_GET_FREQ(r)   (((r) >> 17) & 0x7fff)
+#define   BACKLIGHT_GET_LEGACY(r) (((r) >> 16) & 0x1)
+#define   BACKLIGHT_GET_CYCLE(r)  (((r) >>  0) & 0xffff)
+
+#define GMBUS_NUM_PORTS    6
+#define OLD_GPIOA          (0x5010)
+#define OLD_GPIOB          (0x5014)
+#define OLD_GPIOC          (0x5018)
+#define OLD_GPIOD          (0x501c)
+#define OLD_GPIOE          (0x5020)
+#define OLD_GPIOF          (0x5024)
+#define PCH_GPIOA          (0xc5010)
+#define PCH_GPIOB          (0xc5014)
+#define PCH_GPIOC          (0xc5018)
+#define PCH_GPIOD          (0xc501c)
+#define PCH_GPIOE          (0xc5020)
+#define PCH_GPIOF          (0xc5024)
+#define   GPIO_CLOCK_DIR_MASK            (1 << 0)
+#define   GPIO_CLOCK_DIR_IN              (0 << 1)
+#define   GPIO_CLOCK_DIR_OUT             (1 << 1)
+#define   GPIO_CLOCK_VAL_MASK            (1 << 2)
+#define   GPIO_CLOCK_VAL_OUT             (1 << 3)
+#define   GPIO_CLOCK_VAL_IN              (1 << 4)
+#define   GPIO_CLOCK_PULLUP_DISABLE      (1 << 5)
+#define   GPIO_DATA_DIR_MASK             (1 << 8)  
+#define   GPIO_DATA_DIR_IN               (0 << 9)
+#define   GPIO_DATA_DIR_OUT              (1 << 9)
+#define   GPIO_DATA_VAL_MASK             (1 << 10)
+#define   GPIO_DATA_VAL_OUT              (1 << 11)
+#define   GPIO_DATA_VAL_IN               (1 << 12)
+#define   GPIO_DATA_PULLUP_DISABLE       (1 << 13)
+
+#endif
Index: src/sys/dev/pci/igmavar.h
diff -u /dev/null src/sys/dev/pci/igmavar.h:1.1
--- /dev/null	Tue Jan 21 14:52:07 2014
+++ src/sys/dev/pci/igmavar.h	Tue Jan 21 14:52:07 2014
@@ -0,0 +1,76 @@
+/*	$NetBSD: igmavar.h,v 1.1 2014/01/21 14:52:07 mlelstv Exp $	*/
+
+/*
+ * Copyright (c) 2014 Michael van Elst
+ *
+ * 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.
+ */
+
+#ifndef IGMAVAR_H
+#define IGMAVAR_H
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+struct igma_chip;
+struct igma_chip_ops {
+	void (*barrier)(const struct igma_chip *, int);
+	u_int32_t (*read_reg)(const struct igma_chip *, int);
+	void (*write_reg)(const struct igma_chip *, int, u_int32_t);
+	u_int8_t (*read_vga)(const struct igma_chip *, int);
+	void (*write_vga)(const struct igma_chip *, int, u_int8_t);
+#if 0
+	u_int8_t (*read_crtc)(const struct igma_chip *, int);
+	void (*write_crtc)(const struct igma_chip *, int, u_int8_t);
+#endif
+};
+
+struct igma_chip {
+	const struct igma_chip_ops	*ops;
+
+	bus_space_tag_t         gttt;
+	bus_space_handle_t      gtth;
+
+	bus_space_tag_t         mmiot;
+	bus_space_handle_t      mmioh;
+
+	bus_space_tag_t         vgat;
+	bus_space_handle_t      vgah;
+
+	bus_space_tag_t         gmt;
+	bus_space_handle_t      gmh;
+	bus_addr_t		gmb;
+
+	int num_gmbus;
+	int gpio_offset;
+	int vga_cntrl;
+	int num_pipes;
+	int use_pipe;
+	u_int32_t pri_cntrl;
+	int backlight_cntrl;
+	int backlight_cntrl2;
+	int backlight_factor;
+
+	unsigned quirks;
+};
+#define IGMA_PLANESTART_QUIRK   (1L << 0)
+#define IGMA_PFITDISABLE_QUIRK  (1L << 1)
+
+struct igma_attach_args {
+	const struct igma_chip_ops	*iaa_chip_ops;
+	struct igma_chip   	iaa_chip;
+	bool				iaa_console;
+	char				iaa_name[32];
+};
+
+#endif

Index: src/sys/dev/pci/igma/igmafb.c
diff -u /dev/null src/sys/dev/pci/igma/igmafb.c:1.1
--- /dev/null	Tue Jan 21 14:52:07 2014
+++ src/sys/dev/pci/igma/igmafb.c	Tue Jan 21 14:52:07 2014
@@ -0,0 +1,590 @@
+/*	$NetBSD: igmafb.c,v 1.1 2014/01/21 14:52:07 mlelstv Exp $	*/
+
+/*
+ * Copyright (c) 2012 Michael van Elst
+ *
+ * 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.
+ */
+
+/*
+ * Intel Graphic Media Accelerator
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: igmafb.c,v 1.1 2014/01/21 14:52:07 mlelstv Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/bus.h>
+#include <sys/kmem.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pciio.h>
+
+#include <dev/videomode/videomode.h>
+
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/wscons/wsconsio.h>
+#include <dev/wsfont/wsfont.h>
+#include <dev/rasops/rasops.h>
+#include <dev/wscons/wsdisplay_vconsvar.h>
+#include <dev/pci/wsdisplay_pci.h>
+
+#include <dev/pci/igmareg.h>
+#include <dev/pci/igmavar.h>
+
+#include "opt_voyagerfb.h"
+
+struct igmafb_softc {
+	device_t		sc_dev;
+
+	int 			sc_width;
+	int 			sc_height;
+	int 			sc_depth;
+	int 			sc_stride;
+	void			*sc_fbaddr;
+	bus_size_t		sc_fbsize;
+	struct vcons_screen	sc_console_screen;
+	struct wsscreen_descr	sc_defaultscreen_descr;
+	const struct wsscreen_descr	*sc_screens[1];
+	struct wsscreen_list	sc_screenlist;
+	struct vcons_data	vd;
+
+	struct igma_chip	sc_chip;
+	void			*sc_vga_save;
+
+	int			sc_backlight;
+	int			sc_brightness;
+	int			sc_brightness_max;
+};
+
+static int igmafb_match(device_t, cfdata_t, void *);
+static void igmafb_attach(device_t, device_t, void *);
+
+CFATTACH_DECL_NEW(igmafb, sizeof(struct igmafb_softc),
+    igmafb_match, igmafb_attach, NULL, NULL);
+
+static int igmafb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
+static paddr_t igmafb_mmap(void *, void *, off_t, int);
+static void igmafb_pollc(void *v, int);
+
+static /*const*/ struct wsdisplay_accessops igmafb_accessops = {
+	igmafb_ioctl,
+	igmafb_mmap,
+	NULL,	/* alloc_screen */
+	NULL,	/* free_screen */
+	NULL,	/* show_screen */
+	NULL,	/* load_font */
+	igmafb_pollc,	/* pollc */
+	NULL	/* scroll */
+};
+
+static void igmafb_init_screen(void *, struct vcons_screen *, int, long *);
+static void igmafb_guess_size(struct igmafb_softc *, int *, int*);
+static void igmafb_set_mode(struct igmafb_softc *, bool);
+
+static void igmafb_planestart_quirk(struct igmafb_softc *);
+static void igmafb_pfitdisable_quirk(struct igmafb_softc *);
+
+static void igmafb_get_brightness_max(struct igmafb_softc *, int *);
+static void igmafb_get_brightness(struct igmafb_softc *, int *);
+static void igmafb_set_brightness(struct igmafb_softc *, int);
+
+static int
+igmafb_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct igma_attach_args *iaa = (struct igma_attach_args *)aux;
+
+	if (strcmp(iaa->iaa_name, "igmafb") == 0) return 100;
+	return 0;
+}
+
+static void
+igmafb_attach(device_t parent, device_t self, void *aux)
+{
+	struct igmafb_softc *sc = device_private(self);
+	struct igma_attach_args *iaa = (struct igma_attach_args *)aux;
+	struct rasops_info *ri;
+	prop_dictionary_t dict;
+	bool is_console;
+	unsigned long defattr;
+	struct wsemuldisplaydev_attach_args waa;
+
+	sc->sc_dev = self;
+
+	aprint_normal("\n");
+
+	dict = device_properties(self);
+	prop_dictionary_get_bool(dict, "is_console", &is_console);
+	if (iaa->iaa_console)
+		is_console = true;
+
+	sc->sc_chip = iaa->iaa_chip;
+
+	sc->sc_fbaddr = bus_space_vaddr(sc->sc_chip.gmt, sc->sc_chip.gmh);
+	sc->sc_fbsize = 16 * 1024 * 1024;
+
+	igmafb_guess_size(sc, &sc->sc_width, &sc->sc_height);
+	sc->sc_depth = 32;
+	sc->sc_stride = (sc->sc_width*4 + 511)/512*512;
+
+	aprint_normal("%s: %d x %d, %d bit, stride %d\n", device_xname(self),
+		sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride);
+
+	aprint_normal("%s: %d MB video memory at 0x%p\n", device_xname(self),
+		(int)sc->sc_fbsize >> 20, (void *)sc->sc_chip.gmb);
+
+	sc->sc_vga_save = kmem_alloc(256*1024, KM_SLEEP);
+
+	igmafb_get_brightness(sc, &sc->sc_brightness);
+	igmafb_get_brightness_max(sc, &sc->sc_brightness_max);
+	sc->sc_backlight = sc->sc_brightness != 0;
+
+	sc->sc_defaultscreen_descr = (struct wsscreen_descr){
+		"default",
+		0, 0,
+		NULL,
+		8, 16,
+		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
+		NULL
+	};
+	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
+	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
+
+	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
+		&igmafb_accessops);
+	sc->vd.init_screen = igmafb_init_screen;
+
+	/* enable hardware display */
+	igmafb_set_mode(sc, true);
+
+	ri = &sc->sc_console_screen.scr_ri;
+
+	if (is_console) {
+		vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
+			&defattr);
+
+		sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC
+			| VCONS_NO_COPYROWS | VCONS_NO_COPYCOLS;
+		vcons_redraw_screen(&sc->sc_console_screen);
+
+		sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
+		sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
+		sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
+		sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
+
+		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
+			defattr);
+		vcons_replay_msgbuf(&sc->sc_console_screen);
+	} else {
+		if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
+			/* do some minimal setup to avoid weirdness later */
+			vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
+				&defattr);
+		} else
+			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
+	}
+
+	waa.console = is_console;
+	waa.scrdata = &sc->sc_screenlist;
+	waa.accessops = &igmafb_accessops;
+	waa.accesscookie = &sc->vd;
+
+	config_found(sc->sc_dev, &waa, wsemuldisplaydevprint);
+}
+
+/*
+ * wsdisplay accessops
+ */
+
+static int
+igmafb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
+    struct lwp *l)
+{
+	struct vcons_data *vd = v;
+	struct igmafb_softc *sc = vd->cookie;
+	struct wsdisplay_fbinfo *wdf;
+	struct vcons_screen *ms = vd->active;
+	struct wsdisplayio_fbinfo *fbi;
+	struct wsdisplay_param *param;
+	int val;
+
+	switch (cmd) {
+	case WSDISPLAYIO_GTYPE:
+		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
+		return 0;
+	case WSDISPLAYIO_GINFO:
+		if (ms == NULL)
+			return ENODEV;
+		wdf = data;
+		wdf->width  = ms->scr_ri.ri_width;
+		wdf->height = ms->scr_ri.ri_height;
+		wdf->depth  = ms->scr_ri.ri_depth;
+		wdf->cmsize = 256; /* XXX */
+		return 0;
+	case WSDISPLAYIO_LINEBYTES:
+		if (ms == NULL)
+			return ENODEV;
+		*(u_int *)data = ms->scr_ri.ri_stride;
+		return 0;
+	case WSDISPLAYIO_GET_FBINFO:
+		fbi = data;
+		return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
+	case WSDISPLAYIO_SVIDEO:
+		val = (*(u_int *)data) != WSDISPLAYIO_VIDEO_OFF;
+		sc->sc_backlight = val;
+		if (val)
+			igmafb_set_brightness(sc, sc->sc_brightness);
+		else
+			igmafb_set_brightness(sc, 0);
+		return 0;
+	case WSDISPLAYIO_GETPARAM:
+		param = (struct wsdisplay_param *)data;
+		switch (param->param) {
+		case WSDISPLAYIO_PARAM_BRIGHTNESS:
+			param->min = 0;
+			param->max = 255;
+			if (sc->sc_backlight)
+				igmafb_get_brightness(sc, &val);
+			else
+				val = sc->sc_brightness;
+			val = val * 255 / sc->sc_brightness_max;
+			param->curval = val;
+			return 0;
+		case WSDISPLAYIO_PARAM_BACKLIGHT:
+			param->min = 0;
+			param->max = 1;
+			param->curval = sc->sc_backlight;
+			return 0;
+		}
+		return EPASSTHROUGH;
+	case WSDISPLAYIO_SETPARAM:
+		param = (struct wsdisplay_param *)data;
+		switch (param->param) {
+		case WSDISPLAYIO_PARAM_BRIGHTNESS:
+			val = param->curval;
+			if (val < 0)
+				val = 0;
+			if (val > 255)
+				val = 255;
+			val = val * sc->sc_brightness_max / 255;
+			sc->sc_brightness = val;
+			if (sc->sc_backlight)
+				igmafb_set_brightness(sc, val);
+			return 0;
+		case WSDISPLAYIO_PARAM_BACKLIGHT:
+			val = param->curval;
+			sc->sc_backlight = val;
+			if (val)
+				igmafb_set_brightness(sc, sc->sc_brightness);
+			else
+				igmafb_set_brightness(sc, 0);
+			return 0;
+		}
+		return EPASSTHROUGH;
+	}
+
+	return EPASSTHROUGH;
+}
+
+static paddr_t
+igmafb_mmap(void *v, void *vs, off_t offset, int prot)
+{
+	struct vcons_data *vd = v;
+	struct igmafb_softc *sc = vd->cookie;
+
+	if ((offset & PAGE_MASK) != 0)
+		return -1;
+
+	if (offset < 0 || offset >= sc->sc_fbsize)
+		return -1;
+
+	return bus_space_mmap(sc->sc_chip.gmt, sc->sc_chip.gmb, offset, prot,
+		BUS_SPACE_MAP_LINEAR);
+}
+
+static void
+igmafb_pollc(void *v, int on)
+{
+	struct vcons_data *vd = v;
+	struct igmafb_softc *sc = vd->cookie;
+
+	if (sc == NULL)
+		return;
+	if (sc->sc_console_screen.scr_vd == NULL)
+		return;
+
+	if (on)
+		vcons_enable_polling(&sc->vd);
+	else
+		vcons_disable_polling(&sc->vd);
+}
+
+static void
+igmafb_init_screen(void *cookie, struct vcons_screen *scr,
+    int existing, long *defattr)
+{
+	struct igmafb_softc *sc = cookie;
+	struct rasops_info *ri = &scr->scr_ri;
+
+	memset(ri, 0, sizeof(struct rasops_info));
+
+	ri->ri_depth = sc->sc_depth;
+	ri->ri_width = sc->sc_width;
+	ri->ri_height = sc->sc_height;
+	ri->ri_stride = sc->sc_stride;
+	ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
+
+	ri->ri_bits = (char *)sc->sc_fbaddr;
+
+	if (existing) {
+		ri->ri_flg |= RI_CLEAR;
+	}
+
+	switch (sc->sc_depth) {
+	case 32:
+		ri->ri_rnum = 8;
+		ri->ri_gnum = 8;
+		ri->ri_bnum = 8;
+		ri->ri_rpos = 16;
+		ri->ri_gpos = 8;
+		ri->ri_bpos = 0;
+		break;
+	}
+
+	rasops_init(ri, 0, 0);
+	ri->ri_caps = WSSCREEN_WSCOLORS;
+
+	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
+		sc->sc_width / ri->ri_font->fontwidth);
+
+	ri->ri_hw = scr;
+}
+
+static void
+igmafb_guess_size(struct igmafb_softc *sc, int *widthp, int *heightp)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	int pipe = cd->use_pipe;
+	u_int32_t r;
+
+	r = co->read_reg(cd, PIPE_HTOTAL(pipe));
+	*widthp = PIPE_HTOTAL_GET_ACTIVE(r);
+	r = co->read_reg(cd, PIPE_VTOTAL(pipe));
+	*heightp = PIPE_VTOTAL_GET_ACTIVE(r);
+
+	aprint_normal("%s: vga active size %d x %d\n",
+		device_xname(sc->sc_dev),
+		*widthp, *heightp);
+
+	if (*widthp < 640 || *heightp < 400) {
+		r = co->read_reg(cd, PF_WINSZ(pipe));
+		*widthp  = PF_WINSZ_GET_WIDTH(r);
+		*heightp = PF_WINSZ_GET_HEIGHT(r);
+
+		aprint_normal("%s: window size %d x %d\n",
+			device_xname(sc->sc_dev),
+			*widthp, *heightp);
+	}
+
+	if (*widthp  < 640) *widthp  = 640;
+	if (*heightp < 400) *heightp = 400;
+}
+
+static void
+igmafb_set_mode(struct igmafb_softc *sc, bool enable)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	int pipe = cd->use_pipe;
+	u_int32_t r;
+	u_int8_t b;
+	int i;
+
+	if (enable) {
+		/* disable VGA machinery */
+		b = co->read_vga(cd, 0x01);
+		co->write_vga(cd, 0x01, b | 0x20);
+
+		/* disable VGA compatible display */
+		r = co->read_reg(cd, sc->sc_chip.vga_cntrl);
+		co->write_reg(cd, sc->sc_chip.vga_cntrl, r | VGA_CNTRL_DISABLE);
+
+		/* save VGA memory */
+		memcpy(sc->sc_vga_save, sc->sc_fbaddr, 256*1024);
+
+		/* configure panel fitter */
+		co->write_reg(cd, PF_WINPOS(pipe),
+			PF_WINPOS_VAL(0, 0));
+		co->write_reg(cd, PF_WINSZ(pipe),
+			PF_WINSZ_VAL(sc->sc_width, sc->sc_height));
+
+		/* pipe size */
+		co->write_reg(cd, PIPE_SRCSZ(pipe),
+			PIPE_SRCSZ_VAL(sc->sc_width, sc->sc_height));
+
+		/* enable pipe */
+		co->write_reg(cd, PIPE_CONF(pipe),
+			PIPE_CONF_ENABLE | PIPE_CONF_8BPP);
+
+		/* configure planes */
+		r = co->read_reg(cd, PRI_CTRL(pipe));
+		r &= ~(PRI_CTRL_PIXFMTMSK | PRI_CTRL_TILED);
+		r |= PRI_CTRL_ENABLE | PRI_CTRL_BGR;
+		co->write_reg(cd, PRI_CTRL(pipe), r | cd->pri_cntrl);
+		co->write_reg(cd, PRI_LINOFF(pipe), 0);
+		co->write_reg(cd, PRI_STRIDE(pipe), sc->sc_stride);
+		co->write_reg(cd, PRI_SURF(pipe), 0);
+		co->write_reg(cd, PRI_TILEOFF(pipe), 0);
+
+		if (cd->quirks & IGMA_PLANESTART_QUIRK)
+			igmafb_planestart_quirk(sc);
+
+		if (cd->quirks & IGMA_PFITDISABLE_QUIRK)
+			igmafb_pfitdisable_quirk(sc);
+	} else {
+		/* disable planes */
+		co->write_reg(cd, PRI_CTRL(pipe), 0 | cd->pri_cntrl);
+		co->write_reg(cd, PRI_LINOFF(pipe), 0);
+		co->write_reg(cd, PRI_STRIDE(pipe), 2560);
+		co->write_reg(cd, PRI_SURF(pipe), 0);
+		co->write_reg(cd, PRI_TILEOFF(pipe), 0);
+
+		/* pipe size */
+		co->write_reg(cd, PIPE_SRCSZ(pipe),
+			PIPE_SRCSZ_VAL(720,400));
+
+		/* disable pipe */
+		co->write_reg(cd, PIPE_CONF(pipe), 0);
+		for (i=0; i<10; ++i) {
+			delay(10);
+			if ((co->read_reg(cd, PIPE_CONF(pipe)) & PIPE_CONF_STATE) == 0)
+				break;
+		}
+
+		/* workaround before enabling VGA */
+		r = co->read_reg(cd, 0x42000);
+		co->write_reg(cd, 0x42000, (r & 0x1fffffff) | 0xa0000000);
+		r = co->read_reg(cd, 0x42004);
+		co->write_reg(cd, 0x42004, (r & 0xfbffffff) | 0x00000000);
+
+		/* configure panel fitter */
+		co->write_reg(cd, PF_WINPOS(pipe),
+			PF_WINPOS_VAL(0, 0));
+		co->write_reg(cd, PF_WINSZ(pipe),
+			PF_WINSZ_VAL(sc->sc_width, sc->sc_height));
+
+		/* enable VGA compatible display */
+		r = co->read_reg(cd, sc->sc_chip.vga_cntrl);
+		co->write_reg(cd, sc->sc_chip.vga_cntrl, r & ~VGA_CNTRL_DISABLE);
+
+		/* enable VGA machinery */
+		b = co->read_vga(cd, 0x01);
+		co->write_vga(cd, 0x01, b & ~0x20);
+
+		/* restore VGA memory */
+		memcpy(sc->sc_fbaddr, sc->sc_vga_save, 256*1024);
+
+		/* enable pipe again */
+		co->write_reg(cd, PIPE_CONF(pipe),
+			PIPE_CONF_ENABLE | PIPE_CONF_6BPP | PIPE_CONF_DITHER);
+	}
+}
+
+static void
+igmafb_planestart_quirk(struct igmafb_softc *sc)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	int pipe = cd->use_pipe;
+	u_int32_t cntrl, fwbcl;
+
+	/* disable self refresh */
+	fwbcl = co->read_reg(cd, FW_BLC_SELF);
+	co->write_reg(cd, FW_BLC_SELF, fwbcl & ~FW_BLC_SELF_EN);
+
+	cntrl = co->read_reg(cd, CUR_CNTR(pipe));
+	co->write_reg(cd, CUR_CNTR(pipe), 1<<5 | 0x07);
+
+	/* "wait for vblank" */
+	delay(40000);
+
+	co->write_reg(cd, CUR_CNTR(pipe), cntrl);
+	co->write_reg(cd, CUR_BASE(pipe),
+		co->read_reg(cd, CUR_BASE(pipe)));
+
+	co->write_reg(cd, FW_BLC_SELF, fwbcl);
+}
+
+static void
+igmafb_pfitdisable_quirk(struct igmafb_softc *sc)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	u_int32_t r;
+
+	/* disable i965 panel fitter */
+	r = co->read_reg(cd, PF_CTRL_I965);
+	co->write_reg(cd, PF_CTRL_I965, r & ~PF_ENABLE);
+}
+
+static void
+igmafb_get_brightness_max(struct igmafb_softc *sc, int *valp)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	u_int32_t r, f;
+
+	r = co->read_reg(cd, cd->backlight_cntrl);
+	f = BACKLIGHT_GET_FREQ(r);
+	if (f == 0) {
+		r = co->read_reg(cd, RAWCLK_FREQ);
+		f = r * 1000000 / (200 * 128);
+		if (f == 0 || f > 32767)
+			f = 125 * 100000 / (200 * 128);
+	}
+
+	*valp = f;
+}
+
+static void
+igmafb_get_brightness(struct igmafb_softc *sc, int *valp)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	u_int32_t r, v;
+
+	r = co->read_reg(cd, cd->backlight_cntrl);
+	v = BACKLIGHT_GET_CYCLE(r);
+	*valp = v;
+}
+
+static void
+igmafb_set_brightness(struct igmafb_softc *sc, int val)
+{
+	const struct igma_chip *cd = &sc->sc_chip;
+	const struct igma_chip_ops *co = cd->ops;
+	u_int32_t r, f, l;
+
+	r = co->read_reg(cd, cd->backlight_cntrl);
+	f = BACKLIGHT_GET_FREQ(r);
+	l = BACKLIGHT_GET_LEGACY(r);
+
+	co->write_reg(cd, cd->backlight_cntrl,
+		BACKLIGHT_VAL(f,l,val));
+}
+

Reply via email to