0001
0002
0003
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
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);
0102 if (!fmt->alpha_enable ||
0103 !(ctx->caps->features & BIT(DPU_WB_PIPE_ALPHA)))
0104 dst_format |= BIT(14);
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
0166
0167
0168
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
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 }