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 5032a1795fSJyri Sarha static const struct drm_mode_config_funcs mode_config_funcs = { 5132a1795fSJyri Sarha .fb_create = drm_gem_fb_create, 5232a1795fSJyri Sarha .atomic_check = drm_atomic_helper_check, 5332a1795fSJyri Sarha .atomic_commit = drm_atomic_helper_commit, 5432a1795fSJyri Sarha }; 5532a1795fSJyri Sarha 5632a1795fSJyri Sarha static int tidss_dispc_modeset_init(struct tidss_device *tidss) 5732a1795fSJyri Sarha { 5832a1795fSJyri Sarha struct device *dev = tidss->dev; 5932a1795fSJyri Sarha unsigned int fourccs_len; 6032a1795fSJyri Sarha const u32 *fourccs = dispc_plane_formats(tidss->dispc, &fourccs_len); 6132a1795fSJyri Sarha unsigned int i; 6232a1795fSJyri Sarha 6332a1795fSJyri Sarha struct pipe { 6432a1795fSJyri Sarha u32 hw_videoport; 6532a1795fSJyri Sarha struct drm_bridge *bridge; 6632a1795fSJyri Sarha u32 enc_type; 6732a1795fSJyri Sarha }; 6832a1795fSJyri Sarha 6932a1795fSJyri Sarha const struct dispc_features *feat = tidss->feat; 7032a1795fSJyri Sarha u32 max_vps = feat->num_vps; 7132a1795fSJyri Sarha u32 max_planes = feat->num_planes; 7232a1795fSJyri Sarha 7332a1795fSJyri Sarha struct pipe pipes[TIDSS_MAX_PORTS]; 7432a1795fSJyri Sarha u32 num_pipes = 0; 7532a1795fSJyri Sarha u32 crtc_mask; 7632a1795fSJyri Sarha 7732a1795fSJyri Sarha /* first find all the connected panels & bridges */ 7832a1795fSJyri Sarha 7932a1795fSJyri Sarha for (i = 0; i < max_vps; i++) { 8032a1795fSJyri Sarha struct drm_panel *panel; 8132a1795fSJyri Sarha struct drm_bridge *bridge; 8232a1795fSJyri Sarha u32 enc_type = DRM_MODE_ENCODER_NONE; 8332a1795fSJyri Sarha int ret; 8432a1795fSJyri Sarha 8532a1795fSJyri Sarha ret = drm_of_find_panel_or_bridge(dev->of_node, i, 0, 8632a1795fSJyri Sarha &panel, &bridge); 8732a1795fSJyri Sarha if (ret == -ENODEV) { 8832a1795fSJyri Sarha dev_dbg(dev, "no panel/bridge for port %d\n", i); 8932a1795fSJyri Sarha continue; 9032a1795fSJyri Sarha } else if (ret) { 9132a1795fSJyri Sarha dev_dbg(dev, "port %d probe returned %d\n", i, ret); 9232a1795fSJyri Sarha return ret; 9332a1795fSJyri Sarha } 9432a1795fSJyri Sarha 9532a1795fSJyri Sarha if (panel) { 9632a1795fSJyri Sarha u32 conn_type; 9732a1795fSJyri Sarha 9832a1795fSJyri Sarha dev_dbg(dev, "Setting up panel for port %d\n", i); 9932a1795fSJyri Sarha 10032a1795fSJyri Sarha switch (feat->vp_bus_type[i]) { 10132a1795fSJyri Sarha case DISPC_VP_OLDI: 10232a1795fSJyri Sarha enc_type = DRM_MODE_ENCODER_LVDS; 10332a1795fSJyri Sarha conn_type = DRM_MODE_CONNECTOR_LVDS; 10432a1795fSJyri Sarha break; 10532a1795fSJyri Sarha case DISPC_VP_DPI: 10632a1795fSJyri Sarha enc_type = DRM_MODE_ENCODER_DPI; 10732a1795fSJyri Sarha conn_type = DRM_MODE_CONNECTOR_LVDS; 10832a1795fSJyri Sarha break; 10932a1795fSJyri Sarha default: 11032a1795fSJyri Sarha WARN_ON(1); 11132a1795fSJyri Sarha return -EINVAL; 11232a1795fSJyri Sarha } 11332a1795fSJyri Sarha 11432a1795fSJyri Sarha if (panel->connector_type != conn_type) { 11532a1795fSJyri Sarha dev_err(dev, 11632a1795fSJyri Sarha "%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n", 11732a1795fSJyri Sarha __func__, dev_name(panel->dev), i, 11832a1795fSJyri Sarha panel->connector_type, conn_type); 11932a1795fSJyri Sarha return -EINVAL; 12032a1795fSJyri Sarha } 12132a1795fSJyri Sarha 12232a1795fSJyri Sarha bridge = devm_drm_panel_bridge_add(dev, panel); 12332a1795fSJyri Sarha if (IS_ERR(bridge)) { 12432a1795fSJyri Sarha dev_err(dev, 12532a1795fSJyri Sarha "failed to set up panel bridge for port %d\n", 12632a1795fSJyri Sarha i); 12732a1795fSJyri Sarha return PTR_ERR(bridge); 12832a1795fSJyri Sarha } 12932a1795fSJyri Sarha } 13032a1795fSJyri Sarha 13132a1795fSJyri Sarha pipes[num_pipes].hw_videoport = i; 13232a1795fSJyri Sarha pipes[num_pipes].bridge = bridge; 13332a1795fSJyri Sarha pipes[num_pipes].enc_type = enc_type; 13432a1795fSJyri Sarha num_pipes++; 13532a1795fSJyri Sarha } 13632a1795fSJyri Sarha 13732a1795fSJyri Sarha /* all planes can be on any crtc */ 13832a1795fSJyri Sarha crtc_mask = (1 << num_pipes) - 1; 13932a1795fSJyri Sarha 14032a1795fSJyri Sarha /* then create a plane, a crtc and an encoder for each panel/bridge */ 14132a1795fSJyri Sarha 14232a1795fSJyri Sarha for (i = 0; i < num_pipes; ++i) { 14332a1795fSJyri Sarha struct tidss_plane *tplane; 14432a1795fSJyri Sarha struct tidss_crtc *tcrtc; 14532a1795fSJyri Sarha struct drm_encoder *enc; 14632a1795fSJyri Sarha u32 hw_plane_id = feat->vid_order[tidss->num_planes]; 14732a1795fSJyri Sarha int ret; 14832a1795fSJyri Sarha 14932a1795fSJyri Sarha tplane = tidss_plane_create(tidss, hw_plane_id, 15032a1795fSJyri Sarha DRM_PLANE_TYPE_PRIMARY, crtc_mask, 15132a1795fSJyri Sarha fourccs, fourccs_len); 15232a1795fSJyri Sarha if (IS_ERR(tplane)) { 15332a1795fSJyri Sarha dev_err(tidss->dev, "plane create failed\n"); 15432a1795fSJyri Sarha return PTR_ERR(tplane); 15532a1795fSJyri Sarha } 15632a1795fSJyri Sarha 15732a1795fSJyri Sarha tidss->planes[tidss->num_planes++] = &tplane->plane; 15832a1795fSJyri Sarha 15932a1795fSJyri Sarha tcrtc = tidss_crtc_create(tidss, pipes[i].hw_videoport, 16032a1795fSJyri Sarha &tplane->plane); 16132a1795fSJyri Sarha if (IS_ERR(tcrtc)) { 16232a1795fSJyri Sarha dev_err(tidss->dev, "crtc create failed\n"); 16332a1795fSJyri Sarha return PTR_ERR(tcrtc); 16432a1795fSJyri Sarha } 16532a1795fSJyri Sarha 16632a1795fSJyri Sarha tidss->crtcs[tidss->num_crtcs++] = &tcrtc->crtc; 16732a1795fSJyri Sarha 16832a1795fSJyri Sarha enc = tidss_encoder_create(tidss, pipes[i].enc_type, 16932a1795fSJyri Sarha 1 << tcrtc->crtc.index); 17032a1795fSJyri Sarha if (IS_ERR(enc)) { 17132a1795fSJyri Sarha dev_err(tidss->dev, "encoder create failed\n"); 17232a1795fSJyri Sarha return PTR_ERR(enc); 17332a1795fSJyri Sarha } 17432a1795fSJyri Sarha 175a25b988fSLaurent Pinchart ret = drm_bridge_attach(enc, pipes[i].bridge, NULL, 0); 17632a1795fSJyri Sarha if (ret) { 17732a1795fSJyri Sarha dev_err(tidss->dev, "bridge attach failed: %d\n", ret); 17832a1795fSJyri Sarha return ret; 17932a1795fSJyri Sarha } 18032a1795fSJyri Sarha } 18132a1795fSJyri Sarha 18232a1795fSJyri Sarha /* create overlay planes of the leftover planes */ 18332a1795fSJyri Sarha 18432a1795fSJyri Sarha while (tidss->num_planes < max_planes) { 18532a1795fSJyri Sarha struct tidss_plane *tplane; 18632a1795fSJyri Sarha u32 hw_plane_id = feat->vid_order[tidss->num_planes]; 18732a1795fSJyri Sarha 18832a1795fSJyri Sarha tplane = tidss_plane_create(tidss, hw_plane_id, 18932a1795fSJyri Sarha DRM_PLANE_TYPE_OVERLAY, crtc_mask, 19032a1795fSJyri Sarha fourccs, fourccs_len); 19132a1795fSJyri Sarha 19232a1795fSJyri Sarha if (IS_ERR(tplane)) { 19332a1795fSJyri Sarha dev_err(tidss->dev, "plane create failed\n"); 19432a1795fSJyri Sarha return PTR_ERR(tplane); 19532a1795fSJyri Sarha } 19632a1795fSJyri Sarha 19732a1795fSJyri Sarha tidss->planes[tidss->num_planes++] = &tplane->plane; 19832a1795fSJyri Sarha } 19932a1795fSJyri Sarha 20032a1795fSJyri Sarha return 0; 20132a1795fSJyri Sarha } 20232a1795fSJyri Sarha 20332a1795fSJyri Sarha int tidss_modeset_init(struct tidss_device *tidss) 20432a1795fSJyri Sarha { 20532a1795fSJyri Sarha struct drm_device *ddev = &tidss->ddev; 20632a1795fSJyri Sarha unsigned int i; 20732a1795fSJyri Sarha int ret; 20832a1795fSJyri Sarha 20932a1795fSJyri Sarha dev_dbg(tidss->dev, "%s\n", __func__); 21032a1795fSJyri Sarha 21132a1795fSJyri Sarha drm_mode_config_init(ddev); 21232a1795fSJyri Sarha 21332a1795fSJyri Sarha ddev->mode_config.min_width = 8; 21432a1795fSJyri Sarha ddev->mode_config.min_height = 8; 21532a1795fSJyri Sarha ddev->mode_config.max_width = 8096; 21632a1795fSJyri Sarha ddev->mode_config.max_height = 8096; 21732a1795fSJyri Sarha ddev->mode_config.normalize_zpos = true; 21832a1795fSJyri Sarha ddev->mode_config.funcs = &mode_config_funcs; 21932a1795fSJyri Sarha ddev->mode_config.helper_private = &mode_config_helper_funcs; 22032a1795fSJyri Sarha 22132a1795fSJyri Sarha ret = tidss_dispc_modeset_init(tidss); 22232a1795fSJyri Sarha if (ret) 22332a1795fSJyri Sarha goto err_mode_config_cleanup; 22432a1795fSJyri Sarha 22532a1795fSJyri Sarha ret = drm_vblank_init(ddev, tidss->num_crtcs); 22632a1795fSJyri Sarha if (ret) 22732a1795fSJyri Sarha goto err_mode_config_cleanup; 22832a1795fSJyri Sarha 22932a1795fSJyri Sarha /* Start with vertical blanking interrupt reporting disabled. */ 23032a1795fSJyri Sarha for (i = 0; i < tidss->num_crtcs; ++i) 23132a1795fSJyri Sarha drm_crtc_vblank_reset(tidss->crtcs[i]); 23232a1795fSJyri Sarha 23332a1795fSJyri Sarha drm_mode_config_reset(ddev); 23432a1795fSJyri Sarha 23532a1795fSJyri Sarha dev_dbg(tidss->dev, "%s done\n", __func__); 23632a1795fSJyri Sarha 23732a1795fSJyri Sarha return 0; 23832a1795fSJyri Sarha 23932a1795fSJyri Sarha err_mode_config_cleanup: 24032a1795fSJyri Sarha drm_mode_config_cleanup(ddev); 24132a1795fSJyri Sarha return ret; 24232a1795fSJyri Sarha } 24332a1795fSJyri Sarha 24432a1795fSJyri Sarha void tidss_modeset_cleanup(struct tidss_device *tidss) 24532a1795fSJyri Sarha { 24632a1795fSJyri Sarha struct drm_device *ddev = &tidss->ddev; 24732a1795fSJyri Sarha 24832a1795fSJyri Sarha drm_mode_config_cleanup(ddev); 24932a1795fSJyri Sarha } 250