linux/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
   3 * Copyright (c) 2014, Inforce Computing. All rights reserved.
   4 *
   5 * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License version 2 as published by
   9 * the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14 * more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along with
  17 * this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include <drm/drm_crtc.h>
  21#include <drm/drm_crtc_helper.h>
  22
  23#include "mdp4_kms.h"
  24
  25struct mdp4_dsi_encoder {
  26        struct drm_encoder base;
  27        struct drm_panel *panel;
  28        bool enabled;
  29};
  30#define to_mdp4_dsi_encoder(x) container_of(x, struct mdp4_dsi_encoder, base)
  31
  32static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
  33{
  34        struct msm_drm_private *priv = encoder->dev->dev_private;
  35        return to_mdp4_kms(to_mdp_kms(priv->kms));
  36}
  37
  38static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder)
  39{
  40        struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
  41
  42        drm_encoder_cleanup(encoder);
  43        kfree(mdp4_dsi_encoder);
  44}
  45
  46static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
  47        .destroy = mdp4_dsi_encoder_destroy,
  48};
  49
  50static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
  51                                      struct drm_display_mode *mode,
  52                                      struct drm_display_mode *adjusted_mode)
  53{
  54        struct mdp4_kms *mdp4_kms = get_kms(encoder);
  55        uint32_t dsi_hsync_skew, vsync_period, vsync_len, ctrl_pol;
  56        uint32_t display_v_start, display_v_end;
  57        uint32_t hsync_start_x, hsync_end_x;
  58
  59        mode = adjusted_mode;
  60
  61        DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
  62                        mode->base.id, mode->name,
  63                        mode->vrefresh, mode->clock,
  64                        mode->hdisplay, mode->hsync_start,
  65                        mode->hsync_end, mode->htotal,
  66                        mode->vdisplay, mode->vsync_start,
  67                        mode->vsync_end, mode->vtotal,
  68                        mode->type, mode->flags);
  69
  70        ctrl_pol = 0;
  71        if (mode->flags & DRM_MODE_FLAG_NHSYNC)
  72                ctrl_pol |= MDP4_DSI_CTRL_POLARITY_HSYNC_LOW;
  73        if (mode->flags & DRM_MODE_FLAG_NVSYNC)
  74                ctrl_pol |= MDP4_DSI_CTRL_POLARITY_VSYNC_LOW;
  75        /* probably need to get DATA_EN polarity from panel.. */
  76
  77        dsi_hsync_skew = 0;  /* get this from panel? */
  78
  79        hsync_start_x = (mode->htotal - mode->hsync_start);
  80        hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
  81
  82        vsync_period = mode->vtotal * mode->htotal;
  83        vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
  84        display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dsi_hsync_skew;
  85        display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dsi_hsync_skew - 1;
  86
  87        mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_CTRL,
  88                        MDP4_DSI_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
  89                        MDP4_DSI_HSYNC_CTRL_PERIOD(mode->htotal));
  90        mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_PERIOD, vsync_period);
  91        mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_LEN, vsync_len);
  92        mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_HCTRL,
  93                        MDP4_DSI_DISPLAY_HCTRL_START(hsync_start_x) |
  94                        MDP4_DSI_DISPLAY_HCTRL_END(hsync_end_x));
  95        mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VSTART, display_v_start);
  96        mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VEND, display_v_end);
  97
  98        mdp4_write(mdp4_kms, REG_MDP4_DSI_CTRL_POLARITY, ctrl_pol);
  99        mdp4_write(mdp4_kms, REG_MDP4_DSI_UNDERFLOW_CLR,
 100                        MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY |
 101                        MDP4_DSI_UNDERFLOW_CLR_COLOR(0xff));
 102        mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_HCTL,
 103                        MDP4_DSI_ACTIVE_HCTL_START(0) |
 104                        MDP4_DSI_ACTIVE_HCTL_END(0));
 105        mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_SKEW, dsi_hsync_skew);
 106        mdp4_write(mdp4_kms, REG_MDP4_DSI_BORDER_CLR, 0);
 107        mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VSTART, 0);
 108        mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VEND, 0);
 109}
 110
 111static void mdp4_dsi_encoder_disable(struct drm_encoder *encoder)
 112{
 113        struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
 114        struct mdp4_kms *mdp4_kms = get_kms(encoder);
 115
 116        if (!mdp4_dsi_encoder->enabled)
 117                return;
 118
 119        mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
 120
 121        /*
 122         * Wait for a vsync so we know the ENABLE=0 latched before
 123         * the (connector) source of the vsync's gets disabled,
 124         * otherwise we end up in a funny state if we re-enable
 125         * before the disable latches, which results that some of
 126         * the settings changes for the new modeset (like new
 127         * scanout buffer) don't latch properly..
 128         */
 129        mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
 130
 131        mdp4_dsi_encoder->enabled = false;
 132}
 133
 134static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder)
 135{
 136        struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
 137        struct mdp4_kms *mdp4_kms = get_kms(encoder);
 138
 139        if (mdp4_dsi_encoder->enabled)
 140                return;
 141
 142         mdp4_crtc_set_config(encoder->crtc,
 143                        MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
 144                        MDP4_DMA_CONFIG_DEFLKR_EN |
 145                        MDP4_DMA_CONFIG_DITHER_EN |
 146                        MDP4_DMA_CONFIG_R_BPC(BPC8) |
 147                        MDP4_DMA_CONFIG_G_BPC(BPC8) |
 148                        MDP4_DMA_CONFIG_B_BPC(BPC8) |
 149                        MDP4_DMA_CONFIG_PACK(0x21));
 150
 151        mdp4_crtc_set_intf(encoder->crtc, INTF_DSI_VIDEO, 0);
 152
 153        mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 1);
 154
 155        mdp4_dsi_encoder->enabled = true;
 156}
 157
 158static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = {
 159        .mode_set = mdp4_dsi_encoder_mode_set,
 160        .disable = mdp4_dsi_encoder_disable,
 161        .enable = mdp4_dsi_encoder_enable,
 162};
 163
 164/* initialize encoder */
 165struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
 166{
 167        struct drm_encoder *encoder = NULL;
 168        struct mdp4_dsi_encoder *mdp4_dsi_encoder;
 169        int ret;
 170
 171        mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL);
 172        if (!mdp4_dsi_encoder) {
 173                ret = -ENOMEM;
 174                goto fail;
 175        }
 176
 177        encoder = &mdp4_dsi_encoder->base;
 178
 179        drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs,
 180                         DRM_MODE_ENCODER_DSI, NULL);
 181        drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs);
 182
 183        return encoder;
 184
 185fail:
 186        if (encoder)
 187                mdp4_dsi_encoder_destroy(encoder);
 188
 189        return ERR_PTR(ret);
 190}
 191