xref: /linux/drivers/gpu/drm/meson/meson_osd_afbcd.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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 
meson_gxm_afbcd_pixel_fmt(u64 modifier,uint32_t format)58 static 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 
meson_gxm_afbcd_supported_fmt(u64 modifier,uint32_t format)71 static 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 
meson_gxm_afbcd_reset(struct meson_drm * priv)82 static 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 
meson_gxm_afbcd_init(struct meson_drm * priv)91 static int meson_gxm_afbcd_init(struct meson_drm *priv)
92 {
93 	return 0;
94 }
95 
meson_gxm_afbcd_exit(struct meson_drm * priv)96 static void meson_gxm_afbcd_exit(struct meson_drm *priv)
97 {
98 	meson_gxm_afbcd_reset(priv);
99 }
100 
meson_gxm_afbcd_enable(struct meson_drm * priv)101 static 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 
meson_gxm_afbcd_disable(struct meson_drm * priv)110 static 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 
meson_gxm_afbcd_setup(struct meson_drm * priv)118 static 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(priv->afbcd.modifier,
125 					     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 
178 struct 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 */
191 enum {
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 
meson_g12a_afbcd_pixel_fmt(u64 modifier,uint32_t format)206 static 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 
meson_g12a_afbcd_bpp(uint32_t format)235 static 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 
meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier,uint32_t format)254 static 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 
meson_g12a_afbcd_supported_fmt(u64 modifier,uint32_t format)273 static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format)
274 {
275 	return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0;
276 }
277 
meson_g12a_afbcd_reset(struct meson_drm * priv)278 static 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, 0, VIU_SW_RESET);
286 
287 	return 0;
288 }
289 
meson_g12a_afbcd_init(struct meson_drm * priv)290 static 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 
meson_g12a_afbcd_exit(struct meson_drm * priv)307 static void meson_g12a_afbcd_exit(struct meson_drm *priv)
308 {
309 	meson_g12a_afbcd_reset(priv);
310 	meson_rdma_free(priv);
311 }
312 
meson_g12a_afbcd_enable(struct meson_drm * priv)313 static 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 
meson_g12a_afbcd_disable(struct meson_drm * priv)333 static 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 
meson_g12a_afbcd_setup(struct meson_drm * priv)341 static int meson_g12a_afbcd_setup(struct meson_drm *priv)
342 {
343 	u32 format = meson_g12a_afbcd_pixel_fmt(priv->afbcd.modifier,
344 						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, format,
360 			       VPU_MAFBC_FORMAT_SPECIFIER_S0);
361 
362 	meson_rdma_writel_sync(priv, priv->viu.osd1_addr,
363 			       VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0);
364 	meson_rdma_writel_sync(priv, 0,
365 			       VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0);
366 
367 	meson_rdma_writel_sync(priv, 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, 0,
373 			       VPU_MAFBC_BOUNDING_BOX_X_START_S0);
374 	meson_rdma_writel_sync(priv, priv->viu.osd1_width - 1,
375 			       VPU_MAFBC_BOUNDING_BOX_X_END_S0);
376 	meson_rdma_writel_sync(priv, 0,
377 			       VPU_MAFBC_BOUNDING_BOX_Y_START_S0);
378 	meson_rdma_writel_sync(priv, 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, 0,
384 			       VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0);
385 
386 	meson_rdma_writel_sync(priv, priv->viu.osd1_width *
387 			       (meson_g12a_afbcd_bpp(priv->afbcd.format) / 8),
388 			       VPU_MAFBC_OUTPUT_BUF_STRIDE_S0);
389 
390 	return 0;
391 }
392 
393 struct 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