diff options
author | Chao Xu <cxu@nvidia.com> | 2013-05-24 18:35:22 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:05:19 -0400 |
commit | f41eddb73288de4568e5d026b1ae3d08ccc1fef0 (patch) | |
tree | 296b448159c8d695830f2d0edde28ec7d3d579f3 /drivers/video/tegra/dc/dp.c | |
parent | bb38f885525b59e5d0c5778072e45defc10f97f7 (diff) |
video: tegra: dc: Update eDP code
Verified on FPGA (bug 1258447).
Change-Id: Ie95880b99f453d57d659579e6f3b9e6aed393190
Signed-off-by: Chao Xu <cxu@nvidia.com>
Reviewed-on: http://git-master/r/242513
Diffstat (limited to 'drivers/video/tegra/dc/dp.c')
-rw-r--r-- | drivers/video/tegra/dc/dp.c | 508 |
1 files changed, 332 insertions, 176 deletions
diff --git a/drivers/video/tegra/dc/dp.c b/drivers/video/tegra/dc/dp.c index dec8da9df..5aa6f9009 100644 --- a/drivers/video/tegra/dc/dp.c +++ b/drivers/video/tegra/dc/dp.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/video/tegra/dc/dp.c | 2 | * drivers/video/tegra/dc/dp.c |
3 | * | 3 | * |
4 | * Copyright (c) 2011-2012, NVIDIA Corporation. | 4 | * Copyright (c) 2011-2013, NVIDIA Corporation. |
5 | * | 5 | * |
6 | * This software is licensed under the terms of the GNU General Public | 6 | * This software is licensed under the terms of the GNU General Public |
7 | * License version 2, as published by the Free Software Foundation, and | 7 | * License version 2, as published by the Free Software Foundation, and |
@@ -15,19 +15,17 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | 17 | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/err.h> | 18 | #include <linux/err.h> |
20 | #include <linux/fb.h> | ||
21 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
22 | #include <linux/kernel.h> | ||
23 | #include <linux/nvhost.h> | ||
24 | #include <linux/wait.h> | 20 | #include <linux/wait.h> |
25 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/seq_file.h> | ||
24 | #include <linux/debugfs.h> | ||
27 | 25 | ||
28 | #include <mach/clk.h> | ||
29 | #include <mach/dc.h> | 26 | #include <mach/dc.h> |
30 | #include <mach/fb.h> | 27 | #include <mach/fb.h> |
28 | #include <mach/hardware.h> | ||
31 | 29 | ||
32 | #include "dp.h" | 30 | #include "dp.h" |
33 | #include "sor.h" | 31 | #include "sor.h" |
@@ -37,24 +35,23 @@ | |||
37 | 35 | ||
38 | 36 | ||
39 | 37 | ||
40 | static inline unsigned long tegra_dpaux_readl(struct tegra_dc_dp_data *dp, | 38 | static inline u32 tegra_dpaux_readl(struct tegra_dc_dp_data *dp, u32 reg) |
41 | unsigned long reg) | ||
42 | { | 39 | { |
43 | return readl(dp->aux_base + reg * 4); | 40 | return readl(dp->aux_base + reg * 4); |
44 | } | 41 | } |
45 | 42 | ||
46 | static inline void tegra_dpaux_writel(struct tegra_dc_dp_data *dp, | 43 | static inline void tegra_dpaux_writel(struct tegra_dc_dp_data *dp, |
47 | unsigned long reg, unsigned long val) | 44 | u32 reg, u32 val) |
48 | { | 45 | { |
49 | writel(val, dp->aux_base + reg * 4); | 46 | writel(val, dp->aux_base + reg * 4); |
50 | } | 47 | } |
51 | 48 | ||
52 | 49 | ||
53 | static unsigned long tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp, | 50 | static inline u32 tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp, |
54 | u32 reg, u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_ms) | 51 | u32 reg, u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_ms) |
55 | { | 52 | { |
56 | unsigned long timeout_jf = jiffies + msecs_to_jiffies(timeout_ms); | 53 | unsigned long timeout_jf = jiffies + msecs_to_jiffies(timeout_ms); |
57 | u32 reg_val = 0; | 54 | u32 reg_val = 0; |
58 | 55 | ||
59 | do { | 56 | do { |
60 | usleep_range(poll_interval_us, poll_interval_us << 1); | 57 | usleep_range(poll_interval_us, poll_interval_us << 1); |
@@ -70,7 +67,7 @@ static unsigned long tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp, | |||
70 | } | 67 | } |
71 | 68 | ||
72 | 69 | ||
73 | static int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp) | 70 | static inline int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp) |
74 | { | 71 | { |
75 | /* According to DP spec, each aux transaction needs to finish | 72 | /* According to DP spec, each aux transaction needs to finish |
76 | within 40ms. */ | 73 | within 40ms. */ |
@@ -86,46 +83,13 @@ static int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp) | |||
86 | } | 83 | } |
87 | 84 | ||
88 | 85 | ||
89 | static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp) | ||
90 | { | ||
91 | unsigned long reg_val; | ||
92 | |||
93 | /* clear interrupt */ | ||
94 | tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff); | ||
95 | /* do not enable interrupt for now. Enable them when Isr in place */ | ||
96 | tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0); | ||
97 | |||
98 | /* Power up aux/hybrid pads */ | ||
99 | /* TODO: this may not needed for t124 */ | ||
100 | reg_val = DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP; | ||
101 | tegra_dpaux_writel(dp, DPAUX_HYBRID_SPARE, reg_val); | ||
102 | |||
103 | /* Put HYBRID PAD in AUX mode */ | ||
104 | reg_val = tegra_dpaux_readl(dp, DPAUX_HYBRID_PADCTL); | ||
105 | reg_val &= ~DPAUX_HYBRID_PADCTL_MODE_I2C; | ||
106 | reg_val |= DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE; | ||
107 | reg_val &= ~DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV_ENABLE; | ||
108 | reg_val &= ~DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV_ENABLE; | ||
109 | tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL, reg_val); | ||
110 | |||
111 | } | ||
112 | |||
113 | static void tegra_dc_dpaux_disable(struct tegra_dc_dp_data *dp) | ||
114 | { | ||
115 | tegra_dpaux_writel(dp, NV_DPCD_SET_POWER, | ||
116 | NV_DPCD_SET_POWER_VAL_D3_PWRDWN); | ||
117 | |||
118 | /* TODO: power down DPAUX_HYBRID_SPARE too? */ | ||
119 | } | ||
120 | |||
121 | |||
122 | static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | 86 | static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, |
123 | u32 addr, u8 *data, u32 *size, u32 *aux_stat) | 87 | u32 addr, u8 *data, u32 *size, u32 *aux_stat) |
124 | { | 88 | { |
125 | int i; | 89 | int i; |
126 | unsigned long reg_val; | 90 | u32 reg_val; |
127 | u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; | 91 | u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; |
128 | u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; | 92 | u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; |
129 | 93 | ||
130 | if (*size >= DP_AUX_MAX_BYTES) | 94 | if (*size >= DP_AUX_MAX_BYTES) |
131 | return -EINVAL; /* only write one chunk of data */ | 95 | return -EINVAL; /* only write one chunk of data */ |
@@ -142,24 +106,24 @@ static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
142 | return -EINVAL; | 106 | return -EINVAL; |
143 | } | 107 | } |
144 | 108 | ||
145 | #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM | 109 | if (tegra_platform_is_silicon()) { |
146 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); | 110 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); |
147 | if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { | 111 | if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { |
148 | dev_err(&dp->dc->ndev->dev, "dp: HPD is not detected\n"); | 112 | dev_err(&dp->dc->ndev->dev, "dp: HPD is not detected\n"); |
149 | return -EFAULT; | 113 | return -EFAULT; |
114 | } | ||
150 | } | 115 | } |
151 | #endif | ||
152 | 116 | ||
153 | tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); | 117 | tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); |
154 | for (i = 0; i < DP_AUX_MAX_BYTES/4; ++i) { | 118 | for (i = 0; i < DP_AUX_MAX_BYTES/4; ++i) { |
155 | tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), | 119 | tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), |
156 | (unsigned long)*data); | 120 | (u32)*data); |
157 | data += 4; | 121 | data += 4; |
158 | } | 122 | } |
159 | 123 | ||
160 | reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); | 124 | reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); |
161 | reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; | 125 | reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; |
162 | reg_val |= (cmd << DPAUX_DP_AUXCTL_CMD_SHIFT); | 126 | reg_val |= cmd; |
163 | reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; | 127 | reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; |
164 | reg_val |= (*size << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); | 128 | reg_val |= (*size << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); |
165 | 129 | ||
@@ -178,6 +142,10 @@ static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
178 | 142 | ||
179 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); | 143 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); |
180 | 144 | ||
145 | /* Ignore I2C errors on fpga */ | ||
146 | if (tegra_platform_is_fpga()) | ||
147 | *aux_stat &= ~DPAUX_DP_AUXSTAT_REPLYTYPE_I2CNACK; | ||
148 | |||
181 | if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || | 149 | if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || |
182 | (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || | 150 | (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || |
183 | (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || | 151 | (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || |
@@ -186,9 +154,13 @@ static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
186 | dev_dbg(&dp->dc->ndev->dev, | 154 | dev_dbg(&dp->dc->ndev->dev, |
187 | "dp: aux write retry (0x%x) -- %d\n", | 155 | "dp: aux write retry (0x%x) -- %d\n", |
188 | *aux_stat, timeout_retries); | 156 | *aux_stat, timeout_retries); |
157 | /* clear the error bits */ | ||
158 | tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, | ||
159 | *aux_stat); | ||
189 | continue; | 160 | continue; |
190 | } else { | 161 | } else { |
191 | dev_err(&dp->dc->ndev->dev, "dp: aux write got error (0x%x)\n", | 162 | dev_err(&dp->dc->ndev->dev, |
163 | "dp: aux write got error (0x%x)\n", | ||
192 | *aux_stat); | 164 | *aux_stat); |
193 | return -EFAULT; | 165 | return -EFAULT; |
194 | } | 166 | } |
@@ -200,10 +172,14 @@ static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
200 | dev_dbg(&dp->dc->ndev->dev, | 172 | dev_dbg(&dp->dc->ndev->dev, |
201 | "dp: aux write defer (0x%x) -- %d\n", | 173 | "dp: aux write defer (0x%x) -- %d\n", |
202 | *aux_stat, defer_retries); | 174 | *aux_stat, defer_retries); |
175 | /* clear the error bits */ | ||
176 | tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, | ||
177 | *aux_stat); | ||
203 | continue; | 178 | continue; |
204 | } else { | 179 | } else { |
205 | dev_err(&dp->dc->ndev->dev, | 180 | dev_err(&dp->dc->ndev->dev, |
206 | "dp: aux write defer exceeds max retries (0x%x)\n", | 181 | "dp: aux write defer exceeds max retries " |
182 | "(0x%x)\n", | ||
207 | *aux_stat); | 183 | *aux_stat); |
208 | return -EFAULT; | 184 | return -EFAULT; |
209 | } | 185 | } |
@@ -252,9 +228,9 @@ static int tegra_dc_dpaux_write(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr, | |||
252 | static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | 228 | static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, |
253 | u32 addr, u8 *data, u32 *size, u32 *aux_stat) | 229 | u32 addr, u8 *data, u32 *size, u32 *aux_stat) |
254 | { | 230 | { |
255 | unsigned long reg_val; | 231 | u32 reg_val; |
256 | u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; | 232 | u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES; |
257 | u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; | 233 | u32 defer_retries = DP_AUX_DEFER_MAX_TRIES; |
258 | 234 | ||
259 | if (*size >= DP_AUX_MAX_BYTES) | 235 | if (*size >= DP_AUX_MAX_BYTES) |
260 | return -EINVAL; /* only read one chunk */ | 236 | return -EINVAL; /* only read one chunk */ |
@@ -272,19 +248,19 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
272 | return -EINVAL; | 248 | return -EINVAL; |
273 | } | 249 | } |
274 | 250 | ||
275 | #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM | 251 | if (tegra_platform_is_silicon()) { |
276 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); | 252 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); |
277 | if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { | 253 | if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { |
278 | dev_err(&dp->dc->ndev->dev, "dp: HPD is not detected\n"); | 254 | dev_err(&dp->dc->ndev->dev, "dp: HPD is not detected\n"); |
279 | return -EFAULT; | 255 | return -EFAULT; |
256 | } | ||
280 | } | 257 | } |
281 | #endif | ||
282 | 258 | ||
283 | tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); | 259 | tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr); |
284 | 260 | ||
285 | reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); | 261 | reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL); |
286 | reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; | 262 | reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK; |
287 | reg_val |= (cmd << DPAUX_DP_AUXCTL_CMD_SHIFT); | 263 | reg_val |= cmd; |
288 | reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; | 264 | reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD; |
289 | reg_val |= (*size << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); | 265 | reg_val |= (*size << DPAUX_DP_AUXCTL_CMDLEN_SHIFT); |
290 | 266 | ||
@@ -294,7 +270,6 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
294 | usleep_range(DP_DPCP_RETRY_SLEEP_NS, | 270 | usleep_range(DP_DPCP_RETRY_SLEEP_NS, |
295 | DP_DPCP_RETRY_SLEEP_NS << 1); | 271 | DP_DPCP_RETRY_SLEEP_NS << 1); |
296 | 272 | ||
297 | |||
298 | reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; | 273 | reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING; |
299 | tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); | 274 | tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val); |
300 | 275 | ||
@@ -304,6 +279,10 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
304 | 279 | ||
305 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); | 280 | *aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT); |
306 | 281 | ||
282 | /* Ignore I2C errors on fpga */ | ||
283 | if (tegra_platform_is_fpga()) | ||
284 | *aux_stat &= ~DPAUX_DP_AUXSTAT_REPLYTYPE_I2CNACK; | ||
285 | |||
307 | if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || | 286 | if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) || |
308 | (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || | 287 | (*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) || |
309 | (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || | 288 | (*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) || |
@@ -312,9 +291,13 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
312 | dev_dbg(&dp->dc->ndev->dev, | 291 | dev_dbg(&dp->dc->ndev->dev, |
313 | "dp: aux read retry (0x%x) -- %d\n", | 292 | "dp: aux read retry (0x%x) -- %d\n", |
314 | *aux_stat, timeout_retries); | 293 | *aux_stat, timeout_retries); |
294 | /* clear the error bits */ | ||
295 | tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, | ||
296 | *aux_stat); | ||
315 | continue; /* retry */ | 297 | continue; /* retry */ |
316 | } else { | 298 | } else { |
317 | dev_err(&dp->dc->ndev->dev, "dp: aux read got error (0x%x)\n", | 299 | dev_err(&dp->dc->ndev->dev, |
300 | "dp: aux read got error (0x%x)\n", | ||
318 | *aux_stat); | 301 | *aux_stat); |
319 | return -EFAULT; | 302 | return -EFAULT; |
320 | } | 303 | } |
@@ -326,11 +309,14 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
326 | dev_dbg(&dp->dc->ndev->dev, | 309 | dev_dbg(&dp->dc->ndev->dev, |
327 | "dp: aux read defer (0x%x) -- %d\n", | 310 | "dp: aux read defer (0x%x) -- %d\n", |
328 | *aux_stat, defer_retries); | 311 | *aux_stat, defer_retries); |
312 | /* clear the error bits */ | ||
313 | tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT, | ||
314 | *aux_stat); | ||
329 | continue; | 315 | continue; |
330 | } else { | 316 | } else { |
331 | dev_err(&dp->dc->ndev->dev, | 317 | dev_err(&dp->dc->ndev->dev, |
332 | "dp: aux read defer exceeds max retries (0x%x)\n", | 318 | "dp: aux read defer exceeds max retries " |
333 | *aux_stat); | 319 | "(0x%x)\n", *aux_stat); |
334 | return -EFAULT; | 320 | return -EFAULT; |
335 | } | 321 | } |
336 | } | 322 | } |
@@ -345,7 +331,7 @@ static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd, | |||
345 | DPAUX_DP_AUXDATA_READ_W(i)); | 331 | DPAUX_DP_AUXDATA_READ_W(i)); |
346 | 332 | ||
347 | *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); | 333 | *size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK); |
348 | memcpy(temp_data, data, *size); | 334 | memcpy(data, temp_data, *size); |
349 | 335 | ||
350 | return 0; | 336 | return 0; |
351 | } else { | 337 | } else { |
@@ -386,7 +372,7 @@ static int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr, | |||
386 | return ret; | 372 | return ret; |
387 | } | 373 | } |
388 | 374 | ||
389 | static inline int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd, | 375 | static int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd, |
390 | u8 *data_ptr) | 376 | u8 *data_ptr) |
391 | { | 377 | { |
392 | u32 size = 0; | 378 | u32 size = 0; |
@@ -395,7 +381,7 @@ static inline int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd, | |||
395 | 381 | ||
396 | ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, | 382 | ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD, |
397 | cmd, data_ptr, &size, &status); | 383 | cmd, data_ptr, &size, &status); |
398 | if (!ret) | 384 | if (ret) |
399 | dev_err(&dp->dc->ndev->dev, | 385 | dev_err(&dp->dc->ndev->dev, |
400 | "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", | 386 | "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", |
401 | cmd, status); | 387 | cmd, status); |
@@ -403,7 +389,7 @@ static inline int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd, | |||
403 | return ret; | 389 | return ret; |
404 | } | 390 | } |
405 | 391 | ||
406 | static inline int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd, | 392 | static int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd, |
407 | u8 data) | 393 | u8 data) |
408 | { | 394 | { |
409 | u32 size = 0; | 395 | u32 size = 0; |
@@ -412,7 +398,7 @@ static inline int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd, | |||
412 | 398 | ||
413 | ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR, | 399 | ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR, |
414 | cmd, &data, &size, &status); | 400 | cmd, &data, &size, &status); |
415 | if (!ret) | 401 | if (ret) |
416 | dev_err(&dp->dc->ndev->dev, | 402 | dev_err(&dp->dc->ndev->dev, |
417 | "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", | 403 | "dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n", |
418 | cmd, status); | 404 | cmd, status); |
@@ -427,41 +413,128 @@ static inline u64 tegra_div64(u64 dividend, u32 divisor) | |||
427 | } | 413 | } |
428 | 414 | ||
429 | 415 | ||
430 | static int tegra_dc_init_max_link_cfg(struct tegra_dc_dp_data *dp, | 416 | #ifdef CONFIG_DEBUG_FS |
431 | struct tegra_dc_dp_link_config *cfg) | 417 | static int dbg_dp_show(struct seq_file *s, void *unused) |
432 | { | 418 | { |
433 | u8 dpcd_data; | 419 | struct tegra_dc_dp_data *dp = s->private; |
434 | int ret; | ||
435 | 420 | ||
436 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT, | 421 | #define DUMP_REG(a) seq_printf(s, "%-32s %03x %08x\n", \ |
437 | &dpcd_data)); | 422 | #a, a, tegra_dpaux_readl(dp, a)) |
438 | cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK; | ||
439 | 423 | ||
440 | cfg->support_enhanced_framing = | 424 | tegra_dc_io_start(dp->dc); |
441 | (dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ? | 425 | clk_prepare_enable(dp->clk); |
442 | true : false; | ||
443 | 426 | ||
444 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD, | 427 | DUMP_REG(DPAUX_INTR_EN_AUX); |
445 | &dpcd_data)); | 428 | DUMP_REG(DPAUX_INTR_AUX); |
446 | cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT) ? | 429 | DUMP_REG(DPAUX_DP_AUXADDR); |
447 | true : false; | 430 | DUMP_REG(DPAUX_DP_AUXCTL); |
431 | DUMP_REG(DPAUX_DP_AUXSTAT); | ||
432 | DUMP_REG(DPAUX_HPD_CONFIG); | ||
433 | DUMP_REG(DPAUX_HPD_IRQ_CONFIG); | ||
434 | DUMP_REG(DPAUX_DP_AUX_CONFIG); | ||
435 | DUMP_REG(DPAUX_HYBRID_PADCTL); | ||
436 | DUMP_REG(DPAUX_HYBRID_SPARE); | ||
448 | 437 | ||
449 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH, | 438 | clk_disable_unprepare(dp->clk); |
450 | &cfg->max_link_bw)); | 439 | tegra_dc_io_end(dp->dc); |
451 | 440 | ||
452 | cfg->bytes_per_pixel = dp->dc->pdata->fb->bits_per_pixel / 8; | 441 | return 0; |
442 | } | ||
453 | 443 | ||
454 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP, | 444 | static int dbg_dp_open(struct inode *inode, struct file *file) |
455 | &dpcd_data)); | 445 | { |
456 | cfg->alt_scramber_reset_cap = | 446 | return single_open(file, dbg_dp_show, inode->i_private); |
457 | (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ? | 447 | } |
458 | true : false; | ||
459 | cfg->only_enhanced_framing = | ||
460 | (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ? | ||
461 | true : false; | ||
462 | 448 | ||
463 | return 0; | 449 | static const struct file_operations dbg_fops = { |
450 | .open = dbg_dp_open, | ||
451 | .read = seq_read, | ||
452 | .llseek = seq_lseek, | ||
453 | .release = single_release, | ||
454 | }; | ||
455 | |||
456 | static struct dentry *dpdir; | ||
457 | |||
458 | static void tegra_dc_dp_debug_create(struct tegra_dc_dp_data *dp) | ||
459 | { | ||
460 | struct dentry *retval; | ||
461 | |||
462 | dpdir = debugfs_create_dir("tegra_dp", NULL); | ||
463 | if (!dpdir) | ||
464 | return; | ||
465 | retval = debugfs_create_file("regs", S_IRUGO, dpdir, dp, &dbg_fops); | ||
466 | if (!retval) | ||
467 | goto free_out; | ||
468 | return; | ||
469 | free_out: | ||
470 | debugfs_remove_recursive(dpdir); | ||
471 | dpdir = NULL; | ||
472 | return; | ||
464 | } | 473 | } |
474 | #else | ||
475 | static inline void tegra_dc_dp_debug_create(struct tegra_dc_dp_data *dp) | ||
476 | { } | ||
477 | #endif | ||
478 | |||
479 | static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp) | ||
480 | { | ||
481 | /* clear interrupt */ | ||
482 | tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff); | ||
483 | /* do not enable interrupt for now. Enable them when Isr in place */ | ||
484 | tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0); | ||
485 | |||
486 | tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL, | ||
487 | DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 | | ||
488 | DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 | | ||
489 | 0x18 << DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT | | ||
490 | DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE); | ||
491 | } | ||
492 | |||
493 | static void tegra_dc_dpaux_disable(struct tegra_dc_dp_data *dp) | ||
494 | { | ||
495 | tegra_dpaux_writel(dp, NV_DPCD_SET_POWER, | ||
496 | NV_DPCD_SET_POWER_VAL_D3_PWRDWN); | ||
497 | |||
498 | /* TODO: power down DPAUX_HYBRID_SPARE too? */ | ||
499 | } | ||
500 | |||
501 | static void tegra_dc_dp_dump_link_cfg(struct tegra_dc_dp_data *dp, | ||
502 | const struct tegra_dc_dp_link_config *cfg) | ||
503 | { | ||
504 | BUG_ON(!cfg || !cfg->is_valid); | ||
505 | |||
506 | dev_info(&dp->dc->ndev->dev, "DP config: cfg_name cfg_value\n"); | ||
507 | dev_info(&dp->dc->ndev->dev, " Lane Count %d\n", | ||
508 | cfg->max_lane_count); | ||
509 | dev_info(&dp->dc->ndev->dev, " SupportEnhancedFraming %s\n", | ||
510 | cfg->support_enhanced_framing ? "Y" : "N"); | ||
511 | dev_info(&dp->dc->ndev->dev, " Bandwidth %d\n", | ||
512 | cfg->max_link_bw); | ||
513 | dev_info(&dp->dc->ndev->dev, " BPP %d\n", | ||
514 | cfg->bytes_per_pixel); | ||
515 | dev_info(&dp->dc->ndev->dev, " EnhancedFraming %s\n\n", | ||
516 | cfg->enhanced_framing ? "Y" : "N"); | ||
517 | dev_info(&dp->dc->ndev->dev, " Scramble_enabled %s\n", | ||
518 | cfg->scramble_ena ? "Y" : "N"); | ||
519 | dev_info(&dp->dc->ndev->dev, " LinkBW %d\n", | ||
520 | cfg->link_bw); | ||
521 | dev_info(&dp->dc->ndev->dev, " lane_count %d\n", | ||
522 | cfg->lane_count); | ||
523 | dev_info(&dp->dc->ndev->dev, " activespolarity %d\n", | ||
524 | cfg->activepolarity); | ||
525 | dev_info(&dp->dc->ndev->dev, " active_count %d\n", | ||
526 | cfg->active_count); | ||
527 | dev_info(&dp->dc->ndev->dev, " tu_size %d\n", | ||
528 | cfg->tu_size); | ||
529 | dev_info(&dp->dc->ndev->dev, " active_frac %d\n", | ||
530 | cfg->active_frac); | ||
531 | dev_info(&dp->dc->ndev->dev, " watermark %d\n", | ||
532 | cfg->watermark); | ||
533 | dev_info(&dp->dc->ndev->dev, " hblank_sym %d\n", | ||
534 | cfg->hblank_sym); | ||
535 | dev_info(&dp->dc->ndev->dev, " vblank_sym %d\n", | ||
536 | cfg->vblank_sym); | ||
537 | }; | ||
465 | 538 | ||
466 | static bool tegra_dc_dp_lower_config(struct tegra_dc_dp_data *dp, | 539 | static bool tegra_dc_dp_lower_config(struct tegra_dc_dp_data *dp, |
467 | struct tegra_dc_dp_link_config *cfg) | 540 | struct tegra_dc_dp_link_config *cfg) |
@@ -530,7 +603,7 @@ static bool tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp, | |||
530 | (u64)link_rate * mode->h_active, mode->pclk); | 603 | (u64)link_rate * mode->h_active, mode->pclk); |
531 | 604 | ||
532 | ratio_f = (u64)mode->pclk * cfg->bytes_per_pixel * f; | 605 | ratio_f = (u64)mode->pclk * cfg->bytes_per_pixel * f; |
533 | ratio_f /= 8; | 606 | /* ratio_f /= 8; */ |
534 | ratio_f = tegra_div64(ratio_f, link_rate * cfg->lane_count); | 607 | ratio_f = tegra_div64(ratio_f, link_rate * cfg->lane_count); |
535 | 608 | ||
536 | for (i = 64; i >= 32; --i) { | 609 | for (i = 64; i >= 32; --i) { |
@@ -611,11 +684,11 @@ static bool tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp, | |||
611 | cfg->activepolarity, cfg->active_count, cfg->tu_size, | 684 | cfg->activepolarity, cfg->active_count, cfg->tu_size, |
612 | cfg->active_frac); | 685 | cfg->active_frac); |
613 | 686 | ||
614 | watermark_f = ratio_f * cfg->tu_size * tegra_div64(f - ratio_f, f); | 687 | watermark_f = tegra_div64(ratio_f * cfg->tu_size * (f - ratio_f), f); |
615 | cfg->watermark = 2*((cfg->bytes_per_pixel) * f / 8) + watermark_f + | 688 | cfg->watermark = (u32)tegra_div64(watermark_f + lowest_neg_error_f, |
616 | (u32)tegra_div64(lowest_neg_error_f, (u32)f) - 1; | 689 | f) + 2 * cfg->bytes_per_pixel - 1; |
617 | num_symbols_per_line = (mode->h_active * cfg->bytes_per_pixel) / | 690 | num_symbols_per_line = (mode->h_active * cfg->bytes_per_pixel) / |
618 | (8 * cfg->lane_count); | 691 | cfg->lane_count; |
619 | if (cfg->watermark > 30) { | 692 | if (cfg->watermark > 30) { |
620 | dev_dbg(&dp->dc->ndev->dev, | 693 | dev_dbg(&dp->dc->ndev->dev, |
621 | "dp: sor setting: unable to get a good tusize, " | 694 | "dp: sor setting: unable to get a good tusize, " |
@@ -635,7 +708,7 @@ static bool tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp, | |||
635 | /* SetRasterBlankStart.X - 7) * link_clk / pclk) */ | 708 | /* SetRasterBlankStart.X - 7) * link_clk / pclk) */ |
636 | /* - 3 * enhanced_framing - Y */ | 709 | /* - 3 * enhanced_framing - Y */ |
637 | /* where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 */ | 710 | /* where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 */ |
638 | cfg->hblank_sym = tegra_div64((u64)(mode->h_back_porch + | 711 | cfg->hblank_sym = (int)tegra_div64((u64)(mode->h_back_porch + |
639 | mode->h_front_porch + mode->h_sync_width - 7) | 712 | mode->h_front_porch + mode->h_sync_width - 7) |
640 | * link_rate, mode->pclk) | 713 | * link_rate, mode->pclk) |
641 | - 3 * cfg->enhanced_framing - (12 / cfg->lane_count); | 714 | - 3 * cfg->enhanced_framing - (12 / cfg->lane_count); |
@@ -645,19 +718,68 @@ static bool tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp, | |||
645 | 718 | ||
646 | 719 | ||
647 | /* Refer to dev_disp.ref for more information. */ | 720 | /* Refer to dev_disp.ref for more information. */ |
648 | /* # symbols/vblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - */ | 721 | /* # symbols/vblank = ((SetRasterBlankStart.X - */ |
649 | /* SetRasterBlankStart.X - 7) * link_clk / pclk) */ | 722 | /* SetRasterBlankEen.X - 25) * link_clk / pclk) */ |
650 | /* - Y - 1; */ | 723 | /* - Y - 1; */ |
651 | /* where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 */ | 724 | /* where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 */ |
652 | cfg->vblank_sym = tegra_div64((u64)(mode->v_back_porch + | 725 | cfg->vblank_sym = (int)tegra_div64((u64)(mode->h_active - 25) |
653 | mode->v_front_porch + mode->v_sync_width - 25) | ||
654 | * link_rate, mode->pclk) - (36 / cfg->lane_count) - 4; | 726 | * link_rate, mode->pclk) - (36 / cfg->lane_count) - 4; |
655 | 727 | ||
656 | if (cfg->vblank_sym < 0) | 728 | if (cfg->vblank_sym < 0) |
657 | cfg->vblank_sym = 0; | 729 | cfg->vblank_sym = 0; |
730 | |||
731 | cfg->is_valid = true; | ||
732 | tegra_dc_dp_dump_link_cfg(dp, cfg); | ||
733 | |||
658 | return true; | 734 | return true; |
659 | } | 735 | } |
660 | 736 | ||
737 | static int tegra_dc_dp_init_max_link_cfg(struct tegra_dc_dp_data *dp, | ||
738 | struct tegra_dc_dp_link_config *cfg) | ||
739 | { | ||
740 | u8 dpcd_data; | ||
741 | int ret; | ||
742 | |||
743 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT, | ||
744 | &dpcd_data)); | ||
745 | |||
746 | cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK; | ||
747 | |||
748 | cfg->support_enhanced_framing = | ||
749 | (dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ? | ||
750 | true : false; | ||
751 | |||
752 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD, | ||
753 | &dpcd_data)); | ||
754 | cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT) ? | ||
755 | true : false; | ||
756 | |||
757 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH, | ||
758 | &cfg->max_link_bw)); | ||
759 | |||
760 | cfg->bytes_per_pixel = dp->dc->pdata->fb->bits_per_pixel / 8; | ||
761 | |||
762 | CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP, | ||
763 | &dpcd_data)); | ||
764 | cfg->alt_scramber_reset_cap = | ||
765 | (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ? | ||
766 | true : false; | ||
767 | cfg->only_enhanced_framing = | ||
768 | (dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ? | ||
769 | true : false; | ||
770 | |||
771 | if (tegra_platform_is_fpga()) /* hardcoded to 1.62G on fpga */ | ||
772 | cfg->max_link_bw = SOR_LINK_SPEED_G1_62; | ||
773 | cfg->lane_count = cfg->max_lane_count; | ||
774 | cfg->link_bw = cfg->max_link_bw; | ||
775 | cfg->enhanced_framing = cfg->support_enhanced_framing; | ||
776 | |||
777 | tegra_dc_dp_calc_config(dp, dp->mode, cfg); | ||
778 | tegra_dc_dp_dump_link_cfg(dp, cfg); | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | |||
661 | static int tegra_dc_dp_set_assr(struct tegra_dc_dp_data *dp, bool ena) | 783 | static int tegra_dc_dp_set_assr(struct tegra_dc_dp_data *dp, bool ena) |
662 | { | 784 | { |
663 | int ret; | 785 | int ret; |
@@ -699,7 +821,6 @@ static int tegra_dp_set_lane_count(struct tegra_dc_dp_data *dp, | |||
699 | tegra_dc_sor_set_lane_count(dp->sor, cfg->lane_count); | 821 | tegra_dc_sor_set_lane_count(dp->sor, cfg->lane_count); |
700 | 822 | ||
701 | /* Also power down lanes that will not be used */ | 823 | /* Also power down lanes that will not be used */ |
702 | return tegra_dc_sor_power_dplanes(dp->sor, cfg->lane_count); | ||
703 | } | 824 | } |
704 | 825 | ||
705 | static int tegra_dc_dp_set_lane_config(struct tegra_dc_dp_data *dp, | 826 | static int tegra_dc_dp_set_lane_config(struct tegra_dc_dp_data *dp, |
@@ -1047,7 +1168,7 @@ static int tegra_dc_dp_link_training(struct tegra_dc_dp_data *dp, | |||
1047 | } | 1168 | } |
1048 | 1169 | ||
1049 | static bool tegra_dc_dp_link_trained(struct tegra_dc_dp_data *dp, | 1170 | static bool tegra_dc_dp_link_trained(struct tegra_dc_dp_data *dp, |
1050 | struct tegra_dc_dp_link_config *cfg) | 1171 | const struct tegra_dc_dp_link_config *cfg) |
1051 | { | 1172 | { |
1052 | u32 lane; | 1173 | u32 lane; |
1053 | u8 mask; | 1174 | u8 mask; |
@@ -1073,34 +1194,40 @@ static bool tegra_dc_dp_link_trained(struct tegra_dc_dp_data *dp, | |||
1073 | 1194 | ||
1074 | 1195 | ||
1075 | static int tegra_dc_dp_fast_link_training(struct tegra_dc_dp_data *dp, | 1196 | static int tegra_dc_dp_fast_link_training(struct tegra_dc_dp_data *dp, |
1076 | struct tegra_dc_dp_link_config *cfg) | 1197 | const struct tegra_dc_dp_link_config *cfg) |
1077 | { | 1198 | { |
1078 | struct tegra_dc_sor_data *sor = dp->sor; | 1199 | struct tegra_dc_sor_data *sor = dp->sor; |
1079 | int ret; | 1200 | u8 link_bw; |
1201 | u8 lane_count; | ||
1080 | 1202 | ||
1203 | BUG_ON(!cfg || !cfg->is_valid); | ||
1081 | tegra_dc_sor_set_link_bandwidth(sor, cfg->link_bw); | 1204 | tegra_dc_sor_set_link_bandwidth(sor, cfg->link_bw); |
1082 | tegra_dc_sor_set_lane_count(sor, cfg->lane_count); | 1205 | tegra_dc_sor_set_lane_count(sor, cfg->lane_count); |
1083 | 1206 | ||
1084 | /* Send TP1 */ | 1207 | /* Send TP1 */ |
1085 | tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_1, cfg, | 1208 | tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_1, cfg); |
1086 | false); | ||
1087 | 1209 | ||
1088 | usleep_range(500, 1000); | 1210 | usleep_range(500, 1000); |
1089 | /* enable ASSR */ | 1211 | /* enable ASSR */ |
1090 | tegra_dc_dp_set_assr(dp, true); | 1212 | tegra_dc_dp_set_assr(dp, true); |
1091 | tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_2, cfg, | 1213 | tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_2, cfg); |
1092 | true); | ||
1093 | 1214 | ||
1094 | usleep_range(500, 1000); | 1215 | usleep_range(500, 1000); |
1095 | tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_Disabled, | 1216 | tegra_dc_sor_set_dp_linkctl(sor, true, trainingPattern_Disabled, cfg); |
1096 | cfg, false); | 1217 | |
1218 | if (!tegra_dc_dp_link_trained(dp, cfg)) { | ||
1219 | tegra_dc_sor_read_link_config(dp->sor, &link_bw, | ||
1220 | &lane_count); | ||
1221 | dev_info(&dp->dc->ndev->dev, | ||
1222 | "Fast link trainging failed, link bw %d, lane # %d\n", | ||
1223 | link_bw, lane_count); | ||
1224 | return -EFAULT; | ||
1225 | } else | ||
1226 | dev_dbg(&dp->dc->ndev->dev, | ||
1227 | "Fast link trainging succeeded, link bw %d, lane %d\n", | ||
1228 | cfg->link_bw, cfg->lane_count); | ||
1097 | 1229 | ||
1098 | ret = tegra_dc_dp_link_trained(dp, cfg); | 1230 | return 0; |
1099 | if (!ret) { | ||
1100 | tegra_dc_sor_read_link_config(dp->sor, &cfg->link_bw, | ||
1101 | &cfg->lane_count); | ||
1102 | } | ||
1103 | return ret; | ||
1104 | } | 1231 | } |
1105 | 1232 | ||
1106 | static int tegra_dp_link_config(struct tegra_dc_dp_data *dp, | 1233 | static int tegra_dp_link_config(struct tegra_dc_dp_data *dp, |
@@ -1125,7 +1252,7 @@ static int tegra_dp_link_config(struct tegra_dc_dp_data *dp, | |||
1125 | do { | 1252 | do { |
1126 | ret = tegra_dc_dp_dpcd_write(dp, | 1253 | ret = tegra_dc_dp_dpcd_write(dp, |
1127 | NV_DPCD_SET_POWER, dpcd_data); | 1254 | NV_DPCD_SET_POWER, dpcd_data); |
1128 | } while ((--retry > 0) && (ret != 0)); | 1255 | } while ((--retry > 0) && ret); |
1129 | if (ret) { | 1256 | if (ret) { |
1130 | dev_err(&dp->dc->ndev->dev, | 1257 | dev_err(&dp->dc->ndev->dev, |
1131 | "dp: Failed to set DP panel power\n"); | 1258 | "dp: Failed to set DP panel power\n"); |
@@ -1147,13 +1274,13 @@ static int tegra_dp_link_config(struct tegra_dc_dp_data *dp, | |||
1147 | dev_err(&dp->dc->ndev->dev, "dp: Failed to set lane count\n"); | 1274 | dev_err(&dp->dc->ndev->dev, "dp: Failed to set lane count\n"); |
1148 | return ret; | 1275 | return ret; |
1149 | } | 1276 | } |
1150 | tegra_dc_sor_set_dp_linkctl(dp->sor, true, trainingPattern_Disabled, | 1277 | tegra_dc_dp_dump_link_cfg(dp, cfg); |
1151 | cfg, true); | 1278 | tegra_dc_sor_set_dp_linkctl(dp->sor, true, trainingPattern_None, cfg); |
1152 | 1279 | ||
1153 | /* Now do the link training */ | 1280 | /* Now do the fast link training for eDP */ |
1154 | ret = tegra_dc_dp_link_training(dp, cfg); | 1281 | ret = tegra_dc_dp_fast_link_training(dp, cfg); |
1155 | if (ret) { | 1282 | if (ret) { |
1156 | dev_dbg(&dp->dc->ndev->dev, "dp: link training failed\n"); | 1283 | dev_err(&dp->dc->ndev->dev, "dp: fast link training failed\n"); |
1157 | return ret; | 1284 | return ret; |
1158 | } | 1285 | } |
1159 | 1286 | ||
@@ -1184,7 +1311,7 @@ static int tegra_dc_dp_explore_link_cfg(struct tegra_dc_dp_data *dp, | |||
1184 | } | 1311 | } |
1185 | 1312 | ||
1186 | cfg->is_valid = false; | 1313 | cfg->is_valid = false; |
1187 | memcpy(cfg, &temp_cfg, sizeof(temp_cfg)); | 1314 | memcpy(&temp_cfg, cfg, sizeof(temp_cfg)); |
1188 | 1315 | ||
1189 | temp_cfg.link_bw = temp_cfg.max_link_bw; | 1316 | temp_cfg.link_bw = temp_cfg.max_link_bw; |
1190 | temp_cfg.lane_count = temp_cfg.max_lane_count; | 1317 | temp_cfg.lane_count = temp_cfg.max_lane_count; |
@@ -1192,8 +1319,7 @@ static int tegra_dc_dp_explore_link_cfg(struct tegra_dc_dp_data *dp, | |||
1192 | while (tegra_dc_dp_calc_config(dp, mode, &temp_cfg) && | 1319 | while (tegra_dc_dp_calc_config(dp, mode, &temp_cfg) && |
1193 | tegra_dp_link_config(dp, &temp_cfg)) { | 1320 | tegra_dp_link_config(dp, &temp_cfg)) { |
1194 | /* current link cfg is doable */ | 1321 | /* current link cfg is doable */ |
1195 | memcpy(&temp_cfg, cfg, sizeof(temp_cfg)); | 1322 | memcpy(cfg, &temp_cfg, sizeof(temp_cfg)); |
1196 | cfg->is_valid = true; | ||
1197 | 1323 | ||
1198 | /* try to lower the config */ | 1324 | /* try to lower the config */ |
1199 | if (!tegra_dc_dp_lower_config(dp, &temp_cfg)) | 1325 | if (!tegra_dc_dp_lower_config(dp, &temp_cfg)) |
@@ -1211,10 +1337,10 @@ static void tegra_dc_dp_lt_worker(struct work_struct *work) | |||
1211 | tegra_dc_disable(dp->dc); | 1337 | tegra_dc_disable(dp->dc); |
1212 | 1338 | ||
1213 | if (!dp->link_cfg.is_valid || | 1339 | if (!dp->link_cfg.is_valid || |
1214 | !tegra_dp_link_config(dp, &dp->link_cfg)) { | 1340 | tegra_dp_link_config(dp, &dp->link_cfg)) { |
1215 | /* If current config is not valid or cannot be trained, | 1341 | /* If current config is not valid or cannot be trained, |
1216 | needs to re-explore the possilbe config */ | 1342 | needs to re-explore the possilbe config */ |
1217 | if (tegra_dc_init_max_link_cfg(dp, &dp->link_cfg)) | 1343 | if (tegra_dc_dp_init_max_link_cfg(dp, &dp->link_cfg)) |
1218 | dev_err(&dp->dc->ndev->dev, | 1344 | dev_err(&dp->dc->ndev->dev, |
1219 | "dp: failed to init link configuration\n"); | 1345 | "dp: failed to init link configuration\n"); |
1220 | else if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, | 1346 | else if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, |
@@ -1273,7 +1399,7 @@ static int tegra_dc_dp_init(struct tegra_dc *dc) | |||
1273 | if (!dp) | 1399 | if (!dp) |
1274 | return -ENOMEM; | 1400 | return -ENOMEM; |
1275 | 1401 | ||
1276 | res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, "dpaux"); | 1402 | res = platform_get_resource_byname(dc->ndev, IORESOURCE_MEM, "dpaux"); |
1277 | if (!res) { | 1403 | if (!res) { |
1278 | dev_err(&dc->ndev->dev, "dp: no mem resources for dpaux\n"); | 1404 | dev_err(&dc->ndev->dev, "dp: no mem resources for dpaux\n"); |
1279 | err = -EFAULT; | 1405 | err = -EFAULT; |
@@ -1295,7 +1421,7 @@ static int tegra_dc_dp_init(struct tegra_dc *dc) | |||
1295 | goto err_release_resource_reg; | 1421 | goto err_release_resource_reg; |
1296 | } | 1422 | } |
1297 | 1423 | ||
1298 | clk = clk_get(&dc->ndev->dev, "edp"); | 1424 | clk = clk_get_sys("dpaux", NULL); |
1299 | if (IS_ERR_OR_NULL(clk)) { | 1425 | if (IS_ERR_OR_NULL(clk)) { |
1300 | dev_err(&dc->ndev->dev, "dp: dc clock %s.edp unavailable\n", | 1426 | dev_err(&dc->ndev->dev, "dp: dc clock %s.edp unavailable\n", |
1301 | dev_name(&dc->ndev->dev)); | 1427 | dev_name(&dc->ndev->dev)); |
@@ -1332,6 +1458,7 @@ static int tegra_dc_dp_init(struct tegra_dc *dc) | |||
1332 | INIT_WORK(&dp->lt_work, tegra_dc_dp_lt_worker); | 1458 | INIT_WORK(&dp->lt_work, tegra_dc_dp_lt_worker); |
1333 | 1459 | ||
1334 | tegra_dc_set_outdata(dc, dp); | 1460 | tegra_dc_set_outdata(dc, dp); |
1461 | tegra_dc_dp_debug_create(dp); | ||
1335 | 1462 | ||
1336 | return 0; | 1463 | return 0; |
1337 | 1464 | ||
@@ -1354,16 +1481,23 @@ static void tegra_dc_dp_enable(struct tegra_dc *dc) | |||
1354 | u32 retry; | 1481 | u32 retry; |
1355 | int ret; | 1482 | int ret; |
1356 | 1483 | ||
1484 | if (!tegra_is_clk_enabled(dp->clk)) | ||
1485 | clk_prepare_enable(dp->clk); | ||
1486 | |||
1357 | tegra_dc_dpaux_enable(dp); | 1487 | tegra_dc_dpaux_enable(dp); |
1358 | clk_enable(dp->clk); | ||
1359 | 1488 | ||
1360 | /* Power on panel */ | 1489 | /* Power on panel */ |
1361 | tegra_dc_sor_set_panel_power(dp->sor, true); | 1490 | tegra_dc_sor_set_panel_power(dp->sor, true); |
1362 | 1491 | ||
1363 | /* TODO: power on lanes as well? */ | 1492 | if (tegra_dc_dp_init_max_link_cfg(dp, &dp->link_cfg)) { |
1493 | dev_err(&dc->ndev->dev, | ||
1494 | "dp: failed to init link configuration\n"); | ||
1495 | goto error_enable; | ||
1496 | } | ||
1364 | 1497 | ||
1365 | /* Enable backlight -- TODO: need to go through I2C */ | 1498 | tegra_dc_sor_enable_dp(dp->sor); |
1366 | 1499 | ||
1500 | /* Enable backlight -- TODO: need to go through I2C */ | ||
1367 | msleep(DP_LCDVCC_TO_HPD_DELAY_MS); | 1501 | msleep(DP_LCDVCC_TO_HPD_DELAY_MS); |
1368 | 1502 | ||
1369 | /* Write power on to DPCD */ | 1503 | /* Write power on to DPCD */ |
@@ -1381,39 +1515,30 @@ static void tegra_dc_dp_enable(struct tegra_dc *dc) | |||
1381 | } | 1515 | } |
1382 | 1516 | ||
1383 | /* Confirm DP is plugging status */ | 1517 | /* Confirm DP is plugging status */ |
1384 | #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM | 1518 | if (tegra_platform_is_silicon() && |
1385 | if (!(tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT) & | 1519 | !(tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT) & |
1386 | DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { | 1520 | DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) { |
1387 | dev_err(&dp->dc->ndev->dev, "dp: could not detect HPD\n"); | 1521 | dev_err(&dp->dc->ndev->dev, "dp: could not detect HPD\n"); |
1388 | return; | 1522 | return; |
1389 | } | 1523 | } |
1390 | #endif | ||
1391 | 1524 | ||
1392 | /* Check DP version */ | 1525 | /* Check DP version */ |
1393 | if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_REV, &dp->revision)) | 1526 | if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_REV, &dp->revision)) |
1394 | dev_err(&dp->dc->ndev->dev, | 1527 | dev_err(&dp->dc->ndev->dev, |
1395 | "dp: failed to read the revision number from sink\n"); | 1528 | "dp: failed to read the revision number from sink\n"); |
1396 | 1529 | ||
1397 | if (!dp->link_cfg.is_valid || | 1530 | if (tegra_dp_link_config(dp, &dp->link_cfg)) { |
1398 | tegra_dc_dp_fast_link_training(dp, &dp->link_cfg)) { | 1531 | dev_err(&dp->dc->ndev->dev, "dp: Could not setup link\n"); |
1399 | /* if valid link config is not ready yet, or current | 1532 | return; |
1400 | config cannot be link-trained, try to find the | ||
1401 | new minimal config */ | ||
1402 | if (tegra_dc_init_max_link_cfg(dp, &dp->link_cfg)) { | ||
1403 | dev_err(&dp->dc->ndev->dev, | ||
1404 | "dp: failed to init link configuration\n"); | ||
1405 | return; | ||
1406 | } | ||
1407 | if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, dp->mode) || | ||
1408 | tegra_dc_dp_link_training(dp, &dp->link_cfg)) { | ||
1409 | dev_err(&dp->dc->ndev->dev, | ||
1410 | "dp: Current mode is not possible\n"); | ||
1411 | return; | ||
1412 | } | ||
1413 | } | 1533 | } |
1414 | 1534 | ||
1415 | /* enable SOR by programming the watermark/v/hblank_sym etc */ | 1535 | tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, dp->mode); |
1416 | tegra_dc_sor_enable_dp(dp->sor); | 1536 | |
1537 | mdelay(100); | ||
1538 | tegra_dc_sor_attach(dp->sor); | ||
1539 | |||
1540 | error_enable: | ||
1541 | return; | ||
1417 | } | 1542 | } |
1418 | 1543 | ||
1419 | static void tegra_dc_dp_destroy(struct tegra_dc *dc) | 1544 | static void tegra_dc_dp_destroy(struct tegra_dc *dc) |
@@ -1444,24 +1569,55 @@ static void tegra_dc_dp_disable(struct tegra_dc *dc) | |||
1444 | /* Make sure the timing meet the eDP specs */ | 1569 | /* Make sure the timing meet the eDP specs */ |
1445 | } | 1570 | } |
1446 | 1571 | ||
1572 | extern struct clk *tegra_get_clock_by_name(const char *name); | ||
1573 | |||
1574 | static long tegra_dc_dp_setup_clk(struct tegra_dc *dc, struct clk *clk) | ||
1575 | { | ||
1576 | struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc); | ||
1577 | struct clk *sor_clk = dp->sor->sor_clk; | ||
1578 | struct clk *parent_clk; | ||
1579 | |||
1580 | tegra_dc_sor_setup_clk(dp->sor, clk, false); | ||
1581 | |||
1582 | parent_clk = tegra_get_clock_by_name("pll_dp"); | ||
1583 | |||
1584 | if (clk_get_parent(sor_clk) != parent_clk) | ||
1585 | clk_set_parent(sor_clk, parent_clk); | ||
1586 | clk_set_rate(parent_clk, 270000000); | ||
1587 | |||
1588 | if (!tegra_is_clk_enabled(parent_clk)) | ||
1589 | clk_prepare_enable(parent_clk); | ||
1590 | |||
1591 | return tegra_dc_pclk_round_rate(dc, dp->sor->dc->mode.pclk); | ||
1592 | } | ||
1447 | 1593 | ||
1448 | 1594 | ||
1449 | static void tegra_dc_dp_suspend(struct tegra_dc *dc) | 1595 | static void tegra_dc_dp_suspend(struct tegra_dc *dc) |
1450 | { | 1596 | { |
1451 | /* TBD */ | 1597 | struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc); |
1598 | |||
1599 | tegra_dc_dp_disable(dc); | ||
1600 | dp->suspended = true; | ||
1452 | } | 1601 | } |
1453 | 1602 | ||
1454 | 1603 | ||
1455 | static void tegra_dc_dp_resume(struct tegra_dc *dc) | 1604 | static void tegra_dc_dp_resume(struct tegra_dc *dc) |
1456 | { | 1605 | { |
1457 | /* TBD */ | 1606 | struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc); |
1607 | |||
1608 | if (!dp->suspended) | ||
1609 | return; | ||
1610 | tegra_dc_dp_enable(dc); | ||
1458 | } | 1611 | } |
1459 | 1612 | ||
1460 | struct tegra_dc_out_ops tegra_dc_dp_ops = { | 1613 | struct tegra_dc_out_ops tegra_dc_dp_ops = { |
1461 | .init = tegra_dc_dp_init, | 1614 | .init = tegra_dc_dp_init, |
1462 | .destroy = tegra_dc_dp_destroy, | 1615 | .destroy = tegra_dc_dp_destroy, |
1463 | .enable = tegra_dc_dp_enable, | 1616 | .enable = tegra_dc_dp_enable, |
1464 | .disable = tegra_dc_dp_disable, | 1617 | .disable = tegra_dc_dp_disable, |
1465 | .suspend = tegra_dc_dp_suspend, | 1618 | .suspend = tegra_dc_dp_suspend, |
1466 | .resume = tegra_dc_dp_resume, | 1619 | .resume = tegra_dc_dp_resume, |
1620 | .setup_clk = tegra_dc_dp_setup_clk, | ||
1467 | }; | 1621 | }; |
1622 | |||
1623 | |||