132a1795fSJyri Sarha // SPDX-License-Identifier: GPL-2.0 232a1795fSJyri Sarha /* 332a1795fSJyri Sarha * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 432a1795fSJyri Sarha * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 532a1795fSJyri Sarha */ 632a1795fSJyri Sarha 732a1795fSJyri Sarha #include <drm/drm_atomic.h> 832a1795fSJyri Sarha #include <drm/drm_atomic_helper.h> 932a1795fSJyri Sarha #include <drm/drm_bridge.h> 1032a1795fSJyri Sarha #include <drm/drm_crtc_helper.h> 1132a1795fSJyri Sarha #include <drm/drm_fb_cma_helper.h> 1232a1795fSJyri Sarha #include <drm/drm_fb_helper.h> 1332a1795fSJyri Sarha #include <drm/drm_gem_framebuffer_helper.h> 1432a1795fSJyri Sarha #include <drm/drm_of.h> 1532a1795fSJyri Sarha #include <drm/drm_panel.h> 1632a1795fSJyri Sarha #include <drm/drm_vblank.h> 1732a1795fSJyri Sarha 1832a1795fSJyri Sarha #include "tidss_crtc.h" 1932a1795fSJyri Sarha #include "tidss_dispc.h" 2032a1795fSJyri Sarha #include "tidss_drv.h" 2132a1795fSJyri Sarha #include "tidss_encoder.h" 2232a1795fSJyri Sarha #include "tidss_kms.h" 2332a1795fSJyri Sarha #include "tidss_plane.h" 2432a1795fSJyri Sarha 2532a1795fSJyri Sarha static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state) 2632a1795fSJyri Sarha { 2732a1795fSJyri Sarha struct drm_device *ddev = old_state->dev; 2832a1795fSJyri Sarha struct tidss_device *tidss = ddev->dev_private; 2932a1795fSJyri Sarha 3032a1795fSJyri Sarha dev_dbg(ddev->dev, "%s\n", __func__); 3132a1795fSJyri Sarha 3232a1795fSJyri Sarha tidss_runtime_get(tidss); 3332a1795fSJyri Sarha 3432a1795fSJyri Sarha drm_atomic_helper_commit_modeset_disables(ddev, old_state); 3532a1795fSJyri Sarha drm_atomic_helper_commit_planes(ddev, old_state, 0); 3632a1795fSJyri Sarha drm_atomic_helper_commit_modeset_enables(ddev, old_state); 3732a1795fSJyri Sarha 3832a1795fSJyri Sarha drm_atomic_helper_commit_hw_done(old_state); 3932a1795fSJyri Sarha drm_atomic_helper_wait_for_flip_done(ddev, old_state); 4032a1795fSJyri Sarha 4132a1795fSJyri Sarha drm_atomic_helper_cleanup_planes(ddev, old_state); 4232a1795fSJyri Sarha 4332a1795fSJyri Sarha tidss_runtime_put(tidss); 4432a1795fSJyri Sarha } 4532a1795fSJyri Sarha 4632a1795fSJyri Sarha static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = { 4732a1795fSJyri Sarha .atomic_commit_tail = tidss_atomic_commit_tail, 4832a1795fSJyri Sarha }; 4932a1795fSJyri Sarha 50b33b5474SJyri Sarha static int tidss_atomic_check(struct drm_device *ddev, 51b33b5474SJyri Sarha struct drm_atomic_state *state) 52b33b5474SJyri Sarha { 53b33b5474SJyri Sarha struct drm_plane_state *opstate; 54b33b5474SJyri Sarha struct drm_plane_state *npstate; 55b33b5474SJyri Sarha struct drm_plane *plane; 56b33b5474SJyri Sarha struct drm_crtc_state *cstate; 57b33b5474SJyri Sarha struct drm_crtc *crtc; 58b33b5474SJyri Sarha int ret, i; 59b33b5474SJyri Sarha 60b33b5474SJyri Sarha ret = drm_atomic_helper_check(ddev, state); 61b33b5474SJyri Sarha if (ret) 62b33b5474SJyri Sarha return ret; 63b33b5474SJyri Sarha 64b33b5474SJyri Sarha /* 65b33b5474SJyri Sarha * Add all active planes on a CRTC to the atomic state, if 66b33b5474SJyri Sarha * x/y/z position or activity of any plane on that CRTC 67b33b5474SJyri Sarha * changes. This is needed for updating the plane positions in 68b33b5474SJyri Sarha * tidss_crtc_position_planes() which is called from 69b33b5474SJyri Sarha * crtc_atomic_enable() and crtc_atomic_flush(). We have an 70b33b5474SJyri Sarha * extra flag to to mark x,y-position changes and together 71b33b5474SJyri Sarha * with zpos_changed the condition recognizes all the above 72b33b5474SJyri Sarha * cases. 73b33b5474SJyri Sarha */ 74b33b5474SJyri Sarha for_each_oldnew_plane_in_state(state, plane, opstate, npstate, i) { 75b33b5474SJyri Sarha if (!npstate->crtc || !npstate->visible) 76b33b5474SJyri Sarha continue; 77b33b5474SJyri Sarha 78b33b5474SJyri Sarha if (!opstate->crtc || opstate->crtc_x != npstate->crtc_x || 79b33b5474SJyri Sarha opstate->crtc_y != npstate->crtc_y) { 80b33b5474SJyri Sarha cstate = drm_atomic_get_crtc_state(state, 81b33b5474SJyri Sarha npstate->crtc); 82b33b5474SJyri Sarha if (IS_ERR(cstate)) 83b33b5474SJyri Sarha return PTR_ERR(cstate); 84b33b5474SJyri Sarha to_tidss_crtc_state(cstate)->plane_pos_changed = true; 85b33b5474SJyri Sarha } 86b33b5474SJyri Sarha } 87b33b5474SJyri Sarha 88b33b5474SJyri Sarha for_each_new_crtc_in_state(state, crtc, cstate, i) { 89b33b5474SJyri Sarha if (to_tidss_crtc_state(cstate)->plane_pos_changed || 90b33b5474SJyri Sarha cstate->zpos_changed) { 91b33b5474SJyri Sarha ret = drm_atomic_add_affected_planes(state, crtc); 92b33b5474SJyri Sarha if (ret) 93b33b5474SJyri Sarha return ret; 94b33b5474SJyri Sarha } 95b33b5474SJyri Sarha } 96b33b5474SJyri Sarha 97b33b5474SJyri Sarha return 0; 98b33b5474SJyri Sarha } 99b33b5474SJyri Sarha 10032a1795fSJyri Sarha static const struct drm_mode_config_funcs mode_config_funcs = { 10132a1795fSJyri Sarha .fb_create = drm_gem_fb_create, 102b33b5474SJyri Sarha .atomic_check = tidss_atomic_check, 10332a1795fSJyri Sarha .atomic_commit = drm_atomic_helper_commit, 10432a1795fSJyri Sarha }; 10532a1795fSJyri Sarha 10632a1795fSJyri Sarha static int tidss_dispc_modeset_init(struct tidss_device *tidss) 10732a1795fSJyri Sarha { 10832a1795fSJyri Sarha struct device *dev = tidss->dev; 10932a1795fSJyri Sarha unsigned int fourccs_len; 11032a1795fSJyri Sarha const u32 *fourccs = dispc_plane_formats(tidss->dispc, &fourccs_len); 11132a1795fSJyri Sarha unsigned int i; 11232a1795fSJyri Sarha 11332a1795fSJyri Sarha struct pipe { 11432a1795fSJyri Sarha u32 hw_videoport; 11532a1795fSJyri Sarha struct drm_bridge *bridge; 11632a1795fSJyri Sarha u32 enc_type; 11732a1795fSJyri Sarha }; 11832a1795fSJyri Sarha 11932a1795fSJyri Sarha const struct dispc_features *feat = tidss->feat; 12032a1795fSJyri Sarha u32 max_vps = feat->num_vps; 12132a1795fSJyri Sarha u32 max_planes = feat->num_planes; 12232a1795fSJyri Sarha 12332a1795fSJyri Sarha struct pipe pipes[TIDSS_MAX_PORTS]; 12432a1795fSJyri Sarha u32 num_pipes = 0; 12532a1795fSJyri Sarha u32 crtc_mask; 12632a1795fSJyri Sarha 12732a1795fSJyri Sarha /* first find all the connected panels & bridges */ 12832a1795fSJyri Sarha 12932a1795fSJyri Sarha for (i = 0; i < max_vps; i++) { 13032a1795fSJyri Sarha struct drm_panel *panel; 13132a1795fSJyri Sarha struct drm_bridge *bridge; 13232a1795fSJyri Sarha u32 enc_type = DRM_MODE_ENCODER_NONE; 13332a1795fSJyri Sarha int ret; 13432a1795fSJyri Sarha 13532a1795fSJyri Sarha ret = drm_of_find_panel_or_bridge(dev->of_node, i, 0, 13632a1795fSJyri Sarha &panel, &bridge); 13732a1795fSJyri Sarha if (ret == -ENODEV) { 13832a1795fSJyri Sarha dev_dbg(dev, "no panel/bridge for port %d\n", i); 13932a1795fSJyri Sarha continue; 14032a1795fSJyri Sarha } else if (ret) { 14132a1795fSJyri Sarha dev_dbg(dev, "port %d probe returned %d\n", i, ret); 14232a1795fSJyri Sarha return ret; 14332a1795fSJyri Sarha } 14432a1795fSJyri Sarha 14532a1795fSJyri Sarha if (panel) { 14632a1795fSJyri Sarha u32 conn_type; 14732a1795fSJyri Sarha 14832a1795fSJyri Sarha dev_dbg(dev, "Setting up panel for port %d\n", i); 14932a1795fSJyri Sarha 15032a1795fSJyri Sarha switch (feat->vp_bus_type[i]) { 15132a1795fSJyri Sarha case DISPC_VP_OLDI: 15232a1795fSJyri Sarha enc_type = DRM_MODE_ENCODER_LVDS; 15332a1795fSJyri Sarha conn_type = DRM_MODE_CONNECTOR_LVDS; 15432a1795fSJyri Sarha break; 15532a1795fSJyri Sarha case DISPC_VP_DPI: 15632a1795fSJyri Sarha enc_type = DRM_MODE_ENCODER_DPI; 15732a1795fSJyri Sarha conn_type = DRM_MODE_CONNECTOR_LVDS; 15832a1795fSJyri Sarha break; 15932a1795fSJyri Sarha default: 16032a1795fSJyri Sarha WARN_ON(1); 16132a1795fSJyri Sarha return -EINVAL; 16232a1795fSJyri Sarha } 16332a1795fSJyri Sarha 16432a1795fSJyri Sarha if (panel->connector_type != conn_type) { 16532a1795fSJyri Sarha dev_err(dev, 16632a1795fSJyri Sarha "%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n", 16732a1795fSJyri Sarha __func__, dev_name(panel->dev), i, 16832a1795fSJyri Sarha panel->connector_type, conn_type); 16932a1795fSJyri Sarha return -EINVAL; 17032a1795fSJyri Sarha } 17132a1795fSJyri Sarha 17232a1795fSJyri Sarha bridge = devm_drm_panel_bridge_add(dev, panel); 17332a1795fSJyri Sarha if (IS_ERR(bridge)) { 17432a1795fSJyri Sarha dev_err(dev, 17532a1795fSJyri Sarha "failed to set up panel bridge for port %d\n", 17632a1795fSJyri Sarha i); 17732a1795fSJyri Sarha return PTR_ERR(bridge); 17832a1795fSJyri Sarha } 17932a1795fSJyri Sarha } 18032a1795fSJyri Sarha 18132a1795fSJyri Sarha pipes[num_pipes].hw_videoport = i; 18232a1795fSJyri Sarha pipes[num_pipes].bridge = bridge; 18332a1795fSJyri Sarha pipes[num_pipes].enc_type = enc_type; 18432a1795fSJyri Sarha num_pipes++; 18532a1795fSJyri Sarha } 18632a1795fSJyri Sarha 18732a1795fSJyri Sarha /* all planes can be on any crtc */ 18832a1795fSJyri Sarha crtc_mask = (1 << num_pipes) - 1; 18932a1795fSJyri Sarha 19032a1795fSJyri Sarha /* then create a plane, a crtc and an encoder for each panel/bridge */ 19132a1795fSJyri Sarha 19232a1795fSJyri Sarha for (i = 0; i < num_pipes; ++i) { 19332a1795fSJyri Sarha struct tidss_plane *tplane; 19432a1795fSJyri Sarha struct tidss_crtc *tcrtc; 19532a1795fSJyri Sarha struct drm_encoder *enc; 19632a1795fSJyri Sarha u32 hw_plane_id = feat->vid_order[tidss->num_planes]; 19732a1795fSJyri Sarha int ret; 19832a1795fSJyri Sarha 19932a1795fSJyri Sarha tplane = tidss_plane_create(tidss, hw_plane_id, 20032a1795fSJyri Sarha DRM_PLANE_TYPE_PRIMARY, crtc_mask, 20132a1795fSJyri Sarha fourccs, fourccs_len); 20232a1795fSJyri Sarha if (IS_ERR(tplane)) { 20332a1795fSJyri Sarha dev_err(tidss->dev, "plane create failed\n"); 20432a1795fSJyri Sarha return PTR_ERR(tplane); 20532a1795fSJyri Sarha } 20632a1795fSJyri Sarha 20732a1795fSJyri Sarha tidss->planes[tidss->num_planes++] = &tplane->plane; 20832a1795fSJyri Sarha 20932a1795fSJyri Sarha tcrtc = tidss_crtc_create(tidss, pipes[i].hw_videoport, 21032a1795fSJyri Sarha &tplane->plane); 21132a1795fSJyri Sarha if (IS_ERR(tcrtc)) { 21232a1795fSJyri Sarha dev_err(tidss->dev, "crtc create failed\n"); 21332a1795fSJyri Sarha return PTR_ERR(tcrtc); 21432a1795fSJyri Sarha } 21532a1795fSJyri Sarha 21632a1795fSJyri Sarha tidss->crtcs[tidss->num_crtcs++] = &tcrtc->crtc; 21732a1795fSJyri Sarha 21832a1795fSJyri Sarha enc = tidss_encoder_create(tidss, pipes[i].enc_type, 21932a1795fSJyri Sarha 1 << tcrtc->crtc.index); 22032a1795fSJyri Sarha if (IS_ERR(enc)) { 22132a1795fSJyri Sarha dev_err(tidss->dev, "encoder create failed\n"); 22232a1795fSJyri Sarha return PTR_ERR(enc); 22332a1795fSJyri Sarha } 22432a1795fSJyri Sarha 225a25b988fSLaurent Pinchart ret = drm_bridge_attach(enc, pipes[i].bridge, NULL, 0); 22632a1795fSJyri Sarha if (ret) { 22732a1795fSJyri Sarha dev_err(tidss->dev, "bridge attach failed: %d\n", ret); 22832a1795fSJyri Sarha return ret; 22932a1795fSJyri Sarha } 23032a1795fSJyri Sarha } 23132a1795fSJyri Sarha 23232a1795fSJyri Sarha /* create overlay planes of the leftover planes */ 23332a1795fSJyri Sarha 23432a1795fSJyri Sarha while (tidss->num_planes < max_planes) { 23532a1795fSJyri Sarha struct tidss_plane *tplane; 23632a1795fSJyri Sarha u32 hw_plane_id = feat->vid_order[tidss->num_planes]; 23732a1795fSJyri Sarha 23832a1795fSJyri Sarha tplane = tidss_plane_create(tidss, hw_plane_id, 23932a1795fSJyri Sarha DRM_PLANE_TYPE_OVERLAY, crtc_mask, 24032a1795fSJyri Sarha fourccs, fourccs_len); 24132a1795fSJyri Sarha 24232a1795fSJyri Sarha if (IS_ERR(tplane)) { 24332a1795fSJyri Sarha dev_err(tidss->dev, "plane create failed\n"); 24432a1795fSJyri Sarha return PTR_ERR(tplane); 24532a1795fSJyri Sarha } 24632a1795fSJyri Sarha 24732a1795fSJyri Sarha tidss->planes[tidss->num_planes++] = &tplane->plane; 24832a1795fSJyri Sarha } 24932a1795fSJyri Sarha 25032a1795fSJyri Sarha return 0; 25132a1795fSJyri Sarha } 25232a1795fSJyri Sarha 25332a1795fSJyri Sarha int tidss_modeset_init(struct tidss_device *tidss) 25432a1795fSJyri Sarha { 25532a1795fSJyri Sarha struct drm_device *ddev = &tidss->ddev; 25632a1795fSJyri Sarha unsigned int i; 25732a1795fSJyri Sarha int ret; 25832a1795fSJyri Sarha 25932a1795fSJyri Sarha dev_dbg(tidss->dev, "%s\n", __func__); 26032a1795fSJyri Sarha 261c792098bSDaniel Vetter ret = drmm_mode_config_init(ddev); 262c792098bSDaniel Vetter if (ret) 263c792098bSDaniel Vetter return ret; 26432a1795fSJyri Sarha 26532a1795fSJyri Sarha ddev->mode_config.min_width = 8; 26632a1795fSJyri Sarha ddev->mode_config.min_height = 8; 26732a1795fSJyri Sarha ddev->mode_config.max_width = 8096; 26832a1795fSJyri Sarha ddev->mode_config.max_height = 8096; 26932a1795fSJyri Sarha ddev->mode_config.normalize_zpos = true; 27032a1795fSJyri Sarha ddev->mode_config.funcs = &mode_config_funcs; 27132a1795fSJyri Sarha ddev->mode_config.helper_private = &mode_config_helper_funcs; 27232a1795fSJyri Sarha 27332a1795fSJyri Sarha ret = tidss_dispc_modeset_init(tidss); 27432a1795fSJyri Sarha if (ret) 275c792098bSDaniel Vetter return ret; 27632a1795fSJyri Sarha 27732a1795fSJyri Sarha ret = drm_vblank_init(ddev, tidss->num_crtcs); 27832a1795fSJyri Sarha if (ret) 279c792098bSDaniel Vetter return ret; 28032a1795fSJyri Sarha 28132a1795fSJyri Sarha /* Start with vertical blanking interrupt reporting disabled. */ 28232a1795fSJyri Sarha for (i = 0; i < tidss->num_crtcs; ++i) 28332a1795fSJyri Sarha drm_crtc_vblank_reset(tidss->crtcs[i]); 28432a1795fSJyri Sarha 28532a1795fSJyri Sarha drm_mode_config_reset(ddev); 28632a1795fSJyri Sarha 28732a1795fSJyri Sarha dev_dbg(tidss->dev, "%s done\n", __func__); 28832a1795fSJyri Sarha 28932a1795fSJyri Sarha return 0; 29032a1795fSJyri Sarha } 291