diff options
Diffstat (limited to 'drivers/gpu/drm')
| -rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 431 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 12 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 24 |
3 files changed, 372 insertions, 95 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index d35ff8be7ae8..52bf63fbf384 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
| @@ -18,26 +18,143 @@ | |||
| 18 | #include "drm.h" | 18 | #include "drm.h" |
| 19 | #include "dc.h" | 19 | #include "dc.h" |
| 20 | 20 | ||
| 21 | struct tegra_dc_window { | 21 | struct tegra_plane { |
| 22 | fixed20_12 x; | 22 | struct drm_plane base; |
| 23 | fixed20_12 y; | 23 | unsigned int index; |
| 24 | fixed20_12 w; | ||
| 25 | fixed20_12 h; | ||
| 26 | unsigned int outx; | ||
| 27 | unsigned int outy; | ||
| 28 | unsigned int outw; | ||
| 29 | unsigned int outh; | ||
| 30 | unsigned int stride; | ||
| 31 | unsigned int fmt; | ||
| 32 | }; | 24 | }; |
| 33 | 25 | ||
| 26 | static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane) | ||
| 27 | { | ||
| 28 | return container_of(plane, struct tegra_plane, base); | ||
| 29 | } | ||
| 30 | |||
| 31 | static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | ||
| 32 | struct drm_framebuffer *fb, int crtc_x, | ||
| 33 | int crtc_y, unsigned int crtc_w, | ||
| 34 | unsigned int crtc_h, uint32_t src_x, | ||
| 35 | uint32_t src_y, uint32_t src_w, uint32_t src_h) | ||
| 36 | { | ||
| 37 | struct tegra_plane *p = to_tegra_plane(plane); | ||
| 38 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 39 | struct tegra_dc_window window; | ||
| 40 | unsigned int i; | ||
| 41 | |||
| 42 | memset(&window, 0, sizeof(window)); | ||
| 43 | window.src.x = src_x >> 16; | ||
| 44 | window.src.y = src_y >> 16; | ||
| 45 | window.src.w = src_w >> 16; | ||
| 46 | window.src.h = src_h >> 16; | ||
| 47 | window.dst.x = crtc_x; | ||
| 48 | window.dst.y = crtc_y; | ||
| 49 | window.dst.w = crtc_w; | ||
| 50 | window.dst.h = crtc_h; | ||
| 51 | window.format = tegra_dc_format(fb->pixel_format); | ||
| 52 | window.bits_per_pixel = fb->bits_per_pixel; | ||
| 53 | |||
| 54 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { | ||
| 55 | struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i); | ||
| 56 | |||
| 57 | window.base[i] = gem->paddr + fb->offsets[i]; | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Tegra doesn't support different strides for U and V planes | ||
| 61 | * so we display a warning if the user tries to display a | ||
| 62 | * framebuffer with such a configuration. | ||
| 63 | */ | ||
| 64 | if (i >= 2) { | ||
| 65 | if (fb->pitches[i] != window.stride[1]) | ||
| 66 | DRM_ERROR("unsupported UV-plane configuration\n"); | ||
| 67 | } else { | ||
| 68 | window.stride[i] = fb->pitches[i]; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | return tegra_dc_setup_window(dc, p->index, &window); | ||
| 73 | } | ||
| 74 | |||
| 75 | static int tegra_plane_disable(struct drm_plane *plane) | ||
| 76 | { | ||
| 77 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
| 78 | struct tegra_plane *p = to_tegra_plane(plane); | ||
| 79 | unsigned long value; | ||
| 80 | |||
| 81 | value = WINDOW_A_SELECT << p->index; | ||
| 82 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 83 | |||
| 84 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
| 85 | value &= ~WIN_ENABLE; | ||
| 86 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
| 87 | |||
| 88 | tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL); | ||
| 89 | tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
| 95 | { | ||
| 96 | tegra_plane_disable(plane); | ||
| 97 | drm_plane_cleanup(plane); | ||
| 98 | } | ||
| 99 | |||
| 100 | static const struct drm_plane_funcs tegra_plane_funcs = { | ||
| 101 | .update_plane = tegra_plane_update, | ||
| 102 | .disable_plane = tegra_plane_disable, | ||
| 103 | .destroy = tegra_plane_destroy, | ||
| 104 | }; | ||
| 105 | |||
| 106 | static const uint32_t plane_formats[] = { | ||
| 107 | DRM_FORMAT_XRGB8888, | ||
| 108 | DRM_FORMAT_UYVY, | ||
| 109 | DRM_FORMAT_YUV420, | ||
| 110 | DRM_FORMAT_YUV422, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | ||
| 114 | { | ||
| 115 | unsigned int i; | ||
| 116 | int err = 0; | ||
| 117 | |||
| 118 | for (i = 0; i < 2; i++) { | ||
| 119 | struct tegra_plane *plane; | ||
| 120 | |||
| 121 | plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL); | ||
| 122 | if (!plane) | ||
| 123 | return -ENOMEM; | ||
| 124 | |||
| 125 | plane->index = 1 + i; | ||
| 126 | |||
| 127 | err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
| 128 | &tegra_plane_funcs, plane_formats, | ||
| 129 | ARRAY_SIZE(plane_formats), false); | ||
| 130 | if (err < 0) | ||
| 131 | return err; | ||
| 132 | } | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 34 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | 137 | static const struct drm_crtc_funcs tegra_crtc_funcs = { |
| 35 | .set_config = drm_crtc_helper_set_config, | 138 | .set_config = drm_crtc_helper_set_config, |
| 36 | .destroy = drm_crtc_cleanup, | 139 | .destroy = drm_crtc_cleanup, |
| 37 | }; | 140 | }; |
| 38 | 141 | ||
| 39 | static void tegra_crtc_dpms(struct drm_crtc *crtc, int mode) | 142 | static void tegra_crtc_disable(struct drm_crtc *crtc) |
| 40 | { | 143 | { |
| 144 | struct drm_device *drm = crtc->dev; | ||
| 145 | struct drm_plane *plane; | ||
| 146 | |||
| 147 | list_for_each_entry(plane, &drm->mode_config.plane_list, head) { | ||
| 148 | if (plane->crtc == crtc) { | ||
| 149 | tegra_plane_disable(plane); | ||
| 150 | plane->crtc = NULL; | ||
| 151 | |||
| 152 | if (plane->fb) { | ||
| 153 | drm_framebuffer_unreference(plane->fb); | ||
| 154 | plane->fb = NULL; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 41 | } | 158 | } |
| 42 | 159 | ||
| 43 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, | 160 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, |
| @@ -47,10 +164,11 @@ static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, | |||
| 47 | return true; | 164 | return true; |
| 48 | } | 165 | } |
| 49 | 166 | ||
| 50 | static inline u32 compute_dda_inc(fixed20_12 inf, unsigned int out, bool v, | 167 | static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, |
| 51 | unsigned int bpp) | 168 | unsigned int bpp) |
| 52 | { | 169 | { |
| 53 | fixed20_12 outf = dfixed_init(out); | 170 | fixed20_12 outf = dfixed_init(out); |
| 171 | fixed20_12 inf = dfixed_init(in); | ||
| 54 | u32 dda_inc; | 172 | u32 dda_inc; |
| 55 | int max; | 173 | int max; |
| 56 | 174 | ||
| @@ -80,9 +198,10 @@ static inline u32 compute_dda_inc(fixed20_12 inf, unsigned int out, bool v, | |||
| 80 | return dda_inc; | 198 | return dda_inc; |
| 81 | } | 199 | } |
| 82 | 200 | ||
| 83 | static inline u32 compute_initial_dda(fixed20_12 in) | 201 | static inline u32 compute_initial_dda(unsigned int in) |
| 84 | { | 202 | { |
| 85 | return dfixed_frac(in); | 203 | fixed20_12 inf = dfixed_init(in); |
| 204 | return dfixed_frac(inf); | ||
| 86 | } | 205 | } |
| 87 | 206 | ||
| 88 | static int tegra_dc_set_timings(struct tegra_dc *dc, | 207 | static int tegra_dc_set_timings(struct tegra_dc *dc, |
| @@ -153,6 +272,185 @@ static int tegra_crtc_setup_clk(struct drm_crtc *crtc, | |||
| 153 | return 0; | 272 | return 0; |
| 154 | } | 273 | } |
| 155 | 274 | ||
| 275 | static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar) | ||
| 276 | { | ||
| 277 | switch (format) { | ||
| 278 | case WIN_COLOR_DEPTH_YCbCr422: | ||
| 279 | case WIN_COLOR_DEPTH_YUV422: | ||
| 280 | if (planar) | ||
| 281 | *planar = false; | ||
| 282 | |||
| 283 | return true; | ||
| 284 | |||
| 285 | case WIN_COLOR_DEPTH_YCbCr420P: | ||
| 286 | case WIN_COLOR_DEPTH_YUV420P: | ||
| 287 | case WIN_COLOR_DEPTH_YCbCr422P: | ||
| 288 | case WIN_COLOR_DEPTH_YUV422P: | ||
| 289 | case WIN_COLOR_DEPTH_YCbCr422R: | ||
| 290 | case WIN_COLOR_DEPTH_YUV422R: | ||
| 291 | case WIN_COLOR_DEPTH_YCbCr422RA: | ||
| 292 | case WIN_COLOR_DEPTH_YUV422RA: | ||
| 293 | if (planar) | ||
| 294 | *planar = true; | ||
| 295 | |||
| 296 | return true; | ||
| 297 | } | ||
| 298 | |||
| 299 | return false; | ||
| 300 | } | ||
| 301 | |||
| 302 | int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | ||
| 303 | const struct tegra_dc_window *window) | ||
| 304 | { | ||
| 305 | unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; | ||
| 306 | unsigned long value; | ||
| 307 | bool yuv, planar; | ||
| 308 | |||
| 309 | /* | ||
| 310 | * For YUV planar modes, the number of bytes per pixel takes into | ||
| 311 | * account only the luma component and therefore is 1. | ||
| 312 | */ | ||
| 313 | yuv = tegra_dc_format_is_yuv(window->format, &planar); | ||
| 314 | if (!yuv) | ||
| 315 | bpp = window->bits_per_pixel / 8; | ||
| 316 | else | ||
| 317 | bpp = planar ? 1 : 2; | ||
| 318 | |||
| 319 | value = WINDOW_A_SELECT << index; | ||
| 320 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 321 | |||
| 322 | tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH); | ||
| 323 | tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); | ||
| 324 | |||
| 325 | value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); | ||
| 326 | tegra_dc_writel(dc, value, DC_WIN_POSITION); | ||
| 327 | |||
| 328 | value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); | ||
| 329 | tegra_dc_writel(dc, value, DC_WIN_SIZE); | ||
| 330 | |||
| 331 | h_offset = window->src.x * bpp; | ||
| 332 | v_offset = window->src.y; | ||
| 333 | h_size = window->src.w * bpp; | ||
| 334 | v_size = window->src.h; | ||
| 335 | |||
| 336 | value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); | ||
| 337 | tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); | ||
| 338 | |||
| 339 | /* | ||
| 340 | * For DDA computations the number of bytes per pixel for YUV planar | ||
| 341 | * modes needs to take into account all Y, U and V components. | ||
| 342 | */ | ||
| 343 | if (yuv && planar) | ||
| 344 | bpp = 2; | ||
| 345 | |||
| 346 | h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); | ||
| 347 | v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); | ||
| 348 | |||
| 349 | value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); | ||
| 350 | tegra_dc_writel(dc, value, DC_WIN_DDA_INC); | ||
| 351 | |||
| 352 | h_dda = compute_initial_dda(window->src.x); | ||
| 353 | v_dda = compute_initial_dda(window->src.y); | ||
| 354 | |||
| 355 | tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); | ||
| 356 | tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); | ||
| 357 | |||
| 358 | tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); | ||
| 359 | tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); | ||
| 360 | |||
| 361 | tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR); | ||
| 362 | |||
| 363 | if (yuv && planar) { | ||
| 364 | tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U); | ||
| 365 | tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V); | ||
| 366 | value = window->stride[1] << 16 | window->stride[0]; | ||
| 367 | tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE); | ||
| 368 | } else { | ||
| 369 | tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE); | ||
| 370 | } | ||
| 371 | |||
| 372 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); | ||
| 373 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); | ||
| 374 | |||
| 375 | value = WIN_ENABLE; | ||
| 376 | |||
| 377 | if (yuv) { | ||
| 378 | /* setup default colorspace conversion coefficients */ | ||
| 379 | tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); | ||
| 380 | tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); | ||
| 381 | tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); | ||
| 382 | tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); | ||
| 383 | tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); | ||
| 384 | tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); | ||
| 385 | tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); | ||
| 386 | tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); | ||
| 387 | |||
| 388 | value |= CSC_ENABLE; | ||
| 389 | } else if (bpp < 24) { | ||
| 390 | value |= COLOR_EXPAND; | ||
| 391 | } | ||
| 392 | |||
| 393 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
| 394 | |||
| 395 | /* | ||
| 396 | * Disable blending and assume Window A is the bottom-most window, | ||
| 397 | * Window C is the top-most window and Window B is in the middle. | ||
| 398 | */ | ||
| 399 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY); | ||
| 400 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN); | ||
| 401 | |||
| 402 | switch (index) { | ||
| 403 | case 0: | ||
| 404 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X); | ||
| 405 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); | ||
| 406 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); | ||
| 407 | break; | ||
| 408 | |||
| 409 | case 1: | ||
| 410 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); | ||
| 411 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); | ||
| 412 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); | ||
| 413 | break; | ||
| 414 | |||
| 415 | case 2: | ||
| 416 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); | ||
| 417 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y); | ||
| 418 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY); | ||
| 419 | break; | ||
| 420 | } | ||
| 421 | |||
| 422 | tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); | ||
| 423 | tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | unsigned int tegra_dc_format(uint32_t format) | ||
| 429 | { | ||
| 430 | switch (format) { | ||
| 431 | case DRM_FORMAT_XRGB8888: | ||
| 432 | return WIN_COLOR_DEPTH_B8G8R8A8; | ||
| 433 | |||
| 434 | case DRM_FORMAT_RGB565: | ||
| 435 | return WIN_COLOR_DEPTH_B5G6R5; | ||
| 436 | |||
| 437 | case DRM_FORMAT_UYVY: | ||
| 438 | return WIN_COLOR_DEPTH_YCbCr422; | ||
| 439 | |||
| 440 | case DRM_FORMAT_YUV420: | ||
| 441 | return WIN_COLOR_DEPTH_YCbCr420P; | ||
| 442 | |||
| 443 | case DRM_FORMAT_YUV422: | ||
| 444 | return WIN_COLOR_DEPTH_YCbCr422P; | ||
| 445 | |||
| 446 | default: | ||
| 447 | break; | ||
| 448 | } | ||
| 449 | |||
| 450 | WARN(1, "unsupported pixel format %u, using default\n", format); | ||
| 451 | return WIN_COLOR_DEPTH_B8G8R8A8; | ||
| 452 | } | ||
| 453 | |||
| 156 | static int tegra_crtc_mode_set(struct drm_crtc *crtc, | 454 | static int tegra_crtc_mode_set(struct drm_crtc *crtc, |
| 157 | struct drm_display_mode *mode, | 455 | struct drm_display_mode *mode, |
| 158 | struct drm_display_mode *adjusted, | 456 | struct drm_display_mode *adjusted, |
| @@ -160,8 +458,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, | |||
| 160 | { | 458 | { |
| 161 | struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(crtc->fb, 0); | 459 | struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(crtc->fb, 0); |
| 162 | struct tegra_dc *dc = to_tegra_dc(crtc); | 460 | struct tegra_dc *dc = to_tegra_dc(crtc); |
| 163 | unsigned int h_dda, v_dda, bpp; | 461 | struct tegra_dc_window window; |
| 164 | struct tegra_dc_window win; | ||
| 165 | unsigned long div, value; | 462 | unsigned long div, value; |
| 166 | int err; | 463 | int err; |
| 167 | 464 | ||
| @@ -192,81 +489,23 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, | |||
| 192 | tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); | 489 | tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); |
| 193 | 490 | ||
| 194 | /* setup window parameters */ | 491 | /* setup window parameters */ |
| 195 | memset(&win, 0, sizeof(win)); | 492 | memset(&window, 0, sizeof(window)); |
| 196 | win.x.full = dfixed_const(0); | 493 | window.src.x = 0; |
| 197 | win.y.full = dfixed_const(0); | 494 | window.src.y = 0; |
| 198 | win.w.full = dfixed_const(mode->hdisplay); | 495 | window.src.w = mode->hdisplay; |
| 199 | win.h.full = dfixed_const(mode->vdisplay); | 496 | window.src.h = mode->vdisplay; |
| 200 | win.outx = 0; | 497 | window.dst.x = 0; |
| 201 | win.outy = 0; | 498 | window.dst.y = 0; |
| 202 | win.outw = mode->hdisplay; | 499 | window.dst.w = mode->hdisplay; |
| 203 | win.outh = mode->vdisplay; | 500 | window.dst.h = mode->vdisplay; |
| 204 | 501 | window.format = tegra_dc_format(crtc->fb->pixel_format); | |
| 205 | switch (crtc->fb->pixel_format) { | 502 | window.bits_per_pixel = crtc->fb->bits_per_pixel; |
| 206 | case DRM_FORMAT_XRGB8888: | 503 | window.stride[0] = crtc->fb->pitches[0]; |
| 207 | win.fmt = WIN_COLOR_DEPTH_B8G8R8A8; | 504 | window.base[0] = gem->paddr; |
| 208 | break; | 505 | |
| 209 | 506 | err = tegra_dc_setup_window(dc, 0, &window); | |
| 210 | case DRM_FORMAT_RGB565: | 507 | if (err < 0) |
| 211 | win.fmt = WIN_COLOR_DEPTH_B5G6R5; | 508 | dev_err(dc->dev, "failed to enable root plane\n"); |
| 212 | break; | ||
| 213 | |||
| 214 | default: | ||
| 215 | win.fmt = WIN_COLOR_DEPTH_B8G8R8A8; | ||
| 216 | WARN_ON(1); | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | |||
| 220 | bpp = crtc->fb->bits_per_pixel / 8; | ||
| 221 | win.stride = crtc->fb->pitches[0]; | ||
| 222 | |||
| 223 | /* program window registers */ | ||
| 224 | value = WINDOW_A_SELECT; | ||
| 225 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 226 | |||
| 227 | tegra_dc_writel(dc, win.fmt, DC_WIN_COLOR_DEPTH); | ||
| 228 | tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); | ||
| 229 | |||
| 230 | value = V_POSITION(win.outy) | H_POSITION(win.outx); | ||
| 231 | tegra_dc_writel(dc, value, DC_WIN_POSITION); | ||
| 232 | |||
| 233 | value = V_SIZE(win.outh) | H_SIZE(win.outw); | ||
| 234 | tegra_dc_writel(dc, value, DC_WIN_SIZE); | ||
| 235 | |||
| 236 | value = V_PRESCALED_SIZE(dfixed_trunc(win.h)) | | ||
| 237 | H_PRESCALED_SIZE(dfixed_trunc(win.w) * bpp); | ||
| 238 | tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); | ||
| 239 | |||
| 240 | h_dda = compute_dda_inc(win.w, win.outw, false, bpp); | ||
| 241 | v_dda = compute_dda_inc(win.h, win.outh, true, bpp); | ||
| 242 | |||
| 243 | value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); | ||
| 244 | tegra_dc_writel(dc, value, DC_WIN_DDA_INC); | ||
| 245 | |||
| 246 | h_dda = compute_initial_dda(win.x); | ||
| 247 | v_dda = compute_initial_dda(win.y); | ||
| 248 | |||
| 249 | tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); | ||
| 250 | tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); | ||
| 251 | |||
| 252 | tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); | ||
| 253 | tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); | ||
| 254 | |||
| 255 | tegra_dc_writel(dc, fb->obj->paddr, DC_WINBUF_START_ADDR); | ||
| 256 | tegra_dc_writel(dc, win.stride, DC_WIN_LINE_STRIDE); | ||
| 257 | tegra_dc_writel(dc, dfixed_trunc(win.x) * bpp, | ||
| 258 | DC_WINBUF_ADDR_H_OFFSET); | ||
| 259 | tegra_dc_writel(dc, dfixed_trunc(win.y), DC_WINBUF_ADDR_V_OFFSET); | ||
| 260 | |||
| 261 | value = WIN_ENABLE; | ||
| 262 | |||
| 263 | if (bpp < 24) | ||
| 264 | value |= COLOR_EXPAND; | ||
| 265 | |||
| 266 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
| 267 | |||
| 268 | tegra_dc_writel(dc, 0xff00, DC_WIN_BLEND_NOKEY); | ||
| 269 | tegra_dc_writel(dc, 0xff00, DC_WIN_BLEND_1WIN); | ||
| 270 | 509 | ||
| 271 | return 0; | 510 | return 0; |
| 272 | } | 511 | } |
| @@ -347,7 +586,7 @@ static void tegra_crtc_load_lut(struct drm_crtc *crtc) | |||
| 347 | } | 586 | } |
| 348 | 587 | ||
| 349 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | 588 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { |
| 350 | .dpms = tegra_crtc_dpms, | 589 | .disable = tegra_crtc_disable, |
| 351 | .mode_fixup = tegra_crtc_mode_fixup, | 590 | .mode_fixup = tegra_crtc_mode_fixup, |
| 352 | .mode_set = tegra_crtc_mode_set, | 591 | .mode_set = tegra_crtc_mode_set, |
| 353 | .prepare = tegra_crtc_prepare, | 592 | .prepare = tegra_crtc_prepare, |
| @@ -588,7 +827,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data) | |||
| 588 | DUMP_REG(DC_WIN_BLEND_1WIN); | 827 | DUMP_REG(DC_WIN_BLEND_1WIN); |
| 589 | DUMP_REG(DC_WIN_BLEND_2WIN_X); | 828 | DUMP_REG(DC_WIN_BLEND_2WIN_X); |
| 590 | DUMP_REG(DC_WIN_BLEND_2WIN_Y); | 829 | DUMP_REG(DC_WIN_BLEND_2WIN_Y); |
| 591 | DUMP_REG(DC_WIN_BLEND32WIN_XY); | 830 | DUMP_REG(DC_WIN_BLEND_3WIN_XY); |
| 592 | DUMP_REG(DC_WIN_HP_FETCH_CONTROL); | 831 | DUMP_REG(DC_WIN_HP_FETCH_CONTROL); |
| 593 | DUMP_REG(DC_WINBUF_START_ADDR); | 832 | DUMP_REG(DC_WINBUF_START_ADDR); |
| 594 | DUMP_REG(DC_WINBUF_START_ADDR_NS); | 833 | DUMP_REG(DC_WINBUF_START_ADDR_NS); |
| @@ -690,6 +929,10 @@ static int tegra_dc_drm_init(struct host1x_client *client, | |||
| 690 | return err; | 929 | return err; |
| 691 | } | 930 | } |
| 692 | 931 | ||
| 932 | err = tegra_dc_add_planes(drm, dc); | ||
| 933 | if (err < 0) | ||
| 934 | return err; | ||
| 935 | |||
| 693 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 936 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
| 694 | err = tegra_dc_debugfs_init(dc, drm->primary); | 937 | err = tegra_dc_debugfs_init(dc, drm->primary); |
| 695 | if (err < 0) | 938 | if (err < 0) |
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 99977b5d5c36..e2fa328861ca 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h | |||
| @@ -290,8 +290,18 @@ | |||
| 290 | #define DC_DISP_SD_HW_K_VALUES 0x4dd | 290 | #define DC_DISP_SD_HW_K_VALUES 0x4dd |
| 291 | #define DC_DISP_SD_MAN_K_VALUES 0x4de | 291 | #define DC_DISP_SD_MAN_K_VALUES 0x4de |
| 292 | 292 | ||
| 293 | #define DC_WIN_CSC_YOF 0x611 | ||
| 294 | #define DC_WIN_CSC_KYRGB 0x612 | ||
| 295 | #define DC_WIN_CSC_KUR 0x613 | ||
| 296 | #define DC_WIN_CSC_KVR 0x614 | ||
| 297 | #define DC_WIN_CSC_KUG 0x615 | ||
| 298 | #define DC_WIN_CSC_KVG 0x616 | ||
| 299 | #define DC_WIN_CSC_KUB 0x617 | ||
| 300 | #define DC_WIN_CSC_KVB 0x618 | ||
| 301 | |||
| 293 | #define DC_WIN_WIN_OPTIONS 0x700 | 302 | #define DC_WIN_WIN_OPTIONS 0x700 |
| 294 | #define COLOR_EXPAND (1 << 6) | 303 | #define COLOR_EXPAND (1 << 6) |
| 304 | #define CSC_ENABLE (1 << 18) | ||
| 295 | #define WIN_ENABLE (1 << 30) | 305 | #define WIN_ENABLE (1 << 30) |
| 296 | 306 | ||
| 297 | #define DC_WIN_BYTE_SWAP 0x701 | 307 | #define DC_WIN_BYTE_SWAP 0x701 |
| @@ -359,7 +369,7 @@ | |||
| 359 | #define DC_WIN_BLEND_1WIN 0x710 | 369 | #define DC_WIN_BLEND_1WIN 0x710 |
| 360 | #define DC_WIN_BLEND_2WIN_X 0x711 | 370 | #define DC_WIN_BLEND_2WIN_X 0x711 |
| 361 | #define DC_WIN_BLEND_2WIN_Y 0x712 | 371 | #define DC_WIN_BLEND_2WIN_Y 0x712 |
| 362 | #define DC_WIN_BLEND32WIN_XY 0x713 | 372 | #define DC_WIN_BLEND_3WIN_XY 0x713 |
| 363 | 373 | ||
| 364 | #define DC_WIN_HP_FETCH_CONTROL 0x714 | 374 | #define DC_WIN_HP_FETCH_CONTROL 0x714 |
| 365 | 375 | ||
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 3c61aab5fcb7..896ff43d32b1 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
| @@ -107,6 +107,30 @@ static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, | |||
| 107 | return readl(dc->regs + (reg << 2)); | 107 | return readl(dc->regs + (reg << 2)); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | struct tegra_dc_window { | ||
| 111 | struct { | ||
| 112 | unsigned int x; | ||
| 113 | unsigned int y; | ||
| 114 | unsigned int w; | ||
| 115 | unsigned int h; | ||
| 116 | } src; | ||
| 117 | struct { | ||
| 118 | unsigned int x; | ||
| 119 | unsigned int y; | ||
| 120 | unsigned int w; | ||
| 121 | unsigned int h; | ||
| 122 | } dst; | ||
| 123 | unsigned int bits_per_pixel; | ||
| 124 | unsigned int format; | ||
| 125 | unsigned int stride[2]; | ||
| 126 | unsigned long base[3]; | ||
| 127 | }; | ||
| 128 | |||
| 129 | /* from dc.c */ | ||
| 130 | extern unsigned int tegra_dc_format(uint32_t format); | ||
| 131 | extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | ||
| 132 | const struct tegra_dc_window *window); | ||
| 133 | |||
| 110 | struct tegra_output_ops { | 134 | struct tegra_output_ops { |
| 111 | int (*enable)(struct tegra_output *output); | 135 | int (*enable)(struct tegra_output *output); |
| 112 | int (*disable)(struct tegra_output *output); | 136 | int (*disable)(struct tegra_output *output); |
