1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2024 NXP
4 */
5
6 #include <linux/bitfield.h>
7 #include <linux/bitops.h>
8 #include <linux/bits.h>
9 #include <linux/math.h>
10
11 #include "dc-fu.h"
12 #include "dc-pe.h"
13
14 /* STATICCONTROL */
15 #define SHDLDREQSTICKY_MASK GENMASK(31, 24)
16 #define SHDLDREQSTICKY(x) FIELD_PREP(SHDLDREQSTICKY_MASK, (x))
17 #define BASEADDRESSAUTOUPDATE_MASK GENMASK(23, 16)
18 #define BASEADDRESSAUTOUPDATE(x) FIELD_PREP(BASEADDRESSAUTOUPDATE_MASK, (x))
19
20 /* BURSTBUFFERMANAGEMENT */
21 #define SETBURSTLENGTH_MASK GENMASK(12, 8)
22 #define SETBURSTLENGTH(x) FIELD_PREP(SETBURSTLENGTH_MASK, (x))
23 #define SETNUMBUFFERS_MASK GENMASK(7, 0)
24 #define SETNUMBUFFERS(x) FIELD_PREP(SETNUMBUFFERS_MASK, (x))
25 #define LINEMODE_MASK BIT(31)
26
27 /* SOURCEBUFFERATTRIBUTES */
28 #define BITSPERPIXEL_MASK GENMASK(21, 16)
29 #define BITSPERPIXEL(x) FIELD_PREP(BITSPERPIXEL_MASK, (x))
30 #define STRIDE_MASK GENMASK(15, 0)
31 #define STRIDE(x) FIELD_PREP(STRIDE_MASK, (x) - 1)
32
33 /* SOURCEBUFFERDIMENSION */
34 #define LINEWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x))
35 #define LINECOUNT(x) FIELD_PREP(GENMASK(29, 16), (x))
36
37 /* LAYEROFFSET */
38 #define LAYERXOFFSET(x) FIELD_PREP(GENMASK(14, 0), (x))
39 #define LAYERYOFFSET(x) FIELD_PREP(GENMASK(30, 16), (x))
40
41 /* CLIPWINDOWOFFSET */
42 #define CLIPWINDOWXOFFSET(x) FIELD_PREP(GENMASK(14, 0), (x))
43 #define CLIPWINDOWYOFFSET(x) FIELD_PREP(GENMASK(30, 16), (x))
44
45 /* CLIPWINDOWDIMENSIONS */
46 #define CLIPWINDOWWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x) - 1)
47 #define CLIPWINDOWHEIGHT(x) FIELD_PREP(GENMASK(29, 16), (x) - 1)
48
49 enum dc_linemode {
50 /*
51 * Mandatory setting for operation in the Display Controller.
52 * Works also for Blit Engine with marginal performance impact.
53 */
54 LINEMODE_DISPLAY = 0,
55 };
56
57 struct dc_fu_pixel_format {
58 u32 pixel_format;
59 u32 bits;
60 u32 shifts;
61 };
62
63 static const struct dc_fu_pixel_format pixel_formats[] = {
64 {
65 DRM_FORMAT_XRGB8888,
66 R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
67 R_SHIFT(16) | G_SHIFT(8) | B_SHIFT(0) | A_SHIFT(0),
68 },
69 };
70
dc_fu_get_pixel_format_bits(struct dc_fu * fu,u32 format,u32 * bits)71 void dc_fu_get_pixel_format_bits(struct dc_fu *fu, u32 format, u32 *bits)
72 {
73 int i;
74
75 for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
76 if (pixel_formats[i].pixel_format == format) {
77 *bits = pixel_formats[i].bits;
78 return;
79 }
80 }
81 }
82
83 void
dc_fu_get_pixel_format_shifts(struct dc_fu * fu,u32 format,u32 * shifts)84 dc_fu_get_pixel_format_shifts(struct dc_fu *fu, u32 format, u32 *shifts)
85 {
86 int i;
87
88 for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
89 if (pixel_formats[i].pixel_format == format) {
90 *shifts = pixel_formats[i].shifts;
91 return;
92 }
93 }
94 }
95
dc_fu_enable_shden(struct dc_fu * fu)96 static inline void dc_fu_enable_shden(struct dc_fu *fu)
97 {
98 regmap_write_bits(fu->reg_cfg, STATICCONTROL, SHDEN, SHDEN);
99 }
100
dc_fu_baddr_autoupdate(struct dc_fu * fu,u8 layer_mask)101 static inline void dc_fu_baddr_autoupdate(struct dc_fu *fu, u8 layer_mask)
102 {
103 regmap_write_bits(fu->reg_cfg, STATICCONTROL,
104 BASEADDRESSAUTOUPDATE_MASK,
105 BASEADDRESSAUTOUPDATE(layer_mask));
106 }
107
dc_fu_shdldreq_sticky(struct dc_fu * fu,u8 layer_mask)108 void dc_fu_shdldreq_sticky(struct dc_fu *fu, u8 layer_mask)
109 {
110 regmap_write_bits(fu->reg_cfg, STATICCONTROL, SHDLDREQSTICKY_MASK,
111 SHDLDREQSTICKY(layer_mask));
112 }
113
dc_fu_set_linemode(struct dc_fu * fu,enum dc_linemode mode)114 static inline void dc_fu_set_linemode(struct dc_fu *fu, enum dc_linemode mode)
115 {
116 regmap_write_bits(fu->reg_cfg, BURSTBUFFERMANAGEMENT, LINEMODE_MASK,
117 mode);
118 }
119
dc_fu_set_numbuffers(struct dc_fu * fu,unsigned int num)120 static inline void dc_fu_set_numbuffers(struct dc_fu *fu, unsigned int num)
121 {
122 regmap_write_bits(fu->reg_cfg, BURSTBUFFERMANAGEMENT,
123 SETNUMBUFFERS_MASK, SETNUMBUFFERS(num));
124 }
125
dc_fu_set_burstlength(struct dc_fu * fu,dma_addr_t baddr)126 static void dc_fu_set_burstlength(struct dc_fu *fu, dma_addr_t baddr)
127 {
128 unsigned int burst_size, burst_length;
129
130 burst_size = 1 << __ffs(baddr);
131 burst_size = round_up(burst_size, 8);
132 burst_size = min(burst_size, 128U);
133 burst_length = burst_size / 8;
134
135 regmap_write_bits(fu->reg_cfg, BURSTBUFFERMANAGEMENT,
136 SETBURSTLENGTH_MASK, SETBURSTLENGTH(burst_length));
137 }
138
dc_fu_set_baseaddress(struct dc_fu * fu,enum dc_fu_frac frac,dma_addr_t baddr)139 static void dc_fu_set_baseaddress(struct dc_fu *fu, enum dc_fu_frac frac,
140 dma_addr_t baddr)
141 {
142 regmap_write(fu->reg_cfg, fu->reg_baseaddr[frac], baddr);
143 }
144
dc_fu_set_src_bpp(struct dc_fu * fu,enum dc_fu_frac frac,unsigned int bpp)145 void dc_fu_set_src_bpp(struct dc_fu *fu, enum dc_fu_frac frac, unsigned int bpp)
146 {
147 regmap_write_bits(fu->reg_cfg, fu->reg_sourcebufferattributes[frac],
148 BITSPERPIXEL_MASK, BITSPERPIXEL(bpp));
149 }
150
dc_fu_set_src_stride(struct dc_fu * fu,enum dc_fu_frac frac,unsigned int stride)151 static void dc_fu_set_src_stride(struct dc_fu *fu, enum dc_fu_frac frac,
152 unsigned int stride)
153 {
154 regmap_write_bits(fu->reg_cfg, fu->reg_sourcebufferattributes[frac],
155 STRIDE_MASK, STRIDE(stride));
156 }
157
dc_fu_set_src_buf_dimensions(struct dc_fu * fu,enum dc_fu_frac frac,int w,int h)158 static void dc_fu_set_src_buf_dimensions(struct dc_fu *fu, enum dc_fu_frac frac,
159 int w, int h)
160 {
161 regmap_write(fu->reg_cfg, fu->reg_sourcebufferdimension[frac],
162 LINEWIDTH(w) | LINECOUNT(h));
163 }
164
dc_fu_layeroffset(struct dc_fu * fu,enum dc_fu_frac frac,unsigned int x,unsigned int y)165 static inline void dc_fu_layeroffset(struct dc_fu *fu, enum dc_fu_frac frac,
166 unsigned int x, unsigned int y)
167 {
168 regmap_write(fu->reg_cfg, fu->reg_layeroffset[frac],
169 LAYERXOFFSET(x) | LAYERYOFFSET(y));
170 }
171
dc_fu_clipoffset(struct dc_fu * fu,enum dc_fu_frac frac,unsigned int x,unsigned int y)172 static inline void dc_fu_clipoffset(struct dc_fu *fu, enum dc_fu_frac frac,
173 unsigned int x, unsigned int y)
174 {
175 regmap_write(fu->reg_cfg, fu->reg_clipwindowoffset[frac],
176 CLIPWINDOWXOFFSET(x) | CLIPWINDOWYOFFSET(y));
177 }
178
dc_fu_clipdimensions(struct dc_fu * fu,enum dc_fu_frac frac,unsigned int w,unsigned int h)179 static inline void dc_fu_clipdimensions(struct dc_fu *fu, enum dc_fu_frac frac,
180 unsigned int w, unsigned int h)
181 {
182 regmap_write(fu->reg_cfg, fu->reg_clipwindowdimensions[frac],
183 CLIPWINDOWWIDTH(w) | CLIPWINDOWHEIGHT(h));
184 }
185
186 static inline void
dc_fu_set_pixel_blend_mode(struct dc_fu * fu,enum dc_fu_frac frac)187 dc_fu_set_pixel_blend_mode(struct dc_fu *fu, enum dc_fu_frac frac)
188 {
189 regmap_write(fu->reg_cfg, fu->reg_layerproperty[frac], 0);
190 regmap_write(fu->reg_cfg, fu->reg_constantcolor[frac], 0);
191 }
192
dc_fu_enable_src_buf(struct dc_fu * fu,enum dc_fu_frac frac)193 static void dc_fu_enable_src_buf(struct dc_fu *fu, enum dc_fu_frac frac)
194 {
195 regmap_write_bits(fu->reg_cfg, fu->reg_layerproperty[frac],
196 SOURCEBUFFERENABLE, SOURCEBUFFERENABLE);
197 }
198
dc_fu_disable_src_buf(struct dc_fu * fu,enum dc_fu_frac frac)199 static void dc_fu_disable_src_buf(struct dc_fu *fu, enum dc_fu_frac frac)
200 {
201 regmap_write_bits(fu->reg_cfg, fu->reg_layerproperty[frac],
202 SOURCEBUFFERENABLE, 0);
203
204 if (fu->lb) {
205 dc_lb_pec_clken(fu->lb, CLKEN_DISABLE);
206 dc_lb_mode(fu->lb, LB_NEUTRAL);
207 }
208 }
209
dc_fu_set_layerblend(struct dc_fu * fu,struct dc_lb * lb)210 static void dc_fu_set_layerblend(struct dc_fu *fu, struct dc_lb *lb)
211 {
212 fu->lb = lb;
213 }
214
dc_fu_get_link_id(struct dc_fu * fu)215 static enum dc_link_id dc_fu_get_link_id(struct dc_fu *fu)
216 {
217 return fu->link_id;
218 }
219
dc_fu_get_name(struct dc_fu * fu)220 static const char *dc_fu_get_name(struct dc_fu *fu)
221 {
222 return fu->name;
223 }
224
225 const struct dc_fu_ops dc_fu_common_ops = {
226 .set_burstlength = dc_fu_set_burstlength,
227 .set_baseaddress = dc_fu_set_baseaddress,
228 .set_src_stride = dc_fu_set_src_stride,
229 .set_src_buf_dimensions = dc_fu_set_src_buf_dimensions,
230 .enable_src_buf = dc_fu_enable_src_buf,
231 .disable_src_buf = dc_fu_disable_src_buf,
232 .set_layerblend = dc_fu_set_layerblend,
233 .get_link_id = dc_fu_get_link_id,
234 .get_name = dc_fu_get_name,
235 };
236
dc_fu_get_ops(struct dc_fu * fu)237 const struct dc_fu_ops *dc_fu_get_ops(struct dc_fu *fu)
238 {
239 return &fu->ops;
240 }
241
dc_fu_common_hw_init(struct dc_fu * fu)242 void dc_fu_common_hw_init(struct dc_fu *fu)
243 {
244 enum dc_fu_frac i;
245
246 dc_fu_baddr_autoupdate(fu, 0x0);
247 dc_fu_enable_shden(fu);
248 dc_fu_set_linemode(fu, LINEMODE_DISPLAY);
249 dc_fu_set_numbuffers(fu, 16);
250
251 for (i = DC_FETCHUNIT_FRAC0; i < DC_FETCHUNIT_FRAC_NUM; i++) {
252 dc_fu_layeroffset(fu, i, 0, 0);
253 dc_fu_clipoffset(fu, i, 0, 0);
254 dc_fu_clipdimensions(fu, i, 1, 1);
255 dc_fu_disable_src_buf(fu, i);
256 dc_fu_set_pixel_blend_mode(fu, i);
257 }
258 }
259