Skip to content

Commit 84a33d0

Browse files
Abhinav Kumarlumag
authored andcommitted
drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks
Add the dpu_hw_wb abstraction to program registers related to the writeback block. These will be invoked once all the configuration is set and ready to be programmed to the registers. changes in v3: - start using the common struct dpu_hw_cdp_cfg - leave a comment about DPU non-DPU_WB_QOS_8LVL chipsets Signed-off-by: Abhinav Kumar <[email protected]> Reviewed-by: Dmitry Baryshkov <[email protected]> Patchwork: https://patchwork.freedesktop.org/patch/483505/ Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Baryshkov <[email protected]>
1 parent 786de93 commit 84a33d0

File tree

3 files changed

+395
-0
lines changed

3 files changed

+395
-0
lines changed

drivers/gpu/drm/msm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
7474
disp/dpu1/dpu_hw_top.o \
7575
disp/dpu1/dpu_hw_util.o \
7676
disp/dpu1/dpu_hw_vbif.o \
77+
disp/dpu1/dpu_hw_wb.o \
7778
disp/dpu1/dpu_kms.o \
7879
disp/dpu1/dpu_plane.o \
7980
disp/dpu1/dpu_rm.o \
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved
4+
*/
5+
6+
#include "dpu_hw_mdss.h"
7+
#include "dpu_hwio.h"
8+
#include "dpu_hw_catalog.h"
9+
#include "dpu_hw_wb.h"
10+
#include "dpu_formats.h"
11+
#include "dpu_kms.h"
12+
13+
#define WB_DST_FORMAT 0x000
14+
#define WB_DST_OP_MODE 0x004
15+
#define WB_DST_PACK_PATTERN 0x008
16+
#define WB_DST0_ADDR 0x00C
17+
#define WB_DST1_ADDR 0x010
18+
#define WB_DST2_ADDR 0x014
19+
#define WB_DST3_ADDR 0x018
20+
#define WB_DST_YSTRIDE0 0x01C
21+
#define WB_DST_YSTRIDE1 0x020
22+
#define WB_DST_YSTRIDE1 0x020
23+
#define WB_DST_DITHER_BITDEPTH 0x024
24+
#define WB_DST_MATRIX_ROW0 0x030
25+
#define WB_DST_MATRIX_ROW1 0x034
26+
#define WB_DST_MATRIX_ROW2 0x038
27+
#define WB_DST_MATRIX_ROW3 0x03C
28+
#define WB_DST_WRITE_CONFIG 0x048
29+
#define WB_ROTATION_DNSCALER 0x050
30+
#define WB_ROTATOR_PIPE_DOWNSCALER 0x054
31+
#define WB_N16_INIT_PHASE_X_C03 0x060
32+
#define WB_N16_INIT_PHASE_X_C12 0x064
33+
#define WB_N16_INIT_PHASE_Y_C03 0x068
34+
#define WB_N16_INIT_PHASE_Y_C12 0x06C
35+
#define WB_OUT_SIZE 0x074
36+
#define WB_ALPHA_X_VALUE 0x078
37+
#define WB_DANGER_LUT 0x084
38+
#define WB_SAFE_LUT 0x088
39+
#define WB_QOS_CTRL 0x090
40+
#define WB_CREQ_LUT_0 0x098
41+
#define WB_CREQ_LUT_1 0x09C
42+
#define WB_UBWC_STATIC_CTRL 0x144
43+
#define WB_MUX 0x150
44+
#define WB_CROP_CTRL 0x154
45+
#define WB_CROP_OFFSET 0x158
46+
#define WB_CSC_BASE 0x260
47+
#define WB_DST_ADDR_SW_STATUS 0x2B0
48+
#define WB_CDP_CNTL 0x2B4
49+
#define WB_OUT_IMAGE_SIZE 0x2C0
50+
#define WB_OUT_XY 0x2C4
51+
52+
/* WB_QOS_CTRL */
53+
#define WB_QOS_CTRL_DANGER_SAFE_EN BIT(0)
54+
55+
static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
56+
const struct dpu_mdss_cfg *m, void __iomem *addr,
57+
struct dpu_hw_blk_reg_map *b)
58+
{
59+
int i;
60+
61+
for (i = 0; i < m->wb_count; i++) {
62+
if (wb == m->wb[i].id) {
63+
b->base_off = addr;
64+
b->blk_off = m->wb[i].base;
65+
b->length = m->wb[i].len;
66+
b->hwversion = m->hwversion;
67+
return &m->wb[i];
68+
}
69+
}
70+
return ERR_PTR(-EINVAL);
71+
}
72+
73+
static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx,
74+
struct dpu_hw_wb_cfg *data)
75+
{
76+
struct dpu_hw_blk_reg_map *c = &ctx->hw;
77+
78+
DPU_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]);
79+
DPU_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]);
80+
DPU_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]);
81+
DPU_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]);
82+
}
83+
84+
static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx,
85+
struct dpu_hw_wb_cfg *data)
86+
{
87+
struct dpu_hw_blk_reg_map *c = &ctx->hw;
88+
const struct dpu_format *fmt = data->dest.format;
89+
u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
90+
u32 write_config = 0;
91+
u32 opmode = 0;
92+
u32 dst_addr_sw = 0;
93+
94+
chroma_samp = fmt->chroma_sample;
95+
96+
dst_format = (chroma_samp << 23) |
97+
(fmt->fetch_planes << 19) |
98+
(fmt->bits[C3_ALPHA] << 6) |
99+
(fmt->bits[C2_R_Cr] << 4) |
100+
(fmt->bits[C1_B_Cb] << 2) |
101+
(fmt->bits[C0_G_Y] << 0);
102+
103+
if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
104+
dst_format |= BIT(8); /* DSTC3_EN */
105+
if (!fmt->alpha_enable ||
106+
!(ctx->caps->features & BIT(DPU_WB_PIPE_ALPHA)))
107+
dst_format |= BIT(14); /* DST_ALPHA_X */
108+
}
109+
110+
pattern = (fmt->element[3] << 24) |
111+
(fmt->element[2] << 16) |
112+
(fmt->element[1] << 8) |
113+
(fmt->element[0] << 0);
114+
115+
dst_format |= (fmt->unpack_align_msb << 18) |
116+
(fmt->unpack_tight << 17) |
117+
((fmt->unpack_count - 1) << 12) |
118+
((fmt->bpp - 1) << 9);
119+
120+
ystride0 = data->dest.plane_pitch[0] |
121+
(data->dest.plane_pitch[1] << 16);
122+
ystride1 = data->dest.plane_pitch[2] |
123+
(data->dest.plane_pitch[3] << 16);
124+
125+
if (drm_rect_height(&data->roi) && drm_rect_width(&data->roi))
126+
outsize = (drm_rect_height(&data->roi) << 16) | drm_rect_width(&data->roi);
127+
else
128+
outsize = (data->dest.height << 16) | data->dest.width;
129+
130+
DPU_REG_WRITE(c, WB_ALPHA_X_VALUE, 0xFF);
131+
DPU_REG_WRITE(c, WB_DST_FORMAT, dst_format);
132+
DPU_REG_WRITE(c, WB_DST_OP_MODE, opmode);
133+
DPU_REG_WRITE(c, WB_DST_PACK_PATTERN, pattern);
134+
DPU_REG_WRITE(c, WB_DST_YSTRIDE0, ystride0);
135+
DPU_REG_WRITE(c, WB_DST_YSTRIDE1, ystride1);
136+
DPU_REG_WRITE(c, WB_OUT_SIZE, outsize);
137+
DPU_REG_WRITE(c, WB_DST_WRITE_CONFIG, write_config);
138+
DPU_REG_WRITE(c, WB_DST_ADDR_SW_STATUS, dst_addr_sw);
139+
}
140+
141+
static void dpu_hw_wb_roi(struct dpu_hw_wb *ctx, struct dpu_hw_wb_cfg *wb)
142+
{
143+
struct dpu_hw_blk_reg_map *c = &ctx->hw;
144+
u32 image_size, out_size, out_xy;
145+
146+
image_size = (wb->dest.height << 16) | wb->dest.width;
147+
out_xy = 0;
148+
out_size = (drm_rect_height(&wb->roi) << 16) | drm_rect_width(&wb->roi);
149+
150+
DPU_REG_WRITE(c, WB_OUT_IMAGE_SIZE, image_size);
151+
DPU_REG_WRITE(c, WB_OUT_XY, out_xy);
152+
DPU_REG_WRITE(c, WB_OUT_SIZE, out_size);
153+
}
154+
155+
static void dpu_hw_wb_setup_qos_lut(struct dpu_hw_wb *ctx,
156+
struct dpu_hw_wb_qos_cfg *cfg)
157+
{
158+
struct dpu_hw_blk_reg_map *c = &ctx->hw;
159+
u32 qos_ctrl = 0;
160+
161+
if (!ctx || !cfg)
162+
return;
163+
164+
DPU_REG_WRITE(c, WB_DANGER_LUT, cfg->danger_lut);
165+
DPU_REG_WRITE(c, WB_SAFE_LUT, cfg->safe_lut);
166+
167+
/*
168+
* for chipsets not using DPU_WB_QOS_8LVL but still using DPU
169+
* driver such as msm8998, the reset value of WB_CREQ_LUT is
170+
* sufficient for writeback to work. SW doesn't need to explicitly
171+
* program a value.
172+
*/
173+
if (ctx->caps && test_bit(DPU_WB_QOS_8LVL, &ctx->caps->features)) {
174+
DPU_REG_WRITE(c, WB_CREQ_LUT_0, cfg->creq_lut);
175+
DPU_REG_WRITE(c, WB_CREQ_LUT_1, cfg->creq_lut >> 32);
176+
}
177+
178+
if (cfg->danger_safe_en)
179+
qos_ctrl |= WB_QOS_CTRL_DANGER_SAFE_EN;
180+
181+
DPU_REG_WRITE(c, WB_QOS_CTRL, qos_ctrl);
182+
}
183+
184+
static void dpu_hw_wb_setup_cdp(struct dpu_hw_wb *ctx,
185+
struct dpu_hw_cdp_cfg *cfg)
186+
{
187+
struct dpu_hw_blk_reg_map *c;
188+
u32 cdp_cntl = 0;
189+
190+
if (!ctx || !cfg)
191+
return;
192+
193+
c = &ctx->hw;
194+
195+
if (cfg->enable)
196+
cdp_cntl |= BIT(0);
197+
if (cfg->ubwc_meta_enable)
198+
cdp_cntl |= BIT(1);
199+
if (cfg->preload_ahead == DPU_WB_CDP_PRELOAD_AHEAD_64)
200+
cdp_cntl |= BIT(3);
201+
202+
DPU_REG_WRITE(c, WB_CDP_CNTL, cdp_cntl);
203+
}
204+
205+
static void dpu_hw_wb_bind_pingpong_blk(
206+
struct dpu_hw_wb *ctx,
207+
bool enable, const enum dpu_pingpong pp)
208+
{
209+
struct dpu_hw_blk_reg_map *c;
210+
int mux_cfg;
211+
212+
if (!ctx)
213+
return;
214+
215+
c = &ctx->hw;
216+
217+
mux_cfg = DPU_REG_READ(c, WB_MUX);
218+
mux_cfg &= ~0xf;
219+
220+
if (enable)
221+
mux_cfg |= (pp - PINGPONG_0) & 0x7;
222+
else
223+
mux_cfg |= 0xf;
224+
225+
DPU_REG_WRITE(c, WB_MUX, mux_cfg);
226+
}
227+
228+
static void _setup_wb_ops(struct dpu_hw_wb_ops *ops,
229+
unsigned long features)
230+
{
231+
ops->setup_outaddress = dpu_hw_wb_setup_outaddress;
232+
ops->setup_outformat = dpu_hw_wb_setup_format;
233+
234+
if (test_bit(DPU_WB_XY_ROI_OFFSET, &features))
235+
ops->setup_roi = dpu_hw_wb_roi;
236+
237+
if (test_bit(DPU_WB_QOS, &features))
238+
ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut;
239+
240+
if (test_bit(DPU_WB_CDP, &features))
241+
ops->setup_cdp = dpu_hw_wb_setup_cdp;
242+
243+
if (test_bit(DPU_WB_INPUT_CTRL, &features))
244+
ops->bind_pingpong_blk = dpu_hw_wb_bind_pingpong_blk;
245+
}
246+
247+
struct dpu_hw_wb *dpu_hw_wb_init(enum dpu_wb idx,
248+
void __iomem *addr, const struct dpu_mdss_cfg *m)
249+
{
250+
struct dpu_hw_wb *c;
251+
const struct dpu_wb_cfg *cfg;
252+
253+
if (!addr || !m)
254+
return ERR_PTR(-EINVAL);
255+
256+
c = kzalloc(sizeof(*c), GFP_KERNEL);
257+
if (!c)
258+
return ERR_PTR(-ENOMEM);
259+
260+
cfg = _wb_offset(idx, m, addr, &c->hw);
261+
if (IS_ERR(cfg)) {
262+
WARN(1, "Unable to find wb idx=%d\n", idx);
263+
kfree(c);
264+
return ERR_PTR(-EINVAL);
265+
}
266+
267+
/* Assign ops */
268+
c->mdp = &m->mdp[0];
269+
c->idx = idx;
270+
c->caps = cfg;
271+
_setup_wb_ops(&c->ops, c->caps->features);
272+
273+
return c;
274+
}
275+
276+
void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb)
277+
{
278+
kfree(hw_wb);
279+
}

0 commit comments

Comments
 (0)