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