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