Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
0004  * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
0005  */
0006 
0007 #include "dpu_hwio.h"
0008 #include "dpu_hw_catalog.h"
0009 #include "dpu_hw_intf.h"
0010 #include "dpu_kms.h"
0011 
0012 #define INTF_TIMING_ENGINE_EN           0x000
0013 #define INTF_CONFIG                     0x004
0014 #define INTF_HSYNC_CTL                  0x008
0015 #define INTF_VSYNC_PERIOD_F0            0x00C
0016 #define INTF_VSYNC_PERIOD_F1            0x010
0017 #define INTF_VSYNC_PULSE_WIDTH_F0       0x014
0018 #define INTF_VSYNC_PULSE_WIDTH_F1       0x018
0019 #define INTF_DISPLAY_V_START_F0         0x01C
0020 #define INTF_DISPLAY_V_START_F1         0x020
0021 #define INTF_DISPLAY_V_END_F0           0x024
0022 #define INTF_DISPLAY_V_END_F1           0x028
0023 #define INTF_ACTIVE_V_START_F0          0x02C
0024 #define INTF_ACTIVE_V_START_F1          0x030
0025 #define INTF_ACTIVE_V_END_F0            0x034
0026 #define INTF_ACTIVE_V_END_F1            0x038
0027 #define INTF_DISPLAY_HCTL               0x03C
0028 #define INTF_ACTIVE_HCTL                0x040
0029 #define INTF_BORDER_COLOR               0x044
0030 #define INTF_UNDERFLOW_COLOR            0x048
0031 #define INTF_HSYNC_SKEW                 0x04C
0032 #define INTF_POLARITY_CTL               0x050
0033 #define INTF_TEST_CTL                   0x054
0034 #define INTF_TP_COLOR0                  0x058
0035 #define INTF_TP_COLOR1                  0x05C
0036 #define INTF_CONFIG2                    0x060
0037 #define INTF_DISPLAY_DATA_HCTL          0x064
0038 #define INTF_ACTIVE_DATA_HCTL           0x068
0039 #define INTF_FRAME_LINE_COUNT_EN        0x0A8
0040 #define INTF_FRAME_COUNT                0x0AC
0041 #define   INTF_LINE_COUNT               0x0B0
0042 
0043 #define   INTF_DEFLICKER_CONFIG         0x0F0
0044 #define   INTF_DEFLICKER_STRNG_COEFF    0x0F4
0045 #define   INTF_DEFLICKER_WEAK_COEFF     0x0F8
0046 
0047 #define   INTF_DSI_CMD_MODE_TRIGGER_EN  0x084
0048 #define   INTF_PANEL_FORMAT             0x090
0049 #define   INTF_TPG_ENABLE               0x100
0050 #define   INTF_TPG_MAIN_CONTROL         0x104
0051 #define   INTF_TPG_VIDEO_CONFIG         0x108
0052 #define   INTF_TPG_COMPONENT_LIMITS     0x10C
0053 #define   INTF_TPG_RECTANGLE            0x110
0054 #define   INTF_TPG_INITIAL_VALUE        0x114
0055 #define   INTF_TPG_BLK_WHITE_PATTERN_FRAMES   0x118
0056 #define   INTF_TPG_RGB_MAPPING          0x11C
0057 #define   INTF_PROG_FETCH_START         0x170
0058 #define   INTF_PROG_ROT_START           0x174
0059 
0060 #define   INTF_FRAME_LINE_COUNT_EN      0x0A8
0061 #define   INTF_FRAME_COUNT              0x0AC
0062 #define   INTF_LINE_COUNT               0x0B0
0063 
0064 #define   INTF_MUX                      0x25C
0065 
0066 #define INTF_CFG_ACTIVE_H_EN    BIT(29)
0067 #define INTF_CFG_ACTIVE_V_EN    BIT(30)
0068 
0069 #define INTF_CFG2_DATABUS_WIDEN BIT(0)
0070 #define INTF_CFG2_DATA_HCTL_EN  BIT(4)
0071 
0072 #define INTF_MISR_CTRL          0x180
0073 #define INTF_MISR_SIGNATURE     0x184
0074 
0075 static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
0076         const struct dpu_mdss_cfg *m,
0077         void __iomem *addr,
0078         struct dpu_hw_blk_reg_map *b)
0079 {
0080     int i;
0081 
0082     for (i = 0; i < m->intf_count; i++) {
0083         if ((intf == m->intf[i].id) &&
0084         (m->intf[i].type != INTF_NONE)) {
0085             b->blk_addr = addr + m->intf[i].base;
0086             b->log_mask = DPU_DBG_MASK_INTF;
0087             return &m->intf[i];
0088         }
0089     }
0090 
0091     return ERR_PTR(-EINVAL);
0092 }
0093 
0094 static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
0095         const struct intf_timing_params *p,
0096         const struct dpu_format *fmt)
0097 {
0098     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0099     u32 hsync_period, vsync_period;
0100     u32 display_v_start, display_v_end;
0101     u32 hsync_start_x, hsync_end_x;
0102     u32 hsync_data_start_x, hsync_data_end_x;
0103     u32 active_h_start, active_h_end;
0104     u32 active_v_start, active_v_end;
0105     u32 active_hctl, display_hctl, hsync_ctl;
0106     u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
0107     u32 panel_format;
0108     u32 intf_cfg, intf_cfg2 = 0;
0109     u32 display_data_hctl = 0, active_data_hctl = 0;
0110     u32 data_width;
0111     bool dp_intf = false;
0112 
0113     /* read interface_cfg */
0114     intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
0115 
0116     if (ctx->cap->type == INTF_DP)
0117         dp_intf = true;
0118 
0119     hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
0120     p->h_front_porch;
0121     vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
0122     p->v_front_porch;
0123 
0124     display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
0125     hsync_period) + p->hsync_skew;
0126     display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
0127     p->hsync_skew - 1;
0128 
0129     hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
0130     hsync_end_x = hsync_period - p->h_front_porch - 1;
0131 
0132     if (p->width != p->xres) { /* border fill added */
0133         active_h_start = hsync_start_x;
0134         active_h_end = active_h_start + p->xres - 1;
0135     } else {
0136         active_h_start = 0;
0137         active_h_end = 0;
0138     }
0139 
0140     if (p->height != p->yres) { /* border fill added */
0141         active_v_start = display_v_start;
0142         active_v_end = active_v_start + (p->yres * hsync_period) - 1;
0143     } else {
0144         active_v_start = 0;
0145         active_v_end = 0;
0146     }
0147 
0148     if (active_h_end) {
0149         active_hctl = (active_h_end << 16) | active_h_start;
0150         intf_cfg |= INTF_CFG_ACTIVE_H_EN;
0151     } else {
0152         active_hctl = 0;
0153     }
0154 
0155     if (active_v_end)
0156         intf_cfg |= INTF_CFG_ACTIVE_V_EN;
0157 
0158     hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
0159     display_hctl = (hsync_end_x << 16) | hsync_start_x;
0160 
0161     /*
0162      * DATA_HCTL_EN controls data timing which can be different from
0163      * video timing. It is recommended to enable it for all cases, except
0164      * if compression is enabled in 1 pixel per clock mode
0165      */
0166     if (p->wide_bus_en)
0167         intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
0168 
0169     data_width = p->width;
0170 
0171     hsync_data_start_x = hsync_start_x;
0172     hsync_data_end_x =  hsync_start_x + data_width - 1;
0173 
0174     display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
0175 
0176     if (dp_intf) {
0177         /* DP timing adjustment */
0178         display_v_start += p->hsync_pulse_width + p->h_back_porch;
0179         display_v_end   -= p->h_front_porch;
0180 
0181         active_h_start = hsync_start_x;
0182         active_h_end = active_h_start + p->xres - 1;
0183         active_v_start = display_v_start;
0184         active_v_end = active_v_start + (p->yres * hsync_period) - 1;
0185 
0186         active_hctl = (active_h_end << 16) | active_h_start;
0187         display_hctl = active_hctl;
0188 
0189         intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
0190     }
0191 
0192     den_polarity = 0;
0193     if (ctx->cap->type == INTF_HDMI) {
0194         hsync_polarity = p->yres >= 720 ? 0 : 1;
0195         vsync_polarity = p->yres >= 720 ? 0 : 1;
0196     } else if (ctx->cap->type == INTF_DP) {
0197         hsync_polarity = p->hsync_polarity;
0198         vsync_polarity = p->vsync_polarity;
0199     } else {
0200         hsync_polarity = 0;
0201         vsync_polarity = 0;
0202     }
0203     polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
0204         (vsync_polarity << 1) | /* VSYNC Polarity */
0205         (hsync_polarity << 0);  /* HSYNC Polarity */
0206 
0207     if (!DPU_FORMAT_IS_YUV(fmt))
0208         panel_format = (fmt->bits[C0_G_Y] |
0209                 (fmt->bits[C1_B_Cb] << 2) |
0210                 (fmt->bits[C2_R_Cr] << 4) |
0211                 (0x21 << 8));
0212     else
0213         /* Interface treats all the pixel data in RGB888 format */
0214         panel_format = (COLOR_8BIT |
0215                 (COLOR_8BIT << 2) |
0216                 (COLOR_8BIT << 4) |
0217                 (0x21 << 8));
0218 
0219     DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
0220     DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
0221     DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
0222             p->vsync_pulse_width * hsync_period);
0223     DPU_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl);
0224     DPU_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start);
0225     DPU_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end);
0226     DPU_REG_WRITE(c, INTF_ACTIVE_HCTL,  active_hctl);
0227     DPU_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start);
0228     DPU_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end);
0229     DPU_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr);
0230     DPU_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr);
0231     DPU_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew);
0232     DPU_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl);
0233     DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
0234     DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
0235     DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
0236     if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) {
0237         DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
0238         DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
0239         DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
0240     }
0241 }
0242 
0243 static void dpu_hw_intf_enable_timing_engine(
0244         struct dpu_hw_intf *intf,
0245         u8 enable)
0246 {
0247     struct dpu_hw_blk_reg_map *c = &intf->hw;
0248     /* Note: Display interface select is handled in top block hw layer */
0249     DPU_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0);
0250 }
0251 
0252 static void dpu_hw_intf_setup_prg_fetch(
0253         struct dpu_hw_intf *intf,
0254         const struct intf_prog_fetch *fetch)
0255 {
0256     struct dpu_hw_blk_reg_map *c = &intf->hw;
0257     int fetch_enable;
0258 
0259     /*
0260      * Fetch should always be outside the active lines. If the fetching
0261      * is programmed within active region, hardware behavior is unknown.
0262      */
0263 
0264     fetch_enable = DPU_REG_READ(c, INTF_CONFIG);
0265     if (fetch->enable) {
0266         fetch_enable |= BIT(31);
0267         DPU_REG_WRITE(c, INTF_PROG_FETCH_START,
0268                 fetch->fetch_start);
0269     } else {
0270         fetch_enable &= ~BIT(31);
0271     }
0272 
0273     DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable);
0274 }
0275 
0276 static void dpu_hw_intf_bind_pingpong_blk(
0277         struct dpu_hw_intf *intf,
0278         bool enable,
0279         const enum dpu_pingpong pp)
0280 {
0281     struct dpu_hw_blk_reg_map *c = &intf->hw;
0282     u32 mux_cfg;
0283 
0284     mux_cfg = DPU_REG_READ(c, INTF_MUX);
0285     mux_cfg &= ~0xf;
0286 
0287     if (enable)
0288         mux_cfg |= (pp - PINGPONG_0) & 0x7;
0289     else
0290         mux_cfg |= 0xf;
0291 
0292     DPU_REG_WRITE(c, INTF_MUX, mux_cfg);
0293 }
0294 
0295 static void dpu_hw_intf_get_status(
0296         struct dpu_hw_intf *intf,
0297         struct intf_status *s)
0298 {
0299     struct dpu_hw_blk_reg_map *c = &intf->hw;
0300 
0301     s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
0302     s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
0303     if (s->is_en) {
0304         s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
0305         s->line_count = DPU_REG_READ(c, INTF_LINE_COUNT);
0306     } else {
0307         s->line_count = 0;
0308         s->frame_count = 0;
0309     }
0310 }
0311 
0312 static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
0313 {
0314     struct dpu_hw_blk_reg_map *c;
0315 
0316     if (!intf)
0317         return 0;
0318 
0319     c = &intf->hw;
0320 
0321     return DPU_REG_READ(c, INTF_LINE_COUNT);
0322 }
0323 
0324 static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf, bool enable, u32 frame_count)
0325 {
0326     dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, enable, frame_count);
0327 }
0328 
0329 static int dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf, u32 *misr_value)
0330 {
0331     return dpu_hw_collect_misr(&intf->hw, INTF_MISR_CTRL, INTF_MISR_SIGNATURE, misr_value);
0332 }
0333 
0334 static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
0335         unsigned long cap)
0336 {
0337     ops->setup_timing_gen = dpu_hw_intf_setup_timing_engine;
0338     ops->setup_prg_fetch  = dpu_hw_intf_setup_prg_fetch;
0339     ops->get_status = dpu_hw_intf_get_status;
0340     ops->enable_timing = dpu_hw_intf_enable_timing_engine;
0341     ops->get_line_count = dpu_hw_intf_get_line_count;
0342     if (cap & BIT(DPU_INTF_INPUT_CTRL))
0343         ops->bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
0344     ops->setup_misr = dpu_hw_intf_setup_misr;
0345     ops->collect_misr = dpu_hw_intf_collect_misr;
0346 }
0347 
0348 struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
0349         void __iomem *addr,
0350         const struct dpu_mdss_cfg *m)
0351 {
0352     struct dpu_hw_intf *c;
0353     const struct dpu_intf_cfg *cfg;
0354 
0355     c = kzalloc(sizeof(*c), GFP_KERNEL);
0356     if (!c)
0357         return ERR_PTR(-ENOMEM);
0358 
0359     cfg = _intf_offset(idx, m, addr, &c->hw);
0360     if (IS_ERR_OR_NULL(cfg)) {
0361         kfree(c);
0362         pr_err("failed to create dpu_hw_intf %d\n", idx);
0363         return ERR_PTR(-EINVAL);
0364     }
0365 
0366     /*
0367      * Assign ops
0368      */
0369     c->idx = idx;
0370     c->cap = cfg;
0371     c->mdss = m;
0372     _setup_intf_ops(&c->ops, c->cap->features);
0373 
0374     return c;
0375 }
0376 
0377 void dpu_hw_intf_destroy(struct dpu_hw_intf *intf)
0378 {
0379     kfree(intf);
0380 }
0381