Commit 56eac98b authored by Dave Airlie's avatar Dave Airlie

Merge tag 'exynos-drm-fixes-for-v4.14-rc1' of...

Merge tag 'exynos-drm-fixes-for-v4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-fixes

- fix suspend/resume issues.
- fix memory corruption detected by kasan.
- fix build error on x86.

* tag 'exynos-drm-fixes-for-v4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos/hdmi: Fix unsafe list iteration
  drm: exynos: include linux/irq.h
  drm/exynos: Fix suspend/resume support
  drm/exynos: Fix locking in the suspend/resume paths
parents c106c7a5 04fc52fb
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
......
...@@ -168,23 +168,19 @@ static struct drm_driver exynos_drm_driver = { ...@@ -168,23 +168,19 @@ static struct drm_driver exynos_drm_driver = {
static int exynos_drm_suspend(struct device *dev) static int exynos_drm_suspend(struct device *dev)
{ {
struct drm_device *drm_dev = dev_get_drvdata(dev); struct drm_device *drm_dev = dev_get_drvdata(dev);
struct drm_connector *connector; struct exynos_drm_private *private = drm_dev->dev_private;
struct drm_connector_list_iter conn_iter;
if (pm_runtime_suspended(dev) || !drm_dev) if (pm_runtime_suspended(dev) || !drm_dev)
return 0; return 0;
drm_connector_list_iter_begin(drm_dev, &conn_iter); drm_kms_helper_poll_disable(drm_dev);
drm_for_each_connector_iter(connector, &conn_iter) { exynos_drm_fbdev_suspend(drm_dev);
int old_dpms = connector->dpms; private->suspend_state = drm_atomic_helper_suspend(drm_dev);
if (IS_ERR(private->suspend_state)) {
if (connector->funcs->dpms) exynos_drm_fbdev_resume(drm_dev);
connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); drm_kms_helper_poll_enable(drm_dev);
return PTR_ERR(private->suspend_state);
/* Set the old mode back to the connector for resume */
connector->dpms = old_dpms;
} }
drm_connector_list_iter_end(&conn_iter);
return 0; return 0;
} }
...@@ -192,22 +188,14 @@ static int exynos_drm_suspend(struct device *dev) ...@@ -192,22 +188,14 @@ static int exynos_drm_suspend(struct device *dev)
static int exynos_drm_resume(struct device *dev) static int exynos_drm_resume(struct device *dev)
{ {
struct drm_device *drm_dev = dev_get_drvdata(dev); struct drm_device *drm_dev = dev_get_drvdata(dev);
struct drm_connector *connector; struct exynos_drm_private *private = drm_dev->dev_private;
struct drm_connector_list_iter conn_iter;
if (pm_runtime_suspended(dev) || !drm_dev) if (pm_runtime_suspended(dev) || !drm_dev)
return 0; return 0;
drm_connector_list_iter_begin(drm_dev, &conn_iter); drm_atomic_helper_resume(drm_dev, private->suspend_state);
drm_for_each_connector_iter(connector, &conn_iter) { exynos_drm_fbdev_resume(drm_dev);
if (connector->funcs->dpms) { drm_kms_helper_poll_enable(drm_dev);
int dpms = connector->dpms;
connector->dpms = DRM_MODE_DPMS_OFF;
connector->funcs->dpms(connector, dpms);
}
}
drm_connector_list_iter_end(&conn_iter);
return 0; return 0;
} }
......
...@@ -202,6 +202,7 @@ struct drm_exynos_file_private { ...@@ -202,6 +202,7 @@ struct drm_exynos_file_private {
*/ */
struct exynos_drm_private { struct exynos_drm_private {
struct drm_fb_helper *fb_helper; struct drm_fb_helper *fb_helper;
struct drm_atomic_state *suspend_state;
struct device *dma_dev; struct device *dma_dev;
void *mapping; void *mapping;
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/exynos_drm.h> #include <drm/exynos_drm.h>
#include <linux/console.h>
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_fb.h" #include "exynos_drm_fb.h"
#include "exynos_drm_fbdev.h" #include "exynos_drm_fbdev.h"
...@@ -285,3 +287,21 @@ void exynos_drm_output_poll_changed(struct drm_device *dev) ...@@ -285,3 +287,21 @@ void exynos_drm_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(fb_helper); drm_fb_helper_hotplug_event(fb_helper);
} }
void exynos_drm_fbdev_suspend(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
console_lock();
drm_fb_helper_set_suspend(private->fb_helper, 1);
console_unlock();
}
void exynos_drm_fbdev_resume(struct drm_device *dev)
{
struct exynos_drm_private *private = dev->dev_private;
console_lock();
drm_fb_helper_set_suspend(private->fb_helper, 0);
console_unlock();
}
...@@ -21,6 +21,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev); ...@@ -21,6 +21,8 @@ int exynos_drm_fbdev_init(struct drm_device *dev);
void exynos_drm_fbdev_fini(struct drm_device *dev); void exynos_drm_fbdev_fini(struct drm_device *dev);
void exynos_drm_fbdev_restore_mode(struct drm_device *dev); void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
void exynos_drm_output_poll_changed(struct drm_device *dev); void exynos_drm_output_poll_changed(struct drm_device *dev);
void exynos_drm_fbdev_suspend(struct drm_device *drm);
void exynos_drm_fbdev_resume(struct drm_device *drm);
#else #else
...@@ -39,6 +41,14 @@ static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev) ...@@ -39,6 +41,14 @@ static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
#define exynos_drm_output_poll_changed (NULL) #define exynos_drm_output_poll_changed (NULL)
static inline void exynos_drm_fbdev_suspend(struct drm_device *drm)
{
}
static inline void exynos_drm_fbdev_resume(struct drm_device *drm)
{
}
#endif #endif
#endif #endif
...@@ -944,22 +944,27 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder, ...@@ -944,22 +944,27 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_display_mode *m; struct drm_display_mode *m;
struct drm_connector_list_iter conn_iter;
int mode_ok; int mode_ok;
drm_mode_set_crtcinfo(adjusted_mode, 0); drm_mode_set_crtcinfo(adjusted_mode, 0);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->encoder == encoder) if (connector->encoder == encoder)
break; break;
} }
if (connector)
drm_connector_get(connector);
drm_connector_list_iter_end(&conn_iter);
if (connector->encoder != encoder) if (!connector)
return true; return true;
mode_ok = hdmi_mode_valid(connector, adjusted_mode); mode_ok = hdmi_mode_valid(connector, adjusted_mode);
if (mode_ok == MODE_OK) if (mode_ok == MODE_OK)
return true; goto cleanup;
/* /*
* Find the most suitable mode and copy it to adjusted_mode. * Find the most suitable mode and copy it to adjusted_mode.
...@@ -979,6 +984,9 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder, ...@@ -979,6 +984,9 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder,
} }
} }
cleanup:
drm_connector_put(connector);
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment