1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
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 * DOC: Driver for the ARM FrameBuffer Compression Decoders
20 *
21 * The Amlogic GXM and G12A SoC families embeds an AFBC Decoder,
22 * to decode compressed buffers generated by the ARM Mali GPU.
23 *
24 * For the GXM Family, Amlogic designed their own Decoder, named in
25 * the vendor source as "MESON_AFBC", and a single decoder is available
26 * for the 2 OSD planes.
27 * This decoder is compatible with the AFBC 1.0 specifications and the
28 * Mali T820 GPU capabilities.
29 * It supports :
30 * - basic AFBC buffer for RGB32 only, thus YTR feature is mandatory
31 * - SPARSE layout and SPLIT layout
32 * - only 16x16 superblock
33 *
34 * The decoder reads the data from the SDRAM, decodes and sends the
35 * decoded pixel stream to the OSD1 Plane pixel composer.
36 *
37 * For the G12A Family, Amlogic integrated an ARM AFBC Decoder, named
38 * in the vendor source as "MALI_AFBC", and the decoder can decode up
39 * to 4 surfaces, one for each of the 4 available OSDs.
40 * This decoder is compatible with the AFBC 1.2 specifications for the
41 * Mali G31 and G52 GPUs.
42 * Is supports :
43 * - basic AFBC buffer for multiple RGB and YUV pixel formats
44 * - SPARSE layout and SPLIT layout
45 * - 16x16 and 32x8 "wideblk" superblocks
46 * - Tiled header
47 *
48 * The ARM AFBC Decoder independent from the VPU Pixel Pipeline, so
49 * the ARM AFBC Decoder reads the data from the SDRAM then decodes
50 * into a private internal physical address where the OSD1 Plane pixel
51 * composer unpacks the decoded data.
52 */
53
54/* Amlogic AFBC Decoder for GXM Family */
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 /* TOFIX support mode formats */
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_reset(struct meson_drm *priv)
83{
84 writel_relaxed(VIU_SW_RESET_OSD1_AFBCD,
85 priv->io_base + _REG(VIU_SW_RESET));
86 writel_relaxed(0, priv->io_base + _REG(VIU_SW_RESET));
87
88 return 0;
89}
90
91static int meson_gxm_afbcd_init(struct meson_drm *priv)
92{
93 return 0;
94}
95
96static void meson_gxm_afbcd_exit(struct meson_drm *priv)
97{
98 meson_gxm_afbcd_reset(priv);
99}
100
101static int meson_gxm_afbcd_enable(struct meson_drm *priv)
102{
103 writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) |
104 OSD1_AFBCD_DEC_ENABLE,
105 priv->io_base + _REG(OSD1_AFBCD_ENABLE));
106
107 return 0;
108}
109
110static int meson_gxm_afbcd_disable(struct meson_drm *priv)
111{
112 writel_bits_relaxed(OSD1_AFBCD_DEC_ENABLE, 0,
113 priv->io_base + _REG(OSD1_AFBCD_ENABLE));
114
115 return 0;
116}
117
118static int meson_gxm_afbcd_setup(struct meson_drm *priv)
119{
120 u32 conv_lbuf_len;
121 u32 mode = FIELD_PREP(OSD1_AFBCD_MIF_URGENT, 3) |
122 FIELD_PREP(OSD1_AFBCD_HOLD_LINE_NUM, 4) |
123 FIELD_PREP(OSD1_AFBCD_RGBA_EXCHAN_CTRL, 0x34) |
124 meson_gxm_afbcd_pixel_fmt(modifier: priv->afbcd.modifier,
125 format: priv->afbcd.format);
126
127 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPARSE)
128 mode |= OSD1_AFBCD_HREG_HALF_BLOCK;
129
130 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
131 mode |= OSD1_AFBCD_HREG_BLOCK_SPLIT;
132
133 writel_relaxed(mode, priv->io_base + _REG(OSD1_AFBCD_MODE));
134
135 writel_relaxed(FIELD_PREP(OSD1_AFBCD_HREG_VSIZE_IN,
136 priv->viu.osd1_width) |
137 FIELD_PREP(OSD1_AFBCD_HREG_HSIZE_IN,
138 priv->viu.osd1_height),
139 priv->io_base + _REG(OSD1_AFBCD_SIZE_IN));
140
141 writel_relaxed(priv->viu.osd1_addr >> 4,
142 priv->io_base + _REG(OSD1_AFBCD_HDR_PTR));
143 writel_relaxed(priv->viu.osd1_addr >> 4,
144 priv->io_base + _REG(OSD1_AFBCD_FRAME_PTR));
145 /* TOFIX: bits 31:24 are not documented, nor the meaning of 0xe4 */
146 writel_relaxed((0xe4 << 24) | (priv->viu.osd1_addr & 0xffffff),
147 priv->io_base + _REG(OSD1_AFBCD_CHROMA_PTR));
148
149 if (priv->viu.osd1_width <= 128)
150 conv_lbuf_len = 32;
151 else if (priv->viu.osd1_width <= 256)
152 conv_lbuf_len = 64;
153 else if (priv->viu.osd1_width <= 512)
154 conv_lbuf_len = 128;
155 else if (priv->viu.osd1_width <= 1024)
156 conv_lbuf_len = 256;
157 else if (priv->viu.osd1_width <= 2048)
158 conv_lbuf_len = 512;
159 else
160 conv_lbuf_len = 1024;
161
162 writel_relaxed(conv_lbuf_len,
163 priv->io_base + _REG(OSD1_AFBCD_CONV_CTRL));
164
165 writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_H, 0) |
166 FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_H,
167 priv->viu.osd1_width - 1),
168 priv->io_base + _REG(OSD1_AFBCD_PIXEL_HSCOPE));
169
170 writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_V, 0) |
171 FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_V,
172 priv->viu.osd1_height - 1),
173 priv->io_base + _REG(OSD1_AFBCD_PIXEL_VSCOPE));
174
175 return 0;
176}
177
178struct meson_afbcd_ops meson_afbcd_gxm_ops = {
179 .init = meson_gxm_afbcd_init,
180 .exit = meson_gxm_afbcd_exit,
181 .reset = meson_gxm_afbcd_reset,
182 .enable = meson_gxm_afbcd_enable,
183 .disable = meson_gxm_afbcd_disable,
184 .setup = meson_gxm_afbcd_setup,
185 .supported_fmt = meson_gxm_afbcd_supported_fmt,
186};
187
188/* ARM AFBC Decoder for G12A Family */
189
190/* Amlogic G12A Mali AFBC Decoder supported formats */
191enum {
192 MAFBC_FMT_RGB565 = 0,
193 MAFBC_FMT_RGBA5551,
194 MAFBC_FMT_RGBA1010102,
195 MAFBC_FMT_YUV420_10B,
196 MAFBC_FMT_RGB888,
197 MAFBC_FMT_RGBA8888,
198 MAFBC_FMT_RGBA4444,
199 MAFBC_FMT_R8,
200 MAFBC_FMT_RG88,
201 MAFBC_FMT_YUV420_8B,
202 MAFBC_FMT_YUV422_8B = 11,
203 MAFBC_FMT_YUV422_10B = 14,
204};
205
206static int meson_g12a_afbcd_pixel_fmt(u64 modifier, uint32_t format)
207{
208 switch (format) {
209 case DRM_FORMAT_XRGB8888:
210 case DRM_FORMAT_ARGB8888:
211 /* YTR is forbidden for non XBGR formats */
212 if (modifier & AFBC_FORMAT_MOD_YTR)
213 return -EINVAL;
214 fallthrough;
215 case DRM_FORMAT_XBGR8888:
216 case DRM_FORMAT_ABGR8888:
217 return MAFBC_FMT_RGBA8888;
218 case DRM_FORMAT_RGB888:
219 /* YTR is forbidden for non XBGR formats */
220 if (modifier & AFBC_FORMAT_MOD_YTR)
221 return -EINVAL;
222 return MAFBC_FMT_RGB888;
223 case DRM_FORMAT_RGB565:
224 /* YTR is forbidden for non XBGR formats */
225 if (modifier & AFBC_FORMAT_MOD_YTR)
226 return -EINVAL;
227 return MAFBC_FMT_RGB565;
228 /* TOFIX support mode formats */
229 default:
230 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
231 return -EINVAL;
232 }
233}
234
235static int meson_g12a_afbcd_bpp(uint32_t format)
236{
237 switch (format) {
238 case DRM_FORMAT_XRGB8888:
239 case DRM_FORMAT_ARGB8888:
240 case DRM_FORMAT_XBGR8888:
241 case DRM_FORMAT_ABGR8888:
242 return 32;
243 case DRM_FORMAT_RGB888:
244 return 24;
245 case DRM_FORMAT_RGB565:
246 return 16;
247 /* TOFIX support mode formats */
248 default:
249 DRM_ERROR("unsupported afbc format[%08x]\n", format);
250 return 0;
251 }
252}
253
254static int meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier, uint32_t format)
255{
256 switch (format) {
257 case DRM_FORMAT_XRGB8888:
258 case DRM_FORMAT_ARGB8888:
259 case DRM_FORMAT_XBGR8888:
260 case DRM_FORMAT_ABGR8888:
261 return OSD_MALI_COLOR_MODE_RGBA8888;
262 case DRM_FORMAT_RGB888:
263 return OSD_MALI_COLOR_MODE_RGB888;
264 case DRM_FORMAT_RGB565:
265 return OSD_MALI_COLOR_MODE_RGB565;
266 /* TOFIX support mode formats */
267 default:
268 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
269 return -EINVAL;
270 }
271}
272
273static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format)
274{
275 return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0;
276}
277
278static int meson_g12a_afbcd_reset(struct meson_drm *priv)
279{
280 meson_rdma_reset(priv);
281
282 meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB |
283 VIU_SW_RESET_G12A_OSD1_AFBCD,
284 VIU_SW_RESET);
285 meson_rdma_writel_sync(priv, val: 0, VIU_SW_RESET);
286
287 return 0;
288}
289
290static int meson_g12a_afbcd_init(struct meson_drm *priv)
291{
292 int ret;
293
294 ret = meson_rdma_init(priv);
295 if (ret)
296 return ret;
297
298 meson_rdma_setup(priv);
299
300 /* Handle AFBC Decoder reset manually */
301 writel_bits_relaxed(MALI_AFBCD_MANUAL_RESET, MALI_AFBCD_MANUAL_RESET,
302 priv->io_base + _REG(MALI_AFBCD_TOP_CTRL));
303
304 return 0;
305}
306
307static void meson_g12a_afbcd_exit(struct meson_drm *priv)
308{
309 meson_g12a_afbcd_reset(priv);
310 meson_rdma_free(priv);
311}
312
313static int meson_g12a_afbcd_enable(struct meson_drm *priv)
314{
315 meson_rdma_writel_sync(priv, VPU_MAFBC_IRQ_SURFACES_COMPLETED |
316 VPU_MAFBC_IRQ_CONFIGURATION_SWAPPED |
317 VPU_MAFBC_IRQ_DECODE_ERROR |
318 VPU_MAFBC_IRQ_DETILING_ERROR,
319 VPU_MAFBC_IRQ_MASK);
320
321 meson_rdma_writel_sync(priv, VPU_MAFBC_S0_ENABLE,
322 VPU_MAFBC_SURFACE_CFG);
323
324 meson_rdma_writel_sync(priv, VPU_MAFBC_DIRECT_SWAP,
325 VPU_MAFBC_COMMAND);
326
327 /* This will enable the RDMA replaying the register writes on vsync */
328 meson_rdma_flush(priv);
329
330 return 0;
331}
332
333static int meson_g12a_afbcd_disable(struct meson_drm *priv)
334{
335 writel_bits_relaxed(VPU_MAFBC_S0_ENABLE, 0,
336 priv->io_base + _REG(VPU_MAFBC_SURFACE_CFG));
337
338 return 0;
339}
340
341static int meson_g12a_afbcd_setup(struct meson_drm *priv)
342{
343 u32 format = meson_g12a_afbcd_pixel_fmt(modifier: priv->afbcd.modifier,
344 format: priv->afbcd.format);
345
346 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_YTR)
347 format |= VPU_MAFBC_YUV_TRANSFORM;
348
349 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
350 format |= VPU_MAFBC_BLOCK_SPLIT;
351
352 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_TILED)
353 format |= VPU_MAFBC_TILED_HEADER_EN;
354
355 if ((priv->afbcd.modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
356 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
357 format |= FIELD_PREP(VPU_MAFBC_SUPER_BLOCK_ASPECT, 1);
358
359 meson_rdma_writel_sync(priv, val: format,
360 VPU_MAFBC_FORMAT_SPECIFIER_S0);
361
362 meson_rdma_writel_sync(priv, val: priv->viu.osd1_addr,
363 VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0);
364 meson_rdma_writel_sync(priv, val: 0,
365 VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0);
366
367 meson_rdma_writel_sync(priv, val: priv->viu.osd1_width,
368 VPU_MAFBC_BUFFER_WIDTH_S0);
369 meson_rdma_writel_sync(priv, ALIGN(priv->viu.osd1_height, 32),
370 VPU_MAFBC_BUFFER_HEIGHT_S0);
371
372 meson_rdma_writel_sync(priv, val: 0,
373 VPU_MAFBC_BOUNDING_BOX_X_START_S0);
374 meson_rdma_writel_sync(priv, val: priv->viu.osd1_width - 1,
375 VPU_MAFBC_BOUNDING_BOX_X_END_S0);
376 meson_rdma_writel_sync(priv, val: 0,
377 VPU_MAFBC_BOUNDING_BOX_Y_START_S0);
378 meson_rdma_writel_sync(priv, val: priv->viu.osd1_height - 1,
379 VPU_MAFBC_BOUNDING_BOX_Y_END_S0);
380
381 meson_rdma_writel_sync(priv, MESON_G12A_AFBCD_OUT_ADDR,
382 VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0);
383 meson_rdma_writel_sync(priv, val: 0,
384 VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0);
385
386 meson_rdma_writel_sync(priv, val: priv->viu.osd1_width *
387 (meson_g12a_afbcd_bpp(format: priv->afbcd.format) / 8),
388 VPU_MAFBC_OUTPUT_BUF_STRIDE_S0);
389
390 return 0;
391}
392
393struct meson_afbcd_ops meson_afbcd_g12a_ops = {
394 .init = meson_g12a_afbcd_init,
395 .exit = meson_g12a_afbcd_exit,
396 .reset = meson_g12a_afbcd_reset,
397 .enable = meson_g12a_afbcd_enable,
398 .disable = meson_g12a_afbcd_disable,
399 .setup = meson_g12a_afbcd_setup,
400 .fmt_to_blk_mode = meson_g12a_afbcd_fmt_to_blk_mode,
401 .supported_fmt = meson_g12a_afbcd_supported_fmt,
402};
403

source code of linux/drivers/gpu/drm/meson/meson_osd_afbcd.c