aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/arm/display/komeda/komeda_kms.c')
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.c130
1 files changed, 121 insertions, 9 deletions
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
index 86f6542afb40..419a8b0e5de8 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -58,7 +58,6 @@ static struct drm_driver komeda_kms_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
DRIVER_PRIME | DRIVER_HAVE_IRQ,
.lastclose = drm_fb_helper_lastclose,
- .irq_handler = komeda_kms_irq_handler,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = komeda_gem_cma_dumb_create,
@@ -100,6 +99,108 @@ static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
.atomic_commit_tail = komeda_kms_commit_tail,
};
+static int komeda_plane_state_list_add(struct drm_plane_state *plane_st,
+ struct list_head *zorder_list)
+{
+ struct komeda_plane_state *new = to_kplane_st(plane_st);
+ struct komeda_plane_state *node, *last;
+
+ last = list_empty(zorder_list) ?
+ NULL : list_last_entry(zorder_list, typeof(*last), zlist_node);
+
+ /* Considering the list sequence is zpos increasing, so if list is empty
+ * or the zpos of new node bigger than the last node in list, no need
+ * loop and just insert the new one to the tail of the list.
+ */
+ if (!last || (new->base.zpos > last->base.zpos)) {
+ list_add_tail(&new->zlist_node, zorder_list);
+ return 0;
+ }
+
+ /* Build the list by zpos increasing */
+ list_for_each_entry(node, zorder_list, zlist_node) {
+ if (new->base.zpos < node->base.zpos) {
+ list_add_tail(&new->zlist_node, &node->zlist_node);
+ break;
+ } else if (node->base.zpos == new->base.zpos) {
+ struct drm_plane *a = node->base.plane;
+ struct drm_plane *b = new->base.plane;
+
+ /* Komeda doesn't support setting a same zpos for
+ * different planes.
+ */
+ DRM_DEBUG_ATOMIC("PLANE: %s and PLANE: %s are configured same zpos: %d.\n",
+ a->name, b->name, node->base.zpos);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_st)
+{
+ struct drm_atomic_state *state = crtc_st->state;
+ struct komeda_crtc *kcrtc = to_kcrtc(crtc);
+ struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_st);
+ struct komeda_plane_state *kplane_st;
+ struct drm_plane_state *plane_st;
+ struct drm_framebuffer *fb;
+ struct drm_plane *plane;
+ struct list_head zorder_list;
+ int order = 0, err;
+
+ DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n",
+ crtc->base.id, crtc->name);
+
+ INIT_LIST_HEAD(&zorder_list);
+
+ /* This loop also added all effected planes into the new state */
+ drm_for_each_plane_mask(plane, crtc->dev, crtc_st->plane_mask) {
+ plane_st = drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_st))
+ return PTR_ERR(plane_st);
+
+ /* Build a list by zpos increasing */
+ err = komeda_plane_state_list_add(plane_st, &zorder_list);
+ if (err)
+ return err;
+ }
+
+ kcrtc_st->max_slave_zorder = 0;
+
+ list_for_each_entry(kplane_st, &zorder_list, zlist_node) {
+ plane_st = &kplane_st->base;
+ fb = plane_st->fb;
+ plane = plane_st->plane;
+
+ plane_st->normalized_zpos = order++;
+ /* When layer_split has been enabled, one plane will be handled
+ * by two separated komeda layers (left/right), which may needs
+ * two zorders.
+ * - zorder: for left_layer for left display part.
+ * - zorder + 1: will be reserved for right layer.
+ */
+ if (to_kplane_st(plane_st)->layer_split)
+ order++;
+
+ DRM_DEBUG_ATOMIC("[PLANE:%d:%s] zpos:%d, normalized zpos: %d\n",
+ plane->base.id, plane->name,
+ plane_st->zpos, plane_st->normalized_zpos);
+
+ /* calculate max slave zorder */
+ if (has_bit(drm_plane_index(plane), kcrtc->slave_planes))
+ kcrtc_st->max_slave_zorder =
+ max(plane_st->normalized_zpos,
+ kcrtc_st->max_slave_zorder);
+ }
+
+ crtc_st->zpos_changed = true;
+
+ return 0;
+}
+
static int komeda_kms_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
@@ -111,7 +212,7 @@ static int komeda_kms_check(struct drm_device *dev,
if (err)
return err;
- /* komeda need to re-calculate resource assumption in every commit
+ /* Komeda need to re-calculate resource assumption in every commit
* so need to add all affected_planes (even unchanged) to
* drm_atomic_state.
*/
@@ -119,6 +220,10 @@ static int komeda_kms_check(struct drm_device *dev,
err = drm_atomic_add_affected_planes(state, crtc);
if (err)
return err;
+
+ err = komeda_crtc_normalize_zpos(crtc, new_crtc_st);
+ if (err)
+ return err;
}
err = drm_atomic_helper_check_planes(dev, state);
@@ -148,7 +253,7 @@ static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
config->min_height = 0;
config->max_width = 4096;
config->max_height = 4096;
- config->allow_fb_modifiers = false;
+ config->allow_fb_modifiers = true;
config->funcs = &komeda_mode_config_funcs;
config->helper_private = &komeda_mode_config_helpers;
@@ -188,29 +293,36 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
if (err)
goto cleanup_mode_config;
+ err = komeda_kms_add_wb_connectors(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
err = component_bind_all(mdev->dev, kms);
if (err)
goto cleanup_mode_config;
drm_mode_config_reset(drm);
- err = drm_irq_install(drm, mdev->irq);
+ err = devm_request_irq(drm->dev, mdev->irq,
+ komeda_kms_irq_handler, IRQF_SHARED,
+ drm->driver->name, drm);
if (err)
goto cleanup_mode_config;
err = mdev->funcs->enable_irq(mdev);
if (err)
- goto uninstall_irq;
+ goto cleanup_mode_config;
+
+ drm->irq_enabled = true;
err = drm_dev_register(drm, 0);
if (err)
- goto uninstall_irq;
+ goto cleanup_mode_config;
return kms;
-uninstall_irq:
- drm_irq_uninstall(drm);
cleanup_mode_config:
+ drm->irq_enabled = false;
drm_mode_config_cleanup(drm);
komeda_kms_cleanup_private_objs(kms);
free_kms:
@@ -223,9 +335,9 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
struct drm_device *drm = &kms->base;
struct komeda_dev *mdev = drm->dev_private;
+ drm->irq_enabled = false;
mdev->funcs->disable_irq(mdev);
drm_dev_unregister(drm);
- drm_irq_uninstall(drm);
component_unbind_all(mdev->dev, drm);
komeda_kms_cleanup_private_objs(kms);
drm_mode_config_cleanup(drm);