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   */
0005 
0006 #include "dpu_hw_mdss.h"
0007 #include "dpu_hwio.h"
0008 #include "dpu_hw_catalog.h"
0009 #include "dpu_hw_wb.h"
0010 #include "dpu_formats.h"
0011 #include "dpu_kms.h"
0012 
0013 #define WB_DST_FORMAT                         0x000
0014 #define WB_DST_OP_MODE                        0x004
0015 #define WB_DST_PACK_PATTERN                   0x008
0016 #define WB_DST0_ADDR                          0x00C
0017 #define WB_DST1_ADDR                          0x010
0018 #define WB_DST2_ADDR                          0x014
0019 #define WB_DST3_ADDR                          0x018
0020 #define WB_DST_YSTRIDE0                       0x01C
0021 #define WB_DST_YSTRIDE1                       0x020
0022 #define WB_DST_YSTRIDE1                       0x020
0023 #define WB_DST_DITHER_BITDEPTH                0x024
0024 #define WB_DST_MATRIX_ROW0                    0x030
0025 #define WB_DST_MATRIX_ROW1                    0x034
0026 #define WB_DST_MATRIX_ROW2                    0x038
0027 #define WB_DST_MATRIX_ROW3                    0x03C
0028 #define WB_DST_WRITE_CONFIG                   0x048
0029 #define WB_ROTATION_DNSCALER                  0x050
0030 #define WB_ROTATOR_PIPE_DOWNSCALER            0x054
0031 #define WB_N16_INIT_PHASE_X_C03               0x060
0032 #define WB_N16_INIT_PHASE_X_C12               0x064
0033 #define WB_N16_INIT_PHASE_Y_C03               0x068
0034 #define WB_N16_INIT_PHASE_Y_C12               0x06C
0035 #define WB_OUT_SIZE                           0x074
0036 #define WB_ALPHA_X_VALUE                      0x078
0037 #define WB_DANGER_LUT                         0x084
0038 #define WB_SAFE_LUT                           0x088
0039 #define WB_QOS_CTRL                           0x090
0040 #define WB_CREQ_LUT_0                         0x098
0041 #define WB_CREQ_LUT_1                         0x09C
0042 #define WB_UBWC_STATIC_CTRL                   0x144
0043 #define WB_MUX                                0x150
0044 #define WB_CROP_CTRL                          0x154
0045 #define WB_CROP_OFFSET                        0x158
0046 #define WB_CSC_BASE                           0x260
0047 #define WB_DST_ADDR_SW_STATUS                 0x2B0
0048 #define WB_CDP_CNTL                           0x2B4
0049 #define WB_OUT_IMAGE_SIZE                     0x2C0
0050 #define WB_OUT_XY                             0x2C4
0051 
0052 /* WB_QOS_CTRL */
0053 #define WB_QOS_CTRL_DANGER_SAFE_EN            BIT(0)
0054 
0055 static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
0056         const struct dpu_mdss_cfg *m, void __iomem *addr,
0057         struct dpu_hw_blk_reg_map *b)
0058 {
0059     int i;
0060 
0061     for (i = 0; i < m->wb_count; i++) {
0062         if (wb == m->wb[i].id) {
0063             b->blk_addr = addr + m->wb[i].base;
0064             return &m->wb[i];
0065         }
0066     }
0067     return ERR_PTR(-EINVAL);
0068 }
0069 
0070 static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx,
0071         struct dpu_hw_wb_cfg *data)
0072 {
0073     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0074 
0075     DPU_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]);
0076     DPU_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]);
0077     DPU_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]);
0078     DPU_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]);
0079 }
0080 
0081 static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx,
0082         struct dpu_hw_wb_cfg *data)
0083 {
0084     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0085     const struct dpu_format *fmt = data->dest.format;
0086     u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
0087     u32 write_config = 0;
0088     u32 opmode = 0;
0089     u32 dst_addr_sw = 0;
0090 
0091     chroma_samp = fmt->chroma_sample;
0092 
0093     dst_format = (chroma_samp << 23) |
0094         (fmt->fetch_planes << 19) |
0095         (fmt->bits[C3_ALPHA] << 6) |
0096         (fmt->bits[C2_R_Cr] << 4) |
0097         (fmt->bits[C1_B_Cb] << 2) |
0098         (fmt->bits[C0_G_Y] << 0);
0099 
0100     if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
0101         dst_format |= BIT(8); /* DSTC3_EN */
0102         if (!fmt->alpha_enable ||
0103             !(ctx->caps->features & BIT(DPU_WB_PIPE_ALPHA)))
0104             dst_format |= BIT(14); /* DST_ALPHA_X */
0105     }
0106 
0107     pattern = (fmt->element[3] << 24) |
0108         (fmt->element[2] << 16) |
0109         (fmt->element[1] << 8)  |
0110         (fmt->element[0] << 0);
0111 
0112     dst_format |= (fmt->unpack_align_msb << 18) |
0113         (fmt->unpack_tight << 17) |
0114         ((fmt->unpack_count - 1) << 12) |
0115         ((fmt->bpp - 1) << 9);
0116 
0117     ystride0 = data->dest.plane_pitch[0] |
0118         (data->dest.plane_pitch[1] << 16);
0119     ystride1 = data->dest.plane_pitch[2] |
0120     (data->dest.plane_pitch[3] << 16);
0121 
0122     if (drm_rect_height(&data->roi) && drm_rect_width(&data->roi))
0123         outsize = (drm_rect_height(&data->roi) << 16) | drm_rect_width(&data->roi);
0124     else
0125         outsize = (data->dest.height << 16) | data->dest.width;
0126 
0127     DPU_REG_WRITE(c, WB_ALPHA_X_VALUE, 0xFF);
0128     DPU_REG_WRITE(c, WB_DST_FORMAT, dst_format);
0129     DPU_REG_WRITE(c, WB_DST_OP_MODE, opmode);
0130     DPU_REG_WRITE(c, WB_DST_PACK_PATTERN, pattern);
0131     DPU_REG_WRITE(c, WB_DST_YSTRIDE0, ystride0);
0132     DPU_REG_WRITE(c, WB_DST_YSTRIDE1, ystride1);
0133     DPU_REG_WRITE(c, WB_OUT_SIZE, outsize);
0134     DPU_REG_WRITE(c, WB_DST_WRITE_CONFIG, write_config);
0135     DPU_REG_WRITE(c, WB_DST_ADDR_SW_STATUS, dst_addr_sw);
0136 }
0137 
0138 static void dpu_hw_wb_roi(struct dpu_hw_wb *ctx, struct dpu_hw_wb_cfg *wb)
0139 {
0140     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0141     u32 image_size, out_size, out_xy;
0142 
0143     image_size = (wb->dest.height << 16) | wb->dest.width;
0144     out_xy = 0;
0145     out_size = (drm_rect_height(&wb->roi) << 16) | drm_rect_width(&wb->roi);
0146 
0147     DPU_REG_WRITE(c, WB_OUT_IMAGE_SIZE, image_size);
0148     DPU_REG_WRITE(c, WB_OUT_XY, out_xy);
0149     DPU_REG_WRITE(c, WB_OUT_SIZE, out_size);
0150 }
0151 
0152 static void dpu_hw_wb_setup_qos_lut(struct dpu_hw_wb *ctx,
0153         struct dpu_hw_wb_qos_cfg *cfg)
0154 {
0155     struct dpu_hw_blk_reg_map *c = &ctx->hw;
0156     u32 qos_ctrl = 0;
0157 
0158     if (!ctx || !cfg)
0159         return;
0160 
0161     DPU_REG_WRITE(c, WB_DANGER_LUT, cfg->danger_lut);
0162     DPU_REG_WRITE(c, WB_SAFE_LUT, cfg->safe_lut);
0163 
0164     /*
0165      * for chipsets not using DPU_WB_QOS_8LVL but still using DPU
0166      * driver such as msm8998, the reset value of WB_CREQ_LUT is
0167      * sufficient for writeback to work. SW doesn't need to explicitly
0168      * program a value.
0169      */
0170     if (ctx->caps && test_bit(DPU_WB_QOS_8LVL, &ctx->caps->features)) {
0171         DPU_REG_WRITE(c, WB_CREQ_LUT_0, cfg->creq_lut);
0172         DPU_REG_WRITE(c, WB_CREQ_LUT_1, cfg->creq_lut >> 32);
0173     }
0174 
0175     if (cfg->danger_safe_en)
0176         qos_ctrl |= WB_QOS_CTRL_DANGER_SAFE_EN;
0177 
0178     DPU_REG_WRITE(c, WB_QOS_CTRL, qos_ctrl);
0179 }
0180 
0181 static void dpu_hw_wb_setup_cdp(struct dpu_hw_wb *ctx,
0182         struct dpu_hw_cdp_cfg *cfg)
0183 {
0184     struct dpu_hw_blk_reg_map *c;
0185     u32 cdp_cntl = 0;
0186 
0187     if (!ctx || !cfg)
0188         return;
0189 
0190     c = &ctx->hw;
0191 
0192     if (cfg->enable)
0193         cdp_cntl |= BIT(0);
0194     if (cfg->ubwc_meta_enable)
0195         cdp_cntl |= BIT(1);
0196     if (cfg->preload_ahead == DPU_WB_CDP_PRELOAD_AHEAD_64)
0197         cdp_cntl |= BIT(3);
0198 
0199     DPU_REG_WRITE(c, WB_CDP_CNTL, cdp_cntl);
0200 }
0201 
0202 static void dpu_hw_wb_bind_pingpong_blk(
0203         struct dpu_hw_wb *ctx,
0204         bool enable, const enum dpu_pingpong pp)
0205 {
0206     struct dpu_hw_blk_reg_map *c;
0207     int mux_cfg;
0208 
0209     if (!ctx)
0210         return;
0211 
0212     c = &ctx->hw;
0213 
0214     mux_cfg = DPU_REG_READ(c, WB_MUX);
0215     mux_cfg &= ~0xf;
0216 
0217     if (enable)
0218         mux_cfg |= (pp - PINGPONG_0) & 0x7;
0219     else
0220         mux_cfg |= 0xf;
0221 
0222     DPU_REG_WRITE(c, WB_MUX, mux_cfg);
0223 }
0224 
0225 static void _setup_wb_ops(struct dpu_hw_wb_ops *ops,
0226         unsigned long features)
0227 {
0228     ops->setup_outaddress = dpu_hw_wb_setup_outaddress;
0229     ops->setup_outformat = dpu_hw_wb_setup_format;
0230 
0231     if (test_bit(DPU_WB_XY_ROI_OFFSET, &features))
0232         ops->setup_roi = dpu_hw_wb_roi;
0233 
0234     if (test_bit(DPU_WB_QOS, &features))
0235         ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut;
0236 
0237     if (test_bit(DPU_WB_CDP, &features))
0238         ops->setup_cdp = dpu_hw_wb_setup_cdp;
0239 
0240     if (test_bit(DPU_WB_INPUT_CTRL, &features))
0241         ops->bind_pingpong_blk = dpu_hw_wb_bind_pingpong_blk;
0242 }
0243 
0244 struct dpu_hw_wb *dpu_hw_wb_init(enum dpu_wb idx,
0245         void __iomem *addr, const struct dpu_mdss_cfg *m)
0246 {
0247     struct dpu_hw_wb *c;
0248     const struct dpu_wb_cfg *cfg;
0249 
0250     if (!addr || !m)
0251         return ERR_PTR(-EINVAL);
0252 
0253     c = kzalloc(sizeof(*c), GFP_KERNEL);
0254     if (!c)
0255         return ERR_PTR(-ENOMEM);
0256 
0257     cfg = _wb_offset(idx, m, addr, &c->hw);
0258     if (IS_ERR(cfg)) {
0259         WARN(1, "Unable to find wb idx=%d\n", idx);
0260         kfree(c);
0261         return ERR_PTR(-EINVAL);
0262     }
0263 
0264     /* Assign ops */
0265     c->mdp = &m->mdp[0];
0266     c->idx = idx;
0267     c->caps = cfg;
0268     _setup_wb_ops(&c->ops, c->caps->features);
0269 
0270     return c;
0271 }
0272 
0273 void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb)
0274 {
0275     kfree(hw_wb);
0276 }