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 4186f5c52dSThierry Reding struct mutex lock; 426b6b6042SThierry Reding bool enabled; 43a82752e1SThierry Reding 44a82752e1SThierry Reding struct dentry *debugfs; 456b6b6042SThierry Reding }; 466b6b6042SThierry Reding 4734fa183bSThierry Reding struct tegra_sor_config { 4834fa183bSThierry Reding u32 bits_per_pixel; 4934fa183bSThierry Reding 5034fa183bSThierry Reding u32 active_polarity; 5134fa183bSThierry Reding u32 active_count; 5234fa183bSThierry Reding u32 tu_size; 5334fa183bSThierry Reding u32 active_frac; 5434fa183bSThierry Reding u32 watermark; 557890b576SThierry Reding 567890b576SThierry Reding u32 hblank_symbols; 577890b576SThierry Reding u32 vblank_symbols; 5834fa183bSThierry Reding }; 5934fa183bSThierry Reding 606b6b6042SThierry Reding static inline struct tegra_sor * 616b6b6042SThierry Reding host1x_client_to_sor(struct host1x_client *client) 626b6b6042SThierry Reding { 636b6b6042SThierry Reding return container_of(client, struct tegra_sor, client); 646b6b6042SThierry Reding } 656b6b6042SThierry Reding 666b6b6042SThierry Reding static inline struct tegra_sor *to_sor(struct tegra_output *output) 676b6b6042SThierry Reding { 686b6b6042SThierry Reding return container_of(output, struct tegra_sor, output); 696b6b6042SThierry Reding } 706b6b6042SThierry Reding 716b6b6042SThierry Reding static inline unsigned long tegra_sor_readl(struct tegra_sor *sor, 726b6b6042SThierry Reding unsigned long offset) 736b6b6042SThierry Reding { 746b6b6042SThierry Reding return readl(sor->regs + (offset << 2)); 756b6b6042SThierry Reding } 766b6b6042SThierry Reding 776b6b6042SThierry Reding static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value, 786b6b6042SThierry Reding unsigned long offset) 796b6b6042SThierry Reding { 806b6b6042SThierry Reding writel(value, sor->regs + (offset << 2)); 816b6b6042SThierry Reding } 826b6b6042SThierry Reding 836b6b6042SThierry Reding static int tegra_sor_dp_train_fast(struct tegra_sor *sor, 846b6b6042SThierry Reding struct drm_dp_link *link) 856b6b6042SThierry Reding { 866b6b6042SThierry Reding unsigned long value; 876b6b6042SThierry Reding unsigned int i; 886b6b6042SThierry Reding u8 pattern; 896b6b6042SThierry Reding int err; 906b6b6042SThierry Reding 916b6b6042SThierry Reding /* setup lane parameters */ 926b6b6042SThierry Reding value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) | 936b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE2(0x40) | 946b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE1(0x40) | 956b6b6042SThierry Reding SOR_LANE_DRIVE_CURRENT_LANE0(0x40); 966b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT_0); 976b6b6042SThierry Reding 986b6b6042SThierry Reding value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) | 996b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE2(0x0f) | 1006b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE1(0x0f) | 1016b6b6042SThierry Reding SOR_LANE_PREEMPHASIS_LANE0(0x0f); 1026b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS_0); 1036b6b6042SThierry Reding 1046b6b6042SThierry Reding value = SOR_LANE_POST_CURSOR_LANE3(0x00) | 1056b6b6042SThierry Reding SOR_LANE_POST_CURSOR_LANE2(0x00) | 1066b6b6042SThierry Reding SOR_LANE_POST_CURSOR_LANE1(0x00) | 1076b6b6042SThierry Reding SOR_LANE_POST_CURSOR_LANE0(0x00); 1086b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_POST_CURSOR_0); 1096b6b6042SThierry Reding 1106b6b6042SThierry Reding /* disable LVDS mode */ 1116b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_LVDS); 1126b6b6042SThierry Reding 1136b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 1146b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU_ENABLE; 1156b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_TX_PU_MASK; 1166b6b6042SThierry Reding value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */ 1176b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 1186b6b6042SThierry Reding 1196b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 1206b6b6042SThierry Reding value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 1216b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0; 1226b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 1236b6b6042SThierry Reding 1246b6b6042SThierry Reding usleep_range(10, 100); 1256b6b6042SThierry Reding 1266b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 1276b6b6042SThierry Reding value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | 1286b6b6042SThierry Reding SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0); 1296b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 1306b6b6042SThierry Reding 1316b6b6042SThierry Reding err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B); 1326b6b6042SThierry Reding if (err < 0) 1336b6b6042SThierry Reding return err; 1346b6b6042SThierry Reding 1356b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 1366b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 1376b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 1386b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN1; 1396b6b6042SThierry Reding value = (value << 8) | lane; 1406b6b6042SThierry Reding } 1416b6b6042SThierry Reding 1426b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 1436b6b6042SThierry Reding 1446b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_1; 1456b6b6042SThierry Reding 1466b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 1476b6b6042SThierry Reding if (err < 0) 1486b6b6042SThierry Reding return err; 1496b6b6042SThierry Reding 1506b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_SPARE_0); 1516b6b6042SThierry Reding value |= SOR_DP_SPARE_SEQ_ENABLE; 1526b6b6042SThierry Reding value &= ~SOR_DP_SPARE_PANEL_INTERNAL; 1536b6b6042SThierry Reding value |= SOR_DP_SPARE_MACRO_SOR_CLK; 1546b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_SPARE_0); 1556b6b6042SThierry Reding 1566b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 1576b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 1586b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_NONE | 1596b6b6042SThierry Reding SOR_DP_TPG_PATTERN_TRAIN2; 1606b6b6042SThierry Reding value = (value << 8) | lane; 1616b6b6042SThierry Reding } 1626b6b6042SThierry Reding 1636b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 1646b6b6042SThierry Reding 1656b6b6042SThierry Reding pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2; 1666b6b6042SThierry Reding 1676b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 1686b6b6042SThierry Reding if (err < 0) 1696b6b6042SThierry Reding return err; 1706b6b6042SThierry Reding 1716b6b6042SThierry Reding for (i = 0, value = 0; i < link->num_lanes; i++) { 1726b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 1736b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 1746b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 1756b6b6042SThierry Reding value = (value << 8) | lane; 1766b6b6042SThierry Reding } 1776b6b6042SThierry Reding 1786b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 1796b6b6042SThierry Reding 1806b6b6042SThierry Reding pattern = DP_TRAINING_PATTERN_DISABLE; 1816b6b6042SThierry Reding 1826b6b6042SThierry Reding err = tegra_dpaux_train(sor->dpaux, link, pattern); 1836b6b6042SThierry Reding if (err < 0) 1846b6b6042SThierry Reding return err; 1856b6b6042SThierry Reding 1866b6b6042SThierry Reding return 0; 1876b6b6042SThierry Reding } 1886b6b6042SThierry Reding 1896b6b6042SThierry Reding static void tegra_sor_super_update(struct tegra_sor *sor) 1906b6b6042SThierry Reding { 1916b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0); 1926b6b6042SThierry Reding tegra_sor_writel(sor, 1, SOR_SUPER_STATE_0); 1936b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0); 1946b6b6042SThierry Reding } 1956b6b6042SThierry Reding 1966b6b6042SThierry Reding static void tegra_sor_update(struct tegra_sor *sor) 1976b6b6042SThierry Reding { 1986b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE_0); 1996b6b6042SThierry Reding tegra_sor_writel(sor, 1, SOR_STATE_0); 2006b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE_0); 2016b6b6042SThierry Reding } 2026b6b6042SThierry Reding 2036b6b6042SThierry Reding static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) 2046b6b6042SThierry Reding { 2056b6b6042SThierry Reding unsigned long value; 2066b6b6042SThierry Reding 2076b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_DIV); 2086b6b6042SThierry Reding value &= ~SOR_PWM_DIV_MASK; 2096b6b6042SThierry Reding value |= 0x400; /* period */ 2106b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_DIV); 2116b6b6042SThierry Reding 2126b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 2136b6b6042SThierry Reding value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK; 2146b6b6042SThierry Reding value |= 0x400; /* duty cycle */ 2156b6b6042SThierry Reding value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */ 2166b6b6042SThierry Reding value |= SOR_PWM_CTL_TRIGGER; 2176b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWM_CTL); 2186b6b6042SThierry Reding 2196b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 2206b6b6042SThierry Reding 2216b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2226b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWM_CTL); 2236b6b6042SThierry Reding if ((value & SOR_PWM_CTL_TRIGGER) == 0) 2246b6b6042SThierry Reding return 0; 2256b6b6042SThierry Reding 2266b6b6042SThierry Reding usleep_range(25, 100); 2276b6b6042SThierry Reding } 2286b6b6042SThierry Reding 2296b6b6042SThierry Reding return -ETIMEDOUT; 2306b6b6042SThierry Reding } 2316b6b6042SThierry Reding 2326b6b6042SThierry Reding static int tegra_sor_attach(struct tegra_sor *sor) 2336b6b6042SThierry Reding { 2346b6b6042SThierry Reding unsigned long value, timeout; 2356b6b6042SThierry Reding 2366b6b6042SThierry Reding /* wake up in normal mode */ 2376b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 2386b6b6042SThierry Reding value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE; 2396b6b6042SThierry Reding value |= SOR_SUPER_STATE_MODE_NORMAL; 2406b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 2416b6b6042SThierry Reding tegra_sor_super_update(sor); 2426b6b6042SThierry Reding 2436b6b6042SThierry Reding /* attach */ 2446b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 2456b6b6042SThierry Reding value |= SOR_SUPER_STATE_ATTACHED; 2466b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 2476b6b6042SThierry Reding tegra_sor_super_update(sor); 2486b6b6042SThierry Reding 2496b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 2506b6b6042SThierry Reding 2516b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2526b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 2536b6b6042SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 2546b6b6042SThierry Reding return 0; 2556b6b6042SThierry Reding 2566b6b6042SThierry Reding usleep_range(25, 100); 2576b6b6042SThierry Reding } 2586b6b6042SThierry Reding 2596b6b6042SThierry Reding return -ETIMEDOUT; 2606b6b6042SThierry Reding } 2616b6b6042SThierry Reding 2626b6b6042SThierry Reding static int tegra_sor_wakeup(struct tegra_sor *sor) 2636b6b6042SThierry Reding { 2646b6b6042SThierry Reding struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); 2656b6b6042SThierry Reding unsigned long value, timeout; 2666b6b6042SThierry Reding 2676b6b6042SThierry Reding /* enable display controller outputs */ 2686b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); 2696b6b6042SThierry Reding value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 2706b6b6042SThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; 2716b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 2726b6b6042SThierry Reding 27362b9e063SThierry Reding tegra_dc_commit(dc); 2746b6b6042SThierry Reding 2756b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 2766b6b6042SThierry Reding 2776b6b6042SThierry Reding /* wait for head to wake up */ 2786b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 2796b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 2806b6b6042SThierry Reding value &= SOR_TEST_HEAD_MODE_MASK; 2816b6b6042SThierry Reding 2826b6b6042SThierry Reding if (value == SOR_TEST_HEAD_MODE_AWAKE) 2836b6b6042SThierry Reding return 0; 2846b6b6042SThierry Reding 2856b6b6042SThierry Reding usleep_range(25, 100); 2866b6b6042SThierry Reding } 2876b6b6042SThierry Reding 2886b6b6042SThierry Reding return -ETIMEDOUT; 2896b6b6042SThierry Reding } 2906b6b6042SThierry Reding 2916b6b6042SThierry Reding static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) 2926b6b6042SThierry Reding { 2936b6b6042SThierry Reding unsigned long value; 2946b6b6042SThierry Reding 2956b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 2966b6b6042SThierry Reding value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; 2976b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 2986b6b6042SThierry Reding 2996b6b6042SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 3006b6b6042SThierry Reding 3016b6b6042SThierry Reding while (time_before(jiffies, timeout)) { 3026b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 3036b6b6042SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 3046b6b6042SThierry Reding return 0; 3056b6b6042SThierry Reding 3066b6b6042SThierry Reding usleep_range(25, 100); 3076b6b6042SThierry Reding } 3086b6b6042SThierry Reding 3096b6b6042SThierry Reding return -ETIMEDOUT; 3106b6b6042SThierry Reding } 3116b6b6042SThierry Reding 31234fa183bSThierry Reding struct tegra_sor_params { 31334fa183bSThierry Reding /* number of link clocks per line */ 31434fa183bSThierry Reding unsigned int num_clocks; 31534fa183bSThierry Reding /* ratio between input and output */ 31634fa183bSThierry Reding u64 ratio; 31734fa183bSThierry Reding /* precision factor */ 31834fa183bSThierry Reding u64 precision; 31934fa183bSThierry Reding 32034fa183bSThierry Reding unsigned int active_polarity; 32134fa183bSThierry Reding unsigned int active_count; 32234fa183bSThierry Reding unsigned int active_frac; 32334fa183bSThierry Reding unsigned int tu_size; 32434fa183bSThierry Reding unsigned int error; 32534fa183bSThierry Reding }; 32634fa183bSThierry Reding 32734fa183bSThierry Reding static int tegra_sor_compute_params(struct tegra_sor *sor, 32834fa183bSThierry Reding struct tegra_sor_params *params, 32934fa183bSThierry Reding unsigned int tu_size) 33034fa183bSThierry Reding { 33134fa183bSThierry Reding u64 active_sym, active_count, frac, approx; 33234fa183bSThierry Reding u32 active_polarity, active_frac = 0; 33334fa183bSThierry Reding const u64 f = params->precision; 33434fa183bSThierry Reding s64 error; 33534fa183bSThierry Reding 33634fa183bSThierry Reding active_sym = params->ratio * tu_size; 33734fa183bSThierry Reding active_count = div_u64(active_sym, f) * f; 33834fa183bSThierry Reding frac = active_sym - active_count; 33934fa183bSThierry Reding 34034fa183bSThierry Reding /* fraction < 0.5 */ 34134fa183bSThierry Reding if (frac >= (f / 2)) { 34234fa183bSThierry Reding active_polarity = 1; 34334fa183bSThierry Reding frac = f - frac; 34434fa183bSThierry Reding } else { 34534fa183bSThierry Reding active_polarity = 0; 34634fa183bSThierry Reding } 34734fa183bSThierry Reding 34834fa183bSThierry Reding if (frac != 0) { 34934fa183bSThierry Reding frac = div_u64(f * f, frac); /* 1/fraction */ 35034fa183bSThierry Reding if (frac <= (15 * f)) { 35134fa183bSThierry Reding active_frac = div_u64(frac, f); 35234fa183bSThierry Reding 35334fa183bSThierry Reding /* round up */ 35434fa183bSThierry Reding if (active_polarity) 35534fa183bSThierry Reding active_frac++; 35634fa183bSThierry Reding } else { 35734fa183bSThierry Reding active_frac = active_polarity ? 1 : 15; 35834fa183bSThierry Reding } 35934fa183bSThierry Reding } 36034fa183bSThierry Reding 36134fa183bSThierry Reding if (active_frac == 1) 36234fa183bSThierry Reding active_polarity = 0; 36334fa183bSThierry Reding 36434fa183bSThierry Reding if (active_polarity == 1) { 36534fa183bSThierry Reding if (active_frac) { 36634fa183bSThierry Reding approx = active_count + (active_frac * (f - 1)) * f; 36734fa183bSThierry Reding approx = div_u64(approx, active_frac * f); 36834fa183bSThierry Reding } else { 36934fa183bSThierry Reding approx = active_count + f; 37034fa183bSThierry Reding } 37134fa183bSThierry Reding } else { 37234fa183bSThierry Reding if (active_frac) 37334fa183bSThierry Reding approx = active_count + div_u64(f, active_frac); 37434fa183bSThierry Reding else 37534fa183bSThierry Reding approx = active_count; 37634fa183bSThierry Reding } 37734fa183bSThierry Reding 37834fa183bSThierry Reding error = div_s64(active_sym - approx, tu_size); 37934fa183bSThierry Reding error *= params->num_clocks; 38034fa183bSThierry Reding 38134fa183bSThierry Reding if (error <= 0 && abs64(error) < params->error) { 38234fa183bSThierry Reding params->active_count = div_u64(active_count, f); 38334fa183bSThierry Reding params->active_polarity = active_polarity; 38434fa183bSThierry Reding params->active_frac = active_frac; 38534fa183bSThierry Reding params->error = abs64(error); 38634fa183bSThierry Reding params->tu_size = tu_size; 38734fa183bSThierry Reding 38834fa183bSThierry Reding if (error == 0) 38934fa183bSThierry Reding return true; 39034fa183bSThierry Reding } 39134fa183bSThierry Reding 39234fa183bSThierry Reding return false; 39334fa183bSThierry Reding } 39434fa183bSThierry Reding 39534fa183bSThierry Reding static int tegra_sor_calc_config(struct tegra_sor *sor, 39634fa183bSThierry Reding struct drm_display_mode *mode, 39734fa183bSThierry Reding struct tegra_sor_config *config, 39834fa183bSThierry Reding struct drm_dp_link *link) 39934fa183bSThierry Reding { 40034fa183bSThierry Reding const u64 f = 100000, link_rate = link->rate * 1000; 40134fa183bSThierry Reding const u64 pclk = mode->clock * 1000; 4027890b576SThierry Reding u64 input, output, watermark, num; 40334fa183bSThierry Reding struct tegra_sor_params params; 40434fa183bSThierry Reding u32 num_syms_per_line; 40534fa183bSThierry Reding unsigned int i; 40634fa183bSThierry Reding 40734fa183bSThierry Reding if (!link_rate || !link->num_lanes || !pclk || !config->bits_per_pixel) 40834fa183bSThierry Reding return -EINVAL; 40934fa183bSThierry Reding 41034fa183bSThierry Reding output = link_rate * 8 * link->num_lanes; 41134fa183bSThierry Reding input = pclk * config->bits_per_pixel; 41234fa183bSThierry Reding 41334fa183bSThierry Reding if (input >= output) 41434fa183bSThierry Reding return -ERANGE; 41534fa183bSThierry Reding 41634fa183bSThierry Reding memset(¶ms, 0, sizeof(params)); 41734fa183bSThierry Reding params.ratio = div64_u64(input * f, output); 41834fa183bSThierry Reding params.num_clocks = div_u64(link_rate * mode->hdisplay, pclk); 41934fa183bSThierry Reding params.precision = f; 42034fa183bSThierry Reding params.error = 64 * f; 42134fa183bSThierry Reding params.tu_size = 64; 42234fa183bSThierry Reding 42334fa183bSThierry Reding for (i = params.tu_size; i >= 32; i--) 42434fa183bSThierry Reding if (tegra_sor_compute_params(sor, ¶ms, i)) 42534fa183bSThierry Reding break; 42634fa183bSThierry Reding 42734fa183bSThierry Reding if (params.active_frac == 0) { 42834fa183bSThierry Reding config->active_polarity = 0; 42934fa183bSThierry Reding config->active_count = params.active_count; 43034fa183bSThierry Reding 43134fa183bSThierry Reding if (!params.active_polarity) 43234fa183bSThierry Reding config->active_count--; 43334fa183bSThierry Reding 43434fa183bSThierry Reding config->tu_size = params.tu_size; 43534fa183bSThierry Reding config->active_frac = 1; 43634fa183bSThierry Reding } else { 43734fa183bSThierry Reding config->active_polarity = params.active_polarity; 43834fa183bSThierry Reding config->active_count = params.active_count; 43934fa183bSThierry Reding config->active_frac = params.active_frac; 44034fa183bSThierry Reding config->tu_size = params.tu_size; 44134fa183bSThierry Reding } 44234fa183bSThierry Reding 44334fa183bSThierry Reding dev_dbg(sor->dev, 44434fa183bSThierry Reding "polarity: %d active count: %d tu size: %d active frac: %d\n", 44534fa183bSThierry Reding config->active_polarity, config->active_count, 44634fa183bSThierry Reding config->tu_size, config->active_frac); 44734fa183bSThierry Reding 44834fa183bSThierry Reding watermark = params.ratio * config->tu_size * (f - params.ratio); 44934fa183bSThierry Reding watermark = div_u64(watermark, f); 45034fa183bSThierry Reding 45134fa183bSThierry Reding watermark = div_u64(watermark + params.error, f); 45234fa183bSThierry Reding config->watermark = watermark + (config->bits_per_pixel / 8) + 2; 45334fa183bSThierry Reding num_syms_per_line = (mode->hdisplay * config->bits_per_pixel) * 45434fa183bSThierry Reding (link->num_lanes * 8); 45534fa183bSThierry Reding 45634fa183bSThierry Reding if (config->watermark > 30) { 45734fa183bSThierry Reding config->watermark = 30; 45834fa183bSThierry Reding dev_err(sor->dev, 45934fa183bSThierry Reding "unable to compute TU size, forcing watermark to %u\n", 46034fa183bSThierry Reding config->watermark); 46134fa183bSThierry Reding } else if (config->watermark > num_syms_per_line) { 46234fa183bSThierry Reding config->watermark = num_syms_per_line; 46334fa183bSThierry Reding dev_err(sor->dev, "watermark too high, forcing to %u\n", 46434fa183bSThierry Reding config->watermark); 46534fa183bSThierry Reding } 46634fa183bSThierry Reding 4677890b576SThierry Reding /* compute the number of symbols per horizontal blanking interval */ 4687890b576SThierry Reding num = ((mode->htotal - mode->hdisplay) - 7) * link_rate; 4697890b576SThierry Reding config->hblank_symbols = div_u64(num, pclk); 4707890b576SThierry Reding 4717890b576SThierry Reding if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 4727890b576SThierry Reding config->hblank_symbols -= 3; 4737890b576SThierry Reding 4747890b576SThierry Reding config->hblank_symbols -= 12 / link->num_lanes; 4757890b576SThierry Reding 4767890b576SThierry Reding /* compute the number of symbols per vertical blanking interval */ 4777890b576SThierry Reding num = (mode->hdisplay - 25) * link_rate; 4787890b576SThierry Reding config->vblank_symbols = div_u64(num, pclk); 4797890b576SThierry Reding config->vblank_symbols -= 36 / link->num_lanes + 4; 4807890b576SThierry Reding 4817890b576SThierry Reding dev_dbg(sor->dev, "blank symbols: H:%u V:%u\n", config->hblank_symbols, 4827890b576SThierry Reding config->vblank_symbols); 4837890b576SThierry Reding 48434fa183bSThierry Reding return 0; 48534fa183bSThierry Reding } 48634fa183bSThierry Reding 4876fad8f66SThierry Reding static int tegra_sor_detach(struct tegra_sor *sor) 4886b6b6042SThierry Reding { 4896fad8f66SThierry Reding unsigned long value, timeout; 4906fad8f66SThierry Reding 4916fad8f66SThierry Reding /* switch to safe mode */ 4926fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 4936fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_MODE_NORMAL; 4946fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 4956fad8f66SThierry Reding tegra_sor_super_update(sor); 4966fad8f66SThierry Reding 4976fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 4986fad8f66SThierry Reding 4996fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5006fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 5016fad8f66SThierry Reding if (value & SOR_PWR_MODE_SAFE) 5026fad8f66SThierry Reding break; 5036fad8f66SThierry Reding } 5046fad8f66SThierry Reding 5056fad8f66SThierry Reding if ((value & SOR_PWR_MODE_SAFE) == 0) 5066fad8f66SThierry Reding return -ETIMEDOUT; 5076fad8f66SThierry Reding 5086fad8f66SThierry Reding /* go to sleep */ 5096fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 5106fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK; 5116fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 5126fad8f66SThierry Reding tegra_sor_super_update(sor); 5136fad8f66SThierry Reding 5146fad8f66SThierry Reding /* detach */ 5156fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); 5166fad8f66SThierry Reding value &= ~SOR_SUPER_STATE_ATTACHED; 5176fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); 5186fad8f66SThierry Reding tegra_sor_super_update(sor); 5196fad8f66SThierry Reding 5206fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5216fad8f66SThierry Reding 5226fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5236fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 5246fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) == 0) 5256fad8f66SThierry Reding break; 5266fad8f66SThierry Reding 5276fad8f66SThierry Reding usleep_range(25, 100); 5286fad8f66SThierry Reding } 5296fad8f66SThierry Reding 5306fad8f66SThierry Reding if ((value & SOR_TEST_ATTACHED) != 0) 5316fad8f66SThierry Reding return -ETIMEDOUT; 5326fad8f66SThierry Reding 5336fad8f66SThierry Reding return 0; 5346fad8f66SThierry Reding } 5356fad8f66SThierry Reding 5366fad8f66SThierry Reding static int tegra_sor_power_down(struct tegra_sor *sor) 5376fad8f66SThierry Reding { 5386fad8f66SThierry Reding unsigned long value, timeout; 5396fad8f66SThierry Reding int err; 5406fad8f66SThierry Reding 5416fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 5426fad8f66SThierry Reding value &= ~SOR_PWR_NORMAL_STATE_PU; 5436fad8f66SThierry Reding value |= SOR_PWR_TRIGGER; 5446fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PWR); 5456fad8f66SThierry Reding 5466fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5476fad8f66SThierry Reding 5486fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5496fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PWR); 5506fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) == 0) 5516fad8f66SThierry Reding return 0; 5526fad8f66SThierry Reding 5536fad8f66SThierry Reding usleep_range(25, 100); 5546fad8f66SThierry Reding } 5556fad8f66SThierry Reding 5566fad8f66SThierry Reding if ((value & SOR_PWR_TRIGGER) != 0) 5576fad8f66SThierry Reding return -ETIMEDOUT; 5586fad8f66SThierry Reding 5596fad8f66SThierry Reding err = clk_set_parent(sor->clk, sor->clk_safe); 5606fad8f66SThierry Reding if (err < 0) 5616fad8f66SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 5626fad8f66SThierry Reding 5636fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 5646fad8f66SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | 5656fad8f66SThierry Reding SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2); 5666fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 5676fad8f66SThierry Reding 5686fad8f66SThierry Reding /* stop lane sequencer */ 5696fad8f66SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP | 5706fad8f66SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_DOWN; 5716fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 5726fad8f66SThierry Reding 5736fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(250); 5746fad8f66SThierry Reding 5756fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 5766fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 5776fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 5786fad8f66SThierry Reding break; 5796fad8f66SThierry Reding 5806fad8f66SThierry Reding usleep_range(25, 100); 5816fad8f66SThierry Reding } 5826fad8f66SThierry Reding 5836fad8f66SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0) 5846fad8f66SThierry Reding return -ETIMEDOUT; 5856fad8f66SThierry Reding 5866fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 5876fad8f66SThierry Reding value |= SOR_PLL_2_PORT_POWERDOWN; 5886fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 5896fad8f66SThierry Reding 5906fad8f66SThierry Reding usleep_range(20, 100); 5916fad8f66SThierry Reding 5926fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_0); 5936fad8f66SThierry Reding value |= SOR_PLL_0_POWER_OFF; 5946fad8f66SThierry Reding value |= SOR_PLL_0_VCOPD; 5956fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 5966fad8f66SThierry Reding 5976fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 5986fad8f66SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD; 5996fad8f66SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; 6006fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 6016fad8f66SThierry Reding 6026fad8f66SThierry Reding usleep_range(20, 100); 6036fad8f66SThierry Reding 6046fad8f66SThierry Reding return 0; 6056fad8f66SThierry Reding } 6066fad8f66SThierry Reding 6076fad8f66SThierry Reding static int tegra_sor_crc_open(struct inode *inode, struct file *file) 6086fad8f66SThierry Reding { 6096fad8f66SThierry Reding file->private_data = inode->i_private; 6106fad8f66SThierry Reding 6116fad8f66SThierry Reding return 0; 6126fad8f66SThierry Reding } 6136fad8f66SThierry Reding 6146fad8f66SThierry Reding static int tegra_sor_crc_release(struct inode *inode, struct file *file) 6156fad8f66SThierry Reding { 6166fad8f66SThierry Reding return 0; 6176fad8f66SThierry Reding } 6186fad8f66SThierry Reding 6196fad8f66SThierry Reding static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout) 6206fad8f66SThierry Reding { 6216fad8f66SThierry Reding u32 value; 6226fad8f66SThierry Reding 6236fad8f66SThierry Reding timeout = jiffies + msecs_to_jiffies(timeout); 6246fad8f66SThierry Reding 6256fad8f66SThierry Reding while (time_before(jiffies, timeout)) { 6266fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_CRC_A); 6276fad8f66SThierry Reding if (value & SOR_CRC_A_VALID) 6286fad8f66SThierry Reding return 0; 6296fad8f66SThierry Reding 6306fad8f66SThierry Reding usleep_range(100, 200); 6316fad8f66SThierry Reding } 6326fad8f66SThierry Reding 6336fad8f66SThierry Reding return -ETIMEDOUT; 6346fad8f66SThierry Reding } 6356fad8f66SThierry Reding 6366fad8f66SThierry Reding static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer, 6376fad8f66SThierry Reding size_t size, loff_t *ppos) 6386fad8f66SThierry Reding { 6396fad8f66SThierry Reding struct tegra_sor *sor = file->private_data; 6406fad8f66SThierry Reding ssize_t num, err; 6416fad8f66SThierry Reding char buf[10]; 6426fad8f66SThierry Reding u32 value; 6436fad8f66SThierry Reding 6446fad8f66SThierry Reding mutex_lock(&sor->lock); 6456fad8f66SThierry Reding 6466fad8f66SThierry Reding if (!sor->enabled) { 6476fad8f66SThierry Reding err = -EAGAIN; 6486fad8f66SThierry Reding goto unlock; 6496fad8f66SThierry Reding } 6506fad8f66SThierry Reding 6516fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_STATE_1); 6526fad8f66SThierry Reding value &= ~SOR_STATE_ASY_CRC_MODE_MASK; 6536fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_STATE_1); 6546fad8f66SThierry Reding 6556fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_CRC_CNTRL); 6566fad8f66SThierry Reding value |= SOR_CRC_CNTRL_ENABLE; 6576fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_CRC_CNTRL); 6586fad8f66SThierry Reding 6596fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_TEST); 6606fad8f66SThierry Reding value &= ~SOR_TEST_CRC_POST_SERIALIZE; 6616fad8f66SThierry Reding tegra_sor_writel(sor, value, SOR_TEST); 6626fad8f66SThierry Reding 6636fad8f66SThierry Reding err = tegra_sor_crc_wait(sor, 100); 6646fad8f66SThierry Reding if (err < 0) 6656fad8f66SThierry Reding goto unlock; 6666fad8f66SThierry Reding 6676fad8f66SThierry Reding tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A); 6686fad8f66SThierry Reding value = tegra_sor_readl(sor, SOR_CRC_B); 6696fad8f66SThierry Reding 6706fad8f66SThierry Reding num = scnprintf(buf, sizeof(buf), "%08x\n", value); 6716fad8f66SThierry Reding 6726fad8f66SThierry Reding err = simple_read_from_buffer(buffer, size, ppos, buf, num); 6736fad8f66SThierry Reding 6746fad8f66SThierry Reding unlock: 6756fad8f66SThierry Reding mutex_unlock(&sor->lock); 6766fad8f66SThierry Reding return err; 6776fad8f66SThierry Reding } 6786fad8f66SThierry Reding 6796fad8f66SThierry Reding static const struct file_operations tegra_sor_crc_fops = { 6806fad8f66SThierry Reding .owner = THIS_MODULE, 6816fad8f66SThierry Reding .open = tegra_sor_crc_open, 6826fad8f66SThierry Reding .read = tegra_sor_crc_read, 6836fad8f66SThierry Reding .release = tegra_sor_crc_release, 6846fad8f66SThierry Reding }; 6856fad8f66SThierry Reding 6866fad8f66SThierry Reding static int tegra_sor_debugfs_init(struct tegra_sor *sor, 6876fad8f66SThierry Reding struct drm_minor *minor) 6886fad8f66SThierry Reding { 6896fad8f66SThierry Reding struct dentry *entry; 6906fad8f66SThierry Reding int err = 0; 6916fad8f66SThierry Reding 6926fad8f66SThierry Reding sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root); 6936fad8f66SThierry Reding if (!sor->debugfs) 6946fad8f66SThierry Reding return -ENOMEM; 6956fad8f66SThierry Reding 6966fad8f66SThierry Reding entry = debugfs_create_file("crc", 0644, sor->debugfs, sor, 6976fad8f66SThierry Reding &tegra_sor_crc_fops); 6986fad8f66SThierry Reding if (!entry) { 6996fad8f66SThierry Reding dev_err(sor->dev, 7006fad8f66SThierry Reding "cannot create /sys/kernel/debug/dri/%s/sor/crc\n", 7016fad8f66SThierry Reding minor->debugfs_root->d_name.name); 7026fad8f66SThierry Reding err = -ENOMEM; 7036fad8f66SThierry Reding goto remove; 7046fad8f66SThierry Reding } 7056fad8f66SThierry Reding 7066fad8f66SThierry Reding return err; 7076fad8f66SThierry Reding 7086fad8f66SThierry Reding remove: 7096fad8f66SThierry Reding debugfs_remove(sor->debugfs); 7106fad8f66SThierry Reding sor->debugfs = NULL; 7116fad8f66SThierry Reding return err; 7126fad8f66SThierry Reding } 7136fad8f66SThierry Reding 7144009c224SThierry Reding static void tegra_sor_debugfs_exit(struct tegra_sor *sor) 7156fad8f66SThierry Reding { 7166fad8f66SThierry Reding debugfs_remove_recursive(sor->debugfs); 7176fad8f66SThierry Reding sor->debugfs = NULL; 7186fad8f66SThierry Reding } 7196fad8f66SThierry Reding 7206fad8f66SThierry Reding static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode) 7216fad8f66SThierry Reding { 7226fad8f66SThierry Reding } 7236fad8f66SThierry Reding 7246fad8f66SThierry Reding static enum drm_connector_status 7256fad8f66SThierry Reding tegra_sor_connector_detect(struct drm_connector *connector, bool force) 7266fad8f66SThierry Reding { 7276fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 7286fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 7296fad8f66SThierry Reding 7306fad8f66SThierry Reding if (sor->dpaux) 7316fad8f66SThierry Reding return tegra_dpaux_detect(sor->dpaux); 7326fad8f66SThierry Reding 7336fad8f66SThierry Reding return connector_status_unknown; 7346fad8f66SThierry Reding } 7356fad8f66SThierry Reding 7366fad8f66SThierry Reding static const struct drm_connector_funcs tegra_sor_connector_funcs = { 7376fad8f66SThierry Reding .dpms = tegra_sor_connector_dpms, 7389d44189fSThierry Reding .reset = drm_atomic_helper_connector_reset, 7396fad8f66SThierry Reding .detect = tegra_sor_connector_detect, 7406fad8f66SThierry Reding .fill_modes = drm_helper_probe_single_connector_modes, 7416fad8f66SThierry Reding .destroy = tegra_output_connector_destroy, 7429d44189fSThierry Reding .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 7434aa3df71SThierry Reding .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 7446fad8f66SThierry Reding }; 7456fad8f66SThierry Reding 7466fad8f66SThierry Reding static int tegra_sor_connector_get_modes(struct drm_connector *connector) 7476fad8f66SThierry Reding { 7486fad8f66SThierry Reding struct tegra_output *output = connector_to_output(connector); 7496fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 7506fad8f66SThierry Reding int err; 7516fad8f66SThierry Reding 7526fad8f66SThierry Reding if (sor->dpaux) 7536fad8f66SThierry Reding tegra_dpaux_enable(sor->dpaux); 7546fad8f66SThierry Reding 7556fad8f66SThierry Reding err = tegra_output_connector_get_modes(connector); 7566fad8f66SThierry Reding 7576fad8f66SThierry Reding if (sor->dpaux) 7586fad8f66SThierry Reding tegra_dpaux_disable(sor->dpaux); 7596fad8f66SThierry Reding 7606fad8f66SThierry Reding return err; 7616fad8f66SThierry Reding } 7626fad8f66SThierry Reding 7636fad8f66SThierry Reding static enum drm_mode_status 7646fad8f66SThierry Reding tegra_sor_connector_mode_valid(struct drm_connector *connector, 7656fad8f66SThierry Reding struct drm_display_mode *mode) 7666fad8f66SThierry Reding { 7676fad8f66SThierry Reding return MODE_OK; 7686fad8f66SThierry Reding } 7696fad8f66SThierry Reding 7706fad8f66SThierry Reding static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = { 7716fad8f66SThierry Reding .get_modes = tegra_sor_connector_get_modes, 7726fad8f66SThierry Reding .mode_valid = tegra_sor_connector_mode_valid, 7736fad8f66SThierry Reding .best_encoder = tegra_output_connector_best_encoder, 7746fad8f66SThierry Reding }; 7756fad8f66SThierry Reding 7766fad8f66SThierry Reding static const struct drm_encoder_funcs tegra_sor_encoder_funcs = { 7776fad8f66SThierry Reding .destroy = tegra_output_encoder_destroy, 7786fad8f66SThierry Reding }; 7796fad8f66SThierry Reding 7806fad8f66SThierry Reding static void tegra_sor_encoder_dpms(struct drm_encoder *encoder, int mode) 7816fad8f66SThierry Reding { 7826fad8f66SThierry Reding } 7836fad8f66SThierry Reding 7846fad8f66SThierry Reding static bool tegra_sor_encoder_mode_fixup(struct drm_encoder *encoder, 7856fad8f66SThierry Reding const struct drm_display_mode *mode, 7866fad8f66SThierry Reding struct drm_display_mode *adjusted) 7876fad8f66SThierry Reding { 7886fad8f66SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 7896fad8f66SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 7906fad8f66SThierry Reding unsigned long pclk = mode->clock * 1000; 7916fad8f66SThierry Reding struct tegra_sor *sor = to_sor(output); 7926fad8f66SThierry Reding int err; 7936fad8f66SThierry Reding 7946fad8f66SThierry Reding err = tegra_dc_setup_clock(dc, sor->clk_parent, pclk, 0); 7956fad8f66SThierry Reding if (err < 0) { 7966fad8f66SThierry Reding dev_err(output->dev, "failed to setup DC clock: %d\n", err); 7976fad8f66SThierry Reding return false; 7986fad8f66SThierry Reding } 7996fad8f66SThierry Reding 8006fad8f66SThierry Reding err = clk_set_rate(sor->clk_parent, pclk); 8016fad8f66SThierry Reding if (err < 0) { 8026fad8f66SThierry Reding dev_err(output->dev, "failed to set clock rate to %lu Hz\n", 8036fad8f66SThierry Reding pclk); 8046fad8f66SThierry Reding return false; 8056fad8f66SThierry Reding } 8066fad8f66SThierry Reding 8076fad8f66SThierry Reding return true; 8086fad8f66SThierry Reding } 8096fad8f66SThierry Reding 8106fad8f66SThierry Reding static void tegra_sor_encoder_prepare(struct drm_encoder *encoder) 8116fad8f66SThierry Reding { 8126fad8f66SThierry Reding } 8136fad8f66SThierry Reding 8146fad8f66SThierry Reding static void tegra_sor_encoder_commit(struct drm_encoder *encoder) 8156fad8f66SThierry Reding { 8166fad8f66SThierry Reding } 8176fad8f66SThierry Reding 8186fad8f66SThierry Reding static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder, 8196fad8f66SThierry Reding struct drm_display_mode *mode, 8206fad8f66SThierry Reding struct drm_display_mode *adjusted) 8216fad8f66SThierry Reding { 8226fad8f66SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 8236fad8f66SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 8246b6b6042SThierry Reding unsigned int vbe, vse, hbe, hse, vbs, hbs, i; 8256b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 82634fa183bSThierry Reding struct tegra_sor_config config; 82734fa183bSThierry Reding struct drm_dp_link link; 82834fa183bSThierry Reding struct drm_dp_aux *aux; 8296b6b6042SThierry Reding unsigned long value; 83086f5c52dSThierry Reding int err = 0; 83186f5c52dSThierry Reding 83286f5c52dSThierry Reding mutex_lock(&sor->lock); 8336b6b6042SThierry Reding 8346b6b6042SThierry Reding if (sor->enabled) 83586f5c52dSThierry Reding goto unlock; 8366b6b6042SThierry Reding 8376b6b6042SThierry Reding err = clk_prepare_enable(sor->clk); 8386b6b6042SThierry Reding if (err < 0) 83986f5c52dSThierry Reding goto unlock; 8406b6b6042SThierry Reding 8416b6b6042SThierry Reding reset_control_deassert(sor->rst); 8426b6b6042SThierry Reding 8436fad8f66SThierry Reding if (output->panel) 8446fad8f66SThierry Reding drm_panel_prepare(output->panel); 8456fad8f66SThierry Reding 84634fa183bSThierry Reding /* FIXME: properly convert to struct drm_dp_aux */ 84734fa183bSThierry Reding aux = (struct drm_dp_aux *)sor->dpaux; 84834fa183bSThierry Reding 8496b6b6042SThierry Reding if (sor->dpaux) { 8506b6b6042SThierry Reding err = tegra_dpaux_enable(sor->dpaux); 8516b6b6042SThierry Reding if (err < 0) 8526b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DP: %d\n", err); 85334fa183bSThierry Reding 85434fa183bSThierry Reding err = drm_dp_link_probe(aux, &link); 85534fa183bSThierry Reding if (err < 0) { 85634fa183bSThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", 85734fa183bSThierry Reding err); 8582263c460SDan Carpenter goto unlock; 85934fa183bSThierry Reding } 8606b6b6042SThierry Reding } 8616b6b6042SThierry Reding 8626b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_safe); 8636b6b6042SThierry Reding if (err < 0) 8646b6b6042SThierry Reding dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); 8656b6b6042SThierry Reding 86634fa183bSThierry Reding memset(&config, 0, sizeof(config)); 867054b1bd1SStéphane Marchesin config.bits_per_pixel = output->connector.display_info.bpc * 3; 86834fa183bSThierry Reding 86934fa183bSThierry Reding err = tegra_sor_calc_config(sor, mode, &config, &link); 87034fa183bSThierry Reding if (err < 0) 87134fa183bSThierry Reding dev_err(sor->dev, "failed to compute link configuration: %d\n", 87234fa183bSThierry Reding err); 87334fa183bSThierry Reding 8746b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 8756b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; 8766b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; 8776b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 8786b6b6042SThierry Reding 8796b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 8806b6b6042SThierry Reding value &= ~SOR_PLL_2_BANDGAP_POWERDOWN; 8816b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 8826b6b6042SThierry Reding usleep_range(20, 100); 8836b6b6042SThierry Reding 8846b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_3); 8856b6b6042SThierry Reding value |= SOR_PLL_3_PLL_VDD_MODE_V3_3; 8866b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_3); 8876b6b6042SThierry Reding 8886b6b6042SThierry Reding value = SOR_PLL_0_ICHPMP(0xf) | SOR_PLL_0_VCOCAP_RST | 8896b6b6042SThierry Reding SOR_PLL_0_PLLREG_LEVEL_V45 | SOR_PLL_0_RESISTOR_EXT; 8906b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 8916b6b6042SThierry Reding 8926b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 8936b6b6042SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD; 8946b6b6042SThierry Reding value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; 8956b6b6042SThierry Reding value |= SOR_PLL_2_LVDS_ENABLE; 8966b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 8976b6b6042SThierry Reding 8986b6b6042SThierry Reding value = SOR_PLL_1_TERM_COMPOUT | SOR_PLL_1_TMDS_TERM; 8996b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_1); 9006b6b6042SThierry Reding 9016b6b6042SThierry Reding while (true) { 9026b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 9036b6b6042SThierry Reding if ((value & SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE) == 0) 9046b6b6042SThierry Reding break; 9056b6b6042SThierry Reding 9066b6b6042SThierry Reding usleep_range(250, 1000); 9076b6b6042SThierry Reding } 9086b6b6042SThierry Reding 9096b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 9106b6b6042SThierry Reding value &= ~SOR_PLL_2_POWERDOWN_OVERRIDE; 9116b6b6042SThierry Reding value &= ~SOR_PLL_2_PORT_POWERDOWN; 9126b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 9136b6b6042SThierry Reding 9146b6b6042SThierry Reding /* 9156b6b6042SThierry Reding * power up 9166b6b6042SThierry Reding */ 9176b6b6042SThierry Reding 9186b6b6042SThierry Reding /* set safe link bandwidth (1.62 Gbps) */ 9196b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 9206b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 9216b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62; 9226b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 9236b6b6042SThierry Reding 9246b6b6042SThierry Reding /* step 1 */ 9256b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 9266b6b6042SThierry Reding value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL_2_PORT_POWERDOWN | 9276b6b6042SThierry Reding SOR_PLL_2_BANDGAP_POWERDOWN; 9286b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 9296b6b6042SThierry Reding 9306b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_0); 9316b6b6042SThierry Reding value |= SOR_PLL_0_VCOPD | SOR_PLL_0_POWER_OFF; 9326b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 9336b6b6042SThierry Reding 9346b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 9356b6b6042SThierry Reding value &= ~SOR_DP_PADCTL_PAD_CAL_PD; 9366b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 9376b6b6042SThierry Reding 9386b6b6042SThierry Reding /* step 2 */ 9396b6b6042SThierry Reding err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS); 9406b6b6042SThierry Reding if (err < 0) { 9416b6b6042SThierry Reding dev_err(sor->dev, "failed to power on I/O rail: %d\n", err); 94286f5c52dSThierry Reding goto unlock; 9436b6b6042SThierry Reding } 9446b6b6042SThierry Reding 9456b6b6042SThierry Reding usleep_range(5, 100); 9466b6b6042SThierry Reding 9476b6b6042SThierry Reding /* step 3 */ 9486b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 9496b6b6042SThierry Reding value &= ~SOR_PLL_2_BANDGAP_POWERDOWN; 9506b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 9516b6b6042SThierry Reding 9526b6b6042SThierry Reding usleep_range(20, 100); 9536b6b6042SThierry Reding 9546b6b6042SThierry Reding /* step 4 */ 9556b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_0); 9566b6b6042SThierry Reding value &= ~SOR_PLL_0_POWER_OFF; 9576b6b6042SThierry Reding value &= ~SOR_PLL_0_VCOPD; 9586b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_0); 9596b6b6042SThierry Reding 9606b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 9616b6b6042SThierry Reding value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; 9626b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 9636b6b6042SThierry Reding 9646b6b6042SThierry Reding usleep_range(200, 1000); 9656b6b6042SThierry Reding 9666b6b6042SThierry Reding /* step 5 */ 9676b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_PLL_2); 9686b6b6042SThierry Reding value &= ~SOR_PLL_2_PORT_POWERDOWN; 9696b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_PLL_2); 9706b6b6042SThierry Reding 9716b6b6042SThierry Reding /* switch to DP clock */ 9726b6b6042SThierry Reding err = clk_set_parent(sor->clk, sor->clk_dp); 9736b6b6042SThierry Reding if (err < 0) 9746b6b6042SThierry Reding dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); 9756b6b6042SThierry Reding 976899451b7SThierry Reding /* power DP lanes */ 9776b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 978899451b7SThierry Reding 979899451b7SThierry Reding if (link.num_lanes <= 2) 980899451b7SThierry Reding value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2); 981899451b7SThierry Reding else 982899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2; 983899451b7SThierry Reding 984899451b7SThierry Reding if (link.num_lanes <= 1) 985899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_1; 986899451b7SThierry Reding else 987899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_1; 988899451b7SThierry Reding 989899451b7SThierry Reding if (link.num_lanes == 0) 990899451b7SThierry Reding value &= ~SOR_DP_PADCTL_PD_TXD_0; 991899451b7SThierry Reding else 992899451b7SThierry Reding value |= SOR_DP_PADCTL_PD_TXD_0; 993899451b7SThierry Reding 9946b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 9956b6b6042SThierry Reding 9966b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); 9976b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 9980c90a184SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(link.num_lanes); 9996b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 10006b6b6042SThierry Reding 10016b6b6042SThierry Reding /* start lane sequencer */ 10026b6b6042SThierry Reding value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | 10036b6b6042SThierry Reding SOR_LANE_SEQ_CTL_POWER_STATE_UP; 10046b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); 10056b6b6042SThierry Reding 10066b6b6042SThierry Reding while (true) { 10076b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); 10086b6b6042SThierry Reding if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) 10096b6b6042SThierry Reding break; 10106b6b6042SThierry Reding 10116b6b6042SThierry Reding usleep_range(250, 1000); 10126b6b6042SThierry Reding } 10136b6b6042SThierry Reding 1014a4263fedSThierry Reding /* set link bandwidth */ 10156b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 10166b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 1017a4263fedSThierry Reding value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; 10186b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 10196b6b6042SThierry Reding 10206b6b6042SThierry Reding /* set linkctl */ 10216b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); 10226b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENABLE; 10236b6b6042SThierry Reding 10246b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; 102534fa183bSThierry Reding value |= SOR_DP_LINKCTL_TU_SIZE(config.tu_size); 10266b6b6042SThierry Reding 10276b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 10286b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 10296b6b6042SThierry Reding 10306b6b6042SThierry Reding for (i = 0, value = 0; i < 4; i++) { 10316b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 10326b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 10336b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 10346b6b6042SThierry Reding value = (value << 8) | lane; 10356b6b6042SThierry Reding } 10366b6b6042SThierry Reding 10376b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 10386b6b6042SThierry Reding 10396b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_CONFIG_0); 10406b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_WATERMARK_MASK; 104134fa183bSThierry Reding value |= SOR_DP_CONFIG_WATERMARK(config.watermark); 10426b6b6042SThierry Reding 10436b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; 104434fa183bSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config.active_count); 10456b6b6042SThierry Reding 10466b6b6042SThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; 104734fa183bSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config.active_frac); 10486b6b6042SThierry Reding 104934fa183bSThierry Reding if (config.active_polarity) 105034fa183bSThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 105134fa183bSThierry Reding else 105234fa183bSThierry Reding value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; 10536b6b6042SThierry Reding 10546b6b6042SThierry Reding value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; 10551f64ae7cSThierry Reding value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; 10566b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_CONFIG_0); 10576b6b6042SThierry Reding 10586b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); 10596b6b6042SThierry Reding value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; 10607890b576SThierry Reding value |= config.hblank_symbols & 0xffff; 10616b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); 10626b6b6042SThierry Reding 10636b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); 10646b6b6042SThierry Reding value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; 10657890b576SThierry Reding value |= config.vblank_symbols & 0xffff; 10666b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); 10676b6b6042SThierry Reding 10686b6b6042SThierry Reding /* enable pad calibration logic */ 10696b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); 10706b6b6042SThierry Reding value |= SOR_DP_PADCTL_PAD_CAL_PD; 10716b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); 10726b6b6042SThierry Reding 10736b6b6042SThierry Reding if (sor->dpaux) { 10746b6b6042SThierry Reding u8 rate, lanes; 10756b6b6042SThierry Reding 10766b6b6042SThierry Reding err = drm_dp_link_probe(aux, &link); 10776b6b6042SThierry Reding if (err < 0) { 10786b6b6042SThierry Reding dev_err(sor->dev, "failed to probe eDP link: %d\n", 10796b6b6042SThierry Reding err); 108086f5c52dSThierry Reding goto unlock; 10816b6b6042SThierry Reding } 10826b6b6042SThierry Reding 10836b6b6042SThierry Reding err = drm_dp_link_power_up(aux, &link); 10846b6b6042SThierry Reding if (err < 0) { 10856b6b6042SThierry Reding dev_err(sor->dev, "failed to power up eDP link: %d\n", 10866b6b6042SThierry Reding err); 108786f5c52dSThierry Reding goto unlock; 10886b6b6042SThierry Reding } 10896b6b6042SThierry Reding 10906b6b6042SThierry Reding err = drm_dp_link_configure(aux, &link); 10916b6b6042SThierry Reding if (err < 0) { 10926b6b6042SThierry Reding dev_err(sor->dev, "failed to configure eDP link: %d\n", 10936b6b6042SThierry Reding err); 109486f5c52dSThierry Reding goto unlock; 10956b6b6042SThierry Reding } 10966b6b6042SThierry Reding 10976b6b6042SThierry Reding rate = drm_dp_link_rate_to_bw_code(link.rate); 10986b6b6042SThierry Reding lanes = link.num_lanes; 10996b6b6042SThierry Reding 11006b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_CLK_CNTRL); 11016b6b6042SThierry Reding value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; 11026b6b6042SThierry Reding value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate); 11036b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CLK_CNTRL); 11046b6b6042SThierry Reding 11056b6b6042SThierry Reding value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); 11066b6b6042SThierry Reding value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; 11076b6b6042SThierry Reding value |= SOR_DP_LINKCTL_LANE_COUNT(lanes); 11086b6b6042SThierry Reding 11096b6b6042SThierry Reding if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) 11106b6b6042SThierry Reding value |= SOR_DP_LINKCTL_ENHANCED_FRAME; 11116b6b6042SThierry Reding 11126b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); 11136b6b6042SThierry Reding 11146b6b6042SThierry Reding /* disable training pattern generator */ 11156b6b6042SThierry Reding 11166b6b6042SThierry Reding for (i = 0; i < link.num_lanes; i++) { 11176b6b6042SThierry Reding unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | 11186b6b6042SThierry Reding SOR_DP_TPG_SCRAMBLER_GALIOS | 11196b6b6042SThierry Reding SOR_DP_TPG_PATTERN_NONE; 11206b6b6042SThierry Reding value = (value << 8) | lane; 11216b6b6042SThierry Reding } 11226b6b6042SThierry Reding 11236b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_DP_TPG); 11246b6b6042SThierry Reding 11256b6b6042SThierry Reding err = tegra_sor_dp_train_fast(sor, &link); 11266b6b6042SThierry Reding if (err < 0) { 11276b6b6042SThierry Reding dev_err(sor->dev, "DP fast link training failed: %d\n", 11286b6b6042SThierry Reding err); 112986f5c52dSThierry Reding goto unlock; 11306b6b6042SThierry Reding } 11316b6b6042SThierry Reding 11326b6b6042SThierry Reding dev_dbg(sor->dev, "fast link training succeeded\n"); 11336b6b6042SThierry Reding } 11346b6b6042SThierry Reding 11356b6b6042SThierry Reding err = tegra_sor_power_up(sor, 250); 11366b6b6042SThierry Reding if (err < 0) { 11376b6b6042SThierry Reding dev_err(sor->dev, "failed to power up SOR: %d\n", err); 113886f5c52dSThierry Reding goto unlock; 11396b6b6042SThierry Reding } 11406b6b6042SThierry Reding 11416b6b6042SThierry Reding /* start display controller in continuous mode */ 11426b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); 11436b6b6042SThierry Reding value |= WRITE_MUX; 11446b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS); 11456b6b6042SThierry Reding 11466b6b6042SThierry Reding tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); 11476b6b6042SThierry Reding tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); 11486b6b6042SThierry Reding 11496b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); 11506b6b6042SThierry Reding value &= ~WRITE_MUX; 11516b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS); 11526b6b6042SThierry Reding 11536b6b6042SThierry Reding /* 11546b6b6042SThierry Reding * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete 11556b6b6042SThierry Reding * raster, associate with display controller) 11566b6b6042SThierry Reding */ 11573f4f3b5fSThierry Reding value = SOR_STATE_ASY_PROTOCOL_DP_A | 11586b6b6042SThierry Reding SOR_STATE_ASY_CRC_MODE_COMPLETE | 11596b6b6042SThierry Reding SOR_STATE_ASY_OWNER(dc->pipe + 1); 116034fa183bSThierry Reding 11613f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_PHSYNC) 11623f4f3b5fSThierry Reding value &= ~SOR_STATE_ASY_HSYNCPOL; 11633f4f3b5fSThierry Reding 11643f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_NHSYNC) 11653f4f3b5fSThierry Reding value |= SOR_STATE_ASY_HSYNCPOL; 11663f4f3b5fSThierry Reding 11673f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_PVSYNC) 11683f4f3b5fSThierry Reding value &= ~SOR_STATE_ASY_VSYNCPOL; 11693f4f3b5fSThierry Reding 11703f4f3b5fSThierry Reding if (mode->flags & DRM_MODE_FLAG_NVSYNC) 11713f4f3b5fSThierry Reding value |= SOR_STATE_ASY_VSYNCPOL; 11723f4f3b5fSThierry Reding 117334fa183bSThierry Reding switch (config.bits_per_pixel) { 117434fa183bSThierry Reding case 24: 117534fa183bSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; 117634fa183bSThierry Reding break; 117734fa183bSThierry Reding 117834fa183bSThierry Reding case 18: 117934fa183bSThierry Reding value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; 118034fa183bSThierry Reding break; 118134fa183bSThierry Reding 118234fa183bSThierry Reding default: 118334fa183bSThierry Reding BUG(); 118434fa183bSThierry Reding break; 118534fa183bSThierry Reding } 118634fa183bSThierry Reding 11876b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_STATE_1); 11886b6b6042SThierry Reding 11896b6b6042SThierry Reding /* 11906b6b6042SThierry Reding * TODO: The video timing programming below doesn't seem to match the 11916b6b6042SThierry Reding * register definitions. 11926b6b6042SThierry Reding */ 11936b6b6042SThierry Reding 11946b6b6042SThierry Reding value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); 11956b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_1(0)); 11966b6b6042SThierry Reding 11976b6b6042SThierry Reding vse = mode->vsync_end - mode->vsync_start - 1; 11986b6b6042SThierry Reding hse = mode->hsync_end - mode->hsync_start - 1; 11996b6b6042SThierry Reding 12006b6b6042SThierry Reding value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); 12016b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_2(0)); 12026b6b6042SThierry Reding 12036b6b6042SThierry Reding vbe = vse + (mode->vsync_start - mode->vdisplay); 12046b6b6042SThierry Reding hbe = hse + (mode->hsync_start - mode->hdisplay); 12056b6b6042SThierry Reding 12066b6b6042SThierry Reding value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); 12076b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_3(0)); 12086b6b6042SThierry Reding 12096b6b6042SThierry Reding vbs = vbe + mode->vdisplay; 12106b6b6042SThierry Reding hbs = hbe + mode->hdisplay; 12116b6b6042SThierry Reding 12126b6b6042SThierry Reding value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); 12136b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_HEAD_STATE_4(0)); 12146b6b6042SThierry Reding 12156b6b6042SThierry Reding /* CSTM (LVDS, link A/B, upper) */ 1216143b1df2SStéphane Marchesin value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | 12176b6b6042SThierry Reding SOR_CSTM_UPPER; 12186b6b6042SThierry Reding tegra_sor_writel(sor, value, SOR_CSTM); 12196b6b6042SThierry Reding 12206b6b6042SThierry Reding /* PWM setup */ 12216b6b6042SThierry Reding err = tegra_sor_setup_pwm(sor, 250); 12226b6b6042SThierry Reding if (err < 0) { 12236b6b6042SThierry Reding dev_err(sor->dev, "failed to setup PWM: %d\n", err); 122486f5c52dSThierry Reding goto unlock; 12256b6b6042SThierry Reding } 12266b6b6042SThierry Reding 12276b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 12286b6b6042SThierry Reding value |= SOR_ENABLE; 12296b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 12306b6b6042SThierry Reding 12316b6b6042SThierry Reding tegra_sor_update(sor); 12326b6b6042SThierry Reding 12336b6b6042SThierry Reding err = tegra_sor_attach(sor); 12346b6b6042SThierry Reding if (err < 0) { 12356b6b6042SThierry Reding dev_err(sor->dev, "failed to attach SOR: %d\n", err); 123686f5c52dSThierry Reding goto unlock; 12376b6b6042SThierry Reding } 12386b6b6042SThierry Reding 12396b6b6042SThierry Reding err = tegra_sor_wakeup(sor); 12406b6b6042SThierry Reding if (err < 0) { 12416b6b6042SThierry Reding dev_err(sor->dev, "failed to enable DC: %d\n", err); 124286f5c52dSThierry Reding goto unlock; 12436b6b6042SThierry Reding } 12446b6b6042SThierry Reding 12456fad8f66SThierry Reding if (output->panel) 12466fad8f66SThierry Reding drm_panel_enable(output->panel); 12476fad8f66SThierry Reding 12486b6b6042SThierry Reding sor->enabled = true; 12496b6b6042SThierry Reding 125086f5c52dSThierry Reding unlock: 125186f5c52dSThierry Reding mutex_unlock(&sor->lock); 12526b6b6042SThierry Reding } 12536b6b6042SThierry Reding 12546fad8f66SThierry Reding static void tegra_sor_encoder_disable(struct drm_encoder *encoder) 12556b6b6042SThierry Reding { 12566fad8f66SThierry Reding struct tegra_output *output = encoder_to_output(encoder); 12576fad8f66SThierry Reding struct tegra_dc *dc = to_tegra_dc(encoder->crtc); 12586b6b6042SThierry Reding struct tegra_sor *sor = to_sor(output); 12596fad8f66SThierry Reding u32 value; 12606fad8f66SThierry Reding int err; 126186f5c52dSThierry Reding 126286f5c52dSThierry Reding mutex_lock(&sor->lock); 12636b6b6042SThierry Reding 12646b6b6042SThierry Reding if (!sor->enabled) 126586f5c52dSThierry Reding goto unlock; 12666b6b6042SThierry Reding 12676fad8f66SThierry Reding if (output->panel) 12686fad8f66SThierry Reding drm_panel_disable(output->panel); 12696fad8f66SThierry Reding 12706b6b6042SThierry Reding err = tegra_sor_detach(sor); 12716b6b6042SThierry Reding if (err < 0) { 12726b6b6042SThierry Reding dev_err(sor->dev, "failed to detach SOR: %d\n", err); 127386f5c52dSThierry Reding goto unlock; 12746b6b6042SThierry Reding } 12756b6b6042SThierry Reding 12766b6b6042SThierry Reding tegra_sor_writel(sor, 0, SOR_STATE_1); 12776b6b6042SThierry Reding tegra_sor_update(sor); 12786b6b6042SThierry Reding 12796b6b6042SThierry Reding /* 12806b6b6042SThierry Reding * The following accesses registers of the display controller, so make 12816b6b6042SThierry Reding * sure it's only executed when the output is attached to one. 12826b6b6042SThierry Reding */ 12836b6b6042SThierry Reding if (dc) { 12846b6b6042SThierry Reding value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); 12856b6b6042SThierry Reding value &= ~SOR_ENABLE; 12866b6b6042SThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); 12876b6b6042SThierry Reding 128862b9e063SThierry Reding tegra_dc_commit(dc); 12896b6b6042SThierry Reding } 12906b6b6042SThierry Reding 12916b6b6042SThierry Reding err = tegra_sor_power_down(sor); 12926b6b6042SThierry Reding if (err < 0) { 12936b6b6042SThierry Reding dev_err(sor->dev, "failed to power down SOR: %d\n", err); 129486f5c52dSThierry Reding goto unlock; 12956b6b6042SThierry Reding } 12966b6b6042SThierry Reding 12976b6b6042SThierry Reding if (sor->dpaux) { 12986b6b6042SThierry Reding err = tegra_dpaux_disable(sor->dpaux); 12996b6b6042SThierry Reding if (err < 0) { 13006b6b6042SThierry Reding dev_err(sor->dev, "failed to disable DP: %d\n", err); 130186f5c52dSThierry Reding goto unlock; 13026b6b6042SThierry Reding } 13036b6b6042SThierry Reding } 13046b6b6042SThierry Reding 13056b6b6042SThierry Reding err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS); 13066b6b6042SThierry Reding if (err < 0) { 13076b6b6042SThierry Reding dev_err(sor->dev, "failed to power off I/O rail: %d\n", err); 130886f5c52dSThierry Reding goto unlock; 13096b6b6042SThierry Reding } 13106b6b6042SThierry Reding 13116fad8f66SThierry Reding if (output->panel) 13126fad8f66SThierry Reding drm_panel_unprepare(output->panel); 13136fad8f66SThierry Reding 13146b6b6042SThierry Reding clk_disable_unprepare(sor->clk); 13156fad8f66SThierry Reding reset_control_assert(sor->rst); 13166b6b6042SThierry Reding 13176b6b6042SThierry Reding sor->enabled = false; 13186b6b6042SThierry Reding 131986f5c52dSThierry Reding unlock: 132086f5c52dSThierry Reding mutex_unlock(&sor->lock); 13216b6b6042SThierry Reding } 13226b6b6042SThierry Reding 1323*82f1511cSThierry Reding static int 1324*82f1511cSThierry Reding tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, 1325*82f1511cSThierry Reding struct drm_crtc_state *crtc_state, 1326*82f1511cSThierry Reding struct drm_connector_state *conn_state) 1327*82f1511cSThierry Reding { 1328*82f1511cSThierry Reding struct tegra_output *output = encoder_to_output(encoder); 1329*82f1511cSThierry Reding struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); 1330*82f1511cSThierry Reding unsigned long pclk = crtc_state->mode.clock * 1000; 1331*82f1511cSThierry Reding struct tegra_sor *sor = to_sor(output); 1332*82f1511cSThierry Reding int err; 1333*82f1511cSThierry Reding 1334*82f1511cSThierry Reding err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, 1335*82f1511cSThierry Reding pclk, 0); 1336*82f1511cSThierry Reding if (err < 0) { 1337*82f1511cSThierry Reding dev_err(output->dev, "failed to setup CRTC state: %d\n", err); 1338*82f1511cSThierry Reding return err; 1339*82f1511cSThierry Reding } 1340*82f1511cSThierry Reding 1341*82f1511cSThierry Reding return 0; 1342*82f1511cSThierry Reding } 1343*82f1511cSThierry Reding 13446fad8f66SThierry Reding static const struct drm_encoder_helper_funcs tegra_sor_encoder_helper_funcs = { 13456fad8f66SThierry Reding .dpms = tegra_sor_encoder_dpms, 13466fad8f66SThierry Reding .mode_fixup = tegra_sor_encoder_mode_fixup, 13476fad8f66SThierry Reding .prepare = tegra_sor_encoder_prepare, 13486fad8f66SThierry Reding .commit = tegra_sor_encoder_commit, 13496fad8f66SThierry Reding .mode_set = tegra_sor_encoder_mode_set, 13506fad8f66SThierry Reding .disable = tegra_sor_encoder_disable, 1351*82f1511cSThierry Reding .atomic_check = tegra_sor_encoder_atomic_check, 13526b6b6042SThierry Reding }; 13536b6b6042SThierry Reding 13546b6b6042SThierry Reding static int tegra_sor_init(struct host1x_client *client) 13556b6b6042SThierry Reding { 13569910f5c4SThierry Reding struct drm_device *drm = dev_get_drvdata(client->parent); 13576b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 13586b6b6042SThierry Reding int err; 13596b6b6042SThierry Reding 13606b6b6042SThierry Reding if (!sor->dpaux) 13616b6b6042SThierry Reding return -ENODEV; 13626b6b6042SThierry Reding 13636b6b6042SThierry Reding sor->output.dev = sor->dev; 13646b6b6042SThierry Reding 13656fad8f66SThierry Reding drm_connector_init(drm, &sor->output.connector, 13666fad8f66SThierry Reding &tegra_sor_connector_funcs, 13676fad8f66SThierry Reding DRM_MODE_CONNECTOR_eDP); 13686fad8f66SThierry Reding drm_connector_helper_add(&sor->output.connector, 13696fad8f66SThierry Reding &tegra_sor_connector_helper_funcs); 13706fad8f66SThierry Reding sor->output.connector.dpms = DRM_MODE_DPMS_OFF; 13716fad8f66SThierry Reding 13726fad8f66SThierry Reding drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs, 13736fad8f66SThierry Reding DRM_MODE_ENCODER_TMDS); 13746fad8f66SThierry Reding drm_encoder_helper_add(&sor->output.encoder, 13756fad8f66SThierry Reding &tegra_sor_encoder_helper_funcs); 13766fad8f66SThierry Reding 13776fad8f66SThierry Reding drm_mode_connector_attach_encoder(&sor->output.connector, 13786fad8f66SThierry Reding &sor->output.encoder); 13796fad8f66SThierry Reding drm_connector_register(&sor->output.connector); 13806fad8f66SThierry Reding 1381ea130b24SThierry Reding err = tegra_output_init(drm, &sor->output); 1382ea130b24SThierry Reding if (err < 0) { 1383ea130b24SThierry Reding dev_err(client->dev, "failed to initialize output: %d\n", err); 1384ea130b24SThierry Reding return err; 1385ea130b24SThierry Reding } 13866fad8f66SThierry Reding 1387ea130b24SThierry Reding sor->output.encoder.possible_crtcs = 0x3; 13886b6b6042SThierry Reding 1389a82752e1SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 13901b0c7b48SThierry Reding err = tegra_sor_debugfs_init(sor, drm->primary); 1391a82752e1SThierry Reding if (err < 0) 1392a82752e1SThierry Reding dev_err(sor->dev, "debugfs setup failed: %d\n", err); 1393a82752e1SThierry Reding } 1394a82752e1SThierry Reding 13956b6b6042SThierry Reding if (sor->dpaux) { 13966b6b6042SThierry Reding err = tegra_dpaux_attach(sor->dpaux, &sor->output); 13976b6b6042SThierry Reding if (err < 0) { 13986b6b6042SThierry Reding dev_err(sor->dev, "failed to attach DP: %d\n", err); 13996b6b6042SThierry Reding return err; 14006b6b6042SThierry Reding } 14016b6b6042SThierry Reding } 14026b6b6042SThierry Reding 14036fad8f66SThierry Reding err = clk_prepare_enable(sor->clk); 14046fad8f66SThierry Reding if (err < 0) { 14056fad8f66SThierry Reding dev_err(sor->dev, "failed to enable clock: %d\n", err); 14066fad8f66SThierry Reding return err; 14076fad8f66SThierry Reding } 14086fad8f66SThierry Reding 14096fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_safe); 14106fad8f66SThierry Reding if (err < 0) 14116fad8f66SThierry Reding return err; 14126fad8f66SThierry Reding 14136fad8f66SThierry Reding err = clk_prepare_enable(sor->clk_dp); 14146fad8f66SThierry Reding if (err < 0) 14156fad8f66SThierry Reding return err; 14166fad8f66SThierry Reding 14176b6b6042SThierry Reding return 0; 14186b6b6042SThierry Reding } 14196b6b6042SThierry Reding 14206b6b6042SThierry Reding static int tegra_sor_exit(struct host1x_client *client) 14216b6b6042SThierry Reding { 14226b6b6042SThierry Reding struct tegra_sor *sor = host1x_client_to_sor(client); 14236b6b6042SThierry Reding int err; 14246b6b6042SThierry Reding 1425328ec69eSThierry Reding tegra_output_exit(&sor->output); 1426328ec69eSThierry Reding 14276b6b6042SThierry Reding if (sor->dpaux) { 14286b6b6042SThierry Reding err = tegra_dpaux_detach(sor->dpaux); 14296b6b6042SThierry Reding if (err < 0) { 14306b6b6042SThierry Reding dev_err(sor->dev, "failed to detach DP: %d\n", err); 14316b6b6042SThierry Reding return err; 14326b6b6042SThierry Reding } 14336b6b6042SThierry Reding } 14346b6b6042SThierry Reding 14356fad8f66SThierry Reding clk_disable_unprepare(sor->clk_safe); 14366fad8f66SThierry Reding clk_disable_unprepare(sor->clk_dp); 14376fad8f66SThierry Reding clk_disable_unprepare(sor->clk); 14386fad8f66SThierry Reding 14394009c224SThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) 14404009c224SThierry Reding tegra_sor_debugfs_exit(sor); 1441a82752e1SThierry Reding 14426b6b6042SThierry Reding return 0; 14436b6b6042SThierry Reding } 14446b6b6042SThierry Reding 14456b6b6042SThierry Reding static const struct host1x_client_ops sor_client_ops = { 14466b6b6042SThierry Reding .init = tegra_sor_init, 14476b6b6042SThierry Reding .exit = tegra_sor_exit, 14486b6b6042SThierry Reding }; 14496b6b6042SThierry Reding 14506b6b6042SThierry Reding static int tegra_sor_probe(struct platform_device *pdev) 14516b6b6042SThierry Reding { 14526b6b6042SThierry Reding struct device_node *np; 14536b6b6042SThierry Reding struct tegra_sor *sor; 14546b6b6042SThierry Reding struct resource *regs; 14556b6b6042SThierry Reding int err; 14566b6b6042SThierry Reding 14576b6b6042SThierry Reding sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); 14586b6b6042SThierry Reding if (!sor) 14596b6b6042SThierry Reding return -ENOMEM; 14606b6b6042SThierry Reding 14616b6b6042SThierry Reding sor->output.dev = sor->dev = &pdev->dev; 14626b6b6042SThierry Reding 14636b6b6042SThierry Reding np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0); 14646b6b6042SThierry Reding if (np) { 14656b6b6042SThierry Reding sor->dpaux = tegra_dpaux_find_by_of_node(np); 14666b6b6042SThierry Reding of_node_put(np); 14676b6b6042SThierry Reding 14686b6b6042SThierry Reding if (!sor->dpaux) 14696b6b6042SThierry Reding return -EPROBE_DEFER; 14706b6b6042SThierry Reding } 14716b6b6042SThierry Reding 14726b6b6042SThierry Reding err = tegra_output_probe(&sor->output); 14736b6b6042SThierry Reding if (err < 0) 14746b6b6042SThierry Reding return err; 14756b6b6042SThierry Reding 14766b6b6042SThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 14776b6b6042SThierry Reding sor->regs = devm_ioremap_resource(&pdev->dev, regs); 14786b6b6042SThierry Reding if (IS_ERR(sor->regs)) 14796b6b6042SThierry Reding return PTR_ERR(sor->regs); 14806b6b6042SThierry Reding 14816b6b6042SThierry Reding sor->rst = devm_reset_control_get(&pdev->dev, "sor"); 14826b6b6042SThierry Reding if (IS_ERR(sor->rst)) 14836b6b6042SThierry Reding return PTR_ERR(sor->rst); 14846b6b6042SThierry Reding 14856b6b6042SThierry Reding sor->clk = devm_clk_get(&pdev->dev, NULL); 14866b6b6042SThierry Reding if (IS_ERR(sor->clk)) 14876b6b6042SThierry Reding return PTR_ERR(sor->clk); 14886b6b6042SThierry Reding 14896b6b6042SThierry Reding sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); 14906b6b6042SThierry Reding if (IS_ERR(sor->clk_parent)) 14916b6b6042SThierry Reding return PTR_ERR(sor->clk_parent); 14926b6b6042SThierry Reding 14936b6b6042SThierry Reding sor->clk_safe = devm_clk_get(&pdev->dev, "safe"); 14946b6b6042SThierry Reding if (IS_ERR(sor->clk_safe)) 14956b6b6042SThierry Reding return PTR_ERR(sor->clk_safe); 14966b6b6042SThierry Reding 14976b6b6042SThierry Reding sor->clk_dp = devm_clk_get(&pdev->dev, "dp"); 14986b6b6042SThierry Reding if (IS_ERR(sor->clk_dp)) 14996b6b6042SThierry Reding return PTR_ERR(sor->clk_dp); 15006b6b6042SThierry Reding 15016b6b6042SThierry Reding INIT_LIST_HEAD(&sor->client.list); 15026b6b6042SThierry Reding sor->client.ops = &sor_client_ops; 15036b6b6042SThierry Reding sor->client.dev = &pdev->dev; 15046b6b6042SThierry Reding 150586f5c52dSThierry Reding mutex_init(&sor->lock); 150686f5c52dSThierry Reding 15076b6b6042SThierry Reding err = host1x_client_register(&sor->client); 15086b6b6042SThierry Reding if (err < 0) { 15096b6b6042SThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 15106b6b6042SThierry Reding err); 15116b6b6042SThierry Reding return err; 15126b6b6042SThierry Reding } 15136b6b6042SThierry Reding 15146b6b6042SThierry Reding platform_set_drvdata(pdev, sor); 15156b6b6042SThierry Reding 15166b6b6042SThierry Reding return 0; 15176b6b6042SThierry Reding } 15186b6b6042SThierry Reding 15196b6b6042SThierry Reding static int tegra_sor_remove(struct platform_device *pdev) 15206b6b6042SThierry Reding { 15216b6b6042SThierry Reding struct tegra_sor *sor = platform_get_drvdata(pdev); 15226b6b6042SThierry Reding int err; 15236b6b6042SThierry Reding 15246b6b6042SThierry Reding err = host1x_client_unregister(&sor->client); 15256b6b6042SThierry Reding if (err < 0) { 15266b6b6042SThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 15276b6b6042SThierry Reding err); 15286b6b6042SThierry Reding return err; 15296b6b6042SThierry Reding } 15306b6b6042SThierry Reding 1531328ec69eSThierry Reding tegra_output_remove(&sor->output); 15326b6b6042SThierry Reding 15336b6b6042SThierry Reding return 0; 15346b6b6042SThierry Reding } 15356b6b6042SThierry Reding 15366b6b6042SThierry Reding static const struct of_device_id tegra_sor_of_match[] = { 15376b6b6042SThierry Reding { .compatible = "nvidia,tegra124-sor", }, 15386b6b6042SThierry Reding { }, 15396b6b6042SThierry Reding }; 1540ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_sor_of_match); 15416b6b6042SThierry Reding 15426b6b6042SThierry Reding struct platform_driver tegra_sor_driver = { 15436b6b6042SThierry Reding .driver = { 15446b6b6042SThierry Reding .name = "tegra-sor", 15456b6b6042SThierry Reding .of_match_table = tegra_sor_of_match, 15466b6b6042SThierry Reding }, 15476b6b6042SThierry Reding .probe = tegra_sor_probe, 15486b6b6042SThierry Reding .remove = tegra_sor_remove, 15496b6b6042SThierry Reding }; 1550