16b6b6042SThierry Reding /* 26b6b6042SThierry Reding * Copyright (C) 2013 NVIDIA Corporation 36b6b6042SThierry Reding * 46b6b6042SThierry Reding * This program is free software; you can redistribute it and/or modify 56b6b6042SThierry Reding * it under the terms of the GNU General Public License version 2 as 66b6b6042SThierry Reding * published by the Free Software Foundation. 76b6b6042SThierry Reding */ 86b6b6042SThierry Reding 96b6b6042SThierry Reding #include <linux/clk.h> 10a82752e1SThierry Reding #include <linux/debugfs.h> 116fad8f66SThierry Reding #include <linux/gpio.h> 126b6b6042SThierry Reding #include <linux/io.h> 136b6b6042SThierry Reding #include <linux/platform_device.h> 146b6b6042SThierry Reding #include <linux/reset.h> 15306a7f91SThierry Reding 167232398aSThierry Reding #include <soc/tegra/pmc.h> 176b6b6042SThierry Reding 184aa3df71SThierry Reding #include <drm/drm_atomic_helper.h> 196b6b6042SThierry Reding #include <drm/drm_dp_helper.h> 206fad8f66SThierry Reding #include <drm/drm_panel.h> 216b6b6042SThierry Reding 226b6b6042SThierry Reding #include "dc.h" 236b6b6042SThierry Reding #include "drm.h" 246b6b6042SThierry Reding #include "sor.h" 256b6b6042SThierry Reding 266b6b6042SThierry Reding struct tegra_sor { 276b6b6042SThierry Reding struct host1x_client client; 286b6b6042SThierry Reding struct tegra_output output; 296b6b6042SThierry Reding struct device *dev; 306b6b6042SThierry Reding 316b6b6042SThierry Reding void __iomem *regs; 326b6b6042SThierry Reding 336b6b6042SThierry Reding struct reset_control *rst; 346b6b6042SThierry Reding struct clk *clk_parent; 356b6b6042SThierry Reding struct clk *clk_safe; 366b6b6042SThierry Reding struct clk *clk_dp; 376b6b6042SThierry Reding struct clk *clk; 386b6b6042SThierry Reding 396b6b6042SThierry Reding struct tegra_dpaux *dpaux; 406b6b6042SThierry Reding 41dab16336SThierry Reding struct drm_info_list *debugfs_files; 42dab16336SThierry Reding struct drm_minor *minor; 43a82752e1SThierry Reding struct dentry *debugfs; 446b6b6042SThierry Reding }; 456b6b6042SThierry Reding 4634fa183bSThierry Reding struct tegra_sor_config { 4734fa183bSThierry Reding u32 bits_per_pixel; 4834fa183bSThierry Reding 4934fa183bSThierry Reding u32 active_polarity; 5034fa183bSThierry Reding u32 active_count; 5134fa183bSThierry Reding u32 tu_size; 5234fa183bSThierry Reding u32 active_frac; 5334fa183bSThierry Reding u32 watermark; 547890b576SThierry Reding 557890b576SThierry Reding u32 hblank_symbols; 567890b576SThierry Reding u32 vblank_symbols; 5734fa183bSThierry Reding }; 5834fa183bSThierry Reding 596b6b6042SThierry Reding static inline struct tegra_sor * 606b6b6042SThierry Reding host1x_client_to_sor(struct host1x_client *client) 616b6b6042SThierry Reding { 626b6b6042SThierry Reding return container_of(client, struct tegra_sor, client); 636b6b6042SThierry Reding } 646b6b6042SThierry Reding 656b6b6042SThierry Reding static inline struct tegra_sor *to_sor(struct tegra_output *output) 666b6b6042SThierry Reding { 676b6b6042SThierry Reding return container_of(output, struct tegra_sor, output); 686b6b6042SThierry Reding } 696b6b6042SThierry Reding 7028fe2076SThierry Reding static inline u32 tegra_sor_readl(struct tegra_sor *sor, unsigned long offset) 716b6b6042SThierry Reding { 726b6b6042SThierry Reding return readl(sor->regs + (offset << 2)); 736b6b6042SThierry Reding } 746b6b6042SThierry Reding 7528fe2076SThierry Reding static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, 766b6b6042SThierry Reding unsigned long offset) 776b6b6042SThierry Reding { 786b6b6042SThierry Reding writel(value, sor->regs + (offset << 2)); 796b6b6042SThierry Reding } 806b6b6042SThierry Reding 816b6b6042SThierry Reding static int tegra_sor_dp_train_fast(struct tegra_sor *sor, 826b6b6042SThierry Reding struct drm_dp_link *link) 836b6b6042SThierry Reding { 846b6b6042SThierry Reding unsigned int i; 856b6b6042SThierry Reding u8 pattern; 8628fe2076SThierry Reding u32 value; 876b6b6042SThierry Reding int err; 886b6b6042SThierry Reding 896b6b6042SThierry Reding /* setup lane parameters */ 906b6b6042SThierry Reding value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) | 916b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE2(0x40) | 926b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE1(0x40) | 936b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE0(0x40); 94a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT0); 956b6b6042SThierry Reding 966b6b6042SThierry Reding value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) | 976b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE2(0x0f) | 986b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE1(0x0f) | 996b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE0(0x0f); 100a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS0); 1016b6b6042SThierry Reding 102a9a9e4fdSThierry Reding value = SOR_LANE_POSTCURSOR_LANE3(0x00) | 103a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE2(0x00) | 104a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE1(0x00) | 105a9a9e4fdSThierry Reding SOR_LANE_POSTCURSOR_LANE0(0x00); 106a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_LANE_POSTCURSOR0); 1076b6b6042SThierry Reding 1086b6b6042SThierry Reding /* disable LVDS mode */ 1096b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_LVDS); 1106b6b6042SThierry Reding 111a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 1126b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 1136b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 1146b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */ 115a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 1166b6b6042SThierry Reding 117a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 1186b6b6042SThierry Reding value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 1196b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0; 120a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 1216b6b6042SThierry Reding 1226b6b6042SThierry Reding usleep_range(10, 100); 1236b6b6042SThierry Reding 124a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 1256b6b6042SThierry Reding value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 1266b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0); 127a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 1286b6b6042SThierry Reding 1296b6b6042SThierry Reding err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B); 1306b6b6042SThierry Reding if (err < 0) 1316b6b6042SThierry Reding return err; 1326b6b6042SThierry Reding 1336b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 1346b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 1356b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 1366b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN1; 1376b6b6042SThierry Reding value = (value << 8) | lane; 1386b6b6042SThierry Reding } 1396b6b6042SThierry Reding 1406b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 1416b6b6042SThierry Reding 1426b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_1; 1436b6b6042SThierry Reding 1446b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 1456b6b6042SThierry Reding if (err < 0) 1466b6b6042SThierry Reding return err; 1476b6b6042SThierry Reding 148a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE0); 1496b6b6042SThierry Reding value |= SOR_DP_SPARE_SEQ_ENABLE; 1506b6b6042SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 1516b6b6042SThierry Reding value |= SOR_DP_SPARE_MACRO_SOR_CLK; 152a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE0); 1536b6b6042SThierry Reding 1546b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 1556b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 1566b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 1576b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN2; 1586b6b6042SThierry Reding value = (value << 8) | lane; 1596b6b6042SThierry Reding } 1606b6b6042SThierry Reding 1616b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 1626b6b6042SThierry Reding 1636b6b6042SThierry Reding pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2; 1646b6b6042SThierry Reding 1656b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 1666b6b6042SThierry Reding if (err < 0) 1676b6b6042SThierry Reding return err; 1686b6b6042SThierry Reding 1696b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 1706b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 1716b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 1726b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 1736b6b6042SThierry Reding value = (value << 8) | lane; 1746b6b6042SThierry Reding } 1756b6b6042SThierry Reding 1766b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 1776b6b6042SThierry Reding 1786b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_DISABLE; 1796b6b6042SThierry Reding 1806b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 1816b6b6042SThierry Reding if (err < 0) 1826b6b6042SThierry Reding return err; 1836b6b6042SThierry Reding 1846b6b6042SThierry Reding return 0; 1856b6b6042SThierry Reding } 1866b6b6042SThierry Reding 1876b6b6042SThierry Reding static void tegra_sor_super_update(struct tegra_sor *sor) 1886b6b6042SThierry Reding { 189a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE0); 190a9a9e4fdSThierry Reding tegra_sor_writel(sor, 1, SOR_SUPER_STATE0); 191a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE0); 1926b6b6042SThierry Reding } 1936b6b6042SThierry Reding 1946b6b6042SThierry Reding static void tegra_sor_update(struct tegra_sor *sor) 1956b6b6042SThierry Reding { 196a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_STATE0); 197a9a9e4fdSThierry Reding tegra_sor_writel(sor, 1, SOR_STATE0); 198a9a9e4fdSThierry Reding tegra_sor_writel(sor, 0, SOR_STATE0); 1996b6b6042SThierry Reding } 2006b6b6042SThierry Reding 2016b6b6042SThierry Reding static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) 2026b6b6042SThierry Reding { 20328fe2076SThierry Reding u32 value; 2046b6b6042SThierry Reding 2056b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_DIV); 2066b6b6042SThierry Reding value &= ~SOR_PWM_DIV_MASK; 2076b6b6042SThierry Reding value |= 0x400; /* period */ 2086b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_DIV); 2096b6b6042SThierry Reding 2106b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 2116b6b6042SThierry Reding value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK; 2126b6b6042SThierry Reding value |= 0x400; /* duty cycle */ 2136b6b6042SThierry Reding value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */ 2146b6b6042SThierry Reding value |= SOR_PWM_CTL_TRIGGER; 2156b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_CTL); 2166b6b6042SThierry Reding 2176b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 2186b6b6042SThierry Reding 2196b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2206b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 2216b6b6042SThierry Reding if ((value & SOR_PWM_CTL_TRIGGER) == 0) 2226b6b6042SThierry Reding return 0; 2236b6b6042SThierry Reding 2246b6b6042SThierry Reding usleep_range(25, 100); 2256b6b6042SThierry Reding } 2266b6b6042SThierry Reding 2276b6b6042SThierry Reding return -ETIMEDOUT; 2286b6b6042SThierry Reding } 2296b6b6042SThierry Reding 2306b6b6042SThierry Reding static int tegra_sor_attach(struct tegra_sor *sor) 2316b6b6042SThierry Reding { 2326b6b6042SThierry Reding unsigned long value, timeout; 2336b6b6042SThierry Reding 2346b6b6042SThierry Reding /* wake up in normal mode */ 235a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 2366b6b6042SThierry Reding value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE; 2376b6b6042SThierry Reding value |= SOR_SUPER_STATE_MODE_NORMAL; 238a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 2396b6b6042SThierry Reding tegra_sor_super_update(sor); 2406b6b6042SThierry Reding 2416b6b6042SThierry Reding /* attach */ 242a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 2436b6b6042SThierry Reding value |= SOR_SUPER_STATE_ATTACHED; 244a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 2456b6b6042SThierry Reding tegra_sor_super_update(sor); 2466b6b6042SThierry Reding 2476b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 2486b6b6042SThierry Reding 2496b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2506b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 2516b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 2526b6b6042SThierry Reding return 0; 2536b6b6042SThierry Reding 2546b6b6042SThierry Reding usleep_range(25, 100); 2556b6b6042SThierry Reding } 2566b6b6042SThierry Reding 2576b6b6042SThierry Reding return -ETIMEDOUT; 2586b6b6042SThierry Reding } 2596b6b6042SThierry Reding 2606b6b6042SThierry Reding static int tegra_sor_wakeup(struct tegra_sor *sor) 2616b6b6042SThierry Reding { 2626b6b6042SThierry Reding unsigned long value, timeout; 2636b6b6042SThierry Reding 2646b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 2656b6b6042SThierry Reding 2666b6b6042SThierry Reding /* wait for head to wake up */ 2676b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2686b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 2696b6b6042SThierry Reding value &= SOR_TEST_HEAD_MODE_MASK; 2706b6b6042SThierry Reding 2716b6b6042SThierry Reding if (value == SOR_TEST_HEAD_MODE_AWAKE) 2726b6b6042SThierry Reding return 0; 2736b6b6042SThierry Reding 2746b6b6042SThierry Reding usleep_range(25, 100); 2756b6b6042SThierry Reding } 2766b6b6042SThierry Reding 2776b6b6042SThierry Reding return -ETIMEDOUT; 2786b6b6042SThierry Reding } 2796b6b6042SThierry Reding 2806b6b6042SThierry Reding static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) 2816b6b6042SThierry Reding { 28228fe2076SThierry Reding u32 value; 2836b6b6042SThierry Reding 2846b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 2856b6b6042SThierry Reding value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; 2866b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 2876b6b6042SThierry Reding 2886b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 2896b6b6042SThierry Reding 2906b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2916b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 2926b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 2936b6b6042SThierry Reding return 0; 2946b6b6042SThierry Reding 2956b6b6042SThierry Reding usleep_range(25, 100); 2966b6b6042SThierry Reding } 2976b6b6042SThierry Reding 2986b6b6042SThierry Reding return -ETIMEDOUT; 2996b6b6042SThierry Reding } 3006b6b6042SThierry Reding 30134fa183bSThierry Reding struct tegra_sor_params { 30234fa183bSThierry Reding /* number of link clocks per line */ 30334fa183bSThierry Reding unsigned int num_clocks; 30434fa183bSThierry Reding /* ratio between input and output */ 30534fa183bSThierry Reding u64 ratio; 30634fa183bSThierry Reding /* precision factor */ 30734fa183bSThierry Reding u64 precision; 30834fa183bSThierry Reding 30934fa183bSThierry Reding unsigned int active_polarity; 31034fa183bSThierry Reding unsigned int active_count; 31134fa183bSThierry Reding unsigned int active_frac; 31234fa183bSThierry Reding unsigned int tu_size; 31334fa183bSThierry Reding unsigned int error; 31434fa183bSThierry Reding }; 31534fa183bSThierry Reding 31634fa183bSThierry Reding static int tegra_sor_compute_params(struct tegra_sor *sor, 31734fa183bSThierry Reding struct tegra_sor_params *params, 31834fa183bSThierry Reding unsigned int tu_size) 31934fa183bSThierry Reding { 32034fa183bSThierry Reding u64 active_sym, active_count, frac, approx; 32134fa183bSThierry Reding u32 active_polarity, active_frac = 0; 32234fa183bSThierry Reding const u64 f = params->precision; 32334fa183bSThierry Reding s64 error; 32434fa183bSThierry Reding 32534fa183bSThierry Reding active_sym = params->ratio * tu_size; 32634fa183bSThierry Reding active_count = div_u64(active_sym, f) * f; 32734fa183bSThierry Reding frac = active_sym - active_count; 32834fa183bSThierry Reding 32934fa183bSThierry Reding /* fraction < 0.5 */ 33034fa183bSThierry Reding if (frac >= (f / 2)) { 33134fa183bSThierry Reding active_polarity = 1; 33234fa183bSThierry Reding frac = f - frac; 33334fa183bSThierry Reding } else { 33434fa183bSThierry Reding active_polarity = 0; 33534fa183bSThierry Reding } 33634fa183bSThierry Reding 33734fa183bSThierry Reding if (frac != 0) { 33834fa183bSThierry Reding frac = div_u64(f * f, frac); /* 1/fraction */ 33934fa183bSThierry Reding if (frac <= (15 * f)) { 34034fa183bSThierry Reding active_frac = div_u64(frac, f); 34134fa183bSThierry Reding 34234fa183bSThierry Reding /* round up */ 34334fa183bSThierry Reding if (active_polarity) 34434fa183bSThierry Reding active_frac++; 34534fa183bSThierry Reding } else { 34634fa183bSThierry Reding active_frac = active_polarity ? 1 : 15; 34734fa183bSThierry Reding } 34834fa183bSThierry Reding } 34934fa183bSThierry Reding 35034fa183bSThierry Reding if (active_frac == 1) 35134fa183bSThierry Reding active_polarity = 0; 35234fa183bSThierry Reding 35334fa183bSThierry Reding if (active_polarity == 1) { 35434fa183bSThierry Reding if (active_frac) { 35534fa183bSThierry Reding approx = active_count + (active_frac * (f - 1)) * f; 35634fa183bSThierry Reding approx = div_u64(approx, active_frac * f); 35734fa183bSThierry Reding } else { 35834fa183bSThierry Reding approx = active_count + f; 35934fa183bSThierry Reding } 36034fa183bSThierry Reding } else { 36134fa183bSThierry Reding if (active_frac) 36234fa183bSThierry Reding approx = active_count + div_u64(f, active_frac); 36334fa183bSThierry Reding else 36434fa183bSThierry Reding approx = active_count; 36534fa183bSThierry Reding } 36634fa183bSThierry Reding 36734fa183bSThierry Reding error = div_s64(active_sym - approx, tu_size); 36834fa183bSThierry Reding error *= params->num_clocks; 36934fa183bSThierry Reding 37034fa183bSThierry Reding if (error <= 0 && abs64(error) < params->error) { 37134fa183bSThierry Reding params->active_count = div_u64(active_count, f); 37234fa183bSThierry Reding params->active_polarity = active_polarity; 37334fa183bSThierry Reding params->active_frac = active_frac; 37434fa183bSThierry Reding params->error = abs64(error); 37534fa183bSThierry Reding params->tu_size = tu_size; 37634fa183bSThierry Reding 37734fa183bSThierry Reding if (error == 0) 37834fa183bSThierry Reding return true; 37934fa183bSThierry Reding } 38034fa183bSThierry Reding 38134fa183bSThierry Reding return false; 38234fa183bSThierry Reding } 38334fa183bSThierry Reding 38434fa183bSThierry Reding static int tegra_sor_calc_config(struct tegra_sor *sor, 38580444495SThierry Reding const struct drm_display_mode *mode, 38634fa183bSThierry Reding struct tegra_sor_config *config, 38734fa183bSThierry Reding struct drm_dp_link *link) 38834fa183bSThierry Reding { 38934fa183bSThierry Reding const u64 f = 100000, link_rate = link->rate * 1000; 39034fa183bSThierry Reding const u64 pclk = mode->clock * 1000; 3917890b576SThierry Reding u64 input, output, watermark, num; 39234fa183bSThierry Reding struct tegra_sor_params params; 39334fa183bSThierry Reding u32 num_syms_per_line; 39434fa183bSThierry Reding unsigned int i; 39534fa183bSThierry Reding 39634fa183bSThierry Reding if (!link_rate || !link->num_lanes || !pclk || !config->bits_per_pixel) 39734fa183bSThierry Reding return -EINVAL; 39834fa183bSThierry Reding 39934fa183bSThierry Reding output = link_rate * 8 * link->num_lanes; 40034fa183bSThierry Reding input = pclk * config->bits_per_pixel; 40134fa183bSThierry Reding 40234fa183bSThierry Reding if (input >= output) 40334fa183bSThierry Reding return -ERANGE; 40434fa183bSThierry Reding 40534fa183bSThierry Reding memset(¶ms, 0, sizeof(params)); 40634fa183bSThierry Reding params.ratio = div64_u64(input * f, output); 40734fa183bSThierry Reding params.num_clocks = div_u64(link_rate * mode->hdisplay, pclk); 40834fa183bSThierry Reding params.precision = f; 40934fa183bSThierry Reding params.error = 64 * f; 41034fa183bSThierry Reding params.tu_size = 64; 41134fa183bSThierry Reding 41234fa183bSThierry Reding for (i = params.tu_size; i >= 32; i--) 41334fa183bSThierry Reding if (tegra_sor_compute_params(sor, ¶ms, i)) 41434fa183bSThierry Reding break; 41534fa183bSThierry Reding 41634fa183bSThierry Reding if (params.active_frac == 0) { 41734fa183bSThierry Reding config->active_polarity = 0; 41834fa183bSThierry Reding config->active_count = params.active_count; 41934fa183bSThierry Reding 42034fa183bSThierry Reding if (!params.active_polarity) 42134fa183bSThierry Reding config->active_count--; 42234fa183bSThierry Reding 42334fa183bSThierry Reding config->tu_size = params.tu_size; 42434fa183bSThierry Reding config->active_frac = 1; 42534fa183bSThierry Reding } else { 42634fa183bSThierry Reding config->active_polarity = params.active_polarity; 42734fa183bSThierry Reding config->active_count = params.active_count; 42834fa183bSThierry Reding config->active_frac = params.active_frac; 42934fa183bSThierry Reding config->tu_size = params.tu_size; 43034fa183bSThierry Reding } 43134fa183bSThierry Reding 43234fa183bSThierry Reding dev_dbg(sor->dev, 43334fa183bSThierry Reding "polarity: %d active count: %d tu size: %d active frac: %d\n", 43434fa183bSThierry Reding config->active_polarity, config->active_count, 43534fa183bSThierry Reding config->tu_size, config->active_frac); 43634fa183bSThierry Reding 43734fa183bSThierry Reding watermark = params.ratio * config->tu_size * (f - params.ratio); 43834fa183bSThierry Reding watermark = div_u64(watermark, f); 43934fa183bSThierry Reding 44034fa183bSThierry Reding watermark = div_u64(watermark + params.error, f); 44134fa183bSThierry Reding config->watermark = watermark + (config->bits_per_pixel / 8) + 2; 44234fa183bSThierry Reding num_syms_per_line = (mode->hdisplay * config->bits_per_pixel) * 44334fa183bSThierry Reding (link->num_lanes * 8); 44434fa183bSThierry Reding 44534fa183bSThierry Reding if (config->watermark > 30) { 44634fa183bSThierry Reding config->watermark = 30; 44734fa183bSThierry Reding dev_err(sor->dev, 44834fa183bSThierry Reding "unable to compute TU size, forcing watermark to %u\n", 44934fa183bSThierry Reding config->watermark); 45034fa183bSThierry Reding } else if (config->watermark > num_syms_per_line) { 45134fa183bSThierry Reding config->watermark = num_syms_per_line; 45234fa183bSThierry Reding dev_err(sor->dev, "watermark too high, forcing to %u\n", 45334fa183bSThierry Reding config->watermark); 45434fa183bSThierry Reding } 45534fa183bSThierry Reding 4567890b576SThierry Reding /* compute the number of symbols per horizontal blanking interval */ 4577890b576SThierry Reding num = ((mode->htotal - mode->hdisplay) - 7) * link_rate; 4587890b576SThierry Reding config->hblank_symbols = div_u64(num, pclk); 4597890b576SThierry Reding 4607890b576SThierry Reding if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 4617890b576SThierry Reding config->hblank_symbols -= 3; 4627890b576SThierry Reding 4637890b576SThierry Reding config->hblank_symbols -= 12 / link->num_lanes; 4647890b576SThierry Reding 4657890b576SThierry Reding /* compute the number of symbols per vertical blanking interval */ 4667890b576SThierry Reding num = (mode->hdisplay - 25) * link_rate; 4677890b576SThierry Reding config->vblank_symbols = div_u64(num, pclk); 4687890b576SThierry Reding config->vblank_symbols -= 36 / link->num_lanes + 4; 4697890b576SThierry Reding 4707890b576SThierry Reding dev_dbg(sor->dev, "blank symbols: H:%u V:%u\n", config->hblank_symbols, 4717890b576SThierry Reding config->vblank_symbols); 4727890b576SThierry Reding 47334fa183bSThierry Reding return 0; 47434fa183bSThierry Reding } 47534fa183bSThierry Reding 4766fad8f66SThierry Reding static int tegra_sor_detach(struct tegra_sor *sor) 4776b6b6042SThierry Reding { 4786fad8f66SThierry Reding unsigned long value, timeout; 4796fad8f66SThierry Reding 4806fad8f66SThierry Reding /* switch to safe mode */ 481a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 4826fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_MODE_NORMAL; 483a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 4846fad8f66SThierry Reding tegra_sor_super_update(sor); 4856fad8f66SThierry Reding 4866fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 4876fad8f66SThierry Reding 4886fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 4896fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 4906fad8f66SThierry Reding if (value & SOR_PWR_MODE_SAFE) 4916fad8f66SThierry Reding break; 4926fad8f66SThierry Reding } 4936fad8f66SThierry Reding 4946fad8f66SThierry Reding if ((value & SOR_PWR_MODE_SAFE) == 0) 4956fad8f66SThierry Reding return -ETIMEDOUT; 4966fad8f66SThierry Reding 4976fad8f66SThierry Reding /* go to sleep */ 498a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 4996fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK; 500a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 5016fad8f66SThierry Reding tegra_sor_super_update(sor); 5026fad8f66SThierry Reding 5036fad8f66SThierry Reding /* detach */ 504a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE1); 5056fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_ATTACHED; 506a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE1); 5076fad8f66SThierry Reding tegra_sor_super_update(sor); 5086fad8f66SThierry Reding 5096fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5106fad8f66SThierry Reding 5116fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5126fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 5136fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) == 0) 5146fad8f66SThierry Reding break; 5156fad8f66SThierry Reding 5166fad8f66SThierry Reding usleep_range(25, 100); 5176fad8f66SThierry Reding } 5186fad8f66SThierry Reding 5196fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 5206fad8f66SThierry Reding return -ETIMEDOUT; 5216fad8f66SThierry Reding 5226fad8f66SThierry Reding return 0; 5236fad8f66SThierry Reding } 5246fad8f66SThierry Reding 5256fad8f66SThierry Reding static int tegra_sor_power_down(struct tegra_sor *sor) 5266fad8f66SThierry Reding { 5276fad8f66SThierry Reding unsigned long value, timeout; 5286fad8f66SThierry Reding int err; 5296fad8f66SThierry Reding 5306fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 5316fad8f66SThierry Reding value &= ~SOR_PWR_NORMAL_STATE_PU; 5326fad8f66SThierry Reding value |= SOR_PWR_TRIGGER; 5336fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 5346fad8f66SThierry Reding 5356fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5366fad8f66SThierry Reding 5376fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5386fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 5396fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 5406fad8f66SThierry Reding return 0; 5416fad8f66SThierry Reding 5426fad8f66SThierry Reding usleep_range(25, 100); 5436fad8f66SThierry Reding } 5446fad8f66SThierry Reding 5456fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) != 0) 5466fad8f66SThierry Reding return -ETIMEDOUT; 5476fad8f66SThierry Reding 5486fad8f66SThierry Reding err = clk_set_parent(sor->clk, sor->clk_safe); 5496fad8f66SThierry Reding if (err < 0) 5506fad8f66SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 5516fad8f66SThierry Reding 552a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 5536fad8f66SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 5546fad8f66SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2); 555a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 5566fad8f66SThierry Reding 5576fad8f66SThierry Reding /* stop lane sequencer */ 5586fad8f66SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP | 5596fad8f66SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_DOWN; 5606fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 5616fad8f66SThierry Reding 5626fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5636fad8f66SThierry Reding 5646fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5656fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 5666fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 5676fad8f66SThierry Reding break; 5686fad8f66SThierry Reding 5696fad8f66SThierry Reding usleep_range(25, 100); 5706fad8f66SThierry Reding } 5716fad8f66SThierry Reding 5726fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0) 5736fad8f66SThierry Reding return -ETIMEDOUT; 5746fad8f66SThierry Reding 575a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 576a9a9e4fdSThierry Reding value |= SOR_PLL2_PORT_POWERDOWN; 577a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 5786fad8f66SThierry Reding 5796fad8f66SThierry Reding usleep_range(20, 100); 5806fad8f66SThierry Reding 581a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 582a9a9e4fdSThierry Reding value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR; 583a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 5846fad8f66SThierry Reding 585a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 586a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD; 587a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 588a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 5896fad8f66SThierry Reding 5906fad8f66SThierry Reding usleep_range(20, 100); 5916fad8f66SThierry Reding 5926fad8f66SThierry Reding return 0; 5936fad8f66SThierry Reding } 5946fad8f66SThierry Reding 5956fad8f66SThierry Reding static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout) 5966fad8f66SThierry Reding { 5976fad8f66SThierry Reding u32 value; 5986fad8f66SThierry Reding 5996fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 6006fad8f66SThierry Reding 6016fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 602a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_CRCA); 603a9a9e4fdSThierry Reding if (value & SOR_CRCA_VALID) 6046fad8f66SThierry Reding return 0; 6056fad8f66SThierry Reding 6066fad8f66SThierry Reding usleep_range(100, 200); 6076fad8f66SThierry Reding } 6086fad8f66SThierry Reding 6096fad8f66SThierry Reding return -ETIMEDOUT; 6106fad8f66SThierry Reding } 6116fad8f66SThierry Reding 612530239a8SThierry Reding static int tegra_sor_show_crc(struct seq_file *s, void *data) 6136fad8f66SThierry Reding { 614530239a8SThierry Reding struct drm_info_node *node = s->private; 615530239a8SThierry Reding struct tegra_sor *sor = node->info_ent->data; 616*850bab44SThierry Reding struct drm_crtc *crtc = sor->output.encoder.crtc; 617*850bab44SThierry Reding struct drm_device *drm = node->minor->dev; 618530239a8SThierry Reding int err = 0; 6196fad8f66SThierry Reding u32 value; 6206fad8f66SThierry Reding 621*850bab44SThierry Reding drm_modeset_lock_all(drm); 6226fad8f66SThierry Reding 623*850bab44SThierry Reding if (!crtc || !crtc->state->active) { 624*850bab44SThierry Reding err = -EBUSY; 6256fad8f66SThierry Reding goto unlock; 6266fad8f66SThierry Reding } 6276fad8f66SThierry Reding 628a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_STATE1); 6296fad8f66SThierry Reding value &= ~SOR_STATE_ASY_CRC_MODE_MASK; 630a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 6316fad8f66SThierry Reding 6326fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_CRC_CNTRL); 6336fad8f66SThierry Reding value |= SOR_CRC_CNTRL_ENABLE; 6346fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_CRC_CNTRL); 6356fad8f66SThierry Reding 6366fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 6376fad8f66SThierry Reding value &= ~SOR_TEST_CRC_POST_SERIALIZE; 6386fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_TEST); 6396fad8f66SThierry Reding 6406fad8f66SThierry Reding err = tegra_sor_crc_wait(sor, 100); 6416fad8f66SThierry Reding if (err < 0) 6426fad8f66SThierry Reding goto unlock; 6436fad8f66SThierry Reding 644a9a9e4fdSThierry Reding tegra_sor_writel(sor, SOR_CRCA_RESET, SOR_CRCA); 645a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_CRCB); 6466fad8f66SThierry Reding 647530239a8SThierry Reding seq_printf(s, "%08x\n", value); 6486fad8f66SThierry Reding 6496fad8f66SThierry Reding unlock: 650*850bab44SThierry Reding drm_modeset_unlock_all(drm); 6516fad8f66SThierry Reding return err; 6526fad8f66SThierry Reding } 6536fad8f66SThierry Reding 654dab16336SThierry Reding static int tegra_sor_show_regs(struct seq_file *s, void *data) 655dab16336SThierry Reding { 656dab16336SThierry Reding struct drm_info_node *node = s->private; 657dab16336SThierry Reding struct tegra_sor *sor = node->info_ent->data; 658*850bab44SThierry Reding struct drm_crtc *crtc = sor->output.encoder.crtc; 659*850bab44SThierry Reding struct drm_device *drm = node->minor->dev; 660*850bab44SThierry Reding int err = 0; 661*850bab44SThierry Reding 662*850bab44SThierry Reding drm_modeset_lock_all(drm); 663*850bab44SThierry Reding 664*850bab44SThierry Reding if (!crtc || !crtc->state->active) { 665*850bab44SThierry Reding err = -EBUSY; 666*850bab44SThierry Reding goto unlock; 667*850bab44SThierry Reding } 668dab16336SThierry Reding 669dab16336SThierry Reding #define DUMP_REG(name) \ 670dab16336SThierry Reding seq_printf(s, "%-38s %#05x %08x\n", #name, name, \ 671dab16336SThierry Reding tegra_sor_readl(sor, name)) 672dab16336SThierry Reding 673dab16336SThierry Reding DUMP_REG(SOR_CTXSW); 674a9a9e4fdSThierry Reding DUMP_REG(SOR_SUPER_STATE0); 675a9a9e4fdSThierry Reding DUMP_REG(SOR_SUPER_STATE1); 676a9a9e4fdSThierry Reding DUMP_REG(SOR_STATE0); 677a9a9e4fdSThierry Reding DUMP_REG(SOR_STATE1); 678a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE0(0)); 679a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE0(1)); 680a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE1(0)); 681a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE1(1)); 682a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE2(0)); 683a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE2(1)); 684a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE3(0)); 685a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE3(1)); 686a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE4(0)); 687a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE4(1)); 688a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE5(0)); 689a9a9e4fdSThierry Reding DUMP_REG(SOR_HEAD_STATE5(1)); 690dab16336SThierry Reding DUMP_REG(SOR_CRC_CNTRL); 691dab16336SThierry Reding DUMP_REG(SOR_DP_DEBUG_MVID); 692dab16336SThierry Reding DUMP_REG(SOR_CLK_CNTRL); 693dab16336SThierry Reding DUMP_REG(SOR_CAP); 694dab16336SThierry Reding DUMP_REG(SOR_PWR); 695dab16336SThierry Reding DUMP_REG(SOR_TEST); 696a9a9e4fdSThierry Reding DUMP_REG(SOR_PLL0); 697a9a9e4fdSThierry Reding DUMP_REG(SOR_PLL1); 698a9a9e4fdSThierry Reding DUMP_REG(SOR_PLL2); 699a9a9e4fdSThierry Reding DUMP_REG(SOR_PLL3); 700dab16336SThierry Reding DUMP_REG(SOR_CSTM); 701dab16336SThierry Reding DUMP_REG(SOR_LVDS); 702a9a9e4fdSThierry Reding DUMP_REG(SOR_CRCA); 703a9a9e4fdSThierry Reding DUMP_REG(SOR_CRCB); 704dab16336SThierry Reding DUMP_REG(SOR_BLANK); 705dab16336SThierry Reding DUMP_REG(SOR_SEQ_CTL); 706dab16336SThierry Reding DUMP_REG(SOR_LANE_SEQ_CTL); 707dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(0)); 708dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(1)); 709dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(2)); 710dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(3)); 711dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(4)); 712dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(5)); 713dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(6)); 714dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(7)); 715dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(8)); 716dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(9)); 717dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(10)); 718dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(11)); 719dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(12)); 720dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(13)); 721dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(14)); 722dab16336SThierry Reding DUMP_REG(SOR_SEQ_INST(15)); 723dab16336SThierry Reding DUMP_REG(SOR_PWM_DIV); 724dab16336SThierry Reding DUMP_REG(SOR_PWM_CTL); 725a9a9e4fdSThierry Reding DUMP_REG(SOR_VCRC_A0); 726a9a9e4fdSThierry Reding DUMP_REG(SOR_VCRC_A1); 727a9a9e4fdSThierry Reding DUMP_REG(SOR_VCRC_B0); 728a9a9e4fdSThierry Reding DUMP_REG(SOR_VCRC_B1); 729a9a9e4fdSThierry Reding DUMP_REG(SOR_CCRC_A0); 730a9a9e4fdSThierry Reding DUMP_REG(SOR_CCRC_A1); 731a9a9e4fdSThierry Reding DUMP_REG(SOR_CCRC_B0); 732a9a9e4fdSThierry Reding DUMP_REG(SOR_CCRC_B1); 733a9a9e4fdSThierry Reding DUMP_REG(SOR_EDATA_A0); 734a9a9e4fdSThierry Reding DUMP_REG(SOR_EDATA_A1); 735a9a9e4fdSThierry Reding DUMP_REG(SOR_EDATA_B0); 736a9a9e4fdSThierry Reding DUMP_REG(SOR_EDATA_B1); 737a9a9e4fdSThierry Reding DUMP_REG(SOR_COUNT_A0); 738a9a9e4fdSThierry Reding DUMP_REG(SOR_COUNT_A1); 739a9a9e4fdSThierry Reding DUMP_REG(SOR_COUNT_B0); 740a9a9e4fdSThierry Reding DUMP_REG(SOR_COUNT_B1); 741a9a9e4fdSThierry Reding DUMP_REG(SOR_DEBUG_A0); 742a9a9e4fdSThierry Reding DUMP_REG(SOR_DEBUG_A1); 743a9a9e4fdSThierry Reding DUMP_REG(SOR_DEBUG_B0); 744a9a9e4fdSThierry Reding DUMP_REG(SOR_DEBUG_B1); 745dab16336SThierry Reding DUMP_REG(SOR_TRIG); 746dab16336SThierry Reding DUMP_REG(SOR_MSCHECK); 747dab16336SThierry Reding DUMP_REG(SOR_XBAR_CTRL); 748dab16336SThierry Reding DUMP_REG(SOR_XBAR_POL); 749a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_LINKCTL0); 750a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_LINKCTL1); 751a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE_DRIVE_CURRENT0); 752a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE_DRIVE_CURRENT1); 753a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE4_DRIVE_CURRENT0); 754a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE4_DRIVE_CURRENT1); 755a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE_PREEMPHASIS0); 756a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE_PREEMPHASIS1); 757a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE4_PREEMPHASIS0); 758a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE4_PREEMPHASIS1); 759a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE_POSTCURSOR0); 760a9a9e4fdSThierry Reding DUMP_REG(SOR_LANE_POSTCURSOR1); 761a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_CONFIG0); 762a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_CONFIG1); 763a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_MN0); 764a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_MN1); 765a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_PADCTL0); 766a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_PADCTL1); 767a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_DEBUG0); 768a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_DEBUG1); 769a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_SPARE0); 770a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_SPARE1); 771dab16336SThierry Reding DUMP_REG(SOR_DP_AUDIO_CTRL); 772dab16336SThierry Reding DUMP_REG(SOR_DP_AUDIO_HBLANK_SYMBOLS); 773dab16336SThierry Reding DUMP_REG(SOR_DP_AUDIO_VBLANK_SYMBOLS); 774dab16336SThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_HEADER); 775a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK0); 776a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK1); 777a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK2); 778a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK3); 779a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK4); 780a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK5); 781a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_GENERIC_INFOFRAME_SUBPACK6); 782dab16336SThierry Reding DUMP_REG(SOR_DP_TPG); 783dab16336SThierry Reding DUMP_REG(SOR_DP_TPG_CONFIG); 784a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_LQ_CSTM0); 785a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_LQ_CSTM1); 786a9a9e4fdSThierry Reding DUMP_REG(SOR_DP_LQ_CSTM2); 787dab16336SThierry Reding 788dab16336SThierry Reding #undef DUMP_REG 789dab16336SThierry Reding 790*850bab44SThierry Reding unlock: 791*850bab44SThierry Reding drm_modeset_unlock_all(drm); 792*850bab44SThierry Reding return err; 793dab16336SThierry Reding } 794dab16336SThierry Reding 795dab16336SThierry Reding static const struct drm_info_list debugfs_files[] = { 796530239a8SThierry Reding { "crc", tegra_sor_show_crc, 0, NULL }, 797dab16336SThierry Reding { "regs", tegra_sor_show_regs, 0, NULL }, 798dab16336SThierry Reding }; 799dab16336SThierry Reding 8006fad8f66SThierry Reding static int tegra_sor_debugfs_init(struct tegra_sor *sor, 8016fad8f66SThierry Reding struct drm_minor *minor) 8026fad8f66SThierry Reding { 803dab16336SThierry Reding unsigned int i; 804530239a8SThierry Reding int err; 8056fad8f66SThierry Reding 8066fad8f66SThierry Reding sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root); 8076fad8f66SThierry Reding if (!sor->debugfs) 8086fad8f66SThierry Reding return -ENOMEM; 8096fad8f66SThierry Reding 810dab16336SThierry Reding sor->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), 811dab16336SThierry Reding GFP_KERNEL); 812dab16336SThierry Reding if (!sor->debugfs_files) { 8136fad8f66SThierry Reding err = -ENOMEM; 8146fad8f66SThierry Reding goto remove; 8156fad8f66SThierry Reding } 8166fad8f66SThierry Reding 817dab16336SThierry Reding for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) 818dab16336SThierry Reding sor->debugfs_files[i].data = sor; 819dab16336SThierry Reding 820dab16336SThierry Reding err = drm_debugfs_create_files(sor->debugfs_files, 821dab16336SThierry Reding ARRAY_SIZE(debugfs_files), 822dab16336SThierry Reding sor->debugfs, minor); 823dab16336SThierry Reding if (err < 0) 824dab16336SThierry Reding goto free; 825dab16336SThierry Reding 8263ff1f22cSThierry Reding sor->minor = minor; 8273ff1f22cSThierry Reding 828530239a8SThierry Reding return 0; 8296fad8f66SThierry Reding 830dab16336SThierry Reding free: 831dab16336SThierry Reding kfree(sor->debugfs_files); 832dab16336SThierry Reding sor->debugfs_files = NULL; 8336fad8f66SThierry Reding remove: 834dab16336SThierry Reding debugfs_remove_recursive(sor->debugfs); 8356fad8f66SThierry Reding sor->debugfs = NULL; 8366fad8f66SThierry Reding return err; 8376fad8f66SThierry Reding } 8386fad8f66SThierry Reding 8394009c224SThierry Reding static void tegra_sor_debugfs_exit(struct tegra_sor *sor) 8406fad8f66SThierry Reding { 841dab16336SThierry Reding drm_debugfs_remove_files(sor->debugfs_files, ARRAY_SIZE(debugfs_files), 842dab16336SThierry Reding sor->minor); 843dab16336SThierry Reding sor->minor = NULL; 844dab16336SThierry Reding 845dab16336SThierry Reding kfree(sor->debugfs_files); 846066d30f8SThierry Reding sor->debugfs_files = NULL; 847dab16336SThierry Reding 848dab16336SThierry Reding debugfs_remove_recursive(sor->debugfs); 849066d30f8SThierry Reding sor->debugfs = NULL; 8506fad8f66SThierry Reding } 8516fad8f66SThierry Reding 8526fad8f66SThierry Reding static enum drm_connector_status 8536fad8f66SThierry Reding tegra_sor_connector_detect(struct drm_connector *connector, bool force) 8546fad8f66SThierry Reding { 8556fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 8566fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 8576fad8f66SThierry Reding 8586fad8f66SThierry Reding if (sor->dpaux) 8596fad8f66SThierry Reding return tegra_dpaux_detect(sor->dpaux); 8606fad8f66SThierry Reding 8616fad8f66SThierry Reding return connector_status_unknown; 8626fad8f66SThierry Reding } 8636fad8f66SThierry Reding 8646fad8f66SThierry Reding static const struct drm_connector_funcs tegra_sor_connector_funcs = { 865*850bab44SThierry Reding .dpms = drm_atomic_helper_connector_dpms, 8669d44189fSThierry Reding .reset = drm_atomic_helper_connector_reset, 8676fad8f66SThierry Reding .detect = tegra_sor_connector_detect, 8686fad8f66SThierry Reding .fill_modes = drm_helper_probe_single_connector_modes, 8696fad8f66SThierry Reding .destroy = tegra_output_connector_destroy, 8709d44189fSThierry Reding .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 8714aa3df71SThierry Reding .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 8726fad8f66SThierry Reding }; 8736fad8f66SThierry Reding 8746fad8f66SThierry Reding static int tegra_sor_connector_get_modes(struct drm_connector *connector) 8756fad8f66SThierry Reding { 8766fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 8776fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 8786fad8f66SThierry Reding int err; 8796fad8f66SThierry Reding 8806fad8f66SThierry Reding if (sor->dpaux) 8816fad8f66SThierry Reding tegra_dpaux_enable(sor->dpaux); 8826fad8f66SThierry Reding 8836fad8f66SThierry Reding err = tegra_output_connector_get_modes(connector); 8846fad8f66SThierry Reding 8856fad8f66SThierry Reding if (sor->dpaux) 8866fad8f66SThierry Reding tegra_dpaux_disable(sor->dpaux); 8876fad8f66SThierry Reding 8886fad8f66SThierry Reding return err; 8896fad8f66SThierry Reding } 8906fad8f66SThierry Reding 8916fad8f66SThierry Reding static enum drm_mode_status 8926fad8f66SThierry Reding tegra_sor_connector_mode_valid(struct drm_connector *connector, 8936fad8f66SThierry Reding struct drm_display_mode *mode) 8946fad8f66SThierry Reding { 8956fad8f66SThierry Reding return MODE_OK; 8966fad8f66SThierry Reding } 8976fad8f66SThierry Reding 8986fad8f66SThierry Reding static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = { 8996fad8f66SThierry Reding .get_modes = tegra_sor_connector_get_modes, 9006fad8f66SThierry Reding .mode_valid = tegra_sor_connector_mode_valid, 9016fad8f66SThierry Reding .best_encoder = tegra_output_connector_best_encoder, 9026fad8f66SThierry Reding }; 9036fad8f66SThierry Reding 9046fad8f66SThierry Reding static const struct drm_encoder_funcs tegra_sor_encoder_funcs = { 9056fad8f66SThierry Reding .destroy = tegra_output_encoder_destroy, 9066fad8f66SThierry Reding }; 9076fad8f66SThierry Reding 908*850bab44SThierry Reding static void tegra_sor_edp_disable(struct drm_encoder *encoder) 9096fad8f66SThierry Reding { 910*850bab44SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 911*850bab44SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 912*850bab44SThierry Reding struct tegra_sor *sor = to_sor(output); 913*850bab44SThierry Reding u32 value; 914*850bab44SThierry Reding int err; 915*850bab44SThierry Reding 916*850bab44SThierry Reding if (output->panel) 917*850bab44SThierry Reding drm_panel_disable(output->panel); 918*850bab44SThierry Reding 919*850bab44SThierry Reding err = tegra_sor_detach(sor); 920*850bab44SThierry Reding if (err < 0) 921*850bab44SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 922*850bab44SThierry Reding 923*850bab44SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE1); 924*850bab44SThierry Reding tegra_sor_update(sor); 925*850bab44SThierry Reding 926*850bab44SThierry Reding /* 927*850bab44SThierry Reding * The following accesses registers of the display controller, so make 928*850bab44SThierry Reding * sure it's only executed when the output is attached to one. 929*850bab44SThierry Reding */ 930*850bab44SThierry Reding if (dc) { 931*850bab44SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 932*850bab44SThierry Reding value &= ~SOR_ENABLE; 933*850bab44SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 934*850bab44SThierry Reding 935*850bab44SThierry Reding tegra_dc_commit(dc); 9366fad8f66SThierry Reding } 9376fad8f66SThierry Reding 938*850bab44SThierry Reding err = tegra_sor_power_down(sor); 939*850bab44SThierry Reding if (err < 0) 940*850bab44SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 941*850bab44SThierry Reding 942*850bab44SThierry Reding if (sor->dpaux) { 943*850bab44SThierry Reding err = tegra_dpaux_disable(sor->dpaux); 944*850bab44SThierry Reding if (err < 0) 945*850bab44SThierry Reding dev_err(sor->dev, "failed to disable DP: %d\n", err); 9466fad8f66SThierry Reding } 9476fad8f66SThierry Reding 948*850bab44SThierry Reding err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS); 949*850bab44SThierry Reding if (err < 0) 950*850bab44SThierry Reding dev_err(sor->dev, "failed to power off I/O rail: %d\n", err); 951*850bab44SThierry Reding 952*850bab44SThierry Reding if (output->panel) 953*850bab44SThierry Reding drm_panel_unprepare(output->panel); 954*850bab44SThierry Reding 955*850bab44SThierry Reding reset_control_assert(sor->rst); 956*850bab44SThierry Reding clk_disable_unprepare(sor->clk); 9576fad8f66SThierry Reding } 9586fad8f66SThierry Reding 959*850bab44SThierry Reding static void tegra_sor_edp_enable(struct drm_encoder *encoder) 9606fad8f66SThierry Reding { 961*850bab44SThierry Reding struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; 9626fad8f66SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 9636fad8f66SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 9646b6b6042SThierry Reding unsigned int vbe, vse, hbe, hse, vbs, hbs, i; 9656b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 96634fa183bSThierry Reding struct tegra_sor_config config; 96734fa183bSThierry Reding struct drm_dp_link link; 96834fa183bSThierry Reding struct drm_dp_aux *aux; 96986f5c52dSThierry Reding int err = 0; 97028fe2076SThierry Reding u32 value; 97186f5c52dSThierry Reding 9726b6b6042SThierry Reding err = clk_prepare_enable(sor->clk); 9736b6b6042SThierry Reding if (err < 0) 974*850bab44SThierry Reding dev_err(sor->dev, "failed to enable clock: %d\n", err); 9756b6b6042SThierry Reding 9766b6b6042SThierry Reding reset_control_deassert(sor->rst); 9776b6b6042SThierry Reding 9786fad8f66SThierry Reding if (output->panel) 9796fad8f66SThierry Reding drm_panel_prepare(output->panel); 9806fad8f66SThierry Reding 98134fa183bSThierry Reding /* FIXME: properly convert to struct drm_dp_aux */ 98234fa183bSThierry Reding aux = (struct drm_dp_aux *)sor->dpaux; 98334fa183bSThierry Reding 9846b6b6042SThierry Reding if (sor->dpaux) { 9856b6b6042SThierry Reding err = tegra_dpaux_enable(sor->dpaux); 9866b6b6042SThierry Reding if (err < 0) 9876b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DP: %d\n", err); 98834fa183bSThierry Reding 98934fa183bSThierry Reding err = drm_dp_link_probe(aux, &link); 99034fa183bSThierry Reding if (err < 0) { 99134fa183bSThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", 99234fa183bSThierry Reding err); 993*850bab44SThierry Reding return; 99434fa183bSThierry Reding } 9956b6b6042SThierry Reding } 9966b6b6042SThierry Reding 9976b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_safe); 9986b6b6042SThierry Reding if (err < 0) 9996b6b6042SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 10006b6b6042SThierry Reding 100134fa183bSThierry Reding memset(&config, 0, sizeof(config)); 1002054b1bd1SStéphane Marchesin config.bits_per_pixel = output->connector.display_info.bpc * 3; 100334fa183bSThierry Reding 100434fa183bSThierry Reding err = tegra_sor_calc_config(sor, mode, &config, &link); 100534fa183bSThierry Reding if (err < 0) 100634fa183bSThierry Reding dev_err(sor->dev, "failed to compute link configuration: %d\n", 100734fa183bSThierry Reding err); 100834fa183bSThierry Reding 10096b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 10106b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 10116b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 10126b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 10136b6b6042SThierry Reding 1014a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1015a9a9e4fdSThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 1016a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10176b6b6042SThierry Reding usleep_range(20, 100); 10186b6b6042SThierry Reding 1019a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL3); 1020a9a9e4fdSThierry Reding value |= SOR_PLL3_PLL_VDD_MODE_3V3; 1021a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL3); 10226b6b6042SThierry Reding 1023a9a9e4fdSThierry Reding value = SOR_PLL0_ICHPMP(0xf) | SOR_PLL0_VCOCAP_RST | 1024a9a9e4fdSThierry Reding SOR_PLL0_PLLREG_LEVEL_V45 | SOR_PLL0_RESISTOR_EXT; 1025a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 10266b6b6042SThierry Reding 1027a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1028a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD; 1029a9a9e4fdSThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1030a9a9e4fdSThierry Reding value |= SOR_PLL2_LVDS_ENABLE; 1031a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10326b6b6042SThierry Reding 1033a9a9e4fdSThierry Reding value = SOR_PLL1_TERM_COMPOUT | SOR_PLL1_TMDS_TERM; 1034a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL1); 10356b6b6042SThierry Reding 10366b6b6042SThierry Reding while (true) { 1037a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1038a9a9e4fdSThierry Reding if ((value & SOR_PLL2_SEQ_PLLCAPPD_ENFORCE) == 0) 10396b6b6042SThierry Reding break; 10406b6b6042SThierry Reding 10416b6b6042SThierry Reding usleep_range(250, 1000); 10426b6b6042SThierry Reding } 10436b6b6042SThierry Reding 1044a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1045a9a9e4fdSThierry Reding value &= ~SOR_PLL2_POWERDOWN_OVERRIDE; 1046a9a9e4fdSThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 1047a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10486b6b6042SThierry Reding 10496b6b6042SThierry Reding /* 10506b6b6042SThierry Reding * power up 10516b6b6042SThierry Reding */ 10526b6b6042SThierry Reding 10536b6b6042SThierry Reding /* set safe link bandwidth (1.62 Gbps) */ 10546b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 10556b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 10566b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62; 10576b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 10586b6b6042SThierry Reding 10596b6b6042SThierry Reding /* step 1 */ 1060a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1061a9a9e4fdSThierry Reding value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL2_PORT_POWERDOWN | 1062a9a9e4fdSThierry Reding SOR_PLL2_BANDGAP_POWERDOWN; 1063a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10646b6b6042SThierry Reding 1065a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 1066a9a9e4fdSThierry Reding value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR; 1067a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 10686b6b6042SThierry Reding 1069a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 10706b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 1071a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 10726b6b6042SThierry Reding 10736b6b6042SThierry Reding /* step 2 */ 10746b6b6042SThierry Reding err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS); 1075*850bab44SThierry Reding if (err < 0) 10766b6b6042SThierry Reding dev_err(sor->dev, "failed to power on I/O rail: %d\n", err); 10776b6b6042SThierry Reding 10786b6b6042SThierry Reding usleep_range(5, 100); 10796b6b6042SThierry Reding 10806b6b6042SThierry Reding /* step 3 */ 1081a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1082a9a9e4fdSThierry Reding value &= ~SOR_PLL2_BANDGAP_POWERDOWN; 1083a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10846b6b6042SThierry Reding 10856b6b6042SThierry Reding usleep_range(20, 100); 10866b6b6042SThierry Reding 10876b6b6042SThierry Reding /* step 4 */ 1088a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL0); 1089a9a9e4fdSThierry Reding value &= ~SOR_PLL0_VCOPD; 1090a9a9e4fdSThierry Reding value &= ~SOR_PLL0_PWR; 1091a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL0); 10926b6b6042SThierry Reding 1093a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1094a9a9e4fdSThierry Reding value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE; 1095a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 10966b6b6042SThierry Reding 10976b6b6042SThierry Reding usleep_range(200, 1000); 10986b6b6042SThierry Reding 10996b6b6042SThierry Reding /* step 5 */ 1100a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_PLL2); 1101a9a9e4fdSThierry Reding value &= ~SOR_PLL2_PORT_POWERDOWN; 1102a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_PLL2); 11036b6b6042SThierry Reding 11046b6b6042SThierry Reding /* switch to DP clock */ 11056b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_dp); 11066b6b6042SThierry Reding if (err < 0) 11076b6b6042SThierry Reding dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); 11086b6b6042SThierry Reding 1109899451b7SThierry Reding /* power DP lanes */ 1110a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 1111899451b7SThierry Reding 1112899451b7SThierry Reding if (link.num_lanes <= 2) 1113899451b7SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2); 1114899451b7SThierry Reding else 1115899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2; 1116899451b7SThierry Reding 1117899451b7SThierry Reding if (link.num_lanes <= 1) 1118899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_1; 1119899451b7SThierry Reding else 1120899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_1; 1121899451b7SThierry Reding 1122899451b7SThierry Reding if (link.num_lanes == 0) 1123899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_0; 1124899451b7SThierry Reding else 1125899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_0; 1126899451b7SThierry Reding 1127a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 11286b6b6042SThierry Reding 1129a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 11306b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 11310c90a184SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(link.num_lanes); 1132a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 11336b6b6042SThierry Reding 11346b6b6042SThierry Reding /* start lane sequencer */ 11356b6b6042SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 11366b6b6042SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP; 11376b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 11386b6b6042SThierry Reding 11396b6b6042SThierry Reding while (true) { 11406b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 11416b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 11426b6b6042SThierry Reding break; 11436b6b6042SThierry Reding 11446b6b6042SThierry Reding usleep_range(250, 1000); 11456b6b6042SThierry Reding } 11466b6b6042SThierry Reding 1147a4263fedSThierry Reding /* set link bandwidth */ 11486b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 11496b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 1150a4263fedSThierry Reding value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; 11516b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 11526b6b6042SThierry Reding 11536b6b6042SThierry Reding /* set linkctl */ 1154a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 11556b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENABLE; 11566b6b6042SThierry Reding 11576b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; 115834fa183bSThierry Reding value |= SOR_DP_LINKCTL_TU_SIZE(config.tu_size); 11596b6b6042SThierry Reding 11606b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 1161a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 11626b6b6042SThierry Reding 11636b6b6042SThierry Reding for (i = 0, value = 0; i < 4; i++) { 11646b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 11656b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 11666b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 11676b6b6042SThierry Reding value = (value << 8) | lane; 11686b6b6042SThierry Reding } 11696b6b6042SThierry Reding 11706b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 11716b6b6042SThierry Reding 1172a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_CONFIG0); 11736b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_WATERMARK_MASK; 117434fa183bSThierry Reding value |= SOR_DP_CONFIG_WATERMARK(config.watermark); 11756b6b6042SThierry Reding 11766b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; 117734fa183bSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config.active_count); 11786b6b6042SThierry Reding 11796b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; 118034fa183bSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config.active_frac); 11816b6b6042SThierry Reding 118234fa183bSThierry Reding if (config.active_polarity) 118334fa183bSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 118434fa183bSThierry Reding else 118534fa183bSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 11866b6b6042SThierry Reding 11876b6b6042SThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; 11881f64ae7cSThierry Reding value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; 1189a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_CONFIG0); 11906b6b6042SThierry Reding 11916b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); 11926b6b6042SThierry Reding value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; 11937890b576SThierry Reding value |= config.hblank_symbols & 0xffff; 11946b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); 11956b6b6042SThierry Reding 11966b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); 11976b6b6042SThierry Reding value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; 11987890b576SThierry Reding value |= config.vblank_symbols & 0xffff; 11996b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); 12006b6b6042SThierry Reding 12016b6b6042SThierry Reding /* enable pad calibration logic */ 1202a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL0); 12036b6b6042SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 1204a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL0); 12056b6b6042SThierry Reding 12066b6b6042SThierry Reding if (sor->dpaux) { 12076b6b6042SThierry Reding u8 rate, lanes; 12086b6b6042SThierry Reding 12096b6b6042SThierry Reding err = drm_dp_link_probe(aux, &link); 1210*850bab44SThierry Reding if (err < 0) 12116b6b6042SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", 12126b6b6042SThierry Reding err); 12136b6b6042SThierry Reding 12146b6b6042SThierry Reding err = drm_dp_link_power_up(aux, &link); 1215*850bab44SThierry Reding if (err < 0) 12166b6b6042SThierry Reding dev_err(sor->dev, "failed to power up eDP link: %d\n", 12176b6b6042SThierry Reding err); 12186b6b6042SThierry Reding 12196b6b6042SThierry Reding err = drm_dp_link_configure(aux, &link); 1220*850bab44SThierry Reding if (err < 0) 12216b6b6042SThierry Reding dev_err(sor->dev, "failed to configure eDP link: %d\n", 12226b6b6042SThierry Reding err); 12236b6b6042SThierry Reding 12246b6b6042SThierry Reding rate = drm_dp_link_rate_to_bw_code(link.rate); 12256b6b6042SThierry Reding lanes = link.num_lanes; 12266b6b6042SThierry Reding 12276b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 12286b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 12296b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate); 12306b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 12316b6b6042SThierry Reding 1232a9a9e4fdSThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); 12336b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 12346b6b6042SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(lanes); 12356b6b6042SThierry Reding 12366b6b6042SThierry Reding if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 12376b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 12386b6b6042SThierry Reding 1239a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); 12406b6b6042SThierry Reding 12416b6b6042SThierry Reding /* disable training pattern generator */ 12426b6b6042SThierry Reding 12436b6b6042SThierry Reding for (i = 0; i < link.num_lanes; i++) { 12446b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 12456b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 12466b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 12476b6b6042SThierry Reding value = (value << 8) | lane; 12486b6b6042SThierry Reding } 12496b6b6042SThierry Reding 12506b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 12516b6b6042SThierry Reding 12526b6b6042SThierry Reding err = tegra_sor_dp_train_fast(sor, &link); 12536b6b6042SThierry Reding if (err < 0) { 12546b6b6042SThierry Reding dev_err(sor->dev, "DP fast link training failed: %d\n", 12556b6b6042SThierry Reding err); 12566b6b6042SThierry Reding } 12576b6b6042SThierry Reding 12586b6b6042SThierry Reding dev_dbg(sor->dev, "fast link training succeeded\n"); 12596b6b6042SThierry Reding } 12606b6b6042SThierry Reding 12616b6b6042SThierry Reding err = tegra_sor_power_up(sor, 250); 1262*850bab44SThierry Reding if (err < 0) 12636b6b6042SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 12646b6b6042SThierry Reding 12656b6b6042SThierry Reding /* 12666b6b6042SThierry Reding * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete 12676b6b6042SThierry Reding * raster, associate with display controller) 12686b6b6042SThierry Reding */ 12693f4f3b5fSThierry Reding value = SOR_STATE_ASY_PROTOCOL_DP_A | 12706b6b6042SThierry Reding SOR_STATE_ASY_CRC_MODE_COMPLETE | 12716b6b6042SThierry Reding SOR_STATE_ASY_OWNER(dc->pipe + 1); 127234fa183bSThierry Reding 12733f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_PHSYNC) 12743f4f3b5fSThierry Reding value &= ~SOR_STATE_ASY_HSYNCPOL; 12753f4f3b5fSThierry Reding 12763f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_NHSYNC) 12773f4f3b5fSThierry Reding value |= SOR_STATE_ASY_HSYNCPOL; 12783f4f3b5fSThierry Reding 12793f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_PVSYNC) 12803f4f3b5fSThierry Reding value &= ~SOR_STATE_ASY_VSYNCPOL; 12813f4f3b5fSThierry Reding 12823f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_NVSYNC) 12833f4f3b5fSThierry Reding value |= SOR_STATE_ASY_VSYNCPOL; 12843f4f3b5fSThierry Reding 128534fa183bSThierry Reding switch (config.bits_per_pixel) { 128634fa183bSThierry Reding case 24: 128734fa183bSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; 128834fa183bSThierry Reding break; 128934fa183bSThierry Reding 129034fa183bSThierry Reding case 18: 129134fa183bSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; 129234fa183bSThierry Reding break; 129334fa183bSThierry Reding 129434fa183bSThierry Reding default: 129534fa183bSThierry Reding BUG(); 129634fa183bSThierry Reding break; 129734fa183bSThierry Reding } 129834fa183bSThierry Reding 1299a9a9e4fdSThierry Reding tegra_sor_writel(sor, value, SOR_STATE1); 13006b6b6042SThierry Reding 13016b6b6042SThierry Reding /* 13026b6b6042SThierry Reding * TODO: The video timing programming below doesn't seem to match the 13036b6b6042SThierry Reding * register definitions. 13046b6b6042SThierry Reding */ 13056b6b6042SThierry Reding 13066b6b6042SThierry Reding value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); 130751511d05SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); 13086b6b6042SThierry Reding 13096b6b6042SThierry Reding vse = mode->vsync_end - mode->vsync_start - 1; 13106b6b6042SThierry Reding hse = mode->hsync_end - mode->hsync_start - 1; 13116b6b6042SThierry Reding 13126b6b6042SThierry Reding value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); 131351511d05SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); 13146b6b6042SThierry Reding 13156b6b6042SThierry Reding vbe = vse + (mode->vsync_start - mode->vdisplay); 13166b6b6042SThierry Reding hbe = hse + (mode->hsync_start - mode->hdisplay); 13176b6b6042SThierry Reding 13186b6b6042SThierry Reding value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); 131951511d05SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); 13206b6b6042SThierry Reding 13216b6b6042SThierry Reding vbs = vbe + mode->vdisplay; 13226b6b6042SThierry Reding hbs = hbe + mode->hdisplay; 13236b6b6042SThierry Reding 13246b6b6042SThierry Reding value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); 132551511d05SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); 132651511d05SThierry Reding 132751511d05SThierry Reding tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe)); 13286b6b6042SThierry Reding 13296b6b6042SThierry Reding /* CSTM (LVDS, link A/B, upper) */ 1330143b1df2SStéphane Marchesin value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | 13316b6b6042SThierry Reding SOR_CSTM_UPPER; 13326b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CSTM); 13336b6b6042SThierry Reding 13346b6b6042SThierry Reding /* PWM setup */ 13356b6b6042SThierry Reding err = tegra_sor_setup_pwm(sor, 250); 1336*850bab44SThierry Reding if (err < 0) 13376b6b6042SThierry Reding dev_err(sor->dev, "failed to setup PWM: %d\n", err); 13386b6b6042SThierry Reding 1339666cb873SThierry Reding tegra_sor_update(sor); 1340666cb873SThierry Reding 13416b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 13426b6b6042SThierry Reding value |= SOR_ENABLE; 13436b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 13446b6b6042SThierry Reding 1345666cb873SThierry Reding tegra_dc_commit(dc); 13466b6b6042SThierry Reding 13476b6b6042SThierry Reding err = tegra_sor_attach(sor); 1348*850bab44SThierry Reding if (err < 0) 13496b6b6042SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 13506b6b6042SThierry Reding 13516b6b6042SThierry Reding err = tegra_sor_wakeup(sor); 1352*850bab44SThierry Reding if (err < 0) 13536b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DC: %d\n", err); 13546b6b6042SThierry Reding 13556fad8f66SThierry Reding if (output->panel) 13566fad8f66SThierry Reding drm_panel_enable(output->panel); 13576b6b6042SThierry Reding } 13586b6b6042SThierry Reding 135982f1511cSThierry Reding static int 136082f1511cSThierry Reding tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, 136182f1511cSThierry Reding struct drm_crtc_state *crtc_state, 136282f1511cSThierry Reding struct drm_connector_state *conn_state) 136382f1511cSThierry Reding { 136482f1511cSThierry Reding struct tegra_output *output = encoder_to_output(encoder); 136582f1511cSThierry Reding struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); 136682f1511cSThierry Reding unsigned long pclk = crtc_state->mode.clock * 1000; 136782f1511cSThierry Reding struct tegra_sor *sor = to_sor(output); 136882f1511cSThierry Reding int err; 136982f1511cSThierry Reding 137082f1511cSThierry Reding err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, 137182f1511cSThierry Reding pclk, 0); 137282f1511cSThierry Reding if (err < 0) { 137382f1511cSThierry Reding dev_err(output->dev, "failed to setup CRTC state: %d\n", err); 137482f1511cSThierry Reding return err; 137582f1511cSThierry Reding } 137682f1511cSThierry Reding 137782f1511cSThierry Reding return 0; 137882f1511cSThierry Reding } 137982f1511cSThierry Reding 1380*850bab44SThierry Reding static const struct drm_encoder_helper_funcs tegra_sor_edp_helper_funcs = { 1381*850bab44SThierry Reding .disable = tegra_sor_edp_disable, 1382*850bab44SThierry Reding .enable = tegra_sor_edp_enable, 138382f1511cSThierry Reding .atomic_check = tegra_sor_encoder_atomic_check, 13846b6b6042SThierry Reding }; 13856b6b6042SThierry Reding 13866b6b6042SThierry Reding static int tegra_sor_init(struct host1x_client *client) 13876b6b6042SThierry Reding { 13889910f5c4SThierry Reding struct drm_device *drm = dev_get_drvdata(client->parent); 13896b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 13906b6b6042SThierry Reding int err; 13916b6b6042SThierry Reding 13926b6b6042SThierry Reding if (!sor->dpaux) 13936b6b6042SThierry Reding return -ENODEV; 13946b6b6042SThierry Reding 13956b6b6042SThierry Reding sor->output.dev = sor->dev; 13966b6b6042SThierry Reding 13976fad8f66SThierry Reding drm_connector_init(drm, &sor->output.connector, 13986fad8f66SThierry Reding &tegra_sor_connector_funcs, 13996fad8f66SThierry Reding DRM_MODE_CONNECTOR_eDP); 14006fad8f66SThierry Reding drm_connector_helper_add(&sor->output.connector, 14016fad8f66SThierry Reding &tegra_sor_connector_helper_funcs); 14026fad8f66SThierry Reding sor->output.connector.dpms = DRM_MODE_DPMS_OFF; 14036fad8f66SThierry Reding 14046fad8f66SThierry Reding drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs, 14056fad8f66SThierry Reding DRM_MODE_ENCODER_TMDS); 14066fad8f66SThierry Reding drm_encoder_helper_add(&sor->output.encoder, 1407*850bab44SThierry Reding &tegra_sor_edp_helper_funcs); 14086fad8f66SThierry Reding 14096fad8f66SThierry Reding drm_mode_connector_attach_encoder(&sor->output.connector, 14106fad8f66SThierry Reding &sor->output.encoder); 14116fad8f66SThierry Reding drm_connector_register(&sor->output.connector); 14126fad8f66SThierry Reding 1413ea130b24SThierry Reding err = tegra_output_init(drm, &sor->output); 1414ea130b24SThierry Reding if (err < 0) { 1415ea130b24SThierry Reding dev_err(client->dev, "failed to initialize output: %d\n", err); 1416ea130b24SThierry Reding return err; 1417ea130b24SThierry Reding } 14186fad8f66SThierry Reding 1419ea130b24SThierry Reding sor->output.encoder.possible_crtcs = 0x3; 14206b6b6042SThierry Reding 1421a82752e1SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 14221b0c7b48SThierry Reding err = tegra_sor_debugfs_init(sor, drm->primary); 1423a82752e1SThierry Reding if (err < 0) 1424a82752e1SThierry Reding dev_err(sor->dev, "debugfs setup failed: %d\n", err); 1425a82752e1SThierry Reding } 1426a82752e1SThierry Reding 14276b6b6042SThierry Reding if (sor->dpaux) { 14286b6b6042SThierry Reding err = tegra_dpaux_attach(sor->dpaux, &sor->output); 14296b6b6042SThierry Reding if (err < 0) { 14306b6b6042SThierry Reding dev_err(sor->dev, "failed to attach DP: %d\n", err); 14316b6b6042SThierry Reding return err; 14326b6b6042SThierry Reding } 14336b6b6042SThierry Reding } 14346b6b6042SThierry Reding 1435535a65dbSTomeu Vizoso /* 1436535a65dbSTomeu Vizoso * XXX: Remove this reset once proper hand-over from firmware to 1437535a65dbSTomeu Vizoso * kernel is possible. 1438535a65dbSTomeu Vizoso */ 1439535a65dbSTomeu Vizoso err = reset_control_assert(sor->rst); 1440535a65dbSTomeu Vizoso if (err < 0) { 1441535a65dbSTomeu Vizoso dev_err(sor->dev, "failed to assert SOR reset: %d\n", err); 1442535a65dbSTomeu Vizoso return err; 1443535a65dbSTomeu Vizoso } 1444535a65dbSTomeu Vizoso 14456fad8f66SThierry Reding err = clk_prepare_enable(sor->clk); 14466fad8f66SThierry Reding if (err < 0) { 14476fad8f66SThierry Reding dev_err(sor->dev, "failed to enable clock: %d\n", err); 14486fad8f66SThierry Reding return err; 14496fad8f66SThierry Reding } 14506fad8f66SThierry Reding 1451535a65dbSTomeu Vizoso usleep_range(1000, 3000); 1452535a65dbSTomeu Vizoso 1453535a65dbSTomeu Vizoso err = reset_control_deassert(sor->rst); 1454535a65dbSTomeu Vizoso if (err < 0) { 1455535a65dbSTomeu Vizoso dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err); 1456535a65dbSTomeu Vizoso return err; 1457535a65dbSTomeu Vizoso } 1458535a65dbSTomeu Vizoso 14596fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_safe); 14606fad8f66SThierry Reding if (err < 0) 14616fad8f66SThierry Reding return err; 14626fad8f66SThierry Reding 14636fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_dp); 14646fad8f66SThierry Reding if (err < 0) 14656fad8f66SThierry Reding return err; 14666fad8f66SThierry Reding 14676b6b6042SThierry Reding return 0; 14686b6b6042SThierry Reding } 14696b6b6042SThierry Reding 14706b6b6042SThierry Reding static int tegra_sor_exit(struct host1x_client *client) 14716b6b6042SThierry Reding { 14726b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 14736b6b6042SThierry Reding int err; 14746b6b6042SThierry Reding 1475328ec69eSThierry Reding tegra_output_exit(&sor->output); 1476328ec69eSThierry Reding 14776b6b6042SThierry Reding if (sor->dpaux) { 14786b6b6042SThierry Reding err = tegra_dpaux_detach(sor->dpaux); 14796b6b6042SThierry Reding if (err < 0) { 14806b6b6042SThierry Reding dev_err(sor->dev, "failed to detach DP: %d\n", err); 14816b6b6042SThierry Reding return err; 14826b6b6042SThierry Reding } 14836b6b6042SThierry Reding } 14846b6b6042SThierry Reding 14856fad8f66SThierry Reding clk_disable_unprepare(sor->clk_safe); 14866fad8f66SThierry Reding clk_disable_unprepare(sor->clk_dp); 14876fad8f66SThierry Reding clk_disable_unprepare(sor->clk); 14886fad8f66SThierry Reding 14894009c224SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) 14904009c224SThierry Reding tegra_sor_debugfs_exit(sor); 1491a82752e1SThierry Reding 14926b6b6042SThierry Reding return 0; 14936b6b6042SThierry Reding } 14946b6b6042SThierry Reding 14956b6b6042SThierry Reding static const struct host1x_client_ops sor_client_ops = { 14966b6b6042SThierry Reding .init = tegra_sor_init, 14976b6b6042SThierry Reding .exit = tegra_sor_exit, 14986b6b6042SThierry Reding }; 14996b6b6042SThierry Reding 15006b6b6042SThierry Reding static int tegra_sor_probe(struct platform_device *pdev) 15016b6b6042SThierry Reding { 15026b6b6042SThierry Reding struct device_node *np; 15036b6b6042SThierry Reding struct tegra_sor *sor; 15046b6b6042SThierry Reding struct resource *regs; 15056b6b6042SThierry Reding int err; 15066b6b6042SThierry Reding 15076b6b6042SThierry Reding sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); 15086b6b6042SThierry Reding if (!sor) 15096b6b6042SThierry Reding return -ENOMEM; 15106b6b6042SThierry Reding 15116b6b6042SThierry Reding sor->output.dev = sor->dev = &pdev->dev; 15126b6b6042SThierry Reding 15136b6b6042SThierry Reding np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0); 15146b6b6042SThierry Reding if (np) { 15156b6b6042SThierry Reding sor->dpaux = tegra_dpaux_find_by_of_node(np); 15166b6b6042SThierry Reding of_node_put(np); 15176b6b6042SThierry Reding 15186b6b6042SThierry Reding if (!sor->dpaux) 15196b6b6042SThierry Reding return -EPROBE_DEFER; 15206b6b6042SThierry Reding } 15216b6b6042SThierry Reding 15226b6b6042SThierry Reding err = tegra_output_probe(&sor->output); 15234dbdc740SThierry Reding if (err < 0) { 15244dbdc740SThierry Reding dev_err(&pdev->dev, "failed to probe output: %d\n", err); 15256b6b6042SThierry Reding return err; 15264dbdc740SThierry Reding } 15276b6b6042SThierry Reding 15286b6b6042SThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15296b6b6042SThierry Reding sor->regs = devm_ioremap_resource(&pdev->dev, regs); 15306b6b6042SThierry Reding if (IS_ERR(sor->regs)) 15316b6b6042SThierry Reding return PTR_ERR(sor->regs); 15326b6b6042SThierry Reding 15336b6b6042SThierry Reding sor->rst = devm_reset_control_get(&pdev->dev, "sor"); 15344dbdc740SThierry Reding if (IS_ERR(sor->rst)) { 15354dbdc740SThierry Reding dev_err(&pdev->dev, "failed to get reset control: %ld\n", 15364dbdc740SThierry Reding PTR_ERR(sor->rst)); 15376b6b6042SThierry Reding return PTR_ERR(sor->rst); 15384dbdc740SThierry Reding } 15396b6b6042SThierry Reding 15406b6b6042SThierry Reding sor->clk = devm_clk_get(&pdev->dev, NULL); 15414dbdc740SThierry Reding if (IS_ERR(sor->clk)) { 15424dbdc740SThierry Reding dev_err(&pdev->dev, "failed to get module clock: %ld\n", 15434dbdc740SThierry Reding PTR_ERR(sor->clk)); 15446b6b6042SThierry Reding return PTR_ERR(sor->clk); 15454dbdc740SThierry Reding } 15466b6b6042SThierry Reding 15476b6b6042SThierry Reding sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); 15484dbdc740SThierry Reding if (IS_ERR(sor->clk_parent)) { 15494dbdc740SThierry Reding dev_err(&pdev->dev, "failed to get parent clock: %ld\n", 15504dbdc740SThierry Reding PTR_ERR(sor->clk_parent)); 15516b6b6042SThierry Reding return PTR_ERR(sor->clk_parent); 15524dbdc740SThierry Reding } 15536b6b6042SThierry Reding 15546b6b6042SThierry Reding sor->clk_safe = devm_clk_get(&pdev->dev, "safe"); 15554dbdc740SThierry Reding if (IS_ERR(sor->clk_safe)) { 15564dbdc740SThierry Reding dev_err(&pdev->dev, "failed to get safe clock: %ld\n", 15574dbdc740SThierry Reding PTR_ERR(sor->clk_safe)); 15586b6b6042SThierry Reding return PTR_ERR(sor->clk_safe); 15594dbdc740SThierry Reding } 15606b6b6042SThierry Reding 15616b6b6042SThierry Reding sor->clk_dp = devm_clk_get(&pdev->dev, "dp"); 15624dbdc740SThierry Reding if (IS_ERR(sor->clk_dp)) { 15634dbdc740SThierry Reding dev_err(&pdev->dev, "failed to get DP clock: %ld\n", 15644dbdc740SThierry Reding PTR_ERR(sor->clk_dp)); 15656b6b6042SThierry Reding return PTR_ERR(sor->clk_dp); 15664dbdc740SThierry Reding } 15676b6b6042SThierry Reding 15686b6b6042SThierry Reding INIT_LIST_HEAD(&sor->client.list); 15696b6b6042SThierry Reding sor->client.ops = &sor_client_ops; 15706b6b6042SThierry Reding sor->client.dev = &pdev->dev; 15716b6b6042SThierry Reding 15726b6b6042SThierry Reding err = host1x_client_register(&sor->client); 15736b6b6042SThierry Reding if (err < 0) { 15746b6b6042SThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 15756b6b6042SThierry Reding err); 15766b6b6042SThierry Reding return err; 15776b6b6042SThierry Reding } 15786b6b6042SThierry Reding 15796b6b6042SThierry Reding platform_set_drvdata(pdev, sor); 15806b6b6042SThierry Reding 15816b6b6042SThierry Reding return 0; 15826b6b6042SThierry Reding } 15836b6b6042SThierry Reding 15846b6b6042SThierry Reding static int tegra_sor_remove(struct platform_device *pdev) 15856b6b6042SThierry Reding { 15866b6b6042SThierry Reding struct tegra_sor *sor = platform_get_drvdata(pdev); 15876b6b6042SThierry Reding int err; 15886b6b6042SThierry Reding 15896b6b6042SThierry Reding err = host1x_client_unregister(&sor->client); 15906b6b6042SThierry Reding if (err < 0) { 15916b6b6042SThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 15926b6b6042SThierry Reding err); 15936b6b6042SThierry Reding return err; 15946b6b6042SThierry Reding } 15956b6b6042SThierry Reding 1596328ec69eSThierry Reding tegra_output_remove(&sor->output); 15976b6b6042SThierry Reding 15986b6b6042SThierry Reding return 0; 15996b6b6042SThierry Reding } 16006b6b6042SThierry Reding 16016b6b6042SThierry Reding static const struct of_device_id tegra_sor_of_match[] = { 16026b6b6042SThierry Reding { .compatible = "nvidia,tegra124-sor", }, 16036b6b6042SThierry Reding { }, 16046b6b6042SThierry Reding }; 1605ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_sor_of_match); 16066b6b6042SThierry Reding 16076b6b6042SThierry Reding struct platform_driver tegra_sor_driver = { 16086b6b6042SThierry Reding .driver = { 16096b6b6042SThierry Reding .name = "tegra-sor", 16106b6b6042SThierry Reding .of_match_table = tegra_sor_of_match, 16116b6b6042SThierry Reding }, 16126b6b6042SThierry Reding .probe = tegra_sor_probe, 16136b6b6042SThierry Reding .remove = tegra_sor_remove, 16146b6b6042SThierry Reding }; 1615