diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2013-03-31 11:43:24 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2013-03-31 11:43:24 +0000 |
commit | c1899bc7c85fa6d695aa723e513dd2a98ee7b166 (patch) | |
tree | a88ae9dd60da63e58b6590a7127108c6d32dce12 | |
parent | ddc6db4bd3543ad0f7e9b910be03c907760224e1 (diff) |
Add bit banging support.
-rw-r--r-- | sys/dev/pci/drm/i915/dvo_ns2501.c | 6 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915/i915_drv.h | 24 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915/intel_i2c.c | 198 |
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; + } +} |