*/
 
 #include <linux/export.h>
+#include <linux/bitfield.h>
+
+#include <drm/drm_fourcc.h>
 
 #include "meson_drv.h"
 #include "meson_viu.h"
        meson_viu_load_matrix(priv);
 }
 
+#define OSD1_MALI_ORDER_ABGR                           \
+       (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_A) |          \
+        FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_B) |          \
+        FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_G) |          \
+        FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_R))
+
+#define OSD1_MALI_ORDER_ARGB                           \
+       (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_A) |          \
+        FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_R) |          \
+        FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_G) |          \
+        FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER,      \
+                   VIU_OSD1_MALI_REORDER_B))
+
+void meson_viu_g12a_enable_osd1_afbc(struct meson_drm *priv)
+{
+       u32 afbc_order = OSD1_MALI_ORDER_ARGB;
+
+       /* Enable Mali AFBC Unpack */
+       writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN,
+                           VIU_OSD1_MALI_UNPACK_EN,
+                           priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL));
+
+       switch (priv->afbcd.format) {
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
+               afbc_order = OSD1_MALI_ORDER_ABGR;
+               break;
+       }
+
+       /* Setup RGBA Reordering */
+       writel_bits_relaxed(VIU_OSD1_MALI_AFBCD_A_REORDER |
+                           VIU_OSD1_MALI_AFBCD_B_REORDER |
+                           VIU_OSD1_MALI_AFBCD_G_REORDER |
+                           VIU_OSD1_MALI_AFBCD_R_REORDER,
+                           afbc_order,
+                           priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL));
+
+       /* Select AFBCD path for OSD1 */
+       writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD,
+                           OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD,
+                           priv->io_base + _REG(OSD_PATH_MISC_CTRL));
+}
+
+void meson_viu_g12a_disable_osd1_afbc(struct meson_drm *priv)
+{
+       /* Disable AFBCD path for OSD1 */
+       writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, 0,
+                           priv->io_base + _REG(OSD_PATH_MISC_CTRL));
+
+       /* Disable AFBCD unpack */
+       writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, 0,
+                           priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL));
+}
+
+void meson_viu_gxm_enable_osd1_afbc(struct meson_drm *priv)
+{
+       writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x90),
+                           priv->io_base + _REG(VIU_MISC_CTRL1));
+}
+
+void meson_viu_gxm_disable_osd1_afbc(struct meson_drm *priv)
+{
+       writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x00),
+                           priv->io_base + _REG(VIU_MISC_CTRL1));
+}
+
 static inline uint32_t meson_viu_osd_burst_length_reg(uint32_t length)
 {
        uint32_t val = (((length & 0x80) % 24) / 12);
 
                writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc),
                                    priv->io_base + _REG(DOLBY_PATH_CTRL));
+
+               meson_viu_g12a_disable_osd1_afbc(priv);
        }
 
+       if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
+               meson_viu_gxm_disable_osd1_afbc(priv);
+
        priv->viu.osd1_enabled = false;
        priv->viu.osd1_commit = false;
        priv->viu.osd1_interlace = false;