1ad49f860SLiviu Dudau /* 2ad49f860SLiviu Dudau * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. 3ad49f860SLiviu Dudau * Author: Liviu Dudau <Liviu.Dudau@arm.com> 4ad49f860SLiviu Dudau * 5ad49f860SLiviu Dudau * This program is free software and is provided to you under the terms of the 6ad49f860SLiviu Dudau * GNU General Public License version 2 as published by the Free Software 7ad49f860SLiviu Dudau * Foundation, and any use by you of this program is subject to the terms 8ad49f860SLiviu Dudau * of such GNU licence. 9ad49f860SLiviu Dudau * 10ad49f860SLiviu Dudau * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where 11ad49f860SLiviu Dudau * the difference between various versions of the hardware is being dealt with 12ad49f860SLiviu Dudau * in an attempt to provide to the rest of the driver code a unified view 13ad49f860SLiviu Dudau */ 14ad49f860SLiviu Dudau 15c2e7f82dSMihail Atanassov #include <linux/clk.h> 16ad49f860SLiviu Dudau #include <linux/types.h> 17ad49f860SLiviu Dudau #include <linux/io.h> 18ad49f860SLiviu Dudau #include <drm/drmP.h> 19ad49f860SLiviu Dudau #include <video/videomode.h> 20ad49f860SLiviu Dudau #include <video/display_timing.h> 21ad49f860SLiviu Dudau 22ad49f860SLiviu Dudau #include "malidp_drv.h" 23ad49f860SLiviu Dudau #include "malidp_hw.h" 248cbc5cafSBrian Starkey #include "malidp_mw.h" 25ad49f860SLiviu Dudau 261cb3cbe7SLiviu Dudau enum { 271cb3cbe7SLiviu Dudau MW_NOT_ENABLED = 0, /* SE writeback not enabled */ 281cb3cbe7SLiviu Dudau MW_ONESHOT, /* SE in one-shot mode for writeback */ 291cb3cbe7SLiviu Dudau MW_START, /* SE started writeback */ 300735cfdfSLiviu Dudau MW_RESTART, /* SE will start another writeback after this one */ 310735cfdfSLiviu Dudau MW_STOP, /* SE needs to stop after this writeback */ 321cb3cbe7SLiviu Dudau }; 331cb3cbe7SLiviu Dudau 346211b486SBrian Starkey static const struct malidp_format_id malidp500_de_formats[] = { 35ad49f860SLiviu Dudau /* fourcc, layers supporting the format, internal id */ 3609368e32SLiviu Dudau { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 0 }, 3709368e32SLiviu Dudau { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 1 }, 38ad49f860SLiviu Dudau { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 }, 39ad49f860SLiviu Dudau { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 }, 4009368e32SLiviu Dudau { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 4 }, 4109368e32SLiviu Dudau { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 5 }, 42ad49f860SLiviu Dudau { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 }, 43ad49f860SLiviu Dudau { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 }, 44ad49f860SLiviu Dudau { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 }, 45ad49f860SLiviu Dudau { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 }, 46ad49f860SLiviu Dudau { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 }, 47ad49f860SLiviu Dudau { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 }, 48ad49f860SLiviu Dudau { DRM_FORMAT_UYVY, DE_VIDEO1, 12 }, 49ad49f860SLiviu Dudau { DRM_FORMAT_YUYV, DE_VIDEO1, 13 }, 5009368e32SLiviu Dudau { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 }, 51ad49f860SLiviu Dudau { DRM_FORMAT_YUV420, DE_VIDEO1, 15 }, 52ad49f860SLiviu Dudau }; 53ad49f860SLiviu Dudau 54ad49f860SLiviu Dudau #define MALIDP_ID(__group, __format) \ 55ad49f860SLiviu Dudau ((((__group) & 0x7) << 3) | ((__format) & 0x7)) 56ad49f860SLiviu Dudau 57ad49f860SLiviu Dudau #define MALIDP_COMMON_FORMATS \ 58ad49f860SLiviu Dudau /* fourcc, layers supporting the format, internal id */ \ 59a67bbbe2SBrian Starkey { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \ 60a67bbbe2SBrian Starkey { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \ 61a67bbbe2SBrian Starkey { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \ 62a67bbbe2SBrian Starkey { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \ 63ad49f860SLiviu Dudau { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \ 64ad49f860SLiviu Dudau { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \ 65ad49f860SLiviu Dudau { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \ 66ad49f860SLiviu Dudau { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \ 67a67bbbe2SBrian Starkey { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \ 68a67bbbe2SBrian Starkey { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \ 69a67bbbe2SBrian Starkey { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \ 70a67bbbe2SBrian Starkey { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \ 71a67bbbe2SBrian Starkey { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \ 72a67bbbe2SBrian Starkey { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \ 73ad49f860SLiviu Dudau { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \ 74ad49f860SLiviu Dudau { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \ 75ad49f860SLiviu Dudau { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \ 76ad49f860SLiviu Dudau { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \ 77ad49f860SLiviu Dudau { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \ 78ad49f860SLiviu Dudau { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \ 79a67bbbe2SBrian Starkey { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \ 80ad49f860SLiviu Dudau { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) } 81ad49f860SLiviu Dudau 826211b486SBrian Starkey static const struct malidp_format_id malidp550_de_formats[] = { 83ad49f860SLiviu Dudau MALIDP_COMMON_FORMATS, 84ad49f860SLiviu Dudau }; 85ad49f860SLiviu Dudau 86ad49f860SLiviu Dudau static const struct malidp_layer malidp500_layers[] = { 876e810eb5SMihail Atanassov { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB }, 886e810eb5SMihail Atanassov { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 896e810eb5SMihail Atanassov { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 90ad49f860SLiviu Dudau }; 91ad49f860SLiviu Dudau 92ad49f860SLiviu Dudau static const struct malidp_layer malidp550_layers[] = { 936e810eb5SMihail Atanassov { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, 946e810eb5SMihail Atanassov { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 956e810eb5SMihail Atanassov { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, 966e810eb5SMihail Atanassov { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 }, 97ad49f860SLiviu Dudau }; 98ad49f860SLiviu Dudau 9928ce675bSMihail Atanassov #define SE_N_SCALING_COEFFS 96 10028ce675bSMihail Atanassov static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = { 10128ce675bSMihail Atanassov [MALIDP_UPSCALING_COEFFS - 1] = { 10228ce675bSMihail Atanassov 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052, 10328ce675bSMihail Atanassov 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f, 10428ce675bSMihail Atanassov 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a, 10528ce675bSMihail Atanassov 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40, 10628ce675bSMihail Atanassov 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c, 10728ce675bSMihail Atanassov 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5, 10828ce675bSMihail Atanassov 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15, 10928ce675bSMihail Atanassov 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5, 11028ce675bSMihail Atanassov 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0, 11128ce675bSMihail Atanassov 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6, 11228ce675bSMihail Atanassov 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073, 11328ce675bSMihail Atanassov 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001 11428ce675bSMihail Atanassov }, 11528ce675bSMihail Atanassov [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = { 11628ce675bSMihail Atanassov 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4, 11728ce675bSMihail Atanassov 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c, 11828ce675bSMihail Atanassov 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5, 11928ce675bSMihail Atanassov 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8, 12028ce675bSMihail Atanassov 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba, 12128ce675bSMihail Atanassov 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20, 12228ce675bSMihail Atanassov 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03, 12328ce675bSMihail Atanassov 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d, 12428ce675bSMihail Atanassov 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68, 12528ce675bSMihail Atanassov 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f, 12628ce675bSMihail Atanassov 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62, 12728ce675bSMihail Atanassov 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f 12828ce675bSMihail Atanassov }, 12928ce675bSMihail Atanassov [MALIDP_DOWNSCALING_2_COEFFS - 1] = { 13028ce675bSMihail Atanassov 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9, 13128ce675bSMihail Atanassov 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52, 13228ce675bSMihail Atanassov 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158, 13328ce675bSMihail Atanassov 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455, 13428ce675bSMihail Atanassov 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e, 13528ce675bSMihail Atanassov 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887, 13628ce675bSMihail Atanassov 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5, 13728ce675bSMihail Atanassov 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e, 13828ce675bSMihail Atanassov 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d, 13928ce675bSMihail Atanassov 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0, 14028ce675bSMihail Atanassov 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf, 14128ce675bSMihail Atanassov 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03 14228ce675bSMihail Atanassov }, 14328ce675bSMihail Atanassov [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = { 14428ce675bSMihail Atanassov 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3, 14528ce675bSMihail Atanassov 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106, 14628ce675bSMihail Atanassov 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280, 14728ce675bSMihail Atanassov 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410, 14828ce675bSMihail Atanassov 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533, 14928ce675bSMihail Atanassov 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3, 15028ce675bSMihail Atanassov 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566, 15128ce675bSMihail Atanassov 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468, 15228ce675bSMihail Atanassov 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4, 15328ce675bSMihail Atanassov 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160, 15428ce675bSMihail Atanassov 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f, 15528ce675bSMihail Atanassov 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60 15628ce675bSMihail Atanassov }, 15728ce675bSMihail Atanassov [MALIDP_DOWNSCALING_4_COEFFS - 1] = { 15828ce675bSMihail Atanassov 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f, 15928ce675bSMihail Atanassov 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff, 16028ce675bSMihail Atanassov 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd, 16128ce675bSMihail Atanassov 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374, 16228ce675bSMihail Atanassov 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db, 16328ce675bSMihail Atanassov 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a, 16428ce675bSMihail Atanassov 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed, 16528ce675bSMihail Atanassov 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397, 16628ce675bSMihail Atanassov 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb, 16728ce675bSMihail Atanassov 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233, 16828ce675bSMihail Atanassov 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160, 16928ce675bSMihail Atanassov 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9 17028ce675bSMihail Atanassov }, 17128ce675bSMihail Atanassov }; 17228ce675bSMihail Atanassov 173ad49f860SLiviu Dudau #define MALIDP_DE_DEFAULT_PREFETCH_START 5 174ad49f860SLiviu Dudau 175ad49f860SLiviu Dudau static int malidp500_query_hw(struct malidp_hw_device *hwdev) 176ad49f860SLiviu Dudau { 177ad49f860SLiviu Dudau u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID); 178ad49f860SLiviu Dudau /* bit 4 of the CONFIG_ID register holds the line size multiplier */ 179ad49f860SLiviu Dudau u8 ln_size_mult = conf & 0x10 ? 2 : 1; 180ad49f860SLiviu Dudau 181ad49f860SLiviu Dudau hwdev->min_line_size = 2; 182ad49f860SLiviu Dudau hwdev->max_line_size = SZ_2K * ln_size_mult; 183ad49f860SLiviu Dudau hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult; 184ad49f860SLiviu Dudau hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */ 185ad49f860SLiviu Dudau 186ad49f860SLiviu Dudau return 0; 187ad49f860SLiviu Dudau } 188ad49f860SLiviu Dudau 189ad49f860SLiviu Dudau static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev) 190ad49f860SLiviu Dudau { 191ad49f860SLiviu Dudau u32 status, count = 100; 192ad49f860SLiviu Dudau 193ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); 194ad49f860SLiviu Dudau while (count) { 195a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 196ad49f860SLiviu Dudau if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) 197ad49f860SLiviu Dudau break; 198ad49f860SLiviu Dudau /* 199ad49f860SLiviu Dudau * entering config mode can take as long as the rendering 200ad49f860SLiviu Dudau * of a full frame, hence the long sleep here 201ad49f860SLiviu Dudau */ 202ad49f860SLiviu Dudau usleep_range(1000, 10000); 203ad49f860SLiviu Dudau count--; 204ad49f860SLiviu Dudau } 205ad49f860SLiviu Dudau WARN(count == 0, "timeout while entering config mode"); 206ad49f860SLiviu Dudau } 207ad49f860SLiviu Dudau 208ad49f860SLiviu Dudau static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev) 209ad49f860SLiviu Dudau { 210ad49f860SLiviu Dudau u32 status, count = 100; 211ad49f860SLiviu Dudau 212e64053f0SBrian Starkey malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 213ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); 214ad49f860SLiviu Dudau while (count) { 215a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 216ad49f860SLiviu Dudau if ((status & MALIDP500_DC_CONFIG_REQ) == 0) 217ad49f860SLiviu Dudau break; 218ad49f860SLiviu Dudau usleep_range(100, 1000); 219ad49f860SLiviu Dudau count--; 220ad49f860SLiviu Dudau } 221ad49f860SLiviu Dudau WARN(count == 0, "timeout while leaving config mode"); 222ad49f860SLiviu Dudau } 223ad49f860SLiviu Dudau 224ad49f860SLiviu Dudau static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev) 225ad49f860SLiviu Dudau { 226ad49f860SLiviu Dudau u32 status; 227ad49f860SLiviu Dudau 228a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 229ad49f860SLiviu Dudau if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) 230ad49f860SLiviu Dudau return true; 231ad49f860SLiviu Dudau 232ad49f860SLiviu Dudau return false; 233ad49f860SLiviu Dudau } 234ad49f860SLiviu Dudau 2350735cfdfSLiviu Dudau static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value) 236ad49f860SLiviu Dudau { 2370735cfdfSLiviu Dudau if (value) 238ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 2390735cfdfSLiviu Dudau else 2400735cfdfSLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 241ad49f860SLiviu Dudau } 242ad49f860SLiviu Dudau 243ad49f860SLiviu Dudau static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) 244ad49f860SLiviu Dudau { 245ad49f860SLiviu Dudau u32 val = 0; 246ad49f860SLiviu Dudau 247ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL); 248ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) 249ad49f860SLiviu Dudau val |= MALIDP500_HSYNCPOL; 250ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) 251ad49f860SLiviu Dudau val |= MALIDP500_VSYNCPOL; 252ad49f860SLiviu Dudau val |= MALIDP_DE_DEFAULT_PREFETCH_START; 253ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL); 254ad49f860SLiviu Dudau 255ad49f860SLiviu Dudau /* 256ad49f860SLiviu Dudau * Mali-DP500 encodes the background color like this: 257ad49f860SLiviu Dudau * - red @ MALIDP500_BGND_COLOR[12:0] 258ad49f860SLiviu Dudau * - green @ MALIDP500_BGND_COLOR[27:16] 259ad49f860SLiviu Dudau * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0] 260ad49f860SLiviu Dudau */ 261ad49f860SLiviu Dudau val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) | 262ad49f860SLiviu Dudau (MALIDP_BGND_COLOR_R & 0xfff); 263ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR); 264ad49f860SLiviu Dudau malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4); 265ad49f860SLiviu Dudau 266ad49f860SLiviu Dudau val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | 267ad49f860SLiviu Dudau MALIDP_DE_H_BACKPORCH(mode->hback_porch); 268ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); 269ad49f860SLiviu Dudau 270ad49f860SLiviu Dudau val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) | 271ad49f860SLiviu Dudau MALIDP_DE_V_BACKPORCH(mode->vback_porch); 272ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); 273ad49f860SLiviu Dudau 274ad49f860SLiviu Dudau val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | 275ad49f860SLiviu Dudau MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); 276ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); 277ad49f860SLiviu Dudau 278ad49f860SLiviu Dudau val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); 279ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); 280ad49f860SLiviu Dudau 281ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_INTERLACED) 282ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 283ad49f860SLiviu Dudau else 284ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 285ad49f860SLiviu Dudau } 286ad49f860SLiviu Dudau 287ad49f860SLiviu Dudau static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) 288ad49f860SLiviu Dudau { 289ad49f860SLiviu Dudau /* RGB888 or BGR888 can't be rotated */ 290ad49f860SLiviu Dudau if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) 291ad49f860SLiviu Dudau return -EINVAL; 292ad49f860SLiviu Dudau 293ad49f860SLiviu Dudau /* 294ad49f860SLiviu Dudau * Each layer needs enough rotation memory to fit 8 lines 295ad49f860SLiviu Dudau * worth of pixel data. Required size is then: 296ad49f860SLiviu Dudau * size = rotated_width * (bpp / 8) * 8; 297ad49f860SLiviu Dudau */ 2987ccf281fSLaurent Pinchart return w * drm_format_plane_cpp(fmt, 0) * 8; 299ad49f860SLiviu Dudau } 300ad49f860SLiviu Dudau 30128ce675bSMihail Atanassov static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev, 30228ce675bSMihail Atanassov u32 direction, 30328ce675bSMihail Atanassov u16 addr, 30428ce675bSMihail Atanassov u8 coeffs_id) 30528ce675bSMihail Atanassov { 30628ce675bSMihail Atanassov int i; 30728ce675bSMihail Atanassov u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL; 30828ce675bSMihail Atanassov 30928ce675bSMihail Atanassov malidp_hw_write(hwdev, 31028ce675bSMihail Atanassov direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK), 31128ce675bSMihail Atanassov scaling_control + MALIDP_SE_COEFFTAB_ADDR); 31228ce675bSMihail Atanassov for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i) 31328ce675bSMihail Atanassov malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA( 31428ce675bSMihail Atanassov dp500_se_scaling_coeffs[coeffs_id][i]), 31528ce675bSMihail Atanassov scaling_control + MALIDP_SE_COEFFTAB_DATA); 31628ce675bSMihail Atanassov } 31728ce675bSMihail Atanassov 31828ce675bSMihail Atanassov static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, 31928ce675bSMihail Atanassov struct malidp_se_config *se_config, 32028ce675bSMihail Atanassov struct malidp_se_config *old_config) 32128ce675bSMihail Atanassov { 32228ce675bSMihail Atanassov /* Get array indices into dp500_se_scaling_coeffs. */ 32328ce675bSMihail Atanassov u8 h = (u8)se_config->hcoeff - 1; 32428ce675bSMihail Atanassov u8 v = (u8)se_config->vcoeff - 1; 32528ce675bSMihail Atanassov 32628ce675bSMihail Atanassov if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) || 32728ce675bSMihail Atanassov v >= ARRAY_SIZE(dp500_se_scaling_coeffs))) 32828ce675bSMihail Atanassov return -EINVAL; 32928ce675bSMihail Atanassov 33028ce675bSMihail Atanassov if ((h == v) && (se_config->hcoeff != old_config->hcoeff || 33128ce675bSMihail Atanassov se_config->vcoeff != old_config->vcoeff)) { 33228ce675bSMihail Atanassov malidp500_se_write_pp_coefftab(hwdev, 33328ce675bSMihail Atanassov (MALIDP_SE_V_COEFFTAB | 33428ce675bSMihail Atanassov MALIDP_SE_H_COEFFTAB), 33528ce675bSMihail Atanassov 0, v); 33628ce675bSMihail Atanassov } else { 33728ce675bSMihail Atanassov if (se_config->vcoeff != old_config->vcoeff) 33828ce675bSMihail Atanassov malidp500_se_write_pp_coefftab(hwdev, 33928ce675bSMihail Atanassov MALIDP_SE_V_COEFFTAB, 34028ce675bSMihail Atanassov 0, v); 34128ce675bSMihail Atanassov if (se_config->hcoeff != old_config->hcoeff) 34228ce675bSMihail Atanassov malidp500_se_write_pp_coefftab(hwdev, 34328ce675bSMihail Atanassov MALIDP_SE_H_COEFFTAB, 34428ce675bSMihail Atanassov 0, h); 34528ce675bSMihail Atanassov } 34628ce675bSMihail Atanassov 34728ce675bSMihail Atanassov return 0; 34828ce675bSMihail Atanassov } 34928ce675bSMihail Atanassov 350c2e7f82dSMihail Atanassov static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, 351c2e7f82dSMihail Atanassov struct malidp_se_config *se_config, 352c2e7f82dSMihail Atanassov struct videomode *vm) 353c2e7f82dSMihail Atanassov { 354c2e7f82dSMihail Atanassov unsigned long mclk; 355c2e7f82dSMihail Atanassov unsigned long pxlclk = vm->pixelclock; /* Hz */ 356c2e7f82dSMihail Atanassov unsigned long htotal = vm->hactive + vm->hfront_porch + 357c2e7f82dSMihail Atanassov vm->hback_porch + vm->hsync_len; 358c2e7f82dSMihail Atanassov unsigned long input_size = se_config->input_w * se_config->input_h; 359c2e7f82dSMihail Atanassov unsigned long a = 10; 360c2e7f82dSMihail Atanassov long ret; 361c2e7f82dSMihail Atanassov 362c2e7f82dSMihail Atanassov /* 363c2e7f82dSMihail Atanassov * mclk = max(a, 1.5) * pxlclk 364c2e7f82dSMihail Atanassov * 365c2e7f82dSMihail Atanassov * To avoid float calculaiton, using 15 instead of 1.5 and div by 366c2e7f82dSMihail Atanassov * 10 to get mclk. 367c2e7f82dSMihail Atanassov */ 368c2e7f82dSMihail Atanassov if (se_config->scale_enable) { 369c2e7f82dSMihail Atanassov a = 15 * input_size / (htotal * se_config->output_h); 370c2e7f82dSMihail Atanassov if (a < 15) 371c2e7f82dSMihail Atanassov a = 15; 372c2e7f82dSMihail Atanassov } 373c2e7f82dSMihail Atanassov mclk = a * pxlclk / 10; 374c2e7f82dSMihail Atanassov ret = clk_get_rate(hwdev->mclk); 375c2e7f82dSMihail Atanassov if (ret < mclk) { 376c2e7f82dSMihail Atanassov DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", 377c2e7f82dSMihail Atanassov mclk / 1000); 378c2e7f82dSMihail Atanassov return -EINVAL; 379c2e7f82dSMihail Atanassov } 380c2e7f82dSMihail Atanassov return ret; 381c2e7f82dSMihail Atanassov } 382c2e7f82dSMihail Atanassov 3831cb3cbe7SLiviu Dudau static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev, 3841cb3cbe7SLiviu Dudau dma_addr_t *addrs, s32 *pitches, 3851cb3cbe7SLiviu Dudau int num_planes, u16 w, u16 h, u32 fmt_id) 3861cb3cbe7SLiviu Dudau { 3871cb3cbe7SLiviu Dudau u32 base = MALIDP500_SE_MEMWRITE_BASE; 3881cb3cbe7SLiviu Dudau u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 3891cb3cbe7SLiviu Dudau 3901cb3cbe7SLiviu Dudau /* enable the scaling engine block */ 3911cb3cbe7SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); 3921cb3cbe7SLiviu Dudau 3930735cfdfSLiviu Dudau /* restart the writeback if already enabled */ 3940735cfdfSLiviu Dudau if (hwdev->mw_state != MW_NOT_ENABLED) 3950735cfdfSLiviu Dudau hwdev->mw_state = MW_RESTART; 3960735cfdfSLiviu Dudau else 3971cb3cbe7SLiviu Dudau hwdev->mw_state = MW_START; 3981cb3cbe7SLiviu Dudau 3991cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); 4001cb3cbe7SLiviu Dudau switch (num_planes) { 4011cb3cbe7SLiviu Dudau case 2: 4021cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); 4031cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); 4041cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); 4051cb3cbe7SLiviu Dudau /* fall through */ 4061cb3cbe7SLiviu Dudau case 1: 4071cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); 4081cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); 4091cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); 4101cb3cbe7SLiviu Dudau break; 4111cb3cbe7SLiviu Dudau default: 4121cb3cbe7SLiviu Dudau WARN(1, "Invalid number of planes"); 4131cb3cbe7SLiviu Dudau } 4141cb3cbe7SLiviu Dudau 4151cb3cbe7SLiviu Dudau malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), 4161cb3cbe7SLiviu Dudau MALIDP500_SE_MEMWRITE_OUT_SIZE); 4171cb3cbe7SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); 4181cb3cbe7SLiviu Dudau 4191cb3cbe7SLiviu Dudau return 0; 4201cb3cbe7SLiviu Dudau } 4211cb3cbe7SLiviu Dudau 4221cb3cbe7SLiviu Dudau static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev) 4231cb3cbe7SLiviu Dudau { 4241cb3cbe7SLiviu Dudau u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 4251cb3cbe7SLiviu Dudau 4260735cfdfSLiviu Dudau if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART) 4271cb3cbe7SLiviu Dudau hwdev->mw_state = MW_STOP; 4281cb3cbe7SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); 4291cb3cbe7SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); 4301cb3cbe7SLiviu Dudau } 4311cb3cbe7SLiviu Dudau 432ad49f860SLiviu Dudau static int malidp550_query_hw(struct malidp_hw_device *hwdev) 433ad49f860SLiviu Dudau { 434ad49f860SLiviu Dudau u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 435ad49f860SLiviu Dudau u8 ln_size = (conf >> 4) & 0x3, rsize; 436ad49f860SLiviu Dudau 437ad49f860SLiviu Dudau hwdev->min_line_size = 2; 438ad49f860SLiviu Dudau 439ad49f860SLiviu Dudau switch (ln_size) { 440ad49f860SLiviu Dudau case 0: 441ad49f860SLiviu Dudau hwdev->max_line_size = SZ_2K; 442ad49f860SLiviu Dudau /* two banks of 64KB for rotation memory */ 443ad49f860SLiviu Dudau rsize = 64; 444ad49f860SLiviu Dudau break; 445ad49f860SLiviu Dudau case 1: 446ad49f860SLiviu Dudau hwdev->max_line_size = SZ_4K; 447ad49f860SLiviu Dudau /* two banks of 128KB for rotation memory */ 448ad49f860SLiviu Dudau rsize = 128; 449ad49f860SLiviu Dudau break; 450ad49f860SLiviu Dudau case 2: 451ad49f860SLiviu Dudau hwdev->max_line_size = 1280; 452ad49f860SLiviu Dudau /* two banks of 40KB for rotation memory */ 453ad49f860SLiviu Dudau rsize = 40; 454ad49f860SLiviu Dudau break; 455ad49f860SLiviu Dudau case 3: 456ad49f860SLiviu Dudau /* reserved value */ 457ad49f860SLiviu Dudau hwdev->max_line_size = 0; 458ad49f860SLiviu Dudau return -EINVAL; 459ad49f860SLiviu Dudau } 460ad49f860SLiviu Dudau 461ad49f860SLiviu Dudau hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; 462ad49f860SLiviu Dudau return 0; 463ad49f860SLiviu Dudau } 464ad49f860SLiviu Dudau 465ad49f860SLiviu Dudau static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev) 466ad49f860SLiviu Dudau { 467ad49f860SLiviu Dudau u32 status, count = 100; 468ad49f860SLiviu Dudau 469ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); 470ad49f860SLiviu Dudau while (count) { 471a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 472ad49f860SLiviu Dudau if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) 473ad49f860SLiviu Dudau break; 474ad49f860SLiviu Dudau /* 475ad49f860SLiviu Dudau * entering config mode can take as long as the rendering 476ad49f860SLiviu Dudau * of a full frame, hence the long sleep here 477ad49f860SLiviu Dudau */ 478ad49f860SLiviu Dudau usleep_range(1000, 10000); 479ad49f860SLiviu Dudau count--; 480ad49f860SLiviu Dudau } 481ad49f860SLiviu Dudau WARN(count == 0, "timeout while entering config mode"); 482ad49f860SLiviu Dudau } 483ad49f860SLiviu Dudau 484ad49f860SLiviu Dudau static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev) 485ad49f860SLiviu Dudau { 486ad49f860SLiviu Dudau u32 status, count = 100; 487ad49f860SLiviu Dudau 488e64053f0SBrian Starkey malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 489ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); 490ad49f860SLiviu Dudau while (count) { 491a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 492ad49f860SLiviu Dudau if ((status & MALIDP550_DC_CONFIG_REQ) == 0) 493ad49f860SLiviu Dudau break; 494ad49f860SLiviu Dudau usleep_range(100, 1000); 495ad49f860SLiviu Dudau count--; 496ad49f860SLiviu Dudau } 497ad49f860SLiviu Dudau WARN(count == 0, "timeout while leaving config mode"); 498ad49f860SLiviu Dudau } 499ad49f860SLiviu Dudau 500ad49f860SLiviu Dudau static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev) 501ad49f860SLiviu Dudau { 502ad49f860SLiviu Dudau u32 status; 503ad49f860SLiviu Dudau 504a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 505ad49f860SLiviu Dudau if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) 506ad49f860SLiviu Dudau return true; 507ad49f860SLiviu Dudau 508ad49f860SLiviu Dudau return false; 509ad49f860SLiviu Dudau } 510ad49f860SLiviu Dudau 5110735cfdfSLiviu Dudau static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value) 512ad49f860SLiviu Dudau { 5130735cfdfSLiviu Dudau if (value) 514ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 5150735cfdfSLiviu Dudau else 5160735cfdfSLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 517ad49f860SLiviu Dudau } 518ad49f860SLiviu Dudau 519ad49f860SLiviu Dudau static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) 520ad49f860SLiviu Dudau { 521ad49f860SLiviu Dudau u32 val = MALIDP_DE_DEFAULT_PREFETCH_START; 522ad49f860SLiviu Dudau 523ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL); 524ad49f860SLiviu Dudau /* 525ad49f860SLiviu Dudau * Mali-DP550 and Mali-DP650 encode the background color like this: 526ad49f860SLiviu Dudau * - red @ MALIDP550_DE_BGND_COLOR[23:16] 527ad49f860SLiviu Dudau * - green @ MALIDP550_DE_BGND_COLOR[15:8] 528ad49f860SLiviu Dudau * - blue @ MALIDP550_DE_BGND_COLOR[7:0] 529ad49f860SLiviu Dudau * 530ad49f860SLiviu Dudau * We need to truncate the least significant 4 bits from the default 531ad49f860SLiviu Dudau * MALIDP_BGND_COLOR_x values 532ad49f860SLiviu Dudau */ 533ad49f860SLiviu Dudau val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) | 534ad49f860SLiviu Dudau (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) | 535ad49f860SLiviu Dudau ((MALIDP_BGND_COLOR_B >> 4) & 0xff); 536ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR); 537ad49f860SLiviu Dudau 538ad49f860SLiviu Dudau val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | 539ad49f860SLiviu Dudau MALIDP_DE_H_BACKPORCH(mode->hback_porch); 540ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); 541ad49f860SLiviu Dudau 542ad49f860SLiviu Dudau val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) | 543ad49f860SLiviu Dudau MALIDP_DE_V_BACKPORCH(mode->vback_porch); 544ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); 545ad49f860SLiviu Dudau 546ad49f860SLiviu Dudau val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | 547ad49f860SLiviu Dudau MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); 548ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) 549ad49f860SLiviu Dudau val |= MALIDP550_HSYNCPOL; 550ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) 551ad49f860SLiviu Dudau val |= MALIDP550_VSYNCPOL; 552ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); 553ad49f860SLiviu Dudau 554ad49f860SLiviu Dudau val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); 555ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); 556ad49f860SLiviu Dudau 557ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_INTERLACED) 558ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 559ad49f860SLiviu Dudau else 560ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 561ad49f860SLiviu Dudau } 562ad49f860SLiviu Dudau 563ad49f860SLiviu Dudau static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) 564ad49f860SLiviu Dudau { 565ad49f860SLiviu Dudau u32 bytes_per_col; 566ad49f860SLiviu Dudau 567ad49f860SLiviu Dudau /* raw RGB888 or BGR888 can't be rotated */ 568ad49f860SLiviu Dudau if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) 569ad49f860SLiviu Dudau return -EINVAL; 570ad49f860SLiviu Dudau 571ad49f860SLiviu Dudau switch (fmt) { 572ad49f860SLiviu Dudau /* 8 lines at 4 bytes per pixel */ 573ad49f860SLiviu Dudau case DRM_FORMAT_ARGB2101010: 574ad49f860SLiviu Dudau case DRM_FORMAT_ABGR2101010: 575ad49f860SLiviu Dudau case DRM_FORMAT_RGBA1010102: 576ad49f860SLiviu Dudau case DRM_FORMAT_BGRA1010102: 577ad49f860SLiviu Dudau case DRM_FORMAT_ARGB8888: 578ad49f860SLiviu Dudau case DRM_FORMAT_ABGR8888: 579ad49f860SLiviu Dudau case DRM_FORMAT_RGBA8888: 580ad49f860SLiviu Dudau case DRM_FORMAT_BGRA8888: 581ad49f860SLiviu Dudau case DRM_FORMAT_XRGB8888: 582ad49f860SLiviu Dudau case DRM_FORMAT_XBGR8888: 583ad49f860SLiviu Dudau case DRM_FORMAT_RGBX8888: 584ad49f860SLiviu Dudau case DRM_FORMAT_BGRX8888: 585ad49f860SLiviu Dudau case DRM_FORMAT_RGB888: 586ad49f860SLiviu Dudau case DRM_FORMAT_BGR888: 587ad49f860SLiviu Dudau /* 16 lines at 2 bytes per pixel */ 588ad49f860SLiviu Dudau case DRM_FORMAT_RGBA5551: 589ad49f860SLiviu Dudau case DRM_FORMAT_ABGR1555: 590ad49f860SLiviu Dudau case DRM_FORMAT_RGB565: 591ad49f860SLiviu Dudau case DRM_FORMAT_BGR565: 592ad49f860SLiviu Dudau case DRM_FORMAT_UYVY: 593ad49f860SLiviu Dudau case DRM_FORMAT_YUYV: 594ad49f860SLiviu Dudau bytes_per_col = 32; 595ad49f860SLiviu Dudau break; 596ad49f860SLiviu Dudau /* 16 lines at 1.5 bytes per pixel */ 597ad49f860SLiviu Dudau case DRM_FORMAT_NV12: 598ad49f860SLiviu Dudau case DRM_FORMAT_YUV420: 599ad49f860SLiviu Dudau bytes_per_col = 24; 600ad49f860SLiviu Dudau break; 601ad49f860SLiviu Dudau default: 602ad49f860SLiviu Dudau return -EINVAL; 603ad49f860SLiviu Dudau } 604ad49f860SLiviu Dudau 605ad49f860SLiviu Dudau return w * bytes_per_col; 606ad49f860SLiviu Dudau } 607ad49f860SLiviu Dudau 60828ce675bSMihail Atanassov static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, 60928ce675bSMihail Atanassov struct malidp_se_config *se_config, 61028ce675bSMihail Atanassov struct malidp_se_config *old_config) 61128ce675bSMihail Atanassov { 61228ce675bSMihail Atanassov u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) | 61328ce675bSMihail Atanassov MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK); 61428ce675bSMihail Atanassov u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) | 61528ce675bSMihail Atanassov MALIDP550_SE_CTL_HCSEL(se_config->hcoeff); 61628ce675bSMihail Atanassov 61728ce675bSMihail Atanassov malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL); 61828ce675bSMihail Atanassov malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL); 61928ce675bSMihail Atanassov return 0; 62028ce675bSMihail Atanassov } 62128ce675bSMihail Atanassov 622c2e7f82dSMihail Atanassov static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev, 623c2e7f82dSMihail Atanassov struct malidp_se_config *se_config, 624c2e7f82dSMihail Atanassov struct videomode *vm) 625c2e7f82dSMihail Atanassov { 626c2e7f82dSMihail Atanassov unsigned long mclk; 627c2e7f82dSMihail Atanassov unsigned long pxlclk = vm->pixelclock; 628c2e7f82dSMihail Atanassov unsigned long htotal = vm->hactive + vm->hfront_porch + 629c2e7f82dSMihail Atanassov vm->hback_porch + vm->hsync_len; 630c2e7f82dSMihail Atanassov unsigned long numerator = 1, denominator = 1; 631c2e7f82dSMihail Atanassov long ret; 632c2e7f82dSMihail Atanassov 633c2e7f82dSMihail Atanassov if (se_config->scale_enable) { 634c2e7f82dSMihail Atanassov numerator = max(se_config->input_w, se_config->output_w) * 635c2e7f82dSMihail Atanassov se_config->input_h; 636c2e7f82dSMihail Atanassov numerator += se_config->output_w * 637c2e7f82dSMihail Atanassov (se_config->output_h - 638c2e7f82dSMihail Atanassov min(se_config->input_h, se_config->output_h)); 639c2e7f82dSMihail Atanassov denominator = (htotal - 2) * se_config->output_h; 640c2e7f82dSMihail Atanassov } 641c2e7f82dSMihail Atanassov 642c2e7f82dSMihail Atanassov /* mclk can't be slower than pxlclk. */ 643c2e7f82dSMihail Atanassov if (numerator < denominator) 644c2e7f82dSMihail Atanassov numerator = denominator = 1; 645c2e7f82dSMihail Atanassov mclk = (pxlclk * numerator) / denominator; 646c2e7f82dSMihail Atanassov ret = clk_get_rate(hwdev->mclk); 647c2e7f82dSMihail Atanassov if (ret < mclk) { 648c2e7f82dSMihail Atanassov DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", 649c2e7f82dSMihail Atanassov mclk / 1000); 650c2e7f82dSMihail Atanassov return -EINVAL; 651c2e7f82dSMihail Atanassov } 652c2e7f82dSMihail Atanassov return ret; 653c2e7f82dSMihail Atanassov } 654c2e7f82dSMihail Atanassov 655846c87a0SLiviu Dudau static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev, 656846c87a0SLiviu Dudau dma_addr_t *addrs, s32 *pitches, 657846c87a0SLiviu Dudau int num_planes, u16 w, u16 h, u32 fmt_id) 658846c87a0SLiviu Dudau { 659846c87a0SLiviu Dudau u32 base = MALIDP550_SE_MEMWRITE_BASE; 660846c87a0SLiviu Dudau u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 661846c87a0SLiviu Dudau 662846c87a0SLiviu Dudau /* enable the scaling engine block */ 663846c87a0SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); 664846c87a0SLiviu Dudau 6651cb3cbe7SLiviu Dudau hwdev->mw_state = MW_ONESHOT; 6661cb3cbe7SLiviu Dudau 667846c87a0SLiviu Dudau malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); 668846c87a0SLiviu Dudau switch (num_planes) { 669846c87a0SLiviu Dudau case 2: 670846c87a0SLiviu Dudau malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); 671846c87a0SLiviu Dudau malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); 672846c87a0SLiviu Dudau malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); 673846c87a0SLiviu Dudau /* fall through */ 674846c87a0SLiviu Dudau case 1: 675846c87a0SLiviu Dudau malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); 676846c87a0SLiviu Dudau malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); 677846c87a0SLiviu Dudau malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); 678846c87a0SLiviu Dudau break; 679846c87a0SLiviu Dudau default: 680846c87a0SLiviu Dudau WARN(1, "Invalid number of planes"); 681846c87a0SLiviu Dudau } 682846c87a0SLiviu Dudau 683846c87a0SLiviu Dudau malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), 684846c87a0SLiviu Dudau MALIDP550_SE_MEMWRITE_OUT_SIZE); 685846c87a0SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, 686846c87a0SLiviu Dudau MALIDP550_SE_CONTROL); 687846c87a0SLiviu Dudau 688846c87a0SLiviu Dudau return 0; 689846c87a0SLiviu Dudau } 690846c87a0SLiviu Dudau 691846c87a0SLiviu Dudau static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev) 692846c87a0SLiviu Dudau { 693846c87a0SLiviu Dudau u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 694846c87a0SLiviu Dudau 695846c87a0SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, 696846c87a0SLiviu Dudau MALIDP550_SE_CONTROL); 697846c87a0SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); 698846c87a0SLiviu Dudau } 699846c87a0SLiviu Dudau 700ad49f860SLiviu Dudau static int malidp650_query_hw(struct malidp_hw_device *hwdev) 701ad49f860SLiviu Dudau { 702ad49f860SLiviu Dudau u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 703ad49f860SLiviu Dudau u8 ln_size = (conf >> 4) & 0x3, rsize; 704ad49f860SLiviu Dudau 705ad49f860SLiviu Dudau hwdev->min_line_size = 4; 706ad49f860SLiviu Dudau 707ad49f860SLiviu Dudau switch (ln_size) { 708ad49f860SLiviu Dudau case 0: 709ad49f860SLiviu Dudau case 2: 710ad49f860SLiviu Dudau /* reserved values */ 711ad49f860SLiviu Dudau hwdev->max_line_size = 0; 712ad49f860SLiviu Dudau return -EINVAL; 713ad49f860SLiviu Dudau case 1: 714ad49f860SLiviu Dudau hwdev->max_line_size = SZ_4K; 715ad49f860SLiviu Dudau /* two banks of 128KB for rotation memory */ 716ad49f860SLiviu Dudau rsize = 128; 717ad49f860SLiviu Dudau break; 718ad49f860SLiviu Dudau case 3: 719ad49f860SLiviu Dudau hwdev->max_line_size = 2560; 720ad49f860SLiviu Dudau /* two banks of 80KB for rotation memory */ 721ad49f860SLiviu Dudau rsize = 80; 722ad49f860SLiviu Dudau } 723ad49f860SLiviu Dudau 724ad49f860SLiviu Dudau hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; 725ad49f860SLiviu Dudau return 0; 726ad49f860SLiviu Dudau } 727ad49f860SLiviu Dudau 728a6993b21SLiviu Dudau const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { 729ad49f860SLiviu Dudau [MALIDP_500] = { 730ad49f860SLiviu Dudau .map = { 73102725d31SMihail Atanassov .coeffs_base = MALIDP500_COEFFS_BASE, 732ad49f860SLiviu Dudau .se_base = MALIDP500_SE_BASE, 733ad49f860SLiviu Dudau .dc_base = MALIDP500_DC_BASE, 734ad49f860SLiviu Dudau .out_depth_base = MALIDP500_OUTPUT_DEPTH, 735ad49f860SLiviu Dudau .features = 0, /* no CLEARIRQ register */ 736ad49f860SLiviu Dudau .n_layers = ARRAY_SIZE(malidp500_layers), 737ad49f860SLiviu Dudau .layers = malidp500_layers, 738ad49f860SLiviu Dudau .de_irq_map = { 739ad49f860SLiviu Dudau .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 740ad49f860SLiviu Dudau MALIDP500_DE_IRQ_AXI_ERR | 741ad49f860SLiviu Dudau MALIDP500_DE_IRQ_VSYNC | 742ad49f860SLiviu Dudau MALIDP500_DE_IRQ_GLOBAL, 743ad49f860SLiviu Dudau .vsync_irq = MALIDP500_DE_IRQ_VSYNC, 744ad49f860SLiviu Dudau }, 745ad49f860SLiviu Dudau .se_irq_map = { 74689610dc2SAlison Wang .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | 7471cb3cbe7SLiviu Dudau MALIDP500_SE_IRQ_CONF_VALID | 74889610dc2SAlison Wang MALIDP500_SE_IRQ_GLOBAL, 7491cb3cbe7SLiviu Dudau .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID, 750ad49f860SLiviu Dudau }, 751ad49f860SLiviu Dudau .dc_irq_map = { 752ad49f860SLiviu Dudau .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, 753ad49f860SLiviu Dudau .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID, 754ad49f860SLiviu Dudau }, 7556211b486SBrian Starkey .pixel_formats = malidp500_de_formats, 7566211b486SBrian Starkey .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats), 757a228062cSBrian Starkey .bus_align_bytes = 8, 758ad49f860SLiviu Dudau }, 759ad49f860SLiviu Dudau .query_hw = malidp500_query_hw, 760ad49f860SLiviu Dudau .enter_config_mode = malidp500_enter_config_mode, 761ad49f860SLiviu Dudau .leave_config_mode = malidp500_leave_config_mode, 762ad49f860SLiviu Dudau .in_config_mode = malidp500_in_config_mode, 763ad49f860SLiviu Dudau .set_config_valid = malidp500_set_config_valid, 764ad49f860SLiviu Dudau .modeset = malidp500_modeset, 765ad49f860SLiviu Dudau .rotmem_required = malidp500_rotmem_required, 76628ce675bSMihail Atanassov .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, 767c2e7f82dSMihail Atanassov .se_calc_mclk = malidp500_se_calc_mclk, 7681cb3cbe7SLiviu Dudau .enable_memwrite = malidp500_enable_memwrite, 7691cb3cbe7SLiviu Dudau .disable_memwrite = malidp500_disable_memwrite, 77083d642eeSMihail Atanassov .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, 771ad49f860SLiviu Dudau }, 772ad49f860SLiviu Dudau [MALIDP_550] = { 773ad49f860SLiviu Dudau .map = { 77402725d31SMihail Atanassov .coeffs_base = MALIDP550_COEFFS_BASE, 775ad49f860SLiviu Dudau .se_base = MALIDP550_SE_BASE, 776ad49f860SLiviu Dudau .dc_base = MALIDP550_DC_BASE, 777ad49f860SLiviu Dudau .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 778ad49f860SLiviu Dudau .features = MALIDP_REGMAP_HAS_CLEARIRQ, 779ad49f860SLiviu Dudau .n_layers = ARRAY_SIZE(malidp550_layers), 780ad49f860SLiviu Dudau .layers = malidp550_layers, 781ad49f860SLiviu Dudau .de_irq_map = { 782ad49f860SLiviu Dudau .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 783ad49f860SLiviu Dudau MALIDP550_DE_IRQ_VSYNC, 784ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DE_IRQ_VSYNC, 785ad49f860SLiviu Dudau }, 786ad49f860SLiviu Dudau .se_irq_map = { 787ad49f860SLiviu Dudau .irq_mask = MALIDP550_SE_IRQ_EOW | 788ad49f860SLiviu Dudau MALIDP550_SE_IRQ_AXI_ERR, 789846c87a0SLiviu Dudau .vsync_irq = MALIDP550_SE_IRQ_EOW, 790ad49f860SLiviu Dudau }, 791ad49f860SLiviu Dudau .dc_irq_map = { 792846c87a0SLiviu Dudau .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | 793846c87a0SLiviu Dudau MALIDP550_DC_IRQ_SE, 794ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 795ad49f860SLiviu Dudau }, 7966211b486SBrian Starkey .pixel_formats = malidp550_de_formats, 7976211b486SBrian Starkey .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), 798a228062cSBrian Starkey .bus_align_bytes = 8, 799ad49f860SLiviu Dudau }, 800ad49f860SLiviu Dudau .query_hw = malidp550_query_hw, 801ad49f860SLiviu Dudau .enter_config_mode = malidp550_enter_config_mode, 802ad49f860SLiviu Dudau .leave_config_mode = malidp550_leave_config_mode, 803ad49f860SLiviu Dudau .in_config_mode = malidp550_in_config_mode, 804ad49f860SLiviu Dudau .set_config_valid = malidp550_set_config_valid, 805ad49f860SLiviu Dudau .modeset = malidp550_modeset, 806ad49f860SLiviu Dudau .rotmem_required = malidp550_rotmem_required, 80728ce675bSMihail Atanassov .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, 808c2e7f82dSMihail Atanassov .se_calc_mclk = malidp550_se_calc_mclk, 809846c87a0SLiviu Dudau .enable_memwrite = malidp550_enable_memwrite, 810846c87a0SLiviu Dudau .disable_memwrite = malidp550_disable_memwrite, 81183d642eeSMihail Atanassov .features = 0, 812ad49f860SLiviu Dudau }, 813ad49f860SLiviu Dudau [MALIDP_650] = { 814ad49f860SLiviu Dudau .map = { 81502725d31SMihail Atanassov .coeffs_base = MALIDP550_COEFFS_BASE, 816ad49f860SLiviu Dudau .se_base = MALIDP550_SE_BASE, 817ad49f860SLiviu Dudau .dc_base = MALIDP550_DC_BASE, 818ad49f860SLiviu Dudau .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 819ad49f860SLiviu Dudau .features = MALIDP_REGMAP_HAS_CLEARIRQ, 820ad49f860SLiviu Dudau .n_layers = ARRAY_SIZE(malidp550_layers), 821ad49f860SLiviu Dudau .layers = malidp550_layers, 822ad49f860SLiviu Dudau .de_irq_map = { 823ad49f860SLiviu Dudau .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 824ad49f860SLiviu Dudau MALIDP650_DE_IRQ_DRIFT | 825ad49f860SLiviu Dudau MALIDP550_DE_IRQ_VSYNC, 826ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DE_IRQ_VSYNC, 827ad49f860SLiviu Dudau }, 828ad49f860SLiviu Dudau .se_irq_map = { 829ad49f860SLiviu Dudau .irq_mask = MALIDP550_SE_IRQ_EOW | 830ad49f860SLiviu Dudau MALIDP550_SE_IRQ_AXI_ERR, 831846c87a0SLiviu Dudau .vsync_irq = MALIDP550_SE_IRQ_EOW, 832ad49f860SLiviu Dudau }, 833ad49f860SLiviu Dudau .dc_irq_map = { 834846c87a0SLiviu Dudau .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | 835846c87a0SLiviu Dudau MALIDP550_DC_IRQ_SE, 836ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 837ad49f860SLiviu Dudau }, 8386211b486SBrian Starkey .pixel_formats = malidp550_de_formats, 8396211b486SBrian Starkey .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), 840a228062cSBrian Starkey .bus_align_bytes = 16, 841ad49f860SLiviu Dudau }, 842ad49f860SLiviu Dudau .query_hw = malidp650_query_hw, 843ad49f860SLiviu Dudau .enter_config_mode = malidp550_enter_config_mode, 844ad49f860SLiviu Dudau .leave_config_mode = malidp550_leave_config_mode, 845ad49f860SLiviu Dudau .in_config_mode = malidp550_in_config_mode, 846ad49f860SLiviu Dudau .set_config_valid = malidp550_set_config_valid, 847ad49f860SLiviu Dudau .modeset = malidp550_modeset, 848ad49f860SLiviu Dudau .rotmem_required = malidp550_rotmem_required, 84928ce675bSMihail Atanassov .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, 850c2e7f82dSMihail Atanassov .se_calc_mclk = malidp550_se_calc_mclk, 851846c87a0SLiviu Dudau .enable_memwrite = malidp550_enable_memwrite, 852846c87a0SLiviu Dudau .disable_memwrite = malidp550_disable_memwrite, 85383d642eeSMihail Atanassov .features = 0, 854ad49f860SLiviu Dudau }, 855ad49f860SLiviu Dudau }; 856ad49f860SLiviu Dudau 857ad49f860SLiviu Dudau u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, 858ad49f860SLiviu Dudau u8 layer_id, u32 format) 859ad49f860SLiviu Dudau { 860ad49f860SLiviu Dudau unsigned int i; 861ad49f860SLiviu Dudau 8626211b486SBrian Starkey for (i = 0; i < map->n_pixel_formats; i++) { 8636211b486SBrian Starkey if (((map->pixel_formats[i].layer & layer_id) == layer_id) && 8646211b486SBrian Starkey (map->pixel_formats[i].format == format)) 8656211b486SBrian Starkey return map->pixel_formats[i].id; 866ad49f860SLiviu Dudau } 867ad49f860SLiviu Dudau 868ad49f860SLiviu Dudau return MALIDP_INVALID_FORMAT_ID; 869ad49f860SLiviu Dudau } 870ad49f860SLiviu Dudau 871ad49f860SLiviu Dudau static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq) 872ad49f860SLiviu Dudau { 873ad49f860SLiviu Dudau u32 base = malidp_get_block_base(hwdev, block); 874ad49f860SLiviu Dudau 875a6993b21SLiviu Dudau if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) 876ad49f860SLiviu Dudau malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ); 877ad49f860SLiviu Dudau else 878ad49f860SLiviu Dudau malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS); 879ad49f860SLiviu Dudau } 880ad49f860SLiviu Dudau 881ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq(int irq, void *arg) 882ad49f860SLiviu Dudau { 883ad49f860SLiviu Dudau struct drm_device *drm = arg; 884ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 885ad49f860SLiviu Dudau struct malidp_hw_device *hwdev; 886a6993b21SLiviu Dudau struct malidp_hw *hw; 887ad49f860SLiviu Dudau const struct malidp_irq_map *de; 888ad49f860SLiviu Dudau u32 status, mask, dc_status; 889ad49f860SLiviu Dudau irqreturn_t ret = IRQ_NONE; 890ad49f860SLiviu Dudau 891ad49f860SLiviu Dudau hwdev = malidp->dev; 892a6993b21SLiviu Dudau hw = hwdev->hw; 893a6993b21SLiviu Dudau de = &hw->map.de_irq_map; 894ad49f860SLiviu Dudau 8950df34a80SLiviu Dudau /* 8960df34a80SLiviu Dudau * if we are suspended it is likely that we were invoked because 8970df34a80SLiviu Dudau * we share an interrupt line with some other driver, don't try 8980df34a80SLiviu Dudau * to read the hardware registers 8990df34a80SLiviu Dudau */ 9000df34a80SLiviu Dudau if (hwdev->pm_suspended) 9010df34a80SLiviu Dudau return IRQ_NONE; 9020df34a80SLiviu Dudau 903ad49f860SLiviu Dudau /* first handle the config valid IRQ */ 904a6993b21SLiviu Dudau dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); 905a6993b21SLiviu Dudau if (dc_status & hw->map.dc_irq_map.vsync_irq) { 906ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); 907d862b2d6SLiviu Dudau /* do we have a page flip event? */ 908d862b2d6SLiviu Dudau if (malidp->event != NULL) { 909d862b2d6SLiviu Dudau spin_lock(&drm->event_lock); 910d862b2d6SLiviu Dudau drm_crtc_send_vblank_event(&malidp->crtc, malidp->event); 911d862b2d6SLiviu Dudau malidp->event = NULL; 912d862b2d6SLiviu Dudau spin_unlock(&drm->event_lock); 913d862b2d6SLiviu Dudau } 9141cb3cbe7SLiviu Dudau atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); 915ad49f860SLiviu Dudau ret = IRQ_WAKE_THREAD; 916ad49f860SLiviu Dudau } 917ad49f860SLiviu Dudau 918ad49f860SLiviu Dudau status = malidp_hw_read(hwdev, MALIDP_REG_STATUS); 919ad49f860SLiviu Dudau if (!(status & de->irq_mask)) 920ad49f860SLiviu Dudau return ret; 921ad49f860SLiviu Dudau 922ad49f860SLiviu Dudau mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); 923ad49f860SLiviu Dudau status &= mask; 924d862b2d6SLiviu Dudau if ((status & de->vsync_irq) && malidp->crtc.enabled) 925ad49f860SLiviu Dudau drm_crtc_handle_vblank(&malidp->crtc); 926ad49f860SLiviu Dudau 927ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status); 928ad49f860SLiviu Dudau 929ad49f860SLiviu Dudau return (ret == IRQ_NONE) ? IRQ_HANDLED : ret; 930ad49f860SLiviu Dudau } 931ad49f860SLiviu Dudau 932ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg) 933ad49f860SLiviu Dudau { 934ad49f860SLiviu Dudau struct drm_device *drm = arg; 935ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 936ad49f860SLiviu Dudau 937ad49f860SLiviu Dudau wake_up(&malidp->wq); 938ad49f860SLiviu Dudau 939ad49f860SLiviu Dudau return IRQ_HANDLED; 940ad49f860SLiviu Dudau } 941ad49f860SLiviu Dudau 942ad49f860SLiviu Dudau int malidp_de_irq_init(struct drm_device *drm, int irq) 943ad49f860SLiviu Dudau { 944ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 945ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 946ad49f860SLiviu Dudau int ret; 947ad49f860SLiviu Dudau 948ad49f860SLiviu Dudau /* ensure interrupts are disabled */ 949ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 950ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 951ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 952ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 953ad49f860SLiviu Dudau 954ad49f860SLiviu Dudau ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq, 955ad49f860SLiviu Dudau malidp_de_irq_thread_handler, 956ad49f860SLiviu Dudau IRQF_SHARED, "malidp-de", drm); 957ad49f860SLiviu Dudau if (ret < 0) { 958ad49f860SLiviu Dudau DRM_ERROR("failed to install DE IRQ handler\n"); 959ad49f860SLiviu Dudau return ret; 960ad49f860SLiviu Dudau } 961ad49f860SLiviu Dudau 962ad49f860SLiviu Dudau /* first enable the DC block IRQs */ 963ad49f860SLiviu Dudau malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, 964a6993b21SLiviu Dudau hwdev->hw->map.dc_irq_map.irq_mask); 965ad49f860SLiviu Dudau 966ad49f860SLiviu Dudau /* now enable the DE block IRQs */ 967ad49f860SLiviu Dudau malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, 968a6993b21SLiviu Dudau hwdev->hw->map.de_irq_map.irq_mask); 969ad49f860SLiviu Dudau 970ad49f860SLiviu Dudau return 0; 971ad49f860SLiviu Dudau } 972ad49f860SLiviu Dudau 973ad49f860SLiviu Dudau void malidp_de_irq_fini(struct drm_device *drm) 974ad49f860SLiviu Dudau { 975ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 976ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 977ad49f860SLiviu Dudau 978ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 979a6993b21SLiviu Dudau hwdev->hw->map.de_irq_map.irq_mask); 980ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 981a6993b21SLiviu Dudau hwdev->hw->map.dc_irq_map.irq_mask); 982ad49f860SLiviu Dudau } 983ad49f860SLiviu Dudau 984ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq(int irq, void *arg) 985ad49f860SLiviu Dudau { 986ad49f860SLiviu Dudau struct drm_device *drm = arg; 987ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 988ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 989a6993b21SLiviu Dudau struct malidp_hw *hw = hwdev->hw; 990a6993b21SLiviu Dudau const struct malidp_irq_map *se = &hw->map.se_irq_map; 991ad49f860SLiviu Dudau u32 status, mask; 992ad49f860SLiviu Dudau 9930df34a80SLiviu Dudau /* 9940df34a80SLiviu Dudau * if we are suspended it is likely that we were invoked because 9950df34a80SLiviu Dudau * we share an interrupt line with some other driver, don't try 9960df34a80SLiviu Dudau * to read the hardware registers 9970df34a80SLiviu Dudau */ 9980df34a80SLiviu Dudau if (hwdev->pm_suspended) 9990df34a80SLiviu Dudau return IRQ_NONE; 10000df34a80SLiviu Dudau 1001a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); 1002a6993b21SLiviu Dudau if (!(status & se->irq_mask)) 1003ad49f860SLiviu Dudau return IRQ_NONE; 1004ad49f860SLiviu Dudau 1005a6993b21SLiviu Dudau mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); 1006a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); 1007ad49f860SLiviu Dudau status &= mask; 10081cb3cbe7SLiviu Dudau 10091cb3cbe7SLiviu Dudau if (status & se->vsync_irq) { 10101cb3cbe7SLiviu Dudau switch (hwdev->mw_state) { 10118cbc5cafSBrian Starkey case MW_ONESHOT: 10128cbc5cafSBrian Starkey drm_writeback_signal_completion(&malidp->mw_connector, 0); 10138cbc5cafSBrian Starkey break; 10141cb3cbe7SLiviu Dudau case MW_STOP: 10158cbc5cafSBrian Starkey drm_writeback_signal_completion(&malidp->mw_connector, 0); 10161cb3cbe7SLiviu Dudau /* disable writeback after stop */ 10171cb3cbe7SLiviu Dudau hwdev->mw_state = MW_NOT_ENABLED; 10181cb3cbe7SLiviu Dudau break; 10190735cfdfSLiviu Dudau case MW_RESTART: 10200735cfdfSLiviu Dudau drm_writeback_signal_completion(&malidp->mw_connector, 0); 10210735cfdfSLiviu Dudau /* fall through to a new start */ 10221cb3cbe7SLiviu Dudau case MW_START: 10231cb3cbe7SLiviu Dudau /* writeback started, need to emulate one-shot mode */ 10241cb3cbe7SLiviu Dudau hw->disable_memwrite(hwdev); 10251cb3cbe7SLiviu Dudau /* 10260735cfdfSLiviu Dudau * only set config_valid HW bit if there is no other update 10270735cfdfSLiviu Dudau * in progress or if we raced ahead of the DE IRQ handler 10280735cfdfSLiviu Dudau * and config_valid flag will not be update until later 10291cb3cbe7SLiviu Dudau */ 10300735cfdfSLiviu Dudau status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); 10310735cfdfSLiviu Dudau if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) || 10320735cfdfSLiviu Dudau (status & hw->map.dc_irq_map.vsync_irq)) 10330735cfdfSLiviu Dudau hw->set_config_valid(hwdev, 1); 10341cb3cbe7SLiviu Dudau break; 10351cb3cbe7SLiviu Dudau } 10361cb3cbe7SLiviu Dudau } 1037ad49f860SLiviu Dudau 1038ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status); 1039ad49f860SLiviu Dudau 1040ad49f860SLiviu Dudau return IRQ_HANDLED; 1041ad49f860SLiviu Dudau } 1042ad49f860SLiviu Dudau 1043ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) 1044ad49f860SLiviu Dudau { 1045ad49f860SLiviu Dudau return IRQ_HANDLED; 1046ad49f860SLiviu Dudau } 1047ad49f860SLiviu Dudau 1048ad49f860SLiviu Dudau int malidp_se_irq_init(struct drm_device *drm, int irq) 1049ad49f860SLiviu Dudau { 1050ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 1051ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 1052ad49f860SLiviu Dudau int ret; 1053ad49f860SLiviu Dudau 1054ad49f860SLiviu Dudau /* ensure interrupts are disabled */ 1055ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 1056ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 1057ad49f860SLiviu Dudau 1058ad49f860SLiviu Dudau ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq, 1059ad49f860SLiviu Dudau malidp_se_irq_thread_handler, 1060ad49f860SLiviu Dudau IRQF_SHARED, "malidp-se", drm); 1061ad49f860SLiviu Dudau if (ret < 0) { 1062ad49f860SLiviu Dudau DRM_ERROR("failed to install SE IRQ handler\n"); 1063ad49f860SLiviu Dudau return ret; 1064ad49f860SLiviu Dudau } 1065ad49f860SLiviu Dudau 10661cb3cbe7SLiviu Dudau hwdev->mw_state = MW_NOT_ENABLED; 1067ad49f860SLiviu Dudau malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, 1068a6993b21SLiviu Dudau hwdev->hw->map.se_irq_map.irq_mask); 1069ad49f860SLiviu Dudau 1070ad49f860SLiviu Dudau return 0; 1071ad49f860SLiviu Dudau } 1072ad49f860SLiviu Dudau 1073ad49f860SLiviu Dudau void malidp_se_irq_fini(struct drm_device *drm) 1074ad49f860SLiviu Dudau { 1075ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 1076ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 1077ad49f860SLiviu Dudau 1078ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 1079a6993b21SLiviu Dudau hwdev->hw->map.se_irq_map.irq_mask); 1080ad49f860SLiviu Dudau } 1081