diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_mixer.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 401 |
1 files changed, 199 insertions, 202 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e15438c01129..68ef01028375 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -37,9 +37,6 @@ | |||
37 | #include "exynos_drm_drv.h" | 37 | #include "exynos_drm_drv.h" |
38 | #include "exynos_drm_hdmi.h" | 38 | #include "exynos_drm_hdmi.h" |
39 | 39 | ||
40 | #define MIXER_WIN_NR 3 | ||
41 | #define MIXER_DEFAULT_WIN 0 | ||
42 | |||
43 | #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) | 40 | #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) |
44 | 41 | ||
45 | struct hdmi_win_data { | 42 | struct hdmi_win_data { |
@@ -57,13 +54,14 @@ struct hdmi_win_data { | |||
57 | unsigned int fb_y; | 54 | unsigned int fb_y; |
58 | unsigned int fb_width; | 55 | unsigned int fb_width; |
59 | unsigned int fb_height; | 56 | unsigned int fb_height; |
57 | unsigned int src_width; | ||
58 | unsigned int src_height; | ||
60 | unsigned int mode_width; | 59 | unsigned int mode_width; |
61 | unsigned int mode_height; | 60 | unsigned int mode_height; |
62 | unsigned int scan_flags; | 61 | unsigned int scan_flags; |
63 | }; | 62 | }; |
64 | 63 | ||
65 | struct mixer_resources { | 64 | struct mixer_resources { |
66 | struct device *dev; | ||
67 | int irq; | 65 | int irq; |
68 | void __iomem *mixer_regs; | 66 | void __iomem *mixer_regs; |
69 | void __iomem *vp_regs; | 67 | void __iomem *vp_regs; |
@@ -76,10 +74,13 @@ struct mixer_resources { | |||
76 | }; | 74 | }; |
77 | 75 | ||
78 | struct mixer_context { | 76 | struct mixer_context { |
79 | unsigned int irq; | 77 | struct device *dev; |
80 | int pipe; | 78 | int pipe; |
81 | bool interlace; | 79 | bool interlace; |
80 | bool powered; | ||
81 | u32 int_en; | ||
82 | 82 | ||
83 | struct mutex mixer_mutex; | ||
83 | struct mixer_resources mixer_res; | 84 | struct mixer_resources mixer_res; |
84 | struct hdmi_win_data win_data[MIXER_WIN_NR]; | 85 | struct hdmi_win_data win_data[MIXER_WIN_NR]; |
85 | }; | 86 | }; |
@@ -352,10 +353,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
352 | struct mixer_resources *res = &ctx->mixer_res; | 353 | struct mixer_resources *res = &ctx->mixer_res; |
353 | unsigned long flags; | 354 | unsigned long flags; |
354 | struct hdmi_win_data *win_data; | 355 | struct hdmi_win_data *win_data; |
355 | unsigned int full_width, full_height, width, height; | ||
356 | unsigned int x_ratio, y_ratio; | 356 | unsigned int x_ratio, y_ratio; |
357 | unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; | ||
358 | unsigned int mode_width, mode_height; | ||
359 | unsigned int buf_num; | 357 | unsigned int buf_num; |
360 | dma_addr_t luma_addr[2], chroma_addr[2]; | 358 | dma_addr_t luma_addr[2], chroma_addr[2]; |
361 | bool tiled_mode = false; | 359 | bool tiled_mode = false; |
@@ -382,21 +380,9 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
382 | return; | 380 | return; |
383 | } | 381 | } |
384 | 382 | ||
385 | full_width = win_data->fb_width; | ||
386 | full_height = win_data->fb_height; | ||
387 | width = win_data->crtc_width; | ||
388 | height = win_data->crtc_height; | ||
389 | mode_width = win_data->mode_width; | ||
390 | mode_height = win_data->mode_height; | ||
391 | |||
392 | /* scaling feature: (src << 16) / dst */ | 383 | /* scaling feature: (src << 16) / dst */ |
393 | x_ratio = (width << 16) / width; | 384 | x_ratio = (win_data->src_width << 16) / win_data->crtc_width; |
394 | y_ratio = (height << 16) / height; | 385 | y_ratio = (win_data->src_height << 16) / win_data->crtc_height; |
395 | |||
396 | src_x_offset = win_data->fb_x; | ||
397 | src_y_offset = win_data->fb_y; | ||
398 | dst_x_offset = win_data->crtc_x; | ||
399 | dst_y_offset = win_data->crtc_y; | ||
400 | 386 | ||
401 | if (buf_num == 2) { | 387 | if (buf_num == 2) { |
402 | luma_addr[0] = win_data->dma_addr; | 388 | luma_addr[0] = win_data->dma_addr; |
@@ -404,7 +390,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
404 | } else { | 390 | } else { |
405 | luma_addr[0] = win_data->dma_addr; | 391 | luma_addr[0] = win_data->dma_addr; |
406 | chroma_addr[0] = win_data->dma_addr | 392 | chroma_addr[0] = win_data->dma_addr |
407 | + (full_width * full_height); | 393 | + (win_data->fb_width * win_data->fb_height); |
408 | } | 394 | } |
409 | 395 | ||
410 | if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) { | 396 | if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) { |
@@ -413,8 +399,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
413 | luma_addr[1] = luma_addr[0] + 0x40; | 399 | luma_addr[1] = luma_addr[0] + 0x40; |
414 | chroma_addr[1] = chroma_addr[0] + 0x40; | 400 | chroma_addr[1] = chroma_addr[0] + 0x40; |
415 | } else { | 401 | } else { |
416 | luma_addr[1] = luma_addr[0] + full_width; | 402 | luma_addr[1] = luma_addr[0] + win_data->fb_width; |
417 | chroma_addr[1] = chroma_addr[0] + full_width; | 403 | chroma_addr[1] = chroma_addr[0] + win_data->fb_width; |
418 | } | 404 | } |
419 | } else { | 405 | } else { |
420 | ctx->interlace = false; | 406 | ctx->interlace = false; |
@@ -435,26 +421,26 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
435 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); | 421 | vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); |
436 | 422 | ||
437 | /* setting size of input image */ | 423 | /* setting size of input image */ |
438 | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) | | 424 | vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) | |
439 | VP_IMG_VSIZE(full_height)); | 425 | VP_IMG_VSIZE(win_data->fb_height)); |
440 | /* chroma height has to reduced by 2 to avoid chroma distorions */ | 426 | /* chroma height has to reduced by 2 to avoid chroma distorions */ |
441 | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) | | 427 | vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) | |
442 | VP_IMG_VSIZE(full_height / 2)); | 428 | VP_IMG_VSIZE(win_data->fb_height / 2)); |
443 | 429 | ||
444 | vp_reg_write(res, VP_SRC_WIDTH, width); | 430 | vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width); |
445 | vp_reg_write(res, VP_SRC_HEIGHT, height); | 431 | vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height); |
446 | vp_reg_write(res, VP_SRC_H_POSITION, | 432 | vp_reg_write(res, VP_SRC_H_POSITION, |
447 | VP_SRC_H_POSITION_VAL(src_x_offset)); | 433 | VP_SRC_H_POSITION_VAL(win_data->fb_x)); |
448 | vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset); | 434 | vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y); |
449 | 435 | ||
450 | vp_reg_write(res, VP_DST_WIDTH, width); | 436 | vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width); |
451 | vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset); | 437 | vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x); |
452 | if (ctx->interlace) { | 438 | if (ctx->interlace) { |
453 | vp_reg_write(res, VP_DST_HEIGHT, height / 2); | 439 | vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2); |
454 | vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2); | 440 | vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2); |
455 | } else { | 441 | } else { |
456 | vp_reg_write(res, VP_DST_HEIGHT, height); | 442 | vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height); |
457 | vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset); | 443 | vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y); |
458 | } | 444 | } |
459 | 445 | ||
460 | vp_reg_write(res, VP_H_RATIO, x_ratio); | 446 | vp_reg_write(res, VP_H_RATIO, x_ratio); |
@@ -468,8 +454,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) | |||
468 | vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); | 454 | vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); |
469 | vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); | 455 | vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); |
470 | 456 | ||
471 | mixer_cfg_scan(ctx, mode_height); | 457 | mixer_cfg_scan(ctx, win_data->mode_height); |
472 | mixer_cfg_rgb_fmt(ctx, mode_height); | 458 | mixer_cfg_rgb_fmt(ctx, win_data->mode_height); |
473 | mixer_cfg_layer(ctx, win, true); | 459 | mixer_cfg_layer(ctx, win, true); |
474 | mixer_run(ctx); | 460 | mixer_run(ctx); |
475 | 461 | ||
@@ -484,10 +470,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) | |||
484 | struct mixer_resources *res = &ctx->mixer_res; | 470 | struct mixer_resources *res = &ctx->mixer_res; |
485 | unsigned long flags; | 471 | unsigned long flags; |
486 | struct hdmi_win_data *win_data; | 472 | struct hdmi_win_data *win_data; |
487 | unsigned int full_width, width, height; | ||
488 | unsigned int x_ratio, y_ratio; | 473 | unsigned int x_ratio, y_ratio; |
489 | unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; | 474 | unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; |
490 | unsigned int mode_width, mode_height; | ||
491 | dma_addr_t dma_addr; | 475 | dma_addr_t dma_addr; |
492 | unsigned int fmt; | 476 | unsigned int fmt; |
493 | u32 val; | 477 | u32 val; |
@@ -510,26 +494,17 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) | |||
510 | fmt = ARGB8888; | 494 | fmt = ARGB8888; |
511 | } | 495 | } |
512 | 496 | ||
513 | dma_addr = win_data->dma_addr; | ||
514 | full_width = win_data->fb_width; | ||
515 | width = win_data->crtc_width; | ||
516 | height = win_data->crtc_height; | ||
517 | mode_width = win_data->mode_width; | ||
518 | mode_height = win_data->mode_height; | ||
519 | |||
520 | /* 2x scaling feature */ | 497 | /* 2x scaling feature */ |
521 | x_ratio = 0; | 498 | x_ratio = 0; |
522 | y_ratio = 0; | 499 | y_ratio = 0; |
523 | 500 | ||
524 | src_x_offset = win_data->fb_x; | ||
525 | src_y_offset = win_data->fb_y; | ||
526 | dst_x_offset = win_data->crtc_x; | 501 | dst_x_offset = win_data->crtc_x; |
527 | dst_y_offset = win_data->crtc_y; | 502 | dst_y_offset = win_data->crtc_y; |
528 | 503 | ||
529 | /* converting dma address base and source offset */ | 504 | /* converting dma address base and source offset */ |
530 | dma_addr = dma_addr | 505 | dma_addr = win_data->dma_addr |
531 | + (src_x_offset * win_data->bpp >> 3) | 506 | + (win_data->fb_x * win_data->bpp >> 3) |
532 | + (src_y_offset * full_width * win_data->bpp >> 3); | 507 | + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3); |
533 | src_x_offset = 0; | 508 | src_x_offset = 0; |
534 | src_y_offset = 0; | 509 | src_y_offset = 0; |
535 | 510 | ||
@@ -546,10 +521,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) | |||
546 | MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK); | 521 | MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK); |
547 | 522 | ||
548 | /* setup geometry */ | 523 | /* setup geometry */ |
549 | mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width); | 524 | mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width); |
550 | 525 | ||
551 | val = MXR_GRP_WH_WIDTH(width); | 526 | val = MXR_GRP_WH_WIDTH(win_data->crtc_width); |
552 | val |= MXR_GRP_WH_HEIGHT(height); | 527 | val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height); |
553 | val |= MXR_GRP_WH_H_SCALE(x_ratio); | 528 | val |= MXR_GRP_WH_H_SCALE(x_ratio); |
554 | val |= MXR_GRP_WH_V_SCALE(y_ratio); | 529 | val |= MXR_GRP_WH_V_SCALE(y_ratio); |
555 | mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); | 530 | mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); |
@@ -567,8 +542,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) | |||
567 | /* set buffer address to mixer */ | 542 | /* set buffer address to mixer */ |
568 | mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); | 543 | mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); |
569 | 544 | ||
570 | mixer_cfg_scan(ctx, mode_height); | 545 | mixer_cfg_scan(ctx, win_data->mode_height); |
571 | mixer_cfg_rgb_fmt(ctx, mode_height); | 546 | mixer_cfg_rgb_fmt(ctx, win_data->mode_height); |
572 | mixer_cfg_layer(ctx, win, true); | 547 | mixer_cfg_layer(ctx, win, true); |
573 | mixer_run(ctx); | 548 | mixer_run(ctx); |
574 | 549 | ||
@@ -591,6 +566,116 @@ static void vp_win_reset(struct mixer_context *ctx) | |||
591 | WARN(tries == 0, "failed to reset Video Processor\n"); | 566 | WARN(tries == 0, "failed to reset Video Processor\n"); |
592 | } | 567 | } |
593 | 568 | ||
569 | static void mixer_win_reset(struct mixer_context *ctx) | ||
570 | { | ||
571 | struct mixer_resources *res = &ctx->mixer_res; | ||
572 | unsigned long flags; | ||
573 | u32 val; /* value stored to register */ | ||
574 | |||
575 | spin_lock_irqsave(&res->reg_slock, flags); | ||
576 | mixer_vsync_set_update(ctx, false); | ||
577 | |||
578 | mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK); | ||
579 | |||
580 | /* set output in RGB888 mode */ | ||
581 | mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK); | ||
582 | |||
583 | /* 16 beat burst in DMA */ | ||
584 | mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST, | ||
585 | MXR_STATUS_BURST_MASK); | ||
586 | |||
587 | /* setting default layer priority: layer1 > layer0 > video | ||
588 | * because typical usage scenario would be | ||
589 | * layer1 - OSD | ||
590 | * layer0 - framebuffer | ||
591 | * video - video overlay | ||
592 | */ | ||
593 | val = MXR_LAYER_CFG_GRP1_VAL(3); | ||
594 | val |= MXR_LAYER_CFG_GRP0_VAL(2); | ||
595 | val |= MXR_LAYER_CFG_VP_VAL(1); | ||
596 | mixer_reg_write(res, MXR_LAYER_CFG, val); | ||
597 | |||
598 | /* setting background color */ | ||
599 | mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); | ||
600 | mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); | ||
601 | mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); | ||
602 | |||
603 | /* setting graphical layers */ | ||
604 | |||
605 | val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ | ||
606 | val |= MXR_GRP_CFG_WIN_BLEND_EN; | ||
607 | val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ | ||
608 | |||
609 | /* the same configuration for both layers */ | ||
610 | mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); | ||
611 | |||
612 | val |= MXR_GRP_CFG_BLEND_PRE_MUL; | ||
613 | val |= MXR_GRP_CFG_PIXEL_BLEND_EN; | ||
614 | mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); | ||
615 | |||
616 | /* configuration of Video Processor Registers */ | ||
617 | vp_win_reset(ctx); | ||
618 | vp_default_filter(res); | ||
619 | |||
620 | /* disable all layers */ | ||
621 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); | ||
622 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); | ||
623 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); | ||
624 | |||
625 | mixer_vsync_set_update(ctx, true); | ||
626 | spin_unlock_irqrestore(&res->reg_slock, flags); | ||
627 | } | ||
628 | |||
629 | static void mixer_poweron(struct mixer_context *ctx) | ||
630 | { | ||
631 | struct mixer_resources *res = &ctx->mixer_res; | ||
632 | |||
633 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
634 | |||
635 | mutex_lock(&ctx->mixer_mutex); | ||
636 | if (ctx->powered) { | ||
637 | mutex_unlock(&ctx->mixer_mutex); | ||
638 | return; | ||
639 | } | ||
640 | ctx->powered = true; | ||
641 | mutex_unlock(&ctx->mixer_mutex); | ||
642 | |||
643 | pm_runtime_get_sync(ctx->dev); | ||
644 | |||
645 | clk_enable(res->mixer); | ||
646 | clk_enable(res->vp); | ||
647 | clk_enable(res->sclk_mixer); | ||
648 | |||
649 | mixer_reg_write(res, MXR_INT_EN, ctx->int_en); | ||
650 | mixer_win_reset(ctx); | ||
651 | } | ||
652 | |||
653 | static void mixer_poweroff(struct mixer_context *ctx) | ||
654 | { | ||
655 | struct mixer_resources *res = &ctx->mixer_res; | ||
656 | |||
657 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
658 | |||
659 | mutex_lock(&ctx->mixer_mutex); | ||
660 | if (!ctx->powered) | ||
661 | goto out; | ||
662 | mutex_unlock(&ctx->mixer_mutex); | ||
663 | |||
664 | ctx->int_en = mixer_reg_read(res, MXR_INT_EN); | ||
665 | |||
666 | clk_disable(res->mixer); | ||
667 | clk_disable(res->vp); | ||
668 | clk_disable(res->sclk_mixer); | ||
669 | |||
670 | pm_runtime_put_sync(ctx->dev); | ||
671 | |||
672 | mutex_lock(&ctx->mixer_mutex); | ||
673 | ctx->powered = false; | ||
674 | |||
675 | out: | ||
676 | mutex_unlock(&ctx->mixer_mutex); | ||
677 | } | ||
678 | |||
594 | static int mixer_enable_vblank(void *ctx, int pipe) | 679 | static int mixer_enable_vblank(void *ctx, int pipe) |
595 | { | 680 | { |
596 | struct mixer_context *mixer_ctx = ctx; | 681 | struct mixer_context *mixer_ctx = ctx; |
@@ -618,6 +703,27 @@ static void mixer_disable_vblank(void *ctx) | |||
618 | mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); | 703 | mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); |
619 | } | 704 | } |
620 | 705 | ||
706 | static void mixer_dpms(void *ctx, int mode) | ||
707 | { | ||
708 | struct mixer_context *mixer_ctx = ctx; | ||
709 | |||
710 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
711 | |||
712 | switch (mode) { | ||
713 | case DRM_MODE_DPMS_ON: | ||
714 | mixer_poweron(mixer_ctx); | ||
715 | break; | ||
716 | case DRM_MODE_DPMS_STANDBY: | ||
717 | case DRM_MODE_DPMS_SUSPEND: | ||
718 | case DRM_MODE_DPMS_OFF: | ||
719 | mixer_poweroff(mixer_ctx); | ||
720 | break; | ||
721 | default: | ||
722 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); | ||
723 | break; | ||
724 | } | ||
725 | } | ||
726 | |||
621 | static void mixer_win_mode_set(void *ctx, | 727 | static void mixer_win_mode_set(void *ctx, |
622 | struct exynos_drm_overlay *overlay) | 728 | struct exynos_drm_overlay *overlay) |
623 | { | 729 | { |
@@ -643,7 +749,7 @@ static void mixer_win_mode_set(void *ctx, | |||
643 | win = MIXER_DEFAULT_WIN; | 749 | win = MIXER_DEFAULT_WIN; |
644 | 750 | ||
645 | if (win < 0 || win > MIXER_WIN_NR) { | 751 | if (win < 0 || win > MIXER_WIN_NR) { |
646 | DRM_ERROR("overlay plane[%d] is wrong\n", win); | 752 | DRM_ERROR("mixer window[%d] is wrong\n", win); |
647 | return; | 753 | return; |
648 | } | 754 | } |
649 | 755 | ||
@@ -665,6 +771,8 @@ static void mixer_win_mode_set(void *ctx, | |||
665 | win_data->fb_y = overlay->fb_y; | 771 | win_data->fb_y = overlay->fb_y; |
666 | win_data->fb_width = overlay->fb_width; | 772 | win_data->fb_width = overlay->fb_width; |
667 | win_data->fb_height = overlay->fb_height; | 773 | win_data->fb_height = overlay->fb_height; |
774 | win_data->src_width = overlay->src_width; | ||
775 | win_data->src_height = overlay->src_height; | ||
668 | 776 | ||
669 | win_data->mode_width = overlay->mode_width; | 777 | win_data->mode_width = overlay->mode_width; |
670 | win_data->mode_height = overlay->mode_height; | 778 | win_data->mode_height = overlay->mode_height; |
@@ -672,44 +780,26 @@ static void mixer_win_mode_set(void *ctx, | |||
672 | win_data->scan_flags = overlay->scan_flag; | 780 | win_data->scan_flags = overlay->scan_flag; |
673 | } | 781 | } |
674 | 782 | ||
675 | static void mixer_win_commit(void *ctx, int zpos) | 783 | static void mixer_win_commit(void *ctx, int win) |
676 | { | 784 | { |
677 | struct mixer_context *mixer_ctx = ctx; | 785 | struct mixer_context *mixer_ctx = ctx; |
678 | int win = zpos; | ||
679 | 786 | ||
680 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); | 787 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); |
681 | 788 | ||
682 | if (win == DEFAULT_ZPOS) | ||
683 | win = MIXER_DEFAULT_WIN; | ||
684 | |||
685 | if (win < 0 || win > MIXER_WIN_NR) { | ||
686 | DRM_ERROR("overlay plane[%d] is wrong\n", win); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | if (win > 1) | 789 | if (win > 1) |
691 | vp_video_buffer(mixer_ctx, win); | 790 | vp_video_buffer(mixer_ctx, win); |
692 | else | 791 | else |
693 | mixer_graph_buffer(mixer_ctx, win); | 792 | mixer_graph_buffer(mixer_ctx, win); |
694 | } | 793 | } |
695 | 794 | ||
696 | static void mixer_win_disable(void *ctx, int zpos) | 795 | static void mixer_win_disable(void *ctx, int win) |
697 | { | 796 | { |
698 | struct mixer_context *mixer_ctx = ctx; | 797 | struct mixer_context *mixer_ctx = ctx; |
699 | struct mixer_resources *res = &mixer_ctx->mixer_res; | 798 | struct mixer_resources *res = &mixer_ctx->mixer_res; |
700 | unsigned long flags; | 799 | unsigned long flags; |
701 | int win = zpos; | ||
702 | 800 | ||
703 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); | 801 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); |
704 | 802 | ||
705 | if (win == DEFAULT_ZPOS) | ||
706 | win = MIXER_DEFAULT_WIN; | ||
707 | |||
708 | if (win < 0 || win > MIXER_WIN_NR) { | ||
709 | DRM_ERROR("overlay plane[%d] is wrong\n", win); | ||
710 | return; | ||
711 | } | ||
712 | |||
713 | spin_lock_irqsave(&res->reg_slock, flags); | 803 | spin_lock_irqsave(&res->reg_slock, flags); |
714 | mixer_vsync_set_update(mixer_ctx, false); | 804 | mixer_vsync_set_update(mixer_ctx, false); |
715 | 805 | ||
@@ -723,6 +813,7 @@ static struct exynos_mixer_ops mixer_ops = { | |||
723 | /* manager */ | 813 | /* manager */ |
724 | .enable_vblank = mixer_enable_vblank, | 814 | .enable_vblank = mixer_enable_vblank, |
725 | .disable_vblank = mixer_disable_vblank, | 815 | .disable_vblank = mixer_disable_vblank, |
816 | .dpms = mixer_dpms, | ||
726 | 817 | ||
727 | /* overlay */ | 818 | /* overlay */ |
728 | .win_mode_set = mixer_win_mode_set, | 819 | .win_mode_set = mixer_win_mode_set, |
@@ -773,7 +864,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) | |||
773 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; | 864 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; |
774 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; | 865 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; |
775 | struct mixer_resources *res = &ctx->mixer_res; | 866 | struct mixer_resources *res = &ctx->mixer_res; |
776 | u32 val, val_base; | 867 | u32 val, base, shadow; |
777 | 868 | ||
778 | spin_lock(&res->reg_slock); | 869 | spin_lock(&res->reg_slock); |
779 | 870 | ||
@@ -784,12 +875,14 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) | |||
784 | if (val & MXR_INT_STATUS_VSYNC) { | 875 | if (val & MXR_INT_STATUS_VSYNC) { |
785 | /* interlace scan need to check shadow register */ | 876 | /* interlace scan need to check shadow register */ |
786 | if (ctx->interlace) { | 877 | if (ctx->interlace) { |
787 | val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); | 878 | base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0)); |
788 | if (ctx->win_data[0].dma_addr != val_base) | 879 | shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); |
880 | if (base != shadow) | ||
789 | goto out; | 881 | goto out; |
790 | 882 | ||
791 | val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); | 883 | base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1)); |
792 | if (ctx->win_data[1].dma_addr != val_base) | 884 | shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); |
885 | if (base != shadow) | ||
793 | goto out; | 886 | goto out; |
794 | } | 887 | } |
795 | 888 | ||
@@ -811,117 +904,6 @@ out: | |||
811 | return IRQ_HANDLED; | 904 | return IRQ_HANDLED; |
812 | } | 905 | } |
813 | 906 | ||
814 | static void mixer_win_reset(struct mixer_context *ctx) | ||
815 | { | ||
816 | struct mixer_resources *res = &ctx->mixer_res; | ||
817 | unsigned long flags; | ||
818 | u32 val; /* value stored to register */ | ||
819 | |||
820 | spin_lock_irqsave(&res->reg_slock, flags); | ||
821 | mixer_vsync_set_update(ctx, false); | ||
822 | |||
823 | mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK); | ||
824 | |||
825 | /* set output in RGB888 mode */ | ||
826 | mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK); | ||
827 | |||
828 | /* 16 beat burst in DMA */ | ||
829 | mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST, | ||
830 | MXR_STATUS_BURST_MASK); | ||
831 | |||
832 | /* setting default layer priority: layer1 > layer0 > video | ||
833 | * because typical usage scenario would be | ||
834 | * layer1 - OSD | ||
835 | * layer0 - framebuffer | ||
836 | * video - video overlay | ||
837 | */ | ||
838 | val = MXR_LAYER_CFG_GRP1_VAL(3); | ||
839 | val |= MXR_LAYER_CFG_GRP0_VAL(2); | ||
840 | val |= MXR_LAYER_CFG_VP_VAL(1); | ||
841 | mixer_reg_write(res, MXR_LAYER_CFG, val); | ||
842 | |||
843 | /* setting background color */ | ||
844 | mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); | ||
845 | mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); | ||
846 | mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); | ||
847 | |||
848 | /* setting graphical layers */ | ||
849 | |||
850 | val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ | ||
851 | val |= MXR_GRP_CFG_WIN_BLEND_EN; | ||
852 | val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ | ||
853 | |||
854 | /* the same configuration for both layers */ | ||
855 | mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); | ||
856 | |||
857 | val |= MXR_GRP_CFG_BLEND_PRE_MUL; | ||
858 | val |= MXR_GRP_CFG_PIXEL_BLEND_EN; | ||
859 | mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); | ||
860 | |||
861 | /* configuration of Video Processor Registers */ | ||
862 | vp_win_reset(ctx); | ||
863 | vp_default_filter(res); | ||
864 | |||
865 | /* disable all layers */ | ||
866 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE); | ||
867 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE); | ||
868 | mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); | ||
869 | |||
870 | mixer_vsync_set_update(ctx, true); | ||
871 | spin_unlock_irqrestore(&res->reg_slock, flags); | ||
872 | } | ||
873 | |||
874 | static void mixer_resource_poweron(struct mixer_context *ctx) | ||
875 | { | ||
876 | struct mixer_resources *res = &ctx->mixer_res; | ||
877 | |||
878 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
879 | |||
880 | clk_enable(res->mixer); | ||
881 | clk_enable(res->vp); | ||
882 | clk_enable(res->sclk_mixer); | ||
883 | |||
884 | mixer_win_reset(ctx); | ||
885 | } | ||
886 | |||
887 | static void mixer_resource_poweroff(struct mixer_context *ctx) | ||
888 | { | ||
889 | struct mixer_resources *res = &ctx->mixer_res; | ||
890 | |||
891 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||
892 | |||
893 | clk_disable(res->mixer); | ||
894 | clk_disable(res->vp); | ||
895 | clk_disable(res->sclk_mixer); | ||
896 | } | ||
897 | |||
898 | static int mixer_runtime_resume(struct device *dev) | ||
899 | { | ||
900 | struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev); | ||
901 | |||
902 | DRM_DEBUG_KMS("resume - start\n"); | ||
903 | |||
904 | mixer_resource_poweron(ctx->ctx); | ||
905 | |||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static int mixer_runtime_suspend(struct device *dev) | ||
910 | { | ||
911 | struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev); | ||
912 | |||
913 | DRM_DEBUG_KMS("suspend - start\n"); | ||
914 | |||
915 | mixer_resource_poweroff(ctx->ctx); | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | static const struct dev_pm_ops mixer_pm_ops = { | ||
921 | .runtime_suspend = mixer_runtime_suspend, | ||
922 | .runtime_resume = mixer_runtime_resume, | ||
923 | }; | ||
924 | |||
925 | static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, | 907 | static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, |
926 | struct platform_device *pdev) | 908 | struct platform_device *pdev) |
927 | { | 909 | { |
@@ -931,7 +913,6 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, | |||
931 | struct resource *res; | 913 | struct resource *res; |
932 | int ret; | 914 | int ret; |
933 | 915 | ||
934 | mixer_res->dev = dev; | ||
935 | spin_lock_init(&mixer_res->reg_slock); | 916 | spin_lock_init(&mixer_res->reg_slock); |
936 | 917 | ||
937 | mixer_res->mixer = clk_get(dev, "mixer"); | 918 | mixer_res->mixer = clk_get(dev, "mixer"); |
@@ -1027,7 +1008,6 @@ fail: | |||
1027 | clk_put(mixer_res->vp); | 1008 | clk_put(mixer_res->vp); |
1028 | if (!IS_ERR_OR_NULL(mixer_res->mixer)) | 1009 | if (!IS_ERR_OR_NULL(mixer_res->mixer)) |
1029 | clk_put(mixer_res->mixer); | 1010 | clk_put(mixer_res->mixer); |
1030 | mixer_res->dev = NULL; | ||
1031 | return ret; | 1011 | return ret; |
1032 | } | 1012 | } |
1033 | 1013 | ||
@@ -1035,7 +1015,6 @@ static void mixer_resources_cleanup(struct mixer_context *ctx) | |||
1035 | { | 1015 | { |
1036 | struct mixer_resources *res = &ctx->mixer_res; | 1016 | struct mixer_resources *res = &ctx->mixer_res; |
1037 | 1017 | ||
1038 | disable_irq(res->irq); | ||
1039 | free_irq(res->irq, ctx); | 1018 | free_irq(res->irq, ctx); |
1040 | 1019 | ||
1041 | iounmap(res->vp_regs); | 1020 | iounmap(res->vp_regs); |
@@ -1064,6 +1043,9 @@ static int __devinit mixer_probe(struct platform_device *pdev) | |||
1064 | return -ENOMEM; | 1043 | return -ENOMEM; |
1065 | } | 1044 | } |
1066 | 1045 | ||
1046 | mutex_init(&ctx->mixer_mutex); | ||
1047 | |||
1048 | ctx->dev = &pdev->dev; | ||
1067 | drm_hdmi_ctx->ctx = (void *)ctx; | 1049 | drm_hdmi_ctx->ctx = (void *)ctx; |
1068 | 1050 | ||
1069 | platform_set_drvdata(pdev, drm_hdmi_ctx); | 1051 | platform_set_drvdata(pdev, drm_hdmi_ctx); |
@@ -1076,7 +1058,7 @@ static int __devinit mixer_probe(struct platform_device *pdev) | |||
1076 | /* register specific callback point to common hdmi. */ | 1058 | /* register specific callback point to common hdmi. */ |
1077 | exynos_mixer_ops_register(&mixer_ops); | 1059 | exynos_mixer_ops_register(&mixer_ops); |
1078 | 1060 | ||
1079 | mixer_resource_poweron(ctx); | 1061 | pm_runtime_enable(dev); |
1080 | 1062 | ||
1081 | return 0; | 1063 | return 0; |
1082 | 1064 | ||
@@ -1095,12 +1077,27 @@ static int mixer_remove(struct platform_device *pdev) | |||
1095 | 1077 | ||
1096 | dev_info(dev, "remove successful\n"); | 1078 | dev_info(dev, "remove successful\n"); |
1097 | 1079 | ||
1098 | mixer_resource_poweroff(ctx); | 1080 | pm_runtime_disable(&pdev->dev); |
1081 | |||
1099 | mixer_resources_cleanup(ctx); | 1082 | mixer_resources_cleanup(ctx); |
1100 | 1083 | ||
1101 | return 0; | 1084 | return 0; |
1102 | } | 1085 | } |
1103 | 1086 | ||
1087 | #ifdef CONFIG_PM_SLEEP | ||
1088 | static int mixer_suspend(struct device *dev) | ||
1089 | { | ||
1090 | struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); | ||
1091 | struct mixer_context *ctx = drm_hdmi_ctx->ctx; | ||
1092 | |||
1093 | mixer_poweroff(ctx); | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | #endif | ||
1098 | |||
1099 | static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL); | ||
1100 | |||
1104 | struct platform_driver mixer_driver = { | 1101 | struct platform_driver mixer_driver = { |
1105 | .driver = { | 1102 | .driver = { |
1106 | .name = "s5p-mixer", | 1103 | .name = "s5p-mixer", |