cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tidss_kms.c (7372B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
      4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
      5 */
      6
      7#include <linux/dma-fence.h>
      8
      9#include <drm/drm_atomic.h>
     10#include <drm/drm_atomic_helper.h>
     11#include <drm/drm_bridge.h>
     12#include <drm/drm_crtc_helper.h>
     13#include <drm/drm_fb_cma_helper.h>
     14#include <drm/drm_fb_helper.h>
     15#include <drm/drm_gem_framebuffer_helper.h>
     16#include <drm/drm_of.h>
     17#include <drm/drm_panel.h>
     18#include <drm/drm_vblank.h>
     19
     20#include "tidss_crtc.h"
     21#include "tidss_dispc.h"
     22#include "tidss_drv.h"
     23#include "tidss_encoder.h"
     24#include "tidss_kms.h"
     25#include "tidss_plane.h"
     26
     27static void tidss_atomic_commit_tail(struct drm_atomic_state *old_state)
     28{
     29	struct drm_device *ddev = old_state->dev;
     30	struct tidss_device *tidss = to_tidss(ddev);
     31	bool fence_cookie = dma_fence_begin_signalling();
     32
     33	dev_dbg(ddev->dev, "%s\n", __func__);
     34
     35	tidss_runtime_get(tidss);
     36
     37	drm_atomic_helper_commit_modeset_disables(ddev, old_state);
     38	drm_atomic_helper_commit_planes(ddev, old_state, 0);
     39	drm_atomic_helper_commit_modeset_enables(ddev, old_state);
     40
     41	drm_atomic_helper_commit_hw_done(old_state);
     42	dma_fence_end_signalling(fence_cookie);
     43	drm_atomic_helper_wait_for_flip_done(ddev, old_state);
     44
     45	drm_atomic_helper_cleanup_planes(ddev, old_state);
     46
     47	tidss_runtime_put(tidss);
     48}
     49
     50static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = {
     51	.atomic_commit_tail = tidss_atomic_commit_tail,
     52};
     53
     54static int tidss_atomic_check(struct drm_device *ddev,
     55			      struct drm_atomic_state *state)
     56{
     57	struct drm_plane_state *opstate;
     58	struct drm_plane_state *npstate;
     59	struct drm_plane *plane;
     60	struct drm_crtc_state *cstate;
     61	struct drm_crtc *crtc;
     62	int ret, i;
     63
     64	ret = drm_atomic_helper_check(ddev, state);
     65	if (ret)
     66		return ret;
     67
     68	/*
     69	 * Add all active planes on a CRTC to the atomic state, if
     70	 * x/y/z position or activity of any plane on that CRTC
     71	 * changes. This is needed for updating the plane positions in
     72	 * tidss_crtc_position_planes() which is called from
     73	 * crtc_atomic_enable() and crtc_atomic_flush(). We have an
     74	 * extra flag to to mark x,y-position changes and together
     75	 * with zpos_changed the condition recognizes all the above
     76	 * cases.
     77	 */
     78	for_each_oldnew_plane_in_state(state, plane, opstate, npstate, i) {
     79		if (!npstate->crtc || !npstate->visible)
     80			continue;
     81
     82		if (!opstate->crtc || opstate->crtc_x != npstate->crtc_x ||
     83		    opstate->crtc_y != npstate->crtc_y) {
     84			cstate = drm_atomic_get_crtc_state(state,
     85							   npstate->crtc);
     86			if (IS_ERR(cstate))
     87				return PTR_ERR(cstate);
     88			to_tidss_crtc_state(cstate)->plane_pos_changed = true;
     89		}
     90	}
     91
     92	for_each_new_crtc_in_state(state, crtc, cstate, i) {
     93		if (to_tidss_crtc_state(cstate)->plane_pos_changed ||
     94		    cstate->zpos_changed) {
     95			ret = drm_atomic_add_affected_planes(state, crtc);
     96			if (ret)
     97				return ret;
     98		}
     99	}
    100
    101	return 0;
    102}
    103
    104static const struct drm_mode_config_funcs mode_config_funcs = {
    105	.fb_create = drm_gem_fb_create,
    106	.atomic_check = tidss_atomic_check,
    107	.atomic_commit = drm_atomic_helper_commit,
    108};
    109
    110static int tidss_dispc_modeset_init(struct tidss_device *tidss)
    111{
    112	struct device *dev = tidss->dev;
    113	unsigned int fourccs_len;
    114	const u32 *fourccs = dispc_plane_formats(tidss->dispc, &fourccs_len);
    115	unsigned int i;
    116
    117	struct pipe {
    118		u32 hw_videoport;
    119		struct drm_bridge *bridge;
    120		u32 enc_type;
    121	};
    122
    123	const struct dispc_features *feat = tidss->feat;
    124	u32 max_vps = feat->num_vps;
    125	u32 max_planes = feat->num_planes;
    126
    127	struct pipe pipes[TIDSS_MAX_PORTS];
    128	u32 num_pipes = 0;
    129	u32 crtc_mask;
    130
    131	/* first find all the connected panels & bridges */
    132
    133	for (i = 0; i < max_vps; i++) {
    134		struct drm_panel *panel;
    135		struct drm_bridge *bridge;
    136		u32 enc_type = DRM_MODE_ENCODER_NONE;
    137		int ret;
    138
    139		ret = drm_of_find_panel_or_bridge(dev->of_node, i, 0,
    140						  &panel, &bridge);
    141		if (ret == -ENODEV) {
    142			dev_dbg(dev, "no panel/bridge for port %d\n", i);
    143			continue;
    144		} else if (ret) {
    145			dev_dbg(dev, "port %d probe returned %d\n", i, ret);
    146			return ret;
    147		}
    148
    149		if (panel) {
    150			u32 conn_type;
    151
    152			dev_dbg(dev, "Setting up panel for port %d\n", i);
    153
    154			switch (feat->vp_bus_type[i]) {
    155			case DISPC_VP_OLDI:
    156				enc_type = DRM_MODE_ENCODER_LVDS;
    157				conn_type = DRM_MODE_CONNECTOR_LVDS;
    158				break;
    159			case DISPC_VP_DPI:
    160				enc_type = DRM_MODE_ENCODER_DPI;
    161				conn_type = DRM_MODE_CONNECTOR_DPI;
    162				break;
    163			default:
    164				WARN_ON(1);
    165				return -EINVAL;
    166			}
    167
    168			if (panel->connector_type != conn_type) {
    169				dev_err(dev,
    170					"%s: Panel %s has incompatible connector type for vp%d (%d != %d)\n",
    171					 __func__, dev_name(panel->dev), i,
    172					 panel->connector_type, conn_type);
    173				return -EINVAL;
    174			}
    175
    176			bridge = devm_drm_panel_bridge_add(dev, panel);
    177			if (IS_ERR(bridge)) {
    178				dev_err(dev,
    179					"failed to set up panel bridge for port %d\n",
    180					i);
    181				return PTR_ERR(bridge);
    182			}
    183		}
    184
    185		pipes[num_pipes].hw_videoport = i;
    186		pipes[num_pipes].bridge = bridge;
    187		pipes[num_pipes].enc_type = enc_type;
    188		num_pipes++;
    189	}
    190
    191	/* all planes can be on any crtc */
    192	crtc_mask = (1 << num_pipes) - 1;
    193
    194	/* then create a plane, a crtc and an encoder for each panel/bridge */
    195
    196	for (i = 0; i < num_pipes; ++i) {
    197		struct tidss_plane *tplane;
    198		struct tidss_crtc *tcrtc;
    199		struct drm_encoder *enc;
    200		u32 hw_plane_id = feat->vid_order[tidss->num_planes];
    201		int ret;
    202
    203		tplane = tidss_plane_create(tidss, hw_plane_id,
    204					    DRM_PLANE_TYPE_PRIMARY, crtc_mask,
    205					    fourccs, fourccs_len);
    206		if (IS_ERR(tplane)) {
    207			dev_err(tidss->dev, "plane create failed\n");
    208			return PTR_ERR(tplane);
    209		}
    210
    211		tidss->planes[tidss->num_planes++] = &tplane->plane;
    212
    213		tcrtc = tidss_crtc_create(tidss, pipes[i].hw_videoport,
    214					  &tplane->plane);
    215		if (IS_ERR(tcrtc)) {
    216			dev_err(tidss->dev, "crtc create failed\n");
    217			return PTR_ERR(tcrtc);
    218		}
    219
    220		tidss->crtcs[tidss->num_crtcs++] = &tcrtc->crtc;
    221
    222		enc = tidss_encoder_create(tidss, pipes[i].enc_type,
    223					   1 << tcrtc->crtc.index);
    224		if (IS_ERR(enc)) {
    225			dev_err(tidss->dev, "encoder create failed\n");
    226			return PTR_ERR(enc);
    227		}
    228
    229		ret = drm_bridge_attach(enc, pipes[i].bridge, NULL, 0);
    230		if (ret)
    231			return ret;
    232	}
    233
    234	/* create overlay planes of the leftover planes */
    235
    236	while (tidss->num_planes < max_planes) {
    237		struct tidss_plane *tplane;
    238		u32 hw_plane_id = feat->vid_order[tidss->num_planes];
    239
    240		tplane = tidss_plane_create(tidss, hw_plane_id,
    241					    DRM_PLANE_TYPE_OVERLAY, crtc_mask,
    242					    fourccs, fourccs_len);
    243
    244		if (IS_ERR(tplane)) {
    245			dev_err(tidss->dev, "plane create failed\n");
    246			return PTR_ERR(tplane);
    247		}
    248
    249		tidss->planes[tidss->num_planes++] = &tplane->plane;
    250	}
    251
    252	return 0;
    253}
    254
    255int tidss_modeset_init(struct tidss_device *tidss)
    256{
    257	struct drm_device *ddev = &tidss->ddev;
    258	int ret;
    259
    260	dev_dbg(tidss->dev, "%s\n", __func__);
    261
    262	ret = drmm_mode_config_init(ddev);
    263	if (ret)
    264		return ret;
    265
    266	ddev->mode_config.min_width = 8;
    267	ddev->mode_config.min_height = 8;
    268	ddev->mode_config.max_width = 8096;
    269	ddev->mode_config.max_height = 8096;
    270	ddev->mode_config.normalize_zpos = true;
    271	ddev->mode_config.funcs = &mode_config_funcs;
    272	ddev->mode_config.helper_private = &mode_config_helper_funcs;
    273
    274	ret = tidss_dispc_modeset_init(tidss);
    275	if (ret)
    276		return ret;
    277
    278	ret = drm_vblank_init(ddev, tidss->num_crtcs);
    279	if (ret)
    280		return ret;
    281
    282	drm_mode_config_reset(ddev);
    283
    284	dev_dbg(tidss->dev, "%s done\n", __func__);
    285
    286	return 0;
    287}