1
2
3
4
5
6
7#include <linux/bitfield.h>
8
9#include <drm/drm_print.h>
10#include <drm/drm_fourcc.h>
11
12#include "meson_drv.h"
13#include "meson_registers.h"
14#include "meson_viu.h"
15#include "meson_rdma.h"
16#include "meson_osd_afbcd.h"
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56#define OSD1_AFBCD_RGB32 0x15
57
58static int meson_gxm_afbcd_pixel_fmt(u64 modifier, uint32_t format)
59{
60 switch (format) {
61 case DRM_FORMAT_XBGR8888:
62 case DRM_FORMAT_ABGR8888:
63 return OSD1_AFBCD_RGB32;
64
65 default:
66 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
67 return -EINVAL;
68 }
69}
70
71static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format)
72{
73 if (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
74 return false;
75
76 if (!(modifier & AFBC_FORMAT_MOD_YTR))
77 return false;
78
79 return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0;
80}
81
82static int meson_gxm_afbcd_init(struct meson_drm *priv)
83{
84 return 0;
85}
86
87static int meson_gxm_afbcd_reset(struct meson_drm *priv)
88{
89 writel_relaxed(VIU_SW_RESET_OSD1_AFBCD,
90 priv->io_base + _REG(VIU_SW_RESET));
91 writel_relaxed(0, priv->io_base + _REG(VIU_SW_RESET));
92
93 return 0;
94}
95
96static int meson_gxm_afbcd_enable(struct meson_drm *priv)
97{
98 writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) |
99 OSD1_AFBCD_DEC_ENABLE,
100 priv->io_base + _REG(OSD1_AFBCD_ENABLE));
101
102 return 0;
103}
104
105static int meson_gxm_afbcd_disable(struct meson_drm *priv)
106{
107 writel_bits_relaxed(OSD1_AFBCD_DEC_ENABLE, 0,
108 priv->io_base + _REG(OSD1_AFBCD_ENABLE));
109
110 return 0;
111}
112
113static int meson_gxm_afbcd_setup(struct meson_drm *priv)
114{
115 u32 conv_lbuf_len;
116 u32 mode = FIELD_PREP(OSD1_AFBCD_MIF_URGENT, 3) |
117 FIELD_PREP(OSD1_AFBCD_HOLD_LINE_NUM, 4) |
118 FIELD_PREP(OSD1_AFBCD_RGBA_EXCHAN_CTRL, 0x34) |
119 meson_gxm_afbcd_pixel_fmt(priv->afbcd.modifier,
120 priv->afbcd.format);
121
122 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPARSE)
123 mode |= OSD1_AFBCD_HREG_HALF_BLOCK;
124
125 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
126 mode |= OSD1_AFBCD_HREG_BLOCK_SPLIT;
127
128 writel_relaxed(mode, priv->io_base + _REG(OSD1_AFBCD_MODE));
129
130 writel_relaxed(FIELD_PREP(OSD1_AFBCD_HREG_VSIZE_IN,
131 priv->viu.osd1_width) |
132 FIELD_PREP(OSD1_AFBCD_HREG_HSIZE_IN,
133 priv->viu.osd1_height),
134 priv->io_base + _REG(OSD1_AFBCD_SIZE_IN));
135
136 writel_relaxed(priv->viu.osd1_addr >> 4,
137 priv->io_base + _REG(OSD1_AFBCD_HDR_PTR));
138 writel_relaxed(priv->viu.osd1_addr >> 4,
139 priv->io_base + _REG(OSD1_AFBCD_FRAME_PTR));
140
141 writel_relaxed((0xe4 << 24) | (priv->viu.osd1_addr & 0xffffff),
142 priv->io_base + _REG(OSD1_AFBCD_CHROMA_PTR));
143
144 if (priv->viu.osd1_width <= 128)
145 conv_lbuf_len = 32;
146 else if (priv->viu.osd1_width <= 256)
147 conv_lbuf_len = 64;
148 else if (priv->viu.osd1_width <= 512)
149 conv_lbuf_len = 128;
150 else if (priv->viu.osd1_width <= 1024)
151 conv_lbuf_len = 256;
152 else if (priv->viu.osd1_width <= 2048)
153 conv_lbuf_len = 512;
154 else
155 conv_lbuf_len = 1024;
156
157 writel_relaxed(conv_lbuf_len,
158 priv->io_base + _REG(OSD1_AFBCD_CONV_CTRL));
159
160 writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_H, 0) |
161 FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_H,
162 priv->viu.osd1_width - 1),
163 priv->io_base + _REG(OSD1_AFBCD_PIXEL_HSCOPE));
164
165 writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_V, 0) |
166 FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_V,
167 priv->viu.osd1_height - 1),
168 priv->io_base + _REG(OSD1_AFBCD_PIXEL_VSCOPE));
169
170 return 0;
171}
172
173struct meson_afbcd_ops meson_afbcd_gxm_ops = {
174 .init = meson_gxm_afbcd_init,
175 .reset = meson_gxm_afbcd_reset,
176 .enable = meson_gxm_afbcd_enable,
177 .disable = meson_gxm_afbcd_disable,
178 .setup = meson_gxm_afbcd_setup,
179 .supported_fmt = meson_gxm_afbcd_supported_fmt,
180};
181
182
183
184
185enum {
186 MAFBC_FMT_RGB565 = 0,
187 MAFBC_FMT_RGBA5551,
188 MAFBC_FMT_RGBA1010102,
189 MAFBC_FMT_YUV420_10B,
190 MAFBC_FMT_RGB888,
191 MAFBC_FMT_RGBA8888,
192 MAFBC_FMT_RGBA4444,
193 MAFBC_FMT_R8,
194 MAFBC_FMT_RG88,
195 MAFBC_FMT_YUV420_8B,
196 MAFBC_FMT_YUV422_8B = 11,
197 MAFBC_FMT_YUV422_10B = 14,
198};
199
200static int meson_g12a_afbcd_pixel_fmt(u64 modifier, uint32_t format)
201{
202 switch (format) {
203 case DRM_FORMAT_XRGB8888:
204 case DRM_FORMAT_ARGB8888:
205
206 if (modifier & AFBC_FORMAT_MOD_YTR)
207 return -EINVAL;
208
209 case DRM_FORMAT_XBGR8888:
210 case DRM_FORMAT_ABGR8888:
211 return MAFBC_FMT_RGBA8888;
212 case DRM_FORMAT_RGB888:
213
214 if (modifier & AFBC_FORMAT_MOD_YTR)
215 return -EINVAL;
216 return MAFBC_FMT_RGB888;
217 case DRM_FORMAT_RGB565:
218
219 if (modifier & AFBC_FORMAT_MOD_YTR)
220 return -EINVAL;
221 return MAFBC_FMT_RGB565;
222
223 default:
224 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
225 return -EINVAL;
226 }
227}
228
229static int meson_g12a_afbcd_bpp(uint32_t format)
230{
231 switch (format) {
232 case DRM_FORMAT_XRGB8888:
233 case DRM_FORMAT_ARGB8888:
234 case DRM_FORMAT_XBGR8888:
235 case DRM_FORMAT_ABGR8888:
236 return 32;
237 case DRM_FORMAT_RGB888:
238 return 24;
239 case DRM_FORMAT_RGB565:
240 return 16;
241
242 default:
243 DRM_ERROR("unsupported afbc format[%08x]\n", format);
244 return 0;
245 }
246}
247
248static int meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier, uint32_t format)
249{
250 switch (format) {
251 case DRM_FORMAT_XRGB8888:
252 case DRM_FORMAT_ARGB8888:
253 case DRM_FORMAT_XBGR8888:
254 case DRM_FORMAT_ABGR8888:
255 return OSD_MALI_COLOR_MODE_RGBA8888;
256 case DRM_FORMAT_RGB888:
257 return OSD_MALI_COLOR_MODE_RGB888;
258 case DRM_FORMAT_RGB565:
259 return OSD_MALI_COLOR_MODE_RGB565;
260
261 default:
262 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
263 return -EINVAL;
264 }
265}
266
267static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format)
268{
269 return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0;
270}
271
272static int meson_g12a_afbcd_init(struct meson_drm *priv)
273{
274 int ret;
275
276 ret = meson_rdma_init(priv);
277 if (ret)
278 return ret;
279
280 meson_rdma_setup(priv);
281
282
283 writel_bits_relaxed(MALI_AFBCD_MANUAL_RESET, MALI_AFBCD_MANUAL_RESET,
284 priv->io_base + _REG(MALI_AFBCD_TOP_CTRL));
285
286 return 0;
287}
288
289static int meson_g12a_afbcd_reset(struct meson_drm *priv)
290{
291 meson_rdma_reset(priv);
292
293 meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB |
294 VIU_SW_RESET_G12A_OSD1_AFBCD,
295 VIU_SW_RESET);
296 meson_rdma_writel_sync(priv, 0, VIU_SW_RESET);
297
298 return 0;
299}
300
301static int meson_g12a_afbcd_enable(struct meson_drm *priv)
302{
303 meson_rdma_writel_sync(priv, VPU_MAFBC_IRQ_SURFACES_COMPLETED |
304 VPU_MAFBC_IRQ_CONFIGURATION_SWAPPED |
305 VPU_MAFBC_IRQ_DECODE_ERROR |
306 VPU_MAFBC_IRQ_DETILING_ERROR,
307 VPU_MAFBC_IRQ_MASK);
308
309 meson_rdma_writel_sync(priv, VPU_MAFBC_S0_ENABLE,
310 VPU_MAFBC_SURFACE_CFG);
311
312 meson_rdma_writel_sync(priv, VPU_MAFBC_DIRECT_SWAP,
313 VPU_MAFBC_COMMAND);
314
315
316 meson_rdma_flush(priv);
317
318 return 0;
319}
320
321static int meson_g12a_afbcd_disable(struct meson_drm *priv)
322{
323 writel_bits_relaxed(VPU_MAFBC_S0_ENABLE, 0,
324 priv->io_base + _REG(VPU_MAFBC_SURFACE_CFG));
325
326 return 0;
327}
328
329static int meson_g12a_afbcd_setup(struct meson_drm *priv)
330{
331 u32 format = meson_g12a_afbcd_pixel_fmt(priv->afbcd.modifier,
332 priv->afbcd.format);
333
334 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_YTR)
335 format |= VPU_MAFBC_YUV_TRANSFORM;
336
337 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
338 format |= VPU_MAFBC_BLOCK_SPLIT;
339
340 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_TILED)
341 format |= VPU_MAFBC_TILED_HEADER_EN;
342
343 if ((priv->afbcd.modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
344 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
345 format |= FIELD_PREP(VPU_MAFBC_SUPER_BLOCK_ASPECT, 1);
346
347 meson_rdma_writel_sync(priv, format,
348 VPU_MAFBC_FORMAT_SPECIFIER_S0);
349
350 meson_rdma_writel_sync(priv, priv->viu.osd1_addr,
351 VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0);
352 meson_rdma_writel_sync(priv, 0,
353 VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0);
354
355 meson_rdma_writel_sync(priv, priv->viu.osd1_width,
356 VPU_MAFBC_BUFFER_WIDTH_S0);
357 meson_rdma_writel_sync(priv, ALIGN(priv->viu.osd1_height, 32),
358 VPU_MAFBC_BUFFER_HEIGHT_S0);
359
360 meson_rdma_writel_sync(priv, 0,
361 VPU_MAFBC_BOUNDING_BOX_X_START_S0);
362 meson_rdma_writel_sync(priv, priv->viu.osd1_width - 1,
363 VPU_MAFBC_BOUNDING_BOX_X_END_S0);
364 meson_rdma_writel_sync(priv, 0,
365 VPU_MAFBC_BOUNDING_BOX_Y_START_S0);
366 meson_rdma_writel_sync(priv, priv->viu.osd1_height - 1,
367 VPU_MAFBC_BOUNDING_BOX_Y_END_S0);
368
369 meson_rdma_writel_sync(priv, MESON_G12A_AFBCD_OUT_ADDR,
370 VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0);
371 meson_rdma_writel_sync(priv, 0,
372 VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0);
373
374 meson_rdma_writel_sync(priv, priv->viu.osd1_width *
375 (meson_g12a_afbcd_bpp(priv->afbcd.format) / 8),
376 VPU_MAFBC_OUTPUT_BUF_STRIDE_S0);
377
378 return 0;
379}
380
381struct meson_afbcd_ops meson_afbcd_g12a_ops = {
382 .init = meson_g12a_afbcd_init,
383 .reset = meson_g12a_afbcd_reset,
384 .enable = meson_g12a_afbcd_enable,
385 .disable = meson_g12a_afbcd_disable,
386 .setup = meson_g12a_afbcd_setup,
387 .fmt_to_blk_mode = meson_g12a_afbcd_fmt_to_blk_mode,
388 .supported_fmt = meson_g12a_afbcd_supported_fmt,
389};
390