0001
0002
0003
0004
0005
0006
0007 #include <linux/bitfield.h>
0008
0009 #include <drm/drm_print.h>
0010 #include <drm/drm_fourcc.h>
0011
0012 #include "meson_drv.h"
0013 #include "meson_registers.h"
0014 #include "meson_viu.h"
0015 #include "meson_rdma.h"
0016 #include "meson_osd_afbcd.h"
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 #define OSD1_AFBCD_RGB32 0x15
0057
0058 static int meson_gxm_afbcd_pixel_fmt(u64 modifier, uint32_t format)
0059 {
0060 switch (format) {
0061 case DRM_FORMAT_XBGR8888:
0062 case DRM_FORMAT_ABGR8888:
0063 return OSD1_AFBCD_RGB32;
0064
0065 default:
0066 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
0067 return -EINVAL;
0068 }
0069 }
0070
0071 static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format)
0072 {
0073 if (modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
0074 return false;
0075
0076 if (!(modifier & AFBC_FORMAT_MOD_YTR))
0077 return false;
0078
0079 return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0;
0080 }
0081
0082 static int meson_gxm_afbcd_reset(struct meson_drm *priv)
0083 {
0084 writel_relaxed(VIU_SW_RESET_OSD1_AFBCD,
0085 priv->io_base + _REG(VIU_SW_RESET));
0086 writel_relaxed(0, priv->io_base + _REG(VIU_SW_RESET));
0087
0088 return 0;
0089 }
0090
0091 static int meson_gxm_afbcd_init(struct meson_drm *priv)
0092 {
0093 return 0;
0094 }
0095
0096 static void meson_gxm_afbcd_exit(struct meson_drm *priv)
0097 {
0098 meson_gxm_afbcd_reset(priv);
0099 }
0100
0101 static int meson_gxm_afbcd_enable(struct meson_drm *priv)
0102 {
0103 writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) |
0104 OSD1_AFBCD_DEC_ENABLE,
0105 priv->io_base + _REG(OSD1_AFBCD_ENABLE));
0106
0107 return 0;
0108 }
0109
0110 static int meson_gxm_afbcd_disable(struct meson_drm *priv)
0111 {
0112 writel_bits_relaxed(OSD1_AFBCD_DEC_ENABLE, 0,
0113 priv->io_base + _REG(OSD1_AFBCD_ENABLE));
0114
0115 return 0;
0116 }
0117
0118 static int meson_gxm_afbcd_setup(struct meson_drm *priv)
0119 {
0120 u32 conv_lbuf_len;
0121 u32 mode = FIELD_PREP(OSD1_AFBCD_MIF_URGENT, 3) |
0122 FIELD_PREP(OSD1_AFBCD_HOLD_LINE_NUM, 4) |
0123 FIELD_PREP(OSD1_AFBCD_RGBA_EXCHAN_CTRL, 0x34) |
0124 meson_gxm_afbcd_pixel_fmt(priv->afbcd.modifier,
0125 priv->afbcd.format);
0126
0127 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPARSE)
0128 mode |= OSD1_AFBCD_HREG_HALF_BLOCK;
0129
0130 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
0131 mode |= OSD1_AFBCD_HREG_BLOCK_SPLIT;
0132
0133 writel_relaxed(mode, priv->io_base + _REG(OSD1_AFBCD_MODE));
0134
0135 writel_relaxed(FIELD_PREP(OSD1_AFBCD_HREG_VSIZE_IN,
0136 priv->viu.osd1_width) |
0137 FIELD_PREP(OSD1_AFBCD_HREG_HSIZE_IN,
0138 priv->viu.osd1_height),
0139 priv->io_base + _REG(OSD1_AFBCD_SIZE_IN));
0140
0141 writel_relaxed(priv->viu.osd1_addr >> 4,
0142 priv->io_base + _REG(OSD1_AFBCD_HDR_PTR));
0143 writel_relaxed(priv->viu.osd1_addr >> 4,
0144 priv->io_base + _REG(OSD1_AFBCD_FRAME_PTR));
0145
0146 writel_relaxed((0xe4 << 24) | (priv->viu.osd1_addr & 0xffffff),
0147 priv->io_base + _REG(OSD1_AFBCD_CHROMA_PTR));
0148
0149 if (priv->viu.osd1_width <= 128)
0150 conv_lbuf_len = 32;
0151 else if (priv->viu.osd1_width <= 256)
0152 conv_lbuf_len = 64;
0153 else if (priv->viu.osd1_width <= 512)
0154 conv_lbuf_len = 128;
0155 else if (priv->viu.osd1_width <= 1024)
0156 conv_lbuf_len = 256;
0157 else if (priv->viu.osd1_width <= 2048)
0158 conv_lbuf_len = 512;
0159 else
0160 conv_lbuf_len = 1024;
0161
0162 writel_relaxed(conv_lbuf_len,
0163 priv->io_base + _REG(OSD1_AFBCD_CONV_CTRL));
0164
0165 writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_H, 0) |
0166 FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_H,
0167 priv->viu.osd1_width - 1),
0168 priv->io_base + _REG(OSD1_AFBCD_PIXEL_HSCOPE));
0169
0170 writel_relaxed(FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_BGN_V, 0) |
0171 FIELD_PREP(OSD1_AFBCD_DEC_PIXEL_END_V,
0172 priv->viu.osd1_height - 1),
0173 priv->io_base + _REG(OSD1_AFBCD_PIXEL_VSCOPE));
0174
0175 return 0;
0176 }
0177
0178 struct meson_afbcd_ops meson_afbcd_gxm_ops = {
0179 .init = meson_gxm_afbcd_init,
0180 .exit = meson_gxm_afbcd_exit,
0181 .reset = meson_gxm_afbcd_reset,
0182 .enable = meson_gxm_afbcd_enable,
0183 .disable = meson_gxm_afbcd_disable,
0184 .setup = meson_gxm_afbcd_setup,
0185 .supported_fmt = meson_gxm_afbcd_supported_fmt,
0186 };
0187
0188
0189
0190
0191 enum {
0192 MAFBC_FMT_RGB565 = 0,
0193 MAFBC_FMT_RGBA5551,
0194 MAFBC_FMT_RGBA1010102,
0195 MAFBC_FMT_YUV420_10B,
0196 MAFBC_FMT_RGB888,
0197 MAFBC_FMT_RGBA8888,
0198 MAFBC_FMT_RGBA4444,
0199 MAFBC_FMT_R8,
0200 MAFBC_FMT_RG88,
0201 MAFBC_FMT_YUV420_8B,
0202 MAFBC_FMT_YUV422_8B = 11,
0203 MAFBC_FMT_YUV422_10B = 14,
0204 };
0205
0206 static int meson_g12a_afbcd_pixel_fmt(u64 modifier, uint32_t format)
0207 {
0208 switch (format) {
0209 case DRM_FORMAT_XRGB8888:
0210 case DRM_FORMAT_ARGB8888:
0211
0212 if (modifier & AFBC_FORMAT_MOD_YTR)
0213 return -EINVAL;
0214 fallthrough;
0215 case DRM_FORMAT_XBGR8888:
0216 case DRM_FORMAT_ABGR8888:
0217 return MAFBC_FMT_RGBA8888;
0218 case DRM_FORMAT_RGB888:
0219
0220 if (modifier & AFBC_FORMAT_MOD_YTR)
0221 return -EINVAL;
0222 return MAFBC_FMT_RGB888;
0223 case DRM_FORMAT_RGB565:
0224
0225 if (modifier & AFBC_FORMAT_MOD_YTR)
0226 return -EINVAL;
0227 return MAFBC_FMT_RGB565;
0228
0229 default:
0230 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
0231 return -EINVAL;
0232 }
0233 }
0234
0235 static int meson_g12a_afbcd_bpp(uint32_t format)
0236 {
0237 switch (format) {
0238 case DRM_FORMAT_XRGB8888:
0239 case DRM_FORMAT_ARGB8888:
0240 case DRM_FORMAT_XBGR8888:
0241 case DRM_FORMAT_ABGR8888:
0242 return 32;
0243 case DRM_FORMAT_RGB888:
0244 return 24;
0245 case DRM_FORMAT_RGB565:
0246 return 16;
0247
0248 default:
0249 DRM_ERROR("unsupported afbc format[%08x]\n", format);
0250 return 0;
0251 }
0252 }
0253
0254 static int meson_g12a_afbcd_fmt_to_blk_mode(u64 modifier, uint32_t format)
0255 {
0256 switch (format) {
0257 case DRM_FORMAT_XRGB8888:
0258 case DRM_FORMAT_ARGB8888:
0259 case DRM_FORMAT_XBGR8888:
0260 case DRM_FORMAT_ABGR8888:
0261 return OSD_MALI_COLOR_MODE_RGBA8888;
0262 case DRM_FORMAT_RGB888:
0263 return OSD_MALI_COLOR_MODE_RGB888;
0264 case DRM_FORMAT_RGB565:
0265 return OSD_MALI_COLOR_MODE_RGB565;
0266
0267 default:
0268 DRM_DEBUG("unsupported afbc format[%08x]\n", format);
0269 return -EINVAL;
0270 }
0271 }
0272
0273 static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format)
0274 {
0275 return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0;
0276 }
0277
0278 static int meson_g12a_afbcd_reset(struct meson_drm *priv)
0279 {
0280 meson_rdma_reset(priv);
0281
0282 meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB |
0283 VIU_SW_RESET_G12A_OSD1_AFBCD,
0284 VIU_SW_RESET);
0285 meson_rdma_writel_sync(priv, 0, VIU_SW_RESET);
0286
0287 return 0;
0288 }
0289
0290 static int meson_g12a_afbcd_init(struct meson_drm *priv)
0291 {
0292 int ret;
0293
0294 ret = meson_rdma_init(priv);
0295 if (ret)
0296 return ret;
0297
0298 meson_rdma_setup(priv);
0299
0300
0301 writel_bits_relaxed(MALI_AFBCD_MANUAL_RESET, MALI_AFBCD_MANUAL_RESET,
0302 priv->io_base + _REG(MALI_AFBCD_TOP_CTRL));
0303
0304 return 0;
0305 }
0306
0307 static void meson_g12a_afbcd_exit(struct meson_drm *priv)
0308 {
0309 meson_g12a_afbcd_reset(priv);
0310 meson_rdma_free(priv);
0311 }
0312
0313 static int meson_g12a_afbcd_enable(struct meson_drm *priv)
0314 {
0315 meson_rdma_writel_sync(priv, VPU_MAFBC_IRQ_SURFACES_COMPLETED |
0316 VPU_MAFBC_IRQ_CONFIGURATION_SWAPPED |
0317 VPU_MAFBC_IRQ_DECODE_ERROR |
0318 VPU_MAFBC_IRQ_DETILING_ERROR,
0319 VPU_MAFBC_IRQ_MASK);
0320
0321 meson_rdma_writel_sync(priv, VPU_MAFBC_S0_ENABLE,
0322 VPU_MAFBC_SURFACE_CFG);
0323
0324 meson_rdma_writel_sync(priv, VPU_MAFBC_DIRECT_SWAP,
0325 VPU_MAFBC_COMMAND);
0326
0327
0328 meson_rdma_flush(priv);
0329
0330 return 0;
0331 }
0332
0333 static int meson_g12a_afbcd_disable(struct meson_drm *priv)
0334 {
0335 writel_bits_relaxed(VPU_MAFBC_S0_ENABLE, 0,
0336 priv->io_base + _REG(VPU_MAFBC_SURFACE_CFG));
0337
0338 return 0;
0339 }
0340
0341 static int meson_g12a_afbcd_setup(struct meson_drm *priv)
0342 {
0343 u32 format = meson_g12a_afbcd_pixel_fmt(priv->afbcd.modifier,
0344 priv->afbcd.format);
0345
0346 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_YTR)
0347 format |= VPU_MAFBC_YUV_TRANSFORM;
0348
0349 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_SPLIT)
0350 format |= VPU_MAFBC_BLOCK_SPLIT;
0351
0352 if (priv->afbcd.modifier & AFBC_FORMAT_MOD_TILED)
0353 format |= VPU_MAFBC_TILED_HEADER_EN;
0354
0355 if ((priv->afbcd.modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
0356 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
0357 format |= FIELD_PREP(VPU_MAFBC_SUPER_BLOCK_ASPECT, 1);
0358
0359 meson_rdma_writel_sync(priv, format,
0360 VPU_MAFBC_FORMAT_SPECIFIER_S0);
0361
0362 meson_rdma_writel_sync(priv, priv->viu.osd1_addr,
0363 VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0);
0364 meson_rdma_writel_sync(priv, 0,
0365 VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0);
0366
0367 meson_rdma_writel_sync(priv, priv->viu.osd1_width,
0368 VPU_MAFBC_BUFFER_WIDTH_S0);
0369 meson_rdma_writel_sync(priv, ALIGN(priv->viu.osd1_height, 32),
0370 VPU_MAFBC_BUFFER_HEIGHT_S0);
0371
0372 meson_rdma_writel_sync(priv, 0,
0373 VPU_MAFBC_BOUNDING_BOX_X_START_S0);
0374 meson_rdma_writel_sync(priv, priv->viu.osd1_width - 1,
0375 VPU_MAFBC_BOUNDING_BOX_X_END_S0);
0376 meson_rdma_writel_sync(priv, 0,
0377 VPU_MAFBC_BOUNDING_BOX_Y_START_S0);
0378 meson_rdma_writel_sync(priv, priv->viu.osd1_height - 1,
0379 VPU_MAFBC_BOUNDING_BOX_Y_END_S0);
0380
0381 meson_rdma_writel_sync(priv, MESON_G12A_AFBCD_OUT_ADDR,
0382 VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0);
0383 meson_rdma_writel_sync(priv, 0,
0384 VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0);
0385
0386 meson_rdma_writel_sync(priv, priv->viu.osd1_width *
0387 (meson_g12a_afbcd_bpp(priv->afbcd.format) / 8),
0388 VPU_MAFBC_OUTPUT_BUF_STRIDE_S0);
0389
0390 return 0;
0391 }
0392
0393 struct meson_afbcd_ops meson_afbcd_g12a_ops = {
0394 .init = meson_g12a_afbcd_init,
0395 .exit = meson_g12a_afbcd_exit,
0396 .reset = meson_g12a_afbcd_reset,
0397 .enable = meson_g12a_afbcd_enable,
0398 .disable = meson_g12a_afbcd_disable,
0399 .setup = meson_g12a_afbcd_setup,
0400 .fmt_to_blk_mode = meson_g12a_afbcd_fmt_to_blk_mode,
0401 .supported_fmt = meson_g12a_afbcd_supported_fmt,
0402 };