Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * Copyright © 2018-2020 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #include <drm/drm_atomic.h> |
| 7 | #include <drm/drm_atomic_helper.h> |
| 8 | #include <drm/drm_crtc.h> |
| 9 | #include <drm/drm_crtc_helper.h> |
| 10 | #include <drm/drm_fb_cma_helper.h> |
| 11 | #include <drm/drm_fb_helper.h> |
| 12 | #include <drm/drm_fourcc.h> |
| 13 | #include <drm/drm_gem_cma_helper.h> |
| 14 | #include <drm/drm_managed.h> |
| 15 | #include <drm/drm_plane_helper.h> |
| 16 | |
| 17 | #include "kmb_drv.h" |
| 18 | #include "kmb_plane.h" |
| 19 | #include "kmb_regs.h" |
| 20 | |
| 21 | const u32 layer_irqs[] = { |
| 22 | LCD_INT_VL0, |
| 23 | LCD_INT_VL1, |
| 24 | LCD_INT_GL0, |
| 25 | LCD_INT_GL1 |
| 26 | }; |
| 27 | |
| 28 | /* Conversion (yuv->rgb) matrix from myriadx */ |
| 29 | static const u32 csc_coef_lcd[] = { |
| 30 | 1024, 0, 1436, |
| 31 | 1024, -352, -731, |
| 32 | 1024, 1814, 0, |
| 33 | -179, 125, -226 |
| 34 | }; |
| 35 | |
Anitha Chrisanthus | 7cb397e | 2020-11-10 13:52:49 -0800 | [diff] [blame] | 36 | /* Graphics layer (layers 2 & 3) formats, only packed formats are supported */ |
| 37 | static const u32 kmb_formats_g[] = { |
| 38 | DRM_FORMAT_RGB332, |
| 39 | DRM_FORMAT_XRGB4444, DRM_FORMAT_XBGR4444, |
| 40 | DRM_FORMAT_ARGB4444, DRM_FORMAT_ABGR4444, |
| 41 | DRM_FORMAT_XRGB1555, DRM_FORMAT_XBGR1555, |
| 42 | DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR1555, |
| 43 | DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, |
| 44 | DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, |
| 45 | DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, |
| 46 | DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, |
| 47 | }; |
| 48 | |
| 49 | /* Video layer ( 0 & 1) formats, packed and planar formats are supported */ |
| 50 | static const u32 kmb_formats_v[] = { |
| 51 | /* packed formats */ |
| 52 | DRM_FORMAT_RGB332, |
| 53 | DRM_FORMAT_XRGB4444, DRM_FORMAT_XBGR4444, |
| 54 | DRM_FORMAT_ARGB4444, DRM_FORMAT_ABGR4444, |
| 55 | DRM_FORMAT_XRGB1555, DRM_FORMAT_XBGR1555, |
| 56 | DRM_FORMAT_ARGB1555, DRM_FORMAT_ABGR1555, |
| 57 | DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, |
| 58 | DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, |
| 59 | DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, |
| 60 | DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, |
| 61 | /*planar formats */ |
| 62 | DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, |
| 63 | DRM_FORMAT_YUV422, DRM_FORMAT_YVU422, |
| 64 | DRM_FORMAT_YUV444, DRM_FORMAT_YVU444, |
| 65 | DRM_FORMAT_NV12, DRM_FORMAT_NV21, |
| 66 | }; |
| 67 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 68 | static unsigned int check_pixel_format(struct drm_plane *plane, u32 format) |
| 69 | { |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 70 | struct kmb_drm_private *kmb; |
| 71 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 72 | int i; |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 73 | int plane_id = kmb_plane->id; |
| 74 | struct disp_cfg init_disp_cfg; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 75 | |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 76 | kmb = to_kmb(plane->dev); |
| 77 | init_disp_cfg = kmb->init_disp_cfg[plane_id]; |
| 78 | /* Due to HW limitations, changing pixel format after initial |
| 79 | * plane configuration is not supported. |
| 80 | */ |
| 81 | if (init_disp_cfg.format && init_disp_cfg.format != format) { |
| 82 | drm_dbg(&kmb->drm, "Cannot change format after initial plane configuration"); |
| 83 | return -EINVAL; |
| 84 | } |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 85 | for (i = 0; i < plane->format_count; i++) { |
| 86 | if (plane->format_types[i] == format) |
| 87 | return 0; |
| 88 | } |
| 89 | return -EINVAL; |
| 90 | } |
| 91 | |
| 92 | static int kmb_plane_atomic_check(struct drm_plane *plane, |
Maxime Ripard | 7c11b99 | 2021-02-19 13:00:24 +0100 | [diff] [blame] | 93 | struct drm_atomic_state *state) |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 94 | { |
Maxime Ripard | 7c11b99 | 2021-02-19 13:00:24 +0100 | [diff] [blame] | 95 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, |
| 96 | plane); |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 97 | struct kmb_drm_private *kmb; |
| 98 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
| 99 | int plane_id = kmb_plane->id; |
| 100 | struct disp_cfg init_disp_cfg; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 101 | struct drm_framebuffer *fb; |
| 102 | int ret; |
| 103 | struct drm_crtc_state *crtc_state; |
| 104 | bool can_position; |
| 105 | |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 106 | kmb = to_kmb(plane->dev); |
| 107 | init_disp_cfg = kmb->init_disp_cfg[plane_id]; |
Maxime Ripard | ba5c164 | 2021-02-19 13:00:22 +0100 | [diff] [blame] | 108 | fb = new_plane_state->fb; |
| 109 | if (!fb || !new_plane_state->crtc) |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 110 | return 0; |
| 111 | |
| 112 | ret = check_pixel_format(plane, fb->format->format); |
| 113 | if (ret) |
| 114 | return ret; |
| 115 | |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 116 | if (new_plane_state->crtc_w > KMB_FB_MAX_WIDTH || |
| 117 | new_plane_state->crtc_h > KMB_FB_MAX_HEIGHT || |
| 118 | new_plane_state->crtc_w < KMB_FB_MIN_WIDTH || |
| 119 | new_plane_state->crtc_h < KMB_FB_MIN_HEIGHT) |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 120 | return -EINVAL; |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 121 | |
| 122 | /* Due to HW limitations, changing plane height or width after |
| 123 | * initial plane configuration is not supported. |
| 124 | */ |
| 125 | if ((init_disp_cfg.width && init_disp_cfg.height) && |
| 126 | (init_disp_cfg.width != fb->width || |
| 127 | init_disp_cfg.height != fb->height)) { |
| 128 | drm_dbg(&kmb->drm, "Cannot change plane height or width after initial configuration"); |
| 129 | return -EINVAL; |
| 130 | } |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 131 | can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); |
| 132 | crtc_state = |
Maxime Ripard | dec9202 | 2021-02-19 13:00:25 +0100 | [diff] [blame] | 133 | drm_atomic_get_existing_crtc_state(state, |
Maxime Ripard | ba5c164 | 2021-02-19 13:00:22 +0100 | [diff] [blame] | 134 | new_plane_state->crtc); |
| 135 | return drm_atomic_helper_check_plane_state(new_plane_state, |
| 136 | crtc_state, |
| 137 | DRM_PLANE_HELPER_NO_SCALING, |
| 138 | DRM_PLANE_HELPER_NO_SCALING, |
| 139 | can_position, true); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | static void kmb_plane_atomic_disable(struct drm_plane *plane, |
Maxime Ripard | 977697e | 2021-02-19 13:00:29 +0100 | [diff] [blame] | 143 | struct drm_atomic_state *state) |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 144 | { |
| 145 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
| 146 | int plane_id = kmb_plane->id; |
| 147 | struct kmb_drm_private *kmb; |
| 148 | |
| 149 | kmb = to_kmb(plane->dev); |
| 150 | |
Arnd Bergmann | 98fdd00 | 2020-11-29 21:09:08 +0100 | [diff] [blame] | 151 | if (WARN_ON(plane_id >= KMB_MAX_PLANES)) |
| 152 | return; |
| 153 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 154 | switch (plane_id) { |
| 155 | case LAYER_0: |
| 156 | kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL1_ENABLE; |
| 157 | break; |
| 158 | case LAYER_1: |
| 159 | kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE; |
| 160 | break; |
| 161 | case LAYER_2: |
| 162 | kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL1_ENABLE; |
| 163 | break; |
| 164 | case LAYER_3: |
| 165 | kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL2_ENABLE; |
| 166 | break; |
| 167 | } |
| 168 | |
| 169 | kmb->plane_status[plane_id].disable = true; |
| 170 | } |
| 171 | |
| 172 | static unsigned int get_pixel_format(u32 format) |
| 173 | { |
| 174 | unsigned int val = 0; |
| 175 | |
| 176 | switch (format) { |
| 177 | /* planar formats */ |
| 178 | case DRM_FORMAT_YUV444: |
| 179 | val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE; |
| 180 | break; |
| 181 | case DRM_FORMAT_YVU444: |
| 182 | val = LCD_LAYER_FORMAT_YCBCR444PLAN | LCD_LAYER_PLANAR_STORAGE |
| 183 | | LCD_LAYER_CRCB_ORDER; |
| 184 | break; |
| 185 | case DRM_FORMAT_YUV422: |
| 186 | val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE; |
| 187 | break; |
| 188 | case DRM_FORMAT_YVU422: |
| 189 | val = LCD_LAYER_FORMAT_YCBCR422PLAN | LCD_LAYER_PLANAR_STORAGE |
| 190 | | LCD_LAYER_CRCB_ORDER; |
| 191 | break; |
| 192 | case DRM_FORMAT_YUV420: |
| 193 | val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE; |
| 194 | break; |
| 195 | case DRM_FORMAT_YVU420: |
| 196 | val = LCD_LAYER_FORMAT_YCBCR420PLAN | LCD_LAYER_PLANAR_STORAGE |
| 197 | | LCD_LAYER_CRCB_ORDER; |
| 198 | break; |
| 199 | case DRM_FORMAT_NV12: |
| 200 | val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE; |
| 201 | break; |
| 202 | case DRM_FORMAT_NV21: |
| 203 | val = LCD_LAYER_FORMAT_NV12 | LCD_LAYER_PLANAR_STORAGE |
| 204 | | LCD_LAYER_CRCB_ORDER; |
| 205 | break; |
| 206 | /* packed formats */ |
| 207 | /* looks hw requires B & G to be swapped when RGB */ |
| 208 | case DRM_FORMAT_RGB332: |
| 209 | val = LCD_LAYER_FORMAT_RGB332 | LCD_LAYER_BGR_ORDER; |
| 210 | break; |
| 211 | case DRM_FORMAT_XBGR4444: |
| 212 | val = LCD_LAYER_FORMAT_RGBX4444; |
| 213 | break; |
| 214 | case DRM_FORMAT_ARGB4444: |
| 215 | val = LCD_LAYER_FORMAT_RGBA4444 | LCD_LAYER_BGR_ORDER; |
| 216 | break; |
| 217 | case DRM_FORMAT_ABGR4444: |
| 218 | val = LCD_LAYER_FORMAT_RGBA4444; |
| 219 | break; |
| 220 | case DRM_FORMAT_XRGB1555: |
| 221 | val = LCD_LAYER_FORMAT_XRGB1555 | LCD_LAYER_BGR_ORDER; |
| 222 | break; |
| 223 | case DRM_FORMAT_XBGR1555: |
| 224 | val = LCD_LAYER_FORMAT_XRGB1555; |
| 225 | break; |
| 226 | case DRM_FORMAT_ARGB1555: |
| 227 | val = LCD_LAYER_FORMAT_RGBA1555 | LCD_LAYER_BGR_ORDER; |
| 228 | break; |
| 229 | case DRM_FORMAT_ABGR1555: |
| 230 | val = LCD_LAYER_FORMAT_RGBA1555; |
| 231 | break; |
| 232 | case DRM_FORMAT_RGB565: |
| 233 | val = LCD_LAYER_FORMAT_RGB565 | LCD_LAYER_BGR_ORDER; |
| 234 | break; |
| 235 | case DRM_FORMAT_BGR565: |
| 236 | val = LCD_LAYER_FORMAT_RGB565; |
| 237 | break; |
| 238 | case DRM_FORMAT_RGB888: |
| 239 | val = LCD_LAYER_FORMAT_RGB888 | LCD_LAYER_BGR_ORDER; |
| 240 | break; |
| 241 | case DRM_FORMAT_BGR888: |
| 242 | val = LCD_LAYER_FORMAT_RGB888; |
| 243 | break; |
| 244 | case DRM_FORMAT_XRGB8888: |
| 245 | val = LCD_LAYER_FORMAT_RGBX8888 | LCD_LAYER_BGR_ORDER; |
| 246 | break; |
| 247 | case DRM_FORMAT_XBGR8888: |
| 248 | val = LCD_LAYER_FORMAT_RGBX8888; |
| 249 | break; |
| 250 | case DRM_FORMAT_ARGB8888: |
| 251 | val = LCD_LAYER_FORMAT_RGBA8888 | LCD_LAYER_BGR_ORDER; |
| 252 | break; |
| 253 | case DRM_FORMAT_ABGR8888: |
| 254 | val = LCD_LAYER_FORMAT_RGBA8888; |
| 255 | break; |
| 256 | } |
| 257 | DRM_INFO_ONCE("%s : %d format=0x%x val=0x%x\n", |
| 258 | __func__, __LINE__, format, val); |
| 259 | return val; |
| 260 | } |
| 261 | |
| 262 | static unsigned int get_bits_per_pixel(const struct drm_format_info *format) |
| 263 | { |
| 264 | u32 bpp = 0; |
| 265 | unsigned int val = 0; |
| 266 | |
| 267 | if (format->num_planes > 1) { |
| 268 | val = LCD_LAYER_8BPP; |
| 269 | return val; |
| 270 | } |
| 271 | |
| 272 | bpp += 8 * format->cpp[0]; |
| 273 | |
| 274 | switch (bpp) { |
| 275 | case 8: |
| 276 | val = LCD_LAYER_8BPP; |
| 277 | break; |
| 278 | case 16: |
| 279 | val = LCD_LAYER_16BPP; |
| 280 | break; |
| 281 | case 24: |
| 282 | val = LCD_LAYER_24BPP; |
| 283 | break; |
| 284 | case 32: |
| 285 | val = LCD_LAYER_32BPP; |
| 286 | break; |
| 287 | } |
| 288 | |
| 289 | DRM_DEBUG("bpp=%d val=0x%x\n", bpp, val); |
| 290 | return val; |
| 291 | } |
| 292 | |
| 293 | static void config_csc(struct kmb_drm_private *kmb, int plane_id) |
| 294 | { |
| 295 | /* YUV to RGB conversion using the fixed matrix csc_coef_lcd */ |
| 296 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF11(plane_id), csc_coef_lcd[0]); |
| 297 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF12(plane_id), csc_coef_lcd[1]); |
| 298 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF13(plane_id), csc_coef_lcd[2]); |
| 299 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF21(plane_id), csc_coef_lcd[3]); |
| 300 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF22(plane_id), csc_coef_lcd[4]); |
| 301 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF23(plane_id), csc_coef_lcd[5]); |
| 302 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF31(plane_id), csc_coef_lcd[6]); |
| 303 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF32(plane_id), csc_coef_lcd[7]); |
| 304 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_COEFF33(plane_id), csc_coef_lcd[8]); |
| 305 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_OFF1(plane_id), csc_coef_lcd[9]); |
| 306 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_OFF2(plane_id), csc_coef_lcd[10]); |
| 307 | kmb_write_lcd(kmb, LCD_LAYERn_CSC_OFF3(plane_id), csc_coef_lcd[11]); |
| 308 | } |
| 309 | |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 310 | static void kmb_plane_set_alpha(struct kmb_drm_private *kmb, |
| 311 | const struct drm_plane_state *state, |
| 312 | unsigned char plane_id, |
| 313 | unsigned int *val) |
| 314 | { |
| 315 | u16 plane_alpha = state->alpha; |
| 316 | u16 pixel_blend_mode = state->pixel_blend_mode; |
| 317 | int has_alpha = state->fb->format->has_alpha; |
| 318 | |
| 319 | if (plane_alpha != DRM_BLEND_ALPHA_OPAQUE) |
| 320 | *val |= LCD_LAYER_ALPHA_STATIC; |
| 321 | |
| 322 | if (has_alpha) { |
| 323 | switch (pixel_blend_mode) { |
| 324 | case DRM_MODE_BLEND_PIXEL_NONE: |
| 325 | break; |
| 326 | case DRM_MODE_BLEND_PREMULTI: |
| 327 | *val |= LCD_LAYER_ALPHA_EMBED | LCD_LAYER_ALPHA_PREMULT; |
| 328 | break; |
| 329 | case DRM_MODE_BLEND_COVERAGE: |
| 330 | *val |= LCD_LAYER_ALPHA_EMBED; |
| 331 | break; |
| 332 | default: |
| 333 | DRM_DEBUG("Missing pixel blend mode case (%s == %ld)\n", |
| 334 | __stringify(pixel_blend_mode), |
| 335 | (long)pixel_blend_mode); |
| 336 | break; |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | if (plane_alpha == DRM_BLEND_ALPHA_OPAQUE && !has_alpha) { |
| 341 | *val &= LCD_LAYER_ALPHA_DISABLED; |
| 342 | return; |
| 343 | } |
| 344 | |
| 345 | kmb_write_lcd(kmb, LCD_LAYERn_ALPHA(plane_id), plane_alpha); |
| 346 | } |
| 347 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 348 | static void kmb_plane_atomic_update(struct drm_plane *plane, |
Maxime Ripard | 977697e | 2021-02-19 13:00:29 +0100 | [diff] [blame] | 349 | struct drm_atomic_state *state) |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 350 | { |
Maxime Ripard | 977697e | 2021-02-19 13:00:29 +0100 | [diff] [blame] | 351 | struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, |
| 352 | plane); |
Maxime Ripard | 37418bf | 2021-02-19 13:00:30 +0100 | [diff] [blame] | 353 | struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, |
| 354 | plane); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 355 | struct drm_framebuffer *fb; |
| 356 | struct kmb_drm_private *kmb; |
| 357 | unsigned int width; |
| 358 | unsigned int height; |
| 359 | unsigned int dma_len; |
| 360 | struct kmb_plane *kmb_plane; |
| 361 | unsigned int dma_cfg; |
| 362 | unsigned int ctrl = 0, val = 0, out_format = 0; |
| 363 | unsigned int src_w, src_h, crtc_x, crtc_y; |
| 364 | unsigned char plane_id; |
| 365 | int num_planes; |
| 366 | static dma_addr_t addr[MAX_SUB_PLANES]; |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 367 | struct disp_cfg *init_disp_cfg; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 368 | |
Maxime Ripard | 977697e | 2021-02-19 13:00:29 +0100 | [diff] [blame] | 369 | if (!plane || !new_plane_state || !old_plane_state) |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 370 | return; |
| 371 | |
Maxime Ripard | e05162c0 | 2021-02-19 13:00:27 +0100 | [diff] [blame] | 372 | fb = new_plane_state->fb; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 373 | if (!fb) |
| 374 | return; |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 375 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 376 | num_planes = fb->format->num_planes; |
| 377 | kmb_plane = to_kmb_plane(plane); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 378 | |
| 379 | kmb = to_kmb(plane->dev); |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 380 | plane_id = kmb_plane->id; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 381 | |
| 382 | spin_lock_irq(&kmb->irq_lock); |
| 383 | if (kmb->kmb_under_flow || kmb->kmb_flush_done) { |
| 384 | spin_unlock_irq(&kmb->irq_lock); |
| 385 | drm_dbg(&kmb->drm, "plane_update:underflow!!!! returning"); |
| 386 | return; |
| 387 | } |
| 388 | spin_unlock_irq(&kmb->irq_lock); |
| 389 | |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 390 | init_disp_cfg = &kmb->init_disp_cfg[plane_id]; |
| 391 | src_w = new_plane_state->src_w >> 16; |
Maxime Ripard | e05162c0 | 2021-02-19 13:00:27 +0100 | [diff] [blame] | 392 | src_h = new_plane_state->src_h >> 16; |
| 393 | crtc_x = new_plane_state->crtc_x; |
| 394 | crtc_y = new_plane_state->crtc_y; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 395 | |
| 396 | drm_dbg(&kmb->drm, |
| 397 | "src_w=%d src_h=%d, fb->format->format=0x%x fb->flags=0x%x\n", |
| 398 | src_w, src_h, fb->format->format, fb->flags); |
| 399 | |
| 400 | width = fb->width; |
| 401 | height = fb->height; |
| 402 | dma_len = (width * height * fb->format->cpp[0]); |
| 403 | drm_dbg(&kmb->drm, "dma_len=%d ", dma_len); |
| 404 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_LEN(plane_id), dma_len); |
| 405 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_LEN_SHADOW(plane_id), dma_len); |
| 406 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_LINE_VSTRIDE(plane_id), |
| 407 | fb->pitches[0]); |
| 408 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_LINE_WIDTH(plane_id), |
| 409 | (width * fb->format->cpp[0])); |
| 410 | |
Maxime Ripard | e05162c0 | 2021-02-19 13:00:27 +0100 | [diff] [blame] | 411 | addr[Y_PLANE] = drm_fb_cma_get_gem_addr(fb, new_plane_state, 0); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 412 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_START_ADDR(plane_id), |
| 413 | addr[Y_PLANE] + fb->offsets[0]); |
| 414 | val = get_pixel_format(fb->format->format); |
| 415 | val |= get_bits_per_pixel(fb->format); |
| 416 | /* Program Cb/Cr for planar formats */ |
| 417 | if (num_planes > 1) { |
| 418 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_CB_LINE_VSTRIDE(plane_id), |
| 419 | width * fb->format->cpp[0]); |
| 420 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_CB_LINE_WIDTH(plane_id), |
| 421 | (width * fb->format->cpp[0])); |
| 422 | |
Maxime Ripard | e05162c0 | 2021-02-19 13:00:27 +0100 | [diff] [blame] | 423 | addr[U_PLANE] = drm_fb_cma_get_gem_addr(fb, new_plane_state, |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 424 | U_PLANE); |
| 425 | /* check if Cb/Cr is swapped*/ |
| 426 | if (num_planes == 3 && (val & LCD_LAYER_CRCB_ORDER)) |
| 427 | kmb_write_lcd(kmb, |
| 428 | LCD_LAYERn_DMA_START_CR_ADR(plane_id), |
| 429 | addr[U_PLANE]); |
| 430 | else |
| 431 | kmb_write_lcd(kmb, |
| 432 | LCD_LAYERn_DMA_START_CB_ADR(plane_id), |
| 433 | addr[U_PLANE]); |
| 434 | |
| 435 | if (num_planes == 3) { |
| 436 | kmb_write_lcd(kmb, |
| 437 | LCD_LAYERn_DMA_CR_LINE_VSTRIDE(plane_id), |
| 438 | ((width) * fb->format->cpp[0])); |
| 439 | |
| 440 | kmb_write_lcd(kmb, |
| 441 | LCD_LAYERn_DMA_CR_LINE_WIDTH(plane_id), |
| 442 | ((width) * fb->format->cpp[0])); |
| 443 | |
| 444 | addr[V_PLANE] = drm_fb_cma_get_gem_addr(fb, |
Maxime Ripard | e05162c0 | 2021-02-19 13:00:27 +0100 | [diff] [blame] | 445 | new_plane_state, |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 446 | V_PLANE); |
| 447 | |
| 448 | /* check if Cb/Cr is swapped*/ |
| 449 | if (val & LCD_LAYER_CRCB_ORDER) |
| 450 | kmb_write_lcd(kmb, |
| 451 | LCD_LAYERn_DMA_START_CB_ADR(plane_id), |
| 452 | addr[V_PLANE]); |
| 453 | else |
| 454 | kmb_write_lcd(kmb, |
| 455 | LCD_LAYERn_DMA_START_CR_ADR(plane_id), |
| 456 | addr[V_PLANE]); |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | kmb_write_lcd(kmb, LCD_LAYERn_WIDTH(plane_id), src_w - 1); |
| 461 | kmb_write_lcd(kmb, LCD_LAYERn_HEIGHT(plane_id), src_h - 1); |
| 462 | kmb_write_lcd(kmb, LCD_LAYERn_COL_START(plane_id), crtc_x); |
| 463 | kmb_write_lcd(kmb, LCD_LAYERn_ROW_START(plane_id), crtc_y); |
| 464 | |
| 465 | val |= LCD_LAYER_FIFO_100; |
| 466 | |
| 467 | if (val & LCD_LAYER_PLANAR_STORAGE) { |
| 468 | val |= LCD_LAYER_CSC_EN; |
| 469 | |
| 470 | /* Enable CSC if input is planar and output is RGB */ |
| 471 | config_csc(kmb, plane_id); |
| 472 | } |
| 473 | |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 474 | kmb_plane_set_alpha(kmb, plane->state, plane_id, &val); |
| 475 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 476 | kmb_write_lcd(kmb, LCD_LAYERn_CFG(plane_id), val); |
| 477 | |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 478 | /* Configure LCD_CONTROL */ |
| 479 | ctrl = kmb_read_lcd(kmb, LCD_CONTROL); |
| 480 | |
| 481 | /* Set layer blending config */ |
| 482 | ctrl &= ~LCD_CTRL_ALPHA_ALL; |
| 483 | ctrl |= LCD_CTRL_ALPHA_BOTTOM_VL1 | |
| 484 | LCD_CTRL_ALPHA_BLEND_VL2; |
| 485 | |
| 486 | ctrl &= ~LCD_CTRL_ALPHA_BLEND_BKGND_DISABLE; |
| 487 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 488 | switch (plane_id) { |
| 489 | case LAYER_0: |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 490 | ctrl |= LCD_CTRL_VL1_ENABLE; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 491 | break; |
| 492 | case LAYER_1: |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 493 | ctrl |= LCD_CTRL_VL2_ENABLE; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 494 | break; |
| 495 | case LAYER_2: |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 496 | ctrl |= LCD_CTRL_GL1_ENABLE; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 497 | break; |
| 498 | case LAYER_3: |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 499 | ctrl |= LCD_CTRL_GL2_ENABLE; |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 500 | break; |
| 501 | } |
| 502 | |
| 503 | ctrl |= LCD_CTRL_PROGRESSIVE | LCD_CTRL_TIM_GEN_ENABLE |
| 504 | | LCD_CTRL_CONTINUOUS | LCD_CTRL_OUTPUT_ENABLED; |
| 505 | |
| 506 | /* LCD is connected to MIPI on kmb |
| 507 | * Therefore this bit is required for DSI Tx |
| 508 | */ |
| 509 | ctrl |= LCD_CTRL_VHSYNC_IDLE_LVL; |
| 510 | |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 511 | kmb_write_lcd(kmb, LCD_CONTROL, ctrl); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 512 | |
Edmund Dea | 0aab5dc | 2020-08-25 14:51:17 -0700 | [diff] [blame] | 513 | /* Enable pipeline AXI read transactions for the DMA |
| 514 | * after setting graphics layers. This must be done |
| 515 | * in a separate write cycle. |
| 516 | */ |
| 517 | kmb_set_bitmask_lcd(kmb, LCD_CONTROL, LCD_CTRL_PIPELINE_DMA); |
| 518 | |
| 519 | /* FIXME no doc on how to set output format, these values are taken |
| 520 | * from the Myriadx tests |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 521 | */ |
| 522 | out_format |= LCD_OUTF_FORMAT_RGB888; |
| 523 | |
| 524 | /* Leave RGB order,conversion mode and clip mode to default */ |
| 525 | /* do not interleave RGB channels for mipi Tx compatibility */ |
| 526 | out_format |= LCD_OUTF_MIPI_RGB_MODE; |
| 527 | kmb_write_lcd(kmb, LCD_OUT_FORMAT_CFG, out_format); |
| 528 | |
| 529 | dma_cfg = LCD_DMA_LAYER_ENABLE | LCD_DMA_LAYER_VSTRIDE_EN | |
| 530 | LCD_DMA_LAYER_CONT_UPDATE | LCD_DMA_LAYER_AXI_BURST_16; |
| 531 | |
| 532 | /* Enable DMA */ |
| 533 | kmb_write_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id), dma_cfg); |
Edmund Dea | 982f8ad | 2021-10-06 16:03:48 -0700 | [diff] [blame] | 534 | |
| 535 | /* Save initial display config */ |
| 536 | if (!init_disp_cfg->width || |
| 537 | !init_disp_cfg->height || |
| 538 | !init_disp_cfg->format) { |
| 539 | init_disp_cfg->width = width; |
| 540 | init_disp_cfg->height = height; |
| 541 | init_disp_cfg->format = fb->format->format; |
| 542 | } |
| 543 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 544 | drm_dbg(&kmb->drm, "dma_cfg=0x%x LCD_DMA_CFG=0x%x\n", dma_cfg, |
| 545 | kmb_read_lcd(kmb, LCD_LAYERn_DMA_CFG(plane_id))); |
| 546 | |
| 547 | kmb_set_bitmask_lcd(kmb, LCD_INT_CLEAR, LCD_INT_EOF | |
| 548 | LCD_INT_DMA_ERR); |
| 549 | kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE, LCD_INT_EOF | |
| 550 | LCD_INT_DMA_ERR); |
| 551 | } |
| 552 | |
| 553 | static const struct drm_plane_helper_funcs kmb_plane_helper_funcs = { |
| 554 | .atomic_check = kmb_plane_atomic_check, |
| 555 | .atomic_update = kmb_plane_atomic_update, |
| 556 | .atomic_disable = kmb_plane_atomic_disable |
| 557 | }; |
| 558 | |
| 559 | void kmb_plane_destroy(struct drm_plane *plane) |
| 560 | { |
| 561 | struct kmb_plane *kmb_plane = to_kmb_plane(plane); |
| 562 | |
| 563 | drm_plane_cleanup(plane); |
| 564 | kfree(kmb_plane); |
| 565 | } |
| 566 | |
| 567 | static const struct drm_plane_funcs kmb_plane_funcs = { |
| 568 | .update_plane = drm_atomic_helper_update_plane, |
| 569 | .disable_plane = drm_atomic_helper_disable_plane, |
| 570 | .destroy = kmb_plane_destroy, |
| 571 | .reset = drm_atomic_helper_plane_reset, |
| 572 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
| 573 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, |
| 574 | }; |
| 575 | |
| 576 | struct kmb_plane *kmb_plane_init(struct drm_device *drm) |
| 577 | { |
| 578 | struct kmb_drm_private *kmb = to_kmb(drm); |
| 579 | struct kmb_plane *plane = NULL; |
| 580 | struct kmb_plane *primary = NULL; |
| 581 | int i = 0; |
| 582 | int ret = 0; |
| 583 | enum drm_plane_type plane_type; |
| 584 | const u32 *plane_formats; |
| 585 | int num_plane_formats; |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 586 | unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | |
| 587 | BIT(DRM_MODE_BLEND_PREMULTI) | |
| 588 | BIT(DRM_MODE_BLEND_COVERAGE); |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 589 | |
| 590 | for (i = 0; i < KMB_MAX_PLANES; i++) { |
| 591 | plane = drmm_kzalloc(drm, sizeof(*plane), GFP_KERNEL); |
| 592 | |
| 593 | if (!plane) { |
| 594 | drm_err(drm, "Failed to allocate plane\n"); |
| 595 | return ERR_PTR(-ENOMEM); |
| 596 | } |
| 597 | |
| 598 | plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY : |
| 599 | DRM_PLANE_TYPE_OVERLAY; |
| 600 | if (i < 2) { |
| 601 | plane_formats = kmb_formats_v; |
| 602 | num_plane_formats = ARRAY_SIZE(kmb_formats_v); |
| 603 | } else { |
| 604 | plane_formats = kmb_formats_g; |
| 605 | num_plane_formats = ARRAY_SIZE(kmb_formats_g); |
| 606 | } |
| 607 | |
| 608 | ret = drm_universal_plane_init(drm, &plane->base_plane, |
| 609 | POSSIBLE_CRTCS, &kmb_plane_funcs, |
| 610 | plane_formats, num_plane_formats, |
| 611 | NULL, plane_type, "plane %d", i); |
| 612 | if (ret < 0) { |
| 613 | drm_err(drm, "drm_universal_plane_init failed (ret=%d)", |
| 614 | ret); |
| 615 | goto cleanup; |
| 616 | } |
| 617 | drm_dbg(drm, "%s : %d i=%d type=%d", |
| 618 | __func__, __LINE__, |
| 619 | i, plane_type); |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 620 | drm_plane_create_alpha_property(&plane->base_plane); |
| 621 | |
| 622 | drm_plane_create_blend_mode_property(&plane->base_plane, |
| 623 | blend_caps); |
| 624 | |
| 625 | drm_plane_create_zpos_immutable_property(&plane->base_plane, i); |
| 626 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 627 | drm_plane_helper_add(&plane->base_plane, |
| 628 | &kmb_plane_helper_funcs); |
Edmund Dea | c026565 | 2020-12-04 14:34:29 -0800 | [diff] [blame] | 629 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 630 | if (plane_type == DRM_PLANE_TYPE_PRIMARY) { |
| 631 | primary = plane; |
| 632 | kmb->plane = plane; |
| 633 | } |
| 634 | drm_dbg(drm, "%s : %d primary=%p\n", __func__, __LINE__, |
| 635 | &primary->base_plane); |
| 636 | plane->id = i; |
| 637 | } |
| 638 | |
Edmund Dea | 0aab5dc | 2020-08-25 14:51:17 -0700 | [diff] [blame] | 639 | /* Disable pipeline AXI read transactions for the DMA |
| 640 | * prior to setting graphics layers |
| 641 | */ |
| 642 | kmb_clr_bitmask_lcd(kmb, LCD_CONTROL, LCD_CTRL_PIPELINE_DMA); |
| 643 | |
Anitha Chrisanthus | 7f7b96a | 2020-11-04 17:15:29 -0800 | [diff] [blame] | 644 | return primary; |
| 645 | cleanup: |
| 646 | drmm_kfree(drm, plane); |
| 647 | return ERR_PTR(ret); |
| 648 | } |