1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2019 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
7 #include <linux/bitfield.h>
9 #include <drm/drm_print.h>
10 #include <drm/drm_fourcc.h>
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"
19 * DOC: Driver for the ARM FrameBuffer Compression Decoders
21 * The Amlogic GXM and G12A SoC families embeds an AFBC Decoder,
22 * to decode compressed buffers generated by the ARM Mali GPU.
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.
30 * - basic AFBC buffer for RGB32 only, thus YTR feature is mandatory
31 * - SPARSE layout and SPLIT layout
32 * - only 16x16 superblock
34 * The decoder reads the data from the SDRAM, decodes and sends the
35 * decoded pixel stream to the OSD1 Plane pixel composer.
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.
43 * - basic AFBC buffer for multiple RGB and YUV pixel formats
44 * - SPARSE layout and SPLIT layout
45 * - 16x16 and 32x8 "wideblk" superblocks
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.
54 /* Amlogic AFBC Decoder for GXM Family */
56 #define OSD1_AFBCD_RGB32 0x15
58 static int meson_gxm_afbcd_pixel_fmt(u64 modifier
, uint32_t format
)
61 case DRM_FORMAT_XBGR8888
:
62 case DRM_FORMAT_ABGR8888
:
63 return OSD1_AFBCD_RGB32
;
64 /* TOFIX support mode formats */
66 DRM_DEBUG("unsupported afbc format[%08x]\n", format
);
71 static bool meson_gxm_afbcd_supported_fmt(u64 modifier
, uint32_t format
)
73 if (modifier
& AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
)
76 if (!(modifier
& AFBC_FORMAT_MOD_YTR
))
79 return meson_gxm_afbcd_pixel_fmt(modifier
, format
) >= 0;
82 static int meson_gxm_afbcd_init(struct meson_drm
*priv
)
87 static int meson_gxm_afbcd_reset(struct meson_drm
*priv
)
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
));
96 static int meson_gxm_afbcd_enable(struct meson_drm
*priv
)
98 writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD
, 0x40) |
99 OSD1_AFBCD_DEC_ENABLE
,
100 priv
->io_base
+ _REG(OSD1_AFBCD_ENABLE
));
105 static int meson_gxm_afbcd_disable(struct meson_drm
*priv
)
107 writel_bits_relaxed(OSD1_AFBCD_DEC_ENABLE
, 0,
108 priv
->io_base
+ _REG(OSD1_AFBCD_ENABLE
));
113 static int meson_gxm_afbcd_setup(struct meson_drm
*priv
)
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
,
122 if (priv
->afbcd
.modifier
& AFBC_FORMAT_MOD_SPARSE
)
123 mode
|= OSD1_AFBCD_HREG_HALF_BLOCK
;
125 if (priv
->afbcd
.modifier
& AFBC_FORMAT_MOD_SPLIT
)
126 mode
|= OSD1_AFBCD_HREG_BLOCK_SPLIT
;
128 writel_relaxed(mode
, priv
->io_base
+ _REG(OSD1_AFBCD_MODE
));
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
));
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 /* TOFIX: bits 31:24 are not documented, nor the meaning of 0xe4 */
141 writel_relaxed((0xe4 << 24) | (priv
->viu
.osd1_addr
& 0xffffff),
142 priv
->io_base
+ _REG(OSD1_AFBCD_CHROMA_PTR
));
144 if (priv
->viu
.osd1_width
<= 128)
146 else if (priv
->viu
.osd1_width
<= 256)
148 else if (priv
->viu
.osd1_width
<= 512)
150 else if (priv
->viu
.osd1_width
<= 1024)
152 else if (priv
->viu
.osd1_width
<= 2048)
155 conv_lbuf_len
= 1024;
157 writel_relaxed(conv_lbuf_len
,
158 priv
->io_base
+ _REG(OSD1_AFBCD_CONV_CTRL
));
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
));
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
));
173 struct 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
,
182 /* ARM AFBC Decoder for G12A Family */
184 /* Amlogic G12A Mali AFBC Decoder supported formats */
186 MAFBC_FMT_RGB565
= 0,
188 MAFBC_FMT_RGBA1010102
,
189 MAFBC_FMT_YUV420_10B
,
196 MAFBC_FMT_YUV422_8B
= 11,
197 MAFBC_FMT_YUV422_10B
= 14,
200 static int meson_g12a_afbcd_pixel_fmt(u64 modifier
, uint32_t format
)
203 case DRM_FORMAT_XRGB8888
:
204 case DRM_FORMAT_ARGB8888
:
205 /* YTR is forbidden for non XBGR formats */
206 if (modifier
& AFBC_FORMAT_MOD_YTR
)
209 case DRM_FORMAT_XBGR8888
:
210 case DRM_FORMAT_ABGR8888
:
211 return MAFBC_FMT_RGBA8888
;
212 case DRM_FORMAT_RGB888
:
213 /* YTR is forbidden for non XBGR formats */
214 if (modifier
& AFBC_FORMAT_MOD_YTR
)
216 return MAFBC_FMT_RGB888
;
217 case DRM_FORMAT_RGB565
:
218 /* YTR is forbidden for non XBGR formats */
219 if (modifier
& AFBC_FORMAT_MOD_YTR
)
221 return MAFBC_FMT_RGB565
;
222 /* TOFIX support mode formats */
224 DRM_DEBUG("unsupported afbc format[%08x]\n", format
);
229 static int meson_g12a_afbcd_bpp(uint32_t format
)
232 case DRM_FORMAT_XRGB8888
:
233 case DRM_FORMAT_ARGB8888
:
234 case DRM_FORMAT_XBGR8888
:
235 case DRM_FORMAT_ABGR8888
:
237 case DRM_FORMAT_RGB888
:
239 case DRM_FORMAT_RGB565
:
241 /* TOFIX support mode formats */
243 DRM_ERROR("unsupported afbc format[%08x]\n", format
);
248 static int meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier
, uint32_t 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 /* TOFIX support mode formats */
262 DRM_DEBUG("unsupported afbc format[%08x]\n", format
);
267 static bool meson_g12a_afbcd_supported_fmt(u64 modifier
, uint32_t format
)
269 return meson_g12a_afbcd_pixel_fmt(modifier
, format
) >= 0;
272 static int meson_g12a_afbcd_init(struct meson_drm
*priv
)
276 ret
= meson_rdma_init(priv
);
280 meson_rdma_setup(priv
);
282 /* Handle AFBC Decoder reset manually */
283 writel_bits_relaxed(MALI_AFBCD_MANUAL_RESET
, MALI_AFBCD_MANUAL_RESET
,
284 priv
->io_base
+ _REG(MALI_AFBCD_TOP_CTRL
));
289 static int meson_g12a_afbcd_reset(struct meson_drm
*priv
)
291 meson_rdma_reset(priv
);
293 meson_rdma_writel_sync(priv
, VIU_SW_RESET_G12A_AFBC_ARB
|
294 VIU_SW_RESET_G12A_OSD1_AFBCD
,
296 meson_rdma_writel_sync(priv
, 0, VIU_SW_RESET
);
301 static int meson_g12a_afbcd_enable(struct meson_drm
*priv
)
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
,
309 meson_rdma_writel_sync(priv
, VPU_MAFBC_S0_ENABLE
,
310 VPU_MAFBC_SURFACE_CFG
);
312 meson_rdma_writel_sync(priv
, VPU_MAFBC_DIRECT_SWAP
,
315 /* This will enable the RDMA replaying the register writes on vsync */
316 meson_rdma_flush(priv
);
321 static int meson_g12a_afbcd_disable(struct meson_drm
*priv
)
323 writel_bits_relaxed(VPU_MAFBC_S0_ENABLE
, 0,
324 priv
->io_base
+ _REG(VPU_MAFBC_SURFACE_CFG
));
329 static int meson_g12a_afbcd_setup(struct meson_drm
*priv
)
331 u32 format
= meson_g12a_afbcd_pixel_fmt(priv
->afbcd
.modifier
,
334 if (priv
->afbcd
.modifier
& AFBC_FORMAT_MOD_YTR
)
335 format
|= VPU_MAFBC_YUV_TRANSFORM
;
337 if (priv
->afbcd
.modifier
& AFBC_FORMAT_MOD_SPLIT
)
338 format
|= VPU_MAFBC_BLOCK_SPLIT
;
340 if (priv
->afbcd
.modifier
& AFBC_FORMAT_MOD_TILED
)
341 format
|= VPU_MAFBC_TILED_HEADER_EN
;
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);
347 meson_rdma_writel_sync(priv
, format
,
348 VPU_MAFBC_FORMAT_SPECIFIER_S0
);
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
);
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
);
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
);
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
);
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
);
381 struct 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
,