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