@@ -47,6 +47,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
if (!private)
return -ENOMEM;
+ INIT_WORK(&private->work, exynos_drm_atomic_work);
+ private->dev = dev;
+
dev_set_drvdata(dev->dev, dev);
dev->dev_private = (void *)private;
@@ -127,6 +130,8 @@ err_free_private:
static int exynos_drm_unload(struct drm_device *dev)
{
+ struct exynos_drm_private *private = dev->dev_private;
+
exynos_drm_device_subdrv_remove(dev);
exynos_drm_fbdev_fini(dev);
@@ -137,6 +142,7 @@ static int exynos_drm_unload(struct drm_device *dev)
drm_mode_config_cleanup(dev);
drm_release_iommu_mapping(dev);
+ flush_work(&private->work);
kfree(dev->dev_private);
dev->dev_private = NULL;
@@ -244,6 +244,10 @@ struct exynos_drm_private {
unsigned long da_space_size;
unsigned int pipe;
+
+ struct drm_device *dev;
+ struct work_struct work;
+ struct drm_atomic_state *state;
};
/*
@@ -296,6 +300,8 @@ static inline int exynos_dpi_remove(struct exynos_drm_display *display)
}
#endif
+void exynos_drm_atomic_work(struct work_struct *work);
+
/* This function creates a encoder and a connector, and initializes them. */
int exynos_drm_create_enc_conn(struct drm_device *dev,
struct exynos_drm_display *display);
@@ -267,20 +267,18 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev)
exynos_drm_fbdev_init(dev);
}
-static int exynos_atomic_commit(struct drm_device *dev,
- struct drm_atomic_state *state,
- bool async)
+static void exynos_atomic_commit_schedule(struct drm_device *dev,
+ struct drm_atomic_state *state)
{
- int ret;
-
- ret = drm_atomic_helper_prepare_planes(dev, state);
- if (ret)
- return ret;
-
- /* This is the point of no return */
+ struct exynos_drm_private *private = dev->dev_private;
- drm_atomic_helper_swap_state(dev, state);
+ private->state = state;
+ schedule_work(&private->work);
+}
+static void exynos_atomic_commit_complete(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
drm_atomic_helper_commit_modeset_disables(dev, state);
drm_atomic_helper_commit_modeset_enables(dev, state);
@@ -298,6 +296,37 @@ static int exynos_atomic_commit(struct drm_device *dev,
drm_atomic_helper_cleanup_planes(dev, state);
drm_atomic_state_free(state);
+}
+
+void exynos_drm_atomic_work(struct work_struct *work)
+{
+ struct exynos_drm_private *private = container_of(work,
+ struct exynos_drm_private, work);
+
+ exynos_atomic_commit_complete(private->dev, private->state);
+}
+
+static int exynos_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ struct exynos_drm_private *private = dev->dev_private;
+ int ret;
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ /* This is the point of no return */
+
+ flush_work(&private->work);
+
+ drm_atomic_helper_swap_state(dev, state);
+
+ if (async)
+ exynos_atomic_commit_schedule(dev, state);
+ else
+ exynos_atomic_commit_complete(dev, state);
return 0;
}