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" 24ad49f860SLiviu Dudau 256211b486SBrian Starkey static const struct malidp_format_id malidp500_de_formats[] = { 26ad49f860SLiviu Dudau /* fourcc, layers supporting the format, internal id */ 27ad49f860SLiviu Dudau { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 }, 28ad49f860SLiviu Dudau { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 }, 29ad49f860SLiviu Dudau { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 }, 30ad49f860SLiviu Dudau { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 }, 31ad49f860SLiviu Dudau { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 4 }, 32ad49f860SLiviu Dudau { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 5 }, 33ad49f860SLiviu Dudau { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 }, 34ad49f860SLiviu Dudau { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 }, 35ad49f860SLiviu Dudau { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 }, 36ad49f860SLiviu Dudau { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 }, 37ad49f860SLiviu Dudau { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 }, 38ad49f860SLiviu Dudau { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 }, 39ad49f860SLiviu Dudau { DRM_FORMAT_UYVY, DE_VIDEO1, 12 }, 40ad49f860SLiviu Dudau { DRM_FORMAT_YUYV, DE_VIDEO1, 13 }, 41ad49f860SLiviu Dudau { DRM_FORMAT_NV12, DE_VIDEO1, 14 }, 42ad49f860SLiviu Dudau { DRM_FORMAT_YUV420, DE_VIDEO1, 15 }, 43ad49f860SLiviu Dudau }; 44ad49f860SLiviu Dudau 45ad49f860SLiviu Dudau #define MALIDP_ID(__group, __format) \ 46ad49f860SLiviu Dudau ((((__group) & 0x7) << 3) | ((__format) & 0x7)) 47ad49f860SLiviu Dudau 48ad49f860SLiviu Dudau #define MALIDP_COMMON_FORMATS \ 49ad49f860SLiviu Dudau /* fourcc, layers supporting the format, internal id */ \ 50ad49f860SLiviu Dudau { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \ 51ad49f860SLiviu Dudau { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \ 52ad49f860SLiviu Dudau { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \ 53ad49f860SLiviu Dudau { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \ 54ad49f860SLiviu Dudau { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \ 55ad49f860SLiviu Dudau { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \ 56ad49f860SLiviu Dudau { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \ 57ad49f860SLiviu Dudau { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \ 58ad49f860SLiviu Dudau { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \ 59ad49f860SLiviu Dudau { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \ 60ad49f860SLiviu Dudau { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \ 61ad49f860SLiviu Dudau { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \ 62ad49f860SLiviu Dudau { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \ 63ad49f860SLiviu Dudau { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \ 64ad49f860SLiviu Dudau { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \ 65ad49f860SLiviu Dudau { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \ 66ad49f860SLiviu Dudau { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \ 67ad49f860SLiviu Dudau { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \ 68ad49f860SLiviu Dudau { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \ 69ad49f860SLiviu Dudau { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \ 70ad49f860SLiviu Dudau { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \ 71ad49f860SLiviu Dudau { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) } 72ad49f860SLiviu Dudau 736211b486SBrian Starkey static const struct malidp_format_id malidp550_de_formats[] = { 74ad49f860SLiviu Dudau MALIDP_COMMON_FORMATS, 75ad49f860SLiviu Dudau }; 76ad49f860SLiviu Dudau 77ad49f860SLiviu Dudau static const struct malidp_layer malidp500_layers[] = { 786e810eb5SMihail Atanassov { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB }, 796e810eb5SMihail Atanassov { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 806e810eb5SMihail Atanassov { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 81ad49f860SLiviu Dudau }; 82ad49f860SLiviu Dudau 83ad49f860SLiviu Dudau static const struct malidp_layer malidp550_layers[] = { 846e810eb5SMihail Atanassov { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, 856e810eb5SMihail Atanassov { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 }, 866e810eb5SMihail Atanassov { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB }, 876e810eb5SMihail Atanassov { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 }, 88ad49f860SLiviu Dudau }; 89ad49f860SLiviu Dudau 9028ce675bSMihail Atanassov #define SE_N_SCALING_COEFFS 96 9128ce675bSMihail Atanassov static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = { 9228ce675bSMihail Atanassov [MALIDP_UPSCALING_COEFFS - 1] = { 9328ce675bSMihail Atanassov 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052, 9428ce675bSMihail Atanassov 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f, 9528ce675bSMihail Atanassov 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a, 9628ce675bSMihail Atanassov 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40, 9728ce675bSMihail Atanassov 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c, 9828ce675bSMihail Atanassov 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5, 9928ce675bSMihail Atanassov 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15, 10028ce675bSMihail Atanassov 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5, 10128ce675bSMihail Atanassov 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0, 10228ce675bSMihail Atanassov 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6, 10328ce675bSMihail Atanassov 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073, 10428ce675bSMihail Atanassov 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001 10528ce675bSMihail Atanassov }, 10628ce675bSMihail Atanassov [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = { 10728ce675bSMihail Atanassov 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4, 10828ce675bSMihail Atanassov 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c, 10928ce675bSMihail Atanassov 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5, 11028ce675bSMihail Atanassov 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8, 11128ce675bSMihail Atanassov 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba, 11228ce675bSMihail Atanassov 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20, 11328ce675bSMihail Atanassov 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03, 11428ce675bSMihail Atanassov 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d, 11528ce675bSMihail Atanassov 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68, 11628ce675bSMihail Atanassov 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f, 11728ce675bSMihail Atanassov 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62, 11828ce675bSMihail Atanassov 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f 11928ce675bSMihail Atanassov }, 12028ce675bSMihail Atanassov [MALIDP_DOWNSCALING_2_COEFFS - 1] = { 12128ce675bSMihail Atanassov 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9, 12228ce675bSMihail Atanassov 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52, 12328ce675bSMihail Atanassov 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158, 12428ce675bSMihail Atanassov 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455, 12528ce675bSMihail Atanassov 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e, 12628ce675bSMihail Atanassov 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887, 12728ce675bSMihail Atanassov 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5, 12828ce675bSMihail Atanassov 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e, 12928ce675bSMihail Atanassov 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d, 13028ce675bSMihail Atanassov 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0, 13128ce675bSMihail Atanassov 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf, 13228ce675bSMihail Atanassov 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03 13328ce675bSMihail Atanassov }, 13428ce675bSMihail Atanassov [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = { 13528ce675bSMihail Atanassov 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3, 13628ce675bSMihail Atanassov 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106, 13728ce675bSMihail Atanassov 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280, 13828ce675bSMihail Atanassov 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410, 13928ce675bSMihail Atanassov 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533, 14028ce675bSMihail Atanassov 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3, 14128ce675bSMihail Atanassov 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566, 14228ce675bSMihail Atanassov 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468, 14328ce675bSMihail Atanassov 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4, 14428ce675bSMihail Atanassov 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160, 14528ce675bSMihail Atanassov 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f, 14628ce675bSMihail Atanassov 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60 14728ce675bSMihail Atanassov }, 14828ce675bSMihail Atanassov [MALIDP_DOWNSCALING_4_COEFFS - 1] = { 14928ce675bSMihail Atanassov 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f, 15028ce675bSMihail Atanassov 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff, 15128ce675bSMihail Atanassov 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd, 15228ce675bSMihail Atanassov 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374, 15328ce675bSMihail Atanassov 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db, 15428ce675bSMihail Atanassov 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a, 15528ce675bSMihail Atanassov 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed, 15628ce675bSMihail Atanassov 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397, 15728ce675bSMihail Atanassov 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb, 15828ce675bSMihail Atanassov 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233, 15928ce675bSMihail Atanassov 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160, 16028ce675bSMihail Atanassov 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9 16128ce675bSMihail Atanassov }, 16228ce675bSMihail Atanassov }; 16328ce675bSMihail Atanassov 164ad49f860SLiviu Dudau #define MALIDP_DE_DEFAULT_PREFETCH_START 5 165ad49f860SLiviu Dudau 166ad49f860SLiviu Dudau static int malidp500_query_hw(struct malidp_hw_device *hwdev) 167ad49f860SLiviu Dudau { 168ad49f860SLiviu Dudau u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID); 169ad49f860SLiviu Dudau /* bit 4 of the CONFIG_ID register holds the line size multiplier */ 170ad49f860SLiviu Dudau u8 ln_size_mult = conf & 0x10 ? 2 : 1; 171ad49f860SLiviu Dudau 172ad49f860SLiviu Dudau hwdev->min_line_size = 2; 173ad49f860SLiviu Dudau hwdev->max_line_size = SZ_2K * ln_size_mult; 174ad49f860SLiviu Dudau hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult; 175ad49f860SLiviu Dudau hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */ 176ad49f860SLiviu Dudau 177ad49f860SLiviu Dudau return 0; 178ad49f860SLiviu Dudau } 179ad49f860SLiviu Dudau 180ad49f860SLiviu Dudau static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev) 181ad49f860SLiviu Dudau { 182ad49f860SLiviu Dudau u32 status, count = 100; 183ad49f860SLiviu Dudau 184ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); 185ad49f860SLiviu Dudau while (count) { 186a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 187ad49f860SLiviu Dudau if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) 188ad49f860SLiviu Dudau break; 189ad49f860SLiviu Dudau /* 190ad49f860SLiviu Dudau * entering config mode can take as long as the rendering 191ad49f860SLiviu Dudau * of a full frame, hence the long sleep here 192ad49f860SLiviu Dudau */ 193ad49f860SLiviu Dudau usleep_range(1000, 10000); 194ad49f860SLiviu Dudau count--; 195ad49f860SLiviu Dudau } 196ad49f860SLiviu Dudau WARN(count == 0, "timeout while entering config mode"); 197ad49f860SLiviu Dudau } 198ad49f860SLiviu Dudau 199ad49f860SLiviu Dudau static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev) 200ad49f860SLiviu Dudau { 201ad49f860SLiviu Dudau u32 status, count = 100; 202ad49f860SLiviu Dudau 203e64053f0SBrian Starkey malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 204ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); 205ad49f860SLiviu Dudau while (count) { 206a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 207ad49f860SLiviu Dudau if ((status & MALIDP500_DC_CONFIG_REQ) == 0) 208ad49f860SLiviu Dudau break; 209ad49f860SLiviu Dudau usleep_range(100, 1000); 210ad49f860SLiviu Dudau count--; 211ad49f860SLiviu Dudau } 212ad49f860SLiviu Dudau WARN(count == 0, "timeout while leaving config mode"); 213ad49f860SLiviu Dudau } 214ad49f860SLiviu Dudau 215ad49f860SLiviu Dudau static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev) 216ad49f860SLiviu Dudau { 217ad49f860SLiviu Dudau u32 status; 218ad49f860SLiviu Dudau 219a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 220ad49f860SLiviu Dudau if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) 221ad49f860SLiviu Dudau return true; 222ad49f860SLiviu Dudau 223ad49f860SLiviu Dudau return false; 224ad49f860SLiviu Dudau } 225ad49f860SLiviu Dudau 226ad49f860SLiviu Dudau static void malidp500_set_config_valid(struct malidp_hw_device *hwdev) 227ad49f860SLiviu Dudau { 228ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 229ad49f860SLiviu Dudau } 230ad49f860SLiviu Dudau 231ad49f860SLiviu Dudau static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) 232ad49f860SLiviu Dudau { 233ad49f860SLiviu Dudau u32 val = 0; 234ad49f860SLiviu Dudau 235ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL); 236ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) 237ad49f860SLiviu Dudau val |= MALIDP500_HSYNCPOL; 238ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) 239ad49f860SLiviu Dudau val |= MALIDP500_VSYNCPOL; 240ad49f860SLiviu Dudau val |= MALIDP_DE_DEFAULT_PREFETCH_START; 241ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL); 242ad49f860SLiviu Dudau 243ad49f860SLiviu Dudau /* 244ad49f860SLiviu Dudau * Mali-DP500 encodes the background color like this: 245ad49f860SLiviu Dudau * - red @ MALIDP500_BGND_COLOR[12:0] 246ad49f860SLiviu Dudau * - green @ MALIDP500_BGND_COLOR[27:16] 247ad49f860SLiviu Dudau * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0] 248ad49f860SLiviu Dudau */ 249ad49f860SLiviu Dudau val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) | 250ad49f860SLiviu Dudau (MALIDP_BGND_COLOR_R & 0xfff); 251ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR); 252ad49f860SLiviu Dudau malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4); 253ad49f860SLiviu Dudau 254ad49f860SLiviu Dudau val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | 255ad49f860SLiviu Dudau MALIDP_DE_H_BACKPORCH(mode->hback_porch); 256ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); 257ad49f860SLiviu Dudau 258ad49f860SLiviu Dudau val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) | 259ad49f860SLiviu Dudau MALIDP_DE_V_BACKPORCH(mode->vback_porch); 260ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); 261ad49f860SLiviu Dudau 262ad49f860SLiviu Dudau val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | 263ad49f860SLiviu Dudau MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); 264ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); 265ad49f860SLiviu Dudau 266ad49f860SLiviu Dudau val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); 267ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); 268ad49f860SLiviu Dudau 269ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_INTERLACED) 270ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 271ad49f860SLiviu Dudau else 272ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 273ad49f860SLiviu Dudau } 274ad49f860SLiviu Dudau 275ad49f860SLiviu Dudau static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) 276ad49f860SLiviu Dudau { 277ad49f860SLiviu Dudau /* RGB888 or BGR888 can't be rotated */ 278ad49f860SLiviu Dudau if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) 279ad49f860SLiviu Dudau return -EINVAL; 280ad49f860SLiviu Dudau 281ad49f860SLiviu Dudau /* 282ad49f860SLiviu Dudau * Each layer needs enough rotation memory to fit 8 lines 283ad49f860SLiviu Dudau * worth of pixel data. Required size is then: 284ad49f860SLiviu Dudau * size = rotated_width * (bpp / 8) * 8; 285ad49f860SLiviu Dudau */ 2867ccf281fSLaurent Pinchart return w * drm_format_plane_cpp(fmt, 0) * 8; 287ad49f860SLiviu Dudau } 288ad49f860SLiviu Dudau 28928ce675bSMihail Atanassov static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev, 29028ce675bSMihail Atanassov u32 direction, 29128ce675bSMihail Atanassov u16 addr, 29228ce675bSMihail Atanassov u8 coeffs_id) 29328ce675bSMihail Atanassov { 29428ce675bSMihail Atanassov int i; 29528ce675bSMihail Atanassov u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL; 29628ce675bSMihail Atanassov 29728ce675bSMihail Atanassov malidp_hw_write(hwdev, 29828ce675bSMihail Atanassov direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK), 29928ce675bSMihail Atanassov scaling_control + MALIDP_SE_COEFFTAB_ADDR); 30028ce675bSMihail Atanassov for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i) 30128ce675bSMihail Atanassov malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA( 30228ce675bSMihail Atanassov dp500_se_scaling_coeffs[coeffs_id][i]), 30328ce675bSMihail Atanassov scaling_control + MALIDP_SE_COEFFTAB_DATA); 30428ce675bSMihail Atanassov } 30528ce675bSMihail Atanassov 30628ce675bSMihail Atanassov static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, 30728ce675bSMihail Atanassov struct malidp_se_config *se_config, 30828ce675bSMihail Atanassov struct malidp_se_config *old_config) 30928ce675bSMihail Atanassov { 31028ce675bSMihail Atanassov /* Get array indices into dp500_se_scaling_coeffs. */ 31128ce675bSMihail Atanassov u8 h = (u8)se_config->hcoeff - 1; 31228ce675bSMihail Atanassov u8 v = (u8)se_config->vcoeff - 1; 31328ce675bSMihail Atanassov 31428ce675bSMihail Atanassov if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) || 31528ce675bSMihail Atanassov v >= ARRAY_SIZE(dp500_se_scaling_coeffs))) 31628ce675bSMihail Atanassov return -EINVAL; 31728ce675bSMihail Atanassov 31828ce675bSMihail Atanassov if ((h == v) && (se_config->hcoeff != old_config->hcoeff || 31928ce675bSMihail Atanassov se_config->vcoeff != old_config->vcoeff)) { 32028ce675bSMihail Atanassov malidp500_se_write_pp_coefftab(hwdev, 32128ce675bSMihail Atanassov (MALIDP_SE_V_COEFFTAB | 32228ce675bSMihail Atanassov MALIDP_SE_H_COEFFTAB), 32328ce675bSMihail Atanassov 0, v); 32428ce675bSMihail Atanassov } else { 32528ce675bSMihail Atanassov if (se_config->vcoeff != old_config->vcoeff) 32628ce675bSMihail Atanassov malidp500_se_write_pp_coefftab(hwdev, 32728ce675bSMihail Atanassov MALIDP_SE_V_COEFFTAB, 32828ce675bSMihail Atanassov 0, v); 32928ce675bSMihail Atanassov if (se_config->hcoeff != old_config->hcoeff) 33028ce675bSMihail Atanassov malidp500_se_write_pp_coefftab(hwdev, 33128ce675bSMihail Atanassov MALIDP_SE_H_COEFFTAB, 33228ce675bSMihail Atanassov 0, h); 33328ce675bSMihail Atanassov } 33428ce675bSMihail Atanassov 33528ce675bSMihail Atanassov return 0; 33628ce675bSMihail Atanassov } 33728ce675bSMihail Atanassov 338c2e7f82dSMihail Atanassov static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, 339c2e7f82dSMihail Atanassov struct malidp_se_config *se_config, 340c2e7f82dSMihail Atanassov struct videomode *vm) 341c2e7f82dSMihail Atanassov { 342c2e7f82dSMihail Atanassov unsigned long mclk; 343c2e7f82dSMihail Atanassov unsigned long pxlclk = vm->pixelclock; /* Hz */ 344c2e7f82dSMihail Atanassov unsigned long htotal = vm->hactive + vm->hfront_porch + 345c2e7f82dSMihail Atanassov vm->hback_porch + vm->hsync_len; 346c2e7f82dSMihail Atanassov unsigned long input_size = se_config->input_w * se_config->input_h; 347c2e7f82dSMihail Atanassov unsigned long a = 10; 348c2e7f82dSMihail Atanassov long ret; 349c2e7f82dSMihail Atanassov 350c2e7f82dSMihail Atanassov /* 351c2e7f82dSMihail Atanassov * mclk = max(a, 1.5) * pxlclk 352c2e7f82dSMihail Atanassov * 353c2e7f82dSMihail Atanassov * To avoid float calculaiton, using 15 instead of 1.5 and div by 354c2e7f82dSMihail Atanassov * 10 to get mclk. 355c2e7f82dSMihail Atanassov */ 356c2e7f82dSMihail Atanassov if (se_config->scale_enable) { 357c2e7f82dSMihail Atanassov a = 15 * input_size / (htotal * se_config->output_h); 358c2e7f82dSMihail Atanassov if (a < 15) 359c2e7f82dSMihail Atanassov a = 15; 360c2e7f82dSMihail Atanassov } 361c2e7f82dSMihail Atanassov mclk = a * pxlclk / 10; 362c2e7f82dSMihail Atanassov ret = clk_get_rate(hwdev->mclk); 363c2e7f82dSMihail Atanassov if (ret < mclk) { 364c2e7f82dSMihail Atanassov DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", 365c2e7f82dSMihail Atanassov mclk / 1000); 366c2e7f82dSMihail Atanassov return -EINVAL; 367c2e7f82dSMihail Atanassov } 368c2e7f82dSMihail Atanassov return ret; 369c2e7f82dSMihail Atanassov } 370c2e7f82dSMihail Atanassov 371ad49f860SLiviu Dudau static int malidp550_query_hw(struct malidp_hw_device *hwdev) 372ad49f860SLiviu Dudau { 373ad49f860SLiviu Dudau u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 374ad49f860SLiviu Dudau u8 ln_size = (conf >> 4) & 0x3, rsize; 375ad49f860SLiviu Dudau 376ad49f860SLiviu Dudau hwdev->min_line_size = 2; 377ad49f860SLiviu Dudau 378ad49f860SLiviu Dudau switch (ln_size) { 379ad49f860SLiviu Dudau case 0: 380ad49f860SLiviu Dudau hwdev->max_line_size = SZ_2K; 381ad49f860SLiviu Dudau /* two banks of 64KB for rotation memory */ 382ad49f860SLiviu Dudau rsize = 64; 383ad49f860SLiviu Dudau break; 384ad49f860SLiviu Dudau case 1: 385ad49f860SLiviu Dudau hwdev->max_line_size = SZ_4K; 386ad49f860SLiviu Dudau /* two banks of 128KB for rotation memory */ 387ad49f860SLiviu Dudau rsize = 128; 388ad49f860SLiviu Dudau break; 389ad49f860SLiviu Dudau case 2: 390ad49f860SLiviu Dudau hwdev->max_line_size = 1280; 391ad49f860SLiviu Dudau /* two banks of 40KB for rotation memory */ 392ad49f860SLiviu Dudau rsize = 40; 393ad49f860SLiviu Dudau break; 394ad49f860SLiviu Dudau case 3: 395ad49f860SLiviu Dudau /* reserved value */ 396ad49f860SLiviu Dudau hwdev->max_line_size = 0; 397ad49f860SLiviu Dudau return -EINVAL; 398ad49f860SLiviu Dudau } 399ad49f860SLiviu Dudau 400ad49f860SLiviu Dudau hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; 401ad49f860SLiviu Dudau return 0; 402ad49f860SLiviu Dudau } 403ad49f860SLiviu Dudau 404ad49f860SLiviu Dudau static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev) 405ad49f860SLiviu Dudau { 406ad49f860SLiviu Dudau u32 status, count = 100; 407ad49f860SLiviu Dudau 408ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); 409ad49f860SLiviu Dudau while (count) { 410a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 411ad49f860SLiviu Dudau if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) 412ad49f860SLiviu Dudau break; 413ad49f860SLiviu Dudau /* 414ad49f860SLiviu Dudau * entering config mode can take as long as the rendering 415ad49f860SLiviu Dudau * of a full frame, hence the long sleep here 416ad49f860SLiviu Dudau */ 417ad49f860SLiviu Dudau usleep_range(1000, 10000); 418ad49f860SLiviu Dudau count--; 419ad49f860SLiviu Dudau } 420ad49f860SLiviu Dudau WARN(count == 0, "timeout while entering config mode"); 421ad49f860SLiviu Dudau } 422ad49f860SLiviu Dudau 423ad49f860SLiviu Dudau static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev) 424ad49f860SLiviu Dudau { 425ad49f860SLiviu Dudau u32 status, count = 100; 426ad49f860SLiviu Dudau 427e64053f0SBrian Starkey malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 428ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); 429ad49f860SLiviu Dudau while (count) { 430a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 431ad49f860SLiviu Dudau if ((status & MALIDP550_DC_CONFIG_REQ) == 0) 432ad49f860SLiviu Dudau break; 433ad49f860SLiviu Dudau usleep_range(100, 1000); 434ad49f860SLiviu Dudau count--; 435ad49f860SLiviu Dudau } 436ad49f860SLiviu Dudau WARN(count == 0, "timeout while leaving config mode"); 437ad49f860SLiviu Dudau } 438ad49f860SLiviu Dudau 439ad49f860SLiviu Dudau static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev) 440ad49f860SLiviu Dudau { 441ad49f860SLiviu Dudau u32 status; 442ad49f860SLiviu Dudau 443a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 444ad49f860SLiviu Dudau if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) 445ad49f860SLiviu Dudau return true; 446ad49f860SLiviu Dudau 447ad49f860SLiviu Dudau return false; 448ad49f860SLiviu Dudau } 449ad49f860SLiviu Dudau 450ad49f860SLiviu Dudau static void malidp550_set_config_valid(struct malidp_hw_device *hwdev) 451ad49f860SLiviu Dudau { 452ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 453ad49f860SLiviu Dudau } 454ad49f860SLiviu Dudau 455ad49f860SLiviu Dudau static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) 456ad49f860SLiviu Dudau { 457ad49f860SLiviu Dudau u32 val = MALIDP_DE_DEFAULT_PREFETCH_START; 458ad49f860SLiviu Dudau 459ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL); 460ad49f860SLiviu Dudau /* 461ad49f860SLiviu Dudau * Mali-DP550 and Mali-DP650 encode the background color like this: 462ad49f860SLiviu Dudau * - red @ MALIDP550_DE_BGND_COLOR[23:16] 463ad49f860SLiviu Dudau * - green @ MALIDP550_DE_BGND_COLOR[15:8] 464ad49f860SLiviu Dudau * - blue @ MALIDP550_DE_BGND_COLOR[7:0] 465ad49f860SLiviu Dudau * 466ad49f860SLiviu Dudau * We need to truncate the least significant 4 bits from the default 467ad49f860SLiviu Dudau * MALIDP_BGND_COLOR_x values 468ad49f860SLiviu Dudau */ 469ad49f860SLiviu Dudau val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) | 470ad49f860SLiviu Dudau (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) | 471ad49f860SLiviu Dudau ((MALIDP_BGND_COLOR_B >> 4) & 0xff); 472ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR); 473ad49f860SLiviu Dudau 474ad49f860SLiviu Dudau val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | 475ad49f860SLiviu Dudau MALIDP_DE_H_BACKPORCH(mode->hback_porch); 476ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); 477ad49f860SLiviu Dudau 478ad49f860SLiviu Dudau val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) | 479ad49f860SLiviu Dudau MALIDP_DE_V_BACKPORCH(mode->vback_porch); 480ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); 481ad49f860SLiviu Dudau 482ad49f860SLiviu Dudau val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | 483ad49f860SLiviu Dudau MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); 484ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) 485ad49f860SLiviu Dudau val |= MALIDP550_HSYNCPOL; 486ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) 487ad49f860SLiviu Dudau val |= MALIDP550_VSYNCPOL; 488ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); 489ad49f860SLiviu Dudau 490ad49f860SLiviu Dudau val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); 491ad49f860SLiviu Dudau malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); 492ad49f860SLiviu Dudau 493ad49f860SLiviu Dudau if (mode->flags & DISPLAY_FLAGS_INTERLACED) 494ad49f860SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 495ad49f860SLiviu Dudau else 496ad49f860SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 497ad49f860SLiviu Dudau } 498ad49f860SLiviu Dudau 499ad49f860SLiviu Dudau static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) 500ad49f860SLiviu Dudau { 501ad49f860SLiviu Dudau u32 bytes_per_col; 502ad49f860SLiviu Dudau 503ad49f860SLiviu Dudau /* raw RGB888 or BGR888 can't be rotated */ 504ad49f860SLiviu Dudau if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) 505ad49f860SLiviu Dudau return -EINVAL; 506ad49f860SLiviu Dudau 507ad49f860SLiviu Dudau switch (fmt) { 508ad49f860SLiviu Dudau /* 8 lines at 4 bytes per pixel */ 509ad49f860SLiviu Dudau case DRM_FORMAT_ARGB2101010: 510ad49f860SLiviu Dudau case DRM_FORMAT_ABGR2101010: 511ad49f860SLiviu Dudau case DRM_FORMAT_RGBA1010102: 512ad49f860SLiviu Dudau case DRM_FORMAT_BGRA1010102: 513ad49f860SLiviu Dudau case DRM_FORMAT_ARGB8888: 514ad49f860SLiviu Dudau case DRM_FORMAT_ABGR8888: 515ad49f860SLiviu Dudau case DRM_FORMAT_RGBA8888: 516ad49f860SLiviu Dudau case DRM_FORMAT_BGRA8888: 517ad49f860SLiviu Dudau case DRM_FORMAT_XRGB8888: 518ad49f860SLiviu Dudau case DRM_FORMAT_XBGR8888: 519ad49f860SLiviu Dudau case DRM_FORMAT_RGBX8888: 520ad49f860SLiviu Dudau case DRM_FORMAT_BGRX8888: 521ad49f860SLiviu Dudau case DRM_FORMAT_RGB888: 522ad49f860SLiviu Dudau case DRM_FORMAT_BGR888: 523ad49f860SLiviu Dudau /* 16 lines at 2 bytes per pixel */ 524ad49f860SLiviu Dudau case DRM_FORMAT_RGBA5551: 525ad49f860SLiviu Dudau case DRM_FORMAT_ABGR1555: 526ad49f860SLiviu Dudau case DRM_FORMAT_RGB565: 527ad49f860SLiviu Dudau case DRM_FORMAT_BGR565: 528ad49f860SLiviu Dudau case DRM_FORMAT_UYVY: 529ad49f860SLiviu Dudau case DRM_FORMAT_YUYV: 530ad49f860SLiviu Dudau bytes_per_col = 32; 531ad49f860SLiviu Dudau break; 532ad49f860SLiviu Dudau /* 16 lines at 1.5 bytes per pixel */ 533ad49f860SLiviu Dudau case DRM_FORMAT_NV12: 534ad49f860SLiviu Dudau case DRM_FORMAT_YUV420: 535ad49f860SLiviu Dudau bytes_per_col = 24; 536ad49f860SLiviu Dudau break; 537ad49f860SLiviu Dudau default: 538ad49f860SLiviu Dudau return -EINVAL; 539ad49f860SLiviu Dudau } 540ad49f860SLiviu Dudau 541ad49f860SLiviu Dudau return w * bytes_per_col; 542ad49f860SLiviu Dudau } 543ad49f860SLiviu Dudau 54428ce675bSMihail Atanassov static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, 54528ce675bSMihail Atanassov struct malidp_se_config *se_config, 54628ce675bSMihail Atanassov struct malidp_se_config *old_config) 54728ce675bSMihail Atanassov { 54828ce675bSMihail Atanassov u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) | 54928ce675bSMihail Atanassov MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK); 55028ce675bSMihail Atanassov u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) | 55128ce675bSMihail Atanassov MALIDP550_SE_CTL_HCSEL(se_config->hcoeff); 55228ce675bSMihail Atanassov 55328ce675bSMihail Atanassov malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL); 55428ce675bSMihail Atanassov malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL); 55528ce675bSMihail Atanassov return 0; 55628ce675bSMihail Atanassov } 55728ce675bSMihail Atanassov 558c2e7f82dSMihail Atanassov static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev, 559c2e7f82dSMihail Atanassov struct malidp_se_config *se_config, 560c2e7f82dSMihail Atanassov struct videomode *vm) 561c2e7f82dSMihail Atanassov { 562c2e7f82dSMihail Atanassov unsigned long mclk; 563c2e7f82dSMihail Atanassov unsigned long pxlclk = vm->pixelclock; 564c2e7f82dSMihail Atanassov unsigned long htotal = vm->hactive + vm->hfront_porch + 565c2e7f82dSMihail Atanassov vm->hback_porch + vm->hsync_len; 566c2e7f82dSMihail Atanassov unsigned long numerator = 1, denominator = 1; 567c2e7f82dSMihail Atanassov long ret; 568c2e7f82dSMihail Atanassov 569c2e7f82dSMihail Atanassov if (se_config->scale_enable) { 570c2e7f82dSMihail Atanassov numerator = max(se_config->input_w, se_config->output_w) * 571c2e7f82dSMihail Atanassov se_config->input_h; 572c2e7f82dSMihail Atanassov numerator += se_config->output_w * 573c2e7f82dSMihail Atanassov (se_config->output_h - 574c2e7f82dSMihail Atanassov min(se_config->input_h, se_config->output_h)); 575c2e7f82dSMihail Atanassov denominator = (htotal - 2) * se_config->output_h; 576c2e7f82dSMihail Atanassov } 577c2e7f82dSMihail Atanassov 578c2e7f82dSMihail Atanassov /* mclk can't be slower than pxlclk. */ 579c2e7f82dSMihail Atanassov if (numerator < denominator) 580c2e7f82dSMihail Atanassov numerator = denominator = 1; 581c2e7f82dSMihail Atanassov mclk = (pxlclk * numerator) / denominator; 582c2e7f82dSMihail Atanassov ret = clk_get_rate(hwdev->mclk); 583c2e7f82dSMihail Atanassov if (ret < mclk) { 584c2e7f82dSMihail Atanassov DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", 585c2e7f82dSMihail Atanassov mclk / 1000); 586c2e7f82dSMihail Atanassov return -EINVAL; 587c2e7f82dSMihail Atanassov } 588c2e7f82dSMihail Atanassov return ret; 589c2e7f82dSMihail Atanassov } 590c2e7f82dSMihail Atanassov 591846c87a0SLiviu Dudau static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev, 592846c87a0SLiviu Dudau dma_addr_t *addrs, s32 *pitches, 593846c87a0SLiviu Dudau int num_planes, u16 w, u16 h, u32 fmt_id) 594846c87a0SLiviu Dudau { 595846c87a0SLiviu Dudau u32 base = MALIDP550_SE_MEMWRITE_BASE; 596846c87a0SLiviu Dudau u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 597846c87a0SLiviu Dudau 598846c87a0SLiviu Dudau /* enable the scaling engine block */ 599846c87a0SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); 600846c87a0SLiviu Dudau 601846c87a0SLiviu Dudau malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); 602846c87a0SLiviu Dudau switch (num_planes) { 603846c87a0SLiviu Dudau case 2: 604846c87a0SLiviu Dudau malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); 605846c87a0SLiviu Dudau malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); 606846c87a0SLiviu Dudau malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); 607846c87a0SLiviu Dudau /* fall through */ 608846c87a0SLiviu Dudau case 1: 609846c87a0SLiviu Dudau malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); 610846c87a0SLiviu Dudau malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); 611846c87a0SLiviu Dudau malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); 612846c87a0SLiviu Dudau break; 613846c87a0SLiviu Dudau default: 614846c87a0SLiviu Dudau WARN(1, "Invalid number of planes"); 615846c87a0SLiviu Dudau } 616846c87a0SLiviu Dudau 617846c87a0SLiviu Dudau malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), 618846c87a0SLiviu Dudau MALIDP550_SE_MEMWRITE_OUT_SIZE); 619846c87a0SLiviu Dudau malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, 620846c87a0SLiviu Dudau MALIDP550_SE_CONTROL); 621846c87a0SLiviu Dudau 622846c87a0SLiviu Dudau return 0; 623846c87a0SLiviu Dudau } 624846c87a0SLiviu Dudau 625846c87a0SLiviu Dudau static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev) 626846c87a0SLiviu Dudau { 627846c87a0SLiviu Dudau u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 628846c87a0SLiviu Dudau 629846c87a0SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, 630846c87a0SLiviu Dudau MALIDP550_SE_CONTROL); 631846c87a0SLiviu Dudau malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); 632846c87a0SLiviu Dudau } 633846c87a0SLiviu Dudau 634ad49f860SLiviu Dudau static int malidp650_query_hw(struct malidp_hw_device *hwdev) 635ad49f860SLiviu Dudau { 636ad49f860SLiviu Dudau u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 637ad49f860SLiviu Dudau u8 ln_size = (conf >> 4) & 0x3, rsize; 638ad49f860SLiviu Dudau 639ad49f860SLiviu Dudau hwdev->min_line_size = 4; 640ad49f860SLiviu Dudau 641ad49f860SLiviu Dudau switch (ln_size) { 642ad49f860SLiviu Dudau case 0: 643ad49f860SLiviu Dudau case 2: 644ad49f860SLiviu Dudau /* reserved values */ 645ad49f860SLiviu Dudau hwdev->max_line_size = 0; 646ad49f860SLiviu Dudau return -EINVAL; 647ad49f860SLiviu Dudau case 1: 648ad49f860SLiviu Dudau hwdev->max_line_size = SZ_4K; 649ad49f860SLiviu Dudau /* two banks of 128KB for rotation memory */ 650ad49f860SLiviu Dudau rsize = 128; 651ad49f860SLiviu Dudau break; 652ad49f860SLiviu Dudau case 3: 653ad49f860SLiviu Dudau hwdev->max_line_size = 2560; 654ad49f860SLiviu Dudau /* two banks of 80KB for rotation memory */ 655ad49f860SLiviu Dudau rsize = 80; 656ad49f860SLiviu Dudau } 657ad49f860SLiviu Dudau 658ad49f860SLiviu Dudau hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; 659ad49f860SLiviu Dudau return 0; 660ad49f860SLiviu Dudau } 661ad49f860SLiviu Dudau 662a6993b21SLiviu Dudau const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { 663ad49f860SLiviu Dudau [MALIDP_500] = { 664ad49f860SLiviu Dudau .map = { 66502725d31SMihail Atanassov .coeffs_base = MALIDP500_COEFFS_BASE, 666ad49f860SLiviu Dudau .se_base = MALIDP500_SE_BASE, 667ad49f860SLiviu Dudau .dc_base = MALIDP500_DC_BASE, 668ad49f860SLiviu Dudau .out_depth_base = MALIDP500_OUTPUT_DEPTH, 669ad49f860SLiviu Dudau .features = 0, /* no CLEARIRQ register */ 670ad49f860SLiviu Dudau .n_layers = ARRAY_SIZE(malidp500_layers), 671ad49f860SLiviu Dudau .layers = malidp500_layers, 672ad49f860SLiviu Dudau .de_irq_map = { 673ad49f860SLiviu Dudau .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 674ad49f860SLiviu Dudau MALIDP500_DE_IRQ_AXI_ERR | 675ad49f860SLiviu Dudau MALIDP500_DE_IRQ_VSYNC | 676ad49f860SLiviu Dudau MALIDP500_DE_IRQ_GLOBAL, 677ad49f860SLiviu Dudau .vsync_irq = MALIDP500_DE_IRQ_VSYNC, 678ad49f860SLiviu Dudau }, 679ad49f860SLiviu Dudau .se_irq_map = { 68089610dc2SAlison Wang .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | 68189610dc2SAlison Wang MALIDP500_SE_IRQ_GLOBAL, 682ad49f860SLiviu Dudau .vsync_irq = 0, 683ad49f860SLiviu Dudau }, 684ad49f860SLiviu Dudau .dc_irq_map = { 685ad49f860SLiviu Dudau .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, 686ad49f860SLiviu Dudau .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID, 687ad49f860SLiviu Dudau }, 6886211b486SBrian Starkey .pixel_formats = malidp500_de_formats, 6896211b486SBrian Starkey .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats), 690a228062cSBrian Starkey .bus_align_bytes = 8, 691ad49f860SLiviu Dudau }, 692ad49f860SLiviu Dudau .query_hw = malidp500_query_hw, 693ad49f860SLiviu Dudau .enter_config_mode = malidp500_enter_config_mode, 694ad49f860SLiviu Dudau .leave_config_mode = malidp500_leave_config_mode, 695ad49f860SLiviu Dudau .in_config_mode = malidp500_in_config_mode, 696ad49f860SLiviu Dudau .set_config_valid = malidp500_set_config_valid, 697ad49f860SLiviu Dudau .modeset = malidp500_modeset, 698ad49f860SLiviu Dudau .rotmem_required = malidp500_rotmem_required, 69928ce675bSMihail Atanassov .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, 700c2e7f82dSMihail Atanassov .se_calc_mclk = malidp500_se_calc_mclk, 70183d642eeSMihail Atanassov .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, 702ad49f860SLiviu Dudau }, 703ad49f860SLiviu Dudau [MALIDP_550] = { 704ad49f860SLiviu Dudau .map = { 70502725d31SMihail Atanassov .coeffs_base = MALIDP550_COEFFS_BASE, 706ad49f860SLiviu Dudau .se_base = MALIDP550_SE_BASE, 707ad49f860SLiviu Dudau .dc_base = MALIDP550_DC_BASE, 708ad49f860SLiviu Dudau .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 709ad49f860SLiviu Dudau .features = MALIDP_REGMAP_HAS_CLEARIRQ, 710ad49f860SLiviu Dudau .n_layers = ARRAY_SIZE(malidp550_layers), 711ad49f860SLiviu Dudau .layers = malidp550_layers, 712ad49f860SLiviu Dudau .de_irq_map = { 713ad49f860SLiviu Dudau .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 714ad49f860SLiviu Dudau MALIDP550_DE_IRQ_VSYNC, 715ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DE_IRQ_VSYNC, 716ad49f860SLiviu Dudau }, 717ad49f860SLiviu Dudau .se_irq_map = { 718ad49f860SLiviu Dudau .irq_mask = MALIDP550_SE_IRQ_EOW | 719ad49f860SLiviu Dudau MALIDP550_SE_IRQ_AXI_ERR, 720846c87a0SLiviu Dudau .vsync_irq = MALIDP550_SE_IRQ_EOW, 721ad49f860SLiviu Dudau }, 722ad49f860SLiviu Dudau .dc_irq_map = { 723846c87a0SLiviu Dudau .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | 724846c87a0SLiviu Dudau MALIDP550_DC_IRQ_SE, 725ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 726ad49f860SLiviu Dudau }, 7276211b486SBrian Starkey .pixel_formats = malidp550_de_formats, 7286211b486SBrian Starkey .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), 729a228062cSBrian Starkey .bus_align_bytes = 8, 730ad49f860SLiviu Dudau }, 731ad49f860SLiviu Dudau .query_hw = malidp550_query_hw, 732ad49f860SLiviu Dudau .enter_config_mode = malidp550_enter_config_mode, 733ad49f860SLiviu Dudau .leave_config_mode = malidp550_leave_config_mode, 734ad49f860SLiviu Dudau .in_config_mode = malidp550_in_config_mode, 735ad49f860SLiviu Dudau .set_config_valid = malidp550_set_config_valid, 736ad49f860SLiviu Dudau .modeset = malidp550_modeset, 737ad49f860SLiviu Dudau .rotmem_required = malidp550_rotmem_required, 73828ce675bSMihail Atanassov .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, 739c2e7f82dSMihail Atanassov .se_calc_mclk = malidp550_se_calc_mclk, 740846c87a0SLiviu Dudau .enable_memwrite = malidp550_enable_memwrite, 741846c87a0SLiviu Dudau .disable_memwrite = malidp550_disable_memwrite, 74283d642eeSMihail Atanassov .features = 0, 743ad49f860SLiviu Dudau }, 744ad49f860SLiviu Dudau [MALIDP_650] = { 745ad49f860SLiviu Dudau .map = { 74602725d31SMihail Atanassov .coeffs_base = MALIDP550_COEFFS_BASE, 747ad49f860SLiviu Dudau .se_base = MALIDP550_SE_BASE, 748ad49f860SLiviu Dudau .dc_base = MALIDP550_DC_BASE, 749ad49f860SLiviu Dudau .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 750ad49f860SLiviu Dudau .features = MALIDP_REGMAP_HAS_CLEARIRQ, 751ad49f860SLiviu Dudau .n_layers = ARRAY_SIZE(malidp550_layers), 752ad49f860SLiviu Dudau .layers = malidp550_layers, 753ad49f860SLiviu Dudau .de_irq_map = { 754ad49f860SLiviu Dudau .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 755ad49f860SLiviu Dudau MALIDP650_DE_IRQ_DRIFT | 756ad49f860SLiviu Dudau MALIDP550_DE_IRQ_VSYNC, 757ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DE_IRQ_VSYNC, 758ad49f860SLiviu Dudau }, 759ad49f860SLiviu Dudau .se_irq_map = { 760ad49f860SLiviu Dudau .irq_mask = MALIDP550_SE_IRQ_EOW | 761ad49f860SLiviu Dudau MALIDP550_SE_IRQ_AXI_ERR, 762846c87a0SLiviu Dudau .vsync_irq = MALIDP550_SE_IRQ_EOW, 763ad49f860SLiviu Dudau }, 764ad49f860SLiviu Dudau .dc_irq_map = { 765846c87a0SLiviu Dudau .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | 766846c87a0SLiviu Dudau MALIDP550_DC_IRQ_SE, 767ad49f860SLiviu Dudau .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 768ad49f860SLiviu Dudau }, 7696211b486SBrian Starkey .pixel_formats = malidp550_de_formats, 7706211b486SBrian Starkey .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), 771a228062cSBrian Starkey .bus_align_bytes = 16, 772ad49f860SLiviu Dudau }, 773ad49f860SLiviu Dudau .query_hw = malidp650_query_hw, 774ad49f860SLiviu Dudau .enter_config_mode = malidp550_enter_config_mode, 775ad49f860SLiviu Dudau .leave_config_mode = malidp550_leave_config_mode, 776ad49f860SLiviu Dudau .in_config_mode = malidp550_in_config_mode, 777ad49f860SLiviu Dudau .set_config_valid = malidp550_set_config_valid, 778ad49f860SLiviu Dudau .modeset = malidp550_modeset, 779ad49f860SLiviu Dudau .rotmem_required = malidp550_rotmem_required, 78028ce675bSMihail Atanassov .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, 781c2e7f82dSMihail Atanassov .se_calc_mclk = malidp550_se_calc_mclk, 782846c87a0SLiviu Dudau .enable_memwrite = malidp550_enable_memwrite, 783846c87a0SLiviu Dudau .disable_memwrite = malidp550_disable_memwrite, 78483d642eeSMihail Atanassov .features = 0, 785ad49f860SLiviu Dudau }, 786ad49f860SLiviu Dudau }; 787ad49f860SLiviu Dudau 788ad49f860SLiviu Dudau u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, 789ad49f860SLiviu Dudau u8 layer_id, u32 format) 790ad49f860SLiviu Dudau { 791ad49f860SLiviu Dudau unsigned int i; 792ad49f860SLiviu Dudau 7936211b486SBrian Starkey for (i = 0; i < map->n_pixel_formats; i++) { 7946211b486SBrian Starkey if (((map->pixel_formats[i].layer & layer_id) == layer_id) && 7956211b486SBrian Starkey (map->pixel_formats[i].format == format)) 7966211b486SBrian Starkey return map->pixel_formats[i].id; 797ad49f860SLiviu Dudau } 798ad49f860SLiviu Dudau 799ad49f860SLiviu Dudau return MALIDP_INVALID_FORMAT_ID; 800ad49f860SLiviu Dudau } 801ad49f860SLiviu Dudau 802ad49f860SLiviu Dudau static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq) 803ad49f860SLiviu Dudau { 804ad49f860SLiviu Dudau u32 base = malidp_get_block_base(hwdev, block); 805ad49f860SLiviu Dudau 806a6993b21SLiviu Dudau if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) 807ad49f860SLiviu Dudau malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ); 808ad49f860SLiviu Dudau else 809ad49f860SLiviu Dudau malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS); 810ad49f860SLiviu Dudau } 811ad49f860SLiviu Dudau 812ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq(int irq, void *arg) 813ad49f860SLiviu Dudau { 814ad49f860SLiviu Dudau struct drm_device *drm = arg; 815ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 816ad49f860SLiviu Dudau struct malidp_hw_device *hwdev; 817a6993b21SLiviu Dudau struct malidp_hw *hw; 818ad49f860SLiviu Dudau const struct malidp_irq_map *de; 819ad49f860SLiviu Dudau u32 status, mask, dc_status; 820ad49f860SLiviu Dudau irqreturn_t ret = IRQ_NONE; 821ad49f860SLiviu Dudau 822ad49f860SLiviu Dudau hwdev = malidp->dev; 823a6993b21SLiviu Dudau hw = hwdev->hw; 824a6993b21SLiviu Dudau de = &hw->map.de_irq_map; 825ad49f860SLiviu Dudau 8260df34a80SLiviu Dudau /* 8270df34a80SLiviu Dudau * if we are suspended it is likely that we were invoked because 8280df34a80SLiviu Dudau * we share an interrupt line with some other driver, don't try 8290df34a80SLiviu Dudau * to read the hardware registers 8300df34a80SLiviu Dudau */ 8310df34a80SLiviu Dudau if (hwdev->pm_suspended) 8320df34a80SLiviu Dudau return IRQ_NONE; 8330df34a80SLiviu Dudau 834ad49f860SLiviu Dudau /* first handle the config valid IRQ */ 835a6993b21SLiviu Dudau dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); 836a6993b21SLiviu Dudau if (dc_status & hw->map.dc_irq_map.vsync_irq) { 837ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); 838d862b2d6SLiviu Dudau /* do we have a page flip event? */ 839d862b2d6SLiviu Dudau if (malidp->event != NULL) { 840d862b2d6SLiviu Dudau spin_lock(&drm->event_lock); 841d862b2d6SLiviu Dudau drm_crtc_send_vblank_event(&malidp->crtc, malidp->event); 842d862b2d6SLiviu Dudau malidp->event = NULL; 843d862b2d6SLiviu Dudau spin_unlock(&drm->event_lock); 844d862b2d6SLiviu Dudau } 845d862b2d6SLiviu Dudau atomic_set(&malidp->config_valid, 1); 846ad49f860SLiviu Dudau ret = IRQ_WAKE_THREAD; 847ad49f860SLiviu Dudau } 848ad49f860SLiviu Dudau 849ad49f860SLiviu Dudau status = malidp_hw_read(hwdev, MALIDP_REG_STATUS); 850ad49f860SLiviu Dudau if (!(status & de->irq_mask)) 851ad49f860SLiviu Dudau return ret; 852ad49f860SLiviu Dudau 853ad49f860SLiviu Dudau mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); 854ad49f860SLiviu Dudau status &= mask; 855d862b2d6SLiviu Dudau if ((status & de->vsync_irq) && malidp->crtc.enabled) 856ad49f860SLiviu Dudau drm_crtc_handle_vblank(&malidp->crtc); 857ad49f860SLiviu Dudau 858ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status); 859ad49f860SLiviu Dudau 860ad49f860SLiviu Dudau return (ret == IRQ_NONE) ? IRQ_HANDLED : ret; 861ad49f860SLiviu Dudau } 862ad49f860SLiviu Dudau 863ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg) 864ad49f860SLiviu Dudau { 865ad49f860SLiviu Dudau struct drm_device *drm = arg; 866ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 867ad49f860SLiviu Dudau 868ad49f860SLiviu Dudau wake_up(&malidp->wq); 869ad49f860SLiviu Dudau 870ad49f860SLiviu Dudau return IRQ_HANDLED; 871ad49f860SLiviu Dudau } 872ad49f860SLiviu Dudau 873ad49f860SLiviu Dudau int malidp_de_irq_init(struct drm_device *drm, int irq) 874ad49f860SLiviu Dudau { 875ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 876ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 877ad49f860SLiviu Dudau int ret; 878ad49f860SLiviu Dudau 879ad49f860SLiviu Dudau /* ensure interrupts are disabled */ 880ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 881ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 882ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 883ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 884ad49f860SLiviu Dudau 885ad49f860SLiviu Dudau ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq, 886ad49f860SLiviu Dudau malidp_de_irq_thread_handler, 887ad49f860SLiviu Dudau IRQF_SHARED, "malidp-de", drm); 888ad49f860SLiviu Dudau if (ret < 0) { 889ad49f860SLiviu Dudau DRM_ERROR("failed to install DE IRQ handler\n"); 890ad49f860SLiviu Dudau return ret; 891ad49f860SLiviu Dudau } 892ad49f860SLiviu Dudau 893ad49f860SLiviu Dudau /* first enable the DC block IRQs */ 894ad49f860SLiviu Dudau malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, 895a6993b21SLiviu Dudau hwdev->hw->map.dc_irq_map.irq_mask); 896ad49f860SLiviu Dudau 897ad49f860SLiviu Dudau /* now enable the DE block IRQs */ 898ad49f860SLiviu Dudau malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, 899a6993b21SLiviu Dudau hwdev->hw->map.de_irq_map.irq_mask); 900ad49f860SLiviu Dudau 901ad49f860SLiviu Dudau return 0; 902ad49f860SLiviu Dudau } 903ad49f860SLiviu Dudau 904ad49f860SLiviu Dudau void malidp_de_irq_fini(struct drm_device *drm) 905ad49f860SLiviu Dudau { 906ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 907ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 908ad49f860SLiviu Dudau 909ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 910a6993b21SLiviu Dudau hwdev->hw->map.de_irq_map.irq_mask); 911ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 912a6993b21SLiviu Dudau hwdev->hw->map.dc_irq_map.irq_mask); 913ad49f860SLiviu Dudau } 914ad49f860SLiviu Dudau 915ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq(int irq, void *arg) 916ad49f860SLiviu Dudau { 917ad49f860SLiviu Dudau struct drm_device *drm = arg; 918ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 919ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 920a6993b21SLiviu Dudau struct malidp_hw *hw = hwdev->hw; 921a6993b21SLiviu Dudau const struct malidp_irq_map *se = &hw->map.se_irq_map; 922ad49f860SLiviu Dudau u32 status, mask; 923ad49f860SLiviu Dudau 9240df34a80SLiviu Dudau /* 9250df34a80SLiviu Dudau * if we are suspended it is likely that we were invoked because 9260df34a80SLiviu Dudau * we share an interrupt line with some other driver, don't try 9270df34a80SLiviu Dudau * to read the hardware registers 9280df34a80SLiviu Dudau */ 9290df34a80SLiviu Dudau if (hwdev->pm_suspended) 9300df34a80SLiviu Dudau return IRQ_NONE; 9310df34a80SLiviu Dudau 932a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); 933a6993b21SLiviu Dudau if (!(status & se->irq_mask)) 934ad49f860SLiviu Dudau return IRQ_NONE; 935ad49f860SLiviu Dudau 936a6993b21SLiviu Dudau mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); 937a6993b21SLiviu Dudau status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); 938ad49f860SLiviu Dudau status &= mask; 939ad49f860SLiviu Dudau /* ToDo: status decoding and firing up of VSYNC and page flip events */ 940ad49f860SLiviu Dudau 941ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status); 942ad49f860SLiviu Dudau 943ad49f860SLiviu Dudau return IRQ_HANDLED; 944ad49f860SLiviu Dudau } 945ad49f860SLiviu Dudau 946ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) 947ad49f860SLiviu Dudau { 948ad49f860SLiviu Dudau return IRQ_HANDLED; 949ad49f860SLiviu Dudau } 950ad49f860SLiviu Dudau 951ad49f860SLiviu Dudau int malidp_se_irq_init(struct drm_device *drm, int irq) 952ad49f860SLiviu Dudau { 953ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 954ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 955ad49f860SLiviu Dudau int ret; 956ad49f860SLiviu Dudau 957ad49f860SLiviu Dudau /* ensure interrupts are disabled */ 958ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 959ad49f860SLiviu Dudau malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 960ad49f860SLiviu Dudau 961ad49f860SLiviu Dudau ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq, 962ad49f860SLiviu Dudau malidp_se_irq_thread_handler, 963ad49f860SLiviu Dudau IRQF_SHARED, "malidp-se", drm); 964ad49f860SLiviu Dudau if (ret < 0) { 965ad49f860SLiviu Dudau DRM_ERROR("failed to install SE IRQ handler\n"); 966ad49f860SLiviu Dudau return ret; 967ad49f860SLiviu Dudau } 968ad49f860SLiviu Dudau 969ad49f860SLiviu Dudau malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, 970a6993b21SLiviu Dudau hwdev->hw->map.se_irq_map.irq_mask); 971ad49f860SLiviu Dudau 972ad49f860SLiviu Dudau return 0; 973ad49f860SLiviu Dudau } 974ad49f860SLiviu Dudau 975ad49f860SLiviu Dudau void malidp_se_irq_fini(struct drm_device *drm) 976ad49f860SLiviu Dudau { 977ad49f860SLiviu Dudau struct malidp_drm *malidp = drm->dev_private; 978ad49f860SLiviu Dudau struct malidp_hw_device *hwdev = malidp->dev; 979ad49f860SLiviu Dudau 980ad49f860SLiviu Dudau malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 981a6993b21SLiviu Dudau hwdev->hw->map.se_irq_map.irq_mask); 982ad49f860SLiviu Dudau } 983