summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authormlelstv <mlelstv@NetBSD.org>2014-01-21 14:52:07 +0000
committermlelstv <mlelstv@NetBSD.org>2014-01-21 14:52:07 +0000
commitbb338d7002aba3c306fcb0eadd835cdb490fd510 (patch)
treeb938936920484ee9789d2c244e0c4990ddf0cfd2 /sys/dev/pci
parentdcc6b5932b4a21ebddd05de8e55d7c0cdc4243e9 (diff)
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.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/files.pci8
-rw-r--r--sys/dev/pci/igma.c642
-rw-r--r--sys/dev/pci/igma/igmafb.c590
-rw-r--r--sys/dev/pci/igmareg.h197
-rw-r--r--sys/dev/pci/igmavar.h76
5 files changed, 1512 insertions, 1 deletions
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 6a6c969d8cd..b348dfb7a08 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -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, rasops16
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
diff --git a/sys/dev/pci/igma.c b/sys/dev/pci/igma.c
new file mode 100644
index 00000000000..9e3d9413d01
--- /dev/null
+++ b/sys/dev/pci/igma.c
@@ -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
diff --git a/sys/dev/pci/igma/igmafb.c b/sys/dev/pci/igma/igmafb.c
new file mode 100644
index 00000000000..c3fcb2e62c1
--- /dev/null
+++ b/sys/dev/pci/igma/igmafb.c
@@ -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));
+}
+
diff --git a/sys/dev/pci/igmareg.h b/sys/dev/pci/igmareg.h
new file mode 100644
index 00000000000..4d4292a8cac
--- /dev/null
+++ b/sys/dev/pci/igmareg.h
@@ -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
diff --git a/sys/dev/pci/igmavar.h b/sys/dev/pci/igmavar.h
new file mode 100644
index 00000000000..fc002361df3
--- /dev/null
+++ b/sys/dev/pci/igmavar.h
@@ -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