diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/sor.c')
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 716 |
1 files changed, 485 insertions, 231 deletions
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 34958d71284b..74d0540b8d4c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c | |||
@@ -7,11 +7,13 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
10 | #include <linux/clk-provider.h> | ||
10 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
11 | #include <linux/gpio.h> | 12 | #include <linux/gpio.h> |
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
13 | #include <linux/of_device.h> | 14 | #include <linux/of_device.h> |
14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> | ||
15 | #include <linux/regulator/consumer.h> | 17 | #include <linux/regulator/consumer.h> |
16 | #include <linux/reset.h> | 18 | #include <linux/reset.h> |
17 | 19 | ||
@@ -149,6 +151,8 @@ struct tegra_sor_soc { | |||
149 | 151 | ||
150 | const struct tegra_sor_hdmi_settings *settings; | 152 | const struct tegra_sor_hdmi_settings *settings; |
151 | unsigned int num_settings; | 153 | unsigned int num_settings; |
154 | |||
155 | const u8 *xbar_cfg; | ||
152 | }; | 156 | }; |
153 | 157 | ||
154 | struct tegra_sor; | 158 | struct tegra_sor; |
@@ -169,7 +173,9 @@ struct tegra_sor { | |||
169 | 173 | ||
170 | struct reset_control *rst; | 174 | struct reset_control *rst; |
171 | struct clk *clk_parent; | 175 | struct clk *clk_parent; |
176 | struct clk *clk_brick; | ||
172 | struct clk *clk_safe; | 177 | struct clk *clk_safe; |
178 | struct clk *clk_src; | ||
173 | struct clk *clk_dp; | 179 | struct clk *clk_dp; |
174 | struct clk *clk; | 180 | struct clk *clk; |
175 | 181 | ||
@@ -190,6 +196,18 @@ struct tegra_sor { | |||
190 | struct regulator *hdmi_supply; | 196 | struct regulator *hdmi_supply; |
191 | }; | 197 | }; |
192 | 198 | ||
199 | struct tegra_sor_state { | ||
200 | struct drm_connector_state base; | ||
201 | |||
202 | unsigned int bpc; | ||
203 | }; | ||
204 | |||
205 | static inline struct tegra_sor_state * | ||
206 | to_sor_state(struct drm_connector_state *state) | ||
207 | { | ||
208 | return container_of(state, struct tegra_sor_state, base); | ||
209 | } | ||
210 | |||
193 | struct tegra_sor_config { | 211 | struct tegra_sor_config { |
194 | u32 bits_per_pixel; | 212 | u32 bits_per_pixel; |
195 | 213 | ||
@@ -225,6 +243,118 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, | |||
225 | writel(value, sor->regs + (offset << 2)); | 243 | writel(value, sor->regs + (offset << 2)); |
226 | } | 244 | } |
227 | 245 | ||
246 | static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent) | ||
247 | { | ||
248 | int err; | ||
249 | |||
250 | clk_disable_unprepare(sor->clk); | ||
251 | |||
252 | err = clk_set_parent(sor->clk, parent); | ||
253 | if (err < 0) | ||
254 | return err; | ||
255 | |||
256 | err = clk_prepare_enable(sor->clk); | ||
257 | if (err < 0) | ||
258 | return err; | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | struct tegra_clk_sor_brick { | ||
264 | struct clk_hw hw; | ||
265 | struct tegra_sor *sor; | ||
266 | }; | ||
267 | |||
268 | static inline struct tegra_clk_sor_brick *to_brick(struct clk_hw *hw) | ||
269 | { | ||
270 | return container_of(hw, struct tegra_clk_sor_brick, hw); | ||
271 | } | ||
272 | |||
273 | static const char * const tegra_clk_sor_brick_parents[] = { | ||
274 | "pll_d2_out0", "pll_dp" | ||
275 | }; | ||
276 | |||
277 | static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index) | ||
278 | { | ||
279 | struct tegra_clk_sor_brick *brick = to_brick(hw); | ||
280 | struct tegra_sor *sor = brick->sor; | ||
281 | u32 value; | ||
282 | |||
283 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); | ||
284 | value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; | ||
285 | |||
286 | switch (index) { | ||
287 | case 0: | ||
288 | value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; | ||
289 | break; | ||
290 | |||
291 | case 1: | ||
292 | value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; | ||
293 | break; | ||
294 | } | ||
295 | |||
296 | tegra_sor_writel(sor, value, SOR_CLK_CNTRL); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw) | ||
302 | { | ||
303 | struct tegra_clk_sor_brick *brick = to_brick(hw); | ||
304 | struct tegra_sor *sor = brick->sor; | ||
305 | u8 parent = U8_MAX; | ||
306 | u32 value; | ||
307 | |||
308 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); | ||
309 | |||
310 | switch (value & SOR_CLK_CNTRL_DP_CLK_SEL_MASK) { | ||
311 | case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK: | ||
312 | case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK: | ||
313 | parent = 0; | ||
314 | break; | ||
315 | |||
316 | case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK: | ||
317 | case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK: | ||
318 | parent = 1; | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | return parent; | ||
323 | } | ||
324 | |||
325 | static const struct clk_ops tegra_clk_sor_brick_ops = { | ||
326 | .set_parent = tegra_clk_sor_brick_set_parent, | ||
327 | .get_parent = tegra_clk_sor_brick_get_parent, | ||
328 | }; | ||
329 | |||
330 | static struct clk *tegra_clk_sor_brick_register(struct tegra_sor *sor, | ||
331 | const char *name) | ||
332 | { | ||
333 | struct tegra_clk_sor_brick *brick; | ||
334 | struct clk_init_data init; | ||
335 | struct clk *clk; | ||
336 | |||
337 | brick = devm_kzalloc(sor->dev, sizeof(*brick), GFP_KERNEL); | ||
338 | if (!brick) | ||
339 | return ERR_PTR(-ENOMEM); | ||
340 | |||
341 | brick->sor = sor; | ||
342 | |||
343 | init.name = name; | ||
344 | init.flags = 0; | ||
345 | init.parent_names = tegra_clk_sor_brick_parents; | ||
346 | init.num_parents = ARRAY_SIZE(tegra_clk_sor_brick_parents); | ||
347 | init.ops = &tegra_clk_sor_brick_ops; | ||
348 | |||
349 | brick->hw.init = &init; | ||
350 | |||
351 | clk = devm_clk_register(sor->dev, &brick->hw); | ||
352 | if (IS_ERR(clk)) | ||
353 | kfree(brick); | ||
354 | |||
355 | return clk; | ||
356 | } | ||
357 | |||
228 | static int tegra_sor_dp_train_fast(struct tegra_sor *sor, | 358 | static int tegra_sor_dp_train_fast(struct tegra_sor *sor, |
229 | struct drm_dp_link *link) | 359 | struct drm_dp_link *link) |
230 | { | 360 | { |
@@ -569,10 +699,10 @@ static int tegra_sor_compute_params(struct tegra_sor *sor, | |||
569 | return false; | 699 | return false; |
570 | } | 700 | } |
571 | 701 | ||
572 | static int tegra_sor_calc_config(struct tegra_sor *sor, | 702 | static int tegra_sor_compute_config(struct tegra_sor *sor, |
573 | const struct drm_display_mode *mode, | 703 | const struct drm_display_mode *mode, |
574 | struct tegra_sor_config *config, | 704 | struct tegra_sor_config *config, |
575 | struct drm_dp_link *link) | 705 | struct drm_dp_link *link) |
576 | { | 706 | { |
577 | const u64 f = 100000, link_rate = link->rate * 1000; | 707 | const u64 f = 100000, link_rate = link->rate * 1000; |
578 | const u64 pclk = mode->clock * 1000; | 708 | const u64 pclk = mode->clock * 1000; |
@@ -661,6 +791,135 @@ static int tegra_sor_calc_config(struct tegra_sor *sor, | |||
661 | return 0; | 791 | return 0; |
662 | } | 792 | } |
663 | 793 | ||
794 | static void tegra_sor_apply_config(struct tegra_sor *sor, | ||
795 | const struct tegra_sor_config *config) | ||
796 | { | ||
797 | u32 value; | ||
798 | |||
799 | value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); | ||
800 | value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; | ||
801 | value |= SOR_DP_LINKCTL_TU_SIZE(config->tu_size); | ||
802 | tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); | ||
803 | |||
804 | value = tegra_sor_readl(sor, SOR_DP_CONFIG0); | ||
805 | value &= ~SOR_DP_CONFIG_WATERMARK_MASK; | ||
806 | value |= SOR_DP_CONFIG_WATERMARK(config->watermark); | ||
807 | |||
808 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; | ||
809 | value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config->active_count); | ||
810 | |||
811 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; | ||
812 | value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config->active_frac); | ||
813 | |||
814 | if (config->active_polarity) | ||
815 | value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
816 | else | ||
817 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
818 | |||
819 | value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; | ||
820 | value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; | ||
821 | tegra_sor_writel(sor, value, SOR_DP_CONFIG0); | ||
822 | |||
823 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
824 | value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; | ||
825 | value |= config->hblank_symbols & 0xffff; | ||
826 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
827 | |||
828 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
829 | value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; | ||
830 | value |= config->vblank_symbols & 0xffff; | ||
831 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
832 | } | ||
833 | |||
834 | static void tegra_sor_mode_set(struct tegra_sor *sor, | ||
835 | const struct drm_display_mode *mode, | ||
836 | struct tegra_sor_state *state) | ||
837 | { | ||
838 | struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); | ||
839 | unsigned int vbe, vse, hbe, hse, vbs, hbs; | ||
840 | u32 value; | ||
841 | |||
842 | value = tegra_sor_readl(sor, SOR_STATE1); | ||
843 | value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK; | ||
844 | value &= ~SOR_STATE_ASY_CRC_MODE_MASK; | ||
845 | value &= ~SOR_STATE_ASY_OWNER_MASK; | ||
846 | |||
847 | value |= SOR_STATE_ASY_CRC_MODE_COMPLETE | | ||
848 | SOR_STATE_ASY_OWNER(dc->pipe + 1); | ||
849 | |||
850 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
851 | value &= ~SOR_STATE_ASY_HSYNCPOL; | ||
852 | |||
853 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
854 | value |= SOR_STATE_ASY_HSYNCPOL; | ||
855 | |||
856 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
857 | value &= ~SOR_STATE_ASY_VSYNCPOL; | ||
858 | |||
859 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
860 | value |= SOR_STATE_ASY_VSYNCPOL; | ||
861 | |||
862 | switch (state->bpc) { | ||
863 | case 16: | ||
864 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_48_444; | ||
865 | break; | ||
866 | |||
867 | case 12: | ||
868 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_36_444; | ||
869 | break; | ||
870 | |||
871 | case 10: | ||
872 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_30_444; | ||
873 | break; | ||
874 | |||
875 | case 8: | ||
876 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
877 | break; | ||
878 | |||
879 | case 6: | ||
880 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; | ||
881 | break; | ||
882 | |||
883 | default: | ||
884 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
885 | break; | ||
886 | } | ||
887 | |||
888 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
889 | |||
890 | /* | ||
891 | * TODO: The video timing programming below doesn't seem to match the | ||
892 | * register definitions. | ||
893 | */ | ||
894 | |||
895 | value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); | ||
896 | tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); | ||
897 | |||
898 | /* sync end = sync width - 1 */ | ||
899 | vse = mode->vsync_end - mode->vsync_start - 1; | ||
900 | hse = mode->hsync_end - mode->hsync_start - 1; | ||
901 | |||
902 | value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); | ||
903 | tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); | ||
904 | |||
905 | /* blank end = sync end + back porch */ | ||
906 | vbe = vse + (mode->vtotal - mode->vsync_end); | ||
907 | hbe = hse + (mode->htotal - mode->hsync_end); | ||
908 | |||
909 | value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); | ||
910 | tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); | ||
911 | |||
912 | /* blank start = blank end + active */ | ||
913 | vbs = vbe + mode->vdisplay; | ||
914 | hbs = hbe + mode->hdisplay; | ||
915 | |||
916 | value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); | ||
917 | tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); | ||
918 | |||
919 | /* XXX interlacing support */ | ||
920 | tegra_sor_writel(sor, 0x001, SOR_HEAD_STATE5(dc->pipe)); | ||
921 | } | ||
922 | |||
664 | static int tegra_sor_detach(struct tegra_sor *sor) | 923 | static int tegra_sor_detach(struct tegra_sor *sor) |
665 | { | 924 | { |
666 | unsigned long value, timeout; | 925 | unsigned long value, timeout; |
@@ -733,7 +992,8 @@ static int tegra_sor_power_down(struct tegra_sor *sor) | |||
733 | if ((value & SOR_PWR_TRIGGER) != 0) | 992 | if ((value & SOR_PWR_TRIGGER) != 0) |
734 | return -ETIMEDOUT; | 993 | return -ETIMEDOUT; |
735 | 994 | ||
736 | err = clk_set_parent(sor->clk, sor->clk_safe); | 995 | /* switch to safe parent clock */ |
996 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
737 | if (err < 0) | 997 | if (err < 0) |
738 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 998 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
739 | 999 | ||
@@ -1038,6 +1298,22 @@ static void tegra_sor_debugfs_exit(struct tegra_sor *sor) | |||
1038 | sor->debugfs = NULL; | 1298 | sor->debugfs = NULL; |
1039 | } | 1299 | } |
1040 | 1300 | ||
1301 | static void tegra_sor_connector_reset(struct drm_connector *connector) | ||
1302 | { | ||
1303 | struct tegra_sor_state *state; | ||
1304 | |||
1305 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
1306 | if (!state) | ||
1307 | return; | ||
1308 | |||
1309 | if (connector->state) { | ||
1310 | __drm_atomic_helper_connector_destroy_state(connector->state); | ||
1311 | kfree(connector->state); | ||
1312 | } | ||
1313 | |||
1314 | __drm_atomic_helper_connector_reset(connector, &state->base); | ||
1315 | } | ||
1316 | |||
1041 | static enum drm_connector_status | 1317 | static enum drm_connector_status |
1042 | tegra_sor_connector_detect(struct drm_connector *connector, bool force) | 1318 | tegra_sor_connector_detect(struct drm_connector *connector, bool force) |
1043 | { | 1319 | { |
@@ -1050,13 +1326,28 @@ tegra_sor_connector_detect(struct drm_connector *connector, bool force) | |||
1050 | return tegra_output_connector_detect(connector, force); | 1326 | return tegra_output_connector_detect(connector, force); |
1051 | } | 1327 | } |
1052 | 1328 | ||
1329 | static struct drm_connector_state * | ||
1330 | tegra_sor_connector_duplicate_state(struct drm_connector *connector) | ||
1331 | { | ||
1332 | struct tegra_sor_state *state = to_sor_state(connector->state); | ||
1333 | struct tegra_sor_state *copy; | ||
1334 | |||
1335 | copy = kmemdup(state, sizeof(*state), GFP_KERNEL); | ||
1336 | if (!copy) | ||
1337 | return NULL; | ||
1338 | |||
1339 | __drm_atomic_helper_connector_duplicate_state(connector, ©->base); | ||
1340 | |||
1341 | return ©->base; | ||
1342 | } | ||
1343 | |||
1053 | static const struct drm_connector_funcs tegra_sor_connector_funcs = { | 1344 | static const struct drm_connector_funcs tegra_sor_connector_funcs = { |
1054 | .dpms = drm_atomic_helper_connector_dpms, | 1345 | .dpms = drm_atomic_helper_connector_dpms, |
1055 | .reset = drm_atomic_helper_connector_reset, | 1346 | .reset = tegra_sor_connector_reset, |
1056 | .detect = tegra_sor_connector_detect, | 1347 | .detect = tegra_sor_connector_detect, |
1057 | .fill_modes = drm_helper_probe_single_connector_modes, | 1348 | .fill_modes = drm_helper_probe_single_connector_modes, |
1058 | .destroy = tegra_output_connector_destroy, | 1349 | .destroy = tegra_output_connector_destroy, |
1059 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 1350 | .atomic_duplicate_state = tegra_sor_connector_duplicate_state, |
1060 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 1351 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
1061 | }; | 1352 | }; |
1062 | 1353 | ||
@@ -1081,6 +1372,10 @@ static enum drm_mode_status | |||
1081 | tegra_sor_connector_mode_valid(struct drm_connector *connector, | 1372 | tegra_sor_connector_mode_valid(struct drm_connector *connector, |
1082 | struct drm_display_mode *mode) | 1373 | struct drm_display_mode *mode) |
1083 | { | 1374 | { |
1375 | /* HDMI 2.0 modes are not yet supported */ | ||
1376 | if (mode->clock > 340000) | ||
1377 | return MODE_NOCLOCK; | ||
1378 | |||
1084 | return MODE_OK; | 1379 | return MODE_OK; |
1085 | } | 1380 | } |
1086 | 1381 | ||
@@ -1140,8 +1435,7 @@ static void tegra_sor_edp_disable(struct drm_encoder *encoder) | |||
1140 | if (output->panel) | 1435 | if (output->panel) |
1141 | drm_panel_unprepare(output->panel); | 1436 | drm_panel_unprepare(output->panel); |
1142 | 1437 | ||
1143 | reset_control_assert(sor->rst); | 1438 | pm_runtime_put(sor->dev); |
1144 | clk_disable_unprepare(sor->clk); | ||
1145 | } | 1439 | } |
1146 | 1440 | ||
1147 | #if 0 | 1441 | #if 0 |
@@ -1191,19 +1485,18 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1191 | struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; | 1485 | struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; |
1192 | struct tegra_output *output = encoder_to_output(encoder); | 1486 | struct tegra_output *output = encoder_to_output(encoder); |
1193 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 1487 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
1194 | unsigned int vbe, vse, hbe, hse, vbs, hbs, i; | ||
1195 | struct tegra_sor *sor = to_sor(output); | 1488 | struct tegra_sor *sor = to_sor(output); |
1196 | struct tegra_sor_config config; | 1489 | struct tegra_sor_config config; |
1490 | struct tegra_sor_state *state; | ||
1197 | struct drm_dp_link link; | 1491 | struct drm_dp_link link; |
1198 | u8 rate, lanes; | 1492 | u8 rate, lanes; |
1493 | unsigned int i; | ||
1199 | int err = 0; | 1494 | int err = 0; |
1200 | u32 value; | 1495 | u32 value; |
1201 | 1496 | ||
1202 | err = clk_prepare_enable(sor->clk); | 1497 | state = to_sor_state(output->connector.state); |
1203 | if (err < 0) | ||
1204 | dev_err(sor->dev, "failed to enable clock: %d\n", err); | ||
1205 | 1498 | ||
1206 | reset_control_deassert(sor->rst); | 1499 | pm_runtime_get_sync(sor->dev); |
1207 | 1500 | ||
1208 | if (output->panel) | 1501 | if (output->panel) |
1209 | drm_panel_prepare(output->panel); | 1502 | drm_panel_prepare(output->panel); |
@@ -1218,17 +1511,17 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1218 | return; | 1511 | return; |
1219 | } | 1512 | } |
1220 | 1513 | ||
1221 | err = clk_set_parent(sor->clk, sor->clk_safe); | 1514 | /* switch to safe parent clock */ |
1515 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
1222 | if (err < 0) | 1516 | if (err < 0) |
1223 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 1517 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
1224 | 1518 | ||
1225 | memset(&config, 0, sizeof(config)); | 1519 | memset(&config, 0, sizeof(config)); |
1226 | config.bits_per_pixel = output->connector.display_info.bpc * 3; | 1520 | config.bits_per_pixel = state->bpc * 3; |
1227 | 1521 | ||
1228 | err = tegra_sor_calc_config(sor, mode, &config, &link); | 1522 | err = tegra_sor_compute_config(sor, mode, &config, &link); |
1229 | if (err < 0) | 1523 | if (err < 0) |
1230 | dev_err(sor->dev, "failed to compute link configuration: %d\n", | 1524 | dev_err(sor->dev, "failed to compute configuration: %d\n", err); |
1231 | err); | ||
1232 | 1525 | ||
1233 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); | 1526 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); |
1234 | value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; | 1527 | value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; |
@@ -1325,10 +1618,18 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1325 | value &= ~SOR_PLL2_PORT_POWERDOWN; | 1618 | value &= ~SOR_PLL2_PORT_POWERDOWN; |
1326 | tegra_sor_writel(sor, value, SOR_PLL2); | 1619 | tegra_sor_writel(sor, value, SOR_PLL2); |
1327 | 1620 | ||
1328 | /* switch to DP clock */ | 1621 | /* XXX not in TRM */ |
1329 | err = clk_set_parent(sor->clk, sor->clk_dp); | 1622 | for (value = 0, i = 0; i < 5; i++) |
1623 | value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | | ||
1624 | SOR_XBAR_CTRL_LINK1_XSEL(i, i); | ||
1625 | |||
1626 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); | ||
1627 | tegra_sor_writel(sor, value, SOR_XBAR_CTRL); | ||
1628 | |||
1629 | /* switch to DP parent clock */ | ||
1630 | err = tegra_sor_set_parent_clock(sor, sor->clk_dp); | ||
1330 | if (err < 0) | 1631 | if (err < 0) |
1331 | dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); | 1632 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); |
1332 | 1633 | ||
1333 | /* power DP lanes */ | 1634 | /* power DP lanes */ |
1334 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); | 1635 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); |
@@ -1374,13 +1675,11 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1374 | value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; | 1675 | value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; |
1375 | tegra_sor_writel(sor, value, SOR_CLK_CNTRL); | 1676 | tegra_sor_writel(sor, value, SOR_CLK_CNTRL); |
1376 | 1677 | ||
1377 | /* set linkctl */ | 1678 | tegra_sor_apply_config(sor, &config); |
1679 | |||
1680 | /* enable link */ | ||
1378 | value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); | 1681 | value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); |
1379 | value |= SOR_DP_LINKCTL_ENABLE; | 1682 | value |= SOR_DP_LINKCTL_ENABLE; |
1380 | |||
1381 | value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; | ||
1382 | value |= SOR_DP_LINKCTL_TU_SIZE(config.tu_size); | ||
1383 | |||
1384 | value |= SOR_DP_LINKCTL_ENHANCED_FRAME; | 1683 | value |= SOR_DP_LINKCTL_ENHANCED_FRAME; |
1385 | tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); | 1684 | tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); |
1386 | 1685 | ||
@@ -1393,35 +1692,6 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1393 | 1692 | ||
1394 | tegra_sor_writel(sor, value, SOR_DP_TPG); | 1693 | tegra_sor_writel(sor, value, SOR_DP_TPG); |
1395 | 1694 | ||
1396 | value = tegra_sor_readl(sor, SOR_DP_CONFIG0); | ||
1397 | value &= ~SOR_DP_CONFIG_WATERMARK_MASK; | ||
1398 | value |= SOR_DP_CONFIG_WATERMARK(config.watermark); | ||
1399 | |||
1400 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; | ||
1401 | value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config.active_count); | ||
1402 | |||
1403 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; | ||
1404 | value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config.active_frac); | ||
1405 | |||
1406 | if (config.active_polarity) | ||
1407 | value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
1408 | else | ||
1409 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
1410 | |||
1411 | value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; | ||
1412 | value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; | ||
1413 | tegra_sor_writel(sor, value, SOR_DP_CONFIG0); | ||
1414 | |||
1415 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
1416 | value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; | ||
1417 | value |= config.hblank_symbols & 0xffff; | ||
1418 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
1419 | |||
1420 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
1421 | value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; | ||
1422 | value |= config.vblank_symbols & 0xffff; | ||
1423 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
1424 | |||
1425 | /* enable pad calibration logic */ | 1695 | /* enable pad calibration logic */ |
1426 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); | 1696 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); |
1427 | value |= SOR_DP_PADCTL_PAD_CAL_PD; | 1697 | value |= SOR_DP_PADCTL_PAD_CAL_PD; |
@@ -1477,75 +1747,19 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1477 | if (err < 0) | 1747 | if (err < 0) |
1478 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); | 1748 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); |
1479 | 1749 | ||
1480 | /* | ||
1481 | * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete | ||
1482 | * raster, associate with display controller) | ||
1483 | */ | ||
1484 | value = SOR_STATE_ASY_PROTOCOL_DP_A | | ||
1485 | SOR_STATE_ASY_CRC_MODE_COMPLETE | | ||
1486 | SOR_STATE_ASY_OWNER(dc->pipe + 1); | ||
1487 | |||
1488 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
1489 | value &= ~SOR_STATE_ASY_HSYNCPOL; | ||
1490 | |||
1491 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
1492 | value |= SOR_STATE_ASY_HSYNCPOL; | ||
1493 | |||
1494 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
1495 | value &= ~SOR_STATE_ASY_VSYNCPOL; | ||
1496 | |||
1497 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
1498 | value |= SOR_STATE_ASY_VSYNCPOL; | ||
1499 | |||
1500 | switch (config.bits_per_pixel) { | ||
1501 | case 24: | ||
1502 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
1503 | break; | ||
1504 | |||
1505 | case 18: | ||
1506 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; | ||
1507 | break; | ||
1508 | |||
1509 | default: | ||
1510 | BUG(); | ||
1511 | break; | ||
1512 | } | ||
1513 | |||
1514 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
1515 | |||
1516 | /* | ||
1517 | * TODO: The video timing programming below doesn't seem to match the | ||
1518 | * register definitions. | ||
1519 | */ | ||
1520 | |||
1521 | value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); | ||
1522 | tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); | ||
1523 | |||
1524 | vse = mode->vsync_end - mode->vsync_start - 1; | ||
1525 | hse = mode->hsync_end - mode->hsync_start - 1; | ||
1526 | |||
1527 | value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); | ||
1528 | tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); | ||
1529 | |||
1530 | vbe = vse + (mode->vsync_start - mode->vdisplay); | ||
1531 | hbe = hse + (mode->hsync_start - mode->hdisplay); | ||
1532 | |||
1533 | value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); | ||
1534 | tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); | ||
1535 | |||
1536 | vbs = vbe + mode->vdisplay; | ||
1537 | hbs = hbe + mode->hdisplay; | ||
1538 | |||
1539 | value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); | ||
1540 | tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); | ||
1541 | |||
1542 | tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe)); | ||
1543 | |||
1544 | /* CSTM (LVDS, link A/B, upper) */ | 1750 | /* CSTM (LVDS, link A/B, upper) */ |
1545 | value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | | 1751 | value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | |
1546 | SOR_CSTM_UPPER; | 1752 | SOR_CSTM_UPPER; |
1547 | tegra_sor_writel(sor, value, SOR_CSTM); | 1753 | tegra_sor_writel(sor, value, SOR_CSTM); |
1548 | 1754 | ||
1755 | /* use DP-A protocol */ | ||
1756 | value = tegra_sor_readl(sor, SOR_STATE1); | ||
1757 | value &= ~SOR_STATE_ASY_PROTOCOL_MASK; | ||
1758 | value |= SOR_STATE_ASY_PROTOCOL_DP_A; | ||
1759 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
1760 | |||
1761 | tegra_sor_mode_set(sor, mode, state); | ||
1762 | |||
1549 | /* PWM setup */ | 1763 | /* PWM setup */ |
1550 | err = tegra_sor_setup_pwm(sor, 250); | 1764 | err = tegra_sor_setup_pwm(sor, 250); |
1551 | if (err < 0) | 1765 | if (err < 0) |
@@ -1577,11 +1791,15 @@ tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, | |||
1577 | struct drm_connector_state *conn_state) | 1791 | struct drm_connector_state *conn_state) |
1578 | { | 1792 | { |
1579 | struct tegra_output *output = encoder_to_output(encoder); | 1793 | struct tegra_output *output = encoder_to_output(encoder); |
1794 | struct tegra_sor_state *state = to_sor_state(conn_state); | ||
1580 | struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); | 1795 | struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); |
1581 | unsigned long pclk = crtc_state->mode.clock * 1000; | 1796 | unsigned long pclk = crtc_state->mode.clock * 1000; |
1582 | struct tegra_sor *sor = to_sor(output); | 1797 | struct tegra_sor *sor = to_sor(output); |
1798 | struct drm_display_info *info; | ||
1583 | int err; | 1799 | int err; |
1584 | 1800 | ||
1801 | info = &output->connector.display_info; | ||
1802 | |||
1585 | err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, | 1803 | err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, |
1586 | pclk, 0); | 1804 | pclk, 0); |
1587 | if (err < 0) { | 1805 | if (err < 0) { |
@@ -1589,6 +1807,18 @@ tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, | |||
1589 | return err; | 1807 | return err; |
1590 | } | 1808 | } |
1591 | 1809 | ||
1810 | switch (info->bpc) { | ||
1811 | case 8: | ||
1812 | case 6: | ||
1813 | state->bpc = info->bpc; | ||
1814 | break; | ||
1815 | |||
1816 | default: | ||
1817 | DRM_DEBUG_KMS("%u bits-per-color not supported\n", info->bpc); | ||
1818 | state->bpc = 8; | ||
1819 | break; | ||
1820 | } | ||
1821 | |||
1592 | return 0; | 1822 | return 0; |
1593 | } | 1823 | } |
1594 | 1824 | ||
@@ -1751,9 +1981,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) | |||
1751 | if (err < 0) | 1981 | if (err < 0) |
1752 | dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err); | 1982 | dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err); |
1753 | 1983 | ||
1754 | reset_control_assert(sor->rst); | 1984 | pm_runtime_put(sor->dev); |
1755 | usleep_range(1000, 2000); | ||
1756 | clk_disable_unprepare(sor->clk); | ||
1757 | } | 1985 | } |
1758 | 1986 | ||
1759 | static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | 1987 | static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) |
@@ -1761,26 +1989,21 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
1761 | struct tegra_output *output = encoder_to_output(encoder); | 1989 | struct tegra_output *output = encoder_to_output(encoder); |
1762 | unsigned int h_ref_to_sync = 1, pulse_start, max_ac; | 1990 | unsigned int h_ref_to_sync = 1, pulse_start, max_ac; |
1763 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 1991 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
1764 | unsigned int vbe, vse, hbe, hse, vbs, hbs, div; | ||
1765 | struct tegra_sor_hdmi_settings *settings; | 1992 | struct tegra_sor_hdmi_settings *settings; |
1766 | struct tegra_sor *sor = to_sor(output); | 1993 | struct tegra_sor *sor = to_sor(output); |
1994 | struct tegra_sor_state *state; | ||
1767 | struct drm_display_mode *mode; | 1995 | struct drm_display_mode *mode; |
1768 | struct drm_display_info *info; | 1996 | unsigned int div, i; |
1769 | u32 value; | 1997 | u32 value; |
1770 | int err; | 1998 | int err; |
1771 | 1999 | ||
2000 | state = to_sor_state(output->connector.state); | ||
1772 | mode = &encoder->crtc->state->adjusted_mode; | 2001 | mode = &encoder->crtc->state->adjusted_mode; |
1773 | info = &output->connector.display_info; | ||
1774 | 2002 | ||
1775 | err = clk_prepare_enable(sor->clk); | 2003 | pm_runtime_get_sync(sor->dev); |
1776 | if (err < 0) | ||
1777 | dev_err(sor->dev, "failed to enable clock: %d\n", err); | ||
1778 | 2004 | ||
1779 | usleep_range(1000, 2000); | 2005 | /* switch to safe parent clock */ |
1780 | 2006 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | |
1781 | reset_control_deassert(sor->rst); | ||
1782 | |||
1783 | err = clk_set_parent(sor->clk, sor->clk_safe); | ||
1784 | if (err < 0) | 2007 | if (err < 0) |
1785 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 2008 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
1786 | 2009 | ||
@@ -1876,22 +2099,20 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
1876 | value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div); | 2099 | value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div); |
1877 | tegra_sor_writel(sor, value, SOR_REFCLK); | 2100 | tegra_sor_writel(sor, value, SOR_REFCLK); |
1878 | 2101 | ||
1879 | /* XXX don't hardcode */ | 2102 | /* XXX not in TRM */ |
1880 | value = SOR_XBAR_CTRL_LINK1_XSEL(4, 4) | | 2103 | for (value = 0, i = 0; i < 5; i++) |
1881 | SOR_XBAR_CTRL_LINK1_XSEL(3, 3) | | 2104 | value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | |
1882 | SOR_XBAR_CTRL_LINK1_XSEL(2, 2) | | 2105 | SOR_XBAR_CTRL_LINK1_XSEL(i, i); |
1883 | SOR_XBAR_CTRL_LINK1_XSEL(1, 1) | | ||
1884 | SOR_XBAR_CTRL_LINK1_XSEL(0, 0) | | ||
1885 | SOR_XBAR_CTRL_LINK0_XSEL(4, 4) | | ||
1886 | SOR_XBAR_CTRL_LINK0_XSEL(3, 3) | | ||
1887 | SOR_XBAR_CTRL_LINK0_XSEL(2, 0) | | ||
1888 | SOR_XBAR_CTRL_LINK0_XSEL(1, 1) | | ||
1889 | SOR_XBAR_CTRL_LINK0_XSEL(0, 2); | ||
1890 | tegra_sor_writel(sor, value, SOR_XBAR_CTRL); | ||
1891 | 2106 | ||
1892 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); | 2107 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); |
2108 | tegra_sor_writel(sor, value, SOR_XBAR_CTRL); | ||
1893 | 2109 | ||
1894 | err = clk_set_parent(sor->clk, sor->clk_parent); | 2110 | /* switch to parent clock */ |
2111 | err = clk_set_parent(sor->clk_src, sor->clk_parent); | ||
2112 | if (err < 0) | ||
2113 | dev_err(sor->dev, "failed to set source clock: %d\n", err); | ||
2114 | |||
2115 | err = tegra_sor_set_parent_clock(sor, sor->clk_src); | ||
1895 | if (err < 0) | 2116 | if (err < 0) |
1896 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); | 2117 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); |
1897 | 2118 | ||
@@ -2001,7 +2222,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
2001 | value &= ~DITHER_CONTROL_MASK; | 2222 | value &= ~DITHER_CONTROL_MASK; |
2002 | value &= ~BASE_COLOR_SIZE_MASK; | 2223 | value &= ~BASE_COLOR_SIZE_MASK; |
2003 | 2224 | ||
2004 | switch (info->bpc) { | 2225 | switch (state->bpc) { |
2005 | case 6: | 2226 | case 6: |
2006 | value |= BASE_COLOR_SIZE_666; | 2227 | value |= BASE_COLOR_SIZE_666; |
2007 | break; | 2228 | break; |
@@ -2011,7 +2232,8 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
2011 | break; | 2232 | break; |
2012 | 2233 | ||
2013 | default: | 2234 | default: |
2014 | WARN(1, "%u bits-per-color not supported\n", info->bpc); | 2235 | WARN(1, "%u bits-per-color not supported\n", state->bpc); |
2236 | value |= BASE_COLOR_SIZE_888; | ||
2015 | break; | 2237 | break; |
2016 | } | 2238 | } |
2017 | 2239 | ||
@@ -2021,83 +2243,19 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
2021 | if (err < 0) | 2243 | if (err < 0) |
2022 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); | 2244 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); |
2023 | 2245 | ||
2024 | /* configure mode */ | 2246 | /* configure dynamic range of output */ |
2025 | value = tegra_sor_readl(sor, SOR_STATE1); | ||
2026 | value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK; | ||
2027 | value &= ~SOR_STATE_ASY_CRC_MODE_MASK; | ||
2028 | value &= ~SOR_STATE_ASY_OWNER_MASK; | ||
2029 | |||
2030 | value |= SOR_STATE_ASY_CRC_MODE_COMPLETE | | ||
2031 | SOR_STATE_ASY_OWNER(dc->pipe + 1); | ||
2032 | |||
2033 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
2034 | value &= ~SOR_STATE_ASY_HSYNCPOL; | ||
2035 | |||
2036 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
2037 | value |= SOR_STATE_ASY_HSYNCPOL; | ||
2038 | |||
2039 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
2040 | value &= ~SOR_STATE_ASY_VSYNCPOL; | ||
2041 | |||
2042 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
2043 | value |= SOR_STATE_ASY_VSYNCPOL; | ||
2044 | |||
2045 | switch (info->bpc) { | ||
2046 | case 8: | ||
2047 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
2048 | break; | ||
2049 | |||
2050 | case 6: | ||
2051 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; | ||
2052 | break; | ||
2053 | |||
2054 | default: | ||
2055 | BUG(); | ||
2056 | break; | ||
2057 | } | ||
2058 | |||
2059 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
2060 | |||
2061 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); | 2247 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); |
2062 | value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK; | 2248 | value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK; |
2063 | value &= ~SOR_HEAD_STATE_DYNRANGE_MASK; | 2249 | value &= ~SOR_HEAD_STATE_DYNRANGE_MASK; |
2064 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); | 2250 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); |
2065 | 2251 | ||
2252 | /* configure colorspace */ | ||
2066 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); | 2253 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); |
2067 | value &= ~SOR_HEAD_STATE_COLORSPACE_MASK; | 2254 | value &= ~SOR_HEAD_STATE_COLORSPACE_MASK; |
2068 | value |= SOR_HEAD_STATE_COLORSPACE_RGB; | 2255 | value |= SOR_HEAD_STATE_COLORSPACE_RGB; |
2069 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); | 2256 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); |
2070 | 2257 | ||
2071 | /* | 2258 | tegra_sor_mode_set(sor, mode, state); |
2072 | * TODO: The video timing programming below doesn't seem to match the | ||
2073 | * register definitions. | ||
2074 | */ | ||
2075 | |||
2076 | value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); | ||
2077 | tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); | ||
2078 | |||
2079 | /* sync end = sync width - 1 */ | ||
2080 | vse = mode->vsync_end - mode->vsync_start - 1; | ||
2081 | hse = mode->hsync_end - mode->hsync_start - 1; | ||
2082 | |||
2083 | value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); | ||
2084 | tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); | ||
2085 | |||
2086 | /* blank end = sync end + back porch */ | ||
2087 | vbe = vse + (mode->vtotal - mode->vsync_end); | ||
2088 | hbe = hse + (mode->htotal - mode->hsync_end); | ||
2089 | |||
2090 | value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); | ||
2091 | tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); | ||
2092 | |||
2093 | /* blank start = blank end + active */ | ||
2094 | vbs = vbe + mode->vdisplay; | ||
2095 | hbs = hbe + mode->hdisplay; | ||
2096 | |||
2097 | value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); | ||
2098 | tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); | ||
2099 | |||
2100 | tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe)); | ||
2101 | 2259 | ||
2102 | tegra_sor_update(sor); | 2260 | tegra_sor_update(sor); |
2103 | 2261 | ||
@@ -2195,10 +2353,13 @@ static int tegra_sor_init(struct host1x_client *client) | |||
2195 | * XXX: Remove this reset once proper hand-over from firmware to | 2353 | * XXX: Remove this reset once proper hand-over from firmware to |
2196 | * kernel is possible. | 2354 | * kernel is possible. |
2197 | */ | 2355 | */ |
2198 | err = reset_control_assert(sor->rst); | 2356 | if (sor->rst) { |
2199 | if (err < 0) { | 2357 | err = reset_control_assert(sor->rst); |
2200 | dev_err(sor->dev, "failed to assert SOR reset: %d\n", err); | 2358 | if (err < 0) { |
2201 | return err; | 2359 | dev_err(sor->dev, "failed to assert SOR reset: %d\n", |
2360 | err); | ||
2361 | return err; | ||
2362 | } | ||
2202 | } | 2363 | } |
2203 | 2364 | ||
2204 | err = clk_prepare_enable(sor->clk); | 2365 | err = clk_prepare_enable(sor->clk); |
@@ -2209,10 +2370,13 @@ static int tegra_sor_init(struct host1x_client *client) | |||
2209 | 2370 | ||
2210 | usleep_range(1000, 3000); | 2371 | usleep_range(1000, 3000); |
2211 | 2372 | ||
2212 | err = reset_control_deassert(sor->rst); | 2373 | if (sor->rst) { |
2213 | if (err < 0) { | 2374 | err = reset_control_deassert(sor->rst); |
2214 | dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err); | 2375 | if (err < 0) { |
2215 | return err; | 2376 | dev_err(sor->dev, "failed to deassert SOR reset: %d\n", |
2377 | err); | ||
2378 | return err; | ||
2379 | } | ||
2216 | } | 2380 | } |
2217 | 2381 | ||
2218 | err = clk_prepare_enable(sor->clk_safe); | 2382 | err = clk_prepare_enable(sor->clk_safe); |
@@ -2323,11 +2487,16 @@ static const struct tegra_sor_ops tegra_sor_hdmi_ops = { | |||
2323 | .remove = tegra_sor_hdmi_remove, | 2487 | .remove = tegra_sor_hdmi_remove, |
2324 | }; | 2488 | }; |
2325 | 2489 | ||
2490 | static const u8 tegra124_sor_xbar_cfg[5] = { | ||
2491 | 0, 1, 2, 3, 4 | ||
2492 | }; | ||
2493 | |||
2326 | static const struct tegra_sor_soc tegra124_sor = { | 2494 | static const struct tegra_sor_soc tegra124_sor = { |
2327 | .supports_edp = true, | 2495 | .supports_edp = true, |
2328 | .supports_lvds = true, | 2496 | .supports_lvds = true, |
2329 | .supports_hdmi = false, | 2497 | .supports_hdmi = false, |
2330 | .supports_dp = false, | 2498 | .supports_dp = false, |
2499 | .xbar_cfg = tegra124_sor_xbar_cfg, | ||
2331 | }; | 2500 | }; |
2332 | 2501 | ||
2333 | static const struct tegra_sor_soc tegra210_sor = { | 2502 | static const struct tegra_sor_soc tegra210_sor = { |
@@ -2335,6 +2504,11 @@ static const struct tegra_sor_soc tegra210_sor = { | |||
2335 | .supports_lvds = false, | 2504 | .supports_lvds = false, |
2336 | .supports_hdmi = false, | 2505 | .supports_hdmi = false, |
2337 | .supports_dp = false, | 2506 | .supports_dp = false, |
2507 | .xbar_cfg = tegra124_sor_xbar_cfg, | ||
2508 | }; | ||
2509 | |||
2510 | static const u8 tegra210_sor_xbar_cfg[5] = { | ||
2511 | 2, 1, 0, 3, 4 | ||
2338 | }; | 2512 | }; |
2339 | 2513 | ||
2340 | static const struct tegra_sor_soc tegra210_sor1 = { | 2514 | static const struct tegra_sor_soc tegra210_sor1 = { |
@@ -2345,6 +2519,8 @@ static const struct tegra_sor_soc tegra210_sor1 = { | |||
2345 | 2519 | ||
2346 | .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), | 2520 | .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), |
2347 | .settings = tegra210_sor_hdmi_defaults, | 2521 | .settings = tegra210_sor_hdmi_defaults, |
2522 | |||
2523 | .xbar_cfg = tegra210_sor_xbar_cfg, | ||
2348 | }; | 2524 | }; |
2349 | 2525 | ||
2350 | static const struct of_device_id tegra_sor_of_match[] = { | 2526 | static const struct of_device_id tegra_sor_of_match[] = { |
@@ -2434,11 +2610,14 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2434 | goto remove; | 2610 | goto remove; |
2435 | } | 2611 | } |
2436 | 2612 | ||
2437 | sor->rst = devm_reset_control_get(&pdev->dev, "sor"); | 2613 | if (!pdev->dev.pm_domain) { |
2438 | if (IS_ERR(sor->rst)) { | 2614 | sor->rst = devm_reset_control_get(&pdev->dev, "sor"); |
2439 | err = PTR_ERR(sor->rst); | 2615 | if (IS_ERR(sor->rst)) { |
2440 | dev_err(&pdev->dev, "failed to get reset control: %d\n", err); | 2616 | err = PTR_ERR(sor->rst); |
2441 | goto remove; | 2617 | dev_err(&pdev->dev, "failed to get reset control: %d\n", |
2618 | err); | ||
2619 | goto remove; | ||
2620 | } | ||
2442 | } | 2621 | } |
2443 | 2622 | ||
2444 | sor->clk = devm_clk_get(&pdev->dev, NULL); | 2623 | sor->clk = devm_clk_get(&pdev->dev, NULL); |
@@ -2448,6 +2627,16 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2448 | goto remove; | 2627 | goto remove; |
2449 | } | 2628 | } |
2450 | 2629 | ||
2630 | if (sor->soc->supports_hdmi || sor->soc->supports_dp) { | ||
2631 | sor->clk_src = devm_clk_get(&pdev->dev, "source"); | ||
2632 | if (IS_ERR(sor->clk_src)) { | ||
2633 | err = PTR_ERR(sor->clk_src); | ||
2634 | dev_err(sor->dev, "failed to get source clock: %d\n", | ||
2635 | err); | ||
2636 | goto remove; | ||
2637 | } | ||
2638 | } | ||
2639 | |||
2451 | sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); | 2640 | sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); |
2452 | if (IS_ERR(sor->clk_parent)) { | 2641 | if (IS_ERR(sor->clk_parent)) { |
2453 | err = PTR_ERR(sor->clk_parent); | 2642 | err = PTR_ERR(sor->clk_parent); |
@@ -2469,6 +2658,19 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2469 | goto remove; | 2658 | goto remove; |
2470 | } | 2659 | } |
2471 | 2660 | ||
2661 | platform_set_drvdata(pdev, sor); | ||
2662 | pm_runtime_enable(&pdev->dev); | ||
2663 | |||
2664 | pm_runtime_get_sync(&pdev->dev); | ||
2665 | sor->clk_brick = tegra_clk_sor_brick_register(sor, "sor1_brick"); | ||
2666 | pm_runtime_put(&pdev->dev); | ||
2667 | |||
2668 | if (IS_ERR(sor->clk_brick)) { | ||
2669 | err = PTR_ERR(sor->clk_brick); | ||
2670 | dev_err(&pdev->dev, "failed to register SOR clock: %d\n", err); | ||
2671 | goto remove; | ||
2672 | } | ||
2673 | |||
2472 | INIT_LIST_HEAD(&sor->client.list); | 2674 | INIT_LIST_HEAD(&sor->client.list); |
2473 | sor->client.ops = &sor_client_ops; | 2675 | sor->client.ops = &sor_client_ops; |
2474 | sor->client.dev = &pdev->dev; | 2676 | sor->client.dev = &pdev->dev; |
@@ -2480,8 +2682,6 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2480 | goto remove; | 2682 | goto remove; |
2481 | } | 2683 | } |
2482 | 2684 | ||
2483 | platform_set_drvdata(pdev, sor); | ||
2484 | |||
2485 | return 0; | 2685 | return 0; |
2486 | 2686 | ||
2487 | remove: | 2687 | remove: |
@@ -2497,6 +2697,8 @@ static int tegra_sor_remove(struct platform_device *pdev) | |||
2497 | struct tegra_sor *sor = platform_get_drvdata(pdev); | 2697 | struct tegra_sor *sor = platform_get_drvdata(pdev); |
2498 | int err; | 2698 | int err; |
2499 | 2699 | ||
2700 | pm_runtime_disable(&pdev->dev); | ||
2701 | |||
2500 | err = host1x_client_unregister(&sor->client); | 2702 | err = host1x_client_unregister(&sor->client); |
2501 | if (err < 0) { | 2703 | if (err < 0) { |
2502 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | 2704 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", |
@@ -2515,10 +2717,62 @@ static int tegra_sor_remove(struct platform_device *pdev) | |||
2515 | return 0; | 2717 | return 0; |
2516 | } | 2718 | } |
2517 | 2719 | ||
2720 | #ifdef CONFIG_PM | ||
2721 | static int tegra_sor_suspend(struct device *dev) | ||
2722 | { | ||
2723 | struct tegra_sor *sor = dev_get_drvdata(dev); | ||
2724 | int err; | ||
2725 | |||
2726 | if (sor->rst) { | ||
2727 | err = reset_control_assert(sor->rst); | ||
2728 | if (err < 0) { | ||
2729 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
2730 | return err; | ||
2731 | } | ||
2732 | } | ||
2733 | |||
2734 | usleep_range(1000, 2000); | ||
2735 | |||
2736 | clk_disable_unprepare(sor->clk); | ||
2737 | |||
2738 | return 0; | ||
2739 | } | ||
2740 | |||
2741 | static int tegra_sor_resume(struct device *dev) | ||
2742 | { | ||
2743 | struct tegra_sor *sor = dev_get_drvdata(dev); | ||
2744 | int err; | ||
2745 | |||
2746 | err = clk_prepare_enable(sor->clk); | ||
2747 | if (err < 0) { | ||
2748 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
2749 | return err; | ||
2750 | } | ||
2751 | |||
2752 | usleep_range(1000, 2000); | ||
2753 | |||
2754 | if (sor->rst) { | ||
2755 | err = reset_control_deassert(sor->rst); | ||
2756 | if (err < 0) { | ||
2757 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
2758 | clk_disable_unprepare(sor->clk); | ||
2759 | return err; | ||
2760 | } | ||
2761 | } | ||
2762 | |||
2763 | return 0; | ||
2764 | } | ||
2765 | #endif | ||
2766 | |||
2767 | static const struct dev_pm_ops tegra_sor_pm_ops = { | ||
2768 | SET_RUNTIME_PM_OPS(tegra_sor_suspend, tegra_sor_resume, NULL) | ||
2769 | }; | ||
2770 | |||
2518 | struct platform_driver tegra_sor_driver = { | 2771 | struct platform_driver tegra_sor_driver = { |
2519 | .driver = { | 2772 | .driver = { |
2520 | .name = "tegra-sor", | 2773 | .name = "tegra-sor", |
2521 | .of_match_table = tegra_sor_of_match, | 2774 | .of_match_table = tegra_sor_of_match, |
2775 | .pm = &tegra_sor_pm_ops, | ||
2522 | }, | 2776 | }, |
2523 | .probe = tegra_sor_probe, | 2777 | .probe = tegra_sor_probe, |
2524 | .remove = tegra_sor_remove, | 2778 | .remove = tegra_sor_remove, |