linux/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   3 */
   4
   5#include "dpu_hwio.h"
   6#include "dpu_hw_catalog.h"
   7#include "dpu_hw_intf.h"
   8#include "dpu_kms.h"
   9
  10#define INTF_TIMING_ENGINE_EN           0x000
  11#define INTF_CONFIG                     0x004
  12#define INTF_HSYNC_CTL                  0x008
  13#define INTF_VSYNC_PERIOD_F0            0x00C
  14#define INTF_VSYNC_PERIOD_F1            0x010
  15#define INTF_VSYNC_PULSE_WIDTH_F0       0x014
  16#define INTF_VSYNC_PULSE_WIDTH_F1       0x018
  17#define INTF_DISPLAY_V_START_F0         0x01C
  18#define INTF_DISPLAY_V_START_F1         0x020
  19#define INTF_DISPLAY_V_END_F0           0x024
  20#define INTF_DISPLAY_V_END_F1           0x028
  21#define INTF_ACTIVE_V_START_F0          0x02C
  22#define INTF_ACTIVE_V_START_F1          0x030
  23#define INTF_ACTIVE_V_END_F0            0x034
  24#define INTF_ACTIVE_V_END_F1            0x038
  25#define INTF_DISPLAY_HCTL               0x03C
  26#define INTF_ACTIVE_HCTL                0x040
  27#define INTF_BORDER_COLOR               0x044
  28#define INTF_UNDERFLOW_COLOR            0x048
  29#define INTF_HSYNC_SKEW                 0x04C
  30#define INTF_POLARITY_CTL               0x050
  31#define INTF_TEST_CTL                   0x054
  32#define INTF_TP_COLOR0                  0x058
  33#define INTF_TP_COLOR1                  0x05C
  34#define INTF_CONFIG2                    0x060
  35#define INTF_DISPLAY_DATA_HCTL          0x064
  36#define INTF_FRAME_LINE_COUNT_EN        0x0A8
  37#define INTF_FRAME_COUNT                0x0AC
  38#define   INTF_LINE_COUNT               0x0B0
  39
  40#define   INTF_DEFLICKER_CONFIG         0x0F0
  41#define   INTF_DEFLICKER_STRNG_COEFF    0x0F4
  42#define   INTF_DEFLICKER_WEAK_COEFF     0x0F8
  43
  44#define   INTF_DSI_CMD_MODE_TRIGGER_EN  0x084
  45#define   INTF_PANEL_FORMAT             0x090
  46#define   INTF_TPG_ENABLE               0x100
  47#define   INTF_TPG_MAIN_CONTROL         0x104
  48#define   INTF_TPG_VIDEO_CONFIG         0x108
  49#define   INTF_TPG_COMPONENT_LIMITS     0x10C
  50#define   INTF_TPG_RECTANGLE            0x110
  51#define   INTF_TPG_INITIAL_VALUE        0x114
  52#define   INTF_TPG_BLK_WHITE_PATTERN_FRAMES   0x118
  53#define   INTF_TPG_RGB_MAPPING          0x11C
  54#define   INTF_PROG_FETCH_START         0x170
  55#define   INTF_PROG_ROT_START           0x174
  56
  57#define   INTF_FRAME_LINE_COUNT_EN      0x0A8
  58#define   INTF_FRAME_COUNT              0x0AC
  59#define   INTF_LINE_COUNT               0x0B0
  60
  61#define   INTF_MUX                      0x25C
  62
  63static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
  64                const struct dpu_mdss_cfg *m,
  65                void __iomem *addr,
  66                struct dpu_hw_blk_reg_map *b)
  67{
  68        int i;
  69
  70        for (i = 0; i < m->intf_count; i++) {
  71                if ((intf == m->intf[i].id) &&
  72                (m->intf[i].type != INTF_NONE)) {
  73                        b->base_off = addr;
  74                        b->blk_off = m->intf[i].base;
  75                        b->length = m->intf[i].len;
  76                        b->hwversion = m->hwversion;
  77                        b->log_mask = DPU_DBG_MASK_INTF;
  78                        return &m->intf[i];
  79                }
  80        }
  81
  82        return ERR_PTR(-EINVAL);
  83}
  84
  85static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
  86                const struct intf_timing_params *p,
  87                const struct dpu_format *fmt)
  88{
  89        struct dpu_hw_blk_reg_map *c = &ctx->hw;
  90        u32 hsync_period, vsync_period;
  91        u32 display_v_start, display_v_end;
  92        u32 hsync_start_x, hsync_end_x;
  93        u32 active_h_start, active_h_end;
  94        u32 active_v_start, active_v_end;
  95        u32 active_hctl, display_hctl, hsync_ctl;
  96        u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
  97        u32 panel_format;
  98        u32 intf_cfg, intf_cfg2 = 0, display_data_hctl = 0;
  99
 100        /* read interface_cfg */
 101        intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
 102        hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
 103        p->h_front_porch;
 104        vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
 105        p->v_front_porch;
 106
 107        display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
 108        hsync_period) + p->hsync_skew;
 109        display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
 110        p->hsync_skew - 1;
 111
 112        hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
 113        hsync_end_x = hsync_period - p->h_front_porch - 1;
 114
 115        if (p->width != p->xres) {
 116                active_h_start = hsync_start_x;
 117                active_h_end = active_h_start + p->xres - 1;
 118        } else {
 119                active_h_start = 0;
 120                active_h_end = 0;
 121        }
 122
 123        if (p->height != p->yres) {
 124                active_v_start = display_v_start;
 125                active_v_end = active_v_start + (p->yres * hsync_period) - 1;
 126        } else {
 127                active_v_start = 0;
 128                active_v_end = 0;
 129        }
 130
 131        if (active_h_end) {
 132                active_hctl = (active_h_end << 16) | active_h_start;
 133                intf_cfg |= BIT(29);    /* ACTIVE_H_ENABLE */
 134        } else {
 135                active_hctl = 0;
 136        }
 137
 138        if (active_v_end)
 139                intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */
 140
 141        hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
 142        display_hctl = (hsync_end_x << 16) | hsync_start_x;
 143
 144        if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP) {
 145                active_h_start = hsync_start_x;
 146                active_h_end = active_h_start + p->xres - 1;
 147                active_v_start = display_v_start;
 148                active_v_end = active_v_start + (p->yres * hsync_period) - 1;
 149
 150                display_v_start += p->hsync_pulse_width + p->h_back_porch;
 151
 152                active_hctl = (active_h_end << 16) | active_h_start;
 153                display_hctl = active_hctl;
 154        }
 155
 156        den_polarity = 0;
 157        if (ctx->cap->type == INTF_HDMI) {
 158                hsync_polarity = p->yres >= 720 ? 0 : 1;
 159                vsync_polarity = p->yres >= 720 ? 0 : 1;
 160        } else if (ctx->cap->type == INTF_DP) {
 161                hsync_polarity = p->hsync_polarity;
 162                vsync_polarity = p->vsync_polarity;
 163        } else {
 164                hsync_polarity = 0;
 165                vsync_polarity = 0;
 166        }
 167        polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
 168                (vsync_polarity << 1) | /* VSYNC Polarity */
 169                (hsync_polarity << 0);  /* HSYNC Polarity */
 170
 171        if (!DPU_FORMAT_IS_YUV(fmt))
 172                panel_format = (fmt->bits[C0_G_Y] |
 173                                (fmt->bits[C1_B_Cb] << 2) |
 174                                (fmt->bits[C2_R_Cr] << 4) |
 175                                (0x21 << 8));
 176        else
 177                /* Interface treats all the pixel data in RGB888 format */
 178                panel_format = (COLOR_8BIT |
 179                                (COLOR_8BIT << 2) |
 180                                (COLOR_8BIT << 4) |
 181                                (0x21 << 8));
 182
 183        if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) {
 184                intf_cfg2 |= BIT(4);
 185                display_data_hctl = display_hctl;
 186                DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
 187                DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
 188        }
 189
 190        DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
 191        DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
 192        DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
 193                        p->vsync_pulse_width * hsync_period);
 194        DPU_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl);
 195        DPU_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start);
 196        DPU_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end);
 197        DPU_REG_WRITE(c, INTF_ACTIVE_HCTL,  active_hctl);
 198        DPU_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start);
 199        DPU_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end);
 200        DPU_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr);
 201        DPU_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr);
 202        DPU_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew);
 203        DPU_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl);
 204        DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
 205        DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
 206        DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
 207}
 208
 209static void dpu_hw_intf_enable_timing_engine(
 210                struct dpu_hw_intf *intf,
 211                u8 enable)
 212{
 213        struct dpu_hw_blk_reg_map *c = &intf->hw;
 214        /* Note: Display interface select is handled in top block hw layer */
 215        DPU_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0);
 216}
 217
 218static void dpu_hw_intf_setup_prg_fetch(
 219                struct dpu_hw_intf *intf,
 220                const struct intf_prog_fetch *fetch)
 221{
 222        struct dpu_hw_blk_reg_map *c = &intf->hw;
 223        int fetch_enable;
 224
 225        /*
 226         * Fetch should always be outside the active lines. If the fetching
 227         * is programmed within active region, hardware behavior is unknown.
 228         */
 229
 230        fetch_enable = DPU_REG_READ(c, INTF_CONFIG);
 231        if (fetch->enable) {
 232                fetch_enable |= BIT(31);
 233                DPU_REG_WRITE(c, INTF_PROG_FETCH_START,
 234                                fetch->fetch_start);
 235        } else {
 236                fetch_enable &= ~BIT(31);
 237        }
 238
 239        DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable);
 240}
 241
 242static void dpu_hw_intf_bind_pingpong_blk(
 243                struct dpu_hw_intf *intf,
 244                bool enable,
 245                const enum dpu_pingpong pp)
 246{
 247        struct dpu_hw_blk_reg_map *c = &intf->hw;
 248        u32 mux_cfg;
 249
 250        mux_cfg = DPU_REG_READ(c, INTF_MUX);
 251        mux_cfg &= ~0xf;
 252
 253        if (enable)
 254                mux_cfg |= (pp - PINGPONG_0) & 0x7;
 255        else
 256                mux_cfg |= 0xf;
 257
 258        DPU_REG_WRITE(c, INTF_MUX, mux_cfg);
 259}
 260
 261static void dpu_hw_intf_get_status(
 262                struct dpu_hw_intf *intf,
 263                struct intf_status *s)
 264{
 265        struct dpu_hw_blk_reg_map *c = &intf->hw;
 266
 267        s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 268        s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
 269        if (s->is_en) {
 270                s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
 271                s->line_count = DPU_REG_READ(c, INTF_LINE_COUNT);
 272        } else {
 273                s->line_count = 0;
 274                s->frame_count = 0;
 275        }
 276}
 277
 278static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
 279{
 280        struct dpu_hw_blk_reg_map *c;
 281
 282        if (!intf)
 283                return 0;
 284
 285        c = &intf->hw;
 286
 287        return DPU_REG_READ(c, INTF_LINE_COUNT);
 288}
 289
 290static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
 291                unsigned long cap)
 292{
 293        ops->setup_timing_gen = dpu_hw_intf_setup_timing_engine;
 294        ops->setup_prg_fetch  = dpu_hw_intf_setup_prg_fetch;
 295        ops->get_status = dpu_hw_intf_get_status;
 296        ops->enable_timing = dpu_hw_intf_enable_timing_engine;
 297        ops->get_line_count = dpu_hw_intf_get_line_count;
 298        if (cap & BIT(DPU_INTF_INPUT_CTRL))
 299                ops->bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
 300}
 301
 302struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
 303                void __iomem *addr,
 304                const struct dpu_mdss_cfg *m)
 305{
 306        struct dpu_hw_intf *c;
 307        const struct dpu_intf_cfg *cfg;
 308
 309        c = kzalloc(sizeof(*c), GFP_KERNEL);
 310        if (!c)
 311                return ERR_PTR(-ENOMEM);
 312
 313        cfg = _intf_offset(idx, m, addr, &c->hw);
 314        if (IS_ERR_OR_NULL(cfg)) {
 315                kfree(c);
 316                pr_err("failed to create dpu_hw_intf %d\n", idx);
 317                return ERR_PTR(-EINVAL);
 318        }
 319
 320        /*
 321         * Assign ops
 322         */
 323        c->idx = idx;
 324        c->cap = cfg;
 325        c->mdss = m;
 326        _setup_intf_ops(&c->ops, c->cap->features);
 327
 328        return c;
 329}
 330
 331void dpu_hw_intf_destroy(struct dpu_hw_intf *intf)
 332{
 333        kfree(intf);
 334}
 335
 336