@@ -227,12 +227,124 @@ static const struct component_master_ops hisi_drm_ops = {
.unbind = hisi_drm_unbind,
};
+static int exynos_drm_suspend(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+
+ drm_modeset_lock_all(dev);
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ int old_dpms = connector->dpms;
+
+ if (connector->funcs->dpms)
+ connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
+ /* Set the old mode back to the connector for resume */
+ connector->dpms = old_dpms;
+ }
+ drm_modeset_unlock_all(dev);
+
+ return 0;
+}
+
+static int exynos_drm_resume(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+
+ /* reset all the states of crtc/plane/encoder/connector */
+ drm_mode_config_reset(dev);
+
+ /* init kms poll for handling hpd */
+ drm_kms_helper_poll_init(dev);
+
+ /* force detection after connectors init */
+ (void)drm_helper_hpd_irq_event(dev);
+
+
+ drm_modeset_lock_all(dev);
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->funcs->dpms) {
+ int dpms = connector->dpms;
+
+ connector->dpms = DRM_MODE_DPMS_OFF;
+ connector->funcs->dpms(connector, dpms);
+ }
+ }
+ drm_modeset_unlock_all(dev);
+
+ return 0;
+}
+
+static int host1x_drm_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ drm_kms_helper_poll_disable(drm);
+
+ exynos_drm_suspend(drm);
+
+ return 0;
+}
+
+static int host1x_drm_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ exynos_drm_resume(drm);
+
+ drm_kms_helper_poll_enable(drm);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(host1x_drm_pm_ops, host1x_drm_suspend,
+ host1x_drm_resume);
+
+static ssize_t
+sysfs_show_current_drmstate(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t count = 0;
+
+ count = snprintf(buf, PAGE_SIZE, "%s\n", "johntest");
+
+ return count;
+}
+static ssize_t sysfs_set_drmstate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t ret = count;
+
+ if (count < 1)
+ return count;
+
+ /* strip of \n: */
+ if (buf[count-1] == '\n')
+ count--;
+
+ if (!strncmp(buf, "off", count)) {
+ host1x_drm_suspend(dev);
+ } else if (!strncmp(buf, "on", count)) {
+ host1x_drm_resume(dev);
+ } else {
+ printk("JDB: dunno what that is..\n");
+ }
+
+ return ret;
+
+}
+static DEVICE_ATTR(drm_test_state, 0644, sysfs_show_current_drmstate,
+ sysfs_set_drmstate);
+
static int hisi_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct device_node *child_np;
struct component_match *match = NULL;
+ int error;
+
+ error = device_create_file(dev, &dev_attr_drm_test_state);
of_platform_populate(node, NULL, NULL, dev);
@@ -245,6 +357,10 @@ static int hisi_drm_platform_probe(struct platform_device *pdev)
return component_master_add_with_match(dev, &hisi_drm_ops, match);
+
+
+
+
return 0;
}
@@ -261,6 +377,7 @@ static const struct of_device_id hisi_drm_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+
static struct platform_driver hisi_drm_platform_driver = {
.probe = hisi_drm_platform_probe,
.remove = hisi_drm_platform_remove,
@@ -268,6 +385,7 @@ static struct platform_driver hisi_drm_platform_driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
.of_match_table = hisi_drm_dt_ids,
+ .pm = &host1x_drm_pm_ops,
},
};
This is really hacked up and is mostly stolen from the exynos drm and another driver as well. I also added a sysfs test interface that allows you to trigger it on and off w/o the suspend logic. That will have to be removed before this gets merged. Signed-off-by: John Stultz <john.stultz@linaro.org> --- drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 118 +++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) -- 1.9.1