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

mdp5_cmd_encoder.c (5947B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <drm/drm_crtc.h>
      7#include <drm/drm_probe_helper.h>
      8
      9#include "mdp5_kms.h"
     10
     11#ifdef CONFIG_DRM_MSM_DSI
     12
     13static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
     14{
     15	struct msm_drm_private *priv = encoder->dev->dev_private;
     16	return to_mdp5_kms(to_mdp_kms(priv->kms));
     17}
     18
     19#define VSYNC_CLK_RATE 19200000
     20static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
     21				    struct drm_display_mode *mode)
     22{
     23	struct mdp5_kms *mdp5_kms = get_kms(encoder);
     24	struct device *dev = encoder->dev->dev;
     25	u32 total_lines, vclks_line, cfg;
     26	long vsync_clk_speed;
     27	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
     28	int pp_id = mixer->pp;
     29
     30	if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
     31		DRM_DEV_ERROR(dev, "vsync_clk is not initialized\n");
     32		return -EINVAL;
     33	}
     34
     35	total_lines = mode->vtotal * drm_mode_vrefresh(mode);
     36	if (!total_lines) {
     37		DRM_DEV_ERROR(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
     38			      __func__, mode->vtotal, drm_mode_vrefresh(mode));
     39		return -EINVAL;
     40	}
     41
     42	vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
     43	if (vsync_clk_speed <= 0) {
     44		DRM_DEV_ERROR(dev, "vsync_clk round rate failed %ld\n",
     45							vsync_clk_speed);
     46		return -EINVAL;
     47	}
     48	vclks_line = vsync_clk_speed / total_lines;
     49
     50	cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
     51		| MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
     52	cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
     53
     54	/*
     55	 * Tearcheck emits a blanking signal every vclks_line * vtotal * 2 ticks on
     56	 * the vsync_clk equating to roughly half the desired panel refresh rate.
     57	 * This is only necessary as stability fallback if interrupts from the
     58	 * panel arrive too late or not at all, but is currently used by default
     59	 * because these panel interrupts are not wired up yet.
     60	 */
     61	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
     62	mdp5_write(mdp5_kms,
     63		REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), (2 * mode->vtotal));
     64
     65	mdp5_write(mdp5_kms,
     66		REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
     67	mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
     68	mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
     69	mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
     70			MDP5_PP_SYNC_THRESH_START(4) |
     71			MDP5_PP_SYNC_THRESH_CONTINUE(4));
     72	mdp5_write(mdp5_kms, REG_MDP5_PP_AUTOREFRESH_CONFIG(pp_id), 0x0);
     73
     74	return 0;
     75}
     76
     77static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
     78{
     79	struct mdp5_kms *mdp5_kms = get_kms(encoder);
     80	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
     81	int pp_id = mixer->pp;
     82	int ret;
     83
     84	ret = clk_set_rate(mdp5_kms->vsync_clk,
     85		clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
     86	if (ret) {
     87		DRM_DEV_ERROR(encoder->dev->dev,
     88			"vsync_clk clk_set_rate failed, %d\n", ret);
     89		return ret;
     90	}
     91	ret = clk_prepare_enable(mdp5_kms->vsync_clk);
     92	if (ret) {
     93		DRM_DEV_ERROR(encoder->dev->dev,
     94			"vsync_clk clk_prepare_enable failed, %d\n", ret);
     95		return ret;
     96	}
     97
     98	mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
     99
    100	return 0;
    101}
    102
    103static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
    104{
    105	struct mdp5_kms *mdp5_kms = get_kms(encoder);
    106	struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
    107	int pp_id = mixer->pp;
    108
    109	mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
    110	clk_disable_unprepare(mdp5_kms->vsync_clk);
    111}
    112
    113void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
    114			       struct drm_display_mode *mode,
    115			       struct drm_display_mode *adjusted_mode)
    116{
    117	mode = adjusted_mode;
    118
    119	DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
    120	pingpong_tearcheck_setup(encoder, mode);
    121	mdp5_crtc_set_pipeline(encoder->crtc);
    122}
    123
    124void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
    125{
    126	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
    127	struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
    128	struct mdp5_interface *intf = mdp5_cmd_enc->intf;
    129	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
    130
    131	if (WARN_ON(!mdp5_cmd_enc->enabled))
    132		return;
    133
    134	pingpong_tearcheck_disable(encoder);
    135
    136	mdp5_ctl_set_encoder_state(ctl, pipeline, false);
    137	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
    138
    139	mdp5_cmd_enc->enabled = false;
    140}
    141
    142void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
    143{
    144	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
    145	struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
    146	struct mdp5_interface *intf = mdp5_cmd_enc->intf;
    147	struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
    148
    149	if (WARN_ON(mdp5_cmd_enc->enabled))
    150		return;
    151
    152	if (pingpong_tearcheck_enable(encoder))
    153		return;
    154
    155	mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
    156
    157	mdp5_ctl_set_encoder_state(ctl, pipeline, true);
    158
    159	mdp5_cmd_enc->enabled = true;
    160}
    161
    162int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
    163				       struct drm_encoder *slave_encoder)
    164{
    165	struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
    166	struct mdp5_kms *mdp5_kms;
    167	struct device *dev;
    168	int intf_num;
    169	u32 data = 0;
    170
    171	if (!encoder || !slave_encoder)
    172		return -EINVAL;
    173
    174	mdp5_kms = get_kms(encoder);
    175	intf_num = mdp5_cmd_enc->intf->num;
    176
    177	/* Switch slave encoder's trigger MUX, to use the master's
    178	 * start signal for the slave encoder
    179	 */
    180	if (intf_num == 1)
    181		data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
    182	else if (intf_num == 2)
    183		data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
    184	else
    185		return -EINVAL;
    186
    187	/* Smart Panel, Sync mode */
    188	data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
    189
    190	dev = &mdp5_kms->pdev->dev;
    191
    192	/* Make sure clocks are on when connectors calling this function. */
    193	pm_runtime_get_sync(dev);
    194	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
    195
    196	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
    197		   MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
    198	mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
    199	pm_runtime_put_sync(dev);
    200
    201	return 0;
    202}
    203#endif /* CONFIG_DRM_MSM_DSI */