root/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_kms
  2. bs_set
  3. bs_set
  4. pingpong_tearcheck_setup
  5. pingpong_tearcheck_enable
  6. pingpong_tearcheck_disable
  7. mdp5_cmd_encoder_mode_set
  8. mdp5_cmd_encoder_disable
  9. mdp5_cmd_encoder_enable
  10. mdp5_cmd_encoder_set_split_display

   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 static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
  12 {
  13         struct msm_drm_private *priv = encoder->dev->dev_private;
  14         return to_mdp5_kms(to_mdp_kms(priv->kms));
  15 }
  16 
  17 #ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
  18 #include <mach/board.h>
  19 #include <linux/msm-bus.h>
  20 #include <linux/msm-bus-board.h>
  21 
  22 static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx)
  23 {
  24         if (mdp5_cmd_enc->bsc) {
  25                 DBG("set bus scaling: %d", idx);
  26                 /* HACK: scaling down, and then immediately back up
  27                  * seems to leave things broken (underflow).. so
  28                  * never disable:
  29                  */
  30                 idx = 1;
  31                 msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx);
  32         }
  33 }
  34 #else
  35 static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx) {}
  36 #endif
  37 
  38 #define VSYNC_CLK_RATE 19200000
  39 static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
  40                                     struct drm_display_mode *mode)
  41 {
  42         struct mdp5_kms *mdp5_kms = get_kms(encoder);
  43         struct device *dev = encoder->dev->dev;
  44         u32 total_lines_x100, vclks_line, cfg;
  45         long vsync_clk_speed;
  46         struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
  47         int pp_id = mixer->pp;
  48 
  49         if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
  50                 DRM_DEV_ERROR(dev, "vsync_clk is not initialized\n");
  51                 return -EINVAL;
  52         }
  53 
  54         total_lines_x100 = mode->vtotal * drm_mode_vrefresh(mode);
  55         if (!total_lines_x100) {
  56                 DRM_DEV_ERROR(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
  57                               __func__, mode->vtotal, drm_mode_vrefresh(mode));
  58                 return -EINVAL;
  59         }
  60 
  61         vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
  62         if (vsync_clk_speed <= 0) {
  63                 DRM_DEV_ERROR(dev, "vsync_clk round rate failed %ld\n",
  64                                                         vsync_clk_speed);
  65                 return -EINVAL;
  66         }
  67         vclks_line = vsync_clk_speed * 100 / total_lines_x100;
  68 
  69         cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
  70                 | MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
  71         cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
  72 
  73         mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
  74         mdp5_write(mdp5_kms,
  75                 REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
  76         mdp5_write(mdp5_kms,
  77                 REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
  78         mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
  79         mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
  80         mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
  81                         MDP5_PP_SYNC_THRESH_START(4) |
  82                         MDP5_PP_SYNC_THRESH_CONTINUE(4));
  83 
  84         return 0;
  85 }
  86 
  87 static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
  88 {
  89         struct mdp5_kms *mdp5_kms = get_kms(encoder);
  90         struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
  91         int pp_id = mixer->pp;
  92         int ret;
  93 
  94         ret = clk_set_rate(mdp5_kms->vsync_clk,
  95                 clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
  96         if (ret) {
  97                 DRM_DEV_ERROR(encoder->dev->dev,
  98                         "vsync_clk clk_set_rate failed, %d\n", ret);
  99                 return ret;
 100         }
 101         ret = clk_prepare_enable(mdp5_kms->vsync_clk);
 102         if (ret) {
 103                 DRM_DEV_ERROR(encoder->dev->dev,
 104                         "vsync_clk clk_prepare_enable failed, %d\n", ret);
 105                 return ret;
 106         }
 107 
 108         mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
 109 
 110         return 0;
 111 }
 112 
 113 static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
 114 {
 115         struct mdp5_kms *mdp5_kms = get_kms(encoder);
 116         struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
 117         int pp_id = mixer->pp;
 118 
 119         mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
 120         clk_disable_unprepare(mdp5_kms->vsync_clk);
 121 }
 122 
 123 void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
 124                                struct drm_display_mode *mode,
 125                                struct drm_display_mode *adjusted_mode)
 126 {
 127         mode = adjusted_mode;
 128 
 129         DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode));
 130         pingpong_tearcheck_setup(encoder, mode);
 131         mdp5_crtc_set_pipeline(encoder->crtc);
 132 }
 133 
 134 void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
 135 {
 136         struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
 137         struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
 138         struct mdp5_interface *intf = mdp5_cmd_enc->intf;
 139         struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
 140 
 141         if (WARN_ON(!mdp5_cmd_enc->enabled))
 142                 return;
 143 
 144         pingpong_tearcheck_disable(encoder);
 145 
 146         mdp5_ctl_set_encoder_state(ctl, pipeline, false);
 147         mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
 148 
 149         bs_set(mdp5_cmd_enc, 0);
 150 
 151         mdp5_cmd_enc->enabled = false;
 152 }
 153 
 154 void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
 155 {
 156         struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
 157         struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
 158         struct mdp5_interface *intf = mdp5_cmd_enc->intf;
 159         struct mdp5_pipeline *pipeline = mdp5_crtc_get_pipeline(encoder->crtc);
 160 
 161         if (WARN_ON(mdp5_cmd_enc->enabled))
 162                 return;
 163 
 164         bs_set(mdp5_cmd_enc, 1);
 165         if (pingpong_tearcheck_enable(encoder))
 166                 return;
 167 
 168         mdp5_ctl_commit(ctl, pipeline, mdp_ctl_flush_mask_encoder(intf), true);
 169 
 170         mdp5_ctl_set_encoder_state(ctl, pipeline, true);
 171 
 172         mdp5_cmd_enc->enabled = true;
 173 }
 174 
 175 int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
 176                                        struct drm_encoder *slave_encoder)
 177 {
 178         struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
 179         struct mdp5_kms *mdp5_kms;
 180         struct device *dev;
 181         int intf_num;
 182         u32 data = 0;
 183 
 184         if (!encoder || !slave_encoder)
 185                 return -EINVAL;
 186 
 187         mdp5_kms = get_kms(encoder);
 188         intf_num = mdp5_cmd_enc->intf->num;
 189 
 190         /* Switch slave encoder's trigger MUX, to use the master's
 191          * start signal for the slave encoder
 192          */
 193         if (intf_num == 1)
 194                 data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
 195         else if (intf_num == 2)
 196                 data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
 197         else
 198                 return -EINVAL;
 199 
 200         /* Smart Panel, Sync mode */
 201         data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
 202 
 203         dev = &mdp5_kms->pdev->dev;
 204 
 205         /* Make sure clocks are on when connectors calling this function. */
 206         pm_runtime_get_sync(dev);
 207         mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
 208 
 209         mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
 210                    MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
 211         mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
 212         pm_runtime_put_sync(dev);
 213 
 214         return 0;
 215 }

/* [<][>][^][v][top][bottom][index][help] */