summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2013-03-31 11:43:24 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2013-03-31 11:43:24 +0000
commitc1899bc7c85fa6d695aa723e513dd2a98ee7b166 (patch)
treea88ae9dd60da63e58b6590a7127108c6d32dce12
parentddc6db4bd3543ad0f7e9b910be03c907760224e1 (diff)
Add bit banging support.
-rw-r--r--sys/dev/pci/drm/i915/dvo_ns2501.c6
-rw-r--r--sys/dev/pci/drm/i915/i915_drv.h24
-rw-r--r--sys/dev/pci/drm/i915/intel_i2c.c198
3 files changed, 164 insertions, 64 deletions
diff --git a/sys/dev/pci/drm/i915/dvo_ns2501.c b/sys/dev/pci/drm/i915/dvo_ns2501.c
index 59ebc232147..24b0a2d7d58 100644
--- a/sys/dev/pci/drm/i915/dvo_ns2501.c
+++ b/sys/dev/pci/drm/i915/dvo_ns2501.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dvo_ns2501.c,v 1.2 2013/03/30 12:36:50 kettenis Exp $ */
+/* $OpenBSD: dvo_ns2501.c,v 1.3 2013/03/31 11:43:23 kettenis Exp $ */
/*
*
* Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
@@ -111,7 +111,7 @@ enable_dvo(struct intel_dvo_device *dvo)
struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus,
controller);
- drm_i915_private_t *dev_priv = bus->gp.dev_priv;
+ drm_i915_private_t *dev_priv = bus->dev_priv;
DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__);
@@ -139,7 +139,7 @@ restore_dvo(struct intel_dvo_device *dvo)
struct intel_gmbus *bus = container_of(adapter,
struct intel_gmbus,
controller);
- drm_i915_private_t *dev_priv = bus->gp.dev_priv;
+ drm_i915_private_t *dev_priv = bus->dev_priv;
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
I915_WRITE(DVOC, ns->dvoc);
diff --git a/sys/dev/pci/drm/i915/i915_drv.h b/sys/dev/pci/drm/i915/i915_drv.h
index 49dbebed089..32ffa0a5a9a 100644
--- a/sys/dev/pci/drm/i915/i915_drv.h
+++ b/sys/dev/pci/drm/i915/i915_drv.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_drv.h,v 1.10 2013/03/30 04:57:53 jsg Exp $ */
+/* $OpenBSD: i915_drv.h,v 1.11 2013/03/31 11:43:23 kettenis Exp $ */
/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
*/
/*
@@ -248,11 +248,6 @@ struct sdvo_device_mapping {
u8 ddc_pin;
};
-struct gmbus_port {
- struct inteldrm_softc *dev_priv;
- int port;
-};
-
enum intel_pch {
PCH_NONE = 0, /* No PCH present */
PCH_IBX, /* Ibexpeak PCH */
@@ -272,8 +267,13 @@ enum intel_sbi_destination {
struct intel_fbdev;
struct intel_gmbus {
- struct i2c_controller controller;
- struct gmbus_port gp;
+ struct i2c_controller controller;
+ u32 port;
+ u32 speed;
+ u32 force_bit;
+ u32 reg0;
+ u32 gpio_reg;
+ struct inteldrm_softc *dev_priv;
};
struct i915_suspend_saved_registers {
@@ -1205,12 +1205,18 @@ extern int i915_restore_state(struct drm_device *);
/* intel_i2c.c */
extern int intel_setup_gmbus(struct inteldrm_softc *);
-struct i2c_controller *intel_gmbus_get_adapter(drm_i915_private_t *, unsigned);
static inline bool intel_gmbus_is_port_valid(unsigned port)
{
return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD);
}
+struct i2c_controller *intel_gmbus_get_adapter(drm_i915_private_t *, unsigned);
+extern void intel_gmbus_force_bit(struct i2c_controller *, bool);
+static inline bool intel_gmbus_is_forced_bit(struct i2c_controller *i2c)
+{
+ return container_of(i2c, struct intel_gmbus, controller)->force_bit;
+}
+
/* i915_gem.c */
int i915_gem_create(struct drm_file *, struct drm_device *, uint64_t,
uint32_t *);
diff --git a/sys/dev/pci/drm/i915/intel_i2c.c b/sys/dev/pci/drm/i915/intel_i2c.c
index ff80be4fc47..876b71714e0 100644
--- a/sys/dev/pci/drm/i915/intel_i2c.c
+++ b/sys/dev/pci/drm/i915/intel_i2c.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: intel_i2c.c,v 1.2 2013/03/30 12:36:50 kettenis Exp $ */
+/* $OpenBSD: intel_i2c.c,v 1.3 2013/03/31 11:43:23 kettenis Exp $ */
/*
- * Copyright (c) 2012 Mark Kettenis <kettenis@openbsd.org>
+ * Copyright (c) 2012, 2013 Mark Kettenis <kettenis@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
@@ -21,40 +21,57 @@
#include "i915_reg.h"
#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/i2c_bitbang.h>
-int gmbus_i2c_acquire_bus(void *, int);
-void gmbus_i2c_release_bus(void *, int);
-int gmbus_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
+int intel_gmbus_acquire_bus(void *, int);
+void intel_gmbus_release_bus(void *, int);
+int intel_gmbus_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
void *buf, size_t, int);
-void i915_i2c_probe(struct inteldrm_softc *);
+
+void intel_gpio_bb_set_bits(void *, uint32_t);
+void intel_gpio_bb_set_dir(void *, uint32_t);
+uint32_t intel_gpio_bb_read_bits(void *);
+
+int intel_gpio_send_start(void *, int);
+int intel_gpio_send_stop(void *, int);
+int intel_gpio_initiate_xfer(void *, i2c_addr_t, int);
+int intel_gpio_read_byte(void *, u_int8_t *, int);
+int intel_gpio_write_byte(void *, u_int8_t, int);
+
+int gmbus_ports[] = { GPIOB, GPIOA, GPIOC, GPIOD, GPIOE, GPIOF };
+
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_controller *i2c)
+{
+ return container_of(i2c, struct intel_gmbus, controller);
+}
int
-gmbus_i2c_acquire_bus(void *cookie, int flags)
+intel_gmbus_acquire_bus(void *cookie, int flags)
{
- struct gmbus_port *gp = cookie;
- struct inteldrm_softc *dev_priv = gp->dev_priv;
+ struct intel_gmbus *bus = cookie;
+ struct inteldrm_softc *dev_priv = bus->dev_priv;
- I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0,
- GMBUS_RATE_100KHZ | gp->port);
+ I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, bus->reg0);
return (0);
}
void
-gmbus_i2c_release_bus(void *cookie, int flags)
+intel_gmbus_release_bus(void *cookie, int flags)
{
- struct gmbus_port *gp = cookie;
- struct inteldrm_softc *dev_priv = gp->dev_priv;
+ struct intel_gmbus *bus = cookie;
+ struct inteldrm_softc *dev_priv = bus->dev_priv;
I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0);
}
int
-gmbus_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
+intel_gmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
{
- struct gmbus_port *gp = cookie;
- struct inteldrm_softc *dev_priv = gp->dev_priv;
+ struct intel_gmbus *bus = cookie;
+ struct inteldrm_softc *dev_priv = bus->dev_priv;
uint32_t reg, st, val;
int reg_offset = dev_priv->gpio_mmio_base;
uint8_t *b;
@@ -177,39 +194,83 @@ out:
return (0);
}
+struct i2c_bitbang_ops intel_gpio_bbops = {
+ intel_gpio_bb_set_bits,
+ intel_gpio_bb_set_dir,
+ intel_gpio_bb_read_bits,
+ { GPIO_DATA_VAL_IN, GPIO_CLOCK_VAL_IN,
+ GPIO_DATA_DIR_OUT, GPIO_DATA_DIR_IN }
+};
+
void
-i915_i2c_probe(struct inteldrm_softc *dev_priv)
+intel_gpio_bb_set_bits(void *cookie, uint32_t bits)
{
- struct drm_device *dev = (struct drm_device *)dev_priv->drmdev;
- struct gmbus_port gp;
- struct i2c_controller ic;
- uint8_t buf[128];
- uint8_t cmd;
- int err, i;
+ struct intel_gmbus *bus = cookie;
+ struct inteldrm_softc *dev_priv = bus->dev_priv;
+ uint32_t reg;
+
+ reg = I915_READ_NOTRACE(bus->gpio_reg);
+ reg &= (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE);
+ if (bits & GPIO_DATA_VAL_IN)
+ reg |= GPIO_DATA_VAL_OUT;
+ if (bits & GPIO_CLOCK_VAL_IN)
+ reg |= GPIO_CLOCK_VAL_OUT;
+ reg |= (GPIO_DATA_VAL_MASK | GPIO_CLOCK_VAL_MASK);
+ I915_WRITE_NOTRACE(bus->gpio_reg, reg);
+}
- if (HAS_PCH_SPLIT(dev))
- dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
- else
- dev_priv->gpio_mmio_base = 0;
+void
+intel_gpio_bb_set_dir(void *cookie, uint32_t bits)
+{
+ struct intel_gmbus *bus = cookie;
+ struct inteldrm_softc *dev_priv = bus->dev_priv;
+ uint32_t reg;
+
+ reg = I915_READ_NOTRACE(bus->gpio_reg);
+ reg &= (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE);
+ if (bits & GPIO_DATA_DIR_OUT)
+ reg |= GPIO_DATA_DIR_OUT;
+ reg |= (GPIO_DATA_DIR_MASK | GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK);
+ I915_WRITE_NOTRACE(bus->gpio_reg, reg);
+}
+
+uint32_t
+intel_gpio_bb_read_bits(void *cookie)
+{
+ struct intel_gmbus *bus = cookie;
+ struct inteldrm_softc *dev_priv = bus->dev_priv;
+
+ return I915_READ_NOTRACE(bus->gpio_reg);
+}
- gp.dev_priv = dev_priv;
- gp.port = GMBUS_PORT_PANEL;
-
- ic.ic_cookie = &gp;
- ic.ic_acquire_bus = gmbus_i2c_acquire_bus;
- ic.ic_release_bus = gmbus_i2c_release_bus;
- ic.ic_exec = gmbus_i2c_exec;
-
- bzero(buf, sizeof(buf));
- iic_acquire_bus(&ic, 0);
- cmd = 0;
- err = iic_exec(&ic, I2C_OP_READ_WITH_STOP, 0x50, &cmd, 1, buf, 128, 0);
- if (err)
- printf("err %d\n", err);
- iic_release_bus(&ic, 0);
- for (i = 0; i < sizeof(buf); i++)
- printf(" 0x%02x", buf[i]);
- printf("\n");
+int
+intel_gpio_send_start(void *cookie, int flags)
+{
+ return (i2c_bitbang_send_start(cookie, flags, &intel_gpio_bbops));
+}
+
+int
+intel_gpio_send_stop(void *cookie, int flags)
+{
+ return (i2c_bitbang_send_stop(cookie, flags, &intel_gpio_bbops));
+}
+
+int
+intel_gpio_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
+{
+ return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &intel_gpio_bbops));
+}
+
+int
+intel_gpio_read_byte(void *cookie, u_int8_t *bytep, int flags)
+{
+ return (i2c_bitbang_read_byte(cookie, bytep, flags, &intel_gpio_bbops));
+}
+
+int
+intel_gpio_write_byte(void *cookie, u_int8_t byte, int flags)
+{
+ return (i2c_bitbang_write_byte(cookie, byte, flags, &intel_gpio_bbops));
}
int
@@ -226,13 +287,25 @@ intel_setup_gmbus(struct inteldrm_softc *dev_priv)
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
struct intel_gmbus *bus = &dev_priv->gmbus[i];
- bus->gp.dev_priv = dev_priv;
- bus->gp.port = i + 1;
+ bus->dev_priv = dev_priv;
+
+ bus->speed = GMBUS_RATE_100KHZ;
+ bus->port = i + 1;
+ bus->force_bit = 0;
+ bus->reg0 = bus->port | bus->speed;
- bus->controller.ic_cookie = &bus->gp;
- bus->controller.ic_acquire_bus = gmbus_i2c_acquire_bus;
- bus->controller.ic_release_bus = gmbus_i2c_release_bus;
- bus->controller.ic_exec = gmbus_i2c_exec;
+ bus->controller.ic_cookie = bus;
+ bus->controller.ic_acquire_bus = intel_gmbus_acquire_bus;
+ bus->controller.ic_release_bus = intel_gmbus_release_bus;
+ bus->controller.ic_exec = intel_gmbus_exec;
+
+ bus->gpio_reg = dev_priv->gpio_mmio_base + gmbus_ports[i];
+
+ bus->controller.ic_send_start = intel_gpio_send_start;
+ bus->controller.ic_send_stop = intel_gpio_send_stop;
+ bus->controller.ic_initiate_xfer = intel_gpio_initiate_xfer;
+ bus->controller.ic_read_byte = intel_gpio_read_byte;
+ bus->controller.ic_write_byte = intel_gpio_write_byte;
}
return (0);
@@ -245,3 +318,24 @@ intel_gmbus_get_adapter(drm_i915_private_t *dev_priv, unsigned port)
return (intel_gmbus_is_port_valid(port)) ?
&dev_priv->gmbus[port - 1].controller : NULL;
}
+
+void
+intel_gmbus_force_bit(struct i2c_controller *controller, bool force_bit)
+{
+ struct intel_gmbus *bus = to_intel_gmbus(controller);
+
+ if (force_bit)
+ bus->force_bit++;
+ else
+ bus->force_bit--;
+
+ KASSERT(force_bit >= 0);
+
+ if (bus->force_bit) {
+ bus->controller.ic_exec = NULL;
+ bus->reg0 = 0;
+ } else {
+ bus->controller.ic_exec = intel_gmbus_exec;
+ bus->reg0 = bus->port | bus->speed;
+ }
+}