1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved
4 */
5
6 #include <drm/drm_managed.h>
7
8 #include "dpu_hw_mdss.h"
9 #include "dpu_hwio.h"
10 #include "dpu_hw_catalog.h"
11 #include "dpu_hw_wb.h"
12 #include "dpu_formats.h"
13 #include "dpu_kms.h"
14
15 #define WB_DST_FORMAT 0x000
16 #define WB_DST_OP_MODE 0x004
17 #define WB_DST_PACK_PATTERN 0x008
18 #define WB_DST0_ADDR 0x00C
19 #define WB_DST1_ADDR 0x010
20 #define WB_DST2_ADDR 0x014
21 #define WB_DST3_ADDR 0x018
22 #define WB_DST_YSTRIDE0 0x01C
23 #define WB_DST_YSTRIDE1 0x020
24 #define WB_DST_YSTRIDE1 0x020
25 #define WB_DST_DITHER_BITDEPTH 0x024
26 #define WB_DST_MATRIX_ROW0 0x030
27 #define WB_DST_MATRIX_ROW1 0x034
28 #define WB_DST_MATRIX_ROW2 0x038
29 #define WB_DST_MATRIX_ROW3 0x03C
30 #define WB_DST_WRITE_CONFIG 0x048
31 #define WB_ROTATION_DNSCALER 0x050
32 #define WB_ROTATOR_PIPE_DOWNSCALER 0x054
33 #define WB_N16_INIT_PHASE_X_C03 0x060
34 #define WB_N16_INIT_PHASE_X_C12 0x064
35 #define WB_N16_INIT_PHASE_Y_C03 0x068
36 #define WB_N16_INIT_PHASE_Y_C12 0x06C
37 #define WB_OUT_SIZE 0x074
38 #define WB_ALPHA_X_VALUE 0x078
39 #define WB_DANGER_LUT 0x084
40 #define WB_SAFE_LUT 0x088
41 #define WB_QOS_CTRL 0x090
42 #define WB_CREQ_LUT_0 0x098
43 #define WB_CREQ_LUT_1 0x09C
44 #define WB_UBWC_STATIC_CTRL 0x144
45 #define WB_MUX 0x150
46 #define WB_CROP_CTRL 0x154
47 #define WB_CROP_OFFSET 0x158
48 #define WB_CLK_CTRL 0x178
49 #define WB_CSC_BASE 0x260
50 #define WB_DST_ADDR_SW_STATUS 0x2B0
51 #define WB_CDP_CNTL 0x2B4
52 #define WB_OUT_IMAGE_SIZE 0x2C0
53 #define WB_OUT_XY 0x2C4
54
dpu_hw_wb_setup_outaddress(struct dpu_hw_wb * ctx,struct dpu_hw_wb_cfg * data)55 static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx,
56 struct dpu_hw_wb_cfg *data)
57 {
58 struct dpu_hw_blk_reg_map *c = &ctx->hw;
59
60 DPU_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]);
61 DPU_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]);
62 DPU_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]);
63 DPU_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]);
64 }
65
dpu_hw_wb_setup_format(struct dpu_hw_wb * ctx,struct dpu_hw_wb_cfg * data,const struct msm_format * fmt)66 static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx,
67 struct dpu_hw_wb_cfg *data,
68 const struct msm_format *fmt)
69 {
70 struct dpu_hw_blk_reg_map *c = &ctx->hw;
71 u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
72 u32 write_config = 0;
73 u32 opmode = 0;
74 u32 dst_addr_sw = 0;
75
76 chroma_samp = fmt->chroma_sample;
77
78 dst_format = (chroma_samp << 23) |
79 (fmt->fetch_type << 19) |
80 (fmt->bpc_a << 6) |
81 (fmt->bpc_r_cr << 4) |
82 (fmt->bpc_b_cb << 2) |
83 (fmt->bpc_g_y << 0);
84
85 if (fmt->bpc_a || fmt->alpha_enable) {
86 dst_format |= BIT(8); /* DSTC3_EN */
87 if (!fmt->alpha_enable ||
88 !(ctx->caps->features & BIT(DPU_WB_PIPE_ALPHA)))
89 dst_format |= BIT(14); /* DST_ALPHA_X */
90 }
91
92 if (MSM_FORMAT_IS_YUV(fmt))
93 dst_format |= BIT(15);
94
95 pattern = (fmt->element[3] << 24) |
96 (fmt->element[2] << 16) |
97 (fmt->element[1] << 8) |
98 (fmt->element[0] << 0);
99
100 dst_format |= ((fmt->flags & MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB ? 1 : 0) << 18) |
101 ((fmt->flags & MSM_FORMAT_FLAG_UNPACK_TIGHT ? 1 : 0) << 17) |
102 ((fmt->unpack_count - 1) << 12) |
103 ((fmt->bpp - 1) << 9);
104
105 ystride0 = data->dest.plane_pitch[0] |
106 (data->dest.plane_pitch[1] << 16);
107 ystride1 = data->dest.plane_pitch[2] |
108 (data->dest.plane_pitch[3] << 16);
109
110 if (drm_rect_height(&data->roi) && drm_rect_width(&data->roi))
111 outsize = (drm_rect_height(&data->roi) << 16) | drm_rect_width(&data->roi);
112 else
113 outsize = (data->dest.height << 16) | data->dest.width;
114
115 DPU_REG_WRITE(c, WB_ALPHA_X_VALUE, 0xFF);
116 DPU_REG_WRITE(c, WB_DST_FORMAT, dst_format);
117 DPU_REG_WRITE(c, WB_DST_OP_MODE, opmode);
118 DPU_REG_WRITE(c, WB_DST_PACK_PATTERN, pattern);
119 DPU_REG_WRITE(c, WB_DST_YSTRIDE0, ystride0);
120 DPU_REG_WRITE(c, WB_DST_YSTRIDE1, ystride1);
121 DPU_REG_WRITE(c, WB_OUT_SIZE, outsize);
122 DPU_REG_WRITE(c, WB_DST_WRITE_CONFIG, write_config);
123 DPU_REG_WRITE(c, WB_DST_ADDR_SW_STATUS, dst_addr_sw);
124 }
125
dpu_hw_wb_roi(struct dpu_hw_wb * ctx,struct dpu_hw_wb_cfg * wb)126 static void dpu_hw_wb_roi(struct dpu_hw_wb *ctx, struct dpu_hw_wb_cfg *wb)
127 {
128 struct dpu_hw_blk_reg_map *c = &ctx->hw;
129 u32 image_size, out_size, out_xy;
130
131 image_size = (wb->dest.height << 16) | wb->dest.width;
132 out_xy = 0;
133 out_size = (drm_rect_height(&wb->roi) << 16) | drm_rect_width(&wb->roi);
134
135 DPU_REG_WRITE(c, WB_OUT_IMAGE_SIZE, image_size);
136 DPU_REG_WRITE(c, WB_OUT_XY, out_xy);
137 DPU_REG_WRITE(c, WB_OUT_SIZE, out_size);
138 }
139
dpu_hw_wb_setup_qos_lut(struct dpu_hw_wb * ctx,struct dpu_hw_qos_cfg * cfg)140 static void dpu_hw_wb_setup_qos_lut(struct dpu_hw_wb *ctx,
141 struct dpu_hw_qos_cfg *cfg)
142 {
143 if (!ctx || !cfg)
144 return;
145
146 _dpu_hw_setup_qos_lut(&ctx->hw, WB_DANGER_LUT,
147 test_bit(DPU_WB_QOS_8LVL, &ctx->caps->features),
148 cfg);
149 }
150
dpu_hw_wb_setup_cdp(struct dpu_hw_wb * ctx,const struct msm_format * fmt,bool enable)151 static void dpu_hw_wb_setup_cdp(struct dpu_hw_wb *ctx,
152 const struct msm_format *fmt,
153 bool enable)
154 {
155 if (!ctx)
156 return;
157
158 dpu_setup_cdp(&ctx->hw, WB_CDP_CNTL, fmt, enable);
159 }
160
dpu_hw_wb_bind_pingpong_blk(struct dpu_hw_wb * ctx,const enum dpu_pingpong pp)161 static void dpu_hw_wb_bind_pingpong_blk(
162 struct dpu_hw_wb *ctx,
163 const enum dpu_pingpong pp)
164 {
165 struct dpu_hw_blk_reg_map *c;
166 int mux_cfg;
167
168 if (!ctx)
169 return;
170
171 c = &ctx->hw;
172
173 mux_cfg = DPU_REG_READ(c, WB_MUX);
174 mux_cfg &= ~0xf;
175
176 if (pp >= PINGPONG_CWB_0)
177 mux_cfg |= (pp < PINGPONG_CWB_2) ? 0xd : 0xb;
178 else if (pp)
179 mux_cfg |= (pp - PINGPONG_0) & 0x7;
180 else
181 mux_cfg |= 0xf;
182
183 DPU_REG_WRITE(c, WB_MUX, mux_cfg);
184 }
185
dpu_hw_wb_setup_clk_force_ctrl(struct dpu_hw_wb * ctx,bool enable)186 static bool dpu_hw_wb_setup_clk_force_ctrl(struct dpu_hw_wb *ctx, bool enable)
187 {
188 static const struct dpu_clk_ctrl_reg wb_clk_ctrl = {
189 .reg_off = WB_CLK_CTRL,
190 .bit_off = 0
191 };
192
193 return dpu_hw_clk_force_ctrl(&ctx->hw, &wb_clk_ctrl, enable);
194 }
195
_setup_wb_ops(struct dpu_hw_wb_ops * ops,unsigned long features,const struct dpu_mdss_version * mdss_rev)196 static void _setup_wb_ops(struct dpu_hw_wb_ops *ops,
197 unsigned long features, const struct dpu_mdss_version *mdss_rev)
198 {
199 ops->setup_outaddress = dpu_hw_wb_setup_outaddress;
200 ops->setup_outformat = dpu_hw_wb_setup_format;
201
202 if (test_bit(DPU_WB_XY_ROI_OFFSET, &features))
203 ops->setup_roi = dpu_hw_wb_roi;
204
205 if (test_bit(DPU_WB_QOS, &features))
206 ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut;
207
208 if (test_bit(DPU_WB_CDP, &features))
209 ops->setup_cdp = dpu_hw_wb_setup_cdp;
210
211 if (test_bit(DPU_WB_INPUT_CTRL, &features))
212 ops->bind_pingpong_blk = dpu_hw_wb_bind_pingpong_blk;
213
214 if (mdss_rev->core_major_ver >= 9)
215 ops->setup_clk_force_ctrl = dpu_hw_wb_setup_clk_force_ctrl;
216 }
217
218 /**
219 * dpu_hw_wb_init() - Initializes the writeback hw driver object.
220 * @dev: Corresponding device for devres management
221 * @cfg: wb_path catalog entry for which driver object is required
222 * @addr: mapped register io address of MDP
223 * @mdss_rev: dpu core's major and minor versions
224 * Return: Error code or allocated dpu_hw_wb context
225 */
dpu_hw_wb_init(struct drm_device * dev,const struct dpu_wb_cfg * cfg,void __iomem * addr,const struct dpu_mdss_version * mdss_rev)226 struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev,
227 const struct dpu_wb_cfg *cfg,
228 void __iomem *addr,
229 const struct dpu_mdss_version *mdss_rev)
230 {
231 struct dpu_hw_wb *c;
232
233 if (!addr)
234 return ERR_PTR(-EINVAL);
235
236 c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
237 if (!c)
238 return ERR_PTR(-ENOMEM);
239
240 c->hw.blk_addr = addr + cfg->base;
241 c->hw.log_mask = DPU_DBG_MASK_WB;
242
243 /* Assign ops */
244 c->idx = cfg->id;
245 c->caps = cfg;
246 _setup_wb_ops(&c->ops, c->caps->features, mdss_rev);
247
248 return c;
249 }
250