diff options
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_crtc.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_dotclock.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_rgb.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 92 | ||||
| -rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 |
5 files changed, 60 insertions, 44 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 5decae0069d0..78cbc3145e44 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c | |||
| @@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, | |||
| 93 | 93 | ||
| 94 | DRM_DEBUG_DRIVER("Disabling the CRTC\n"); | 94 | DRM_DEBUG_DRIVER("Disabling the CRTC\n"); |
| 95 | 95 | ||
| 96 | drm_crtc_vblank_off(crtc); | ||
| 97 | |||
| 96 | sun4i_tcon_set_status(scrtc->tcon, encoder, false); | 98 | sun4i_tcon_set_status(scrtc->tcon, encoder, false); |
| 97 | 99 | ||
| 98 | if (crtc->state->event && !crtc->state->active) { | 100 | if (crtc->state->event && !crtc->state->active) { |
| @@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc, | |||
| 113 | DRM_DEBUG_DRIVER("Enabling the CRTC\n"); | 115 | DRM_DEBUG_DRIVER("Enabling the CRTC\n"); |
| 114 | 116 | ||
| 115 | sun4i_tcon_set_status(scrtc->tcon, encoder, true); | 117 | sun4i_tcon_set_status(scrtc->tcon, encoder, true); |
| 118 | |||
| 119 | drm_crtc_vblank_on(crtc); | ||
| 116 | } | 120 | } |
| 117 | 121 | ||
| 118 | static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) | 122 | static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc) |
diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 023f39bda633..e36004fbe453 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c | |||
| @@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw) | |||
| 132 | static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) | 132 | static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees) |
| 133 | { | 133 | { |
| 134 | struct sun4i_dclk *dclk = hw_to_dclk(hw); | 134 | struct sun4i_dclk *dclk = hw_to_dclk(hw); |
| 135 | u32 val = degrees / 120; | ||
| 136 | |||
| 137 | val <<= 28; | ||
| 135 | 138 | ||
| 136 | regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, | 139 | regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG, |
| 137 | GENMASK(29, 28), | 140 | GENMASK(29, 28), |
| 138 | degrees / 120); | 141 | val); |
| 139 | 142 | ||
| 140 | return 0; | 143 | return 0; |
| 141 | } | 144 | } |
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 832f8f9bc47f..b8da5a50a61d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c | |||
| @@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, | |||
| 92 | 92 | ||
| 93 | DRM_DEBUG_DRIVER("Vertical parameters OK\n"); | 93 | DRM_DEBUG_DRIVER("Vertical parameters OK\n"); |
| 94 | 94 | ||
| 95 | tcon->dclk_min_div = 6; | ||
| 96 | tcon->dclk_max_div = 127; | ||
| 95 | rounded_rate = clk_round_rate(tcon->dclk, rate); | 97 | rounded_rate = clk_round_rate(tcon->dclk, rate); |
| 96 | if (rounded_rate < rate) | 98 | if (rounded_rate < rate) |
| 97 | return MODE_CLOCK_LOW; | 99 | return MODE_CLOCK_LOW; |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index b3960118deb9..2de586b7c98b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c | |||
| @@ -101,10 +101,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, | |||
| 101 | return; | 101 | return; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | if (enabled) | 104 | if (enabled) { |
| 105 | clk_prepare_enable(clk); | 105 | clk_prepare_enable(clk); |
| 106 | else | 106 | } else { |
| 107 | clk_rate_exclusive_put(clk); | ||
| 107 | clk_disable_unprepare(clk); | 108 | clk_disable_unprepare(clk); |
| 109 | } | ||
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, | 112 | static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, |
| @@ -873,52 +875,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, | |||
| 873 | return ret; | 875 | return ret; |
| 874 | } | 876 | } |
| 875 | 877 | ||
| 876 | /* | 878 | if (tcon->quirks->supports_lvds) { |
| 877 | * This can only be made optional since we've had DT nodes | 879 | /* |
| 878 | * without the LVDS reset properties. | 880 | * This can only be made optional since we've had DT |
| 879 | * | 881 | * nodes without the LVDS reset properties. |
| 880 | * If the property is missing, just disable LVDS, and print a | 882 | * |
| 881 | * warning. | 883 | * If the property is missing, just disable LVDS, and |
| 882 | */ | 884 | * print a warning. |
| 883 | tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); | 885 | */ |
| 884 | if (IS_ERR(tcon->lvds_rst)) { | 886 | tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); |
| 885 | dev_err(dev, "Couldn't get our reset line\n"); | 887 | if (IS_ERR(tcon->lvds_rst)) { |
| 886 | return PTR_ERR(tcon->lvds_rst); | 888 | dev_err(dev, "Couldn't get our reset line\n"); |
| 887 | } else if (tcon->lvds_rst) { | 889 | return PTR_ERR(tcon->lvds_rst); |
| 888 | has_lvds_rst = true; | 890 | } else if (tcon->lvds_rst) { |
| 889 | reset_control_reset(tcon->lvds_rst); | 891 | has_lvds_rst = true; |
| 890 | } else { | 892 | reset_control_reset(tcon->lvds_rst); |
| 891 | has_lvds_rst = false; | 893 | } else { |
| 892 | } | 894 | has_lvds_rst = false; |
| 895 | } | ||
| 893 | 896 | ||
| 894 | /* | 897 | /* |
| 895 | * This can only be made optional since we've had DT nodes | 898 | * This can only be made optional since we've had DT |
| 896 | * without the LVDS reset properties. | 899 | * nodes without the LVDS reset properties. |
| 897 | * | 900 | * |
| 898 | * If the property is missing, just disable LVDS, and print a | 901 | * If the property is missing, just disable LVDS, and |
| 899 | * warning. | 902 | * print a warning. |
| 900 | */ | 903 | */ |
| 901 | if (tcon->quirks->has_lvds_alt) { | 904 | if (tcon->quirks->has_lvds_alt) { |
| 902 | tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); | 905 | tcon->lvds_pll = devm_clk_get(dev, "lvds-alt"); |
| 903 | if (IS_ERR(tcon->lvds_pll)) { | 906 | if (IS_ERR(tcon->lvds_pll)) { |
| 904 | if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { | 907 | if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { |
| 905 | has_lvds_alt = false; | 908 | has_lvds_alt = false; |
| 909 | } else { | ||
| 910 | dev_err(dev, "Couldn't get the LVDS PLL\n"); | ||
| 911 | return PTR_ERR(tcon->lvds_pll); | ||
| 912 | } | ||
| 906 | } else { | 913 | } else { |
| 907 | dev_err(dev, "Couldn't get the LVDS PLL\n"); | 914 | has_lvds_alt = true; |
| 908 | return PTR_ERR(tcon->lvds_pll); | ||
| 909 | } | 915 | } |
| 910 | } else { | ||
| 911 | has_lvds_alt = true; | ||
| 912 | } | 916 | } |
| 913 | } | ||
| 914 | 917 | ||
| 915 | if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { | 918 | if (!has_lvds_rst || |
| 916 | dev_warn(dev, | 919 | (tcon->quirks->has_lvds_alt && !has_lvds_alt)) { |
| 917 | "Missing LVDS properties, Please upgrade your DT\n"); | 920 | dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n"); |
| 918 | dev_warn(dev, "LVDS output disabled\n"); | 921 | dev_warn(dev, "LVDS output disabled\n"); |
| 919 | can_lvds = false; | 922 | can_lvds = false; |
| 923 | } else { | ||
| 924 | can_lvds = true; | ||
| 925 | } | ||
| 920 | } else { | 926 | } else { |
| 921 | can_lvds = true; | 927 | can_lvds = false; |
| 922 | } | 928 | } |
| 923 | 929 | ||
| 924 | ret = sun4i_tcon_init_clocks(dev, tcon); | 930 | ret = sun4i_tcon_init_clocks(dev, tcon); |
| @@ -1137,7 +1143,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = { | |||
| 1137 | }; | 1143 | }; |
| 1138 | 1144 | ||
| 1139 | static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { | 1145 | static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { |
| 1140 | /* nothing is supported */ | 1146 | .supports_lvds = true, |
| 1141 | }; | 1147 | }; |
| 1142 | 1148 | ||
| 1143 | static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { | 1149 | static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index b761c7b823c5..278700c7bf9f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h | |||
| @@ -175,6 +175,7 @@ struct sun4i_tcon_quirks { | |||
| 175 | bool has_channel_1; /* a33 does not have channel 1 */ | 175 | bool has_channel_1; /* a33 does not have channel 1 */ |
| 176 | bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ | 176 | bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */ |
| 177 | bool needs_de_be_mux; /* sun6i needs mux to select backend */ | 177 | bool needs_de_be_mux; /* sun6i needs mux to select backend */ |
| 178 | bool supports_lvds; /* Does the TCON support an LVDS output? */ | ||
| 178 | 179 | ||
| 179 | /* callback to handle tcon muxing options */ | 180 | /* callback to handle tcon muxing options */ |
| 180 | int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); | 181 | int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); |
