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
 384int malidp_format_get_bpp(u32 fmt)
 385{
 386        const struct drm_format_info *info = drm_format_info(fmt);
 387        int bpp = info->cpp[0] * 8;
 388
 389        if (bpp == 0) {
 390                switch (fmt) {
 391                case DRM_FORMAT_VUY101010:
 392                        bpp = 30;
 393                        break;
 394                case DRM_FORMAT_YUV420_10BIT:
 395                        bpp = 15;
 396                        break;
 397                case DRM_FORMAT_YUV420_8BIT:
 398                        bpp = 12;
 399                        break;
 400                default:
 401                        bpp = 0;
 402                }
 403        }
 404
 405        return bpp;
 406}
 407
 408static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
 409                                     u16 h, u32 fmt, bool has_modifier)
 410{
 411        /*
 412         * Each layer needs enough rotation memory to fit 8 lines
 413         * worth of pixel data. Required size is then:
 414         *    size = rotated_width * (bpp / 8) * 8;
 415         */
 416        int bpp = malidp_format_get_bpp(fmt);
 417
 418        return w * bpp;
 419}
 420
 421static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
 422                                           u32 direction,
 423                                           u16 addr,
 424                                           u8 coeffs_id)
 425{
 426        int i;
 427        u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
 428
 429        malidp_hw_write(hwdev,
 430                        direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
 431                        scaling_control + MALIDP_SE_COEFFTAB_ADDR);
 432        for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
 433                malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
 434                                dp500_se_scaling_coeffs[coeffs_id][i]),
 435                                scaling_control + MALIDP_SE_COEFFTAB_DATA);
 436}
 437
 438static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 439                                           struct malidp_se_config *se_config,
 440                                           struct malidp_se_config *old_config)
 441{
 442        /* Get array indices into dp500_se_scaling_coeffs. */
 443        u8 h = (u8)se_config->hcoeff - 1;
 444        u8 v = (u8)se_config->vcoeff - 1;
 445
 446        if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
 447                    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
 448                return -EINVAL;
 449
 450        if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
 451                         se_config->vcoeff != old_config->vcoeff)) {
 452                malidp500_se_write_pp_coefftab(hwdev,
 453                                               (MALIDP_SE_V_COEFFTAB |
 454                                                MALIDP_SE_H_COEFFTAB),
 455                                               0, v);
 456        } else {
 457                if (se_config->vcoeff != old_config->vcoeff)
 458                        malidp500_se_write_pp_coefftab(hwdev,
 459                                                       MALIDP_SE_V_COEFFTAB,
 460                                                       0, v);
 461                if (se_config->hcoeff != old_config->hcoeff)
 462                        malidp500_se_write_pp_coefftab(hwdev,
 463                                                       MALIDP_SE_H_COEFFTAB,
 464                                                       0, h);
 465        }
 466
 467        return 0;
 468}
 469
 470static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
 471                                   struct malidp_se_config *se_config,
 472                                   struct videomode *vm)
 473{
 474        unsigned long mclk;
 475        unsigned long pxlclk = vm->pixelclock; /* Hz */
 476        unsigned long htotal = vm->hactive + vm->hfront_porch +
 477                               vm->hback_porch + vm->hsync_len;
 478        unsigned long input_size = se_config->input_w * se_config->input_h;
 479        unsigned long a = 10;
 480        long ret;
 481
 482        /*
 483         * mclk = max(a, 1.5) * pxlclk
 484         *
 485         * To avoid float calculaiton, using 15 instead of 1.5 and div by
 486         * 10 to get mclk.
 487         */
 488        if (se_config->scale_enable) {
 489                a = 15 * input_size / (htotal * se_config->output_h);
 490                if (a < 15)
 491                        a = 15;
 492        }
 493        mclk = a * pxlclk / 10;
 494        ret = clk_get_rate(hwdev->mclk);
 495        if (ret < mclk) {
 496                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 497                                 mclk / 1000);
 498                return -EINVAL;
 499        }
 500        return ret;
 501}
 502
 503static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
 504                                     dma_addr_t *addrs, s32 *pitches,
 505                                     int num_planes, u16 w, u16 h, u32 fmt_id,
 506                                     const s16 *rgb2yuv_coeffs)
 507{
 508        u32 base = MALIDP500_SE_MEMWRITE_BASE;
 509        u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 510
 511        /* enable the scaling engine block */
 512        malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
 513
 514        /* restart the writeback if already enabled */
 515        if (hwdev->mw_state != MW_NOT_ENABLED)
 516                hwdev->mw_state = MW_RESTART;
 517        else
 518                hwdev->mw_state = MW_START;
 519
 520        malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
 521        switch (num_planes) {
 522        case 2:
 523                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
 524                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
 525                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
 526                /* fall through */
 527        case 1:
 528                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
 529                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
 530                malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
 531                break;
 532        default:
 533                WARN(1, "Invalid number of planes");
 534        }
 535
 536        malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
 537                        MALIDP500_SE_MEMWRITE_OUT_SIZE);
 538
 539        if (rgb2yuv_coeffs) {
 540                int i;
 541
 542                for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
 543                        malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
 544                                        MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
 545                }
 546        }
 547
 548        malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
 549
 550        return 0;
 551}
 552
 553static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
 554{
 555        u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 556
 557        if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
 558                hwdev->mw_state = MW_STOP;
 559        malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
 560        malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
 561}
 562
 563static int malidp550_query_hw(struct malidp_hw_device *hwdev)
 564{
 565        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 566        u8 ln_size = (conf >> 4) & 0x3, rsize;
 567
 568        hwdev->min_line_size = 2;
 569
 570        switch (ln_size) {
 571        case 0:
 572                hwdev->max_line_size = SZ_2K;
 573                /* two banks of 64KB for rotation memory */
 574                rsize = 64;
 575                break;
 576        case 1:
 577                hwdev->max_line_size = SZ_4K;
 578                /* two banks of 128KB for rotation memory */
 579                rsize = 128;
 580                break;
 581        case 2:
 582                hwdev->max_line_size = 1280;
 583                /* two banks of 40KB for rotation memory */
 584                rsize = 40;
 585                break;
 586        case 3:
 587                /* reserved value */
 588                hwdev->max_line_size = 0;
 589                return -EINVAL;
 590        }
 591
 592        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 593        return 0;
 594}
 595
 596static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
 597{
 598        u32 status, count = 100;
 599
 600        malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 601        while (count) {
 602                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 603                if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 604                        break;
 605                /*
 606                 * entering config mode can take as long as the rendering
 607                 * of a full frame, hence the long sleep here
 608                 */
 609                usleep_range(1000, 10000);
 610                count--;
 611        }
 612        WARN(count == 0, "timeout while entering config mode");
 613}
 614
 615static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
 616{
 617        u32 status, count = 100;
 618
 619        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 620        malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 621        while (count) {
 622                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 623                if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
 624                        break;
 625                usleep_range(100, 1000);
 626                count--;
 627        }
 628        WARN(count == 0, "timeout while leaving config mode");
 629}
 630
 631static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
 632{
 633        u32 status;
 634
 635        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 636        if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 637                return true;
 638
 639        return false;
 640}
 641
 642static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
 643{
 644        if (value)
 645                malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 646        else
 647                malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 648}
 649
 650static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 651{
 652        u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
 653
 654        malidp_hw_write(hwdev, hwdev->output_color_depth,
 655                hwdev->hw->map.out_depth_base);
 656        malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
 657        /*
 658         * Mali-DP550 and Mali-DP650 encode the background color like this:
 659         *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
 660         *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
 661         *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
 662         *
 663         * We need to truncate the least significant 4 bits from the default
 664         * MALIDP_BGND_COLOR_x values
 665         */
 666        val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
 667              (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
 668              ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
 669        malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
 670
 671        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 672                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 673        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 674
 675        val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
 676                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 677        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 678
 679        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 680                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 681        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 682                val |= MALIDP550_HSYNCPOL;
 683        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 684                val |= MALIDP550_VSYNCPOL;
 685        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 686
 687        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 688        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 689
 690        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 691                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 692        else
 693                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 694}
 695
 696static int malidpx50_get_bytes_per_column(u32 fmt)
 697{
 698        u32 bytes_per_column;
 699
 700        switch (fmt) {
 701        /* 8 lines at 4 bytes per pixel */
 702        case DRM_FORMAT_ARGB2101010:
 703        case DRM_FORMAT_ABGR2101010:
 704        case DRM_FORMAT_RGBA1010102:
 705        case DRM_FORMAT_BGRA1010102:
 706        case DRM_FORMAT_ARGB8888:
 707        case DRM_FORMAT_ABGR8888:
 708        case DRM_FORMAT_RGBA8888:
 709        case DRM_FORMAT_BGRA8888:
 710        case DRM_FORMAT_XRGB8888:
 711        case DRM_FORMAT_XBGR8888:
 712        case DRM_FORMAT_RGBX8888:
 713        case DRM_FORMAT_BGRX8888:
 714        case DRM_FORMAT_RGB888:
 715        case DRM_FORMAT_BGR888:
 716        /* 16 lines at 2 bytes per pixel */
 717        case DRM_FORMAT_RGBA5551:
 718        case DRM_FORMAT_ABGR1555:
 719        case DRM_FORMAT_RGB565:
 720        case DRM_FORMAT_BGR565:
 721        case DRM_FORMAT_UYVY:
 722        case DRM_FORMAT_YUYV:
 723        case DRM_FORMAT_X0L0:
 724                bytes_per_column = 32;
 725                break;
 726        /* 16 lines at 1.5 bytes per pixel */
 727        case DRM_FORMAT_NV12:
 728        case DRM_FORMAT_YUV420:
 729        /* 8 lines at 3 bytes per pixel */
 730        case DRM_FORMAT_VUY888:
 731        /* 16 lines at 12 bits per pixel */
 732        case DRM_FORMAT_YUV420_8BIT:
 733        /* 8 lines at 3 bytes per pixel */
 734        case DRM_FORMAT_P010:
 735                bytes_per_column = 24;
 736                break;
 737        /* 8 lines at 30 bits per pixel */
 738        case DRM_FORMAT_VUY101010:
 739        /* 16 lines at 15 bits per pixel */
 740        case DRM_FORMAT_YUV420_10BIT:
 741                bytes_per_column = 30;
 742                break;
 743        default:
 744                return -EINVAL;
 745        }
 746
 747        return bytes_per_column;
 748}
 749
 750static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
 751                                     u16 h, u32 fmt, bool has_modifier)
 752{
 753        int bytes_per_column = 0;
 754
 755        switch (fmt) {
 756        /* 8 lines at 15 bits per pixel */
 757        case DRM_FORMAT_YUV420_10BIT:
 758                bytes_per_column = 15;
 759                break;
 760        /* Uncompressed YUV 420 10 bit single plane cannot be rotated */
 761        case DRM_FORMAT_X0L2:
 762                if (has_modifier)
 763                        bytes_per_column = 8;
 764                else
 765                        return -EINVAL;
 766                break;
 767        default:
 768                bytes_per_column = malidpx50_get_bytes_per_column(fmt);
 769        }
 770
 771        if (bytes_per_column == -EINVAL)
 772                return bytes_per_column;
 773
 774        return w * bytes_per_column;
 775}
 776
 777static int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
 778                                     u16 h, u32 fmt, bool has_modifier)
 779{
 780        int bytes_per_column = 0;
 781
 782        switch (fmt) {
 783        /* 16 lines at 2 bytes per pixel */
 784        case DRM_FORMAT_X0L2:
 785                bytes_per_column = 32;
 786                break;
 787        default:
 788                bytes_per_column = malidpx50_get_bytes_per_column(fmt);
 789        }
 790
 791        if (bytes_per_column == -EINVAL)
 792                return bytes_per_column;
 793
 794        return w * bytes_per_column;
 795}
 796
 797static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 798                                           struct malidp_se_config *se_config,
 799                                           struct malidp_se_config *old_config)
 800{
 801        u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
 802                   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
 803        u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
 804                        MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
 805
 806        malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
 807        malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
 808        return 0;
 809}
 810
 811static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
 812                                   struct malidp_se_config *se_config,
 813                                   struct videomode *vm)
 814{
 815        unsigned long mclk;
 816        unsigned long pxlclk = vm->pixelclock;
 817        unsigned long htotal = vm->hactive + vm->hfront_porch +
 818                               vm->hback_porch + vm->hsync_len;
 819        unsigned long numerator = 1, denominator = 1;
 820        long ret;
 821
 822        if (se_config->scale_enable) {
 823                numerator = max(se_config->input_w, se_config->output_w) *
 824                            se_config->input_h;
 825                numerator += se_config->output_w *
 826                             (se_config->output_h -
 827                              min(se_config->input_h, se_config->output_h));
 828                denominator = (htotal - 2) * se_config->output_h;
 829        }
 830
 831        /* mclk can't be slower than pxlclk. */
 832        if (numerator < denominator)
 833                numerator = denominator = 1;
 834        mclk = (pxlclk * numerator) / denominator;
 835        ret = clk_get_rate(hwdev->mclk);
 836        if (ret < mclk) {
 837                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 838                                 mclk / 1000);
 839                return -EINVAL;
 840        }
 841        return ret;
 842}
 843
 844static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
 845                                     dma_addr_t *addrs, s32 *pitches,
 846                                     int num_planes, u16 w, u16 h, u32 fmt_id,
 847                                     const s16 *rgb2yuv_coeffs)
 848{
 849        u32 base = MALIDP550_SE_MEMWRITE_BASE;
 850        u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 851
 852        /* enable the scaling engine block */
 853        malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
 854
 855        hwdev->mw_state = MW_ONESHOT;
 856
 857        malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
 858        switch (num_planes) {
 859        case 2:
 860                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
 861                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
 862                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
 863                /* fall through */
 864        case 1:
 865                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
 866                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
 867                malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
 868                break;
 869        default:
 870                WARN(1, "Invalid number of planes");
 871        }
 872
 873        malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
 874                        MALIDP550_SE_MEMWRITE_OUT_SIZE);
 875        malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
 876                          MALIDP550_SE_CONTROL);
 877
 878        if (rgb2yuv_coeffs) {
 879                int i;
 880
 881                for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
 882                        malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
 883                                        MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
 884                }
 885        }
 886
 887        return 0;
 888}
 889
 890static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
 891{
 892        u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 893
 894        malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
 895                            MALIDP550_SE_CONTROL);
 896        malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
 897}
 898
 899static int malidp650_query_hw(struct malidp_hw_device *hwdev)
 900{
 901        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 902        u8 ln_size = (conf >> 4) & 0x3, rsize;
 903
 904        hwdev->min_line_size = 4;
 905
 906        switch (ln_size) {
 907        case 0:
 908        case 2:
 909                /* reserved values */
 910                hwdev->max_line_size = 0;
 911                return -EINVAL;
 912        case 1:
 913                hwdev->max_line_size = SZ_4K;
 914                /* two banks of 128KB for rotation memory */
 915                rsize = 128;
 916                break;
 917        case 3:
 918                hwdev->max_line_size = 2560;
 919                /* two banks of 80KB for rotation memory */
 920                rsize = 80;
 921        }
 922
 923        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 924        return 0;
 925}
 926
 927const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
 928        [MALIDP_500] = {
 929                .map = {
 930                        .coeffs_base = MALIDP500_COEFFS_BASE,
 931                        .se_base = MALIDP500_SE_BASE,
 932                        .dc_base = MALIDP500_DC_BASE,
 933                        .out_depth_base = MALIDP500_OUTPUT_DEPTH,
 934                        .features = 0,  /* no CLEARIRQ register */
 935                        .n_layers = ARRAY_SIZE(malidp500_layers),
 936                        .layers = malidp500_layers,
 937                        .de_irq_map = {
 938                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 939                                            MALIDP500_DE_IRQ_AXI_ERR |
 940                                            MALIDP500_DE_IRQ_VSYNC |
 941                                            MALIDP500_DE_IRQ_GLOBAL,
 942                                .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
 943                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
 944                                            MALIDP500_DE_IRQ_AXI_ERR |
 945                                            MALIDP500_DE_IRQ_SATURATION,
 946                        },
 947                        .se_irq_map = {
 948                                .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
 949                                            MALIDP500_SE_IRQ_CONF_VALID |
 950                                            MALIDP500_SE_IRQ_GLOBAL,
 951                                .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
 952                                .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
 953                                            MALIDP500_SE_IRQ_AXI_ERROR |
 954                                            MALIDP500_SE_IRQ_OVERRUN,
 955                        },
 956                        .dc_irq_map = {
 957                                .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
 958                                .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
 959                        },
 960                        .pixel_formats = malidp500_de_formats,
 961                        .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
 962                        .bus_align_bytes = 8,
 963                },
 964                .query_hw = malidp500_query_hw,
 965                .enter_config_mode = malidp500_enter_config_mode,
 966                .leave_config_mode = malidp500_leave_config_mode,
 967                .in_config_mode = malidp500_in_config_mode,
 968                .set_config_valid = malidp500_set_config_valid,
 969                .modeset = malidp500_modeset,
 970                .rotmem_required = malidp500_rotmem_required,
 971                .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
 972                .se_calc_mclk = malidp500_se_calc_mclk,
 973                .enable_memwrite = malidp500_enable_memwrite,
 974                .disable_memwrite = malidp500_disable_memwrite,
 975                .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
 976        },
 977        [MALIDP_550] = {
 978                .map = {
 979                        .coeffs_base = MALIDP550_COEFFS_BASE,
 980                        .se_base = MALIDP550_SE_BASE,
 981                        .dc_base = MALIDP550_DC_BASE,
 982                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
 983                        .features = MALIDP_REGMAP_HAS_CLEARIRQ |
 984                                    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
 985                                    MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
 986                                    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
 987                        .n_layers = ARRAY_SIZE(malidp550_layers),
 988                        .layers = malidp550_layers,
 989                        .de_irq_map = {
 990                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 991                                            MALIDP550_DE_IRQ_VSYNC,
 992                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
 993                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
 994                                            MALIDP550_DE_IRQ_SATURATION |
 995                                            MALIDP550_DE_IRQ_AXI_ERR,
 996                        },
 997                        .se_irq_map = {
 998                                .irq_mask = MALIDP550_SE_IRQ_EOW,
 999                                .vsync_irq = MALIDP550_SE_IRQ_EOW,
1000                                .err_mask  = MALIDP550_SE_IRQ_AXI_ERR |
1001                                             MALIDP550_SE_IRQ_OVR |
1002                                             MALIDP550_SE_IRQ_IBSY,
1003                        },
1004                        .dc_irq_map = {
1005                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
1006                                            MALIDP550_DC_IRQ_SE,
1007                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
1008                        },
1009                        .pixel_formats = malidp550_de_formats,
1010                        .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
1011                        .bus_align_bytes = 8,
1012                },
1013                .query_hw = malidp550_query_hw,
1014                .enter_config_mode = malidp550_enter_config_mode,
1015                .leave_config_mode = malidp550_leave_config_mode,
1016                .in_config_mode = malidp550_in_config_mode,
1017                .set_config_valid = malidp550_set_config_valid,
1018                .modeset = malidp550_modeset,
1019                .rotmem_required = malidp550_rotmem_required,
1020                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
1021                .se_calc_mclk = malidp550_se_calc_mclk,
1022                .enable_memwrite = malidp550_enable_memwrite,
1023                .disable_memwrite = malidp550_disable_memwrite,
1024                .features = 0,
1025        },
1026        [MALIDP_650] = {
1027                .map = {
1028                        .coeffs_base = MALIDP550_COEFFS_BASE,
1029                        .se_base = MALIDP550_SE_BASE,
1030                        .dc_base = MALIDP550_DC_BASE,
1031                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
1032                        .features = MALIDP_REGMAP_HAS_CLEARIRQ |
1033                                    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
1034                                    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
1035                        .n_layers = ARRAY_SIZE(malidp650_layers),
1036                        .layers = malidp650_layers,
1037                        .de_irq_map = {
1038                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
1039                                            MALIDP650_DE_IRQ_DRIFT |
1040                                            MALIDP550_DE_IRQ_VSYNC,
1041                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
1042                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
1043                                            MALIDP650_DE_IRQ_DRIFT |
1044                                            MALIDP550_DE_IRQ_SATURATION |
1045                                            MALIDP550_DE_IRQ_AXI_ERR |
1046                                            MALIDP650_DE_IRQ_ACEV1 |
1047                                            MALIDP650_DE_IRQ_ACEV2 |
1048                                            MALIDP650_DE_IRQ_ACEG |
1049                                            MALIDP650_DE_IRQ_AXIEP,
1050                        },
1051                        .se_irq_map = {
1052                                .irq_mask = MALIDP550_SE_IRQ_EOW,
1053                                .vsync_irq = MALIDP550_SE_IRQ_EOW,
1054                                .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
1055                                            MALIDP550_SE_IRQ_OVR |
1056                                            MALIDP550_SE_IRQ_IBSY,
1057                        },
1058                        .dc_irq_map = {
1059                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
1060                                            MALIDP550_DC_IRQ_SE,
1061                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
1062                        },
1063                        .pixel_formats = malidp650_de_formats,
1064                        .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
1065                        .bus_align_bytes = 16,
1066                },
1067                .query_hw = malidp650_query_hw,
1068                .enter_config_mode = malidp550_enter_config_mode,
1069                .leave_config_mode = malidp550_leave_config_mode,
1070                .in_config_mode = malidp550_in_config_mode,
1071                .set_config_valid = malidp550_set_config_valid,
1072                .modeset = malidp550_modeset,
1073                .rotmem_required = malidp650_rotmem_required,
1074                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
1075                .se_calc_mclk = malidp550_se_calc_mclk,
1076                .enable_memwrite = malidp550_enable_memwrite,
1077                .disable_memwrite = malidp550_disable_memwrite,
1078                .features = 0,
1079        },
1080};
1081
1082u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
1083                           u8 layer_id, u32 format, bool has_modifier)
1084{
1085        unsigned int i;
1086
1087        for (i = 0; i < map->n_pixel_formats; i++) {
1088                if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
1089                    (map->pixel_formats[i].format == format)) {
1090                        /*
1091                         * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier
1092                         * is supported by a different h/w format id than
1093                         * DRM_FORMAT_YUYV (only).
1094                         */
1095                        if (format == DRM_FORMAT_YUYV &&
1096                            (has_modifier) &&
1097                            (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2))
1098                                return AFBC_YUV_422_FORMAT_ID;
1099                        else
1100                                return map->pixel_formats[i].id;
1101                }
1102        }
1103
1104        return MALIDP_INVALID_FORMAT_ID;
1105}
1106
1107bool malidp_hw_format_is_linear_only(u32 format)
1108{
1109        switch (format) {
1110        case DRM_FORMAT_ARGB2101010:
1111        case DRM_FORMAT_RGBA1010102:
1112        case DRM_FORMAT_BGRA1010102:
1113        case DRM_FORMAT_ARGB8888:
1114        case DRM_FORMAT_RGBA8888:
1115        case DRM_FORMAT_BGRA8888:
1116        case DRM_FORMAT_XBGR8888:
1117        case DRM_FORMAT_XRGB8888:
1118        case DRM_FORMAT_RGBX8888:
1119        case DRM_FORMAT_BGRX8888:
1120        case DRM_FORMAT_RGB888:
1121        case DRM_FORMAT_RGB565:
1122        case DRM_FORMAT_ARGB1555:
1123        case DRM_FORMAT_RGBA5551:
1124        case DRM_FORMAT_BGRA5551:
1125        case DRM_FORMAT_UYVY:
1126        case DRM_FORMAT_XYUV8888:
1127        case DRM_FORMAT_XVYU2101010:
1128        case DRM_FORMAT_X0L2:
1129        case DRM_FORMAT_X0L0:
1130                return true;
1131        default:
1132                return false;
1133        }
1134}
1135
1136bool malidp_hw_format_is_afbc_only(u32 format)
1137{
1138        switch (format) {
1139        case DRM_FORMAT_VUY888:
1140        case DRM_FORMAT_VUY101010:
1141        case DRM_FORMAT_YUV420_8BIT:
1142        case DRM_FORMAT_YUV420_10BIT:
1143                return true;
1144        default:
1145                return false;
1146        }
1147}
1148
1149static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
1150{
1151        u32 base = malidp_get_block_base(hwdev, block);
1152
1153        if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
1154                malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
1155        else
1156                malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
1157}
1158
1159static irqreturn_t malidp_de_irq(int irq, void *arg)
1160{
1161        struct drm_device *drm = arg;
1162        struct malidp_drm *malidp = drm->dev_private;
1163        struct malidp_hw_device *hwdev;
1164        struct malidp_hw *hw;
1165        const struct malidp_irq_map *de;
1166        u32 status, mask, dc_status;
1167        irqreturn_t ret = IRQ_NONE;
1168
1169        hwdev = malidp->dev;
1170        hw = hwdev->hw;
1171        de = &hw->map.de_irq_map;
1172
1173        /*
1174         * if we are suspended it is likely that we were invoked because
1175         * we share an interrupt line with some other driver, don't try
1176         * to read the hardware registers
1177         */
1178        if (hwdev->pm_suspended)
1179                return IRQ_NONE;
1180
1181        /* first handle the config valid IRQ */
1182        dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1183        if (dc_status & hw->map.dc_irq_map.vsync_irq) {
1184                malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
1185                /* do we have a page flip event? */
1186                if (malidp->event != NULL) {
1187                        spin_lock(&drm->event_lock);
1188                        drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
1189                        malidp->event = NULL;
1190                        spin_unlock(&drm->event_lock);
1191                }
1192                atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
1193                ret = IRQ_WAKE_THREAD;
1194        }
1195
1196        status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
1197        if (!(status & de->irq_mask))
1198                return ret;
1199
1200        mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
1201        /* keep the status of the enabled interrupts, plus the error bits */
1202        status &= (mask | de->err_mask);
1203        if ((status & de->vsync_irq) && malidp->crtc.enabled)
1204                drm_crtc_handle_vblank(&malidp->crtc);
1205
1206#ifdef CONFIG_DEBUG_FS
1207        if (status & de->err_mask) {
1208                malidp_error(malidp, &malidp->de_errors, status,
1209                             drm_crtc_vblank_count(&malidp->crtc));
1210        }
1211#endif
1212        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
1213
1214        return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
1215}
1216
1217static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1218{
1219        struct drm_device *drm = arg;
1220        struct malidp_drm *malidp = drm->dev_private;
1221
1222        wake_up(&malidp->wq);
1223
1224        return IRQ_HANDLED;
1225}
1226
1227void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
1228{
1229        /* ensure interrupts are disabled */
1230        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1231        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1232        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1233        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1234
1235        /* first enable the DC block IRQs */
1236        malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
1237                             hwdev->hw->map.dc_irq_map.irq_mask);
1238
1239        /* now enable the DE block IRQs */
1240        malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
1241                             hwdev->hw->map.de_irq_map.irq_mask);
1242}
1243
1244int malidp_de_irq_init(struct drm_device *drm, int irq)
1245{
1246        struct malidp_drm *malidp = drm->dev_private;
1247        struct malidp_hw_device *hwdev = malidp->dev;
1248        int ret;
1249
1250        /* ensure interrupts are disabled */
1251        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1252        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1253        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1254        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1255
1256        ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
1257                                        malidp_de_irq_thread_handler,
1258                                        IRQF_SHARED, "malidp-de", drm);
1259        if (ret < 0) {
1260                DRM_ERROR("failed to install DE IRQ handler\n");
1261                return ret;
1262        }
1263
1264        malidp_de_irq_hw_init(hwdev);
1265
1266        return 0;
1267}
1268
1269void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
1270{
1271        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
1272                              hwdev->hw->map.de_irq_map.irq_mask);
1273        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
1274                              hwdev->hw->map.dc_irq_map.irq_mask);
1275}
1276
1277static irqreturn_t malidp_se_irq(int irq, void *arg)
1278{
1279        struct drm_device *drm = arg;
1280        struct malidp_drm *malidp = drm->dev_private;
1281        struct malidp_hw_device *hwdev = malidp->dev;
1282        struct malidp_hw *hw = hwdev->hw;
1283        const struct malidp_irq_map *se = &hw->map.se_irq_map;
1284        u32 status, mask;
1285
1286        /*
1287         * if we are suspended it is likely that we were invoked because
1288         * we share an interrupt line with some other driver, don't try
1289         * to read the hardware registers
1290         */
1291        if (hwdev->pm_suspended)
1292                return IRQ_NONE;
1293
1294        status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
1295        if (!(status & (se->irq_mask | se->err_mask)))
1296                return IRQ_NONE;
1297
1298#ifdef CONFIG_DEBUG_FS
1299        if (status & se->err_mask)
1300                malidp_error(malidp, &malidp->se_errors, status,
1301                             drm_crtc_vblank_count(&malidp->crtc));
1302#endif
1303        mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
1304        status &= mask;
1305
1306        if (status & se->vsync_irq) {
1307                switch (hwdev->mw_state) {
1308                case MW_ONESHOT:
1309                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1310                        break;
1311                case MW_STOP:
1312                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1313                        /* disable writeback after stop */
1314                        hwdev->mw_state = MW_NOT_ENABLED;
1315                        break;
1316                case MW_RESTART:
1317                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1318                        /* fall through - to a new start */
1319                case MW_START:
1320                        /* writeback started, need to emulate one-shot mode */
1321                        hw->disable_memwrite(hwdev);
1322                        /*
1323                         * only set config_valid HW bit if there is no other update
1324                         * in progress or if we raced ahead of the DE IRQ handler
1325                         * and config_valid flag will not be update until later
1326                         */
1327                        status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1328                        if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1329                            (status & hw->map.dc_irq_map.vsync_irq))
1330                                hw->set_config_valid(hwdev, 1);
1331                        break;
1332                }
1333        }
1334
1335        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1336
1337        return IRQ_HANDLED;
1338}
1339
1340void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
1341{
1342        /* ensure interrupts are disabled */
1343        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1344        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1345
1346        malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1347                             hwdev->hw->map.se_irq_map.irq_mask);
1348}
1349
1350static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1351{
1352        return IRQ_HANDLED;
1353}
1354
1355int malidp_se_irq_init(struct drm_device *drm, int irq)
1356{
1357        struct malidp_drm *malidp = drm->dev_private;
1358        struct malidp_hw_device *hwdev = malidp->dev;
1359        int ret;
1360
1361        /* ensure interrupts are disabled */
1362        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1363        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1364
1365        ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1366                                        malidp_se_irq_thread_handler,
1367                                        IRQF_SHARED, "malidp-se", drm);
1368        if (ret < 0) {
1369                DRM_ERROR("failed to install SE IRQ handler\n");
1370                return ret;
1371        }
1372
1373        hwdev->mw_state = MW_NOT_ENABLED;
1374        malidp_se_irq_hw_init(hwdev);
1375
1376        return 0;
1377}
1378
1379void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1380{
1381        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1382                              hwdev->hw->map.se_irq_map.irq_mask);
1383}
1384