linux/drivers/gpu/drm/msm/disp/mdp5/mdp5_cmd_encoder.c
<<
>>
Prefs
   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
  11static 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
  22static 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
  35static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx) {}
  36#endif
  37
  38#define VSYNC_CLK_RATE 19200000
  39static 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
  87static 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
 113static 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
 123void 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
 134void 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
 154void 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
 175int 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}
 216