diff options
Diffstat (limited to 'drivers')
61 files changed, 1982 insertions, 511 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index e6709362994a..2337d4bfd85c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | |||
@@ -738,7 +738,6 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) | |||
738 | 738 | ||
739 | drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | 739 | drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; |
740 | drm_kms_helper_poll_disable(drm_dev); | 740 | drm_kms_helper_poll_disable(drm_dev); |
741 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); | ||
742 | 741 | ||
743 | ret = amdgpu_device_suspend(drm_dev, false, false); | 742 | ret = amdgpu_device_suspend(drm_dev, false, false); |
744 | pci_save_state(pdev); | 743 | pci_save_state(pdev); |
@@ -775,7 +774,6 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) | |||
775 | 774 | ||
776 | ret = amdgpu_device_resume(drm_dev, false, false); | 775 | ret = amdgpu_device_resume(drm_dev, false, false); |
777 | drm_kms_helper_poll_enable(drm_dev); | 776 | drm_kms_helper_poll_enable(drm_dev); |
778 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); | ||
779 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; | 777 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; |
780 | return 0; | 778 | return 0; |
781 | } | 779 | } |
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index a693ab3078f0..5c52307146c7 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/iopoll.h> | ||
18 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
19 | #include <linux/of.h> | 20 | #include <linux/of.h> |
20 | #include <linux/of_gpio.h> | 21 | #include <linux/of_gpio.h> |
@@ -35,6 +36,8 @@ | |||
35 | 36 | ||
36 | #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) | 37 | #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) |
37 | 38 | ||
39 | static const bool verify_fast_training; | ||
40 | |||
38 | struct bridge_init { | 41 | struct bridge_init { |
39 | struct i2c_client *client; | 42 | struct i2c_client *client; |
40 | struct device_node *node; | 43 | struct device_node *node; |
@@ -98,18 +101,18 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) | |||
98 | return 0; | 101 | return 0; |
99 | } | 102 | } |
100 | 103 | ||
101 | int analogix_dp_psr_supported(struct analogix_dp_device *dp) | 104 | int analogix_dp_psr_enabled(struct analogix_dp_device *dp) |
102 | { | 105 | { |
103 | 106 | ||
104 | return dp->psr_support; | 107 | return dp->psr_enable; |
105 | } | 108 | } |
106 | EXPORT_SYMBOL_GPL(analogix_dp_psr_supported); | 109 | EXPORT_SYMBOL_GPL(analogix_dp_psr_enabled); |
107 | 110 | ||
108 | int analogix_dp_enable_psr(struct analogix_dp_device *dp) | 111 | int analogix_dp_enable_psr(struct analogix_dp_device *dp) |
109 | { | 112 | { |
110 | struct edp_vsc_psr psr_vsc; | 113 | struct edp_vsc_psr psr_vsc; |
111 | 114 | ||
112 | if (!dp->psr_support) | 115 | if (!dp->psr_enable) |
113 | return 0; | 116 | return 0; |
114 | 117 | ||
115 | /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ | 118 | /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
@@ -122,8 +125,7 @@ int analogix_dp_enable_psr(struct analogix_dp_device *dp) | |||
122 | psr_vsc.DB0 = 0; | 125 | psr_vsc.DB0 = 0; |
123 | psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; | 126 | psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; |
124 | 127 | ||
125 | analogix_dp_send_psr_spd(dp, &psr_vsc); | 128 | return analogix_dp_send_psr_spd(dp, &psr_vsc, true); |
126 | return 0; | ||
127 | } | 129 | } |
128 | EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); | 130 | EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); |
129 | 131 | ||
@@ -132,7 +134,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp) | |||
132 | struct edp_vsc_psr psr_vsc; | 134 | struct edp_vsc_psr psr_vsc; |
133 | int ret; | 135 | int ret; |
134 | 136 | ||
135 | if (!dp->psr_support) | 137 | if (!dp->psr_enable) |
136 | return 0; | 138 | return 0; |
137 | 139 | ||
138 | /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ | 140 | /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
@@ -149,8 +151,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp) | |||
149 | if (ret != 1) | 151 | if (ret != 1) |
150 | dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret); | 152 | dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret); |
151 | 153 | ||
152 | analogix_dp_send_psr_spd(dp, &psr_vsc); | 154 | return analogix_dp_send_psr_spd(dp, &psr_vsc, false); |
153 | return 0; | ||
154 | } | 155 | } |
155 | EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); | 156 | EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); |
156 | 157 | ||
@@ -530,7 +531,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | |||
530 | { | 531 | { |
531 | int lane, lane_count, retval; | 532 | int lane, lane_count, retval; |
532 | u32 reg; | 533 | u32 reg; |
533 | u8 link_align, link_status[2], adjust_request[2]; | 534 | u8 link_align, link_status[2], adjust_request[2], spread; |
534 | 535 | ||
535 | usleep_range(400, 401); | 536 | usleep_range(400, 401); |
536 | 537 | ||
@@ -573,6 +574,20 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) | |||
573 | dev_dbg(dp->dev, "final lane count = %.2x\n", | 574 | dev_dbg(dp->dev, "final lane count = %.2x\n", |
574 | dp->link_train.lane_count); | 575 | dp->link_train.lane_count); |
575 | 576 | ||
577 | retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, | ||
578 | &spread); | ||
579 | if (retval != 1) { | ||
580 | dev_err(dp->dev, "failed to read downspread %d\n", | ||
581 | retval); | ||
582 | dp->fast_train_support = false; | ||
583 | } else { | ||
584 | dp->fast_train_support = | ||
585 | (spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ? | ||
586 | true : false; | ||
587 | } | ||
588 | dev_dbg(dp->dev, "fast link training %s\n", | ||
589 | dp->fast_train_support ? "supported" : "unsupported"); | ||
590 | |||
576 | /* set enhanced mode if available */ | 591 | /* set enhanced mode if available */ |
577 | analogix_dp_set_enhanced_mode(dp); | 592 | analogix_dp_set_enhanced_mode(dp); |
578 | dp->link_train.lt_state = FINISHED; | 593 | dp->link_train.lt_state = FINISHED; |
@@ -629,10 +644,12 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, | |||
629 | *lane_count = DPCD_MAX_LANE_COUNT(data); | 644 | *lane_count = DPCD_MAX_LANE_COUNT(data); |
630 | } | 645 | } |
631 | 646 | ||
632 | static void analogix_dp_init_training(struct analogix_dp_device *dp, | 647 | static int analogix_dp_full_link_train(struct analogix_dp_device *dp, |
633 | enum link_lane_count_type max_lane, | 648 | u32 max_lanes, u32 max_rate) |
634 | int max_rate) | ||
635 | { | 649 | { |
650 | int retval = 0; | ||
651 | bool training_finished = false; | ||
652 | |||
636 | /* | 653 | /* |
637 | * MACRO_RST must be applied after the PLL_LOCK to avoid | 654 | * MACRO_RST must be applied after the PLL_LOCK to avoid |
638 | * the DP inter pair skew issue for at least 10 us | 655 | * the DP inter pair skew issue for at least 10 us |
@@ -658,18 +675,13 @@ static void analogix_dp_init_training(struct analogix_dp_device *dp, | |||
658 | } | 675 | } |
659 | 676 | ||
660 | /* Setup TX lane count & rate */ | 677 | /* Setup TX lane count & rate */ |
661 | if (dp->link_train.lane_count > max_lane) | 678 | if (dp->link_train.lane_count > max_lanes) |
662 | dp->link_train.lane_count = max_lane; | 679 | dp->link_train.lane_count = max_lanes; |
663 | if (dp->link_train.link_rate > max_rate) | 680 | if (dp->link_train.link_rate > max_rate) |
664 | dp->link_train.link_rate = max_rate; | 681 | dp->link_train.link_rate = max_rate; |
665 | 682 | ||
666 | /* All DP analog module power up */ | 683 | /* All DP analog module power up */ |
667 | analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); | 684 | analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); |
668 | } | ||
669 | |||
670 | static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) | ||
671 | { | ||
672 | int retval = 0, training_finished = 0; | ||
673 | 685 | ||
674 | dp->link_train.lt_state = START; | 686 | dp->link_train.lt_state = START; |
675 | 687 | ||
@@ -704,22 +716,88 @@ static int analogix_dp_sw_link_training(struct analogix_dp_device *dp) | |||
704 | return retval; | 716 | return retval; |
705 | } | 717 | } |
706 | 718 | ||
707 | static int analogix_dp_set_link_train(struct analogix_dp_device *dp, | 719 | static int analogix_dp_fast_link_train(struct analogix_dp_device *dp) |
708 | u32 count, u32 bwtype) | ||
709 | { | 720 | { |
710 | int i; | 721 | int i, ret; |
711 | int retval; | 722 | u8 link_align, link_status[2]; |
723 | enum pll_status status; | ||
712 | 724 | ||
713 | for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) { | 725 | analogix_dp_reset_macro(dp); |
714 | analogix_dp_init_training(dp, count, bwtype); | 726 | |
715 | retval = analogix_dp_sw_link_training(dp); | 727 | analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); |
716 | if (retval == 0) | 728 | analogix_dp_set_lane_count(dp, dp->link_train.lane_count); |
717 | break; | ||
718 | 729 | ||
719 | usleep_range(100, 110); | 730 | for (i = 0; i < dp->link_train.lane_count; i++) { |
731 | analogix_dp_set_lane_link_training(dp, | ||
732 | dp->link_train.training_lane[i], i); | ||
720 | } | 733 | } |
721 | 734 | ||
722 | return retval; | 735 | ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status, |
736 | status != PLL_UNLOCKED, 120, | ||
737 | 120 * DP_TIMEOUT_LOOP_COUNT); | ||
738 | if (ret) { | ||
739 | DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret); | ||
740 | return ret; | ||
741 | } | ||
742 | |||
743 | /* source Set training pattern 1 */ | ||
744 | analogix_dp_set_training_pattern(dp, TRAINING_PTN1); | ||
745 | /* From DP spec, pattern must be on-screen for a minimum 500us */ | ||
746 | usleep_range(500, 600); | ||
747 | |||
748 | analogix_dp_set_training_pattern(dp, TRAINING_PTN2); | ||
749 | /* From DP spec, pattern must be on-screen for a minimum 500us */ | ||
750 | usleep_range(500, 600); | ||
751 | |||
752 | /* TODO: enhanced_mode?*/ | ||
753 | analogix_dp_set_training_pattern(dp, DP_NONE); | ||
754 | |||
755 | /* | ||
756 | * Useful for debugging issues with fast link training, disable for more | ||
757 | * speed | ||
758 | */ | ||
759 | if (verify_fast_training) { | ||
760 | ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, | ||
761 | &link_align); | ||
762 | if (ret < 0) { | ||
763 | DRM_DEV_ERROR(dp->dev, "Read align status failed %d\n", | ||
764 | ret); | ||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | ret = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, | ||
769 | 2); | ||
770 | if (ret < 0) { | ||
771 | DRM_DEV_ERROR(dp->dev, "Read link status failed %d\n", | ||
772 | ret); | ||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | if (analogix_dp_clock_recovery_ok(link_status, | ||
777 | dp->link_train.lane_count)) { | ||
778 | DRM_DEV_ERROR(dp->dev, "Clock recovery failed\n"); | ||
779 | analogix_dp_reduce_link_rate(dp); | ||
780 | return -EIO; | ||
781 | } | ||
782 | |||
783 | if (analogix_dp_channel_eq_ok(link_status, link_align, | ||
784 | dp->link_train.lane_count)) { | ||
785 | DRM_DEV_ERROR(dp->dev, "Channel EQ failed\n"); | ||
786 | analogix_dp_reduce_link_rate(dp); | ||
787 | return -EIO; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int analogix_dp_train_link(struct analogix_dp_device *dp) | ||
795 | { | ||
796 | if (dp->fast_train_support) | ||
797 | return analogix_dp_fast_link_train(dp); | ||
798 | |||
799 | return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count, | ||
800 | dp->video_info.max_link_rate); | ||
723 | } | 801 | } |
724 | 802 | ||
725 | static int analogix_dp_config_video(struct analogix_dp_device *dp) | 803 | static int analogix_dp_config_video(struct analogix_dp_device *dp) |
@@ -848,10 +926,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) | |||
848 | DRM_ERROR("failed to disable the panel\n"); | 926 | DRM_ERROR("failed to disable the panel\n"); |
849 | } | 927 | } |
850 | 928 | ||
851 | ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count, | 929 | ret = readx_poll_timeout(analogix_dp_train_link, dp, ret, !ret, 100, |
852 | dp->video_info.max_link_rate); | 930 | DP_TIMEOUT_TRAINING_US * 5); |
853 | if (ret) { | 931 | if (ret) { |
854 | dev_err(dp->dev, "unable to do link train\n"); | 932 | dev_err(dp->dev, "unable to do link train, ret=%d\n", ret); |
855 | return; | 933 | return; |
856 | } | 934 | } |
857 | 935 | ||
@@ -873,8 +951,8 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) | |||
873 | /* Enable video */ | 951 | /* Enable video */ |
874 | analogix_dp_start_video(dp); | 952 | analogix_dp_start_video(dp); |
875 | 953 | ||
876 | dp->psr_support = analogix_dp_detect_sink_psr(dp); | 954 | dp->psr_enable = analogix_dp_detect_sink_psr(dp); |
877 | if (dp->psr_support) | 955 | if (dp->psr_enable) |
878 | analogix_dp_enable_sink_psr(dp); | 956 | analogix_dp_enable_sink_psr(dp); |
879 | } | 957 | } |
880 | 958 | ||
@@ -1119,6 +1197,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) | |||
1119 | if (ret) | 1197 | if (ret) |
1120 | DRM_ERROR("failed to setup the panel ret = %d\n", ret); | 1198 | DRM_ERROR("failed to setup the panel ret = %d\n", ret); |
1121 | 1199 | ||
1200 | dp->psr_enable = false; | ||
1122 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | 1201 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
1123 | } | 1202 | } |
1124 | 1203 | ||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 5c6a28806129..6a96ef7e6934 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | |||
@@ -20,6 +20,10 @@ | |||
20 | #define MAX_CR_LOOP 5 | 20 | #define MAX_CR_LOOP 5 |
21 | #define MAX_EQ_LOOP 5 | 21 | #define MAX_EQ_LOOP 5 |
22 | 22 | ||
23 | /* Training takes 22ms if AUX channel comm fails. Use this as retry interval */ | ||
24 | #define DP_TIMEOUT_TRAINING_US 22000 | ||
25 | #define DP_TIMEOUT_PSR_LOOP_MS 300 | ||
26 | |||
23 | /* DP_MAX_LANE_COUNT */ | 27 | /* DP_MAX_LANE_COUNT */ |
24 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) | 28 | #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) |
25 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) | 29 | #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) |
@@ -168,7 +172,8 @@ struct analogix_dp_device { | |||
168 | int dpms_mode; | 172 | int dpms_mode; |
169 | int hpd_gpio; | 173 | int hpd_gpio; |
170 | bool force_hpd; | 174 | bool force_hpd; |
171 | bool psr_support; | 175 | bool psr_enable; |
176 | bool fast_train_support; | ||
172 | 177 | ||
173 | struct mutex panel_lock; | 178 | struct mutex panel_lock; |
174 | bool panel_is_modeset; | 179 | bool panel_is_modeset; |
@@ -247,8 +252,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); | |||
247 | void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); | 252 | void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); |
248 | void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); | 253 | void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); |
249 | void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); | 254 | void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); |
250 | void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, | 255 | int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, |
251 | struct edp_vsc_psr *vsc); | 256 | struct edp_vsc_psr *vsc, bool blocking); |
252 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, | 257 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, |
253 | struct drm_dp_aux_msg *msg); | 258 | struct drm_dp_aux_msg *msg); |
254 | 259 | ||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 303083ad28e3..9df2f3ef000c 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | |||
@@ -10,10 +10,11 @@ | |||
10 | * option) any later version. | 10 | * option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/device.h> | ||
16 | #include <linux/gpio.h> | 15 | #include <linux/gpio.h> |
16 | #include <linux/io.h> | ||
17 | #include <linux/iopoll.h> | ||
17 | 18 | ||
18 | #include <drm/bridge/analogix_dp.h> | 19 | #include <drm/bridge/analogix_dp.h> |
19 | 20 | ||
@@ -992,10 +993,25 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) | |||
992 | writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); | 993 | writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); |
993 | } | 994 | } |
994 | 995 | ||
995 | void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, | 996 | static ssize_t analogix_dp_get_psr_status(struct analogix_dp_device *dp) |
996 | struct edp_vsc_psr *vsc) | 997 | { |
998 | ssize_t val; | ||
999 | u8 status; | ||
1000 | |||
1001 | val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &status); | ||
1002 | if (val < 0) { | ||
1003 | dev_err(dp->dev, "PSR_STATUS read failed ret=%zd", val); | ||
1004 | return val; | ||
1005 | } | ||
1006 | return status; | ||
1007 | } | ||
1008 | |||
1009 | int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, | ||
1010 | struct edp_vsc_psr *vsc, bool blocking) | ||
997 | { | 1011 | { |
998 | unsigned int val; | 1012 | unsigned int val; |
1013 | int ret; | ||
1014 | ssize_t psr_status; | ||
999 | 1015 | ||
1000 | /* don't send info frame */ | 1016 | /* don't send info frame */ |
1001 | val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); | 1017 | val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
@@ -1036,6 +1052,20 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, | |||
1036 | val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); | 1052 | val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
1037 | val |= IF_EN; | 1053 | val |= IF_EN; |
1038 | writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); | 1054 | writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
1055 | |||
1056 | if (!blocking) | ||
1057 | return 0; | ||
1058 | |||
1059 | ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status, | ||
1060 | psr_status >= 0 && | ||
1061 | ((vsc->DB1 && psr_status == DP_PSR_SINK_ACTIVE_RFB) || | ||
1062 | (!vsc->DB1 && psr_status == DP_PSR_SINK_INACTIVE)), 1500, | ||
1063 | DP_TIMEOUT_PSR_LOOP_MS * 1000); | ||
1064 | if (ret) { | ||
1065 | dev_warn(dp->dev, "Failed to apply PSR %d\n", ret); | ||
1066 | return ret; | ||
1067 | } | ||
1068 | return 0; | ||
1039 | } | 1069 | } |
1040 | 1070 | ||
1041 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, | 1071 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, |
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 53ebbe2904b6..ec8d0006ef7c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | |||
@@ -147,7 +147,6 @@ struct dw_hdmi { | |||
147 | int vic; | 147 | int vic; |
148 | 148 | ||
149 | u8 edid[HDMI_EDID_LEN]; | 149 | u8 edid[HDMI_EDID_LEN]; |
150 | bool cable_plugin; | ||
151 | 150 | ||
152 | struct { | 151 | struct { |
153 | const struct dw_hdmi_phy_ops *ops; | 152 | const struct dw_hdmi_phy_ops *ops; |
@@ -1679,12 +1678,6 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) | |||
1679 | hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); | 1678 | hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); |
1680 | } | 1679 | } |
1681 | 1680 | ||
1682 | static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi) | ||
1683 | { | ||
1684 | hdmi_writeb(hdmi, 0, HDMI_FC_MASK2); | ||
1685 | hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2); | ||
1686 | } | ||
1687 | |||
1688 | static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) | 1681 | static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) |
1689 | { | 1682 | { |
1690 | hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK, | 1683 | hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK, |
@@ -1774,8 +1767,6 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) | |||
1774 | hdmi_tx_hdcp_config(hdmi); | 1767 | hdmi_tx_hdcp_config(hdmi); |
1775 | 1768 | ||
1776 | dw_hdmi_clear_overflow(hdmi); | 1769 | dw_hdmi_clear_overflow(hdmi); |
1777 | if (hdmi->cable_plugin && hdmi->sink_is_hdmi) | ||
1778 | hdmi_enable_overflow_interrupts(hdmi); | ||
1779 | 1770 | ||
1780 | return 0; | 1771 | return 0; |
1781 | } | 1772 | } |
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 34b7d420e555..7d25c42f22db 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -391,8 +391,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, | |||
391 | if (blob) { | 391 | if (blob) { |
392 | if (blob->length != sizeof(struct drm_mode_modeinfo) || | 392 | if (blob->length != sizeof(struct drm_mode_modeinfo) || |
393 | drm_mode_convert_umode(state->crtc->dev, &state->mode, | 393 | drm_mode_convert_umode(state->crtc->dev, &state->mode, |
394 | (const struct drm_mode_modeinfo *) | 394 | blob->data)) |
395 | blob->data)) | ||
396 | return -EINVAL; | 395 | return -EINVAL; |
397 | 396 | ||
398 | state->mode_blob = drm_property_blob_get(blob); | 397 | state->mode_blob = drm_property_blob_get(blob); |
@@ -409,11 +408,36 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, | |||
409 | } | 408 | } |
410 | EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); | 409 | EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); |
411 | 410 | ||
411 | /** | ||
412 | * drm_atomic_replace_property_blob_from_id - lookup the new blob and replace the old one with it | ||
413 | * @dev: DRM device | ||
414 | * @blob: a pointer to the member blob to be replaced | ||
415 | * @blob_id: ID of the new blob | ||
416 | * @expected_size: total expected size of the blob data (in bytes) | ||
417 | * @expected_elem_size: expected element size of the blob data (in bytes) | ||
418 | * @replaced: did the blob get replaced? | ||
419 | * | ||
420 | * Replace @blob with another blob with the ID @blob_id. If @blob_id is zero | ||
421 | * @blob becomes NULL. | ||
422 | * | ||
423 | * If @expected_size is positive the new blob length is expected to be equal | ||
424 | * to @expected_size bytes. If @expected_elem_size is positive the new blob | ||
425 | * length is expected to be a multiple of @expected_elem_size bytes. Otherwise | ||
426 | * an error is returned. | ||
427 | * | ||
428 | * @replaced will indicate to the caller whether the blob was replaced or not. | ||
429 | * If the old and new blobs were in fact the same blob @replaced will be false | ||
430 | * otherwise it will be true. | ||
431 | * | ||
432 | * RETURNS: | ||
433 | * Zero on success, error code on failure. | ||
434 | */ | ||
412 | static int | 435 | static int |
413 | drm_atomic_replace_property_blob_from_id(struct drm_device *dev, | 436 | drm_atomic_replace_property_blob_from_id(struct drm_device *dev, |
414 | struct drm_property_blob **blob, | 437 | struct drm_property_blob **blob, |
415 | uint64_t blob_id, | 438 | uint64_t blob_id, |
416 | ssize_t expected_size, | 439 | ssize_t expected_size, |
440 | ssize_t expected_elem_size, | ||
417 | bool *replaced) | 441 | bool *replaced) |
418 | { | 442 | { |
419 | struct drm_property_blob *new_blob = NULL; | 443 | struct drm_property_blob *new_blob = NULL; |
@@ -423,7 +447,13 @@ drm_atomic_replace_property_blob_from_id(struct drm_device *dev, | |||
423 | if (new_blob == NULL) | 447 | if (new_blob == NULL) |
424 | return -EINVAL; | 448 | return -EINVAL; |
425 | 449 | ||
426 | if (expected_size > 0 && expected_size != new_blob->length) { | 450 | if (expected_size > 0 && |
451 | new_blob->length != expected_size) { | ||
452 | drm_property_blob_put(new_blob); | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | if (expected_elem_size > 0 && | ||
456 | new_blob->length % expected_elem_size != 0) { | ||
427 | drm_property_blob_put(new_blob); | 457 | drm_property_blob_put(new_blob); |
428 | return -EINVAL; | 458 | return -EINVAL; |
429 | } | 459 | } |
@@ -471,7 +501,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
471 | ret = drm_atomic_replace_property_blob_from_id(dev, | 501 | ret = drm_atomic_replace_property_blob_from_id(dev, |
472 | &state->degamma_lut, | 502 | &state->degamma_lut, |
473 | val, | 503 | val, |
474 | -1, | 504 | -1, sizeof(struct drm_color_lut), |
475 | &replaced); | 505 | &replaced); |
476 | state->color_mgmt_changed |= replaced; | 506 | state->color_mgmt_changed |= replaced; |
477 | return ret; | 507 | return ret; |
@@ -479,7 +509,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
479 | ret = drm_atomic_replace_property_blob_from_id(dev, | 509 | ret = drm_atomic_replace_property_blob_from_id(dev, |
480 | &state->ctm, | 510 | &state->ctm, |
481 | val, | 511 | val, |
482 | sizeof(struct drm_color_ctm), | 512 | sizeof(struct drm_color_ctm), -1, |
483 | &replaced); | 513 | &replaced); |
484 | state->color_mgmt_changed |= replaced; | 514 | state->color_mgmt_changed |= replaced; |
485 | return ret; | 515 | return ret; |
@@ -487,7 +517,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, | |||
487 | ret = drm_atomic_replace_property_blob_from_id(dev, | 517 | ret = drm_atomic_replace_property_blob_from_id(dev, |
488 | &state->gamma_lut, | 518 | &state->gamma_lut, |
489 | val, | 519 | val, |
490 | -1, | 520 | -1, sizeof(struct drm_color_lut), |
491 | &replaced); | 521 | &replaced); |
492 | state->color_mgmt_changed |= replaced; | 522 | state->color_mgmt_changed |= replaced; |
493 | return ret; | 523 | return ret; |
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 00c78c1c9681..c35654591c12 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c | |||
@@ -3818,7 +3818,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, | |||
3818 | } | 3818 | } |
3819 | 3819 | ||
3820 | /* Prepare GAMMA_LUT with the legacy values. */ | 3820 | /* Prepare GAMMA_LUT with the legacy values. */ |
3821 | blob_data = (struct drm_color_lut *) blob->data; | 3821 | blob_data = blob->data; |
3822 | for (i = 0; i < size; i++) { | 3822 | for (i = 0; i < size; i++) { |
3823 | blob_data[i].red = red[i]; | 3823 | blob_data[i].red = red[i]; |
3824 | blob_data[i].green = green[i]; | 3824 | blob_data[i].green = green[i]; |
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 1ee84dd802d4..ba8cfe65c65b 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c | |||
@@ -129,10 +129,10 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, | |||
129 | * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where | 129 | * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where |
130 | * applicable and if supported by the kernel. | 130 | * applicable and if supported by the kernel. |
131 | */ | 131 | */ |
132 | static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, | 132 | static int drm_addmap_core(struct drm_device *dev, resource_size_t offset, |
133 | unsigned int size, enum drm_map_type type, | 133 | unsigned int size, enum drm_map_type type, |
134 | enum drm_map_flags flags, | 134 | enum drm_map_flags flags, |
135 | struct drm_map_list ** maplist) | 135 | struct drm_map_list **maplist) |
136 | { | 136 | { |
137 | struct drm_local_map *map; | 137 | struct drm_local_map *map; |
138 | struct drm_map_list *list; | 138 | struct drm_map_list *list; |
@@ -224,7 +224,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, | |||
224 | case _DRM_SHM: | 224 | case _DRM_SHM: |
225 | list = drm_find_matching_map(dev, map); | 225 | list = drm_find_matching_map(dev, map); |
226 | if (list != NULL) { | 226 | if (list != NULL) { |
227 | if(list->map->size != map->size) { | 227 | if (list->map->size != map->size) { |
228 | DRM_DEBUG("Matching maps of type %d with " | 228 | DRM_DEBUG("Matching maps of type %d with " |
229 | "mismatched sizes, (%ld vs %ld)\n", | 229 | "mismatched sizes, (%ld vs %ld)\n", |
230 | map->type, map->size, list->map->size); | 230 | map->type, map->size, list->map->size); |
@@ -361,7 +361,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, | |||
361 | return 0; | 361 | return 0; |
362 | } | 362 | } |
363 | 363 | ||
364 | int drm_legacy_addmap(struct drm_device * dev, resource_size_t offset, | 364 | int drm_legacy_addmap(struct drm_device *dev, resource_size_t offset, |
365 | unsigned int size, enum drm_map_type type, | 365 | unsigned int size, enum drm_map_type type, |
366 | enum drm_map_flags flags, struct drm_local_map **map_ptr) | 366 | enum drm_map_flags flags, struct drm_local_map **map_ptr) |
367 | { | 367 | { |
@@ -637,8 +637,8 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, | |||
637 | * | 637 | * |
638 | * Frees any pages and buffers associated with the given entry. | 638 | * Frees any pages and buffers associated with the given entry. |
639 | */ | 639 | */ |
640 | static void drm_cleanup_buf_error(struct drm_device * dev, | 640 | static void drm_cleanup_buf_error(struct drm_device *dev, |
641 | struct drm_buf_entry * entry) | 641 | struct drm_buf_entry *entry) |
642 | { | 642 | { |
643 | int i; | 643 | int i; |
644 | 644 | ||
@@ -1446,8 +1446,8 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data, | |||
1446 | int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p, | 1446 | int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p, |
1447 | void __user **v, | 1447 | void __user **v, |
1448 | int (*f)(void *, int, unsigned long, | 1448 | int (*f)(void *, int, unsigned long, |
1449 | struct drm_buf *), | 1449 | struct drm_buf *), |
1450 | struct drm_file *file_priv) | 1450 | struct drm_file *file_priv) |
1451 | { | 1451 | { |
1452 | struct drm_device_dma *dma = dev->dma; | 1452 | struct drm_device_dma *dma = dev->dma; |
1453 | int retcode = 0; | 1453 | int retcode = 0; |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a797bbf1cab8..49147b2aa288 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -1554,8 +1554,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, | |||
1554 | struct edid *override = NULL; | 1554 | struct edid *override = NULL; |
1555 | 1555 | ||
1556 | if (connector->override_edid) | 1556 | if (connector->override_edid) |
1557 | override = drm_edid_duplicate((const struct edid *) | 1557 | override = drm_edid_duplicate(connector->edid_blob_ptr->data); |
1558 | connector->edid_blob_ptr->data); | ||
1559 | 1558 | ||
1560 | if (!override) | 1559 | if (!override) |
1561 | override = drm_load_edid_firmware(connector); | 1560 | override = drm_load_edid_firmware(connector); |
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 035784ddd133..0646b108030b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -1351,7 +1351,7 @@ static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc, | |||
1351 | if (IS_ERR(gamma_lut)) | 1351 | if (IS_ERR(gamma_lut)) |
1352 | return gamma_lut; | 1352 | return gamma_lut; |
1353 | 1353 | ||
1354 | lut = (struct drm_color_lut *)gamma_lut->data; | 1354 | lut = gamma_lut->data; |
1355 | if (cmap->start || cmap->len != size) { | 1355 | if (cmap->start || cmap->len != size) { |
1356 | u16 *r = crtc->gamma_store; | 1356 | u16 *r = crtc->gamma_store; |
1357 | u16 *g = r + crtc->gamma_size; | 1357 | u16 *g = r + crtc->gamma_size; |
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 5a13ff29f4f0..0eebe8ba8a2c 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c | |||
@@ -158,9 +158,10 @@ static int framebuffer_check(struct drm_device *dev, | |||
158 | info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); | 158 | info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); |
159 | if (!info) { | 159 | if (!info) { |
160 | struct drm_format_name_buf format_name; | 160 | struct drm_format_name_buf format_name; |
161 | |||
161 | DRM_DEBUG_KMS("bad framebuffer format %s\n", | 162 | DRM_DEBUG_KMS("bad framebuffer format %s\n", |
162 | drm_get_format_name(r->pixel_format, | 163 | drm_get_format_name(r->pixel_format, |
163 | &format_name)); | 164 | &format_name)); |
164 | return -EINVAL; | 165 | return -EINVAL; |
165 | } | 166 | } |
166 | 167 | ||
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 5a8033fda4e3..f6b7c0e36a1a 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -773,24 +773,23 @@ EXPORT_SYMBOL(drm_mode_hsync); | |||
773 | int drm_mode_vrefresh(const struct drm_display_mode *mode) | 773 | int drm_mode_vrefresh(const struct drm_display_mode *mode) |
774 | { | 774 | { |
775 | int refresh = 0; | 775 | int refresh = 0; |
776 | unsigned int calc_val; | ||
777 | 776 | ||
778 | if (mode->vrefresh > 0) | 777 | if (mode->vrefresh > 0) |
779 | refresh = mode->vrefresh; | 778 | refresh = mode->vrefresh; |
780 | else if (mode->htotal > 0 && mode->vtotal > 0) { | 779 | else if (mode->htotal > 0 && mode->vtotal > 0) { |
781 | int vtotal; | 780 | unsigned int num, den; |
782 | vtotal = mode->vtotal; | 781 | |
783 | /* work out vrefresh the value will be x1000 */ | 782 | num = mode->clock * 1000; |
784 | calc_val = (mode->clock * 1000); | 783 | den = mode->htotal * mode->vtotal; |
785 | calc_val /= mode->htotal; | ||
786 | refresh = (calc_val + vtotal / 2) / vtotal; | ||
787 | 784 | ||
788 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | 785 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
789 | refresh *= 2; | 786 | num *= 2; |
790 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | 787 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
791 | refresh /= 2; | 788 | den *= 2; |
792 | if (mode->vscan > 1) | 789 | if (mode->vscan > 1) |
793 | refresh /= mode->vscan; | 790 | den *= mode->vscan; |
791 | |||
792 | refresh = DIV_ROUND_CLOSEST(num, den); | ||
794 | } | 793 | } |
795 | return refresh; | 794 | return refresh; |
796 | } | 795 | } |
@@ -1596,12 +1595,8 @@ int drm_mode_convert_umode(struct drm_device *dev, | |||
1596 | struct drm_display_mode *out, | 1595 | struct drm_display_mode *out, |
1597 | const struct drm_mode_modeinfo *in) | 1596 | const struct drm_mode_modeinfo *in) |
1598 | { | 1597 | { |
1599 | int ret = -EINVAL; | 1598 | if (in->clock > INT_MAX || in->vrefresh > INT_MAX) |
1600 | 1599 | return -ERANGE; | |
1601 | if (in->clock > INT_MAX || in->vrefresh > INT_MAX) { | ||
1602 | ret = -ERANGE; | ||
1603 | goto out; | ||
1604 | } | ||
1605 | 1600 | ||
1606 | out->clock = in->clock; | 1601 | out->clock = in->clock; |
1607 | out->hdisplay = in->hdisplay; | 1602 | out->hdisplay = in->hdisplay; |
@@ -1622,14 +1617,11 @@ int drm_mode_convert_umode(struct drm_device *dev, | |||
1622 | 1617 | ||
1623 | out->status = drm_mode_validate_driver(dev, out); | 1618 | out->status = drm_mode_validate_driver(dev, out); |
1624 | if (out->status != MODE_OK) | 1619 | if (out->status != MODE_OK) |
1625 | goto out; | 1620 | return -EINVAL; |
1626 | 1621 | ||
1627 | drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V); | 1622 | drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V); |
1628 | 1623 | ||
1629 | ret = 0; | 1624 | return 0; |
1630 | |||
1631 | out: | ||
1632 | return ret; | ||
1633 | } | 1625 | } |
1634 | 1626 | ||
1635 | /** | 1627 | /** |
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index a5d1fc7e8a37..6d2a6e428a3e 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c | |||
@@ -104,7 +104,7 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane | |||
104 | if (IS_ERR(blob)) | 104 | if (IS_ERR(blob)) |
105 | return -1; | 105 | return -1; |
106 | 106 | ||
107 | blob_data = (struct drm_format_modifier_blob *)blob->data; | 107 | blob_data = blob->data; |
108 | blob_data->version = FORMAT_BLOB_CURRENT; | 108 | blob_data->version = FORMAT_BLOB_CURRENT; |
109 | blob_data->count_formats = plane->format_count; | 109 | blob_data->count_formats = plane->format_count; |
110 | blob_data->formats_offset = sizeof(struct drm_format_modifier_blob); | 110 | blob_data->formats_offset = sizeof(struct drm_format_modifier_blob); |
diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 781518fd88e3..b25f98f33f6c 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c | |||
@@ -63,16 +63,34 @@ void drm_printf(struct drm_printer *p, const char *f, ...) | |||
63 | } | 63 | } |
64 | EXPORT_SYMBOL(drm_printf); | 64 | EXPORT_SYMBOL(drm_printf); |
65 | 65 | ||
66 | #define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV" | ||
67 | |||
68 | void drm_dev_printk(const struct device *dev, const char *level, | 66 | void drm_dev_printk(const struct device *dev, const char *level, |
69 | unsigned int category, const char *function_name, | 67 | const char *format, ...) |
70 | const char *prefix, const char *format, ...) | ||
71 | { | 68 | { |
72 | struct va_format vaf; | 69 | struct va_format vaf; |
73 | va_list args; | 70 | va_list args; |
74 | 71 | ||
75 | if (category != DRM_UT_NONE && !(drm_debug & category)) | 72 | va_start(args, format); |
73 | vaf.fmt = format; | ||
74 | vaf.va = &args; | ||
75 | |||
76 | if (dev) | ||
77 | dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV", | ||
78 | __builtin_return_address(0), &vaf); | ||
79 | else | ||
80 | printk("%s" "[" DRM_NAME ":%ps] %pV", | ||
81 | level, __builtin_return_address(0), &vaf); | ||
82 | |||
83 | va_end(args); | ||
84 | } | ||
85 | EXPORT_SYMBOL(drm_dev_printk); | ||
86 | |||
87 | void drm_dev_dbg(const struct device *dev, unsigned int category, | ||
88 | const char *format, ...) | ||
89 | { | ||
90 | struct va_format vaf; | ||
91 | va_list args; | ||
92 | |||
93 | if (!(drm_debug & category)) | ||
76 | return; | 94 | return; |
77 | 95 | ||
78 | va_start(args, format); | 96 | va_start(args, format); |
@@ -80,32 +98,47 @@ void drm_dev_printk(const struct device *dev, const char *level, | |||
80 | vaf.va = &args; | 98 | vaf.va = &args; |
81 | 99 | ||
82 | if (dev) | 100 | if (dev) |
83 | dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix, | 101 | dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV", |
84 | &vaf); | 102 | __builtin_return_address(0), &vaf); |
85 | else | 103 | else |
86 | printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf); | 104 | printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV", |
105 | __builtin_return_address(0), &vaf); | ||
87 | 106 | ||
88 | va_end(args); | 107 | va_end(args); |
89 | } | 108 | } |
90 | EXPORT_SYMBOL(drm_dev_printk); | 109 | EXPORT_SYMBOL(drm_dev_dbg); |
91 | 110 | ||
92 | void drm_printk(const char *level, unsigned int category, | 111 | void drm_dbg(unsigned int category, const char *format, ...) |
93 | const char *format, ...) | ||
94 | { | 112 | { |
95 | struct va_format vaf; | 113 | struct va_format vaf; |
96 | va_list args; | 114 | va_list args; |
97 | 115 | ||
98 | if (category != DRM_UT_NONE && !(drm_debug & category)) | 116 | if (!(drm_debug & category)) |
99 | return; | 117 | return; |
100 | 118 | ||
101 | va_start(args, format); | 119 | va_start(args, format); |
102 | vaf.fmt = format; | 120 | vaf.fmt = format; |
103 | vaf.va = &args; | 121 | vaf.va = &args; |
104 | 122 | ||
105 | printk("%s" "[" DRM_NAME ":%ps]%s %pV", | 123 | printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV", |
106 | level, __builtin_return_address(0), | 124 | __builtin_return_address(0), &vaf); |
107 | strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf); | 125 | |
126 | va_end(args); | ||
127 | } | ||
128 | EXPORT_SYMBOL(drm_dbg); | ||
129 | |||
130 | void drm_err(const char *format, ...) | ||
131 | { | ||
132 | struct va_format vaf; | ||
133 | va_list args; | ||
134 | |||
135 | va_start(args, format); | ||
136 | vaf.fmt = format; | ||
137 | vaf.va = &args; | ||
138 | |||
139 | printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV", | ||
140 | __builtin_return_address(0), &vaf); | ||
108 | 141 | ||
109 | va_end(args); | 142 | va_end(args); |
110 | } | 143 | } |
111 | EXPORT_SYMBOL(drm_printk); | 144 | EXPORT_SYMBOL(drm_err); |
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 6ac6ee41a6a3..8f4672daac7f 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c | |||
@@ -567,6 +567,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length, | |||
567 | /* This must be explicitly initialised, so we can safely call list_del | 567 | /* This must be explicitly initialised, so we can safely call list_del |
568 | * on it in the removal handler, even if it isn't in a file list. */ | 568 | * on it in the removal handler, even if it isn't in a file list. */ |
569 | INIT_LIST_HEAD(&blob->head_file); | 569 | INIT_LIST_HEAD(&blob->head_file); |
570 | blob->data = (void *)blob + sizeof(*blob); | ||
570 | blob->length = length; | 571 | blob->length = length; |
571 | blob->dev = dev; | 572 | blob->dev = dev; |
572 | 573 | ||
diff --git a/drivers/gpu/drm/i915/intel_color.c b/drivers/gpu/drm/i915/intel_color.c index 89ab0f70aa22..c6a7beabd58d 100644 --- a/drivers/gpu/drm/i915/intel_color.c +++ b/drivers/gpu/drm/i915/intel_color.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0) | 39 | #define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0) |
40 | #define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1)) | 40 | #define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1)) |
41 | 41 | ||
42 | #define LEGACY_LUT_LENGTH (sizeof(struct drm_color_lut) * 256) | 42 | #define LEGACY_LUT_LENGTH 256 |
43 | 43 | ||
44 | /* Post offset values for RGB->YCBCR conversion */ | 44 | /* Post offset values for RGB->YCBCR conversion */ |
45 | #define POSTOFF_RGB_TO_YUV_HI 0x800 | 45 | #define POSTOFF_RGB_TO_YUV_HI 0x800 |
@@ -79,7 +79,7 @@ static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state) | |||
79 | return !state->degamma_lut && | 79 | return !state->degamma_lut && |
80 | !state->ctm && | 80 | !state->ctm && |
81 | state->gamma_lut && | 81 | state->gamma_lut && |
82 | state->gamma_lut->length == LEGACY_LUT_LENGTH; | 82 | drm_color_lut_size(state->gamma_lut) == LEGACY_LUT_LENGTH; |
83 | } | 83 | } |
84 | 84 | ||
85 | /* | 85 | /* |
@@ -153,8 +153,7 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state) | |||
153 | ilk_load_ycbcr_conversion_matrix(intel_crtc); | 153 | ilk_load_ycbcr_conversion_matrix(intel_crtc); |
154 | return; | 154 | return; |
155 | } else if (crtc_state->ctm) { | 155 | } else if (crtc_state->ctm) { |
156 | struct drm_color_ctm *ctm = | 156 | struct drm_color_ctm *ctm = crtc_state->ctm->data; |
157 | (struct drm_color_ctm *)crtc_state->ctm->data; | ||
158 | const u64 *input; | 157 | const u64 *input; |
159 | u64 temp[9]; | 158 | u64 temp[9]; |
160 | 159 | ||
@@ -262,8 +261,7 @@ static void cherryview_load_csc_matrix(struct drm_crtc_state *state) | |||
262 | uint32_t mode; | 261 | uint32_t mode; |
263 | 262 | ||
264 | if (state->ctm) { | 263 | if (state->ctm) { |
265 | struct drm_color_ctm *ctm = | 264 | struct drm_color_ctm *ctm = state->ctm->data; |
266 | (struct drm_color_ctm *) state->ctm->data; | ||
267 | uint16_t coeffs[9] = { 0, }; | 265 | uint16_t coeffs[9] = { 0, }; |
268 | int i; | 266 | int i; |
269 | 267 | ||
@@ -330,7 +328,7 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc, | |||
330 | } | 328 | } |
331 | 329 | ||
332 | if (blob) { | 330 | if (blob) { |
333 | struct drm_color_lut *lut = (struct drm_color_lut *) blob->data; | 331 | struct drm_color_lut *lut = blob->data; |
334 | for (i = 0; i < 256; i++) { | 332 | for (i = 0; i < 256; i++) { |
335 | uint32_t word = | 333 | uint32_t word = |
336 | (drm_color_lut_extract(lut[i].red, 8) << 16) | | 334 | (drm_color_lut_extract(lut[i].red, 8) << 16) | |
@@ -400,8 +398,7 @@ static void bdw_load_degamma_lut(struct drm_crtc_state *state) | |||
400 | PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT); | 398 | PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT); |
401 | 399 | ||
402 | if (state->degamma_lut) { | 400 | if (state->degamma_lut) { |
403 | struct drm_color_lut *lut = | 401 | struct drm_color_lut *lut = state->degamma_lut->data; |
404 | (struct drm_color_lut *) state->degamma_lut->data; | ||
405 | 402 | ||
406 | for (i = 0; i < lut_size; i++) { | 403 | for (i = 0; i < lut_size; i++) { |
407 | uint32_t word = | 404 | uint32_t word = |
@@ -435,8 +432,7 @@ static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset) | |||
435 | offset); | 432 | offset); |
436 | 433 | ||
437 | if (state->gamma_lut) { | 434 | if (state->gamma_lut) { |
438 | struct drm_color_lut *lut = | 435 | struct drm_color_lut *lut = state->gamma_lut->data; |
439 | (struct drm_color_lut *) state->gamma_lut->data; | ||
440 | 436 | ||
441 | for (i = 0; i < lut_size; i++) { | 437 | for (i = 0; i < lut_size; i++) { |
442 | uint32_t word = | 438 | uint32_t word = |
@@ -568,7 +564,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state) | |||
568 | } | 564 | } |
569 | 565 | ||
570 | if (state->degamma_lut) { | 566 | if (state->degamma_lut) { |
571 | lut = (struct drm_color_lut *) state->degamma_lut->data; | 567 | lut = state->degamma_lut->data; |
572 | lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; | 568 | lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size; |
573 | for (i = 0; i < lut_size; i++) { | 569 | for (i = 0; i < lut_size; i++) { |
574 | /* Write LUT in U0.14 format. */ | 570 | /* Write LUT in U0.14 format. */ |
@@ -583,7 +579,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state) | |||
583 | } | 579 | } |
584 | 580 | ||
585 | if (state->gamma_lut) { | 581 | if (state->gamma_lut) { |
586 | lut = (struct drm_color_lut *) state->gamma_lut->data; | 582 | lut = state->gamma_lut->data; |
587 | lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; | 583 | lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size; |
588 | for (i = 0; i < lut_size; i++) { | 584 | for (i = 0; i < lut_size; i++) { |
589 | /* Write LUT in U0.10 format. */ | 585 | /* Write LUT in U0.10 format. */ |
@@ -623,19 +619,17 @@ int intel_color_check(struct drm_crtc *crtc, | |||
623 | struct drm_i915_private *dev_priv = to_i915(crtc->dev); | 619 | struct drm_i915_private *dev_priv = to_i915(crtc->dev); |
624 | size_t gamma_length, degamma_length; | 620 | size_t gamma_length, degamma_length; |
625 | 621 | ||
626 | degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size * | 622 | degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size; |
627 | sizeof(struct drm_color_lut); | 623 | gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size; |
628 | gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size * | ||
629 | sizeof(struct drm_color_lut); | ||
630 | 624 | ||
631 | /* | 625 | /* |
632 | * We allow both degamma & gamma luts at the right size or | 626 | * We allow both degamma & gamma luts at the right size or |
633 | * NULL. | 627 | * NULL. |
634 | */ | 628 | */ |
635 | if ((!crtc_state->degamma_lut || | 629 | if ((!crtc_state->degamma_lut || |
636 | crtc_state->degamma_lut->length == degamma_length) && | 630 | drm_color_lut_size(crtc_state->degamma_lut) == degamma_length) && |
637 | (!crtc_state->gamma_lut || | 631 | (!crtc_state->gamma_lut || |
638 | crtc_state->gamma_lut->length == gamma_length)) | 632 | drm_color_lut_size(crtc_state->gamma_lut) == gamma_length)) |
639 | return 0; | 633 | return 0; |
640 | 634 | ||
641 | /* | 635 | /* |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 331084082545..3b48fd2561fe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -11059,24 +11059,17 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n, | |||
11059 | static void __printf(3, 4) | 11059 | static void __printf(3, 4) |
11060 | pipe_config_err(bool adjust, const char *name, const char *format, ...) | 11060 | pipe_config_err(bool adjust, const char *name, const char *format, ...) |
11061 | { | 11061 | { |
11062 | char *level; | ||
11063 | unsigned int category; | ||
11064 | struct va_format vaf; | 11062 | struct va_format vaf; |
11065 | va_list args; | 11063 | va_list args; |
11066 | 11064 | ||
11067 | if (adjust) { | ||
11068 | level = KERN_DEBUG; | ||
11069 | category = DRM_UT_KMS; | ||
11070 | } else { | ||
11071 | level = KERN_ERR; | ||
11072 | category = DRM_UT_NONE; | ||
11073 | } | ||
11074 | |||
11075 | va_start(args, format); | 11065 | va_start(args, format); |
11076 | vaf.fmt = format; | 11066 | vaf.fmt = format; |
11077 | vaf.va = &args; | 11067 | vaf.va = &args; |
11078 | 11068 | ||
11079 | drm_printk(level, category, "mismatch in %s %pV", name, &vaf); | 11069 | if (adjust) |
11070 | drm_dbg(DRM_UT_KMS, "mismatch in %s %pV", name, &vaf); | ||
11071 | else | ||
11072 | drm_err("mismatch in %s %pV", name, &vaf); | ||
11080 | 11073 | ||
11081 | va_end(args); | 11074 | va_end(args); |
11082 | } | 11075 | } |
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index f9ad0e960263..32b1a6cdecfc 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c | |||
@@ -189,40 +189,55 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) | |||
189 | 189 | ||
190 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); | 190 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); |
191 | regs = devm_ioremap_resource(dev, res); | 191 | regs = devm_ioremap_resource(dev, res); |
192 | if (IS_ERR(regs)) | 192 | if (IS_ERR(regs)) { |
193 | return PTR_ERR(regs); | 193 | ret = PTR_ERR(regs); |
194 | goto free_drm; | ||
195 | } | ||
194 | 196 | ||
195 | priv->io_base = regs; | 197 | priv->io_base = regs; |
196 | 198 | ||
197 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi"); | 199 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi"); |
200 | if (!res) | ||
201 | return -EINVAL; | ||
198 | /* Simply ioremap since it may be a shared register zone */ | 202 | /* Simply ioremap since it may be a shared register zone */ |
199 | regs = devm_ioremap(dev, res->start, resource_size(res)); | 203 | regs = devm_ioremap(dev, res->start, resource_size(res)); |
200 | if (!regs) | 204 | if (!regs) { |
201 | return -EADDRNOTAVAIL; | 205 | ret = -EADDRNOTAVAIL; |
206 | goto free_drm; | ||
207 | } | ||
202 | 208 | ||
203 | priv->hhi = devm_regmap_init_mmio(dev, regs, | 209 | priv->hhi = devm_regmap_init_mmio(dev, regs, |
204 | &meson_regmap_config); | 210 | &meson_regmap_config); |
205 | if (IS_ERR(priv->hhi)) { | 211 | if (IS_ERR(priv->hhi)) { |
206 | dev_err(&pdev->dev, "Couldn't create the HHI regmap\n"); | 212 | dev_err(&pdev->dev, "Couldn't create the HHI regmap\n"); |
207 | return PTR_ERR(priv->hhi); | 213 | ret = PTR_ERR(priv->hhi); |
214 | goto free_drm; | ||
208 | } | 215 | } |
209 | 216 | ||
210 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); | 217 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); |
218 | if (!res) | ||
219 | return -EINVAL; | ||
211 | /* Simply ioremap since it may be a shared register zone */ | 220 | /* Simply ioremap since it may be a shared register zone */ |
212 | regs = devm_ioremap(dev, res->start, resource_size(res)); | 221 | regs = devm_ioremap(dev, res->start, resource_size(res)); |
213 | if (!regs) | 222 | if (!regs) { |
214 | return -EADDRNOTAVAIL; | 223 | ret = -EADDRNOTAVAIL; |
224 | goto free_drm; | ||
225 | } | ||
215 | 226 | ||
216 | priv->dmc = devm_regmap_init_mmio(dev, regs, | 227 | priv->dmc = devm_regmap_init_mmio(dev, regs, |
217 | &meson_regmap_config); | 228 | &meson_regmap_config); |
218 | if (IS_ERR(priv->dmc)) { | 229 | if (IS_ERR(priv->dmc)) { |
219 | dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); | 230 | dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); |
220 | return PTR_ERR(priv->dmc); | 231 | ret = PTR_ERR(priv->dmc); |
232 | goto free_drm; | ||
221 | } | 233 | } |
222 | 234 | ||
223 | priv->vsync_irq = platform_get_irq(pdev, 0); | 235 | priv->vsync_irq = platform_get_irq(pdev, 0); |
224 | 236 | ||
225 | drm_vblank_init(drm, 1); | 237 | ret = drm_vblank_init(drm, 1); |
238 | if (ret) | ||
239 | goto free_drm; | ||
240 | |||
226 | drm_mode_config_init(drm); | 241 | drm_mode_config_init(drm); |
227 | drm->mode_config.max_width = 3840; | 242 | drm->mode_config.max_width = 3840; |
228 | drm->mode_config.max_height = 2160; | 243 | drm->mode_config.max_height = 2160; |
@@ -281,7 +296,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) | |||
281 | return 0; | 296 | return 0; |
282 | 297 | ||
283 | free_drm: | 298 | free_drm: |
284 | drm_dev_unref(drm); | 299 | drm_dev_put(drm); |
285 | 300 | ||
286 | return ret; | 301 | return ret; |
287 | } | 302 | } |
@@ -300,7 +315,7 @@ static void meson_drv_unbind(struct device *dev) | |||
300 | drm_kms_helper_poll_fini(drm); | 315 | drm_kms_helper_poll_fini(drm); |
301 | drm_fbdev_cma_fini(priv->fbdev); | 316 | drm_fbdev_cma_fini(priv->fbdev); |
302 | drm_mode_config_cleanup(drm); | 317 | drm_mode_config_cleanup(drm); |
303 | drm_dev_unref(drm); | 318 | drm_dev_put(drm); |
304 | 319 | ||
305 | } | 320 | } |
306 | 321 | ||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index d49af17310c9..a393095aac1a 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c | |||
@@ -538,7 +538,6 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id) | |||
538 | return IRQ_HANDLED; | 538 | return IRQ_HANDLED; |
539 | } | 539 | } |
540 | 540 | ||
541 | /* TOFIX Enable support for non-vic modes */ | ||
542 | static enum drm_mode_status | 541 | static enum drm_mode_status |
543 | dw_hdmi_mode_valid(struct drm_connector *connector, | 542 | dw_hdmi_mode_valid(struct drm_connector *connector, |
544 | const struct drm_display_mode *mode) | 543 | const struct drm_display_mode *mode) |
@@ -555,12 +554,12 @@ dw_hdmi_mode_valid(struct drm_connector *connector, | |||
555 | mode->vdisplay, mode->vsync_start, | 554 | mode->vdisplay, mode->vsync_start, |
556 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | 555 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); |
557 | 556 | ||
558 | /* For now, only accept VIC modes */ | 557 | /* Check against non-VIC supported modes */ |
559 | if (!vic) | 558 | if (!vic) { |
560 | return MODE_BAD; | 559 | if (!meson_venc_hdmi_supported_mode(mode)) |
561 | 560 | return MODE_BAD; | |
562 | /* For now, filter by supported VIC modes */ | 561 | /* Check against supported VIC modes */ |
563 | if (!meson_venc_hdmi_supported_vic(vic)) | 562 | } else if (!meson_venc_hdmi_supported_vic(vic)) |
564 | return MODE_BAD; | 563 | return MODE_BAD; |
565 | 564 | ||
566 | vclk_freq = mode->clock; | 565 | vclk_freq = mode->clock; |
@@ -586,9 +585,14 @@ dw_hdmi_mode_valid(struct drm_connector *connector, | |||
586 | 585 | ||
587 | /* Finally filter by configurable vclk frequencies */ | 586 | /* Finally filter by configurable vclk frequencies */ |
588 | switch (vclk_freq) { | 587 | switch (vclk_freq) { |
588 | case 25175: | ||
589 | case 40000: | ||
589 | case 54000: | 590 | case 54000: |
591 | case 65000: | ||
590 | case 74250: | 592 | case 74250: |
593 | case 108000: | ||
591 | case 148500: | 594 | case 148500: |
595 | case 162000: | ||
592 | case 297000: | 596 | case 297000: |
593 | case 594000: | 597 | case 594000: |
594 | return MODE_OK; | 598 | return MODE_OK; |
@@ -653,10 +657,6 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, | |||
653 | DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", | 657 | DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n", |
654 | mode->base.id, mode->name, vic); | 658 | mode->base.id, mode->name, vic); |
655 | 659 | ||
656 | /* Should have been filtered */ | ||
657 | if (!vic) | ||
658 | return; | ||
659 | |||
660 | /* VENC + VENC-DVI Mode setup */ | 660 | /* VENC + VENC-DVI Mode setup */ |
661 | meson_venc_hdmi_mode_set(priv, vic, mode); | 661 | meson_venc_hdmi_mode_set(priv, vic, mode); |
662 | 662 | ||
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 47677047e42d..f0511220317f 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c | |||
@@ -328,14 +328,24 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) | |||
328 | #define MESON_VCLK_HDMI_DDR_54000 2 | 328 | #define MESON_VCLK_HDMI_DDR_54000 2 |
329 | /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ | 329 | /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ |
330 | #define MESON_VCLK_HDMI_DDR_148500 3 | 330 | #define MESON_VCLK_HDMI_DDR_148500 3 |
331 | /* 4028 /4 /4 /1 /5 /2 => /1 /1 */ | ||
332 | #define MESON_VCLK_HDMI_25175 4 | ||
333 | /* 3200 /4 /2 /1 /5 /2 => /1 /1 */ | ||
334 | #define MESON_VCLK_HDMI_40000 5 | ||
335 | /* 5200 /4 /2 /1 /5 /2 => /1 /1 */ | ||
336 | #define MESON_VCLK_HDMI_65000 6 | ||
331 | /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ | 337 | /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ |
332 | #define MESON_VCLK_HDMI_74250 4 | 338 | #define MESON_VCLK_HDMI_74250 7 |
339 | /* 4320 /4 /1 /1 /5 /2 => /1 /1 */ | ||
340 | #define MESON_VCLK_HDMI_108000 8 | ||
333 | /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ | 341 | /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ |
334 | #define MESON_VCLK_HDMI_148500 5 | 342 | #define MESON_VCLK_HDMI_148500 9 |
343 | /* 3240 /2 /1 /1 /5 /2 => /1 /1 */ | ||
344 | #define MESON_VCLK_HDMI_162000 10 | ||
335 | /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ | 345 | /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ |
336 | #define MESON_VCLK_HDMI_297000 6 | 346 | #define MESON_VCLK_HDMI_297000 11 |
337 | /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ | 347 | /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ |
338 | #define MESON_VCLK_HDMI_594000 7 | 348 | #define MESON_VCLK_HDMI_594000 12 |
339 | 349 | ||
340 | struct meson_vclk_params { | 350 | struct meson_vclk_params { |
341 | unsigned int pll_base_freq; | 351 | unsigned int pll_base_freq; |
@@ -401,6 +411,46 @@ struct meson_vclk_params { | |||
401 | .vid_pll_div = VID_PLL_DIV_5, | 411 | .vid_pll_div = VID_PLL_DIV_5, |
402 | .vclk_div = 1, | 412 | .vclk_div = 1, |
403 | }, | 413 | }, |
414 | [MESON_VCLK_HDMI_25175] = { | ||
415 | .pll_base_freq = 4028000, | ||
416 | .pll_od1 = 4, | ||
417 | .pll_od2 = 4, | ||
418 | .pll_od3 = 1, | ||
419 | .vid_pll_div = VID_PLL_DIV_5, | ||
420 | .vclk_div = 2, | ||
421 | }, | ||
422 | [MESON_VCLK_HDMI_40000] = { | ||
423 | .pll_base_freq = 3200000, | ||
424 | .pll_od1 = 4, | ||
425 | .pll_od2 = 2, | ||
426 | .pll_od3 = 1, | ||
427 | .vid_pll_div = VID_PLL_DIV_5, | ||
428 | .vclk_div = 2, | ||
429 | }, | ||
430 | [MESON_VCLK_HDMI_65000] = { | ||
431 | .pll_base_freq = 5200000, | ||
432 | .pll_od1 = 4, | ||
433 | .pll_od2 = 2, | ||
434 | .pll_od3 = 1, | ||
435 | .vid_pll_div = VID_PLL_DIV_5, | ||
436 | .vclk_div = 2, | ||
437 | }, | ||
438 | [MESON_VCLK_HDMI_108000] = { | ||
439 | .pll_base_freq = 4320000, | ||
440 | .pll_od1 = 4, | ||
441 | .pll_od2 = 1, | ||
442 | .pll_od3 = 1, | ||
443 | .vid_pll_div = VID_PLL_DIV_5, | ||
444 | .vclk_div = 2, | ||
445 | }, | ||
446 | [MESON_VCLK_HDMI_162000] = { | ||
447 | .pll_base_freq = 3240000, | ||
448 | .pll_od1 = 2, | ||
449 | .pll_od2 = 1, | ||
450 | .pll_od3 = 1, | ||
451 | .vid_pll_div = VID_PLL_DIV_5, | ||
452 | .vclk_div = 2, | ||
453 | }, | ||
404 | }; | 454 | }; |
405 | 455 | ||
406 | static inline unsigned int pll_od_to_reg(unsigned int od) | 456 | static inline unsigned int pll_od_to_reg(unsigned int od) |
@@ -451,6 +501,90 @@ void meson_hdmi_pll_set(struct meson_drm *priv, | |||
451 | 0xFFFF, 0x4e00); | 501 | 0xFFFF, 0x4e00); |
452 | break; | 502 | break; |
453 | 503 | ||
504 | case 3200000: | ||
505 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242); | ||
506 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
507 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); | ||
508 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
509 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
510 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
511 | |||
512 | /* unreset */ | ||
513 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
514 | BIT(28), 0); | ||
515 | |||
516 | /* Poll for lock bit */ | ||
517 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
518 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
519 | |||
520 | /* div_frac */ | ||
521 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
522 | 0xFFFF, 0x4aab); | ||
523 | break; | ||
524 | |||
525 | case 3240000: | ||
526 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243); | ||
527 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
528 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); | ||
529 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
530 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
531 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
532 | |||
533 | /* unreset */ | ||
534 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
535 | BIT(28), 0); | ||
536 | |||
537 | /* Poll for lock bit */ | ||
538 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
539 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
540 | |||
541 | /* div_frac */ | ||
542 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
543 | 0xFFFF, 0x4800); | ||
544 | break; | ||
545 | |||
546 | case 3865000: | ||
547 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250); | ||
548 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
549 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); | ||
550 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
551 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
552 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
553 | |||
554 | /* unreset */ | ||
555 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
556 | BIT(28), 0); | ||
557 | |||
558 | /* Poll for lock bit */ | ||
559 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
560 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
561 | |||
562 | /* div_frac */ | ||
563 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
564 | 0xFFFF, 0x4855); | ||
565 | break; | ||
566 | |||
567 | case 4028000: | ||
568 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253); | ||
569 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
570 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); | ||
571 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
572 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
573 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
574 | |||
575 | /* unreset */ | ||
576 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
577 | BIT(28), 0); | ||
578 | |||
579 | /* Poll for lock bit */ | ||
580 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
581 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
582 | |||
583 | /* div_frac */ | ||
584 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | ||
585 | 0xFFFF, 0x4eab); | ||
586 | break; | ||
587 | |||
454 | case 4320000: | 588 | case 4320000: |
455 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); | 589 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); |
456 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | 590 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); |
@@ -485,6 +619,23 @@ void meson_hdmi_pll_set(struct meson_drm *priv, | |||
485 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | 619 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, |
486 | val, (val & HDMI_PLL_LOCK), 10, 0); | 620 | val, (val & HDMI_PLL_LOCK), 10, 0); |
487 | break; | 621 | break; |
622 | |||
623 | case 5200000: | ||
624 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c); | ||
625 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); | ||
626 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); | ||
627 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); | ||
628 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | ||
629 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | ||
630 | |||
631 | /* unreset */ | ||
632 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
633 | BIT(28), 0); | ||
634 | |||
635 | /* Poll for lock bit */ | ||
636 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
637 | val, (val & HDMI_PLL_LOCK), 10, 0); | ||
638 | break; | ||
488 | }; | 639 | }; |
489 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 640 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
490 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { | 641 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { |
@@ -498,6 +649,42 @@ void meson_hdmi_pll_set(struct meson_drm *priv, | |||
498 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | 649 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); |
499 | break; | 650 | break; |
500 | 651 | ||
652 | case 3200000: | ||
653 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285); | ||
654 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155); | ||
655 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
656 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
657 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
658 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
659 | break; | ||
660 | |||
661 | case 3240000: | ||
662 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287); | ||
663 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); | ||
664 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
665 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
666 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
667 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
668 | break; | ||
669 | |||
670 | case 3865000: | ||
671 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1); | ||
672 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b); | ||
673 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
674 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
675 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
676 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
677 | break; | ||
678 | |||
679 | case 4028000: | ||
680 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7); | ||
681 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355); | ||
682 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
683 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
684 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
685 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
686 | break; | ||
687 | |||
501 | case 4320000: | 688 | case 4320000: |
502 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); | 689 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); |
503 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); | 690 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); |
@@ -516,6 +703,15 @@ void meson_hdmi_pll_set(struct meson_drm *priv, | |||
516 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | 703 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); |
517 | break; | 704 | break; |
518 | 705 | ||
706 | case 5200000: | ||
707 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8); | ||
708 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab); | ||
709 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); | ||
710 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); | ||
711 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); | ||
712 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); | ||
713 | break; | ||
714 | |||
519 | }; | 715 | }; |
520 | 716 | ||
521 | /* Reset PLL */ | 717 | /* Reset PLL */ |
@@ -590,15 +786,30 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, | |||
590 | else | 786 | else |
591 | freq = MESON_VCLK_HDMI_DDR_54000; | 787 | freq = MESON_VCLK_HDMI_DDR_54000; |
592 | break; | 788 | break; |
789 | case 25175: | ||
790 | freq = MESON_VCLK_HDMI_25175; | ||
791 | break; | ||
792 | case 40000: | ||
793 | freq = MESON_VCLK_HDMI_40000; | ||
794 | break; | ||
795 | case 65000: | ||
796 | freq = MESON_VCLK_HDMI_65000; | ||
797 | break; | ||
593 | case 74250: | 798 | case 74250: |
594 | freq = MESON_VCLK_HDMI_74250; | 799 | freq = MESON_VCLK_HDMI_74250; |
595 | break; | 800 | break; |
801 | case 108000: | ||
802 | freq = MESON_VCLK_HDMI_108000; | ||
803 | break; | ||
596 | case 148500: | 804 | case 148500: |
597 | if (dac_freq != 148500) | 805 | if (dac_freq != 148500) |
598 | freq = MESON_VCLK_HDMI_DDR_148500; | 806 | freq = MESON_VCLK_HDMI_DDR_148500; |
599 | else | 807 | else |
600 | freq = MESON_VCLK_HDMI_148500; | 808 | freq = MESON_VCLK_HDMI_148500; |
601 | break; | 809 | break; |
810 | case 162000: | ||
811 | freq = MESON_VCLK_HDMI_162000; | ||
812 | break; | ||
602 | case 297000: | 813 | case 297000: |
603 | freq = MESON_VCLK_HDMI_297000; | 814 | freq = MESON_VCLK_HDMI_297000; |
604 | break; | 815 | break; |
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 9509017dbded..6e2701389801 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c | |||
@@ -697,6 +697,314 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { | |||
697 | }, | 697 | }, |
698 | }; | 698 | }; |
699 | 699 | ||
700 | union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = { | ||
701 | .encp = { | ||
702 | .dvi_settings = 0x21, | ||
703 | .video_mode = 0x4040, | ||
704 | .video_mode_adv = 0x18, | ||
705 | /* video_prog_mode */ | ||
706 | /* video_sync_mode */ | ||
707 | /* video_yc_dly */ | ||
708 | /* video_rgb_ctrl */ | ||
709 | /* video_filt_ctrl */ | ||
710 | /* video_ofld_voav_ofst */ | ||
711 | /* yfp1_htime */ | ||
712 | /* yfp2_htime */ | ||
713 | .max_pxcnt = 0x31f, | ||
714 | /* hspuls_begin */ | ||
715 | /* hspuls_end */ | ||
716 | /* hspuls_switch */ | ||
717 | /* vspuls_begin */ | ||
718 | /* vspuls_end */ | ||
719 | /* vspuls_bline */ | ||
720 | /* vspuls_eline */ | ||
721 | .havon_begin = 0x90, | ||
722 | .havon_end = 0x30f, | ||
723 | .vavon_bline = 0x23, | ||
724 | .vavon_eline = 0x202, | ||
725 | /* eqpuls_begin */ | ||
726 | /* eqpuls_end */ | ||
727 | /* eqpuls_bline */ | ||
728 | /* eqpuls_eline */ | ||
729 | .hso_begin = 0, | ||
730 | .hso_end = 0x60, | ||
731 | .vso_begin = 0x1e, | ||
732 | .vso_end = 0x32, | ||
733 | .vso_bline = 0, | ||
734 | .vso_eline = 2, | ||
735 | .vso_eline_present = true, | ||
736 | /* sy_val */ | ||
737 | /* sy2_val */ | ||
738 | .max_lncnt = 0x20c, | ||
739 | }, | ||
740 | }; | ||
741 | |||
742 | union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = { | ||
743 | .encp = { | ||
744 | .dvi_settings = 0x21, | ||
745 | .video_mode = 0x4040, | ||
746 | .video_mode_adv = 0x18, | ||
747 | /* video_prog_mode */ | ||
748 | /* video_sync_mode */ | ||
749 | /* video_yc_dly */ | ||
750 | /* video_rgb_ctrl */ | ||
751 | /* video_filt_ctrl */ | ||
752 | /* video_ofld_voav_ofst */ | ||
753 | /* yfp1_htime */ | ||
754 | /* yfp2_htime */ | ||
755 | .max_pxcnt = 0x41f, | ||
756 | /* hspuls_begin */ | ||
757 | /* hspuls_end */ | ||
758 | /* hspuls_switch */ | ||
759 | /* vspuls_begin */ | ||
760 | /* vspuls_end */ | ||
761 | /* vspuls_bline */ | ||
762 | /* vspuls_eline */ | ||
763 | .havon_begin = 0xD8, | ||
764 | .havon_end = 0x3f7, | ||
765 | .vavon_bline = 0x1b, | ||
766 | .vavon_eline = 0x272, | ||
767 | /* eqpuls_begin */ | ||
768 | /* eqpuls_end */ | ||
769 | /* eqpuls_bline */ | ||
770 | /* eqpuls_eline */ | ||
771 | .hso_begin = 0, | ||
772 | .hso_end = 0x80, | ||
773 | .vso_begin = 0x1e, | ||
774 | .vso_end = 0x32, | ||
775 | .vso_bline = 0, | ||
776 | .vso_eline = 4, | ||
777 | .vso_eline_present = true, | ||
778 | /* sy_val */ | ||
779 | /* sy2_val */ | ||
780 | .max_lncnt = 0x273, | ||
781 | }, | ||
782 | }; | ||
783 | |||
784 | union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = { | ||
785 | .encp = { | ||
786 | .dvi_settings = 0x21, | ||
787 | .video_mode = 0x4040, | ||
788 | .video_mode_adv = 0x18, | ||
789 | /* video_prog_mode */ | ||
790 | /* video_sync_mode */ | ||
791 | /* video_yc_dly */ | ||
792 | /* video_rgb_ctrl */ | ||
793 | /* video_filt_ctrl */ | ||
794 | /* video_ofld_voav_ofst */ | ||
795 | /* yfp1_htime */ | ||
796 | /* yfp2_htime */ | ||
797 | .max_pxcnt = 1343, | ||
798 | /* hspuls_begin */ | ||
799 | /* hspuls_end */ | ||
800 | /* hspuls_switch */ | ||
801 | /* vspuls_begin */ | ||
802 | /* vspuls_end */ | ||
803 | /* vspuls_bline */ | ||
804 | /* vspuls_eline */ | ||
805 | .havon_begin = 296, | ||
806 | .havon_end = 1319, | ||
807 | .vavon_bline = 35, | ||
808 | .vavon_eline = 802, | ||
809 | /* eqpuls_begin */ | ||
810 | /* eqpuls_end */ | ||
811 | /* eqpuls_bline */ | ||
812 | /* eqpuls_eline */ | ||
813 | .hso_begin = 0, | ||
814 | .hso_end = 136, | ||
815 | .vso_begin = 30, | ||
816 | .vso_end = 50, | ||
817 | .vso_bline = 0, | ||
818 | .vso_eline = 6, | ||
819 | .vso_eline_present = true, | ||
820 | /* sy_val */ | ||
821 | /* sy2_val */ | ||
822 | .max_lncnt = 805, | ||
823 | }, | ||
824 | }; | ||
825 | |||
826 | union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = { | ||
827 | .encp = { | ||
828 | .dvi_settings = 0x21, | ||
829 | .video_mode = 0x4040, | ||
830 | .video_mode_adv = 0x18, | ||
831 | /* video_prog_mode */ | ||
832 | /* video_sync_mode */ | ||
833 | /* video_yc_dly */ | ||
834 | /* video_rgb_ctrl */ | ||
835 | /* video_filt_ctrl */ | ||
836 | /* video_ofld_voav_ofst */ | ||
837 | /* yfp1_htime */ | ||
838 | /* yfp2_htime */ | ||
839 | .max_pxcnt = 0x63f, | ||
840 | /* hspuls_begin */ | ||
841 | /* hspuls_end */ | ||
842 | /* hspuls_switch */ | ||
843 | /* vspuls_begin */ | ||
844 | /* vspuls_end */ | ||
845 | /* vspuls_bline */ | ||
846 | /* vspuls_eline */ | ||
847 | .havon_begin = 0x180, | ||
848 | .havon_end = 0x5ff, | ||
849 | .vavon_bline = 0x23, | ||
850 | .vavon_eline = 0x382, | ||
851 | /* eqpuls_begin */ | ||
852 | /* eqpuls_end */ | ||
853 | /* eqpuls_bline */ | ||
854 | /* eqpuls_eline */ | ||
855 | .hso_begin = 0, | ||
856 | .hso_end = 0x80, | ||
857 | .vso_begin = 0x1e, | ||
858 | .vso_end = 0x32, | ||
859 | .vso_bline = 0, | ||
860 | .vso_eline = 3, | ||
861 | .vso_eline_present = true, | ||
862 | /* sy_val */ | ||
863 | /* sy2_val */ | ||
864 | .max_lncnt = 0x383, | ||
865 | }, | ||
866 | }; | ||
867 | |||
868 | union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = { | ||
869 | .encp = { | ||
870 | .dvi_settings = 0x21, | ||
871 | .video_mode = 0x4040, | ||
872 | .video_mode_adv = 0x18, | ||
873 | /* video_prog_mode */ | ||
874 | /* video_sync_mode */ | ||
875 | /* video_yc_dly */ | ||
876 | /* video_rgb_ctrl */ | ||
877 | /* video_filt_ctrl */ | ||
878 | /* video_ofld_voav_ofst */ | ||
879 | /* yfp1_htime */ | ||
880 | /* yfp2_htime */ | ||
881 | .max_pxcnt = 0x697, | ||
882 | /* hspuls_begin */ | ||
883 | /* hspuls_end */ | ||
884 | /* hspuls_switch */ | ||
885 | /* vspuls_begin */ | ||
886 | /* vspuls_end */ | ||
887 | /* vspuls_bline */ | ||
888 | /* vspuls_eline */ | ||
889 | .havon_begin = 0x168, | ||
890 | .havon_end = 0x667, | ||
891 | .vavon_bline = 0x29, | ||
892 | .vavon_eline = 0x428, | ||
893 | /* eqpuls_begin */ | ||
894 | /* eqpuls_end */ | ||
895 | /* eqpuls_bline */ | ||
896 | /* eqpuls_eline */ | ||
897 | .hso_begin = 0, | ||
898 | .hso_end = 0x70, | ||
899 | .vso_begin = 0x1e, | ||
900 | .vso_end = 0x32, | ||
901 | .vso_bline = 0, | ||
902 | .vso_eline = 3, | ||
903 | .vso_eline_present = true, | ||
904 | /* sy_val */ | ||
905 | /* sy2_val */ | ||
906 | .max_lncnt = 0x429, | ||
907 | }, | ||
908 | }; | ||
909 | |||
910 | union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = { | ||
911 | .encp = { | ||
912 | .dvi_settings = 0x21, | ||
913 | .video_mode = 0x4040, | ||
914 | .video_mode_adv = 0x18, | ||
915 | /* video_prog_mode */ | ||
916 | /* video_sync_mode */ | ||
917 | /* video_yc_dly */ | ||
918 | /* video_rgb_ctrl */ | ||
919 | /* video_filt_ctrl */ | ||
920 | /* video_ofld_voav_ofst */ | ||
921 | /* yfp1_htime */ | ||
922 | /* yfp2_htime */ | ||
923 | .max_pxcnt = 0x86f, | ||
924 | /* hspuls_begin */ | ||
925 | /* hspuls_end */ | ||
926 | /* hspuls_switch */ | ||
927 | /* vspuls_begin */ | ||
928 | /* vspuls_end */ | ||
929 | /* vspuls_bline */ | ||
930 | /* vspuls_eline */ | ||
931 | .havon_begin = 0x1f0, | ||
932 | .havon_end = 0x82f, | ||
933 | .vavon_bline = 0x31, | ||
934 | .vavon_eline = 0x4e0, | ||
935 | /* eqpuls_begin */ | ||
936 | /* eqpuls_end */ | ||
937 | /* eqpuls_bline */ | ||
938 | /* eqpuls_eline */ | ||
939 | .hso_begin = 0, | ||
940 | .hso_end = 0xc0, | ||
941 | .vso_begin = 0x1e, | ||
942 | .vso_end = 0x32, | ||
943 | .vso_bline = 0, | ||
944 | .vso_eline = 3, | ||
945 | .vso_eline_present = true, | ||
946 | /* sy_val */ | ||
947 | /* sy2_val */ | ||
948 | .max_lncnt = 0x4e1, | ||
949 | }, | ||
950 | }; | ||
951 | |||
952 | struct meson_hdmi_venc_dmt_mode { | ||
953 | struct drm_display_mode drm_mode; | ||
954 | union meson_hdmi_venc_mode *mode; | ||
955 | } meson_hdmi_venc_dmt_modes[] = { | ||
956 | /* 640x480@60Hz */ | ||
957 | { | ||
958 | { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, | ||
959 | 752, 800, 0, 480, 490, 492, 525, 0, | ||
960 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | ||
961 | &meson_hdmi_encp_mode_640x480_60, | ||
962 | }, | ||
963 | /* 800x600@60Hz */ | ||
964 | { | ||
965 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, | ||
966 | 968, 1056, 0, 600, 601, 605, 628, 0, | ||
967 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
968 | &meson_hdmi_encp_mode_800x600_60, | ||
969 | }, | ||
970 | /* 1024x768@60Hz */ | ||
971 | { | ||
972 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, | ||
973 | 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, | ||
974 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | ||
975 | &meson_hdmi_encp_mode_1024x768_60, | ||
976 | }, | ||
977 | /* 1152x864@75Hz */ | ||
978 | { | ||
979 | { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, | ||
980 | 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, | ||
981 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
982 | &meson_hdmi_encp_mode_1152x864_75, | ||
983 | }, | ||
984 | /* 1280x1024@60Hz */ | ||
985 | { | ||
986 | { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, | ||
987 | 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, | ||
988 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
989 | &meson_hdmi_encp_mode_1280x1024_60, | ||
990 | }, | ||
991 | /* 1600x1200@60Hz */ | ||
992 | { | ||
993 | { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, | ||
994 | 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, | ||
995 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
996 | &meson_hdmi_encp_mode_1600x1200_60, | ||
997 | }, | ||
998 | /* 1920x1080@60Hz */ | ||
999 | { | ||
1000 | { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, | ||
1001 | 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||
1002 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | ||
1003 | &meson_hdmi_encp_mode_1080p60 | ||
1004 | }, | ||
1005 | { }, /* sentinel */ | ||
1006 | }; | ||
1007 | |||
700 | struct meson_hdmi_venc_vic_mode { | 1008 | struct meson_hdmi_venc_vic_mode { |
701 | unsigned int vic; | 1009 | unsigned int vic; |
702 | union meson_hdmi_venc_mode *mode; | 1010 | union meson_hdmi_venc_mode *mode; |
@@ -736,6 +1044,20 @@ static unsigned long modulo(unsigned long a, unsigned long b) | |||
736 | return a; | 1044 | return a; |
737 | } | 1045 | } |
738 | 1046 | ||
1047 | bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) | ||
1048 | { | ||
1049 | struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; | ||
1050 | |||
1051 | while (vmode->mode) { | ||
1052 | if (drm_mode_equal(&vmode->drm_mode, mode)) | ||
1053 | return true; | ||
1054 | vmode++; | ||
1055 | } | ||
1056 | |||
1057 | return false; | ||
1058 | } | ||
1059 | EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode); | ||
1060 | |||
739 | bool meson_venc_hdmi_supported_vic(int vic) | 1061 | bool meson_venc_hdmi_supported_vic(int vic) |
740 | { | 1062 | { |
741 | struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; | 1063 | struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; |
@@ -750,6 +1072,20 @@ bool meson_venc_hdmi_supported_vic(int vic) | |||
750 | } | 1072 | } |
751 | EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); | 1073 | EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); |
752 | 1074 | ||
1075 | static union meson_hdmi_venc_mode | ||
1076 | *meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode) | ||
1077 | { | ||
1078 | struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; | ||
1079 | |||
1080 | while (vmode->mode) { | ||
1081 | if (drm_mode_equal(&vmode->drm_mode, mode)) | ||
1082 | return vmode->mode; | ||
1083 | vmode++; | ||
1084 | } | ||
1085 | |||
1086 | return NULL; | ||
1087 | } | ||
1088 | |||
753 | static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) | 1089 | static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) |
754 | { | 1090 | { |
755 | struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; | 1091 | struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes; |
@@ -811,10 +1147,13 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, | |||
811 | unsigned int sof_lines; | 1147 | unsigned int sof_lines; |
812 | unsigned int vsync_lines; | 1148 | unsigned int vsync_lines; |
813 | 1149 | ||
814 | vmode = meson_venc_hdmi_get_vic_vmode(vic); | 1150 | if (meson_venc_hdmi_supported_vic(vic)) |
1151 | vmode = meson_venc_hdmi_get_vic_vmode(vic); | ||
1152 | else | ||
1153 | vmode = meson_venc_hdmi_get_dmt_vmode(mode); | ||
815 | if (!vmode) { | 1154 | if (!vmode) { |
816 | dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n", | 1155 | dev_err(priv->dev, "%s: Fatal Error, unsupported mode " |
817 | __func__, vic); | 1156 | DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode)); |
818 | return; | 1157 | return; |
819 | } | 1158 | } |
820 | 1159 | ||
@@ -864,7 +1203,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, | |||
864 | hsync_pixels_venc *= 2; | 1203 | hsync_pixels_venc *= 2; |
865 | 1204 | ||
866 | /* Disable VDACs */ | 1205 | /* Disable VDACs */ |
867 | writel_bits_relaxed(0x1f, 0x1f, | 1206 | writel_bits_relaxed(0xff, 0xff, |
868 | priv->io_base + _REG(VENC_VDAC_SETTING)); | 1207 | priv->io_base + _REG(VENC_VDAC_SETTING)); |
869 | 1208 | ||
870 | writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); | 1209 | writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); |
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index a1b96e898c14..7c18a36a0dd0 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h | |||
@@ -58,6 +58,7 @@ struct meson_cvbs_enci_mode { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | /* HDMI Clock parameters */ | 60 | /* HDMI Clock parameters */ |
61 | bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); | ||
61 | bool meson_venc_hdmi_supported_vic(int vic); | 62 | bool meson_venc_hdmi_supported_vic(int vic); |
62 | bool meson_venc_hdmi_venc_repeat(int vic); | 63 | bool meson_venc_hdmi_venc_repeat(int vic); |
63 | 64 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 3e293029e3a6..bbbf353682e1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -510,37 +510,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev, | |||
510 | return 0; | 510 | return 0; |
511 | } | 511 | } |
512 | 512 | ||
513 | #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 | ||
514 | |||
515 | static void | ||
516 | nouveau_get_hdmi_dev(struct nouveau_drm *drm) | ||
517 | { | ||
518 | struct pci_dev *pdev = drm->dev->pdev; | ||
519 | |||
520 | if (!pdev) { | ||
521 | NV_DEBUG(drm, "not a PCI device; no HDMI\n"); | ||
522 | drm->hdmi_device = NULL; | ||
523 | return; | ||
524 | } | ||
525 | |||
526 | /* subfunction one is a hdmi audio device? */ | ||
527 | drm->hdmi_device = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), | ||
528 | (unsigned int)pdev->bus->number, | ||
529 | PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); | ||
530 | |||
531 | if (!drm->hdmi_device) { | ||
532 | NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); | ||
533 | return; | ||
534 | } | ||
535 | |||
536 | if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) { | ||
537 | NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class); | ||
538 | pci_dev_put(drm->hdmi_device); | ||
539 | drm->hdmi_device = NULL; | ||
540 | return; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | static int | 513 | static int |
545 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) | 514 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) |
546 | { | 515 | { |
@@ -568,8 +537,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
568 | INIT_LIST_HEAD(&drm->clients); | 537 | INIT_LIST_HEAD(&drm->clients); |
569 | spin_lock_init(&drm->tile.lock); | 538 | spin_lock_init(&drm->tile.lock); |
570 | 539 | ||
571 | nouveau_get_hdmi_dev(drm); | ||
572 | |||
573 | /* workaround an odd issue on nvc1 by disabling the device's | 540 | /* workaround an odd issue on nvc1 by disabling the device's |
574 | * nosnoop capability. hopefully won't cause issues until a | 541 | * nosnoop capability. hopefully won't cause issues until a |
575 | * better fix is found - assuming there is one... | 542 | * better fix is found - assuming there is one... |
@@ -655,8 +622,6 @@ nouveau_drm_unload(struct drm_device *dev) | |||
655 | nouveau_ttm_fini(drm); | 622 | nouveau_ttm_fini(drm); |
656 | nouveau_vga_fini(drm); | 623 | nouveau_vga_fini(drm); |
657 | 624 | ||
658 | if (drm->hdmi_device) | ||
659 | pci_dev_put(drm->hdmi_device); | ||
660 | nouveau_cli_fini(&drm->client); | 625 | nouveau_cli_fini(&drm->client); |
661 | nouveau_cli_fini(&drm->master); | 626 | nouveau_cli_fini(&drm->master); |
662 | kfree(drm); | 627 | kfree(drm); |
@@ -856,7 +821,6 @@ nouveau_pmops_runtime_suspend(struct device *dev) | |||
856 | } | 821 | } |
857 | 822 | ||
858 | drm_kms_helper_poll_disable(drm_dev); | 823 | drm_kms_helper_poll_disable(drm_dev); |
859 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); | ||
860 | nouveau_switcheroo_optimus_dsm(); | 824 | nouveau_switcheroo_optimus_dsm(); |
861 | ret = nouveau_do_suspend(drm_dev, true); | 825 | ret = nouveau_do_suspend(drm_dev, true); |
862 | pci_save_state(pdev); | 826 | pci_save_state(pdev); |
@@ -891,7 +855,6 @@ nouveau_pmops_runtime_resume(struct device *dev) | |||
891 | 855 | ||
892 | /* do magic */ | 856 | /* do magic */ |
893 | nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25)); | 857 | nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25)); |
894 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); | ||
895 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; | 858 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; |
896 | 859 | ||
897 | /* Monitors may have been connected / disconnected during suspend */ | 860 | /* Monitors may have been connected / disconnected during suspend */ |
@@ -913,15 +876,6 @@ nouveau_pmops_runtime_idle(struct device *dev) | |||
913 | return -EBUSY; | 876 | return -EBUSY; |
914 | } | 877 | } |
915 | 878 | ||
916 | /* if we have a hdmi audio device - make sure it has a driver loaded */ | ||
917 | if (drm->hdmi_device) { | ||
918 | if (!drm->hdmi_device->driver) { | ||
919 | DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n"); | ||
920 | pm_runtime_mark_last_busy(dev); | ||
921 | return -EBUSY; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { | 879 | list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) { |
926 | if (crtc->enabled) { | 880 | if (crtc->enabled) { |
927 | DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); | 881 | DRM_DEBUG_DRIVER("failing to power off - crtc active\n"); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 96f6bd8aee5d..881b44b89a01 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -208,7 +208,6 @@ struct nouveau_drm { | |||
208 | bool have_disp_power_ref; | 208 | bool have_disp_power_ref; |
209 | 209 | ||
210 | struct dev_pm_domain vga_pm_domain; | 210 | struct dev_pm_domain vga_pm_domain; |
211 | struct pci_dev *hdmi_device; | ||
212 | }; | 211 | }; |
213 | 212 | ||
214 | static inline struct nouveau_drm * | 213 | static inline struct nouveau_drm * |
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 988048ebcc22..25682ff3449a 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig | |||
@@ -108,6 +108,15 @@ config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN | |||
108 | Pi 7" Touchscreen. To compile this driver as a module, | 108 | Pi 7" Touchscreen. To compile this driver as a module, |
109 | choose M here. | 109 | choose M here. |
110 | 110 | ||
111 | config DRM_PANEL_RAYDIUM_RM68200 | ||
112 | tristate "Raydium RM68200 720x1280 DSI video mode panel" | ||
113 | depends on OF | ||
114 | depends on DRM_MIPI_DSI | ||
115 | depends on BACKLIGHT_CLASS_DEVICE | ||
116 | help | ||
117 | Say Y here if you want to enable support for Raydium RM68200 | ||
118 | 720x1280 DSI video mode panel. | ||
119 | |||
111 | config DRM_PANEL_SAMSUNG_S6E3HA2 | 120 | config DRM_PANEL_SAMSUNG_S6E3HA2 |
112 | tristate "Samsung S6E3HA2 DSI video mode panel" | 121 | tristate "Samsung S6E3HA2 DSI video mode panel" |
113 | depends on OF | 122 | depends on OF |
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 3d2a88d0e965..f26efc11d746 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o | |||
9 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o | 9 | obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o |
10 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o | 10 | obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o |
11 | obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o | 11 | obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o |
12 | obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o | ||
12 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o | 13 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o |
13 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o | 14 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o |
14 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o | 15 | obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o |
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index b4ec0ecff807..bd38bf4f1ba6 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c | |||
@@ -179,7 +179,7 @@ enum ili9322_input { | |||
179 | ILI9322_INPUT_UNKNOWN = 0xc, | 179 | ILI9322_INPUT_UNKNOWN = 0xc, |
180 | }; | 180 | }; |
181 | 181 | ||
182 | const char *ili9322_inputs[] = { | 182 | static const char * const ili9322_inputs[] = { |
183 | "8 bit serial RGB through", | 183 | "8 bit serial RGB through", |
184 | "8 bit serial RGB aligned", | 184 | "8 bit serial RGB aligned", |
185 | "8 bit serial RGB dummy 320x240", | 185 | "8 bit serial RGB dummy 320x240", |
@@ -340,7 +340,7 @@ static bool ili9322_writeable_reg(struct device *dev, unsigned int reg) | |||
340 | return true; | 340 | return true; |
341 | } | 341 | } |
342 | 342 | ||
343 | const struct regmap_config ili9322_regmap_config = { | 343 | static const struct regmap_config ili9322_regmap_config = { |
344 | .reg_bits = 8, | 344 | .reg_bits = 8, |
345 | .val_bits = 8, | 345 | .val_bits = 8, |
346 | .max_register = 0x44, | 346 | .max_register = 0x44, |
diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c index b5e3994f0aa8..5185819c5b79 100644 --- a/drivers/gpu/drm/panel/panel-lvds.c +++ b/drivers/gpu/drm/panel/panel-lvds.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * rcar_du_crtc.c -- R-Car Display Unit CRTCs | 2 | * Generic LVDS panel driver |
3 | * | 3 | * |
4 | * Copyright (C) 2016 Laurent Pinchart | 4 | * Copyright (C) 2016 Laurent Pinchart |
5 | * Copyright (C) 2016 Renesas Electronics Corporation | 5 | * Copyright (C) 2016 Renesas Electronics Corporation |
diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index c189cd6329c8..90f1ae4af93c 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | |||
@@ -1,16 +1,17 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | /* | 2 | /* |
2 | * Copyright (C) STMicroelectronics SA 2017 | 3 | * Copyright (C) STMicroelectronics SA 2017 |
3 | * | 4 | * |
4 | * Authors: Philippe Cornu <philippe.cornu@st.com> | 5 | * Authors: Philippe Cornu <philippe.cornu@st.com> |
5 | * Yannick Fertre <yannick.fertre@st.com> | 6 | * Yannick Fertre <yannick.fertre@st.com> |
6 | * | ||
7 | * License terms: GNU General Public License (GPL), version 2 | ||
8 | */ | 7 | */ |
8 | |||
9 | #include <drm/drmP.h> | 9 | #include <drm/drmP.h> |
10 | #include <drm/drm_mipi_dsi.h> | 10 | #include <drm/drm_mipi_dsi.h> |
11 | #include <drm/drm_panel.h> | 11 | #include <drm/drm_panel.h> |
12 | #include <linux/backlight.h> | 12 | #include <linux/backlight.h> |
13 | #include <linux/gpio/consumer.h> | 13 | #include <linux/gpio/consumer.h> |
14 | #include <linux/regulator/consumer.h> | ||
14 | #include <video/mipi_display.h> | 15 | #include <video/mipi_display.h> |
15 | 16 | ||
16 | #define DRV_NAME "orisetech_otm8009a" | 17 | #define DRV_NAME "orisetech_otm8009a" |
@@ -62,6 +63,7 @@ struct otm8009a { | |||
62 | struct drm_panel panel; | 63 | struct drm_panel panel; |
63 | struct backlight_device *bl_dev; | 64 | struct backlight_device *bl_dev; |
64 | struct gpio_desc *reset_gpio; | 65 | struct gpio_desc *reset_gpio; |
66 | struct regulator *supply; | ||
65 | bool prepared; | 67 | bool prepared; |
66 | bool enabled; | 68 | bool enabled; |
67 | }; | 69 | }; |
@@ -279,6 +281,8 @@ static int otm8009a_unprepare(struct drm_panel *panel) | |||
279 | msleep(20); | 281 | msleep(20); |
280 | } | 282 | } |
281 | 283 | ||
284 | regulator_disable(ctx->supply); | ||
285 | |||
282 | ctx->prepared = false; | 286 | ctx->prepared = false; |
283 | 287 | ||
284 | return 0; | 288 | return 0; |
@@ -292,6 +296,12 @@ static int otm8009a_prepare(struct drm_panel *panel) | |||
292 | if (ctx->prepared) | 296 | if (ctx->prepared) |
293 | return 0; | 297 | return 0; |
294 | 298 | ||
299 | ret = regulator_enable(ctx->supply); | ||
300 | if (ret < 0) { | ||
301 | DRM_ERROR("failed to enable supply: %d\n", ret); | ||
302 | return ret; | ||
303 | } | ||
304 | |||
295 | if (ctx->reset_gpio) { | 305 | if (ctx->reset_gpio) { |
296 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); | 306 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); |
297 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); | 307 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); |
@@ -414,6 +424,13 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) | |||
414 | return PTR_ERR(ctx->reset_gpio); | 424 | return PTR_ERR(ctx->reset_gpio); |
415 | } | 425 | } |
416 | 426 | ||
427 | ctx->supply = devm_regulator_get(dev, "power"); | ||
428 | if (IS_ERR(ctx->supply)) { | ||
429 | ret = PTR_ERR(ctx->supply); | ||
430 | dev_err(dev, "failed to request regulator: %d\n", ret); | ||
431 | return ret; | ||
432 | } | ||
433 | |||
417 | mipi_dsi_set_drvdata(dsi, ctx); | 434 | mipi_dsi_set_drvdata(dsi, ctx); |
418 | 435 | ||
419 | ctx->dev = dev; | 436 | ctx->dev = dev; |
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c new file mode 100644 index 000000000000..77593533abcd --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c | |||
@@ -0,0 +1,448 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) STMicroelectronics SA 2017 | ||
4 | * | ||
5 | * Authors: Philippe Cornu <philippe.cornu@st.com> | ||
6 | * Yannick Fertre <yannick.fertre@st.com> | ||
7 | */ | ||
8 | |||
9 | #include <linux/backlight.h> | ||
10 | #include <linux/gpio/consumer.h> | ||
11 | #include <linux/regulator/consumer.h> | ||
12 | |||
13 | #include <video/mipi_display.h> | ||
14 | |||
15 | #include <drm/drmP.h> | ||
16 | #include <drm/drm_mipi_dsi.h> | ||
17 | #include <drm/drm_panel.h> | ||
18 | |||
19 | /*** Manufacturer Command Set ***/ | ||
20 | #define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */ | ||
21 | #define MCS_CMD1_UCS 0x00 /* User Command Set (UCS = CMD1) */ | ||
22 | #define MCS_CMD2_P0 0x01 /* Manufacture Command Set Page0 (CMD2 P0) */ | ||
23 | #define MCS_CMD2_P1 0x02 /* Manufacture Command Set Page1 (CMD2 P1) */ | ||
24 | #define MCS_CMD2_P2 0x03 /* Manufacture Command Set Page2 (CMD2 P2) */ | ||
25 | #define MCS_CMD2_P3 0x04 /* Manufacture Command Set Page3 (CMD2 P3) */ | ||
26 | |||
27 | /* CMD2 P0 commands (Display Options and Power) */ | ||
28 | #define MCS_STBCTR 0x12 /* TE1 Output Setting Zig-Zag Connection */ | ||
29 | #define MCS_SGOPCTR 0x16 /* Source Bias Current */ | ||
30 | #define MCS_SDCTR 0x1A /* Source Output Delay Time */ | ||
31 | #define MCS_INVCTR 0x1B /* Inversion Type */ | ||
32 | #define MCS_EXT_PWR_IC 0x24 /* External PWR IC Control */ | ||
33 | #define MCS_SETAVDD 0x27 /* PFM Control for AVDD Output */ | ||
34 | #define MCS_SETAVEE 0x29 /* PFM Control for AVEE Output */ | ||
35 | #define MCS_BT2CTR 0x2B /* DDVDL Charge Pump Control */ | ||
36 | #define MCS_BT3CTR 0x2F /* VGH Charge Pump Control */ | ||
37 | #define MCS_BT4CTR 0x34 /* VGL Charge Pump Control */ | ||
38 | #define MCS_VCMCTR 0x46 /* VCOM Output Level Control */ | ||
39 | #define MCS_SETVGN 0x52 /* VG M/S N Control */ | ||
40 | #define MCS_SETVGP 0x54 /* VG M/S P Control */ | ||
41 | #define MCS_SW_CTRL 0x5F /* Interface Control for PFM and MIPI */ | ||
42 | |||
43 | /* CMD2 P2 commands (GOA Timing Control) - no description in datasheet */ | ||
44 | #define GOA_VSTV1 0x00 | ||
45 | #define GOA_VSTV2 0x07 | ||
46 | #define GOA_VCLK1 0x0E | ||
47 | #define GOA_VCLK2 0x17 | ||
48 | #define GOA_VCLK_OPT1 0x20 | ||
49 | #define GOA_BICLK1 0x2A | ||
50 | #define GOA_BICLK2 0x37 | ||
51 | #define GOA_BICLK3 0x44 | ||
52 | #define GOA_BICLK4 0x4F | ||
53 | #define GOA_BICLK_OPT1 0x5B | ||
54 | #define GOA_BICLK_OPT2 0x60 | ||
55 | #define MCS_GOA_GPO1 0x6D | ||
56 | #define MCS_GOA_GPO2 0x71 | ||
57 | #define MCS_GOA_EQ 0x74 | ||
58 | #define MCS_GOA_CLK_GALLON 0x7C | ||
59 | #define MCS_GOA_FS_SEL0 0x7E | ||
60 | #define MCS_GOA_FS_SEL1 0x87 | ||
61 | #define MCS_GOA_FS_SEL2 0x91 | ||
62 | #define MCS_GOA_FS_SEL3 0x9B | ||
63 | #define MCS_GOA_BS_SEL0 0xAC | ||
64 | #define MCS_GOA_BS_SEL1 0xB5 | ||
65 | #define MCS_GOA_BS_SEL2 0xBF | ||
66 | #define MCS_GOA_BS_SEL3 0xC9 | ||
67 | #define MCS_GOA_BS_SEL4 0xD3 | ||
68 | |||
69 | /* CMD2 P3 commands (Gamma) */ | ||
70 | #define MCS_GAMMA_VP 0x60 /* Gamma VP1~VP16 */ | ||
71 | #define MCS_GAMMA_VN 0x70 /* Gamma VN1~VN16 */ | ||
72 | |||
73 | struct rm68200 { | ||
74 | struct device *dev; | ||
75 | struct drm_panel panel; | ||
76 | struct gpio_desc *reset_gpio; | ||
77 | struct regulator *supply; | ||
78 | struct backlight_device *backlight; | ||
79 | bool prepared; | ||
80 | bool enabled; | ||
81 | }; | ||
82 | |||
83 | static const struct drm_display_mode default_mode = { | ||
84 | .clock = 52582, | ||
85 | .hdisplay = 720, | ||
86 | .hsync_start = 720 + 38, | ||
87 | .hsync_end = 720 + 38 + 8, | ||
88 | .htotal = 720 + 38 + 8 + 38, | ||
89 | .vdisplay = 1280, | ||
90 | .vsync_start = 1280 + 12, | ||
91 | .vsync_end = 1280 + 12 + 4, | ||
92 | .vtotal = 1280 + 12 + 4 + 12, | ||
93 | .vrefresh = 50, | ||
94 | .flags = 0, | ||
95 | .width_mm = 68, | ||
96 | .height_mm = 122, | ||
97 | }; | ||
98 | |||
99 | static inline struct rm68200 *panel_to_rm68200(struct drm_panel *panel) | ||
100 | { | ||
101 | return container_of(panel, struct rm68200, panel); | ||
102 | } | ||
103 | |||
104 | static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data, | ||
105 | size_t len) | ||
106 | { | ||
107 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
108 | int err; | ||
109 | |||
110 | err = mipi_dsi_dcs_write_buffer(dsi, data, len); | ||
111 | if (err < 0) | ||
112 | DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n", | ||
113 | err); | ||
114 | } | ||
115 | |||
116 | static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value) | ||
117 | { | ||
118 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
119 | int err; | ||
120 | |||
121 | err = mipi_dsi_dcs_write(dsi, cmd, &value, 1); | ||
122 | if (err < 0) | ||
123 | DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err); | ||
124 | } | ||
125 | |||
126 | #define dcs_write_seq(ctx, seq...) \ | ||
127 | ({ \ | ||
128 | static const u8 d[] = { seq }; \ | ||
129 | \ | ||
130 | rm68200_dcs_write_buf(ctx, d, ARRAY_SIZE(d)); \ | ||
131 | }) | ||
132 | |||
133 | /* | ||
134 | * This panel is not able to auto-increment all cmd addresses so for some of | ||
135 | * them, we need to send them one by one... | ||
136 | */ | ||
137 | #define dcs_write_cmd_seq(ctx, cmd, seq...) \ | ||
138 | ({ \ | ||
139 | static const u8 d[] = { seq }; \ | ||
140 | unsigned int i; \ | ||
141 | \ | ||
142 | for (i = 0; i < ARRAY_SIZE(d) ; i++) \ | ||
143 | rm68200_dcs_write_cmd(ctx, cmd + i, d[i]); \ | ||
144 | }) | ||
145 | |||
146 | static void rm68200_init_sequence(struct rm68200 *ctx) | ||
147 | { | ||
148 | /* Enter CMD2 with page 0 */ | ||
149 | dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P0); | ||
150 | dcs_write_cmd_seq(ctx, MCS_EXT_PWR_IC, 0xC0, 0x53, 0x00); | ||
151 | dcs_write_seq(ctx, MCS_BT2CTR, 0xE5); | ||
152 | dcs_write_seq(ctx, MCS_SETAVDD, 0x0A); | ||
153 | dcs_write_seq(ctx, MCS_SETAVEE, 0x0A); | ||
154 | dcs_write_seq(ctx, MCS_SGOPCTR, 0x52); | ||
155 | dcs_write_seq(ctx, MCS_BT3CTR, 0x53); | ||
156 | dcs_write_seq(ctx, MCS_BT4CTR, 0x5A); | ||
157 | dcs_write_seq(ctx, MCS_INVCTR, 0x00); | ||
158 | dcs_write_seq(ctx, MCS_STBCTR, 0x0A); | ||
159 | dcs_write_seq(ctx, MCS_SDCTR, 0x06); | ||
160 | dcs_write_seq(ctx, MCS_VCMCTR, 0x56); | ||
161 | dcs_write_seq(ctx, MCS_SETVGN, 0xA0, 0x00); | ||
162 | dcs_write_seq(ctx, MCS_SETVGP, 0xA0, 0x00); | ||
163 | dcs_write_seq(ctx, MCS_SW_CTRL, 0x11); /* 2 data lanes, see doc */ | ||
164 | |||
165 | dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P2); | ||
166 | dcs_write_seq(ctx, GOA_VSTV1, 0x05); | ||
167 | dcs_write_seq(ctx, 0x02, 0x0B); | ||
168 | dcs_write_seq(ctx, 0x03, 0x0F); | ||
169 | dcs_write_seq(ctx, 0x04, 0x7D, 0x00, 0x50); | ||
170 | dcs_write_cmd_seq(ctx, GOA_VSTV2, 0x05, 0x16, 0x0D, 0x11, 0x7D, 0x00, | ||
171 | 0x50); | ||
172 | dcs_write_cmd_seq(ctx, GOA_VCLK1, 0x07, 0x08, 0x01, 0x02, 0x00, 0x7D, | ||
173 | 0x00, 0x85, 0x08); | ||
174 | dcs_write_cmd_seq(ctx, GOA_VCLK2, 0x03, 0x04, 0x05, 0x06, 0x00, 0x7D, | ||
175 | 0x00, 0x85, 0x08); | ||
176 | dcs_write_seq(ctx, GOA_VCLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
177 | 0x00, 0x00, 0x00, 0x00); | ||
178 | dcs_write_cmd_seq(ctx, GOA_BICLK1, 0x07, 0x08); | ||
179 | dcs_write_seq(ctx, 0x2D, 0x01); | ||
180 | dcs_write_seq(ctx, 0x2F, 0x02, 0x00, 0x40, 0x05, 0x08, 0x54, 0x7D, | ||
181 | 0x00); | ||
182 | dcs_write_cmd_seq(ctx, GOA_BICLK2, 0x03, 0x04, 0x05, 0x06, 0x00); | ||
183 | dcs_write_seq(ctx, 0x3D, 0x40); | ||
184 | dcs_write_seq(ctx, 0x3F, 0x05, 0x08, 0x54, 0x7D, 0x00); | ||
185 | dcs_write_seq(ctx, GOA_BICLK3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
186 | 0x00, 0x00, 0x00, 0x00, 0x00); | ||
187 | dcs_write_seq(ctx, GOA_BICLK4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
188 | 0x00, 0x00); | ||
189 | dcs_write_seq(ctx, 0x58, 0x00, 0x00, 0x00); | ||
190 | dcs_write_seq(ctx, GOA_BICLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00); | ||
191 | dcs_write_seq(ctx, GOA_BICLK_OPT2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); | ||
193 | dcs_write_seq(ctx, MCS_GOA_GPO1, 0x00, 0x00, 0x00, 0x00); | ||
194 | dcs_write_seq(ctx, MCS_GOA_GPO2, 0x00, 0x20, 0x00); | ||
195 | dcs_write_seq(ctx, MCS_GOA_EQ, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
196 | 0x00, 0x00); | ||
197 | dcs_write_seq(ctx, MCS_GOA_CLK_GALLON, 0x00, 0x00); | ||
198 | dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL0, 0xBF, 0x02, 0x06, 0x14, 0x10, | ||
199 | 0x16, 0x12, 0x08, 0x3F); | ||
200 | dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0C, | ||
201 | 0x0A, 0x0E, 0x3F, 0x3F, 0x00); | ||
202 | dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL2, 0x04, 0x3F, 0x3F, 0x3F, 0x3F, | ||
203 | 0x05, 0x01, 0x3F, 0x3F, 0x0F); | ||
204 | dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL3, 0x0B, 0x0D, 0x3F, 0x3F, 0x3F, | ||
205 | 0x3F); | ||
206 | dcs_write_cmd_seq(ctx, 0xA2, 0x3F, 0x09, 0x13, 0x17, 0x11, 0x15); | ||
207 | dcs_write_cmd_seq(ctx, 0xA9, 0x07, 0x03, 0x3F); | ||
208 | dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL0, 0x3F, 0x05, 0x01, 0x17, 0x13, | ||
209 | 0x15, 0x11, 0x0F, 0x3F); | ||
210 | dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0B, | ||
211 | 0x0D, 0x09, 0x3F, 0x3F, 0x07); | ||
212 | dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL2, 0x03, 0x3F, 0x3F, 0x3F, 0x3F, | ||
213 | 0x02, 0x06, 0x3F, 0x3F, 0x08); | ||
214 | dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL3, 0x0C, 0x0A, 0x3F, 0x3F, 0x3F, | ||
215 | 0x3F, 0x3F, 0x0E, 0x10, 0x14); | ||
216 | dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL4, 0x12, 0x16, 0x00, 0x04, 0x3F); | ||
217 | dcs_write_seq(ctx, 0xDC, 0x02); | ||
218 | dcs_write_seq(ctx, 0xDE, 0x12); | ||
219 | |||
220 | dcs_write_seq(ctx, MCS_CMD_MODE_SW, 0x0E); /* No documentation */ | ||
221 | dcs_write_seq(ctx, 0x01, 0x75); | ||
222 | |||
223 | dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P3); | ||
224 | dcs_write_cmd_seq(ctx, MCS_GAMMA_VP, 0x00, 0x0C, 0x12, 0x0E, 0x06, | ||
225 | 0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F, | ||
226 | 0x12, 0x0C, 0x00); | ||
227 | dcs_write_cmd_seq(ctx, MCS_GAMMA_VN, 0x00, 0x0C, 0x12, 0x0E, 0x06, | ||
228 | 0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F, | ||
229 | 0x12, 0x0C, 0x00); | ||
230 | |||
231 | /* Exit CMD2 */ | ||
232 | dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD1_UCS); | ||
233 | } | ||
234 | |||
235 | static int rm68200_disable(struct drm_panel *panel) | ||
236 | { | ||
237 | struct rm68200 *ctx = panel_to_rm68200(panel); | ||
238 | |||
239 | if (!ctx->enabled) | ||
240 | return 0; | ||
241 | |||
242 | backlight_disable(ctx->backlight); | ||
243 | |||
244 | ctx->enabled = false; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int rm68200_unprepare(struct drm_panel *panel) | ||
250 | { | ||
251 | struct rm68200 *ctx = panel_to_rm68200(panel); | ||
252 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
253 | int ret; | ||
254 | |||
255 | if (!ctx->prepared) | ||
256 | return 0; | ||
257 | |||
258 | ret = mipi_dsi_dcs_set_display_off(dsi); | ||
259 | if (ret) | ||
260 | DRM_WARN("failed to set display off: %d\n", ret); | ||
261 | |||
262 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | ||
263 | if (ret) | ||
264 | DRM_WARN("failed to enter sleep mode: %d\n", ret); | ||
265 | |||
266 | msleep(120); | ||
267 | |||
268 | if (ctx->reset_gpio) { | ||
269 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); | ||
270 | msleep(20); | ||
271 | } | ||
272 | |||
273 | regulator_disable(ctx->supply); | ||
274 | |||
275 | ctx->prepared = false; | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int rm68200_prepare(struct drm_panel *panel) | ||
281 | { | ||
282 | struct rm68200 *ctx = panel_to_rm68200(panel); | ||
283 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||
284 | int ret; | ||
285 | |||
286 | if (ctx->prepared) | ||
287 | return 0; | ||
288 | |||
289 | ret = regulator_enable(ctx->supply); | ||
290 | if (ret < 0) { | ||
291 | DRM_ERROR("failed to enable supply: %d\n", ret); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | if (ctx->reset_gpio) { | ||
296 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); | ||
297 | msleep(20); | ||
298 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); | ||
299 | msleep(100); | ||
300 | } | ||
301 | |||
302 | rm68200_init_sequence(ctx); | ||
303 | |||
304 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | ||
305 | if (ret) | ||
306 | return ret; | ||
307 | |||
308 | msleep(125); | ||
309 | |||
310 | ret = mipi_dsi_dcs_set_display_on(dsi); | ||
311 | if (ret) | ||
312 | return ret; | ||
313 | |||
314 | msleep(20); | ||
315 | |||
316 | ctx->prepared = true; | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int rm68200_enable(struct drm_panel *panel) | ||
322 | { | ||
323 | struct rm68200 *ctx = panel_to_rm68200(panel); | ||
324 | |||
325 | if (ctx->enabled) | ||
326 | return 0; | ||
327 | |||
328 | backlight_enable(ctx->backlight); | ||
329 | |||
330 | ctx->enabled = true; | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int rm68200_get_modes(struct drm_panel *panel) | ||
336 | { | ||
337 | struct drm_display_mode *mode; | ||
338 | |||
339 | mode = drm_mode_duplicate(panel->drm, &default_mode); | ||
340 | if (!mode) { | ||
341 | DRM_ERROR("failed to add mode %ux%ux@%u\n", | ||
342 | default_mode.hdisplay, default_mode.vdisplay, | ||
343 | default_mode.vrefresh); | ||
344 | return -ENOMEM; | ||
345 | } | ||
346 | |||
347 | drm_mode_set_name(mode); | ||
348 | |||
349 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||
350 | drm_mode_probed_add(panel->connector, mode); | ||
351 | |||
352 | panel->connector->display_info.width_mm = mode->width_mm; | ||
353 | panel->connector->display_info.height_mm = mode->height_mm; | ||
354 | |||
355 | return 1; | ||
356 | } | ||
357 | |||
358 | static const struct drm_panel_funcs rm68200_drm_funcs = { | ||
359 | .disable = rm68200_disable, | ||
360 | .unprepare = rm68200_unprepare, | ||
361 | .prepare = rm68200_prepare, | ||
362 | .enable = rm68200_enable, | ||
363 | .get_modes = rm68200_get_modes, | ||
364 | }; | ||
365 | |||
366 | static int rm68200_probe(struct mipi_dsi_device *dsi) | ||
367 | { | ||
368 | struct device *dev = &dsi->dev; | ||
369 | struct rm68200 *ctx; | ||
370 | int ret; | ||
371 | |||
372 | ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | ||
373 | if (!ctx) | ||
374 | return -ENOMEM; | ||
375 | |||
376 | ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | ||
377 | if (IS_ERR(ctx->reset_gpio)) { | ||
378 | ret = PTR_ERR(ctx->reset_gpio); | ||
379 | dev_err(dev, "cannot get reset GPIO: %d\n", ret); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | ctx->supply = devm_regulator_get(dev, "power"); | ||
384 | if (IS_ERR(ctx->supply)) { | ||
385 | ret = PTR_ERR(ctx->supply); | ||
386 | dev_err(dev, "cannot get regulator: %d\n", ret); | ||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | ctx->backlight = devm_of_find_backlight(dev); | ||
391 | if (IS_ERR(ctx->backlight)) | ||
392 | return PTR_ERR(ctx->backlight); | ||
393 | |||
394 | mipi_dsi_set_drvdata(dsi, ctx); | ||
395 | |||
396 | ctx->dev = dev; | ||
397 | |||
398 | dsi->lanes = 2; | ||
399 | dsi->format = MIPI_DSI_FMT_RGB888; | ||
400 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | | ||
401 | MIPI_DSI_MODE_LPM; | ||
402 | |||
403 | drm_panel_init(&ctx->panel); | ||
404 | ctx->panel.dev = dev; | ||
405 | ctx->panel.funcs = &rm68200_drm_funcs; | ||
406 | |||
407 | drm_panel_add(&ctx->panel); | ||
408 | |||
409 | ret = mipi_dsi_attach(dsi); | ||
410 | if (ret < 0) { | ||
411 | dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret); | ||
412 | drm_panel_remove(&ctx->panel); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int rm68200_remove(struct mipi_dsi_device *dsi) | ||
420 | { | ||
421 | struct rm68200 *ctx = mipi_dsi_get_drvdata(dsi); | ||
422 | |||
423 | mipi_dsi_detach(dsi); | ||
424 | drm_panel_remove(&ctx->panel); | ||
425 | |||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static const struct of_device_id raydium_rm68200_of_match[] = { | ||
430 | { .compatible = "raydium,rm68200" }, | ||
431 | { } | ||
432 | }; | ||
433 | MODULE_DEVICE_TABLE(of, raydium_rm68200_of_match); | ||
434 | |||
435 | static struct mipi_dsi_driver raydium_rm68200_driver = { | ||
436 | .probe = rm68200_probe, | ||
437 | .remove = rm68200_remove, | ||
438 | .driver = { | ||
439 | .name = "panel-raydium-rm68200", | ||
440 | .of_match_table = raydium_rm68200_of_match, | ||
441 | }, | ||
442 | }; | ||
443 | module_mipi_dsi_driver(raydium_rm68200_driver); | ||
444 | |||
445 | MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>"); | ||
446 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | ||
447 | MODULE_DESCRIPTION("DRM Driver for Raydium RM68200 MIPI DSI panel"); | ||
448 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5591984a392b..cbf1ab404ee7 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c | |||
@@ -581,6 +581,29 @@ static const struct panel_desc auo_b133htn01 = { | |||
581 | }, | 581 | }, |
582 | }; | 582 | }; |
583 | 583 | ||
584 | static const struct drm_display_mode auo_g104sn02_mode = { | ||
585 | .clock = 40000, | ||
586 | .hdisplay = 800, | ||
587 | .hsync_start = 800 + 40, | ||
588 | .hsync_end = 800 + 40 + 216, | ||
589 | .htotal = 800 + 40 + 216 + 128, | ||
590 | .vdisplay = 600, | ||
591 | .vsync_start = 600 + 10, | ||
592 | .vsync_end = 600 + 10 + 35, | ||
593 | .vtotal = 600 + 10 + 35 + 2, | ||
594 | .vrefresh = 60, | ||
595 | }; | ||
596 | |||
597 | static const struct panel_desc auo_g104sn02 = { | ||
598 | .modes = &auo_g104sn02_mode, | ||
599 | .num_modes = 1, | ||
600 | .bpc = 8, | ||
601 | .size = { | ||
602 | .width = 211, | ||
603 | .height = 158, | ||
604 | }, | ||
605 | }; | ||
606 | |||
584 | static const struct display_timing auo_g133han01_timings = { | 607 | static const struct display_timing auo_g133han01_timings = { |
585 | .pixelclock = { 134000000, 141200000, 149000000 }, | 608 | .pixelclock = { 134000000, 141200000, 149000000 }, |
586 | .hactive = { 1920, 1920, 1920 }, | 609 | .hactive = { 1920, 1920, 1920 }, |
@@ -1217,6 +1240,30 @@ static const struct panel_desc innolux_zj070na_01p = { | |||
1217 | }, | 1240 | }, |
1218 | }; | 1241 | }; |
1219 | 1242 | ||
1243 | static const struct display_timing koe_tx31d200vm0baa_timing = { | ||
1244 | .pixelclock = { 39600000, 43200000, 48000000 }, | ||
1245 | .hactive = { 1280, 1280, 1280 }, | ||
1246 | .hfront_porch = { 16, 36, 56 }, | ||
1247 | .hback_porch = { 16, 36, 56 }, | ||
1248 | .hsync_len = { 8, 8, 8 }, | ||
1249 | .vactive = { 480, 480, 480 }, | ||
1250 | .vfront_porch = { 6, 21, 33.5 }, | ||
1251 | .vback_porch = { 6, 21, 33.5 }, | ||
1252 | .vsync_len = { 8, 8, 8 }, | ||
1253 | .flags = DISPLAY_FLAGS_DE_HIGH, | ||
1254 | }; | ||
1255 | |||
1256 | static const struct panel_desc koe_tx31d200vm0baa = { | ||
1257 | .timings = &koe_tx31d200vm0baa_timing, | ||
1258 | .num_timings = 1, | ||
1259 | .bpc = 6, | ||
1260 | .size = { | ||
1261 | .width = 292, | ||
1262 | .height = 109, | ||
1263 | }, | ||
1264 | .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, | ||
1265 | }; | ||
1266 | |||
1220 | static const struct display_timing kyo_tcg121xglp_timing = { | 1267 | static const struct display_timing kyo_tcg121xglp_timing = { |
1221 | .pixelclock = { 52000000, 65000000, 71000000 }, | 1268 | .pixelclock = { 52000000, 65000000, 71000000 }, |
1222 | .hactive = { 1024, 1024, 1024 }, | 1269 | .hactive = { 1024, 1024, 1024 }, |
@@ -1597,7 +1644,7 @@ static const struct panel_desc ontat_yx700wv03 = { | |||
1597 | .width = 154, | 1644 | .width = 154, |
1598 | .height = 83, | 1645 | .height = 83, |
1599 | }, | 1646 | }, |
1600 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | 1647 | .bus_format = MEDIA_BUS_FMT_RGB666_1X18, |
1601 | }; | 1648 | }; |
1602 | 1649 | ||
1603 | static const struct drm_display_mode ortustech_com43h4m85ulc_mode = { | 1650 | static const struct drm_display_mode ortustech_com43h4m85ulc_mode = { |
@@ -1741,23 +1788,22 @@ static const struct panel_desc sharp_lq101k1ly04 = { | |||
1741 | .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, | 1788 | .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, |
1742 | }; | 1789 | }; |
1743 | 1790 | ||
1744 | static const struct drm_display_mode sharp_lq123p1jx31_mode = { | 1791 | static const struct display_timing sharp_lq123p1jx31_timing = { |
1745 | .clock = 252750, | 1792 | .pixelclock = { 252750000, 252750000, 266604720 }, |
1746 | .hdisplay = 2400, | 1793 | .hactive = { 2400, 2400, 2400 }, |
1747 | .hsync_start = 2400 + 48, | 1794 | .hfront_porch = { 48, 48, 48 }, |
1748 | .hsync_end = 2400 + 48 + 32, | 1795 | .hback_porch = { 80, 80, 84 }, |
1749 | .htotal = 2400 + 48 + 32 + 80, | 1796 | .hsync_len = { 32, 32, 32 }, |
1750 | .vdisplay = 1600, | 1797 | .vactive = { 1600, 1600, 1600 }, |
1751 | .vsync_start = 1600 + 3, | 1798 | .vfront_porch = { 3, 3, 3 }, |
1752 | .vsync_end = 1600 + 3 + 10, | 1799 | .vback_porch = { 33, 33, 120 }, |
1753 | .vtotal = 1600 + 3 + 10 + 33, | 1800 | .vsync_len = { 10, 10, 10 }, |
1754 | .vrefresh = 60, | 1801 | .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW, |
1755 | .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, | ||
1756 | }; | 1802 | }; |
1757 | 1803 | ||
1758 | static const struct panel_desc sharp_lq123p1jx31 = { | 1804 | static const struct panel_desc sharp_lq123p1jx31 = { |
1759 | .modes = &sharp_lq123p1jx31_mode, | 1805 | .timings = &sharp_lq123p1jx31_timing, |
1760 | .num_modes = 1, | 1806 | .num_timings = 1, |
1761 | .bpc = 8, | 1807 | .bpc = 8, |
1762 | .size = { | 1808 | .size = { |
1763 | .width = 259, | 1809 | .width = 259, |
@@ -2049,6 +2095,9 @@ static const struct of_device_id platform_of_match[] = { | |||
2049 | .compatible = "auo,b133xtn01", | 2095 | .compatible = "auo,b133xtn01", |
2050 | .data = &auo_b133xtn01, | 2096 | .data = &auo_b133xtn01, |
2051 | }, { | 2097 | }, { |
2098 | .compatible = "auo,g104sn02", | ||
2099 | .data = &auo_g104sn02, | ||
2100 | }, { | ||
2052 | .compatible = "auo,g133han01", | 2101 | .compatible = "auo,g133han01", |
2053 | .data = &auo_g133han01, | 2102 | .data = &auo_g133han01, |
2054 | }, { | 2103 | }, { |
@@ -2124,6 +2173,9 @@ static const struct of_device_id platform_of_match[] = { | |||
2124 | .compatible = "innolux,zj070na-01p", | 2173 | .compatible = "innolux,zj070na-01p", |
2125 | .data = &innolux_zj070na_01p, | 2174 | .data = &innolux_zj070na_01p, |
2126 | }, { | 2175 | }, { |
2176 | .compatible = "koe,tx31d200vm0baa", | ||
2177 | .data = &koe_tx31d200vm0baa, | ||
2178 | }, { | ||
2127 | .compatible = "kyo,tcg121xglp", | 2179 | .compatible = "kyo,tcg121xglp", |
2128 | .data = &kyo_tcg121xglp, | 2180 | .data = &kyo_tcg121xglp, |
2129 | }, { | 2181 | }, { |
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 9a9214ae0fb5..ecb35ed0eac8 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c | |||
@@ -309,7 +309,7 @@ void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb) | |||
309 | struct qxl_bo *bo = gem_to_qxl_bo(qxl_fb->obj); | 309 | struct qxl_bo *bo = gem_to_qxl_bo(qxl_fb->obj); |
310 | 310 | ||
311 | WARN_ON(bo->shadow); | 311 | WARN_ON(bo->shadow); |
312 | drm_gem_object_unreference_unlocked(qxl_fb->obj); | 312 | drm_gem_object_put_unlocked(qxl_fb->obj); |
313 | drm_framebuffer_cleanup(fb); | 313 | drm_framebuffer_cleanup(fb); |
314 | kfree(qxl_fb); | 314 | kfree(qxl_fb); |
315 | } | 315 | } |
@@ -1215,7 +1215,7 @@ qxl_user_framebuffer_create(struct drm_device *dev, | |||
1215 | ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj, &qxl_fb_funcs); | 1215 | ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj, &qxl_fb_funcs); |
1216 | if (ret) { | 1216 | if (ret) { |
1217 | kfree(qxl_fb); | 1217 | kfree(qxl_fb); |
1218 | drm_gem_object_unreference_unlocked(obj); | 1218 | drm_gem_object_put_unlocked(obj); |
1219 | return NULL; | 1219 | return NULL; |
1220 | } | 1220 | } |
1221 | 1221 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_dumb.c b/drivers/gpu/drm/qxl/qxl_dumb.c index 11085ab01374..c666b89eed5d 100644 --- a/drivers/gpu/drm/qxl/qxl_dumb.c +++ b/drivers/gpu/drm/qxl/qxl_dumb.c | |||
@@ -82,6 +82,6 @@ int qxl_mode_dumb_mmap(struct drm_file *file_priv, | |||
82 | return -ENOENT; | 82 | return -ENOENT; |
83 | qobj = gem_to_qxl_bo(gobj); | 83 | qobj = gem_to_qxl_bo(gobj); |
84 | *offset_p = qxl_bo_mmap_offset(qobj); | 84 | *offset_p = qxl_bo_mmap_offset(qobj); |
85 | drm_gem_object_unreference_unlocked(gobj); | 85 | drm_gem_object_put_unlocked(gobj); |
86 | return 0; | 86 | return 0; |
87 | } | 87 | } |
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 23af3e352673..338891401f35 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c | |||
@@ -95,7 +95,7 @@ static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj) | |||
95 | qxl_bo_kunmap(qbo); | 95 | qxl_bo_kunmap(qbo); |
96 | qxl_bo_unpin(qbo); | 96 | qxl_bo_unpin(qbo); |
97 | 97 | ||
98 | drm_gem_object_unreference_unlocked(gobj); | 98 | drm_gem_object_put_unlocked(gobj); |
99 | } | 99 | } |
100 | 100 | ||
101 | int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, | 101 | int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, |
@@ -316,11 +316,11 @@ out_unref: | |||
316 | qxl_bo_unpin(qbo); | 316 | qxl_bo_unpin(qbo); |
317 | } | 317 | } |
318 | if (fb && ret) { | 318 | if (fb && ret) { |
319 | drm_gem_object_unreference_unlocked(gobj); | 319 | drm_gem_object_put_unlocked(gobj); |
320 | drm_framebuffer_cleanup(fb); | 320 | drm_framebuffer_cleanup(fb); |
321 | kfree(fb); | 321 | kfree(fb); |
322 | } | 322 | } |
323 | drm_gem_object_unreference_unlocked(gobj); | 323 | drm_gem_object_put_unlocked(gobj); |
324 | return ret; | 324 | return ret; |
325 | } | 325 | } |
326 | 326 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_gem.c b/drivers/gpu/drm/qxl/qxl_gem.c index 85f546719adb..f5c1e7872e92 100644 --- a/drivers/gpu/drm/qxl/qxl_gem.c +++ b/drivers/gpu/drm/qxl/qxl_gem.c | |||
@@ -98,7 +98,7 @@ int qxl_gem_object_create_with_handle(struct qxl_device *qdev, | |||
98 | return r; | 98 | return r; |
99 | /* drop reference from allocate - handle holds it now */ | 99 | /* drop reference from allocate - handle holds it now */ |
100 | *qobj = gem_to_qxl_bo(gobj); | 100 | *qobj = gem_to_qxl_bo(gobj); |
101 | drm_gem_object_unreference_unlocked(gobj); | 101 | drm_gem_object_put_unlocked(gobj); |
102 | return 0; | 102 | return 0; |
103 | } | 103 | } |
104 | 104 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index e8c0b1037230..e238a1a2eca1 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c | |||
@@ -121,7 +121,7 @@ static int qxlhw_handle_to_bo(struct drm_file *file_priv, uint64_t handle, | |||
121 | qobj = gem_to_qxl_bo(gobj); | 121 | qobj = gem_to_qxl_bo(gobj); |
122 | 122 | ||
123 | ret = qxl_release_list_add(release, qobj); | 123 | ret = qxl_release_list_add(release, qobj); |
124 | drm_gem_object_unreference_unlocked(gobj); | 124 | drm_gem_object_put_unlocked(gobj); |
125 | if (ret) | 125 | if (ret) |
126 | return ret; | 126 | return ret; |
127 | 127 | ||
@@ -343,7 +343,7 @@ out2: | |||
343 | qxl_bo_unreserve(qobj); | 343 | qxl_bo_unreserve(qobj); |
344 | 344 | ||
345 | out: | 345 | out: |
346 | drm_gem_object_unreference_unlocked(gobj); | 346 | drm_gem_object_put_unlocked(gobj); |
347 | return ret; | 347 | return ret; |
348 | } | 348 | } |
349 | 349 | ||
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index af62824ed4cc..6a30196e9d6c 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c | |||
@@ -211,13 +211,13 @@ void qxl_bo_unref(struct qxl_bo **bo) | |||
211 | if ((*bo) == NULL) | 211 | if ((*bo) == NULL) |
212 | return; | 212 | return; |
213 | 213 | ||
214 | drm_gem_object_unreference_unlocked(&(*bo)->gem_base); | 214 | drm_gem_object_put_unlocked(&(*bo)->gem_base); |
215 | *bo = NULL; | 215 | *bo = NULL; |
216 | } | 216 | } |
217 | 217 | ||
218 | struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo) | 218 | struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo) |
219 | { | 219 | { |
220 | drm_gem_object_reference(&bo->gem_base); | 220 | drm_gem_object_get(&bo->gem_base); |
221 | return bo; | 221 | return bo; |
222 | } | 222 | } |
223 | 223 | ||
@@ -318,7 +318,7 @@ void qxl_bo_force_delete(struct qxl_device *qdev) | |||
318 | list_del_init(&bo->list); | 318 | list_del_init(&bo->list); |
319 | mutex_unlock(&qdev->gem.mutex); | 319 | mutex_unlock(&qdev->gem.mutex); |
320 | /* this should unref the ttm bo */ | 320 | /* this should unref the ttm bo */ |
321 | drm_gem_object_unreference_unlocked(&bo->gem_base); | 321 | drm_gem_object_put_unlocked(&bo->gem_base); |
322 | } | 322 | } |
323 | } | 323 | } |
324 | 324 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 31dd04f6baa1..b28288a781ef 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
@@ -415,7 +415,6 @@ static int radeon_pmops_runtime_suspend(struct device *dev) | |||
415 | 415 | ||
416 | drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | 416 | drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; |
417 | drm_kms_helper_poll_disable(drm_dev); | 417 | drm_kms_helper_poll_disable(drm_dev); |
418 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); | ||
419 | 418 | ||
420 | ret = radeon_suspend_kms(drm_dev, false, false, false); | 419 | ret = radeon_suspend_kms(drm_dev, false, false, false); |
421 | pci_save_state(pdev); | 420 | pci_save_state(pdev); |
@@ -452,7 +451,6 @@ static int radeon_pmops_runtime_resume(struct device *dev) | |||
452 | 451 | ||
453 | ret = radeon_resume_kms(drm_dev, false, false); | 452 | ret = radeon_resume_kms(drm_dev, false, false); |
454 | drm_kms_helper_poll_enable(drm_dev); | 453 | drm_kms_helper_poll_enable(drm_dev); |
455 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); | ||
456 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; | 454 | drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; |
457 | return 0; | 455 | return 0; |
458 | } | 456 | } |
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 7d76ff47028d..3e8bf79bea58 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | |||
@@ -71,10 +71,6 @@ struct rockchip_dp_device { | |||
71 | struct regmap *grf; | 71 | struct regmap *grf; |
72 | struct reset_control *rst; | 72 | struct reset_control *rst; |
73 | 73 | ||
74 | struct work_struct psr_work; | ||
75 | struct mutex psr_lock; | ||
76 | unsigned int psr_state; | ||
77 | |||
78 | const struct rockchip_dp_chip_data *data; | 74 | const struct rockchip_dp_chip_data *data; |
79 | 75 | ||
80 | struct analogix_dp_device *adp; | 76 | struct analogix_dp_device *adp; |
@@ -84,28 +80,13 @@ struct rockchip_dp_device { | |||
84 | static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) | 80 | static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled) |
85 | { | 81 | { |
86 | struct rockchip_dp_device *dp = to_dp(encoder); | 82 | struct rockchip_dp_device *dp = to_dp(encoder); |
83 | int ret; | ||
87 | 84 | ||
88 | if (!analogix_dp_psr_supported(dp->adp)) | 85 | if (!analogix_dp_psr_enabled(dp->adp)) |
89 | return; | 86 | return; |
90 | 87 | ||
91 | DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); | 88 | DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit"); |
92 | 89 | ||
93 | mutex_lock(&dp->psr_lock); | ||
94 | if (enabled) | ||
95 | dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE; | ||
96 | else | ||
97 | dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; | ||
98 | |||
99 | schedule_work(&dp->psr_work); | ||
100 | mutex_unlock(&dp->psr_lock); | ||
101 | } | ||
102 | |||
103 | static void analogix_dp_psr_work(struct work_struct *work) | ||
104 | { | ||
105 | struct rockchip_dp_device *dp = | ||
106 | container_of(work, typeof(*dp), psr_work); | ||
107 | int ret; | ||
108 | |||
109 | ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, | 90 | ret = rockchip_drm_wait_vact_end(dp->encoder.crtc, |
110 | PSR_WAIT_LINE_FLAG_TIMEOUT_MS); | 91 | PSR_WAIT_LINE_FLAG_TIMEOUT_MS); |
111 | if (ret) { | 92 | if (ret) { |
@@ -113,12 +94,10 @@ static void analogix_dp_psr_work(struct work_struct *work) | |||
113 | return; | 94 | return; |
114 | } | 95 | } |
115 | 96 | ||
116 | mutex_lock(&dp->psr_lock); | 97 | if (enabled) |
117 | if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE) | ||
118 | analogix_dp_enable_psr(dp->adp); | 98 | analogix_dp_enable_psr(dp->adp); |
119 | else | 99 | else |
120 | analogix_dp_disable_psr(dp->adp); | 100 | analogix_dp_disable_psr(dp->adp); |
121 | mutex_unlock(&dp->psr_lock); | ||
122 | } | 101 | } |
123 | 102 | ||
124 | static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) | 103 | static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) |
@@ -135,8 +114,6 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) | |||
135 | struct rockchip_dp_device *dp = to_dp(plat_data); | 114 | struct rockchip_dp_device *dp = to_dp(plat_data); |
136 | int ret; | 115 | int ret; |
137 | 116 | ||
138 | cancel_work_sync(&dp->psr_work); | ||
139 | |||
140 | ret = clk_prepare_enable(dp->pclk); | 117 | ret = clk_prepare_enable(dp->pclk); |
141 | if (ret < 0) { | 118 | if (ret < 0) { |
142 | DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); | 119 | DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret); |
@@ -355,10 +332,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, | |||
355 | dp->plat_data.power_off = rockchip_dp_powerdown; | 332 | dp->plat_data.power_off = rockchip_dp_powerdown; |
356 | dp->plat_data.get_modes = rockchip_dp_get_modes; | 333 | dp->plat_data.get_modes = rockchip_dp_get_modes; |
357 | 334 | ||
358 | mutex_init(&dp->psr_lock); | ||
359 | dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE; | ||
360 | INIT_WORK(&dp->psr_work, analogix_dp_psr_work); | ||
361 | |||
362 | ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); | 335 | ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set); |
363 | if (ret < 0) | 336 | if (ret < 0) |
364 | goto err_cleanup_encoder; | 337 | goto err_cleanup_encoder; |
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index ec999d9f15f6..c6fbdcd87c16 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c | |||
@@ -43,8 +43,6 @@ | |||
43 | #define GRF_SOC_CON9 0x6224 | 43 | #define GRF_SOC_CON9 0x6224 |
44 | #define DP_SEL_VOP_LIT BIT(12) | 44 | #define DP_SEL_VOP_LIT BIT(12) |
45 | #define GRF_SOC_CON26 0x6268 | 45 | #define GRF_SOC_CON26 0x6268 |
46 | #define UPHY_SEL_BIT 3 | ||
47 | #define UPHY_SEL_MASK BIT(19) | ||
48 | #define DPTX_HPD_SEL (3 << 12) | 46 | #define DPTX_HPD_SEL (3 << 12) |
49 | #define DPTX_HPD_DEL (2 << 12) | 47 | #define DPTX_HPD_DEL (2 << 12) |
50 | #define DPTX_HPD_SEL_MASK (3 << 28) | 48 | #define DPTX_HPD_SEL_MASK (3 << 28) |
@@ -394,11 +392,6 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) | |||
394 | union extcon_property_value property; | 392 | union extcon_property_value property; |
395 | int ret; | 393 | int ret; |
396 | 394 | ||
397 | ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, | ||
398 | (port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK); | ||
399 | if (ret) | ||
400 | return ret; | ||
401 | |||
402 | if (!port->phy_enabled) { | 395 | if (!port->phy_enabled) { |
403 | ret = phy_power_on(port->phy); | 396 | ret = phy_power_on(port->phy); |
404 | if (ret) { | 397 | if (ret) { |
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 158e79e5062e..53d4afe15278 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c | |||
@@ -117,6 +117,8 @@ struct vop { | |||
117 | spinlock_t reg_lock; | 117 | spinlock_t reg_lock; |
118 | /* lock vop irq reg */ | 118 | /* lock vop irq reg */ |
119 | spinlock_t irq_lock; | 119 | spinlock_t irq_lock; |
120 | /* protects crtc enable/disable */ | ||
121 | struct mutex vop_lock; | ||
120 | 122 | ||
121 | unsigned int irq; | 123 | unsigned int irq; |
122 | 124 | ||
@@ -517,7 +519,10 @@ static int vop_enable(struct drm_crtc *crtc) | |||
517 | goto err_disable_aclk; | 519 | goto err_disable_aclk; |
518 | } | 520 | } |
519 | 521 | ||
520 | memcpy(vop->regs, vop->regsbak, vop->len); | 522 | spin_lock(&vop->reg_lock); |
523 | for (i = 0; i < vop->len; i += 4) | ||
524 | writel_relaxed(vop->regsbak[i / 4], vop->regs + i); | ||
525 | |||
521 | /* | 526 | /* |
522 | * We need to make sure that all windows are disabled before we | 527 | * We need to make sure that all windows are disabled before we |
523 | * enable the crtc. Otherwise we might try to scan from a destroyed | 528 | * enable the crtc. Otherwise we might try to scan from a destroyed |
@@ -527,10 +532,9 @@ static int vop_enable(struct drm_crtc *crtc) | |||
527 | struct vop_win *vop_win = &vop->win[i]; | 532 | struct vop_win *vop_win = &vop->win[i]; |
528 | const struct vop_win_data *win = vop_win->data; | 533 | const struct vop_win_data *win = vop_win->data; |
529 | 534 | ||
530 | spin_lock(&vop->reg_lock); | ||
531 | VOP_WIN_SET(vop, win, enable, 0); | 535 | VOP_WIN_SET(vop, win, enable, 0); |
532 | spin_unlock(&vop->reg_lock); | ||
533 | } | 536 | } |
537 | spin_unlock(&vop->reg_lock); | ||
534 | 538 | ||
535 | vop_cfg_done(vop); | 539 | vop_cfg_done(vop); |
536 | 540 | ||
@@ -569,6 +573,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, | |||
569 | 573 | ||
570 | WARN_ON(vop->event); | 574 | WARN_ON(vop->event); |
571 | 575 | ||
576 | mutex_lock(&vop->vop_lock); | ||
572 | drm_crtc_vblank_off(crtc); | 577 | drm_crtc_vblank_off(crtc); |
573 | 578 | ||
574 | /* | 579 | /* |
@@ -604,6 +609,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, | |||
604 | clk_disable(vop->aclk); | 609 | clk_disable(vop->aclk); |
605 | clk_disable(vop->hclk); | 610 | clk_disable(vop->hclk); |
606 | pm_runtime_put(vop->dev); | 611 | pm_runtime_put(vop->dev); |
612 | mutex_unlock(&vop->vop_lock); | ||
607 | 613 | ||
608 | if (crtc->state->event && !crtc->state->active) { | 614 | if (crtc->state->event && !crtc->state->active) { |
609 | spin_lock_irq(&crtc->dev->event_lock); | 615 | spin_lock_irq(&crtc->dev->event_lock); |
@@ -868,10 +874,13 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, | |||
868 | uint32_t pin_pol, val; | 874 | uint32_t pin_pol, val; |
869 | int ret; | 875 | int ret; |
870 | 876 | ||
877 | mutex_lock(&vop->vop_lock); | ||
878 | |||
871 | WARN_ON(vop->event); | 879 | WARN_ON(vop->event); |
872 | 880 | ||
873 | ret = vop_enable(crtc); | 881 | ret = vop_enable(crtc); |
874 | if (ret) { | 882 | if (ret) { |
883 | mutex_unlock(&vop->vop_lock); | ||
875 | DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); | 884 | DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret); |
876 | return; | 885 | return; |
877 | } | 886 | } |
@@ -935,6 +944,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, | |||
935 | clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); | 944 | clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); |
936 | 945 | ||
937 | VOP_REG_SET(vop, common, standby, 0); | 946 | VOP_REG_SET(vop, common, standby, 0); |
947 | mutex_unlock(&vop->vop_lock); | ||
938 | } | 948 | } |
939 | 949 | ||
940 | static bool vop_fs_irq_is_pending(struct vop *vop) | 950 | static bool vop_fs_irq_is_pending(struct vop *vop) |
@@ -1137,15 +1147,14 @@ static void vop_handle_vblank(struct vop *vop) | |||
1137 | { | 1147 | { |
1138 | struct drm_device *drm = vop->drm_dev; | 1148 | struct drm_device *drm = vop->drm_dev; |
1139 | struct drm_crtc *crtc = &vop->crtc; | 1149 | struct drm_crtc *crtc = &vop->crtc; |
1140 | unsigned long flags; | ||
1141 | 1150 | ||
1142 | spin_lock_irqsave(&drm->event_lock, flags); | 1151 | spin_lock(&drm->event_lock); |
1143 | if (vop->event) { | 1152 | if (vop->event) { |
1144 | drm_crtc_send_vblank_event(crtc, vop->event); | 1153 | drm_crtc_send_vblank_event(crtc, vop->event); |
1145 | drm_crtc_vblank_put(crtc); | 1154 | drm_crtc_vblank_put(crtc); |
1146 | vop->event = NULL; | 1155 | vop->event = NULL; |
1147 | } | 1156 | } |
1148 | spin_unlock_irqrestore(&drm->event_lock, flags); | 1157 | spin_unlock(&drm->event_lock); |
1149 | 1158 | ||
1150 | if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) | 1159 | if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) |
1151 | drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq); | 1160 | drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq); |
@@ -1156,21 +1165,20 @@ static irqreturn_t vop_isr(int irq, void *data) | |||
1156 | struct vop *vop = data; | 1165 | struct vop *vop = data; |
1157 | struct drm_crtc *crtc = &vop->crtc; | 1166 | struct drm_crtc *crtc = &vop->crtc; |
1158 | uint32_t active_irqs; | 1167 | uint32_t active_irqs; |
1159 | unsigned long flags; | ||
1160 | int ret = IRQ_NONE; | 1168 | int ret = IRQ_NONE; |
1161 | 1169 | ||
1162 | /* | 1170 | /* |
1163 | * interrupt register has interrupt status, enable and clear bits, we | 1171 | * interrupt register has interrupt status, enable and clear bits, we |
1164 | * must hold irq_lock to avoid a race with enable/disable_vblank(). | 1172 | * must hold irq_lock to avoid a race with enable/disable_vblank(). |
1165 | */ | 1173 | */ |
1166 | spin_lock_irqsave(&vop->irq_lock, flags); | 1174 | spin_lock(&vop->irq_lock); |
1167 | 1175 | ||
1168 | active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK); | 1176 | active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK); |
1169 | /* Clear all active interrupt sources */ | 1177 | /* Clear all active interrupt sources */ |
1170 | if (active_irqs) | 1178 | if (active_irqs) |
1171 | VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1); | 1179 | VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1); |
1172 | 1180 | ||
1173 | spin_unlock_irqrestore(&vop->irq_lock, flags); | 1181 | spin_unlock(&vop->irq_lock); |
1174 | 1182 | ||
1175 | /* This is expected for vop iommu irqs, since the irq is shared */ | 1183 | /* This is expected for vop iommu irqs, since the irq is shared */ |
1176 | if (!active_irqs) | 1184 | if (!active_irqs) |
@@ -1393,7 +1401,11 @@ static int vop_initial(struct vop *vop) | |||
1393 | usleep_range(10, 20); | 1401 | usleep_range(10, 20); |
1394 | reset_control_deassert(ahb_rst); | 1402 | reset_control_deassert(ahb_rst); |
1395 | 1403 | ||
1396 | memcpy(vop->regsbak, vop->regs, vop->len); | 1404 | VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); |
1405 | VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); | ||
1406 | |||
1407 | for (i = 0; i < vop->len; i += sizeof(u32)) | ||
1408 | vop->regsbak[i / 4] = readl_relaxed(vop->regs + i); | ||
1397 | 1409 | ||
1398 | VOP_REG_SET(vop, misc, global_regdone_en, 1); | 1410 | VOP_REG_SET(vop, misc, global_regdone_en, 1); |
1399 | VOP_REG_SET(vop, common, dsp_blank, 0); | 1411 | VOP_REG_SET(vop, common, dsp_blank, 0); |
@@ -1473,15 +1485,21 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) | |||
1473 | { | 1485 | { |
1474 | struct vop *vop = to_vop(crtc); | 1486 | struct vop *vop = to_vop(crtc); |
1475 | unsigned long jiffies_left; | 1487 | unsigned long jiffies_left; |
1488 | int ret = 0; | ||
1476 | 1489 | ||
1477 | if (!crtc || !vop->is_enabled) | 1490 | if (!crtc || !vop->is_enabled) |
1478 | return -ENODEV; | 1491 | return -ENODEV; |
1479 | 1492 | ||
1480 | if (mstimeout <= 0) | 1493 | mutex_lock(&vop->vop_lock); |
1481 | return -EINVAL; | 1494 | if (mstimeout <= 0) { |
1495 | ret = -EINVAL; | ||
1496 | goto out; | ||
1497 | } | ||
1482 | 1498 | ||
1483 | if (vop_line_flag_irq_is_enabled(vop)) | 1499 | if (vop_line_flag_irq_is_enabled(vop)) { |
1484 | return -EBUSY; | 1500 | ret = -EBUSY; |
1501 | goto out; | ||
1502 | } | ||
1485 | 1503 | ||
1486 | reinit_completion(&vop->line_flag_completion); | 1504 | reinit_completion(&vop->line_flag_completion); |
1487 | vop_line_flag_irq_enable(vop); | 1505 | vop_line_flag_irq_enable(vop); |
@@ -1492,10 +1510,13 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) | |||
1492 | 1510 | ||
1493 | if (jiffies_left == 0) { | 1511 | if (jiffies_left == 0) { |
1494 | DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n"); | 1512 | DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n"); |
1495 | return -ETIMEDOUT; | 1513 | ret = -ETIMEDOUT; |
1514 | goto out; | ||
1496 | } | 1515 | } |
1497 | 1516 | ||
1498 | return 0; | 1517 | out: |
1518 | mutex_unlock(&vop->vop_lock); | ||
1519 | return ret; | ||
1499 | } | 1520 | } |
1500 | EXPORT_SYMBOL(rockchip_drm_wait_vact_end); | 1521 | EXPORT_SYMBOL(rockchip_drm_wait_vact_end); |
1501 | 1522 | ||
@@ -1545,18 +1566,11 @@ static int vop_bind(struct device *dev, struct device *master, void *data) | |||
1545 | 1566 | ||
1546 | spin_lock_init(&vop->reg_lock); | 1567 | spin_lock_init(&vop->reg_lock); |
1547 | spin_lock_init(&vop->irq_lock); | 1568 | spin_lock_init(&vop->irq_lock); |
1548 | 1569 | mutex_init(&vop->vop_lock); | |
1549 | ret = devm_request_irq(dev, vop->irq, vop_isr, | ||
1550 | IRQF_SHARED, dev_name(dev), vop); | ||
1551 | if (ret) | ||
1552 | return ret; | ||
1553 | |||
1554 | /* IRQ is initially disabled; it gets enabled in power_on */ | ||
1555 | disable_irq(vop->irq); | ||
1556 | 1570 | ||
1557 | ret = vop_create_crtc(vop); | 1571 | ret = vop_create_crtc(vop); |
1558 | if (ret) | 1572 | if (ret) |
1559 | goto err_enable_irq; | 1573 | return ret; |
1560 | 1574 | ||
1561 | pm_runtime_enable(&pdev->dev); | 1575 | pm_runtime_enable(&pdev->dev); |
1562 | 1576 | ||
@@ -1567,13 +1581,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data) | |||
1567 | goto err_disable_pm_runtime; | 1581 | goto err_disable_pm_runtime; |
1568 | } | 1582 | } |
1569 | 1583 | ||
1584 | ret = devm_request_irq(dev, vop->irq, vop_isr, | ||
1585 | IRQF_SHARED, dev_name(dev), vop); | ||
1586 | if (ret) | ||
1587 | goto err_disable_pm_runtime; | ||
1588 | |||
1589 | /* IRQ is initially disabled; it gets enabled in power_on */ | ||
1590 | disable_irq(vop->irq); | ||
1591 | |||
1570 | return 0; | 1592 | return 0; |
1571 | 1593 | ||
1572 | err_disable_pm_runtime: | 1594 | err_disable_pm_runtime: |
1573 | pm_runtime_disable(&pdev->dev); | 1595 | pm_runtime_disable(&pdev->dev); |
1574 | vop_destroy_crtc(vop); | 1596 | vop_destroy_crtc(vop); |
1575 | err_enable_irq: | ||
1576 | enable_irq(vop->irq); /* To balance out the disable_irq above */ | ||
1577 | return ret; | 1597 | return ret; |
1578 | } | 1598 | } |
1579 | 1599 | ||
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 092ade4ff6a5..9bad54f3de38 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c | |||
@@ -42,6 +42,56 @@ static const u32 sunxi_rgb2yuv_coef[12] = { | |||
42 | 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 | 42 | 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 |
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* | ||
46 | * These coefficients are taken from the A33 BSP from Allwinner. | ||
47 | * | ||
48 | * The formula is for each component, each coefficient being multiplied by | ||
49 | * 1024 and each constant being multiplied by 16: | ||
50 | * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 | ||
51 | * R = 1.164 * Y + 1.596 * V - 222 | ||
52 | * B = 1.164 * Y + 2.018 * U + 276 | ||
53 | * | ||
54 | * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], | ||
55 | * following the BT601 spec. | ||
56 | */ | ||
57 | static const u32 sunxi_bt601_yuv2rgb_coef[12] = { | ||
58 | 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, | ||
59 | 0x000004a7, 0x00000000, 0x00000662, 0x00003211, | ||
60 | 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, | ||
61 | }; | ||
62 | |||
63 | static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format) | ||
64 | { | ||
65 | switch (format) { | ||
66 | case DRM_FORMAT_YUV411: | ||
67 | case DRM_FORMAT_YUV422: | ||
68 | case DRM_FORMAT_YUV444: | ||
69 | return true; | ||
70 | default: | ||
71 | return false; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) | ||
76 | { | ||
77 | switch (format) { | ||
78 | case DRM_FORMAT_YUYV: | ||
79 | case DRM_FORMAT_YVYU: | ||
80 | case DRM_FORMAT_UYVY: | ||
81 | case DRM_FORMAT_VYUY: | ||
82 | return true; | ||
83 | |||
84 | default: | ||
85 | return false; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static inline bool sun4i_backend_format_is_yuv(uint32_t format) | ||
90 | { | ||
91 | return sun4i_backend_format_is_planar_yuv(format) || | ||
92 | sun4i_backend_format_is_packed_yuv422(format); | ||
93 | } | ||
94 | |||
45 | static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) | 95 | static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) |
46 | { | 96 | { |
47 | int i; | 97 | int i; |
@@ -166,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, | |||
166 | return 0; | 216 | return 0; |
167 | } | 217 | } |
168 | 218 | ||
219 | static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend, | ||
220 | int layer, struct drm_plane *plane) | ||
221 | { | ||
222 | struct drm_plane_state *state = plane->state; | ||
223 | struct drm_framebuffer *fb = state->fb; | ||
224 | uint32_t format = fb->format->format; | ||
225 | u32 val = SUN4I_BACKEND_IYUVCTL_EN; | ||
226 | int i; | ||
227 | |||
228 | for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++) | ||
229 | regmap_write(backend->engine.regs, | ||
230 | SUN4I_BACKEND_YGCOEF_REG(i), | ||
231 | sunxi_bt601_yuv2rgb_coef[i]); | ||
232 | |||
233 | /* | ||
234 | * We should do that only for a single plane, but the | ||
235 | * framebuffer's atomic_check has our back on this. | ||
236 | */ | ||
237 | regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), | ||
238 | SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, | ||
239 | SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); | ||
240 | |||
241 | /* TODO: Add support for the multi-planar YUV formats */ | ||
242 | if (sun4i_backend_format_is_packed_yuv422(format)) | ||
243 | val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; | ||
244 | else | ||
245 | DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format); | ||
246 | |||
247 | /* | ||
248 | * Allwinner seems to list the pixel sequence from right to left, while | ||
249 | * DRM lists it from left to right. | ||
250 | */ | ||
251 | switch (format) { | ||
252 | case DRM_FORMAT_YUYV: | ||
253 | val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; | ||
254 | break; | ||
255 | case DRM_FORMAT_YVYU: | ||
256 | val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY; | ||
257 | break; | ||
258 | case DRM_FORMAT_UYVY: | ||
259 | val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU; | ||
260 | break; | ||
261 | case DRM_FORMAT_VYUY: | ||
262 | val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV; | ||
263 | break; | ||
264 | default: | ||
265 | DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n", | ||
266 | format); | ||
267 | } | ||
268 | |||
269 | regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
169 | int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, | 274 | int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, |
170 | int layer, struct drm_plane *plane) | 275 | int layer, struct drm_plane *plane) |
171 | { | 276 | { |
@@ -175,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, | |||
175 | u32 val; | 280 | u32 val; |
176 | int ret; | 281 | int ret; |
177 | 282 | ||
283 | /* Clear the YUV mode */ | ||
284 | regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer), | ||
285 | SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); | ||
286 | |||
178 | if (plane->state->crtc) | 287 | if (plane->state->crtc) |
179 | interlaced = plane->state->crtc->state->adjusted_mode.flags | 288 | interlaced = plane->state->crtc->state->adjusted_mode.flags |
180 | & DRM_MODE_FLAG_INTERLACE; | 289 | & DRM_MODE_FLAG_INTERLACE; |
@@ -186,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, | |||
186 | DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", | 295 | DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", |
187 | interlaced ? "on" : "off"); | 296 | interlaced ? "on" : "off"); |
188 | 297 | ||
298 | if (sun4i_backend_format_is_yuv(fb->format->format)) | ||
299 | return sun4i_backend_update_yuv_format(backend, layer, plane); | ||
300 | |||
189 | ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); | 301 | ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); |
190 | if (ret) { | 302 | if (ret) { |
191 | DRM_DEBUG_DRIVER("Invalid format\n"); | 303 | DRM_DEBUG_DRIVER("Invalid format\n"); |
@@ -223,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend, | |||
223 | return 0; | 335 | return 0; |
224 | } | 336 | } |
225 | 337 | ||
338 | static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend, | ||
339 | struct drm_framebuffer *fb, | ||
340 | dma_addr_t paddr) | ||
341 | { | ||
342 | /* TODO: Add support for the multi-planar YUV formats */ | ||
343 | DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr); | ||
344 | regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr); | ||
345 | |||
346 | DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); | ||
347 | regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0), | ||
348 | fb->pitches[0] * 8); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
226 | int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, | 353 | int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, |
227 | int layer, struct drm_plane *plane) | 354 | int layer, struct drm_plane *plane) |
228 | { | 355 | { |
@@ -248,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, | |||
248 | */ | 375 | */ |
249 | paddr -= PHYS_OFFSET; | 376 | paddr -= PHYS_OFFSET; |
250 | 377 | ||
378 | if (sun4i_backend_format_is_yuv(fb->format->format)) | ||
379 | return sun4i_backend_update_yuv_buffer(backend, fb, paddr); | ||
380 | |||
251 | /* Write the 32 lower bits of the address (in bits) */ | 381 | /* Write the 32 lower bits of the address (in bits) */ |
252 | lo_paddr = paddr << 3; | 382 | lo_paddr = paddr << 3; |
253 | DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); | 383 | DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); |
@@ -330,6 +460,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, | |||
330 | unsigned int num_planes = 0; | 460 | unsigned int num_planes = 0; |
331 | unsigned int num_alpha_planes = 0; | 461 | unsigned int num_alpha_planes = 0; |
332 | unsigned int num_frontend_planes = 0; | 462 | unsigned int num_frontend_planes = 0; |
463 | unsigned int num_yuv_planes = 0; | ||
333 | unsigned int current_pipe = 0; | 464 | unsigned int current_pipe = 0; |
334 | unsigned int i; | 465 | unsigned int i; |
335 | 466 | ||
@@ -362,6 +493,11 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, | |||
362 | if (fb->format->has_alpha) | 493 | if (fb->format->has_alpha) |
363 | num_alpha_planes++; | 494 | num_alpha_planes++; |
364 | 495 | ||
496 | if (sun4i_backend_format_is_yuv(fb->format->format)) { | ||
497 | DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); | ||
498 | num_yuv_planes++; | ||
499 | } | ||
500 | |||
365 | DRM_DEBUG_DRIVER("Plane zpos is %d\n", | 501 | DRM_DEBUG_DRIVER("Plane zpos is %d\n", |
366 | plane_state->normalized_zpos); | 502 | plane_state->normalized_zpos); |
367 | 503 | ||
@@ -430,13 +566,20 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, | |||
430 | s_state->pipe = current_pipe; | 566 | s_state->pipe = current_pipe; |
431 | } | 567 | } |
432 | 568 | ||
569 | /* We can only have a single YUV plane at a time */ | ||
570 | if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) { | ||
571 | DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n"); | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | |||
433 | if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) { | 575 | if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) { |
434 | DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); | 576 | DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n"); |
435 | return -EINVAL; | 577 | return -EINVAL; |
436 | } | 578 | } |
437 | 579 | ||
438 | DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n", | 580 | DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video, %u YUV\n", |
439 | num_planes, num_alpha_planes, num_frontend_planes); | 581 | num_planes, num_alpha_planes, num_frontend_planes, |
582 | num_yuv_planes); | ||
440 | 583 | ||
441 | return 0; | 584 | return 0; |
442 | } | 585 | } |
@@ -793,6 +936,9 @@ static const struct sun4i_backend_quirks sun7i_backend_quirks = { | |||
793 | static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { | 936 | static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { |
794 | }; | 937 | }; |
795 | 938 | ||
939 | static const struct sun4i_backend_quirks sun9i_backend_quirks = { | ||
940 | }; | ||
941 | |||
796 | static const struct of_device_id sun4i_backend_of_table[] = { | 942 | static const struct of_device_id sun4i_backend_of_table[] = { |
797 | { | 943 | { |
798 | .compatible = "allwinner,sun4i-a10-display-backend", | 944 | .compatible = "allwinner,sun4i-a10-display-backend", |
@@ -814,6 +960,10 @@ static const struct of_device_id sun4i_backend_of_table[] = { | |||
814 | .compatible = "allwinner,sun8i-a33-display-backend", | 960 | .compatible = "allwinner,sun8i-a33-display-backend", |
815 | .data = &sun8i_a33_backend_quirks, | 961 | .data = &sun8i_a33_backend_quirks, |
816 | }, | 962 | }, |
963 | { | ||
964 | .compatible = "allwinner,sun9i-a80-display-backend", | ||
965 | .data = &sun9i_backend_quirks, | ||
966 | }, | ||
817 | { } | 967 | { } |
818 | }; | 968 | }; |
819 | MODULE_DEVICE_TABLE(of, sun4i_backend_of_table); | 969 | MODULE_DEVICE_TABLE(of, sun4i_backend_of_table); |
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 52e77591186a..316f2179e9e1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h | |||
@@ -72,6 +72,7 @@ | |||
72 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) | 72 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15) |
73 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) | 73 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10) |
74 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) | 74 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10) |
75 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2) | ||
75 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1) | 76 | #define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1) |
76 | 77 | ||
77 | #define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) | 78 | #define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l))) |
@@ -110,7 +111,23 @@ | |||
110 | #define SUN4I_BACKEND_SPREN_REG 0x900 | 111 | #define SUN4I_BACKEND_SPREN_REG 0x900 |
111 | #define SUN4I_BACKEND_SPRFMTCTL_REG 0x908 | 112 | #define SUN4I_BACKEND_SPRFMTCTL_REG 0x908 |
112 | #define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c | 113 | #define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c |
114 | |||
113 | #define SUN4I_BACKEND_IYUVCTL_REG 0x920 | 115 | #define SUN4I_BACKEND_IYUVCTL_REG 0x920 |
116 | #define SUN4I_BACKEND_IYUVCTL_FBFMT_MASK GENMASK(14, 12) | ||
117 | #define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV444 (4 << 12) | ||
118 | #define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422 (3 << 12) | ||
119 | #define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV444 (2 << 12) | ||
120 | #define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV222 (1 << 12) | ||
121 | #define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV111 (0 << 12) | ||
122 | #define SUN4I_BACKEND_IYUVCTL_FBPS_MASK GENMASK(9, 8) | ||
123 | #define SUN4I_BACKEND_IYUVCTL_FBPS_YVYU (3 << 8) | ||
124 | #define SUN4I_BACKEND_IYUVCTL_FBPS_VYUY (2 << 8) | ||
125 | #define SUN4I_BACKEND_IYUVCTL_FBPS_YUYV (1 << 8) | ||
126 | #define SUN4I_BACKEND_IYUVCTL_FBPS_UYVY (0 << 8) | ||
127 | #define SUN4I_BACKEND_IYUVCTL_FBPS_VUYA (1 << 8) | ||
128 | #define SUN4I_BACKEND_IYUVCTL_FBPS_AYUV (0 << 8) | ||
129 | #define SUN4I_BACKEND_IYUVCTL_EN BIT(0) | ||
130 | |||
114 | #define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) | 131 | #define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c))) |
115 | 132 | ||
116 | #define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c))) | 133 | #define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c))) |
@@ -149,6 +166,7 @@ | |||
149 | #define SUN4I_BACKEND_NUM_LAYERS 4 | 166 | #define SUN4I_BACKEND_NUM_LAYERS 4 |
150 | #define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1 | 167 | #define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1 |
151 | #define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1 | 168 | #define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1 |
169 | #define SUN4I_BACKEND_NUM_YUV_PLANES 1 | ||
152 | 170 | ||
153 | struct sun4i_backend { | 171 | struct sun4i_backend { |
154 | struct sunxi_engine engine; | 172 | struct sunxi_engine engine; |
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index a0f43b81c64c..7f0705ef9f4e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c | |||
@@ -176,7 +176,13 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node) | |||
176 | of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") || | 176 | of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") || |
177 | of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") || | 177 | of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") || |
178 | of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") || | 178 | of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") || |
179 | of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend"); | 179 | of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") || |
180 | of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend"); | ||
181 | } | ||
182 | |||
183 | static bool sun4i_drv_node_is_deu(struct device_node *node) | ||
184 | { | ||
185 | return of_device_is_compatible(node, "allwinner,sun9i-a80-deu"); | ||
180 | } | 186 | } |
181 | 187 | ||
182 | static bool sun4i_drv_node_is_supported_frontend(struct device_node *node) | 188 | static bool sun4i_drv_node_is_supported_frontend(struct device_node *node) |
@@ -257,7 +263,8 @@ static int sun4i_drv_add_endpoints(struct device *dev, | |||
257 | * enabled frontend supported by the driver, we add it to our | 263 | * enabled frontend supported by the driver, we add it to our |
258 | * component list. | 264 | * component list. |
259 | */ | 265 | */ |
260 | if (!sun4i_drv_node_is_frontend(node) || | 266 | if (!(sun4i_drv_node_is_frontend(node) || |
267 | sun4i_drv_node_is_deu(node)) || | ||
261 | (sun4i_drv_node_is_supported_frontend(node) && | 268 | (sun4i_drv_node_is_supported_frontend(node) && |
262 | of_device_is_available(node))) { | 269 | of_device_is_available(node))) { |
263 | /* Add current component */ | 270 | /* Add current component */ |
@@ -361,6 +368,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { | |||
361 | { .compatible = "allwinner,sun8i-a83t-display-engine" }, | 368 | { .compatible = "allwinner,sun8i-a83t-display-engine" }, |
362 | { .compatible = "allwinner,sun8i-h3-display-engine" }, | 369 | { .compatible = "allwinner,sun8i-h3-display-engine" }, |
363 | { .compatible = "allwinner,sun8i-v3s-display-engine" }, | 370 | { .compatible = "allwinner,sun8i-v3s-display-engine" }, |
371 | { .compatible = "allwinner,sun9i-a80-display-engine" }, | ||
364 | { } | 372 | { } |
365 | }; | 373 | }; |
366 | MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); | 374 | MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); |
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 33ad377569ec..2949a3c912c1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c | |||
@@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = { | |||
134 | DRM_FORMAT_RGBA4444, | 134 | DRM_FORMAT_RGBA4444, |
135 | DRM_FORMAT_RGB888, | 135 | DRM_FORMAT_RGB888, |
136 | DRM_FORMAT_RGB565, | 136 | DRM_FORMAT_RGB565, |
137 | DRM_FORMAT_UYVY, | ||
138 | DRM_FORMAT_VYUY, | ||
137 | DRM_FORMAT_XRGB8888, | 139 | DRM_FORMAT_XRGB8888, |
140 | DRM_FORMAT_YUYV, | ||
141 | DRM_FORMAT_YVYU, | ||
138 | }; | 142 | }; |
139 | 143 | ||
140 | static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, | 144 | static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, |
diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index be3f14d7746d..bffff4c9fbf5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c | |||
@@ -94,9 +94,64 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder) | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | static enum drm_mode_status sun4i_lvds_encoder_mode_valid(struct drm_encoder *crtc, | ||
98 | const struct drm_display_mode *mode) | ||
99 | { | ||
100 | struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(crtc); | ||
101 | struct sun4i_tcon *tcon = lvds->tcon; | ||
102 | u32 hsync = mode->hsync_end - mode->hsync_start; | ||
103 | u32 vsync = mode->vsync_end - mode->vsync_start; | ||
104 | unsigned long rate = mode->clock * 1000; | ||
105 | long rounded_rate; | ||
106 | |||
107 | DRM_DEBUG_DRIVER("Validating modes...\n"); | ||
108 | |||
109 | if (hsync < 1) | ||
110 | return MODE_HSYNC_NARROW; | ||
111 | |||
112 | if (hsync > 0x3ff) | ||
113 | return MODE_HSYNC_WIDE; | ||
114 | |||
115 | if ((mode->hdisplay < 1) || (mode->htotal < 1)) | ||
116 | return MODE_H_ILLEGAL; | ||
117 | |||
118 | if ((mode->hdisplay > 0x7ff) || (mode->htotal > 0xfff)) | ||
119 | return MODE_BAD_HVALUE; | ||
120 | |||
121 | DRM_DEBUG_DRIVER("Horizontal parameters OK\n"); | ||
122 | |||
123 | if (vsync < 1) | ||
124 | return MODE_VSYNC_NARROW; | ||
125 | |||
126 | if (vsync > 0x3ff) | ||
127 | return MODE_VSYNC_WIDE; | ||
128 | |||
129 | if ((mode->vdisplay < 1) || (mode->vtotal < 1)) | ||
130 | return MODE_V_ILLEGAL; | ||
131 | |||
132 | if ((mode->vdisplay > 0x7ff) || (mode->vtotal > 0xfff)) | ||
133 | return MODE_BAD_VVALUE; | ||
134 | |||
135 | DRM_DEBUG_DRIVER("Vertical parameters OK\n"); | ||
136 | |||
137 | tcon->dclk_min_div = 7; | ||
138 | tcon->dclk_max_div = 7; | ||
139 | rounded_rate = clk_round_rate(tcon->dclk, rate); | ||
140 | if (rounded_rate < rate) | ||
141 | return MODE_CLOCK_LOW; | ||
142 | |||
143 | if (rounded_rate > rate) | ||
144 | return MODE_CLOCK_HIGH; | ||
145 | |||
146 | DRM_DEBUG_DRIVER("Clock rate OK\n"); | ||
147 | |||
148 | return MODE_OK; | ||
149 | } | ||
150 | |||
97 | static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = { | 151 | static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = { |
98 | .disable = sun4i_lvds_encoder_disable, | 152 | .disable = sun4i_lvds_encoder_disable, |
99 | .enable = sun4i_lvds_encoder_enable, | 153 | .enable = sun4i_lvds_encoder_enable, |
154 | .mode_valid = sun4i_lvds_encoder_mode_valid, | ||
100 | }; | 155 | }; |
101 | 156 | ||
102 | static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = { | 157 | static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = { |
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 832f8f9bc47f..a2a697a099e6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c | |||
@@ -52,10 +52,10 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector) | |||
52 | return drm_panel_get_modes(tcon->panel); | 52 | return drm_panel_get_modes(tcon->panel); |
53 | } | 53 | } |
54 | 54 | ||
55 | static int sun4i_rgb_mode_valid(struct drm_connector *connector, | 55 | static enum drm_mode_status sun4i_rgb_mode_valid(struct drm_encoder *crtc, |
56 | struct drm_display_mode *mode) | 56 | const struct drm_display_mode *mode) |
57 | { | 57 | { |
58 | struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); | 58 | struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(crtc); |
59 | struct sun4i_tcon *tcon = rgb->tcon; | 59 | struct sun4i_tcon *tcon = rgb->tcon; |
60 | u32 hsync = mode->hsync_end - mode->hsync_start; | 60 | u32 hsync = mode->hsync_end - mode->hsync_start; |
61 | u32 vsync = mode->vsync_end - mode->vsync_start; | 61 | u32 vsync = mode->vsync_end - mode->vsync_start; |
@@ -106,7 +106,6 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, | |||
106 | 106 | ||
107 | static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { | 107 | static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = { |
108 | .get_modes = sun4i_rgb_get_modes, | 108 | .get_modes = sun4i_rgb_get_modes, |
109 | .mode_valid = sun4i_rgb_mode_valid, | ||
110 | }; | 109 | }; |
111 | 110 | ||
112 | static void | 111 | static void |
@@ -156,6 +155,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder) | |||
156 | static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { | 155 | static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = { |
157 | .disable = sun4i_rgb_encoder_disable, | 156 | .disable = sun4i_rgb_encoder_disable, |
158 | .enable = sun4i_rgb_encoder_enable, | 157 | .enable = sun4i_rgb_encoder_enable, |
158 | .mode_valid = sun4i_rgb_mode_valid, | ||
159 | }; | 159 | }; |
160 | 160 | ||
161 | static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder) | 161 | static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder) |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 0d6c5ed44795..1a114e380f13 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <drm/drm_encoder.h> | 17 | #include <drm/drm_encoder.h> |
18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
19 | #include <drm/drm_of.h> | 19 | #include <drm/drm_of.h> |
20 | #include <drm/drm_panel.h> | ||
20 | 21 | ||
21 | #include <uapi/drm/drm_mode.h> | 22 | #include <uapi/drm/drm_mode.h> |
22 | 23 | ||
@@ -343,6 +344,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, | |||
343 | static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, | 344 | static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, |
344 | const struct drm_display_mode *mode) | 345 | const struct drm_display_mode *mode) |
345 | { | 346 | { |
347 | struct drm_panel *panel = tcon->panel; | ||
348 | struct drm_connector *connector = panel->connector; | ||
349 | struct drm_display_info display_info = connector->display_info; | ||
346 | unsigned int bp, hsync, vsync; | 350 | unsigned int bp, hsync, vsync; |
347 | u8 clk_delay; | 351 | u8 clk_delay; |
348 | u32 val = 0; | 352 | u32 val = 0; |
@@ -400,6 +404,27 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, | |||
400 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | 404 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) |
401 | val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; | 405 | val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; |
402 | 406 | ||
407 | /* | ||
408 | * On A20 and similar SoCs, the only way to achieve Positive Edge | ||
409 | * (Rising Edge), is setting dclk clock phase to 2/3(240°). | ||
410 | * By default TCON works in Negative Edge(Falling Edge), | ||
411 | * this is why phase is set to 0 in that case. | ||
412 | * Unfortunately there's no way to logically invert dclk through | ||
413 | * IO_POL register. | ||
414 | * The only acceptable way to work, triple checked with scope, | ||
415 | * is using clock phase set to 0° for Negative Edge and set to 240° | ||
416 | * for Positive Edge. | ||
417 | * On A33 and similar SoCs there would be a 90° phase option, | ||
418 | * but it divides also dclk by 2. | ||
419 | * Following code is a way to avoid quirks all around TCON | ||
420 | * and DOTCLOCK drivers. | ||
421 | */ | ||
422 | if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) | ||
423 | clk_set_phase(tcon->dclk, 240); | ||
424 | |||
425 | if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) | ||
426 | clk_set_phase(tcon->dclk, 0); | ||
427 | |||
403 | regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, | 428 | regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, |
404 | SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, | 429 | SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, |
405 | val); | 430 | val); |
@@ -850,6 +875,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, | |||
850 | struct sunxi_engine *engine; | 875 | struct sunxi_engine *engine; |
851 | struct device_node *remote; | 876 | struct device_node *remote; |
852 | struct sun4i_tcon *tcon; | 877 | struct sun4i_tcon *tcon; |
878 | struct reset_control *edp_rstc; | ||
853 | bool has_lvds_rst, has_lvds_alt, can_lvds; | 879 | bool has_lvds_rst, has_lvds_alt, can_lvds; |
854 | int ret; | 880 | int ret; |
855 | 881 | ||
@@ -874,6 +900,20 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, | |||
874 | return PTR_ERR(tcon->lcd_rst); | 900 | return PTR_ERR(tcon->lcd_rst); |
875 | } | 901 | } |
876 | 902 | ||
903 | if (tcon->quirks->needs_edp_reset) { | ||
904 | edp_rstc = devm_reset_control_get_shared(dev, "edp"); | ||
905 | if (IS_ERR(edp_rstc)) { | ||
906 | dev_err(dev, "Couldn't get edp reset line\n"); | ||
907 | return PTR_ERR(edp_rstc); | ||
908 | } | ||
909 | |||
910 | ret = reset_control_deassert(edp_rstc); | ||
911 | if (ret) { | ||
912 | dev_err(dev, "Couldn't deassert edp reset line\n"); | ||
913 | return ret; | ||
914 | } | ||
915 | } | ||
916 | |||
877 | /* Make sure our TCON is reset */ | 917 | /* Make sure our TCON is reset */ |
878 | ret = reset_control_reset(tcon->lcd_rst); | 918 | ret = reset_control_reset(tcon->lcd_rst); |
879 | if (ret) { | 919 | if (ret) { |
@@ -1166,6 +1206,16 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { | |||
1166 | .has_channel_0 = true, | 1206 | .has_channel_0 = true, |
1167 | }; | 1207 | }; |
1168 | 1208 | ||
1209 | static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = { | ||
1210 | .has_channel_0 = true, | ||
1211 | .needs_edp_reset = true, | ||
1212 | }; | ||
1213 | |||
1214 | static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = { | ||
1215 | .has_channel_1 = true, | ||
1216 | .needs_edp_reset = true, | ||
1217 | }; | ||
1218 | |||
1169 | /* sun4i_drv uses this list to check if a device node is a TCON */ | 1219 | /* sun4i_drv uses this list to check if a device node is a TCON */ |
1170 | const struct of_device_id sun4i_tcon_of_table[] = { | 1220 | const struct of_device_id sun4i_tcon_of_table[] = { |
1171 | { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks }, | 1221 | { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks }, |
@@ -1177,6 +1227,8 @@ const struct of_device_id sun4i_tcon_of_table[] = { | |||
1177 | { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks }, | 1227 | { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks }, |
1178 | { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks }, | 1228 | { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks }, |
1179 | { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks }, | 1229 | { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks }, |
1230 | { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks }, | ||
1231 | { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks }, | ||
1180 | { } | 1232 | { } |
1181 | }; | 1233 | }; |
1182 | MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); | 1234 | MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table); |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 78d55e7cd2b3..d3a945b7bb60 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h | |||
@@ -176,6 +176,7 @@ struct sun4i_tcon_quirks { | |||
176 | bool has_channel_1; /* a33 does not have channel 1 */ | 176 | bool has_channel_1; /* a33 does not have channel 1 */ |
177 | bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ | 177 | bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ |
178 | bool needs_de_be_mux; /* sun6i needs mux to select backend */ | 178 | bool needs_de_be_mux; /* sun6i needs mux to select backend */ |
179 | bool needs_edp_reset; /* a80 edp reset needed for tcon0 access */ | ||
179 | 180 | ||
180 | /* callback to handle tcon muxing options */ | 181 | /* callback to handle tcon muxing options */ |
181 | int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); | 182 | int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); |
diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c index 09bba853e2a4..b5e071a49045 100644 --- a/drivers/gpu/drm/sun4i/sun6i_drc.c +++ b/drivers/gpu/drm/sun4i/sun6i_drc.c | |||
@@ -101,6 +101,7 @@ static const struct of_device_id sun6i_drc_of_table[] = { | |||
101 | { .compatible = "allwinner,sun6i-a31-drc" }, | 101 | { .compatible = "allwinner,sun6i-a31-drc" }, |
102 | { .compatible = "allwinner,sun6i-a31s-drc" }, | 102 | { .compatible = "allwinner,sun6i-a31s-drc" }, |
103 | { .compatible = "allwinner,sun8i-a33-drc" }, | 103 | { .compatible = "allwinner,sun8i-a33-drc" }, |
104 | { .compatible = "allwinner,sun9i-a80-drc" }, | ||
104 | { } | 105 | { } |
105 | }; | 106 | }; |
106 | MODULE_DEVICE_TABLE(of, sun6i_drc_of_table); | 107 | MODULE_DEVICE_TABLE(of, sun6i_drc_of_table); |
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index ce1e3b9e14c9..bf4667481935 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c | |||
@@ -643,9 +643,12 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, | |||
643 | { | 643 | { |
644 | struct drm_device *dev = crtc->dev; | 644 | struct drm_device *dev = crtc->dev; |
645 | struct vc4_dev *vc4 = to_vc4_dev(dev); | 645 | struct vc4_dev *vc4 = to_vc4_dev(dev); |
646 | struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); | ||
646 | struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); | 647 | struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); |
647 | struct drm_plane *plane; | 648 | struct drm_plane *plane; |
649 | struct vc4_plane_state *vc4_plane_state; | ||
648 | bool debug_dump_regs = false; | 650 | bool debug_dump_regs = false; |
651 | bool enable_bg_fill = false; | ||
649 | u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; | 652 | u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; |
650 | u32 __iomem *dlist_next = dlist_start; | 653 | u32 __iomem *dlist_next = dlist_start; |
651 | 654 | ||
@@ -656,6 +659,20 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, | |||
656 | 659 | ||
657 | /* Copy all the active planes' dlist contents to the hardware dlist. */ | 660 | /* Copy all the active planes' dlist contents to the hardware dlist. */ |
658 | drm_atomic_crtc_for_each_plane(plane, crtc) { | 661 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
662 | /* Is this the first active plane? */ | ||
663 | if (dlist_next == dlist_start) { | ||
664 | /* We need to enable background fill when a plane | ||
665 | * could be alpha blending from the background, i.e. | ||
666 | * where no other plane is underneath. It suffices to | ||
667 | * consider the first active plane here since we set | ||
668 | * needs_bg_fill such that either the first plane | ||
669 | * already needs it or all planes on top blend from | ||
670 | * the first or a lower plane. | ||
671 | */ | ||
672 | vc4_plane_state = to_vc4_plane_state(plane->state); | ||
673 | enable_bg_fill = vc4_plane_state->needs_bg_fill; | ||
674 | } | ||
675 | |||
659 | dlist_next += vc4_plane_write_dlist(plane, dlist_next); | 676 | dlist_next += vc4_plane_write_dlist(plane, dlist_next); |
660 | } | 677 | } |
661 | 678 | ||
@@ -664,6 +681,14 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc, | |||
664 | 681 | ||
665 | WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); | 682 | WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size); |
666 | 683 | ||
684 | if (enable_bg_fill) | ||
685 | /* This sets a black background color fill, as is the case | ||
686 | * with other DRM drivers. | ||
687 | */ | ||
688 | HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel), | ||
689 | HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) | | ||
690 | SCALER_DISPBKGND_FILL); | ||
691 | |||
667 | /* Only update DISPLIST if the CRTC was already running and is not | 692 | /* Only update DISPLIST if the CRTC was already running and is not |
668 | * being disabled. | 693 | * being disabled. |
669 | * vc4_crtc_enable() takes care of updating the dlist just after | 694 | * vc4_crtc_enable() takes care of updating the dlist just after |
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index fefa1664a9f5..1b4cd1fabf56 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h | |||
@@ -310,6 +310,66 @@ to_vc4_plane(struct drm_plane *plane) | |||
310 | return (struct vc4_plane *)plane; | 310 | return (struct vc4_plane *)plane; |
311 | } | 311 | } |
312 | 312 | ||
313 | enum vc4_scaling_mode { | ||
314 | VC4_SCALING_NONE, | ||
315 | VC4_SCALING_TPZ, | ||
316 | VC4_SCALING_PPF, | ||
317 | }; | ||
318 | |||
319 | struct vc4_plane_state { | ||
320 | struct drm_plane_state base; | ||
321 | /* System memory copy of the display list for this element, computed | ||
322 | * at atomic_check time. | ||
323 | */ | ||
324 | u32 *dlist; | ||
325 | u32 dlist_size; /* Number of dwords allocated for the display list */ | ||
326 | u32 dlist_count; /* Number of used dwords in the display list. */ | ||
327 | |||
328 | /* Offset in the dlist to various words, for pageflip or | ||
329 | * cursor updates. | ||
330 | */ | ||
331 | u32 pos0_offset; | ||
332 | u32 pos2_offset; | ||
333 | u32 ptr0_offset; | ||
334 | |||
335 | /* Offset where the plane's dlist was last stored in the | ||
336 | * hardware at vc4_crtc_atomic_flush() time. | ||
337 | */ | ||
338 | u32 __iomem *hw_dlist; | ||
339 | |||
340 | /* Clipped coordinates of the plane on the display. */ | ||
341 | int crtc_x, crtc_y, crtc_w, crtc_h; | ||
342 | /* Clipped area being scanned from in the FB. */ | ||
343 | u32 src_x, src_y; | ||
344 | |||
345 | u32 src_w[2], src_h[2]; | ||
346 | |||
347 | /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */ | ||
348 | enum vc4_scaling_mode x_scaling[2], y_scaling[2]; | ||
349 | bool is_unity; | ||
350 | bool is_yuv; | ||
351 | |||
352 | /* Offset to start scanning out from the start of the plane's | ||
353 | * BO. | ||
354 | */ | ||
355 | u32 offsets[3]; | ||
356 | |||
357 | /* Our allocation in LBM for temporary storage during scaling. */ | ||
358 | struct drm_mm_node lbm; | ||
359 | |||
360 | /* Set when the plane has per-pixel alpha content or does not cover | ||
361 | * the entire screen. This is a hint to the CRTC that it might need | ||
362 | * to enable background color fill. | ||
363 | */ | ||
364 | bool needs_bg_fill; | ||
365 | }; | ||
366 | |||
367 | static inline struct vc4_plane_state * | ||
368 | to_vc4_plane_state(struct drm_plane_state *state) | ||
369 | { | ||
370 | return (struct vc4_plane_state *)state; | ||
371 | } | ||
372 | |||
313 | enum vc4_encoder_type { | 373 | enum vc4_encoder_type { |
314 | VC4_ENCODER_TYPE_NONE, | 374 | VC4_ENCODER_TYPE_NONE, |
315 | VC4_ENCODER_TYPE_HDMI, | 375 | VC4_ENCODER_TYPE_HDMI, |
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index c4c7af11fec5..ce39390be389 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c | |||
@@ -27,60 +27,6 @@ | |||
27 | #include "vc4_drv.h" | 27 | #include "vc4_drv.h" |
28 | #include "vc4_regs.h" | 28 | #include "vc4_regs.h" |
29 | 29 | ||
30 | enum vc4_scaling_mode { | ||
31 | VC4_SCALING_NONE, | ||
32 | VC4_SCALING_TPZ, | ||
33 | VC4_SCALING_PPF, | ||
34 | }; | ||
35 | |||
36 | struct vc4_plane_state { | ||
37 | struct drm_plane_state base; | ||
38 | /* System memory copy of the display list for this element, computed | ||
39 | * at atomic_check time. | ||
40 | */ | ||
41 | u32 *dlist; | ||
42 | u32 dlist_size; /* Number of dwords allocated for the display list */ | ||
43 | u32 dlist_count; /* Number of used dwords in the display list. */ | ||
44 | |||
45 | /* Offset in the dlist to various words, for pageflip or | ||
46 | * cursor updates. | ||
47 | */ | ||
48 | u32 pos0_offset; | ||
49 | u32 pos2_offset; | ||
50 | u32 ptr0_offset; | ||
51 | |||
52 | /* Offset where the plane's dlist was last stored in the | ||
53 | * hardware at vc4_crtc_atomic_flush() time. | ||
54 | */ | ||
55 | u32 __iomem *hw_dlist; | ||
56 | |||
57 | /* Clipped coordinates of the plane on the display. */ | ||
58 | int crtc_x, crtc_y, crtc_w, crtc_h; | ||
59 | /* Clipped area being scanned from in the FB. */ | ||
60 | u32 src_x, src_y; | ||
61 | |||
62 | u32 src_w[2], src_h[2]; | ||
63 | |||
64 | /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */ | ||
65 | enum vc4_scaling_mode x_scaling[2], y_scaling[2]; | ||
66 | bool is_unity; | ||
67 | bool is_yuv; | ||
68 | |||
69 | /* Offset to start scanning out from the start of the plane's | ||
70 | * BO. | ||
71 | */ | ||
72 | u32 offsets[3]; | ||
73 | |||
74 | /* Our allocation in LBM for temporary storage during scaling. */ | ||
75 | struct drm_mm_node lbm; | ||
76 | }; | ||
77 | |||
78 | static inline struct vc4_plane_state * | ||
79 | to_vc4_plane_state(struct drm_plane_state *state) | ||
80 | { | ||
81 | return (struct vc4_plane_state *)state; | ||
82 | } | ||
83 | |||
84 | static const struct hvs_format { | 30 | static const struct hvs_format { |
85 | u32 drm; /* DRM_FORMAT_* */ | 31 | u32 drm; /* DRM_FORMAT_* */ |
86 | u32 hvs; /* HVS_FORMAT_* */ | 32 | u32 hvs; /* HVS_FORMAT_* */ |
@@ -521,6 +467,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, | |||
521 | u32 ctl0_offset = vc4_state->dlist_count; | 467 | u32 ctl0_offset = vc4_state->dlist_count; |
522 | const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); | 468 | const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); |
523 | int num_planes = drm_format_num_planes(format->drm); | 469 | int num_planes = drm_format_num_planes(format->drm); |
470 | bool covers_screen; | ||
524 | u32 scl0, scl1, pitch0; | 471 | u32 scl0, scl1, pitch0; |
525 | u32 lbm_size, tiling; | 472 | u32 lbm_size, tiling; |
526 | unsigned long irqflags; | 473 | unsigned long irqflags; |
@@ -618,13 +565,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane, | |||
618 | SCALER_POS1_SCL_HEIGHT)); | 565 | SCALER_POS1_SCL_HEIGHT)); |
619 | } | 566 | } |
620 | 567 | ||
621 | /* Position Word 2: Source Image Size, Alpha Mode */ | 568 | /* Position Word 2: Source Image Size, Alpha */ |
622 | vc4_state->pos2_offset = vc4_state->dlist_count; | 569 | vc4_state->pos2_offset = vc4_state->dlist_count; |
623 | vc4_dlist_write(vc4_state, | 570 | vc4_dlist_write(vc4_state, |
624 | VC4_SET_FIELD(fb->format->has_alpha ? | 571 | VC4_SET_FIELD(fb->format->has_alpha ? |
625 | SCALER_POS2_ALPHA_MODE_PIPELINE : | 572 | SCALER_POS2_ALPHA_MODE_PIPELINE : |
626 | SCALER_POS2_ALPHA_MODE_FIXED, | 573 | SCALER_POS2_ALPHA_MODE_FIXED, |
627 | SCALER_POS2_ALPHA_MODE) | | 574 | SCALER_POS2_ALPHA_MODE) | |
575 | (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) | | ||
628 | VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | | 576 | VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | |
629 | VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); | 577 | VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); |
630 | 578 | ||
@@ -700,6 +648,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, | |||
700 | vc4_state->dlist[ctl0_offset] |= | 648 | vc4_state->dlist[ctl0_offset] |= |
701 | VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); | 649 | VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); |
702 | 650 | ||
651 | /* crtc_* are already clipped coordinates. */ | ||
652 | covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 && | ||
653 | vc4_state->crtc_w == state->crtc->mode.hdisplay && | ||
654 | vc4_state->crtc_h == state->crtc->mode.vdisplay; | ||
655 | /* Background fill might be necessary when the plane has per-pixel | ||
656 | * alpha content and blends from the background or does not cover | ||
657 | * the entire screen. | ||
658 | */ | ||
659 | vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen; | ||
660 | |||
703 | return 0; | 661 | return 0; |
704 | } | 662 | } |
705 | 663 | ||
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index b9749cb24063..a141496104a6 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h | |||
@@ -848,6 +848,7 @@ enum hvs_pixel_format { | |||
848 | #define SCALER_POS2_ALPHA_MODE_FIXED 1 | 848 | #define SCALER_POS2_ALPHA_MODE_FIXED 1 |
849 | #define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2 | 849 | #define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2 |
850 | #define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3 | 850 | #define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3 |
851 | #define SCALER_POS2_ALPHA_PREMULT BIT(29) | ||
851 | 852 | ||
852 | #define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16) | 853 | #define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16) |
853 | #define SCALER_POS2_HEIGHT_SHIFT 16 | 854 | #define SCALER_POS2_HEIGHT_SHIFT 16 |
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 2db485abb186..eec76af49f04 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c | |||
@@ -753,7 +753,7 @@ validate_gl_shader_rec(struct drm_device *dev, | |||
753 | 28, /* cs */ | 753 | 28, /* cs */ |
754 | }; | 754 | }; |
755 | uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); | 755 | uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); |
756 | struct drm_gem_cma_object *bo[shader_reloc_count + 8]; | 756 | struct drm_gem_cma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8]; |
757 | uint32_t nr_attributes, nr_relocs, packet_size; | 757 | uint32_t nr_attributes, nr_relocs, packet_size; |
758 | int i; | 758 | int i; |
759 | 759 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index d23a18aae476..be7d7fb1b44b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | |||
@@ -500,7 +500,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par, | |||
500 | } | 500 | } |
501 | 501 | ||
502 | if (cur_fb) { | 502 | if (cur_fb) { |
503 | drm_framebuffer_unreference(cur_fb); | 503 | drm_framebuffer_put(cur_fb); |
504 | par->set_fb = NULL; | 504 | par->set_fb = NULL; |
505 | } | 505 | } |
506 | 506 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 67f844678ac8..c5e8eae0dbe2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | |||
@@ -316,7 +316,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, | |||
316 | out_no_surface: | 316 | out_no_surface: |
317 | ttm_read_unlock(&dev_priv->reservation_sem); | 317 | ttm_read_unlock(&dev_priv->reservation_sem); |
318 | out_no_ttm_lock: | 318 | out_no_ttm_lock: |
319 | drm_framebuffer_unreference(fb); | 319 | drm_framebuffer_put(fb); |
320 | out_no_fb: | 320 | out_no_fb: |
321 | drm_modeset_unlock_all(dev); | 321 | drm_modeset_unlock_all(dev); |
322 | out_no_copy: | 322 | out_no_copy: |
@@ -393,7 +393,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, | |||
393 | 393 | ||
394 | ttm_read_unlock(&dev_priv->reservation_sem); | 394 | ttm_read_unlock(&dev_priv->reservation_sem); |
395 | out_no_ttm_lock: | 395 | out_no_ttm_lock: |
396 | drm_framebuffer_unreference(fb); | 396 | drm_framebuffer_put(fb); |
397 | out_no_fb: | 397 | out_no_fb: |
398 | drm_modeset_unlock_all(dev); | 398 | drm_modeset_unlock_all(dev); |
399 | out_no_copy: | 399 | out_no_copy: |
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 3cd153c6d271..fc4adf3d34e8 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c | |||
@@ -92,7 +92,8 @@ | |||
92 | * struct vga_switcheroo_client - registered client | 92 | * struct vga_switcheroo_client - registered client |
93 | * @pdev: client pci device | 93 | * @pdev: client pci device |
94 | * @fb_info: framebuffer to which console is remapped on switching | 94 | * @fb_info: framebuffer to which console is remapped on switching |
95 | * @pwr_state: current power state | 95 | * @pwr_state: current power state if manual power control is used. |
96 | * For driver power control, call vga_switcheroo_pwr_state(). | ||
96 | * @ops: client callbacks | 97 | * @ops: client callbacks |
97 | * @id: client identifier. Determining the id requires the handler, | 98 | * @id: client identifier. Determining the id requires the handler, |
98 | * so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID | 99 | * so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID |
@@ -104,8 +105,7 @@ | |||
104 | * @list: client list | 105 | * @list: client list |
105 | * | 106 | * |
106 | * Registered client. A client can be either a GPU or an audio device on a GPU. | 107 | * Registered client. A client can be either a GPU or an audio device on a GPU. |
107 | * For audio clients, the @fb_info, @active and @driver_power_control members | 108 | * For audio clients, the @fb_info and @active members are bogus. |
108 | * are bogus. | ||
109 | */ | 109 | */ |
110 | struct vga_switcheroo_client { | 110 | struct vga_switcheroo_client { |
111 | struct pci_dev *pdev; | 111 | struct pci_dev *pdev; |
@@ -331,8 +331,8 @@ EXPORT_SYMBOL(vga_switcheroo_register_client); | |||
331 | * @ops: client callbacks | 331 | * @ops: client callbacks |
332 | * @id: client identifier | 332 | * @id: client identifier |
333 | * | 333 | * |
334 | * Register audio client (audio device on a GPU). The power state of the | 334 | * Register audio client (audio device on a GPU). The client is assumed |
335 | * client is assumed to be ON. Beforehand, vga_switcheroo_client_probe_defer() | 335 | * to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer() |
336 | * shall be called to ensure that all prerequisites are met. | 336 | * shall be called to ensure that all prerequisites are met. |
337 | * | 337 | * |
338 | * Return: 0 on success, -ENOMEM on memory allocation error. | 338 | * Return: 0 on success, -ENOMEM on memory allocation error. |
@@ -341,7 +341,7 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev, | |||
341 | const struct vga_switcheroo_client_ops *ops, | 341 | const struct vga_switcheroo_client_ops *ops, |
342 | enum vga_switcheroo_client_id id) | 342 | enum vga_switcheroo_client_id id) |
343 | { | 343 | { |
344 | return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false); | 344 | return register_client(pdev, ops, id | ID_BIT_AUDIO, false, true); |
345 | } | 345 | } |
346 | EXPORT_SYMBOL(vga_switcheroo_register_audio_client); | 346 | EXPORT_SYMBOL(vga_switcheroo_register_audio_client); |
347 | 347 | ||
@@ -406,6 +406,19 @@ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) | |||
406 | } | 406 | } |
407 | EXPORT_SYMBOL(vga_switcheroo_client_probe_defer); | 407 | EXPORT_SYMBOL(vga_switcheroo_client_probe_defer); |
408 | 408 | ||
409 | static enum vga_switcheroo_state | ||
410 | vga_switcheroo_pwr_state(struct vga_switcheroo_client *client) | ||
411 | { | ||
412 | if (client->driver_power_control) | ||
413 | if (pm_runtime_enabled(&client->pdev->dev) && | ||
414 | pm_runtime_active(&client->pdev->dev)) | ||
415 | return VGA_SWITCHEROO_ON; | ||
416 | else | ||
417 | return VGA_SWITCHEROO_OFF; | ||
418 | else | ||
419 | return client->pwr_state; | ||
420 | } | ||
421 | |||
409 | /** | 422 | /** |
410 | * vga_switcheroo_get_client_state() - obtain power state of a given client | 423 | * vga_switcheroo_get_client_state() - obtain power state of a given client |
411 | * @pdev: client pci device | 424 | * @pdev: client pci device |
@@ -425,7 +438,7 @@ enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev) | |||
425 | if (!client) | 438 | if (!client) |
426 | ret = VGA_SWITCHEROO_NOT_FOUND; | 439 | ret = VGA_SWITCHEROO_NOT_FOUND; |
427 | else | 440 | else |
428 | ret = client->pwr_state; | 441 | ret = vga_switcheroo_pwr_state(client); |
429 | mutex_unlock(&vgasr_mutex); | 442 | mutex_unlock(&vgasr_mutex); |
430 | return ret; | 443 | return ret; |
431 | } | 444 | } |
@@ -598,7 +611,7 @@ static int vga_switcheroo_show(struct seq_file *m, void *v) | |||
598 | client_is_vga(client) ? "" : "-Audio", | 611 | client_is_vga(client) ? "" : "-Audio", |
599 | client->active ? '+' : ' ', | 612 | client->active ? '+' : ' ', |
600 | client->driver_power_control ? "Dyn" : "", | 613 | client->driver_power_control ? "Dyn" : "", |
601 | client->pwr_state ? "Pwr" : "Off", | 614 | vga_switcheroo_pwr_state(client) ? "Pwr" : "Off", |
602 | pci_name(client->pdev)); | 615 | pci_name(client->pdev)); |
603 | i++; | 616 | i++; |
604 | } | 617 | } |
@@ -641,10 +654,8 @@ static void set_audio_state(enum vga_switcheroo_client_id id, | |||
641 | struct vga_switcheroo_client *client; | 654 | struct vga_switcheroo_client *client; |
642 | 655 | ||
643 | client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO); | 656 | client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO); |
644 | if (client && client->pwr_state != state) { | 657 | if (client) |
645 | client->ops->set_gpu_state(client->pdev, state); | 658 | client->ops->set_gpu_state(client->pdev, state); |
646 | client->pwr_state = state; | ||
647 | } | ||
648 | } | 659 | } |
649 | 660 | ||
650 | /* stage one happens before delay */ | 661 | /* stage one happens before delay */ |
@@ -656,7 +667,7 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) | |||
656 | if (!active) | 667 | if (!active) |
657 | return 0; | 668 | return 0; |
658 | 669 | ||
659 | if (new_client->pwr_state == VGA_SWITCHEROO_OFF) | 670 | if (vga_switcheroo_pwr_state(new_client) == VGA_SWITCHEROO_OFF) |
660 | vga_switchon(new_client); | 671 | vga_switchon(new_client); |
661 | 672 | ||
662 | vga_set_default_device(new_client->pdev); | 673 | vga_set_default_device(new_client->pdev); |
@@ -675,7 +686,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) | |||
675 | 686 | ||
676 | active->active = false; | 687 | active->active = false; |
677 | 688 | ||
678 | set_audio_state(active->id, VGA_SWITCHEROO_OFF); | 689 | /* let HDA controller autosuspend if GPU uses driver power control */ |
690 | if (!active->driver_power_control) | ||
691 | set_audio_state(active->id, VGA_SWITCHEROO_OFF); | ||
679 | 692 | ||
680 | if (new_client->fb_info) { | 693 | if (new_client->fb_info) { |
681 | struct fb_event event; | 694 | struct fb_event event; |
@@ -695,10 +708,12 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) | |||
695 | if (new_client->ops->reprobe) | 708 | if (new_client->ops->reprobe) |
696 | new_client->ops->reprobe(new_client->pdev); | 709 | new_client->ops->reprobe(new_client->pdev); |
697 | 710 | ||
698 | if (active->pwr_state == VGA_SWITCHEROO_ON) | 711 | if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON) |
699 | vga_switchoff(active); | 712 | vga_switchoff(active); |
700 | 713 | ||
701 | set_audio_state(new_client->id, VGA_SWITCHEROO_ON); | 714 | /* let HDA controller autoresume if GPU uses driver power control */ |
715 | if (!new_client->driver_power_control) | ||
716 | set_audio_state(new_client->id, VGA_SWITCHEROO_ON); | ||
702 | 717 | ||
703 | new_client->active = true; | 718 | new_client->active = true; |
704 | return 0; | 719 | return 0; |
@@ -939,11 +954,6 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); | |||
939 | * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel | 954 | * Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel |
940 | * command line disables it. | 955 | * command line disables it. |
941 | * | 956 | * |
942 | * When the driver decides to power up or down, it notifies vga_switcheroo | ||
943 | * thereof so that it can (a) power the audio device on the GPU up or down, | ||
944 | * and (b) update its internal power state representation for the device. | ||
945 | * This is achieved by vga_switcheroo_set_dynamic_switch(). | ||
946 | * | ||
947 | * After the GPU has been suspended, the handler needs to be called to cut | 957 | * After the GPU has been suspended, the handler needs to be called to cut |
948 | * power to the GPU. Likewise it needs to reinstate power before the GPU | 958 | * power to the GPU. Likewise it needs to reinstate power before the GPU |
949 | * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(), | 959 | * can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(), |
@@ -951,8 +961,9 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); | |||
951 | * calls to the handler. | 961 | * calls to the handler. |
952 | * | 962 | * |
953 | * When the audio device resumes, the GPU needs to be woken. This is achieved | 963 | * When the audio device resumes, the GPU needs to be woken. This is achieved |
954 | * by vga_switcheroo_init_domain_pm_optimus_hdmi_audio(), which augments the | 964 | * by a PCI quirk which calls device_link_add() to declare a dependency on the |
955 | * audio device's resume function. | 965 | * GPU. That way, the GPU is kept awake whenever and as long as the audio |
966 | * device is in use. | ||
956 | * | 967 | * |
957 | * On muxed machines, if the mux is initially switched to the discrete GPU, | 968 | * On muxed machines, if the mux is initially switched to the discrete GPU, |
958 | * the user ends up with a black screen when the GPU powers down after boot. | 969 | * the user ends up with a black screen when the GPU powers down after boot. |
@@ -978,35 +989,6 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev, | |||
978 | vgasr_priv.handler->power_state(client->id, state); | 989 | vgasr_priv.handler->power_state(client->id, state); |
979 | } | 990 | } |
980 | 991 | ||
981 | /** | ||
982 | * vga_switcheroo_set_dynamic_switch() - helper for driver power control | ||
983 | * @pdev: client pci device | ||
984 | * @dynamic: new power state | ||
985 | * | ||
986 | * Helper for GPUs whose power state is controlled by the driver's runtime pm. | ||
987 | * When the driver decides to power up or down, it notifies vga_switcheroo | ||
988 | * thereof using this helper so that it can (a) power the audio device on | ||
989 | * the GPU up or down, and (b) update its internal power state representation | ||
990 | * for the device. | ||
991 | */ | ||
992 | void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, | ||
993 | enum vga_switcheroo_state dynamic) | ||
994 | { | ||
995 | struct vga_switcheroo_client *client; | ||
996 | |||
997 | mutex_lock(&vgasr_mutex); | ||
998 | client = find_client_from_pci(&vgasr_priv.clients, pdev); | ||
999 | if (!client || !client->driver_power_control) { | ||
1000 | mutex_unlock(&vgasr_mutex); | ||
1001 | return; | ||
1002 | } | ||
1003 | |||
1004 | client->pwr_state = dynamic; | ||
1005 | set_audio_state(client->id, dynamic); | ||
1006 | mutex_unlock(&vgasr_mutex); | ||
1007 | } | ||
1008 | EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch); | ||
1009 | |||
1010 | /* switcheroo power domain */ | 992 | /* switcheroo power domain */ |
1011 | static int vga_switcheroo_runtime_suspend(struct device *dev) | 993 | static int vga_switcheroo_runtime_suspend(struct device *dev) |
1012 | { | 994 | { |
@@ -1022,6 +1004,7 @@ static int vga_switcheroo_runtime_suspend(struct device *dev) | |||
1022 | vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); | 1004 | vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD); |
1023 | mutex_unlock(&vgasr_priv.mux_hw_lock); | 1005 | mutex_unlock(&vgasr_priv.mux_hw_lock); |
1024 | } | 1006 | } |
1007 | pci_bus_set_current_state(pdev->bus, PCI_D3cold); | ||
1025 | vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF); | 1008 | vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF); |
1026 | mutex_unlock(&vgasr_mutex); | 1009 | mutex_unlock(&vgasr_mutex); |
1027 | return 0; | 1010 | return 0; |
@@ -1035,6 +1018,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev) | |||
1035 | mutex_lock(&vgasr_mutex); | 1018 | mutex_lock(&vgasr_mutex); |
1036 | vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON); | 1019 | vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON); |
1037 | mutex_unlock(&vgasr_mutex); | 1020 | mutex_unlock(&vgasr_mutex); |
1021 | pci_wakeup_bus(pdev->bus); | ||
1038 | ret = dev->bus->pm->runtime_resume(dev); | 1022 | ret = dev->bus->pm->runtime_resume(dev); |
1039 | if (ret) | 1023 | if (ret) |
1040 | return ret; | 1024 | return ret; |
@@ -1076,69 +1060,3 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev) | |||
1076 | dev_pm_domain_set(dev, NULL); | 1060 | dev_pm_domain_set(dev, NULL); |
1077 | } | 1061 | } |
1078 | EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops); | 1062 | EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops); |
1079 | |||
1080 | static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev) | ||
1081 | { | ||
1082 | struct pci_dev *pdev = to_pci_dev(dev); | ||
1083 | struct vga_switcheroo_client *client; | ||
1084 | struct device *video_dev = NULL; | ||
1085 | int ret; | ||
1086 | |||
1087 | /* we need to check if we have to switch back on the video | ||
1088 | * device so the audio device can come back | ||
1089 | */ | ||
1090 | mutex_lock(&vgasr_mutex); | ||
1091 | list_for_each_entry(client, &vgasr_priv.clients, list) { | ||
1092 | if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) && | ||
1093 | client_is_vga(client)) { | ||
1094 | video_dev = &client->pdev->dev; | ||
1095 | break; | ||
1096 | } | ||
1097 | } | ||
1098 | mutex_unlock(&vgasr_mutex); | ||
1099 | |||
1100 | if (video_dev) { | ||
1101 | ret = pm_runtime_get_sync(video_dev); | ||
1102 | if (ret && ret != 1) | ||
1103 | return ret; | ||
1104 | } | ||
1105 | ret = dev->bus->pm->runtime_resume(dev); | ||
1106 | |||
1107 | /* put the reference for the gpu */ | ||
1108 | if (video_dev) { | ||
1109 | pm_runtime_mark_last_busy(video_dev); | ||
1110 | pm_runtime_put_autosuspend(video_dev); | ||
1111 | } | ||
1112 | return ret; | ||
1113 | } | ||
1114 | |||
1115 | /** | ||
1116 | * vga_switcheroo_init_domain_pm_optimus_hdmi_audio() - helper for driver | ||
1117 | * power control | ||
1118 | * @dev: audio client device | ||
1119 | * @domain: power domain | ||
1120 | * | ||
1121 | * Helper for GPUs whose power state is controlled by the driver's runtime pm. | ||
1122 | * When the audio device resumes, the GPU needs to be woken. This helper | ||
1123 | * augments the audio device's resume function to do that. | ||
1124 | * | ||
1125 | * Return: 0 on success, -EINVAL if no power management operations are | ||
1126 | * defined for this device. | ||
1127 | */ | ||
1128 | int | ||
1129 | vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, | ||
1130 | struct dev_pm_domain *domain) | ||
1131 | { | ||
1132 | /* copy over all the bus versions */ | ||
1133 | if (dev->bus && dev->bus->pm) { | ||
1134 | domain->ops = *dev->bus->pm; | ||
1135 | domain->ops.runtime_resume = | ||
1136 | vga_switcheroo_runtime_resume_hdmi_audio; | ||
1137 | |||
1138 | dev_pm_domain_set(dev, domain); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | dev_pm_domain_set(dev, NULL); | ||
1142 | return -EINVAL; | ||
1143 | } | ||
1144 | EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio); | ||
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 3bed6beda051..6a67cdbd0e6a 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -1224,11 +1224,14 @@ static int pci_pm_runtime_suspend(struct device *dev) | |||
1224 | int error; | 1224 | int error; |
1225 | 1225 | ||
1226 | /* | 1226 | /* |
1227 | * If pci_dev->driver is not set (unbound), the device should | 1227 | * If pci_dev->driver is not set (unbound), we leave the device in D0, |
1228 | * always remain in D0 regardless of the runtime PM status | 1228 | * but it may go to D3cold when the bridge above it runtime suspends. |
1229 | * Save its config space in case that happens. | ||
1229 | */ | 1230 | */ |
1230 | if (!pci_dev->driver) | 1231 | if (!pci_dev->driver) { |
1232 | pci_save_state(pci_dev); | ||
1231 | return 0; | 1233 | return 0; |
1234 | } | ||
1232 | 1235 | ||
1233 | if (!pm || !pm->runtime_suspend) | 1236 | if (!pm || !pm->runtime_suspend) |
1234 | return -ENOSYS; | 1237 | return -ENOSYS; |
@@ -1276,16 +1279,18 @@ static int pci_pm_runtime_resume(struct device *dev) | |||
1276 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | 1279 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
1277 | 1280 | ||
1278 | /* | 1281 | /* |
1279 | * If pci_dev->driver is not set (unbound), the device should | 1282 | * Restoring config space is necessary even if the device is not bound |
1280 | * always remain in D0 regardless of the runtime PM status | 1283 | * to a driver because although we left it in D0, it may have gone to |
1284 | * D3cold when the bridge above it runtime suspended. | ||
1281 | */ | 1285 | */ |
1286 | pci_restore_standard_config(pci_dev); | ||
1287 | |||
1282 | if (!pci_dev->driver) | 1288 | if (!pci_dev->driver) |
1283 | return 0; | 1289 | return 0; |
1284 | 1290 | ||
1285 | if (!pm || !pm->runtime_resume) | 1291 | if (!pm || !pm->runtime_resume) |
1286 | return -ENOSYS; | 1292 | return -ENOSYS; |
1287 | 1293 | ||
1288 | pci_restore_standard_config(pci_dev); | ||
1289 | pci_fixup_device(pci_fixup_resume_early, pci_dev); | 1294 | pci_fixup_device(pci_fixup_resume_early, pci_dev); |
1290 | pci_enable_wake(pci_dev, PCI_D0, false); | 1295 | pci_enable_wake(pci_dev, PCI_D0, false); |
1291 | pci_fixup_device(pci_fixup_resume, pci_dev); | 1296 | pci_fixup_device(pci_fixup_resume, pci_dev); |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f6a4dd10d9b0..bd6f156dc3cf 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -800,7 +800,7 @@ static int pci_wakeup(struct pci_dev *pci_dev, void *ign) | |||
800 | * pci_wakeup_bus - Walk given bus and wake up devices on it | 800 | * pci_wakeup_bus - Walk given bus and wake up devices on it |
801 | * @bus: Top bus of the subtree to walk. | 801 | * @bus: Top bus of the subtree to walk. |
802 | */ | 802 | */ |
803 | static void pci_wakeup_bus(struct pci_bus *bus) | 803 | void pci_wakeup_bus(struct pci_bus *bus) |
804 | { | 804 | { |
805 | if (bus) | 805 | if (bus) |
806 | pci_walk_bus(bus, pci_wakeup, NULL); | 806 | pci_walk_bus(bus, pci_wakeup, NULL); |
@@ -850,11 +850,11 @@ static int __pci_dev_set_current_state(struct pci_dev *dev, void *data) | |||
850 | } | 850 | } |
851 | 851 | ||
852 | /** | 852 | /** |
853 | * __pci_bus_set_current_state - Walk given bus and set current state of devices | 853 | * pci_bus_set_current_state - Walk given bus and set current state of devices |
854 | * @bus: Top bus of the subtree to walk. | 854 | * @bus: Top bus of the subtree to walk. |
855 | * @state: state to be set | 855 | * @state: state to be set |
856 | */ | 856 | */ |
857 | static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state) | 857 | void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state) |
858 | { | 858 | { |
859 | if (bus) | 859 | if (bus) |
860 | pci_walk_bus(bus, __pci_dev_set_current_state, &state); | 860 | pci_walk_bus(bus, __pci_dev_set_current_state, &state); |
@@ -876,7 +876,7 @@ int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state) | |||
876 | ret = pci_platform_power_transition(dev, state); | 876 | ret = pci_platform_power_transition(dev, state); |
877 | /* Power off the bridge may power off the whole hierarchy */ | 877 | /* Power off the bridge may power off the whole hierarchy */ |
878 | if (!ret && state == PCI_D3cold) | 878 | if (!ret && state == PCI_D3cold) |
879 | __pci_bus_set_current_state(dev->subordinate, PCI_D3cold); | 879 | pci_bus_set_current_state(dev->subordinate, PCI_D3cold); |
880 | return ret; | 880 | return ret; |
881 | } | 881 | } |
882 | EXPORT_SYMBOL_GPL(__pci_complete_power_transition); | 882 | EXPORT_SYMBOL_GPL(__pci_complete_power_transition); |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index fc734014206f..ec582d37c189 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/ktime.h> | 26 | #include <linux/ktime.h> |
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/platform_data/x86/apple.h> | 28 | #include <linux/platform_data/x86/apple.h> |
29 | #include <linux/pm_runtime.h> | ||
29 | #include <asm/dma.h> /* isa_dma_bridge_buggy */ | 30 | #include <asm/dma.h> /* isa_dma_bridge_buggy */ |
30 | #include "pci.h" | 31 | #include "pci.h" |
31 | 32 | ||
@@ -4832,3 +4833,41 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev) | |||
4832 | pdev->no_msi = 1; | 4833 | pdev->no_msi = 1; |
4833 | } | 4834 | } |
4834 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); | 4835 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); |
4836 | |||
4837 | /* | ||
4838 | * GPUs with integrated HDA controller for streaming audio to attached displays | ||
4839 | * need a device link from the HDA controller (consumer) to the GPU (supplier) | ||
4840 | * so that the GPU is powered up whenever the HDA controller is accessed. | ||
4841 | * The GPU and HDA controller are functions 0 and 1 of the same PCI device. | ||
4842 | * The device link stays in place until shutdown (or removal of the PCI device | ||
4843 | * if it's hotplugged). Runtime PM is allowed by default on the HDA controller | ||
4844 | * to prevent it from permanently keeping the GPU awake. | ||
4845 | */ | ||
4846 | static void quirk_gpu_hda(struct pci_dev *hda) | ||
4847 | { | ||
4848 | struct pci_dev *gpu; | ||
4849 | |||
4850 | if (PCI_FUNC(hda->devfn) != 1) | ||
4851 | return; | ||
4852 | |||
4853 | gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus), | ||
4854 | hda->bus->number, | ||
4855 | PCI_DEVFN(PCI_SLOT(hda->devfn), 0)); | ||
4856 | if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) { | ||
4857 | pci_dev_put(gpu); | ||
4858 | return; | ||
4859 | } | ||
4860 | |||
4861 | if (!device_link_add(&hda->dev, &gpu->dev, | ||
4862 | DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) | ||
4863 | pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu)); | ||
4864 | |||
4865 | pm_runtime_allow(&hda->dev); | ||
4866 | pci_dev_put(gpu); | ||
4867 | } | ||
4868 | DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID, | ||
4869 | PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); | ||
4870 | DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID, | ||
4871 | PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); | ||
4872 | DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, | ||
4873 | PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); | ||