Message ID | 20171013001350.172155-1-tutankhamen@chromium.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, Oct 12, 2017 at 8:13 PM, Robert Tarasov <tutankhamen@chromium.org> wrote: > Fixed problem with DisplayLink and DisplayLink certified adapers in drm/udl > driver when adapter doesn't want to work if it was initialized with > disconnected DVI cable by enabling drm connectot polling and updating > current connector's state. > > Signed-off-by: Robert Tarasov <tutankhamen@chromium.org> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> > --- > drivers/gpu/drm/udl/udl_connector.c | 76 ++++++++++++++++++++++++------------- > drivers/gpu/drm/udl/udl_connector.h | 13 +++++++ > drivers/gpu/drm/udl/udl_drv.c | 4 ++ > drivers/gpu/drm/udl/udl_main.c | 5 +++ > 4 files changed, 72 insertions(+), 26 deletions(-) > create mode 100644 drivers/gpu/drm/udl/udl_connector.h > > diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c > index 091ca81658eb..6a9250ac8f29 100644 > --- a/drivers/gpu/drm/udl/udl_connector.c > +++ b/drivers/gpu/drm/udl/udl_connector.c > @@ -14,6 +14,7 @@ > #include <drm/drm_crtc.h> > #include <drm/drm_edid.h> > #include <drm/drm_crtc_helper.h> > +#include "udl_connector.h" > #include "udl_drv.h" > > /* dummy connector to just get EDID, > @@ -56,28 +57,15 @@ static u8 *udl_get_edid(struct udl_device *udl) > > static int udl_get_modes(struct drm_connector *connector) > { > - struct udl_device *udl = connector->dev->dev_private; > - struct edid *edid; > - int ret; > - > - edid = (struct edid *)udl_get_edid(udl); > - if (!edid) { > - drm_mode_connector_update_edid_property(connector, NULL); > - return 0; > - } > - > - /* > - * We only read the main block, but if the monitor reports extension > - * blocks then the drm edid code expects them to be present, so patch > - * the extension count to 0. > - */ > - edid->checksum += edid->extensions; > - edid->extensions = 0; > - > - drm_mode_connector_update_edid_property(connector, edid); > - ret = drm_add_edid_modes(connector, edid); > - kfree(edid); > - return ret; > + struct udl_drm_connector *udl_connector = > + container_of(connector, > + struct udl_drm_connector, > + connector); > + > + drm_mode_connector_update_edid_property(connector, udl_connector->edid); > + if (udl_connector->edid) > + return drm_add_edid_modes(connector, udl_connector->edid); > + return 0; > } > > static int udl_mode_valid(struct drm_connector *connector, > @@ -96,8 +84,33 @@ static int udl_mode_valid(struct drm_connector *connector, > static enum drm_connector_status > udl_detect(struct drm_connector *connector, bool force) > { > - if (drm_dev_is_unplugged(connector->dev)) > + struct edid *edid; > + struct udl_device *udl = connector->dev->dev_private; > + struct udl_drm_connector *udl_connector = > + container_of(connector, > + struct udl_drm_connector, > + connector); > + > + if (udl_connector->edid != NULL) { > + kfree(udl_connector->edid); > + udl_connector->edid = NULL; > + } > + > + edid = (struct edid *)udl_get_edid(udl); > + if (!edid || !memchr_inv(edid, 0, EDID_LENGTH)) > return connector_status_disconnected; > + > + udl_connector->edid = edid; > + > + /* > + * We only read the main block, but if the monitor reports extension > + * blocks then the drm edid code expects them to be present, so patch > + * the extension count to 0. > + */ > + udl_connector->edid->checksum += > + udl_connector->edid->extensions; > + udl_connector->edid->extensions = 0; > + > return connector_status_connected; > } > > @@ -117,8 +130,14 @@ static int udl_connector_set_property(struct drm_connector *connector, > > static void udl_connector_destroy(struct drm_connector *connector) > { > + struct udl_drm_connector *udl_connector = > + container_of(connector, > + struct udl_drm_connector, > + connector); > + > drm_connector_unregister(connector); > drm_connector_cleanup(connector); > + kfree(udl_connector->edid); > kfree(connector); > } > > @@ -138,17 +157,22 @@ static const struct drm_connector_funcs udl_connector_funcs = { > > int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder) > { > + struct udl_drm_connector *udl_connector; > struct drm_connector *connector; > > - connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL); > - if (!connector) > + udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL); > + if (!udl_connector) > return -ENOMEM; > > - drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_DVII); > + connector = &udl_connector->connector; > + drm_connector_init(dev, connector, &udl_connector_funcs, > + DRM_MODE_CONNECTOR_DVII); > drm_connector_helper_add(connector, &udl_connector_helper_funcs); > > drm_connector_register(connector); > drm_mode_connector_attach_encoder(connector, encoder); > + connector->polled = DRM_CONNECTOR_POLL_HPD | > + DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; > > return 0; > } > diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h > new file mode 100644 > index 000000000000..0fb0db5c4612 > --- /dev/null > +++ b/drivers/gpu/drm/udl/udl_connector.h > @@ -0,0 +1,13 @@ > +#ifndef __UDL_CONNECTOR_H__ > +#define __UDL_CONNECTOR_H__ > + > +#include <drm/drm_crtc.h> > + > +struct udl_drm_connector { > + struct drm_connector connector; > + /* last udl_detect edid */ > + struct edid *edid; > +}; > + > + > +#endif //__UDL_CONNECTOR_H__ > diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c > index 31421b6b586e..3c45a3064726 100644 > --- a/drivers/gpu/drm/udl/udl_drv.c > +++ b/drivers/gpu/drm/udl/udl_drv.c > @@ -14,6 +14,9 @@ > static int udl_usb_suspend(struct usb_interface *interface, > pm_message_t message) > { > + struct drm_device *dev = usb_get_intfdata(interface); > + > + drm_kms_helper_poll_disable(dev); > return 0; > } > > @@ -21,6 +24,7 @@ static int udl_usb_resume(struct usb_interface *interface) > { > struct drm_device *dev = usb_get_intfdata(interface); > > + drm_kms_helper_poll_enable(dev); > udl_modeset_restore(dev); > return 0; > } > diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c > index 0328b2c7b210..f1ec4528a73e 100644 > --- a/drivers/gpu/drm/udl/udl_main.c > +++ b/drivers/gpu/drm/udl/udl_main.c > @@ -11,6 +11,7 @@ > * more details. > */ > #include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > #include "udl_drv.h" > > /* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */ > @@ -350,6 +351,8 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) > if (ret) > goto err_fb; > > + drm_kms_helper_poll_init(dev); > + > return 0; > err_fb: > udl_fbdev_cleanup(dev); > @@ -371,6 +374,8 @@ void udl_driver_unload(struct drm_device *dev) > { > struct udl_device *udl = dev->dev_private; > > + drm_kms_helper_poll_fini(dev); > + > if (udl->urbs.count) > udl_free_urb_list(dev); > > -- > 2.15.0.rc0.271.g36b669edcc-goog > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 091ca81658eb..6a9250ac8f29 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -14,6 +14,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_edid.h> #include <drm/drm_crtc_helper.h> +#include "udl_connector.h" #include "udl_drv.h" /* dummy connector to just get EDID, @@ -56,28 +57,15 @@ static u8 *udl_get_edid(struct udl_device *udl) static int udl_get_modes(struct drm_connector *connector) { - struct udl_device *udl = connector->dev->dev_private; - struct edid *edid; - int ret; - - edid = (struct edid *)udl_get_edid(udl); - if (!edid) { - drm_mode_connector_update_edid_property(connector, NULL); - return 0; - } - - /* - * We only read the main block, but if the monitor reports extension - * blocks then the drm edid code expects them to be present, so patch - * the extension count to 0. - */ - edid->checksum += edid->extensions; - edid->extensions = 0; - - drm_mode_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - return ret; + struct udl_drm_connector *udl_connector = + container_of(connector, + struct udl_drm_connector, + connector); + + drm_mode_connector_update_edid_property(connector, udl_connector->edid); + if (udl_connector->edid) + return drm_add_edid_modes(connector, udl_connector->edid); + return 0; } static int udl_mode_valid(struct drm_connector *connector, @@ -96,8 +84,33 @@ static int udl_mode_valid(struct drm_connector *connector, static enum drm_connector_status udl_detect(struct drm_connector *connector, bool force) { - if (drm_dev_is_unplugged(connector->dev)) + struct edid *edid; + struct udl_device *udl = connector->dev->dev_private; + struct udl_drm_connector *udl_connector = + container_of(connector, + struct udl_drm_connector, + connector); + + if (udl_connector->edid != NULL) { + kfree(udl_connector->edid); + udl_connector->edid = NULL; + } + + edid = (struct edid *)udl_get_edid(udl); + if (!edid || !memchr_inv(edid, 0, EDID_LENGTH)) return connector_status_disconnected; + + udl_connector->edid = edid; + + /* + * We only read the main block, but if the monitor reports extension + * blocks then the drm edid code expects them to be present, so patch + * the extension count to 0. + */ + udl_connector->edid->checksum += + udl_connector->edid->extensions; + udl_connector->edid->extensions = 0; + return connector_status_connected; } @@ -117,8 +130,14 @@ static int udl_connector_set_property(struct drm_connector *connector, static void udl_connector_destroy(struct drm_connector *connector) { + struct udl_drm_connector *udl_connector = + container_of(connector, + struct udl_drm_connector, + connector); + drm_connector_unregister(connector); drm_connector_cleanup(connector); + kfree(udl_connector->edid); kfree(connector); } @@ -138,17 +157,22 @@ static const struct drm_connector_funcs udl_connector_funcs = { int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder) { + struct udl_drm_connector *udl_connector; struct drm_connector *connector; - connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL); - if (!connector) + udl_connector = kzalloc(sizeof(struct udl_drm_connector), GFP_KERNEL); + if (!udl_connector) return -ENOMEM; - drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_DVII); + connector = &udl_connector->connector; + drm_connector_init(dev, connector, &udl_connector_funcs, + DRM_MODE_CONNECTOR_DVII); drm_connector_helper_add(connector, &udl_connector_helper_funcs); drm_connector_register(connector); drm_mode_connector_attach_encoder(connector, encoder); + connector->polled = DRM_CONNECTOR_POLL_HPD | + DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; return 0; } diff --git a/drivers/gpu/drm/udl/udl_connector.h b/drivers/gpu/drm/udl/udl_connector.h new file mode 100644 index 000000000000..0fb0db5c4612 --- /dev/null +++ b/drivers/gpu/drm/udl/udl_connector.h @@ -0,0 +1,13 @@ +#ifndef __UDL_CONNECTOR_H__ +#define __UDL_CONNECTOR_H__ + +#include <drm/drm_crtc.h> + +struct udl_drm_connector { + struct drm_connector connector; + /* last udl_detect edid */ + struct edid *edid; +}; + + +#endif //__UDL_CONNECTOR_H__ diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 31421b6b586e..3c45a3064726 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -14,6 +14,9 @@ static int udl_usb_suspend(struct usb_interface *interface, pm_message_t message) { + struct drm_device *dev = usb_get_intfdata(interface); + + drm_kms_helper_poll_disable(dev); return 0; } @@ -21,6 +24,7 @@ static int udl_usb_resume(struct usb_interface *interface) { struct drm_device *dev = usb_get_intfdata(interface); + drm_kms_helper_poll_enable(dev); udl_modeset_restore(dev); return 0; } diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 0328b2c7b210..f1ec4528a73e 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -11,6 +11,7 @@ * more details. */ #include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> #include "udl_drv.h" /* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */ @@ -350,6 +351,8 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_fb; + drm_kms_helper_poll_init(dev); + return 0; err_fb: udl_fbdev_cleanup(dev); @@ -371,6 +374,8 @@ void udl_driver_unload(struct drm_device *dev) { struct udl_device *udl = dev->dev_private; + drm_kms_helper_poll_fini(dev); + if (udl->urbs.count) udl_free_urb_list(dev);
Fixed problem with DisplayLink and DisplayLink certified adapers in drm/udl driver when adapter doesn't want to work if it was initialized with disconnected DVI cable by enabling drm connectot polling and updating current connector's state. Signed-off-by: Robert Tarasov <tutankhamen@chromium.org> --- drivers/gpu/drm/udl/udl_connector.c | 76 ++++++++++++++++++++++++------------- drivers/gpu/drm/udl/udl_connector.h | 13 +++++++ drivers/gpu/drm/udl/udl_drv.c | 4 ++ drivers/gpu/drm/udl/udl_main.c | 5 +++ 4 files changed, 72 insertions(+), 26 deletions(-) create mode 100644 drivers/gpu/drm/udl/udl_connector.h