Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
0004  * Author: Liviu Dudau <Liviu.Dudau@arm.com>
0005  *
0006  * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
0007  * the difference between various versions of the hardware is being dealt with
0008  * in an attempt to provide to the rest of the driver code a unified view
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/delay.h>
0013 #include <linux/types.h>
0014 #include <linux/io.h>
0015 
0016 #include <video/videomode.h>
0017 #include <video/display_timing.h>
0018 
0019 #include <drm/drm_fourcc.h>
0020 #include <drm/drm_vblank.h>
0021 #include <drm/drm_print.h>
0022 
0023 #include "malidp_drv.h"
0024 #include "malidp_hw.h"
0025 #include "malidp_mw.h"
0026 
0027 enum {
0028     MW_NOT_ENABLED = 0, /* SE writeback not enabled */
0029     MW_ONESHOT,     /* SE in one-shot mode for writeback */
0030     MW_START,       /* SE started writeback */
0031     MW_RESTART,     /* SE will start another writeback after this one */
0032     MW_STOP,        /* SE needs to stop after this writeback */
0033 };
0034 
0035 static const struct malidp_format_id malidp500_de_formats[] = {
0036     /*    fourcc,   layers supporting the format,     internal id  */
0037     { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  0 },
0038     { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  1 },
0039     { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
0040     { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
0041     { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  4 },
0042     { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  5 },
0043     { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
0044     { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
0045     { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
0046     { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
0047     { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
0048     { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
0049     { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
0050     { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
0051     { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
0052     { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
0053     { DRM_FORMAT_XYUV8888, DE_VIDEO1, 16 },
0054     /* These are supported with AFBC only */
0055     { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1, 14 },
0056     { DRM_FORMAT_VUY888, DE_VIDEO1, 16 },
0057     { DRM_FORMAT_VUY101010, DE_VIDEO1, 17 },
0058     { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1, 18 }
0059 };
0060 
0061 #define MALIDP_ID(__group, __format) \
0062     ((((__group) & 0x7) << 3) | ((__format) & 0x7))
0063 
0064 #define AFBC_YUV_422_FORMAT_ID  MALIDP_ID(5, 1)
0065 
0066 #define MALIDP_COMMON_FORMATS \
0067     /*    fourcc,   layers supporting the format,      internal id   */ \
0068     { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
0069     { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \
0070     { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \
0071     { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \
0072     { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
0073     { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
0074     { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
0075     { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
0076     { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \
0077     { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \
0078     { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \
0079     { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \
0080     { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \
0081     { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \
0082     { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
0083     { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
0084     { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
0085     { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
0086     /* This is only supported with linear modifier */   \
0087     { DRM_FORMAT_XYUV8888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) },\
0088     /* This is only supported with AFBC modifier */     \
0089     { DRM_FORMAT_VUY888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) }, \
0090     { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },    \
0091     /* This is only supported with linear modifier */ \
0092     { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },    \
0093     { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },  \
0094     /* This is only supported with AFBC modifier */ \
0095     { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
0096     { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
0097     /* This is only supported with linear modifier */ \
0098     { DRM_FORMAT_XVYU2101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
0099     /* This is only supported with AFBC modifier */ \
0100     { DRM_FORMAT_VUY101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
0101     { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}, \
0102     /* This is only supported with AFBC modifier */ \
0103     { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}, \
0104     { DRM_FORMAT_P010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}
0105 
0106 static const struct malidp_format_id malidp550_de_formats[] = {
0107     MALIDP_COMMON_FORMATS,
0108 };
0109 
0110 static const struct malidp_format_id malidp650_de_formats[] = {
0111     MALIDP_COMMON_FORMATS,
0112     { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
0113 };
0114 
0115 static const struct malidp_layer malidp500_layers[] = {
0116     /* id, base address, fb pointer address base, stride offset,
0117      *  yuv2rgb matrix offset, mmu control register offset, rotation_features
0118      */
0119     { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
0120         MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY,
0121         MALIDP500_DE_LV_AD_CTRL },
0122     { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
0123         MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
0124         MALIDP500_DE_LG1_AD_CTRL },
0125     { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
0126         MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
0127         MALIDP500_DE_LG2_AD_CTRL },
0128 };
0129 
0130 static const struct malidp_layer malidp550_layers[] = {
0131     /* id, base address, fb pointer address base, stride offset,
0132      *  yuv2rgb matrix offset, mmu control register offset, rotation_features
0133      */
0134     { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
0135         MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
0136         MALIDP550_DE_LV1_AD_CTRL },
0137     { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
0138         MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
0139         MALIDP550_DE_LG_AD_CTRL },
0140     { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
0141         MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
0142         MALIDP550_DE_LV2_AD_CTRL },
0143     { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
0144         MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 },
0145 };
0146 
0147 static const struct malidp_layer malidp650_layers[] = {
0148     /* id, base address, fb pointer address base, stride offset,
0149      *  yuv2rgb matrix offset, mmu control register offset,
0150      *  rotation_features
0151      */
0152     { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
0153         MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
0154         MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
0155         MALIDP550_DE_LV1_AD_CTRL },
0156     { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
0157         MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
0158         ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL },
0159     { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
0160         MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
0161         MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
0162         MALIDP550_DE_LV2_AD_CTRL },
0163     { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
0164         MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
0165         ROTATE_NONE, 0 },
0166 };
0167 
0168 const u64 malidp_format_modifiers[] = {
0169     /* All RGB formats (except XRGB, RGBX, XBGR, BGRX) */
0170     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE),
0171     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR),
0172 
0173     /* All RGB formats > 16bpp (except XRGB, RGBX, XBGR, BGRX) */
0174     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE | AFBC_SPLIT),
0175 
0176     /* All 8 or 10 bit YUV 444 formats. */
0177     /* In DP550, 10 bit YUV 420 format also supported */
0178     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT),
0179 
0180     /* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */
0181     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE),
0182     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16),
0183 
0184     /* YUV 420, 422 P1 8, 10 bit formats */
0185     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR | AFBC_SPARSE),
0186     DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR),
0187 
0188     /* All formats */
0189     DRM_FORMAT_MOD_LINEAR,
0190 
0191     DRM_FORMAT_MOD_INVALID
0192 };
0193 
0194 #define SE_N_SCALING_COEFFS 96
0195 static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
0196     [MALIDP_UPSCALING_COEFFS - 1] = {
0197         0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
0198         0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
0199         0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
0200         0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
0201         0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
0202         0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
0203         0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
0204         0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
0205         0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
0206         0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
0207         0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
0208         0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
0209     },
0210     [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
0211         0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
0212         0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
0213         0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
0214         0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
0215         0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
0216         0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
0217         0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
0218         0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
0219         0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
0220         0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
0221         0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
0222         0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
0223     },
0224     [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
0225         0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
0226         0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
0227         0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
0228         0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
0229         0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
0230         0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
0231         0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
0232         0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
0233         0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
0234         0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
0235         0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
0236         0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
0237     },
0238     [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
0239         0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
0240         0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
0241         0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
0242         0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
0243         0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
0244         0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
0245         0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
0246         0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
0247         0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
0248         0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
0249         0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
0250         0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
0251     },
0252     [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
0253         0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
0254         0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
0255         0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
0256         0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
0257         0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
0258         0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
0259         0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
0260         0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
0261         0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
0262         0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
0263         0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
0264         0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
0265     },
0266 };
0267 
0268 #define MALIDP_DE_DEFAULT_PREFETCH_START    5
0269 
0270 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
0271 {
0272     u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
0273     /* bit 4 of the CONFIG_ID register holds the line size multiplier */
0274     u8 ln_size_mult = conf & 0x10 ? 2 : 1;
0275 
0276     hwdev->min_line_size = 2;
0277     hwdev->max_line_size = SZ_2K * ln_size_mult;
0278     hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
0279     hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
0280 
0281     return 0;
0282 }
0283 
0284 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
0285 {
0286     u32 status, count = 100;
0287 
0288     malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
0289     while (count) {
0290         status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
0291         if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
0292             break;
0293         /*
0294          * entering config mode can take as long as the rendering
0295          * of a full frame, hence the long sleep here
0296          */
0297         usleep_range(1000, 10000);
0298         count--;
0299     }
0300     WARN(count == 0, "timeout while entering config mode");
0301 }
0302 
0303 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
0304 {
0305     u32 status, count = 100;
0306 
0307     malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
0308     malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
0309     while (count) {
0310         status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
0311         if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
0312             break;
0313         usleep_range(100, 1000);
0314         count--;
0315     }
0316     WARN(count == 0, "timeout while leaving config mode");
0317 }
0318 
0319 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
0320 {
0321     u32 status;
0322 
0323     status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
0324     if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
0325         return true;
0326 
0327     return false;
0328 }
0329 
0330 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
0331 {
0332     if (value)
0333         malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
0334     else
0335         malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
0336 }
0337 
0338 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
0339 {
0340     u32 val = 0;
0341 
0342     malidp_hw_write(hwdev, hwdev->output_color_depth,
0343         hwdev->hw->map.out_depth_base);
0344     malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
0345     if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
0346         val |= MALIDP500_HSYNCPOL;
0347     if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
0348         val |= MALIDP500_VSYNCPOL;
0349     val |= MALIDP_DE_DEFAULT_PREFETCH_START;
0350     malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
0351 
0352     /*
0353      * Mali-DP500 encodes the background color like this:
0354      *    - red   @ MALIDP500_BGND_COLOR[12:0]
0355      *    - green @ MALIDP500_BGND_COLOR[27:16]
0356      *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
0357      */
0358     val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
0359           (MALIDP_BGND_COLOR_R & 0xfff);
0360     malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
0361     malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
0362 
0363     val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
0364         MALIDP_DE_H_BACKPORCH(mode->hback_porch);
0365     malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
0366 
0367     val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
0368         MALIDP_DE_V_BACKPORCH(mode->vback_porch);
0369     malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
0370 
0371     val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
0372         MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
0373     malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
0374 
0375     val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
0376     malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
0377 
0378     if (mode->flags & DISPLAY_FLAGS_INTERLACED)
0379         malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
0380     else
0381         malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
0382 
0383     /*
0384      * Program the RQoS register to avoid high resolutions flicker
0385      * issue on the LS1028A.
0386      */
0387     if (hwdev->arqos_value) {
0388         val = hwdev->arqos_value;
0389         malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY);
0390     }
0391 }
0392 
0393 int malidp_format_get_bpp(u32 fmt)
0394 {
0395     const struct drm_format_info *info = drm_format_info(fmt);
0396     int bpp = info->cpp[0] * 8;
0397 
0398     if (bpp == 0) {
0399         switch (fmt) {
0400         case DRM_FORMAT_VUY101010:
0401             bpp = 30;
0402             break;
0403         case DRM_FORMAT_YUV420_10BIT:
0404             bpp = 15;
0405             break;
0406         case DRM_FORMAT_YUV420_8BIT:
0407             bpp = 12;
0408             break;
0409         default:
0410             bpp = 0;
0411         }
0412     }
0413 
0414     return bpp;
0415 }
0416 
0417 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
0418                      u16 h, u32 fmt, bool has_modifier)
0419 {
0420     /*
0421      * Each layer needs enough rotation memory to fit 8 lines
0422      * worth of pixel data. Required size is then:
0423      *    size = rotated_width * (bpp / 8) * 8;
0424      */
0425     int bpp = malidp_format_get_bpp(fmt);
0426 
0427     return w * bpp;
0428 }
0429 
0430 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
0431                        u32 direction,
0432                        u16 addr,
0433                        u8 coeffs_id)
0434 {
0435     int i;
0436     u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
0437 
0438     malidp_hw_write(hwdev,
0439             direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
0440             scaling_control + MALIDP_SE_COEFFTAB_ADDR);
0441     for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
0442         malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
0443                 dp500_se_scaling_coeffs[coeffs_id][i]),
0444                 scaling_control + MALIDP_SE_COEFFTAB_DATA);
0445 }
0446 
0447 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
0448                        struct malidp_se_config *se_config,
0449                        struct malidp_se_config *old_config)
0450 {
0451     /* Get array indices into dp500_se_scaling_coeffs. */
0452     u8 h = (u8)se_config->hcoeff - 1;
0453     u8 v = (u8)se_config->vcoeff - 1;
0454 
0455     if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
0456             v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
0457         return -EINVAL;
0458 
0459     if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
0460              se_config->vcoeff != old_config->vcoeff)) {
0461         malidp500_se_write_pp_coefftab(hwdev,
0462                            (MALIDP_SE_V_COEFFTAB |
0463                         MALIDP_SE_H_COEFFTAB),
0464                            0, v);
0465     } else {
0466         if (se_config->vcoeff != old_config->vcoeff)
0467             malidp500_se_write_pp_coefftab(hwdev,
0468                                MALIDP_SE_V_COEFFTAB,
0469                                0, v);
0470         if (se_config->hcoeff != old_config->hcoeff)
0471             malidp500_se_write_pp_coefftab(hwdev,
0472                                MALIDP_SE_H_COEFFTAB,
0473                                0, h);
0474     }
0475 
0476     return 0;
0477 }
0478 
0479 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
0480                    struct malidp_se_config *se_config,
0481                    struct videomode *vm)
0482 {
0483     unsigned long mclk;
0484     unsigned long pxlclk = vm->pixelclock; /* Hz */
0485     unsigned long htotal = vm->hactive + vm->hfront_porch +
0486                    vm->hback_porch + vm->hsync_len;
0487     unsigned long input_size = se_config->input_w * se_config->input_h;
0488     unsigned long a = 10;
0489     long ret;
0490 
0491     /*
0492      * mclk = max(a, 1.5) * pxlclk
0493      *
0494      * To avoid float calculaiton, using 15 instead of 1.5 and div by
0495      * 10 to get mclk.
0496      */
0497     if (se_config->scale_enable) {
0498         a = 15 * input_size / (htotal * se_config->output_h);
0499         if (a < 15)
0500             a = 15;
0501     }
0502     mclk = a * pxlclk / 10;
0503     ret = clk_get_rate(hwdev->mclk);
0504     if (ret < mclk) {
0505         DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
0506                  mclk / 1000);
0507         return -EINVAL;
0508     }
0509     return ret;
0510 }
0511 
0512 static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
0513                      dma_addr_t *addrs, s32 *pitches,
0514                      int num_planes, u16 w, u16 h, u32 fmt_id,
0515                      const s16 *rgb2yuv_coeffs)
0516 {
0517     u32 base = MALIDP500_SE_MEMWRITE_BASE;
0518     u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
0519 
0520     /* enable the scaling engine block */
0521     malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
0522 
0523     /* restart the writeback if already enabled */
0524     if (hwdev->mw_state != MW_NOT_ENABLED)
0525         hwdev->mw_state = MW_RESTART;
0526     else
0527         hwdev->mw_state = MW_START;
0528 
0529     malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
0530     switch (num_planes) {
0531     case 2:
0532         malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
0533         malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
0534         malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
0535         fallthrough;
0536     case 1:
0537         malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
0538         malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
0539         malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
0540         break;
0541     default:
0542         WARN(1, "Invalid number of planes");
0543     }
0544 
0545     malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
0546             MALIDP500_SE_MEMWRITE_OUT_SIZE);
0547 
0548     if (rgb2yuv_coeffs) {
0549         int i;
0550 
0551         for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
0552             malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
0553                     MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
0554         }
0555     }
0556 
0557     malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
0558 
0559     return 0;
0560 }
0561 
0562 static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
0563 {
0564     u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
0565 
0566     if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
0567         hwdev->mw_state = MW_STOP;
0568     malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
0569     malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
0570 }
0571 
0572 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
0573 {
0574     u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
0575     u8 ln_size = (conf >> 4) & 0x3, rsize;
0576 
0577     hwdev->min_line_size = 2;
0578 
0579     switch (ln_size) {
0580     case 0:
0581         hwdev->max_line_size = SZ_2K;
0582         /* two banks of 64KB for rotation memory */
0583         rsize = 64;
0584         break;
0585     case 1:
0586         hwdev->max_line_size = SZ_4K;
0587         /* two banks of 128KB for rotation memory */
0588         rsize = 128;
0589         break;
0590     case 2:
0591         hwdev->max_line_size = 1280;
0592         /* two banks of 40KB for rotation memory */
0593         rsize = 40;
0594         break;
0595     case 3:
0596         /* reserved value */
0597         hwdev->max_line_size = 0;
0598         return -EINVAL;
0599     }
0600 
0601     hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
0602     return 0;
0603 }
0604 
0605 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
0606 {
0607     u32 status, count = 100;
0608 
0609     malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
0610     while (count) {
0611         status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
0612         if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
0613             break;
0614         /*
0615          * entering config mode can take as long as the rendering
0616          * of a full frame, hence the long sleep here
0617          */
0618         usleep_range(1000, 10000);
0619         count--;
0620     }
0621     WARN(count == 0, "timeout while entering config mode");
0622 }
0623 
0624 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
0625 {
0626     u32 status, count = 100;
0627 
0628     malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
0629     malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
0630     while (count) {
0631         status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
0632         if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
0633             break;
0634         usleep_range(100, 1000);
0635         count--;
0636     }
0637     WARN(count == 0, "timeout while leaving config mode");
0638 }
0639 
0640 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
0641 {
0642     u32 status;
0643 
0644     status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
0645     if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
0646         return true;
0647 
0648     return false;
0649 }
0650 
0651 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
0652 {
0653     if (value)
0654         malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
0655     else
0656         malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
0657 }
0658 
0659 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
0660 {
0661     u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
0662 
0663     malidp_hw_write(hwdev, hwdev->output_color_depth,
0664         hwdev->hw->map.out_depth_base);
0665     malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
0666     /*
0667      * Mali-DP550 and Mali-DP650 encode the background color like this:
0668      *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
0669      *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
0670      *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
0671      *
0672      * We need to truncate the least significant 4 bits from the default
0673      * MALIDP_BGND_COLOR_x values
0674      */
0675     val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
0676           (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
0677           ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
0678     malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
0679 
0680     val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
0681         MALIDP_DE_H_BACKPORCH(mode->hback_porch);
0682     malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
0683 
0684     val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
0685         MALIDP_DE_V_BACKPORCH(mode->vback_porch);
0686     malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
0687 
0688     val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
0689         MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
0690     if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
0691         val |= MALIDP550_HSYNCPOL;
0692     if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
0693         val |= MALIDP550_VSYNCPOL;
0694     malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
0695 
0696     val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
0697     malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
0698 
0699     if (mode->flags & DISPLAY_FLAGS_INTERLACED)
0700         malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
0701     else
0702         malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
0703 }
0704 
0705 static int malidpx50_get_bytes_per_column(u32 fmt)
0706 {
0707     u32 bytes_per_column;
0708 
0709     switch (fmt) {
0710     /* 8 lines at 4 bytes per pixel */
0711     case DRM_FORMAT_ARGB2101010:
0712     case DRM_FORMAT_ABGR2101010:
0713     case DRM_FORMAT_RGBA1010102:
0714     case DRM_FORMAT_BGRA1010102:
0715     case DRM_FORMAT_ARGB8888:
0716     case DRM_FORMAT_ABGR8888:
0717     case DRM_FORMAT_RGBA8888:
0718     case DRM_FORMAT_BGRA8888:
0719     case DRM_FORMAT_XRGB8888:
0720     case DRM_FORMAT_XBGR8888:
0721     case DRM_FORMAT_RGBX8888:
0722     case DRM_FORMAT_BGRX8888:
0723     case DRM_FORMAT_RGB888:
0724     case DRM_FORMAT_BGR888:
0725     /* 16 lines at 2 bytes per pixel */
0726     case DRM_FORMAT_RGBA5551:
0727     case DRM_FORMAT_ABGR1555:
0728     case DRM_FORMAT_RGB565:
0729     case DRM_FORMAT_BGR565:
0730     case DRM_FORMAT_UYVY:
0731     case DRM_FORMAT_YUYV:
0732     case DRM_FORMAT_X0L0:
0733         bytes_per_column = 32;
0734         break;
0735     /* 16 lines at 1.5 bytes per pixel */
0736     case DRM_FORMAT_NV12:
0737     case DRM_FORMAT_YUV420:
0738     /* 8 lines at 3 bytes per pixel */
0739     case DRM_FORMAT_VUY888:
0740     /* 16 lines at 12 bits per pixel */
0741     case DRM_FORMAT_YUV420_8BIT:
0742     /* 8 lines at 3 bytes per pixel */
0743     case DRM_FORMAT_P010:
0744         bytes_per_column = 24;
0745         break;
0746     /* 8 lines at 30 bits per pixel */
0747     case DRM_FORMAT_VUY101010:
0748     /* 16 lines at 15 bits per pixel */
0749     case DRM_FORMAT_YUV420_10BIT:
0750         bytes_per_column = 30;
0751         break;
0752     default:
0753         return -EINVAL;
0754     }
0755 
0756     return bytes_per_column;
0757 }
0758 
0759 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
0760                      u16 h, u32 fmt, bool has_modifier)
0761 {
0762     int bytes_per_column = 0;
0763 
0764     switch (fmt) {
0765     /* 8 lines at 15 bits per pixel */
0766     case DRM_FORMAT_YUV420_10BIT:
0767         bytes_per_column = 15;
0768         break;
0769     /* Uncompressed YUV 420 10 bit single plane cannot be rotated */
0770     case DRM_FORMAT_X0L2:
0771         if (has_modifier)
0772             bytes_per_column = 8;
0773         else
0774             return -EINVAL;
0775         break;
0776     default:
0777         bytes_per_column = malidpx50_get_bytes_per_column(fmt);
0778     }
0779 
0780     if (bytes_per_column == -EINVAL)
0781         return bytes_per_column;
0782 
0783     return w * bytes_per_column;
0784 }
0785 
0786 static int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
0787                      u16 h, u32 fmt, bool has_modifier)
0788 {
0789     int bytes_per_column = 0;
0790 
0791     switch (fmt) {
0792     /* 16 lines at 2 bytes per pixel */
0793     case DRM_FORMAT_X0L2:
0794         bytes_per_column = 32;
0795         break;
0796     default:
0797         bytes_per_column = malidpx50_get_bytes_per_column(fmt);
0798     }
0799 
0800     if (bytes_per_column == -EINVAL)
0801         return bytes_per_column;
0802 
0803     return w * bytes_per_column;
0804 }
0805 
0806 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
0807                        struct malidp_se_config *se_config,
0808                        struct malidp_se_config *old_config)
0809 {
0810     u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
0811            MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
0812     u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
0813             MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
0814 
0815     malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
0816     malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
0817     return 0;
0818 }
0819 
0820 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
0821                    struct malidp_se_config *se_config,
0822                    struct videomode *vm)
0823 {
0824     unsigned long mclk;
0825     unsigned long pxlclk = vm->pixelclock;
0826     unsigned long htotal = vm->hactive + vm->hfront_porch +
0827                    vm->hback_porch + vm->hsync_len;
0828     unsigned long numerator = 1, denominator = 1;
0829     long ret;
0830 
0831     if (se_config->scale_enable) {
0832         numerator = max(se_config->input_w, se_config->output_w) *
0833                 se_config->input_h;
0834         numerator += se_config->output_w *
0835                  (se_config->output_h -
0836                   min(se_config->input_h, se_config->output_h));
0837         denominator = (htotal - 2) * se_config->output_h;
0838     }
0839 
0840     /* mclk can't be slower than pxlclk. */
0841     if (numerator < denominator)
0842         numerator = denominator = 1;
0843     mclk = (pxlclk * numerator) / denominator;
0844     ret = clk_get_rate(hwdev->mclk);
0845     if (ret < mclk) {
0846         DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
0847                  mclk / 1000);
0848         return -EINVAL;
0849     }
0850     return ret;
0851 }
0852 
0853 static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
0854                      dma_addr_t *addrs, s32 *pitches,
0855                      int num_planes, u16 w, u16 h, u32 fmt_id,
0856                      const s16 *rgb2yuv_coeffs)
0857 {
0858     u32 base = MALIDP550_SE_MEMWRITE_BASE;
0859     u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
0860 
0861     /* enable the scaling engine block */
0862     malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
0863 
0864     hwdev->mw_state = MW_ONESHOT;
0865 
0866     malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
0867     switch (num_planes) {
0868     case 2:
0869         malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
0870         malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
0871         malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
0872         fallthrough;
0873     case 1:
0874         malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
0875         malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
0876         malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
0877         break;
0878     default:
0879         WARN(1, "Invalid number of planes");
0880     }
0881 
0882     malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
0883             MALIDP550_SE_MEMWRITE_OUT_SIZE);
0884     malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
0885               MALIDP550_SE_CONTROL);
0886 
0887     if (rgb2yuv_coeffs) {
0888         int i;
0889 
0890         for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
0891             malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
0892                     MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
0893         }
0894     }
0895 
0896     return 0;
0897 }
0898 
0899 static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
0900 {
0901     u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
0902 
0903     malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
0904                 MALIDP550_SE_CONTROL);
0905     malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
0906 }
0907 
0908 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
0909 {
0910     u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
0911     u8 ln_size = (conf >> 4) & 0x3, rsize;
0912 
0913     hwdev->min_line_size = 4;
0914 
0915     switch (ln_size) {
0916     case 0:
0917     case 2:
0918         /* reserved values */
0919         hwdev->max_line_size = 0;
0920         return -EINVAL;
0921     case 1:
0922         hwdev->max_line_size = SZ_4K;
0923         /* two banks of 128KB for rotation memory */
0924         rsize = 128;
0925         break;
0926     case 3:
0927         hwdev->max_line_size = 2560;
0928         /* two banks of 80KB for rotation memory */
0929         rsize = 80;
0930     }
0931 
0932     hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
0933     return 0;
0934 }
0935 
0936 const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
0937     [MALIDP_500] = {
0938         .map = {
0939             .coeffs_base = MALIDP500_COEFFS_BASE,
0940             .se_base = MALIDP500_SE_BASE,
0941             .dc_base = MALIDP500_DC_BASE,
0942             .out_depth_base = MALIDP500_OUTPUT_DEPTH,
0943             .features = 0,  /* no CLEARIRQ register */
0944             .n_layers = ARRAY_SIZE(malidp500_layers),
0945             .layers = malidp500_layers,
0946             .de_irq_map = {
0947                 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
0948                         MALIDP500_DE_IRQ_AXI_ERR |
0949                         MALIDP500_DE_IRQ_VSYNC |
0950                         MALIDP500_DE_IRQ_GLOBAL,
0951                 .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
0952                 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
0953                         MALIDP500_DE_IRQ_AXI_ERR |
0954                         MALIDP500_DE_IRQ_SATURATION,
0955             },
0956             .se_irq_map = {
0957                 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
0958                         MALIDP500_SE_IRQ_CONF_VALID |
0959                         MALIDP500_SE_IRQ_GLOBAL,
0960                 .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
0961                 .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
0962                         MALIDP500_SE_IRQ_AXI_ERROR |
0963                         MALIDP500_SE_IRQ_OVERRUN,
0964             },
0965             .dc_irq_map = {
0966                 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
0967                 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
0968             },
0969             .pixel_formats = malidp500_de_formats,
0970             .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
0971             .bus_align_bytes = 8,
0972         },
0973         .query_hw = malidp500_query_hw,
0974         .enter_config_mode = malidp500_enter_config_mode,
0975         .leave_config_mode = malidp500_leave_config_mode,
0976         .in_config_mode = malidp500_in_config_mode,
0977         .set_config_valid = malidp500_set_config_valid,
0978         .modeset = malidp500_modeset,
0979         .rotmem_required = malidp500_rotmem_required,
0980         .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
0981         .se_calc_mclk = malidp500_se_calc_mclk,
0982         .enable_memwrite = malidp500_enable_memwrite,
0983         .disable_memwrite = malidp500_disable_memwrite,
0984         .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
0985     },
0986     [MALIDP_550] = {
0987         .map = {
0988             .coeffs_base = MALIDP550_COEFFS_BASE,
0989             .se_base = MALIDP550_SE_BASE,
0990             .dc_base = MALIDP550_DC_BASE,
0991             .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
0992             .features = MALIDP_REGMAP_HAS_CLEARIRQ |
0993                     MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
0994                     MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
0995                     MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
0996             .n_layers = ARRAY_SIZE(malidp550_layers),
0997             .layers = malidp550_layers,
0998             .de_irq_map = {
0999                 .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 
1091 u8 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 
1116 bool 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 
1145 bool 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 
1158 static 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 
1168 static 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 
1226 static 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 
1236 void 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 
1253 int 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 
1278 void 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 
1286 static 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 
1349 void 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 
1359 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1360 {
1361     return IRQ_HANDLED;
1362 }
1363 
1364 int 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 
1388 void 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 }