diff --git a/sys/dev/drm/intel_iic.c b/sys/dev/drm/intel_iic.c index 8a45971..18bb632 100644 --- a/sys/dev/drm/intel_iic.c +++ b/sys/dev/drm/intel_iic.c @@ -59,9 +59,10 @@ #include "dev/drm/i915_drv.h" #include "dev/drm/intel_drv.h" #include +#include +#include #include "iicbus_if.h" #include "iicbb_if.h" -#include static int intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs); static void intel_teardown_gmbus_m(struct drm_device *dev, int m); @@ -72,6 +73,7 @@ static void intel_teardown_gmbus_m(struct drm_device *dev, int m); struct intel_iic_softc { struct drm_device *drm_dev; + device_t iic_dev; bool force_bit_dev; char name[32]; uint32_t reg; @@ -315,6 +325,8 @@ clear_err: */ I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); I915_WRITE(GMBUS1 + reg_offset, 0); + I915_WRITE(GMBUS0 + reg_offset, 0); + return (EIO); done: /* Mark the GMBUS interface as disabled. We will re-enable it at the @@ -342,8 +354,14 @@ void intel_gmbus_set_speed(device_t idev, int speed) { struct intel_iic_softc *sc; + struct drm_i915_private *dev_priv; + int unit; + + printf("intel_gmbus_set_speed: %s\n", devclass_get_name(device_get_devclass(idev))); + sc = device_get_softc(device_get_parent(idev)); + dev_priv = sc->drm_dev->dev_private; + unit = device_get_unit(device_get_parent(idev)); - sc = device_get_softc(idev); /* speed: * 0x0 = 100 KHz * 0x1 = 50 KHz @@ -358,28 +382,43 @@ intel_gmbus_force_bit(device_t idev, bool force_bit) { struct intel_iic_softc *sc; - sc = device_get_softc(idev); + printf("intel_gmbus_force_bit: %s\n", devclass_get_name(device_get_devclass(idev))); + sc = device_get_softc(device_get_parent(idev)); sc->force_bit_dev = force_bit; } static int intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs) { + device_t bridge_dev; struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; int ret; + int i; - sc = device_get_softc(idev); + bridge_dev = device_get_parent(device_get_parent(idev)); + sc = device_get_softc(bridge_dev); dev_priv = sc->drm_dev->dev_private; iicbus_reset(idev, 0, 0, NULL); intel_iic_quirk_set(dev_priv, TRUE); - IICBB_SETSDA(device_get_parent(idev), 1); - IICBB_SETSCL(device_get_parent(idev), 1); + IICBB_SETSDA(bridge_dev, 1); + IICBB_SETSCL(bridge_dev, 1); DELAY(I2C_RISEFALL_TIME); + + printf("intel_gmbus_force_bit: %s\n", devclass_get_name(device_get_devclass(idev))); + printf("intel_iic_quirk_xfer, slave = %u (%x)\n", msgs[0].slave, msgs[0].slave); + + /* convert slave addresses to format expected by iicbb */ + for (i = 0; i < nmsgs; i++) + msgs[i].slave <<= 1; ret = iicbus_transfer(idev, msgs, nmsgs); - IICBB_SETSDA(device_get_parent(idev), 1); - IICBB_SETSCL(device_get_parent(idev), 1); + printf("iicbus_transfer returned %d\n", ret); + /* restore just in case */ + for (i = 0; i < nmsgs; i++) + msgs[i].slave >>= 1; + IICBB_SETSDA(bridge_dev, 1); + IICBB_SETSCL(bridge_dev, 1); intel_iic_quirk_set(dev_priv, FALSE); return (ret); @@ -426,6 +465,12 @@ intel_gmbus_attach(device_t idev) sc->force_bit_dev = TRUE; } + /* add bus interface device */ + sc->iic_dev = device_add_child(idev, "iicbus", -1); + if (sc->iic_dev == NULL) + return (ENXIO); + bus_generic_attach(idev); + return (0); } @@ -434,12 +479,18 @@ intel_gmbus_detach(device_t idev) { struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; + device_t child; int u; sc = device_get_softc(idev); u = device_get_unit(idev); dev_priv = sc->drm_dev->dev_private; + child = sc->iic_dev; + bus_generic_detach(idev); + if (child) + device_delete_child(idev, child); + return (0); } @@ -453,6 +504,17 @@ intel_iicbb_probe(device_t dev) static int intel_iicbb_attach(device_t idev) { + static const int map_pin_to_reg[] = { + 0, + GPIOB, + GPIOA, + GPIOC, + GPIOD, + GPIOE, + 0, + GPIOF + }; + struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; int pin; @@ -466,6 +528,16 @@ intel_iicbb_attach(device_t idev) device_set_desc(idev, sc->name); sc->reg0 = pin | GMBUS_RATE_100KHZ; + sc->reg = map_pin_to_reg[pin]; + if (HAS_PCH_SPLIT(dev_priv->dev)) + sc->reg += PCH_GPIOA - GPIOA; + printf("intel_iicbb_attach: reg = 0x%x\n", sc->reg); + + /* add generic bit-banging code */ + sc->iic_dev = device_add_child(idev, "iicbb", -1); + if (sc->iic_dev == NULL) + return (ENXIO); + bus_generic_attach(idev); return (0); } @@ -473,7 +545,14 @@ intel_iicbb_attach(device_t idev) static int intel_iicbb_detach(device_t idev) { + struct intel_iic_softc *sc; + device_t child; + sc = device_get_softc(idev); + child = sc->iic_dev; + bus_generic_detach(idev); + if (child) + device_delete_child(idev, child); return (0); } @@ -481,6 +560,10 @@ static device_method_t intel_gmbus_methods[] = { DEVMETHOD(device_probe, intel_gmbus_probe), DEVMETHOD(device_attach, intel_gmbus_attach), DEVMETHOD(device_detach, intel_gmbus_detach), + + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(iicbus_reset, intel_iic_reset), DEVMETHOD(iicbus_transfer, intel_gmbus_transfer), { 0, 0 } @@ -493,11 +576,16 @@ static driver_t intel_gmbus_driver = { static devclass_t intel_gmbus_devclass; DRIVER_MODULE_ORDERED(intel_gmbus, drm, intel_gmbus_driver, intel_gmbus_devclass, 0, 0, SI_ORDER_FIRST); +DRIVER_MODULE(iicbus, intel_gmbus, iicbus_driver, iicbus_devclass, 0, 0); static device_method_t intel_iicbb_methods[] = { DEVMETHOD(device_probe, intel_iicbb_probe), DEVMETHOD(device_attach, intel_iicbb_attach), DEVMETHOD(device_detach, intel_iicbb_detach), + + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(iicbb_callback, iicbus_null_callback), DEVMETHOD(iicbb_reset, intel_iic_reset), DEVMETHOD(iicbb_setsda, intel_iicbb_setsda), @@ -514,77 +602,13 @@ static driver_t intel_iicbb_driver = { static devclass_t intel_iicbb_devclass; DRIVER_MODULE_ORDERED(intel_iicbb, drm, intel_iicbb_driver, intel_iicbb_devclass, 0, 0, SI_ORDER_FIRST); - -static int -intel_ddc_port_probe(device_t idev) -{ - - return (BUS_PROBE_DEFAULT); -} - -static int -intel_ddc_port_attach(device_t idev) -{ - struct intel_iic_softc *sc; - struct drm_i915_private *dev_priv; - int pin; - - sc = device_get_softc(idev); - sc->drm_dev = device_get_softc(device_get_parent( - device_get_parent(idev))); - dev_priv = sc->drm_dev->dev_private; - pin = device_get_unit(idev); - - snprintf(sc->name, sizeof(sc->name), "gmbus port %s", gpio_names[pin]); - device_set_desc(idev, sc->name); - - /* By default use a conservative clock rate */ - sc->reg0 = pin | GMBUS_RATE_100KHZ; - - return (0); -} - -static int -intel_ddc_port_detach(device_t idev) -{ - - return (0); -} - -static device_method_t intel_ddc_port_methods[] = { - DEVMETHOD(device_probe, intel_ddc_port_probe), - DEVMETHOD(device_attach, intel_ddc_port_attach), - DEVMETHOD(device_detach, intel_ddc_port_detach), - { 0, 0 } -}; -static driver_t intel_ddc_port_driver = { - "intel_ddc_port", - intel_ddc_port_methods, - sizeof(struct intel_iic_softc) -}; -static devclass_t intel_ddc_port_devclass; -DRIVER_MODULE_ORDERED(intel_ddc_port, intel_gmbus, intel_ddc_port_driver, - intel_ddc_port_devclass, 0, 0, SI_ORDER_SECOND); - -static device_method_t intel_ddc_bb_port_methods[] = { - DEVMETHOD(device_probe, intel_ddc_port_probe), - DEVMETHOD(device_attach, intel_ddc_port_attach), - DEVMETHOD(device_detach, intel_ddc_port_detach), - { 0, 0 } -}; -static driver_t intel_ddc_bb_port_driver = { - "intel_ddc_bb_port", - intel_ddc_bb_port_methods, - sizeof(struct intel_iic_softc) -}; -static devclass_t intel_ddc_bb_port_devclass; -DRIVER_MODULE_ORDERED(intel_ddc_bb_port, intel_iicbb, intel_ddc_bb_port_driver, - intel_ddc_bb_port_devclass, 0, 0, SI_ORDER_SECOND); +DRIVER_MODULE(iicbb, intel_iicbb, iicbb_driver, iicbb_devclass, 0, 0); int intel_setup_gmbus(struct drm_device *dev) { struct drm_i915_private *dev_priv; + device_t iic_dev; int i, ret; dev_priv = dev->dev_private; @@ -624,20 +648,19 @@ intel_setup_gmbus(struct drm_device *dev) goto err; } - dev_priv->bbbus[i] = device_add_child(dev_priv->bbbus_bridge[i], - "intel_ddc_bb_port", i); - if (dev_priv->bbbus[i] == NULL) { - DRM_ERROR("bbbus port %d creation error\n", i); - ret = ENXIO; + iic_dev = device_find_child(dev_priv->bbbus_bridge[i], "iicbb", -1); + if (iic_dev == NULL) { + DRM_ERROR("bbbus bridge doesn't have iicbb child\n"); goto err; } - device_quiet(dev_priv->bbbus[i]); - ret = device_probe_and_attach(dev_priv->bbbus[i]); - if (ret != 0) { - DRM_ERROR("bbbus port %d attach error %d\n", i, ret); + iic_dev = device_find_child(iic_dev, "iicbus", -1); + if (iic_dev == NULL) { + DRM_ERROR("bbbus bridge doesn't have iicbus grandchild\n"); goto err; } + dev_priv->bbbus[i] = iic_dev; + dev_priv->gmbus_bridge[i] = device_add_child(dev->device, "intel_gmbus", i); if (dev_priv->gmbus_bridge[i] == NULL) { @@ -654,20 +677,14 @@ intel_setup_gmbus(struct drm_device *dev) goto err; } - dev_priv->gmbus[i] = device_add_child(dev_priv->gmbus_bridge[i], - "intel_ddc_port", i); - if (dev_priv->gmbus[i] == NULL) { - DRM_ERROR("gmbus port %d creation error\n", i); - ret = ENXIO; - goto err; - } - device_quiet(dev_priv->gmbus[i]); - ret = device_probe_and_attach(dev_priv->gmbus[i]); - if (ret != 0) { - DRM_ERROR("gmbus port %d attach error %d\n", i, ret); + iic_dev = device_find_child(dev_priv->gmbus_bridge[i], "iicbus", -1); + if (iic_dev == NULL) { + DRM_ERROR("gmbus bridge doesn't have iicbus child\n"); goto err; } - intel_iic_reset(dev_priv->gmbus[i], 0, 0, NULL); + dev_priv->gmbus[i] = iic_dev; + + iicbus_reset(dev_priv->gmbus[i], 0, 0, NULL); } mtx_unlock(&Giant); @@ -683,31 +700,9 @@ static void intel_teardown_gmbus_m(struct drm_device *dev, int m) { struct drm_i915_private *dev_priv; - int i; dev_priv = dev->dev_private; - for (i = m; i>= 0; i--) { - if (dev_priv->gmbus[i] != 0) { - device_delete_child(dev_priv->gmbus_bridge[i], - dev_priv->gmbus[i]); - dev_priv->gmbus[i] = NULL; - } - if (dev_priv->gmbus_bridge[i] != 0) { - device_delete_child(dev->device, - dev_priv->gmbus_bridge[i]); - dev_priv->gmbus_bridge[i] = NULL; - } - if (dev_priv->bbbus[i] != 0) { - device_delete_child(dev_priv->bbbus_bridge[i], - dev_priv->bbbus[i]); - dev_priv->bbbus[i] = NULL; - } - if (dev_priv->bbbus_bridge[i] != 0) { - device_delete_child(dev->device, - dev_priv->bbbus_bridge[i]); - dev_priv->bbbus_bridge[i] = NULL; - } - } + free(dev_priv->gmbus, DRM_MEM_DRIVER); dev_priv->gmbus = NULL; free(dev_priv->bbbus, DRM_MEM_DRIVER);