linux/drivers/gpu/drm/arm/malidp_hw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
   4 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
   5 *
   6 * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
   7 * the difference between various versions of the hardware is being dealt with
   8 * in an attempt to provide to the rest of the driver code a unified view
   9 */
  10
  11#include <linux/clk.h>
  12#include <linux/delay.h>
  13#include <linux/types.h>
  14#include <linux/io.h>
  15
  16#include <video/videomode.h>
  17#include <video/display_timing.h>
  18
  19#include <drm/drm_fourcc.h>
  20#include <drm/drm_vblank.h>
  21#include <drm/drm_print.h>
  22
  23#include "malidp_drv.h"
  24#include "malidp_hw.h"
  25#include "malidp_mw.h"
  26
  27enum {
  28        MW_NOT_ENABLED = 0,     /* SE writeback not enabled */
  29        MW_ONESHOT,             /* SE in one-shot mode for writeback */
  30        MW_START,               /* SE started writeback */
  31        MW_RESTART,             /* SE will start another writeback after this one */
  32        MW_STOP,                /* SE needs to stop after this writeback */
  33};
  34
  35static const struct malidp_format_id malidp500_de_formats[] = {
  36        /*    fourcc,   layers supporting the format,     internal id  */
  37        { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  0 },
  38        { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  1 },
  39        { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
  40        { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
  41        { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  4 },
  42        { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  5 },
  43        { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
  44        { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
  45        { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
  46        { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
  47        { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
  48        { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
  49        { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
  50        { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
  51        { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
  52        { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
  53        { DRM_FORMAT_XYUV8888, DE_VIDEO1, 16 },
  54        /* These are supported with AFBC only */
  55        { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1, 14 },
  56        { DRM_FORMAT_VUY888, DE_VIDEO1, 16 },
  57        { DRM_FORMAT_VUY101010, DE_VIDEO1, 17 },
  58        { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1, 18 }
  59};
  60
  61#define MALIDP_ID(__group, __format) \
  62        ((((__group) & 0x7) << 3) | ((__format) & 0x7))
  63
  64#define AFBC_YUV_422_FORMAT_ID  MALIDP_ID(5, 1)
  65
  66#define MALIDP_COMMON_FORMATS \
  67        /*    fourcc,   layers supporting the format,      internal id   */ \
  68        { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
  69        { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \
  70        { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \
  71        { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \
  72        { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
  73        { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
  74        { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
  75        { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
  76        { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \
  77        { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \
  78        { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \
  79        { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \
  80        { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \
  81        { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \
  82        { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
  83        { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
  84        { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
  85        { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
  86        /* This is only supported with linear modifier */       \
  87        { DRM_FORMAT_XYUV8888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) },\
  88        /* This is only supported with AFBC modifier */         \
  89        { DRM_FORMAT_VUY888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) }, \
  90        { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },    \
  91        /* This is only supported with linear modifier */ \
  92        { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },    \
  93        { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },      \
  94        /* This is only supported with AFBC modifier */ \
  95        { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
  96        { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
  97        /* This is only supported with linear modifier */ \
  98        { DRM_FORMAT_XVYU2101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
  99        /* This is only supported with AFBC modifier */ \
 100        { DRM_FORMAT_VUY101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
 101        { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}, \
 102        /* This is only supported with AFBC modifier */ \
 103        { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}, \
 104        { DRM_FORMAT_P010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}
 105
 106static const struct malidp_format_id malidp550_de_formats[] = {
 107        MALIDP_COMMON_FORMATS,
 108};
 109
 110static const struct malidp_format_id malidp650_de_formats[] = {
 111        MALIDP_COMMON_FORMATS,
 112        { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
 113};
 114
 115static const struct malidp_layer malidp500_layers[] = {
 116        /* id, base address, fb pointer address base, stride offset,
 117         *      yuv2rgb matrix offset, mmu control register offset, rotation_features
 118         */
 119        { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
 120                MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY,
 121                MALIDP500_DE_LV_AD_CTRL },
 122        { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
 123                MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
 124                MALIDP500_DE_LG1_AD_CTRL },
 125        { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
 126                MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
 127                MALIDP500_DE_LG2_AD_CTRL },
 128};
 129
 130static const struct malidp_layer malidp550_layers[] = {
 131        /* id, base address, fb pointer address base, stride offset,
 132         *      yuv2rgb matrix offset, mmu control register offset, rotation_features
 133         */
 134        { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
 135                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
 136                MALIDP550_DE_LV1_AD_CTRL },
 137        { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
 138                MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
 139                MALIDP550_DE_LG_AD_CTRL },
 140        { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
 141                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
 142                MALIDP550_DE_LV2_AD_CTRL },
 143        { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
 144                MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 },
 145};
 146
 147static const struct malidp_layer malidp650_layers[] = {
 148        /* id, base address, fb pointer address base, stride offset,
 149         *      yuv2rgb matrix offset, mmu control register offset,
 150         *      rotation_features
 151         */
 152        { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
 153                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
 154                MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
 155                MALIDP550_DE_LV1_AD_CTRL },
 156        { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
 157                MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
 158                ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL },
 159        { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
 160                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
 161                MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
 162                MALIDP550_DE_LV2_AD_CTRL },
 163        { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
 164                MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
 165                ROTATE_NONE, 0 },
 166};
 167
 168const u64 malidp_format_modifiers[] = {
 169        /* All RGB formats (except XRGB, RGBX, XBGR, BGRX) */
 170        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE),
 171        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR),
 172
 173        /* All RGB formats > 16bpp (except XRGB, RGBX, XBGR, BGRX) */
 174        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE | AFBC_SPLIT),
 175
 176        /* All 8 or 10 bit YUV 444 formats. */
 177        /* In DP550, 10 bit YUV 420 format also supported */
 178        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT),
 179
 180        /* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */
 181        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE),
 182        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16),
 183
 184        /* YUV 420, 422 P1 8, 10 bit formats */
 185        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR | AFBC_SPARSE),
 186        DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR),
 187
 188        /* All formats */
 189        DRM_FORMAT_MOD_LINEAR,
 190
 191        DRM_FORMAT_MOD_INVALID
 192};
 193
 194#define SE_N_SCALING_COEFFS     96
 195static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
 196        [MALIDP_UPSCALING_COEFFS - 1] = {
 197                0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
 198                0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
 199                0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
 200                0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
 201                0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
 202                0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
 203                0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
 204                0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
 205                0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
 206                0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
 207                0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
 208                0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
 209        },
 210        [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
 211                0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
 212                0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
 213                0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
 214                0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
 215                0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
 216                0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
 217                0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
 218                0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
 219                0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
 220                0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
 221                0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
 222                0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
 223        },
 224        [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
 225                0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
 226                0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
 227                0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
 228                0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
 229                0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
 230                0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
 231                0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
 232                0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
 233                0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
 234                0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
 235                0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
 236                0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
 237        },
 238        [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
 239                0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
 240                0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
 241                0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
 242                0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
 243                0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
 244                0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
 245                0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
 246                0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
 247                0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
 248                0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
 249                0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
 250                0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
 251        },
 252        [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
 253                0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
 254                0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
 255                0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
 256                0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
 257                0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
 258                0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
 259                0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
 260                0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
 261                0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
 262                0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
 263                0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
 264                0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
 265        },
 266};
 267
 268#define MALIDP_DE_DEFAULT_PREFETCH_START        5
 269
 270static int malidp500_query_hw(struct malidp_hw_device *hwdev)
 271{
 272        u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
 273        /* bit 4 of the CONFIG_ID register holds the line size multiplier */
 274        u8 ln_size_mult = conf & 0x10 ? 2 : 1;
 275
 276        hwdev->min_line_size = 2;
 277        hwdev->max_line_size = SZ_2K * ln_size_mult;
 278        hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
 279        hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
 280
 281        return 0;
 282}
 283
 284static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
 285{
 286        u32 status, count = 100;
 287
 288        malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
 289        while (count) {
 290                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 291                if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
 292                        break;
 293                /*
 294                 * entering config mode can take as long as the rendering
 295                 * of a full frame, hence the long sleep here
 296                 */
 297                usleep_range(1000, 10000);
 298                count--;
 299        }
 300        WARN(count == 0, "timeout while entering config mode");
 301}
 302
 303static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
 304{
 305        u32 status, count = 100;
 306
 307        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 308        malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
 309        while (count) {
 310                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 311                if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
 312                        break;
 313                usleep_range(100, 1000);
 314                count--;
 315        }
 316        WARN(count == 0, "timeout while leaving config mode");
 317}
 318
 319static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
 320{
 321        u32 status;
 322
 323        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 324        if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
 325                return true;
 326
 327        return false;
 328}
 329
 330static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
 331{
 332        if (value)
 333                malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 334        else
 335                malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 336}
 337
 338static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 339{
 340        u32 val = 0;
 341
 342        malidp_hw_write(hwdev, hwdev->output_color_depth,
 343                hwdev->hw->map.out_depth_base);
 344        malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
 345        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 346                val |= MALIDP500_HSYNCPOL;
 347        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 348                val |= MALIDP500_VSYNCPOL;
 349        val |= MALIDP_DE_DEFAULT_PREFETCH_START;
 350        malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
 351
 352        /*
 353         * Mali-DP500 encodes the background color like this:
 354         *    - red   @ MALIDP500_BGND_COLOR[12:0]
 355         *    - green @ MALIDP500_BGND_COLOR[27:16]
 356         *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
 357         */
 358        val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
 359              (MALIDP_BGND_COLOR_R & 0xfff);
 360        malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
 361        malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
 362
 363        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 364                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 365        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 366
 367        val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
 368                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 369        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 370
 371        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 372                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 373        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 374
 375        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 376        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 377
 378        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 379                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 380        else
 381                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 382
 383        /*
 384         * Program the RQoS register to avoid high resolutions flicker
 385         * issue on the LS1028A.
 386         */
 387        if (hwdev->arqos_value) {
 388                val = hwdev->arqos_value;
 389                malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY);
 390        }
 391}
 392
 393int malidp_format_get_bpp(u32 fmt)
 394{
 395        const struct drm_format_info *info = drm_format_info(fmt);
 396        int bpp = info->cpp[0] * 8;
 397
 398        if (bpp == 0) {
 399                switch (fmt) {
 400                case DRM_FORMAT_VUY101010:
 401                        bpp = 30;
 402                        break;
 403                case DRM_FORMAT_YUV420_10BIT:
 404                        bpp = 15;
 405                        break;
 406                case DRM_FORMAT_YUV420_8BIT:
 407                        bpp = 12;
 408                        break;
 409                default:
 410                        bpp = 0;
 411                }
 412        }
 413
 414        return bpp;
 415}
 416
 417static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
 418                                     u16 h, u32 fmt, bool has_modifier)
 419{
 420        /*
 421         * Each layer needs enough rotation memory to fit 8 lines
 422         * worth of pixel data. Required size is then:
 423         *    size = rotated_width * (bpp / 8) * 8;
 424         */
 425        int bpp = malidp_format_get_bpp(fmt);
 426
 427        return w * bpp;
 428}
 429
 430static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
 431                                           u32 direction,
 432                                           u16 addr,
 433                                           u8 coeffs_id)
 434{
 435        int i;
 436        u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
 437
 438        malidp_hw_write(hwdev,
 439                        direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
 440                        scaling_control + MALIDP_SE_COEFFTAB_ADDR);
 441        for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
 442                malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
 443                                dp500_se_scaling_coeffs[coeffs_id][i]),
 444                                scaling_control + MALIDP_SE_COEFFTAB_DATA);
 445}
 446
 447static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 448                                           struct malidp_se_config *se_config,
 449                                           struct malidp_se_config *old_config)
 450{
 451        /* Get array indices into dp500_se_scaling_coeffs. */
 452        u8 h = (u8)se_config->hcoeff - 1;
 453        u8 v = (u8)se_config->vcoeff - 1;
 454
 455        if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
 456                    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
 457                return -EINVAL;
 458
 459        if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
 460                         se_config->vcoeff != old_config->vcoeff)) {
 461                malidp500_se_write_pp_coefftab(hwdev,
 462                                               (MALIDP_SE_V_COEFFTAB |
 463                                                MALIDP_SE_H_COEFFTAB),
 464                                               0, v);
 465        } else {
 466                if (se_config->vcoeff != old_config->vcoeff)
 467                        malidp500_se_write_pp_coefftab(hwdev,
 468                                                       MALIDP_SE_V_COEFFTAB,
 469                                                       0, v);
 470                if (se_config->hcoeff != old_config->hcoeff)
 471                        malidp500_se_write_pp_coefftab(hwdev,
 472                                                       MALIDP_SE_H_COEFFTAB,
 473                                                       0, h);
 474        }
 475
 476        return 0;
 477}
 478
 479static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
 480                                   struct malidp_se_config *se_config,
 481                                   struct videomode *vm)
 482{
 483        unsigned long mclk;
 484        unsigned long pxlclk = vm->pixelclock; /* Hz */
 485        unsigned long htotal = vm->hactive + vm->hfront_porch +
 486                               vm->hback_porch + vm->hsync_len;
 487        unsigned long input_size = se_config->input_w * se_config->input_h;
 488        unsigned long a = 10;
 489        long ret;
 490
 491        /*
 492         * mclk = max(a, 1.5) * pxlclk
 493         *
 494         * To avoid float calculaiton, using 15 instead of 1.5 and div by
 495         * 10 to get mclk.
 496         */
 497        if (se_config->scale_enable) {
 498                a = 15 * input_size / (htotal * se_config->output_h);
 499                if (a < 15)
 500                        a = 15;
 501        }
 502        mclk = a * pxlclk / 10;
 503        ret = clk_get_rate(hwdev->mclk);
 504        if (ret < mclk) {
 505                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 506                                 mclk / 1000);
 507                return -EINVAL;
 508        }
 509        return ret;
 510}
 511
 512static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
 513                                     dma_addr_t *addrs, s32 *pitches,
 514                                     int num_planes, u16 w, u16 h, u32 fmt_id,
 515                                     const s16 *rgb2yuv_coeffs)
 516{
 517        u32 base = MALIDP500_SE_MEMWRITE_BASE;
 518        u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 519
 520        /* enable the scaling engine block */
 521        malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
 522
 523        /* restart the writeback if already enabled */
 524        if (hwdev->mw_state != MW_NOT_ENABLED)
 525                hwdev->mw_state = MW_RESTART;
 526        else
 527                hwdev->mw_state = MW_START;
 528
 529        malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
 530        switch (num_planes) {
 531        case 2:
 532                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
 533                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
 534                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
 535                fallthrough;
 536        case 1:
 537                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
 538                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
 539                malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
 540                break;
 541        default:
 542                WARN(1, "Invalid number of planes");
 543        }
 544
 545        malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
 546                        MALIDP500_SE_MEMWRITE_OUT_SIZE);
 547
 548        if (rgb2yuv_coeffs) {
 549                int i;
 550
 551                for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
 552                        malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
 553                                        MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
 554                }
 555        }
 556
 557        malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
 558
 559        return 0;
 560}
 561
 562static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
 563{
 564        u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 565
 566        if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
 567                hwdev->mw_state = MW_STOP;
 568        malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
 569        malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
 570}
 571
 572static int malidp550_query_hw(struct malidp_hw_device *hwdev)
 573{
 574        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 575        u8 ln_size = (conf >> 4) & 0x3, rsize;
 576
 577        hwdev->min_line_size = 2;
 578
 579        switch (ln_size) {
 580        case 0:
 581                hwdev->max_line_size = SZ_2K;
 582                /* two banks of 64KB for rotation memory */
 583                rsize = 64;
 584                break;
 585        case 1:
 586                hwdev->max_line_size = SZ_4K;
 587                /* two banks of 128KB for rotation memory */
 588                rsize = 128;
 589                break;
 590        case 2:
 591                hwdev->max_line_size = 1280;
 592                /* two banks of 40KB for rotation memory */
 593                rsize = 40;
 594                break;
 595        case 3:
 596                /* reserved value */
 597                hwdev->max_line_size = 0;
 598                return -EINVAL;
 599        }
 600
 601        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 602        return 0;
 603}
 604
 605static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
 606{
 607        u32 status, count = 100;
 608
 609        malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 610        while (count) {
 611                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 612                if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 613                        break;
 614                /*
 615                 * entering config mode can take as long as the rendering
 616                 * of a full frame, hence the long sleep here
 617                 */
 618                usleep_range(1000, 10000);
 619                count--;
 620        }
 621        WARN(count == 0, "timeout while entering config mode");
 622}
 623
 624static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
 625{
 626        u32 status, count = 100;
 627
 628        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 629        malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 630        while (count) {
 631                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 632                if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
 633                        break;
 634                usleep_range(100, 1000);
 635                count--;
 636        }
 637        WARN(count == 0, "timeout while leaving config mode");
 638}
 639
 640static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
 641{
 642        u32 status;
 643
 644        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 645        if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 646                return true;
 647
 648        return false;
 649}
 650
 651static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
 652{
 653        if (value)
 654                malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 655        else
 656                malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 657}
 658
 659static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 660{
 661        u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
 662
 663        malidp_hw_write(hwdev, hwdev->output_color_depth,
 664                hwdev->hw->map.out_depth_base);
 665        malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
 666        /*
 667         * Mali-DP550 and Mali-DP650 encode the background color like this:
 668         *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
 669         *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
 670         *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
 671         *
 672         * We need to truncate the least significant 4 bits from the default
 673         * MALIDP_BGND_COLOR_x values
 674         */
 675        val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
 676              (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
 677              ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
 678        malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
 679
 680        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 681                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 682        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 683
 684        val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
 685                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 686        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 687
 688        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 689                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 690        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 691                val |= MALIDP550_HSYNCPOL;
 692        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 693                val |= MALIDP550_VSYNCPOL;
 694        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 695
 696        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 697        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 698
 699        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 700                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 701        else
 702                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 703}
 704
 705static int malidpx50_get_bytes_per_column(u32 fmt)
 706{
 707        u32 bytes_per_column;
 708
 709        switch (fmt) {
 710        /* 8 lines at 4 bytes per pixel */
 711        case DRM_FORMAT_ARGB2101010:
 712        case DRM_FORMAT_ABGR2101010:
 713        case DRM_FORMAT_RGBA1010102:
 714        case DRM_FORMAT_BGRA1010102:
 715        case DRM_FORMAT_ARGB8888:
 716        case DRM_FORMAT_ABGR8888:
 717        case DRM_FORMAT_RGBA8888:
 718        case DRM_FORMAT_BGRA8888:
 719        case DRM_FORMAT_XRGB8888:
 720        case DRM_FORMAT_XBGR8888:
 721        case DRM_FORMAT_RGBX8888:
 722        case DRM_FORMAT_BGRX8888:
 723        case DRM_FORMAT_RGB888:
 724        case DRM_FORMAT_BGR888:
 725        /* 16 lines at 2 bytes per pixel */
 726        case DRM_FORMAT_RGBA5551:
 727        case DRM_FORMAT_ABGR1555:
 728        case DRM_FORMAT_RGB565:
 729        case DRM_FORMAT_BGR565:
 730        case DRM_FORMAT_UYVY:
 731        case DRM_FORMAT_YUYV:
 732        case DRM_FORMAT_X0L0:
 733                bytes_per_column = 32;
 734                break;
 735        /* 16 lines at 1.5 bytes per pixel */
 736        case DRM_FORMAT_NV12:
 737        case DRM_FORMAT_YUV420:
 738        /* 8 lines at 3 bytes per pixel */
 739        case DRM_FORMAT_VUY888:
 740        /* 16 lines at 12 bits per pixel */
 741        case DRM_FORMAT_YUV420_8BIT:
 742        /* 8 lines at 3 bytes per pixel */
 743        case DRM_FORMAT_P010:
 744                bytes_per_column = 24;
 745                break;
 746        /* 8 lines at 30 bits per pixel */
 747        case DRM_FORMAT_VUY101010:
 748        /* 16 lines at 15 bits per pixel */
 749        case DRM_FORMAT_YUV420_10BIT:
 750                bytes_per_column = 30;
 751                break;
 752        default:
 753                return -EINVAL;
 754        }
 755
 756        return bytes_per_column;
 757}
 758
 759static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
 760                                     u16 h, u32 fmt, bool has_modifier)
 761{
 762        int bytes_per_column = 0;
 763
 764        switch (fmt) {
 765        /* 8 lines at 15 bits per pixel */
 766        case DRM_FORMAT_YUV420_10BIT:
 767                bytes_per_column = 15;
 768                break;
 769        /* Uncompressed YUV 420 10 bit single plane cannot be rotated */
 770        case DRM_FORMAT_X0L2:
 771                if (has_modifier)
 772                        bytes_per_column = 8;
 773                else
 774                        return -EINVAL;
 775                break;
 776        default:
 777                bytes_per_column = malidpx50_get_bytes_per_column(fmt);
 778        }
 779
 780        if (bytes_per_column == -EINVAL)
 781                return bytes_per_column;
 782
 783        return w * bytes_per_column;
 784}
 785
 786static int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
 787                                     u16 h, u32 fmt, bool has_modifier)
 788{
 789        int bytes_per_column = 0;
 790
 791        switch (fmt) {
 792        /* 16 lines at 2 bytes per pixel */
 793        case DRM_FORMAT_X0L2:
 794                bytes_per_column = 32;
 795                break;
 796        default:
 797                bytes_per_column = malidpx50_get_bytes_per_column(fmt);
 798        }
 799
 800        if (bytes_per_column == -EINVAL)
 801                return bytes_per_column;
 802
 803        return w * bytes_per_column;
 804}
 805
 806static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 807                                           struct malidp_se_config *se_config,
 808                                           struct malidp_se_config *old_config)
 809{
 810        u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
 811                   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
 812        u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
 813                        MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
 814
 815        malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
 816        malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
 817        return 0;
 818}
 819
 820static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
 821                                   struct malidp_se_config *se_config,
 822                                   struct videomode *vm)
 823{
 824        unsigned long mclk;
 825        unsigned long pxlclk = vm->pixelclock;
 826        unsigned long htotal = vm->hactive + vm->hfront_porch +
 827                               vm->hback_porch + vm->hsync_len;
 828        unsigned long numerator = 1, denominator = 1;
 829        long ret;
 830
 831        if (se_config->scale_enable) {
 832                numerator = max(se_config->input_w, se_config->output_w) *
 833                            se_config->input_h;
 834                numerator += se_config->output_w *
 835                             (se_config->output_h -
 836                              min(se_config->input_h, se_config->output_h));
 837                denominator = (htotal - 2) * se_config->output_h;
 838        }
 839
 840        /* mclk can't be slower than pxlclk. */
 841        if (numerator < denominator)
 842                numerator = denominator = 1;
 843        mclk = (pxlclk * numerator) / denominator;
 844        ret = clk_get_rate(hwdev->mclk);
 845        if (ret < mclk) {
 846                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 847                                 mclk / 1000);
 848                return -EINVAL;
 849        }
 850        return ret;
 851}
 852
 853static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
 854                                     dma_addr_t *addrs, s32 *pitches,
 855                                     int num_planes, u16 w, u16 h, u32 fmt_id,
 856                                     const s16 *rgb2yuv_coeffs)
 857{
 858        u32 base = MALIDP550_SE_MEMWRITE_BASE;
 859        u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 860
 861        /* enable the scaling engine block */
 862        malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
 863
 864        hwdev->mw_state = MW_ONESHOT;
 865
 866        malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
 867        switch (num_planes) {
 868        case 2:
 869                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
 870                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
 871                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
 872                fallthrough;
 873        case 1:
 874                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
 875                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
 876                malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
 877                break;
 878        default:
 879                WARN(1, "Invalid number of planes");
 880        }
 881
 882        malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
 883                        MALIDP550_SE_MEMWRITE_OUT_SIZE);
 884        malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
 885                          MALIDP550_SE_CONTROL);
 886
 887        if (rgb2yuv_coeffs) {
 888                int i;
 889
 890                for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
 891                        malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
 892                                        MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
 893                }
 894        }
 895
 896        return 0;
 897}
 898
 899static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
 900{
 901        u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 902
 903        malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
 904                            MALIDP550_SE_CONTROL);
 905        malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
 906}
 907
 908static int malidp650_query_hw(struct malidp_hw_device *hwdev)
 909{
 910        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 911        u8 ln_size = (conf >> 4) & 0x3, rsize;
 912
 913        hwdev->min_line_size = 4;
 914
 915        switch (ln_size) {
 916        case 0:
 917        case 2:
 918                /* reserved values */
 919                hwdev->max_line_size = 0;
 920                return -EINVAL;
 921        case 1:
 922                hwdev->max_line_size = SZ_4K;
 923                /* two banks of 128KB for rotation memory */
 924                rsize = 128;
 925                break;
 926        case 3:
 927                hwdev->max_line_size = 2560;
 928                /* two banks of 80KB for rotation memory */
 929                rsize = 80;
 930        }
 931
 932        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 933        return 0;
 934}
 935
 936const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
 937        [MALIDP_500] = {
 938                .map = {
 939                        .coeffs_base = MALIDP500_COEFFS_BASE,
 940                        .se_base = MALIDP500_SE_BASE,
 941                        .dc_base = MALIDP500_DC_BASE,
 942                        .out_depth_base = MALIDP500_OUTPUT_DEPTH,
 943                        .features = 0,  /* no CLEARIRQ register */
 944                        .n_layers = ARRAY_SIZE(malidp500_layers),
 945                        .layers = malidp500_layers,
 946                        .de_irq_map = {
 947                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 948                                            MALIDP500_DE_IRQ_AXI_ERR |
 949                                            MALIDP500_DE_IRQ_VSYNC |
 950                                            MALIDP500_DE_IRQ_GLOBAL,
 951                                .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
 952                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
 953                                            MALIDP500_DE_IRQ_AXI_ERR |
 954                                            MALIDP500_DE_IRQ_SATURATION,
 955                        },
 956                        .se_irq_map = {
 957                                .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
 958                                            MALIDP500_SE_IRQ_CONF_VALID |
 959                                            MALIDP500_SE_IRQ_GLOBAL,
 960                                .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
 961                                .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
 962                                            MALIDP500_SE_IRQ_AXI_ERROR |
 963                                            MALIDP500_SE_IRQ_OVERRUN,
 964                        },
 965                        .dc_irq_map = {
 966                                .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
 967                                .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
 968                        },
 969                        .pixel_formats = malidp500_de_formats,
 970                        .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
 971                        .bus_align_bytes = 8,
 972                },
 973                .query_hw = malidp500_query_hw,
 974                .enter_config_mode = malidp500_enter_config_mode,
 975                .leave_config_mode = malidp500_leave_config_mode,
 976                .in_config_mode = malidp500_in_config_mode,
 977                .set_config_valid = malidp500_set_config_valid,
 978                .modeset = malidp500_modeset,
 979                .rotmem_required = malidp500_rotmem_required,
 980                .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
 981                .se_calc_mclk = malidp500_se_calc_mclk,
 982                .enable_memwrite = malidp500_enable_memwrite,
 983                .disable_memwrite = malidp500_disable_memwrite,
 984                .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
 985        },
 986        [MALIDP_550] = {
 987                .map = {
 988                        .coeffs_base = MALIDP550_COEFFS_BASE,
 989                        .se_base = MALIDP550_SE_BASE,
 990                        .dc_base = MALIDP550_DC_BASE,
 991                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
 992                        .features = MALIDP_REGMAP_HAS_CLEARIRQ |
 993                                    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
 994                                    MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
 995                                    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
 996                        .n_layers = ARRAY_SIZE(malidp550_layers),
 997                        .layers = malidp550_layers,
 998                        .de_irq_map = {
 999                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
1000                                            MALIDP550_DE_IRQ_VSYNC,
1001                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
1002                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
1003                                            MALIDP550_DE_IRQ_SATURATION |
1004                                            MALIDP550_DE_IRQ_AXI_ERR,
1005                        },
1006                        .se_irq_map = {
1007                                .irq_mask = MALIDP550_SE_IRQ_EOW,
1008                                .vsync_irq = MALIDP550_SE_IRQ_EOW,
1009                                .err_mask  = MALIDP550_SE_IRQ_AXI_ERR |
1010                                             MALIDP550_SE_IRQ_OVR |
1011                                             MALIDP550_SE_IRQ_IBSY,
1012                        },
1013                        .dc_irq_map = {
1014                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
1015                                            MALIDP550_DC_IRQ_SE,
1016                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
1017                        },
1018                        .pixel_formats = malidp550_de_formats,
1019                        .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
1020                        .bus_align_bytes = 8,
1021                },
1022                .query_hw = malidp550_query_hw,
1023                .enter_config_mode = malidp550_enter_config_mode,
1024                .leave_config_mode = malidp550_leave_config_mode,
1025                .in_config_mode = malidp550_in_config_mode,
1026                .set_config_valid = malidp550_set_config_valid,
1027                .modeset = malidp550_modeset,
1028                .rotmem_required = malidp550_rotmem_required,
1029                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
1030                .se_calc_mclk = malidp550_se_calc_mclk,
1031                .enable_memwrite = malidp550_enable_memwrite,
1032                .disable_memwrite = malidp550_disable_memwrite,
1033                .features = 0,
1034        },
1035        [MALIDP_650] = {
1036                .map = {
1037                        .coeffs_base = MALIDP550_COEFFS_BASE,
1038                        .se_base = MALIDP550_SE_BASE,
1039                        .dc_base = MALIDP550_DC_BASE,
1040                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
1041                        .features = MALIDP_REGMAP_HAS_CLEARIRQ |
1042                                    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
1043                                    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
1044                        .n_layers = ARRAY_SIZE(malidp650_layers),
1045                        .layers = malidp650_layers,
1046                        .de_irq_map = {
1047                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
1048                                            MALIDP650_DE_IRQ_DRIFT |
1049                                            MALIDP550_DE_IRQ_VSYNC,
1050                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
1051                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
1052                                            MALIDP650_DE_IRQ_DRIFT |
1053                                            MALIDP550_DE_IRQ_SATURATION |
1054                                            MALIDP550_DE_IRQ_AXI_ERR |
1055                                            MALIDP650_DE_IRQ_ACEV1 |
1056                                            MALIDP650_DE_IRQ_ACEV2 |
1057                                            MALIDP650_DE_IRQ_ACEG |
1058                                            MALIDP650_DE_IRQ_AXIEP,
1059                        },
1060                        .se_irq_map = {
1061                                .irq_mask = MALIDP550_SE_IRQ_EOW,
1062                                .vsync_irq = MALIDP550_SE_IRQ_EOW,
1063                                .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
1064                                            MALIDP550_SE_IRQ_OVR |
1065                                            MALIDP550_SE_IRQ_IBSY,
1066                        },
1067                        .dc_irq_map = {
1068                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
1069                                            MALIDP550_DC_IRQ_SE,
1070                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
1071                        },
1072                        .pixel_formats = malidp650_de_formats,
1073                        .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
1074                        .bus_align_bytes = 16,
1075                },
1076                .query_hw = malidp650_query_hw,
1077                .enter_config_mode = malidp550_enter_config_mode,
1078                .leave_config_mode = malidp550_leave_config_mode,
1079                .in_config_mode = malidp550_in_config_mode,
1080                .set_config_valid = malidp550_set_config_valid,
1081                .modeset = malidp550_modeset,
1082                .rotmem_required = malidp650_rotmem_required,
1083                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
1084                .se_calc_mclk = malidp550_se_calc_mclk,
1085                .enable_memwrite = malidp550_enable_memwrite,
1086                .disable_memwrite = malidp550_disable_memwrite,
1087                .features = 0,
1088        },
1089};
1090
1091u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
1092                           u8 layer_id, u32 format, bool has_modifier)
1093{
1094        unsigned int i;
1095
1096        for (i = 0; i < map->n_pixel_formats; i++) {
1097                if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
1098                    (map->pixel_formats[i].format == format)) {
1099                        /*
1100                         * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier
1101                         * is supported by a different h/w format id than
1102                         * DRM_FORMAT_YUYV (only).
1103                         */
1104                        if (format == DRM_FORMAT_YUYV &&
1105                            (has_modifier) &&
1106                            (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2))
1107                                return AFBC_YUV_422_FORMAT_ID;
1108                        else
1109                                return map->pixel_formats[i].id;
1110                }
1111        }
1112
1113        return MALIDP_INVALID_FORMAT_ID;
1114}
1115
1116bool malidp_hw_format_is_linear_only(u32 format)
1117{
1118        switch (format) {
1119        case DRM_FORMAT_ARGB2101010:
1120        case DRM_FORMAT_RGBA1010102:
1121        case DRM_FORMAT_BGRA1010102:
1122        case DRM_FORMAT_ARGB8888:
1123        case DRM_FORMAT_RGBA8888:
1124        case DRM_FORMAT_BGRA8888:
1125        case DRM_FORMAT_XBGR8888:
1126        case DRM_FORMAT_XRGB8888:
1127        case DRM_FORMAT_RGBX8888:
1128        case DRM_FORMAT_BGRX8888:
1129        case DRM_FORMAT_RGB888:
1130        case DRM_FORMAT_RGB565:
1131        case DRM_FORMAT_ARGB1555:
1132        case DRM_FORMAT_RGBA5551:
1133        case DRM_FORMAT_BGRA5551:
1134        case DRM_FORMAT_UYVY:
1135        case DRM_FORMAT_XYUV8888:
1136        case DRM_FORMAT_XVYU2101010:
1137        case DRM_FORMAT_X0L2:
1138        case DRM_FORMAT_X0L0:
1139                return true;
1140        default:
1141                return false;
1142        }
1143}
1144
1145bool malidp_hw_format_is_afbc_only(u32 format)
1146{
1147        switch (format) {
1148        case DRM_FORMAT_VUY888:
1149        case DRM_FORMAT_VUY101010:
1150        case DRM_FORMAT_YUV420_8BIT:
1151        case DRM_FORMAT_YUV420_10BIT:
1152                return true;
1153        default:
1154                return false;
1155        }
1156}
1157
1158static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
1159{
1160        u32 base = malidp_get_block_base(hwdev, block);
1161
1162        if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
1163                malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
1164        else
1165                malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
1166}
1167
1168static irqreturn_t malidp_de_irq(int irq, void *arg)
1169{
1170        struct drm_device *drm = arg;
1171        struct malidp_drm *malidp = drm->dev_private;
1172        struct malidp_hw_device *hwdev;
1173        struct malidp_hw *hw;
1174        const struct malidp_irq_map *de;
1175        u32 status, mask, dc_status;
1176        irqreturn_t ret = IRQ_NONE;
1177
1178        hwdev = malidp->dev;
1179        hw = hwdev->hw;
1180        de = &hw->map.de_irq_map;
1181
1182        /*
1183         * if we are suspended it is likely that we were invoked because
1184         * we share an interrupt line with some other driver, don't try
1185         * to read the hardware registers
1186         */
1187        if (hwdev->pm_suspended)
1188                return IRQ_NONE;
1189
1190        /* first handle the config valid IRQ */
1191        dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1192        if (dc_status & hw->map.dc_irq_map.vsync_irq) {
1193                malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
1194                /* do we have a page flip event? */
1195                if (malidp->event != NULL) {
1196                        spin_lock(&drm->event_lock);
1197                        drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
1198                        malidp->event = NULL;
1199                        spin_unlock(&drm->event_lock);
1200                }
1201                atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
1202                ret = IRQ_WAKE_THREAD;
1203        }
1204
1205        status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
1206        if (!(status & de->irq_mask))
1207                return ret;
1208
1209        mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
1210        /* keep the status of the enabled interrupts, plus the error bits */
1211        status &= (mask | de->err_mask);
1212        if ((status & de->vsync_irq) && malidp->crtc.enabled)
1213                drm_crtc_handle_vblank(&malidp->crtc);
1214
1215#ifdef CONFIG_DEBUG_FS
1216        if (status & de->err_mask) {
1217                malidp_error(malidp, &malidp->de_errors, status,
1218                             drm_crtc_vblank_count(&malidp->crtc));
1219        }
1220#endif
1221        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
1222
1223        return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
1224}
1225
1226static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1227{
1228        struct drm_device *drm = arg;
1229        struct malidp_drm *malidp = drm->dev_private;
1230
1231        wake_up(&malidp->wq);
1232
1233        return IRQ_HANDLED;
1234}
1235
1236void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
1237{
1238        /* ensure interrupts are disabled */
1239        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1240        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1241        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1242        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1243
1244        /* first enable the DC block IRQs */
1245        malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
1246                             hwdev->hw->map.dc_irq_map.irq_mask);
1247
1248        /* now enable the DE block IRQs */
1249        malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
1250                             hwdev->hw->map.de_irq_map.irq_mask);
1251}
1252
1253int malidp_de_irq_init(struct drm_device *drm, int irq)
1254{
1255        struct malidp_drm *malidp = drm->dev_private;
1256        struct malidp_hw_device *hwdev = malidp->dev;
1257        int ret;
1258
1259        /* ensure interrupts are disabled */
1260        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1261        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1262        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1263        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1264
1265        ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
1266                                        malidp_de_irq_thread_handler,
1267                                        IRQF_SHARED, "malidp-de", drm);
1268        if (ret < 0) {
1269                DRM_ERROR("failed to install DE IRQ handler\n");
1270                return ret;
1271        }
1272
1273        malidp_de_irq_hw_init(hwdev);
1274
1275        return 0;
1276}
1277
1278void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
1279{
1280        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
1281                              hwdev->hw->map.de_irq_map.irq_mask);
1282        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
1283                              hwdev->hw->map.dc_irq_map.irq_mask);
1284}
1285
1286static irqreturn_t malidp_se_irq(int irq, void *arg)
1287{
1288        struct drm_device *drm = arg;
1289        struct malidp_drm *malidp = drm->dev_private;
1290        struct malidp_hw_device *hwdev = malidp->dev;
1291        struct malidp_hw *hw = hwdev->hw;
1292        const struct malidp_irq_map *se = &hw->map.se_irq_map;
1293        u32 status, mask;
1294
1295        /*
1296         * if we are suspended it is likely that we were invoked because
1297         * we share an interrupt line with some other driver, don't try
1298         * to read the hardware registers
1299         */
1300        if (hwdev->pm_suspended)
1301                return IRQ_NONE;
1302
1303        status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
1304        if (!(status & (se->irq_mask | se->err_mask)))
1305                return IRQ_NONE;
1306
1307#ifdef CONFIG_DEBUG_FS
1308        if (status & se->err_mask)
1309                malidp_error(malidp, &malidp->se_errors, status,
1310                             drm_crtc_vblank_count(&malidp->crtc));
1311#endif
1312        mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
1313        status &= mask;
1314
1315        if (status & se->vsync_irq) {
1316                switch (hwdev->mw_state) {
1317                case MW_ONESHOT:
1318                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1319                        break;
1320                case MW_STOP:
1321                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1322                        /* disable writeback after stop */
1323                        hwdev->mw_state = MW_NOT_ENABLED;
1324                        break;
1325                case MW_RESTART:
1326                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1327                        fallthrough;    /* to a new start */
1328                case MW_START:
1329                        /* writeback started, need to emulate one-shot mode */
1330                        hw->disable_memwrite(hwdev);
1331                        /*
1332                         * only set config_valid HW bit if there is no other update
1333                         * in progress or if we raced ahead of the DE IRQ handler
1334                         * and config_valid flag will not be update until later
1335                         */
1336                        status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1337                        if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1338                            (status & hw->map.dc_irq_map.vsync_irq))
1339                                hw->set_config_valid(hwdev, 1);
1340                        break;
1341                }
1342        }
1343
1344        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1345
1346        return IRQ_HANDLED;
1347}
1348
1349void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
1350{
1351        /* ensure interrupts are disabled */
1352        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1353        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1354
1355        malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1356                             hwdev->hw->map.se_irq_map.irq_mask);
1357}
1358
1359static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1360{
1361        return IRQ_HANDLED;
1362}
1363
1364int malidp_se_irq_init(struct drm_device *drm, int irq)
1365{
1366        struct malidp_drm *malidp = drm->dev_private;
1367        struct malidp_hw_device *hwdev = malidp->dev;
1368        int ret;
1369
1370        /* ensure interrupts are disabled */
1371        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1372        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1373
1374        ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1375                                        malidp_se_irq_thread_handler,
1376                                        IRQF_SHARED, "malidp-se", drm);
1377        if (ret < 0) {
1378                DRM_ERROR("failed to install SE IRQ handler\n");
1379                return ret;
1380        }
1381
1382        hwdev->mw_state = MW_NOT_ENABLED;
1383        malidp_se_irq_hw_init(hwdev);
1384
1385        return 0;
1386}
1387
1388void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1389{
1390        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1391                              hwdev->hw->map.se_irq_map.irq_mask);
1392}
1393