diff options
Diffstat (limited to 'drivers/video/tegra/dc')
25 files changed, 16042 insertions, 0 deletions
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile new file mode 100644 index 00000000000..01f13918ca6 --- /dev/null +++ b/drivers/video/tegra/dc/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | obj-y += dc.o | ||
3 | obj-y += rgb.o | ||
4 | obj-y += hdmi.o | ||
5 | obj-$(CONFIG_TEGRA_NVHDCP) += nvhdcp.o | ||
6 | obj-y += edid.o | ||
7 | obj-y += nvsd.o | ||
8 | obj-y += dsi.o | ||
9 | obj-y += dc_sysfs.o | ||
10 | obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/ | ||
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c new file mode 100644 index 00000000000..8b3bf041a7d --- /dev/null +++ b/drivers/video/tegra/dc/dc.c | |||
@@ -0,0 +1,3120 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dc.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * Copyright (C) 2010-2012 NVIDIA Corporation | ||
8 | * | ||
9 | * This software is licensed under the terms of the GNU General Public | ||
10 | * License version 2, as published by the Free Software Foundation, and | ||
11 | * may be copied, distributed, and modified under those terms. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/clk.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/dma-mapping.h> | ||
31 | #include <linux/workqueue.h> | ||
32 | #include <linux/ktime.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/backlight.h> | ||
36 | #include <video/tegrafb.h> | ||
37 | #include <drm/drm_fixed.h> | ||
38 | #ifdef CONFIG_SWITCH | ||
39 | #include <linux/switch.h> | ||
40 | #endif | ||
41 | |||
42 | |||
43 | #include <mach/clk.h> | ||
44 | #include <mach/dc.h> | ||
45 | #include <mach/fb.h> | ||
46 | #include <mach/mc.h> | ||
47 | #include <linux/nvhost.h> | ||
48 | #include <mach/latency_allowance.h> | ||
49 | |||
50 | #include "dc_reg.h" | ||
51 | #include "dc_priv.h" | ||
52 | #include "nvsd.h" | ||
53 | |||
54 | #define TEGRA_CRC_LATCHED_DELAY 34 | ||
55 | |||
56 | #define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL 0x01000000 | ||
57 | #define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL 0x0 | ||
58 | |||
59 | #ifndef CONFIG_TEGRA_FPGA_PLATFORM | ||
60 | #define ALL_UF_INT (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT) | ||
61 | #else | ||
62 | /* ignore underflows when on simulation and fpga platform */ | ||
63 | #define ALL_UF_INT (0) | ||
64 | #endif | ||
65 | |||
66 | static int no_vsync; | ||
67 | |||
68 | static void _tegra_dc_controller_disable(struct tegra_dc *dc); | ||
69 | |||
70 | module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR); | ||
71 | |||
72 | static int use_dynamic_emc = 1; | ||
73 | |||
74 | module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR); | ||
75 | |||
76 | struct tegra_dc *tegra_dcs[TEGRA_MAX_DC]; | ||
77 | |||
78 | DEFINE_MUTEX(tegra_dc_lock); | ||
79 | DEFINE_MUTEX(shared_lock); | ||
80 | |||
81 | static const struct { | ||
82 | bool h; | ||
83 | bool v; | ||
84 | } can_filter[] = { | ||
85 | /* Window A has no filtering */ | ||
86 | { false, false }, | ||
87 | /* Window B has both H and V filtering */ | ||
88 | { true, true }, | ||
89 | /* Window C has only H filtering */ | ||
90 | { false, true }, | ||
91 | }; | ||
92 | static inline bool win_use_v_filter(const struct tegra_dc_win *win) | ||
93 | { | ||
94 | return can_filter[win->idx].v && | ||
95 | win->h.full != dfixed_const(win->out_h); | ||
96 | } | ||
97 | static inline bool win_use_h_filter(const struct tegra_dc_win *win) | ||
98 | { | ||
99 | return can_filter[win->idx].h && | ||
100 | win->w.full != dfixed_const(win->out_w); | ||
101 | } | ||
102 | |||
103 | static inline int tegra_dc_fmt_bpp(int fmt) | ||
104 | { | ||
105 | switch (fmt) { | ||
106 | case TEGRA_WIN_FMT_P1: | ||
107 | return 1; | ||
108 | |||
109 | case TEGRA_WIN_FMT_P2: | ||
110 | return 2; | ||
111 | |||
112 | case TEGRA_WIN_FMT_P4: | ||
113 | return 4; | ||
114 | |||
115 | case TEGRA_WIN_FMT_P8: | ||
116 | return 8; | ||
117 | |||
118 | case TEGRA_WIN_FMT_B4G4R4A4: | ||
119 | case TEGRA_WIN_FMT_B5G5R5A: | ||
120 | case TEGRA_WIN_FMT_B5G6R5: | ||
121 | case TEGRA_WIN_FMT_AB5G5R5: | ||
122 | return 16; | ||
123 | |||
124 | case TEGRA_WIN_FMT_B8G8R8A8: | ||
125 | case TEGRA_WIN_FMT_R8G8B8A8: | ||
126 | case TEGRA_WIN_FMT_B6x2G6x2R6x2A8: | ||
127 | case TEGRA_WIN_FMT_R6x2G6x2B6x2A8: | ||
128 | return 32; | ||
129 | |||
130 | /* for planar formats, size of the Y plane, 8bit */ | ||
131 | case TEGRA_WIN_FMT_YCbCr420P: | ||
132 | case TEGRA_WIN_FMT_YUV420P: | ||
133 | case TEGRA_WIN_FMT_YCbCr422P: | ||
134 | case TEGRA_WIN_FMT_YUV422P: | ||
135 | case TEGRA_WIN_FMT_YCbCr422R: | ||
136 | case TEGRA_WIN_FMT_YUV422R: | ||
137 | case TEGRA_WIN_FMT_YCbCr422RA: | ||
138 | case TEGRA_WIN_FMT_YUV422RA: | ||
139 | return 8; | ||
140 | |||
141 | case TEGRA_WIN_FMT_YCbCr422: | ||
142 | case TEGRA_WIN_FMT_YUV422: | ||
143 | /* FIXME: need to know the bpp of these formats */ | ||
144 | return 0; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static inline bool tegra_dc_is_yuv_planar(int fmt) | ||
150 | { | ||
151 | switch (fmt) { | ||
152 | case TEGRA_WIN_FMT_YUV420P: | ||
153 | case TEGRA_WIN_FMT_YCbCr420P: | ||
154 | case TEGRA_WIN_FMT_YCbCr422P: | ||
155 | case TEGRA_WIN_FMT_YUV422P: | ||
156 | case TEGRA_WIN_FMT_YCbCr422R: | ||
157 | case TEGRA_WIN_FMT_YUV422R: | ||
158 | case TEGRA_WIN_FMT_YCbCr422RA: | ||
159 | case TEGRA_WIN_FMT_YUV422RA: | ||
160 | return true; | ||
161 | } | ||
162 | return false; | ||
163 | } | ||
164 | |||
165 | #define DUMP_REG(a) do { \ | ||
166 | snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \ | ||
167 | #a, a, tegra_dc_readl(dc, a)); \ | ||
168 | print(data, buff); \ | ||
169 | } while (0) | ||
170 | |||
171 | static void _dump_regs(struct tegra_dc *dc, void *data, | ||
172 | void (* print)(void *data, const char *str)) | ||
173 | { | ||
174 | int i; | ||
175 | char buff[256]; | ||
176 | |||
177 | tegra_dc_io_start(dc); | ||
178 | clk_enable(dc->clk); | ||
179 | |||
180 | DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); | ||
181 | DUMP_REG(DC_CMD_DISPLAY_COMMAND); | ||
182 | DUMP_REG(DC_CMD_SIGNAL_RAISE); | ||
183 | DUMP_REG(DC_CMD_INT_STATUS); | ||
184 | DUMP_REG(DC_CMD_INT_MASK); | ||
185 | DUMP_REG(DC_CMD_INT_ENABLE); | ||
186 | DUMP_REG(DC_CMD_INT_TYPE); | ||
187 | DUMP_REG(DC_CMD_INT_POLARITY); | ||
188 | DUMP_REG(DC_CMD_SIGNAL_RAISE1); | ||
189 | DUMP_REG(DC_CMD_SIGNAL_RAISE2); | ||
190 | DUMP_REG(DC_CMD_SIGNAL_RAISE3); | ||
191 | DUMP_REG(DC_CMD_STATE_ACCESS); | ||
192 | DUMP_REG(DC_CMD_STATE_CONTROL); | ||
193 | DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); | ||
194 | DUMP_REG(DC_CMD_REG_ACT_CONTROL); | ||
195 | |||
196 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
197 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1); | ||
198 | DUMP_REG(DC_DISP_DISP_WIN_OPTIONS); | ||
199 | DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY); | ||
200 | DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
201 | DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS); | ||
202 | DUMP_REG(DC_DISP_REF_TO_SYNC); | ||
203 | DUMP_REG(DC_DISP_SYNC_WIDTH); | ||
204 | DUMP_REG(DC_DISP_BACK_PORCH); | ||
205 | DUMP_REG(DC_DISP_DISP_ACTIVE); | ||
206 | DUMP_REG(DC_DISP_FRONT_PORCH); | ||
207 | DUMP_REG(DC_DISP_H_PULSE0_CONTROL); | ||
208 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_A); | ||
209 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_B); | ||
210 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_C); | ||
211 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_D); | ||
212 | DUMP_REG(DC_DISP_H_PULSE1_CONTROL); | ||
213 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_A); | ||
214 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_B); | ||
215 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_C); | ||
216 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_D); | ||
217 | DUMP_REG(DC_DISP_H_PULSE2_CONTROL); | ||
218 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_A); | ||
219 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_B); | ||
220 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_C); | ||
221 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_D); | ||
222 | DUMP_REG(DC_DISP_V_PULSE0_CONTROL); | ||
223 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_A); | ||
224 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_B); | ||
225 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_C); | ||
226 | DUMP_REG(DC_DISP_V_PULSE1_CONTROL); | ||
227 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_A); | ||
228 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_B); | ||
229 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_C); | ||
230 | DUMP_REG(DC_DISP_V_PULSE2_CONTROL); | ||
231 | DUMP_REG(DC_DISP_V_PULSE2_POSITION_A); | ||
232 | DUMP_REG(DC_DISP_V_PULSE3_CONTROL); | ||
233 | DUMP_REG(DC_DISP_V_PULSE3_POSITION_A); | ||
234 | DUMP_REG(DC_DISP_M0_CONTROL); | ||
235 | DUMP_REG(DC_DISP_M1_CONTROL); | ||
236 | DUMP_REG(DC_DISP_DI_CONTROL); | ||
237 | DUMP_REG(DC_DISP_PP_CONTROL); | ||
238 | DUMP_REG(DC_DISP_PP_SELECT_A); | ||
239 | DUMP_REG(DC_DISP_PP_SELECT_B); | ||
240 | DUMP_REG(DC_DISP_PP_SELECT_C); | ||
241 | DUMP_REG(DC_DISP_PP_SELECT_D); | ||
242 | DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL); | ||
243 | DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL); | ||
244 | DUMP_REG(DC_DISP_DISP_COLOR_CONTROL); | ||
245 | DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS); | ||
246 | DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS); | ||
247 | DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS); | ||
248 | DUMP_REG(DC_DISP_LCD_SPI_OPTIONS); | ||
249 | DUMP_REG(DC_DISP_BORDER_COLOR); | ||
250 | DUMP_REG(DC_DISP_COLOR_KEY0_LOWER); | ||
251 | DUMP_REG(DC_DISP_COLOR_KEY0_UPPER); | ||
252 | DUMP_REG(DC_DISP_COLOR_KEY1_LOWER); | ||
253 | DUMP_REG(DC_DISP_COLOR_KEY1_UPPER); | ||
254 | DUMP_REG(DC_DISP_CURSOR_FOREGROUND); | ||
255 | DUMP_REG(DC_DISP_CURSOR_BACKGROUND); | ||
256 | DUMP_REG(DC_DISP_CURSOR_START_ADDR); | ||
257 | DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS); | ||
258 | DUMP_REG(DC_DISP_CURSOR_POSITION); | ||
259 | DUMP_REG(DC_DISP_CURSOR_POSITION_NS); | ||
260 | DUMP_REG(DC_DISP_INIT_SEQ_CONTROL); | ||
261 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A); | ||
262 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B); | ||
263 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C); | ||
264 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D); | ||
265 | DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL); | ||
266 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST); | ||
267 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST); | ||
268 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0C_HYST); | ||
269 | DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST); | ||
270 | DUMP_REG(DC_DISP_DAC_CRT_CTRL); | ||
271 | DUMP_REG(DC_DISP_DISP_MISC_CONTROL); | ||
272 | |||
273 | |||
274 | for (i = 0; i < 3; i++) { | ||
275 | print(data, "\n"); | ||
276 | snprintf(buff, sizeof(buff), "WINDOW %c:\n", 'A' + i); | ||
277 | print(data, buff); | ||
278 | |||
279 | tegra_dc_writel(dc, WINDOW_A_SELECT << i, | ||
280 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
281 | DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); | ||
282 | DUMP_REG(DC_WIN_WIN_OPTIONS); | ||
283 | DUMP_REG(DC_WIN_BYTE_SWAP); | ||
284 | DUMP_REG(DC_WIN_BUFFER_CONTROL); | ||
285 | DUMP_REG(DC_WIN_COLOR_DEPTH); | ||
286 | DUMP_REG(DC_WIN_POSITION); | ||
287 | DUMP_REG(DC_WIN_SIZE); | ||
288 | DUMP_REG(DC_WIN_PRESCALED_SIZE); | ||
289 | DUMP_REG(DC_WIN_H_INITIAL_DDA); | ||
290 | DUMP_REG(DC_WIN_V_INITIAL_DDA); | ||
291 | DUMP_REG(DC_WIN_DDA_INCREMENT); | ||
292 | DUMP_REG(DC_WIN_LINE_STRIDE); | ||
293 | DUMP_REG(DC_WIN_BUF_STRIDE); | ||
294 | DUMP_REG(DC_WIN_UV_BUF_STRIDE); | ||
295 | DUMP_REG(DC_WIN_BLEND_NOKEY); | ||
296 | DUMP_REG(DC_WIN_BLEND_1WIN); | ||
297 | DUMP_REG(DC_WIN_BLEND_2WIN_X); | ||
298 | DUMP_REG(DC_WIN_BLEND_2WIN_Y); | ||
299 | DUMP_REG(DC_WIN_BLEND_3WIN_XY); | ||
300 | DUMP_REG(DC_WINBUF_START_ADDR); | ||
301 | DUMP_REG(DC_WINBUF_START_ADDR_U); | ||
302 | DUMP_REG(DC_WINBUF_START_ADDR_V); | ||
303 | DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); | ||
304 | DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); | ||
305 | DUMP_REG(DC_WINBUF_UFLOW_STATUS); | ||
306 | DUMP_REG(DC_WIN_CSC_YOF); | ||
307 | DUMP_REG(DC_WIN_CSC_KYRGB); | ||
308 | DUMP_REG(DC_WIN_CSC_KUR); | ||
309 | DUMP_REG(DC_WIN_CSC_KVR); | ||
310 | DUMP_REG(DC_WIN_CSC_KUG); | ||
311 | DUMP_REG(DC_WIN_CSC_KVG); | ||
312 | DUMP_REG(DC_WIN_CSC_KUB); | ||
313 | DUMP_REG(DC_WIN_CSC_KVB); | ||
314 | } | ||
315 | |||
316 | DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL); | ||
317 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE2); | ||
318 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY2); | ||
319 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA2); | ||
320 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE2); | ||
321 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT5); | ||
322 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
323 | DUMP_REG(DC_DISP_M1_CONTROL); | ||
324 | DUMP_REG(DC_COM_PM1_CONTROL); | ||
325 | DUMP_REG(DC_COM_PM1_DUTY_CYCLE); | ||
326 | DUMP_REG(DC_DISP_SD_CONTROL); | ||
327 | |||
328 | clk_disable(dc->clk); | ||
329 | tegra_dc_io_end(dc); | ||
330 | } | ||
331 | |||
332 | #undef DUMP_REG | ||
333 | |||
334 | #ifdef DEBUG | ||
335 | static void dump_regs_print(void *data, const char *str) | ||
336 | { | ||
337 | struct tegra_dc *dc = data; | ||
338 | dev_dbg(&dc->ndev->dev, "%s", str); | ||
339 | } | ||
340 | |||
341 | static void dump_regs(struct tegra_dc *dc) | ||
342 | { | ||
343 | _dump_regs(dc, dc, dump_regs_print); | ||
344 | } | ||
345 | #else /* !DEBUG */ | ||
346 | |||
347 | static void dump_regs(struct tegra_dc *dc) {} | ||
348 | |||
349 | #endif /* DEBUG */ | ||
350 | |||
351 | #ifdef CONFIG_DEBUG_FS | ||
352 | |||
353 | static void dbg_regs_print(void *data, const char *str) | ||
354 | { | ||
355 | struct seq_file *s = data; | ||
356 | |||
357 | seq_printf(s, "%s", str); | ||
358 | } | ||
359 | |||
360 | #undef DUMP_REG | ||
361 | |||
362 | static int dbg_dc_show(struct seq_file *s, void *unused) | ||
363 | { | ||
364 | struct tegra_dc *dc = s->private; | ||
365 | |||
366 | _dump_regs(dc, s, dbg_regs_print); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | |||
372 | static int dbg_dc_open(struct inode *inode, struct file *file) | ||
373 | { | ||
374 | return single_open(file, dbg_dc_show, inode->i_private); | ||
375 | } | ||
376 | |||
377 | static const struct file_operations regs_fops = { | ||
378 | .open = dbg_dc_open, | ||
379 | .read = seq_read, | ||
380 | .llseek = seq_lseek, | ||
381 | .release = single_release, | ||
382 | }; | ||
383 | |||
384 | static int dbg_dc_mode_show(struct seq_file *s, void *unused) | ||
385 | { | ||
386 | struct tegra_dc *dc = s->private; | ||
387 | struct tegra_dc_mode *m; | ||
388 | |||
389 | mutex_lock(&dc->lock); | ||
390 | m = &dc->mode; | ||
391 | seq_printf(s, | ||
392 | "pclk: %d\n" | ||
393 | "h_ref_to_sync: %d\n" | ||
394 | "v_ref_to_sync: %d\n" | ||
395 | "h_sync_width: %d\n" | ||
396 | "v_sync_width: %d\n" | ||
397 | "h_back_porch: %d\n" | ||
398 | "v_back_porch: %d\n" | ||
399 | "h_active: %d\n" | ||
400 | "v_active: %d\n" | ||
401 | "h_front_porch: %d\n" | ||
402 | "v_front_porch: %d\n" | ||
403 | "stereo_mode: %d\n", | ||
404 | m->pclk, m->h_ref_to_sync, m->v_ref_to_sync, | ||
405 | m->h_sync_width, m->v_sync_width, | ||
406 | m->h_back_porch, m->v_back_porch, | ||
407 | m->h_active, m->v_active, | ||
408 | m->h_front_porch, m->v_front_porch, | ||
409 | m->stereo_mode); | ||
410 | mutex_unlock(&dc->lock); | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int dbg_dc_mode_open(struct inode *inode, struct file *file) | ||
415 | { | ||
416 | return single_open(file, dbg_dc_mode_show, inode->i_private); | ||
417 | } | ||
418 | |||
419 | static const struct file_operations mode_fops = { | ||
420 | .open = dbg_dc_mode_open, | ||
421 | .read = seq_read, | ||
422 | .llseek = seq_lseek, | ||
423 | .release = single_release, | ||
424 | }; | ||
425 | |||
426 | static int dbg_dc_stats_show(struct seq_file *s, void *unused) | ||
427 | { | ||
428 | struct tegra_dc *dc = s->private; | ||
429 | |||
430 | mutex_lock(&dc->lock); | ||
431 | seq_printf(s, | ||
432 | "underflows: %llu\n" | ||
433 | "underflows_a: %llu\n" | ||
434 | "underflows_b: %llu\n" | ||
435 | "underflows_c: %llu\n", | ||
436 | dc->stats.underflows, | ||
437 | dc->stats.underflows_a, | ||
438 | dc->stats.underflows_b, | ||
439 | dc->stats.underflows_c); | ||
440 | mutex_unlock(&dc->lock); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int dbg_dc_stats_open(struct inode *inode, struct file *file) | ||
446 | { | ||
447 | return single_open(file, dbg_dc_stats_show, inode->i_private); | ||
448 | } | ||
449 | |||
450 | static const struct file_operations stats_fops = { | ||
451 | .open = dbg_dc_stats_open, | ||
452 | .read = seq_read, | ||
453 | .llseek = seq_lseek, | ||
454 | .release = single_release, | ||
455 | }; | ||
456 | |||
457 | static void __devexit tegra_dc_remove_debugfs(struct tegra_dc *dc) | ||
458 | { | ||
459 | if (dc->debugdir) | ||
460 | debugfs_remove_recursive(dc->debugdir); | ||
461 | dc->debugdir = NULL; | ||
462 | } | ||
463 | |||
464 | static void tegra_dc_create_debugfs(struct tegra_dc *dc) | ||
465 | { | ||
466 | struct dentry *retval; | ||
467 | |||
468 | dc->debugdir = debugfs_create_dir(dev_name(&dc->ndev->dev), NULL); | ||
469 | if (!dc->debugdir) | ||
470 | goto remove_out; | ||
471 | |||
472 | retval = debugfs_create_file("regs", S_IRUGO, dc->debugdir, dc, | ||
473 | ®s_fops); | ||
474 | if (!retval) | ||
475 | goto remove_out; | ||
476 | |||
477 | retval = debugfs_create_file("mode", S_IRUGO, dc->debugdir, dc, | ||
478 | &mode_fops); | ||
479 | if (!retval) | ||
480 | goto remove_out; | ||
481 | |||
482 | retval = debugfs_create_file("stats", S_IRUGO, dc->debugdir, dc, | ||
483 | &stats_fops); | ||
484 | if (!retval) | ||
485 | goto remove_out; | ||
486 | |||
487 | return; | ||
488 | remove_out: | ||
489 | dev_err(&dc->ndev->dev, "could not create debugfs\n"); | ||
490 | tegra_dc_remove_debugfs(dc); | ||
491 | } | ||
492 | |||
493 | #else /* !CONFIG_DEBUGFS */ | ||
494 | static inline void tegra_dc_create_debugfs(struct tegra_dc *dc) { }; | ||
495 | static inline void __devexit tegra_dc_remove_debugfs(struct tegra_dc *dc) { }; | ||
496 | #endif /* CONFIG_DEBUGFS */ | ||
497 | |||
498 | static int tegra_dc_set(struct tegra_dc *dc, int index) | ||
499 | { | ||
500 | int ret = 0; | ||
501 | |||
502 | mutex_lock(&tegra_dc_lock); | ||
503 | if (index >= TEGRA_MAX_DC) { | ||
504 | ret = -EINVAL; | ||
505 | goto out; | ||
506 | } | ||
507 | |||
508 | if (dc != NULL && tegra_dcs[index] != NULL) { | ||
509 | ret = -EBUSY; | ||
510 | goto out; | ||
511 | } | ||
512 | |||
513 | tegra_dcs[index] = dc; | ||
514 | |||
515 | out: | ||
516 | mutex_unlock(&tegra_dc_lock); | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | static unsigned int tegra_dc_has_multiple_dc(void) | ||
522 | { | ||
523 | unsigned int idx; | ||
524 | unsigned int cnt = 0; | ||
525 | struct tegra_dc *dc; | ||
526 | |||
527 | mutex_lock(&tegra_dc_lock); | ||
528 | for (idx = 0; idx < TEGRA_MAX_DC; idx++) | ||
529 | cnt += ((dc = tegra_dcs[idx]) != NULL && dc->enabled) ? 1 : 0; | ||
530 | mutex_unlock(&tegra_dc_lock); | ||
531 | |||
532 | return (cnt > 1); | ||
533 | } | ||
534 | |||
535 | struct tegra_dc *tegra_dc_get_dc(unsigned idx) | ||
536 | { | ||
537 | if (idx < TEGRA_MAX_DC) | ||
538 | return tegra_dcs[idx]; | ||
539 | else | ||
540 | return NULL; | ||
541 | } | ||
542 | EXPORT_SYMBOL(tegra_dc_get_dc); | ||
543 | |||
544 | struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win) | ||
545 | { | ||
546 | if (win >= dc->n_windows) | ||
547 | return NULL; | ||
548 | |||
549 | return &dc->windows[win]; | ||
550 | } | ||
551 | EXPORT_SYMBOL(tegra_dc_get_window); | ||
552 | |||
553 | static int get_topmost_window(u32 *depths, unsigned long *wins) | ||
554 | { | ||
555 | int idx, best = -1; | ||
556 | |||
557 | for_each_set_bit(idx, wins, DC_N_WINDOWS) { | ||
558 | if (best == -1 || depths[idx] < depths[best]) | ||
559 | best = idx; | ||
560 | } | ||
561 | clear_bit(best, wins); | ||
562 | return best; | ||
563 | } | ||
564 | |||
565 | bool tegra_dc_get_connected(struct tegra_dc *dc) | ||
566 | { | ||
567 | return dc->connected; | ||
568 | } | ||
569 | EXPORT_SYMBOL(tegra_dc_get_connected); | ||
570 | |||
571 | static u32 blend_topwin(u32 flags) | ||
572 | { | ||
573 | if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE) | ||
574 | return BLEND(NOKEY, ALPHA, 0xff, 0xff); | ||
575 | else if (flags & TEGRA_WIN_FLAG_BLEND_PREMULT) | ||
576 | return BLEND(NOKEY, PREMULT, 0xff, 0xff); | ||
577 | else | ||
578 | return BLEND(NOKEY, FIX, 0xff, 0xff); | ||
579 | } | ||
580 | |||
581 | static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy) | ||
582 | { | ||
583 | int other; | ||
584 | |||
585 | for (other = 0; other < DC_N_WINDOWS; other++) { | ||
586 | if (other != idx && (xy-- == 0)) | ||
587 | break; | ||
588 | } | ||
589 | if (BIT(other) & behind_mask) | ||
590 | return blend_topwin(flags[idx]); | ||
591 | else if (flags[other]) | ||
592 | return BLEND(NOKEY, DEPENDANT, 0x00, 0x00); | ||
593 | else | ||
594 | return BLEND(NOKEY, FIX, 0x00, 0x00); | ||
595 | } | ||
596 | |||
597 | static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags) | ||
598 | { | ||
599 | unsigned long infront_mask; | ||
600 | int first; | ||
601 | |||
602 | infront_mask = ~(behind_mask | BIT(idx)); | ||
603 | infront_mask &= (BIT(DC_N_WINDOWS) - 1); | ||
604 | first = ffs(infront_mask) - 1; | ||
605 | |||
606 | if (!infront_mask) | ||
607 | return blend_topwin(flags[idx]); | ||
608 | else if (behind_mask && first != -1 && flags[first]) | ||
609 | return BLEND(NOKEY, DEPENDANT, 0x00, 0x00); | ||
610 | else | ||
611 | return BLEND(NOKEY, FIX, 0x0, 0x0); | ||
612 | } | ||
613 | |||
614 | static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend) | ||
615 | { | ||
616 | unsigned long mask = BIT(DC_N_WINDOWS) - 1; | ||
617 | |||
618 | while (mask) { | ||
619 | int idx = get_topmost_window(blend->z, &mask); | ||
620 | |||
621 | tegra_dc_writel(dc, WINDOW_A_SELECT << idx, | ||
622 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
623 | tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff), | ||
624 | DC_WIN_BLEND_NOKEY); | ||
625 | tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff), | ||
626 | DC_WIN_BLEND_1WIN); | ||
627 | tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0), | ||
628 | DC_WIN_BLEND_2WIN_X); | ||
629 | tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1), | ||
630 | DC_WIN_BLEND_2WIN_Y); | ||
631 | tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags), | ||
632 | DC_WIN_BLEND_3WIN_XY); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | static void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc) | ||
637 | { | ||
638 | csc->yof = 0x00f0; | ||
639 | csc->kyrgb = 0x012a; | ||
640 | csc->kur = 0x0000; | ||
641 | csc->kvr = 0x0198; | ||
642 | csc->kug = 0x039b; | ||
643 | csc->kvg = 0x032f; | ||
644 | csc->kub = 0x0204; | ||
645 | csc->kvb = 0x0000; | ||
646 | } | ||
647 | |||
648 | static void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc) | ||
649 | { | ||
650 | tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF); | ||
651 | tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB); | ||
652 | tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR); | ||
653 | tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR); | ||
654 | tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG); | ||
655 | tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG); | ||
656 | tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB); | ||
657 | tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB); | ||
658 | } | ||
659 | |||
660 | int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx) | ||
661 | { | ||
662 | mutex_lock(&dc->lock); | ||
663 | |||
664 | if (!dc->enabled) { | ||
665 | mutex_unlock(&dc->lock); | ||
666 | return -EFAULT; | ||
667 | } | ||
668 | |||
669 | tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx, | ||
670 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
671 | |||
672 | tegra_dc_set_csc(dc, &dc->windows[win_idx].csc); | ||
673 | |||
674 | mutex_unlock(&dc->lock); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | EXPORT_SYMBOL(tegra_dc_update_csc); | ||
679 | |||
680 | static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut) | ||
681 | { | ||
682 | int i; | ||
683 | for (i = 0; i < 256; i++) | ||
684 | lut->r[i] = lut->g[i] = lut->b[i] = (u8)i; | ||
685 | } | ||
686 | |||
687 | static int tegra_dc_loop_lut(struct tegra_dc *dc, | ||
688 | struct tegra_dc_win *win, | ||
689 | int(*lambda)(struct tegra_dc *dc, int i, u32 rgb)) | ||
690 | { | ||
691 | struct tegra_dc_lut *lut = &win->lut; | ||
692 | struct tegra_dc_lut *global_lut = &dc->fb_lut; | ||
693 | int i; | ||
694 | for (i = 0; i < 256; i++) { | ||
695 | |||
696 | u32 r = (u32)lut->r[i]; | ||
697 | u32 g = (u32)lut->g[i]; | ||
698 | u32 b = (u32)lut->b[i]; | ||
699 | |||
700 | if (!(win->ppflags & TEGRA_WIN_PPFLAG_CP_FBOVERRIDE)) { | ||
701 | r = (u32)global_lut->r[r]; | ||
702 | g = (u32)global_lut->g[g]; | ||
703 | b = (u32)global_lut->b[b]; | ||
704 | } | ||
705 | |||
706 | if (!lambda(dc, i, r | (g<<8) | (b<<16))) | ||
707 | return 0; | ||
708 | } | ||
709 | return 1; | ||
710 | } | ||
711 | |||
712 | static int tegra_dc_lut_isdefaults_lambda(struct tegra_dc *dc, int i, u32 rgb) | ||
713 | { | ||
714 | if (rgb != (i | (i<<8) | (i<<16))) | ||
715 | return 0; | ||
716 | return 1; | ||
717 | } | ||
718 | |||
719 | static int tegra_dc_set_lut_setreg_lambda(struct tegra_dc *dc, int i, u32 rgb) | ||
720 | { | ||
721 | tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i)); | ||
722 | return 1; | ||
723 | } | ||
724 | |||
725 | static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win) | ||
726 | { | ||
727 | unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
728 | |||
729 | tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda); | ||
730 | |||
731 | if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE) | ||
732 | val |= CP_ENABLE; | ||
733 | else | ||
734 | val &= ~CP_ENABLE; | ||
735 | |||
736 | tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS); | ||
737 | } | ||
738 | |||
739 | static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr) | ||
740 | { | ||
741 | struct tegra_dc_win *win = &dc->windows[win_idx]; | ||
742 | |||
743 | mutex_lock(&dc->lock); | ||
744 | |||
745 | if (!dc->enabled) { | ||
746 | mutex_unlock(&dc->lock); | ||
747 | return -EFAULT; | ||
748 | } | ||
749 | |||
750 | if (fbovr > 0) | ||
751 | win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE; | ||
752 | else if (fbovr == 0) | ||
753 | win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE; | ||
754 | |||
755 | if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda)) | ||
756 | win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE; | ||
757 | else | ||
758 | win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE; | ||
759 | |||
760 | tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx, | ||
761 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
762 | |||
763 | tegra_dc_set_lut(dc, win); | ||
764 | |||
765 | mutex_unlock(&dc->lock); | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride) | ||
771 | { | ||
772 | if (win_idx > -1) | ||
773 | return tegra_dc_update_winlut(dc, win_idx, fboveride); | ||
774 | |||
775 | for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) { | ||
776 | int err = tegra_dc_update_winlut(dc, win_idx, fboveride); | ||
777 | if (err) | ||
778 | return err; | ||
779 | } | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | EXPORT_SYMBOL(tegra_dc_update_lut); | ||
784 | |||
785 | static void tegra_dc_set_scaling_filter(struct tegra_dc *dc) | ||
786 | { | ||
787 | unsigned i; | ||
788 | unsigned v0 = 128; | ||
789 | unsigned v1 = 0; | ||
790 | /* linear horizontal and vertical filters */ | ||
791 | for (i = 0; i < 16; i++) { | ||
792 | tegra_dc_writel(dc, (v1 << 16) | (v0 << 8), | ||
793 | DC_WIN_H_FILTER_P(i)); | ||
794 | |||
795 | tegra_dc_writel(dc, v0, | ||
796 | DC_WIN_V_FILTER_P(i)); | ||
797 | v0 -= 8; | ||
798 | v1 += 8; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | static void tegra_dc_set_latency_allowance(struct tegra_dc *dc, | ||
803 | struct tegra_dc_win *w) | ||
804 | { | ||
805 | /* windows A, B, C for first and second display */ | ||
806 | static const enum tegra_la_id la_id_tab[2][3] = { | ||
807 | /* first display */ | ||
808 | { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B, | ||
809 | TEGRA_LA_DISPLAY_0C }, | ||
810 | /* second display */ | ||
811 | { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB, | ||
812 | TEGRA_LA_DISPLAY_0CB }, | ||
813 | }; | ||
814 | /* window B V-filter tap for first and second display. */ | ||
815 | static const enum tegra_la_id vfilter_tab[2] = { | ||
816 | TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB, | ||
817 | }; | ||
818 | unsigned long bw; | ||
819 | |||
820 | BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab)); | ||
821 | BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab)); | ||
822 | BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab)); | ||
823 | |||
824 | bw = w->new_bandwidth; | ||
825 | |||
826 | /* tegra_dc_get_bandwidth() treats V filter windows as double | ||
827 | * bandwidth, but LA has a seperate client for V filter */ | ||
828 | if (w->idx == 1 && win_use_v_filter(w)) | ||
829 | bw /= 2; | ||
830 | |||
831 | /* our bandwidth is in bytes/sec, but LA takes MBps. | ||
832 | * round up bandwidth to 1MBps */ | ||
833 | bw = bw / 1000000 + 1; | ||
834 | |||
835 | #ifdef CONFIG_TEGRA_SILICON_PLATFORM | ||
836 | tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw); | ||
837 | /* if window B, also set the 1B client for the 2-tap V filter. */ | ||
838 | if (w->idx == 1) | ||
839 | tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw); | ||
840 | #endif | ||
841 | |||
842 | w->bandwidth = w->new_bandwidth; | ||
843 | } | ||
844 | |||
845 | static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a, | ||
846 | struct tegra_dc_win *b) | ||
847 | { | ||
848 | if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b)) | ||
849 | return 0; | ||
850 | |||
851 | /* because memory access to load the fifo can overlap, only care | ||
852 | * if windows overlap vertically */ | ||
853 | return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) || | ||
854 | ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y)); | ||
855 | } | ||
856 | |||
857 | static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[], | ||
858 | int n) | ||
859 | { | ||
860 | unsigned i; | ||
861 | unsigned j; | ||
862 | unsigned overlap_count; | ||
863 | unsigned max_bw = 0; | ||
864 | |||
865 | WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely" | ||
866 | "inaccurate.\n"); | ||
867 | |||
868 | /* If we had a large number of windows, we would compute adjacency | ||
869 | * graph representing 2 window overlaps, find all cliques in the graph, | ||
870 | * assign bandwidth to each clique, and then select the clique with | ||
871 | * maximum bandwidth. But because we have at most 3 windows, | ||
872 | * implementing proper Bron-Kerbosh algorithm would be an overkill, | ||
873 | * brute force will suffice. | ||
874 | * | ||
875 | * Thus: find maximum bandwidth for either single or a pair of windows | ||
876 | * and count number of window pair overlaps. If there are three | ||
877 | * pairs, all 3 window overlap. | ||
878 | */ | ||
879 | |||
880 | overlap_count = 0; | ||
881 | for (i = 0; i < n; i++) { | ||
882 | unsigned int bw1; | ||
883 | |||
884 | if (wins[i] == NULL) | ||
885 | continue; | ||
886 | bw1 = wins[i]->new_bandwidth; | ||
887 | if (bw1 > max_bw) | ||
888 | /* Single window */ | ||
889 | max_bw = bw1; | ||
890 | |||
891 | for (j = i + 1; j < n; j++) { | ||
892 | if (wins[j] == NULL) | ||
893 | continue; | ||
894 | if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) { | ||
895 | unsigned int bw2 = wins[j]->new_bandwidth; | ||
896 | if (bw1 + bw2 > max_bw) | ||
897 | /* Window pair overlaps */ | ||
898 | max_bw = bw1 + bw2; | ||
899 | overlap_count++; | ||
900 | } | ||
901 | } | ||
902 | } | ||
903 | |||
904 | if (overlap_count == 3) | ||
905 | /* All three windows overlap */ | ||
906 | max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth + | ||
907 | wins[2]->new_bandwidth; | ||
908 | |||
909 | return max_bw; | ||
910 | } | ||
911 | |||
912 | /* | ||
913 | * Calculate peak EMC bandwidth for each enabled window = | ||
914 | * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor * | ||
915 | * (windows_tiling ? 2 : 1) | ||
916 | * | ||
917 | * | ||
918 | * note: | ||
919 | * (*) We use 2 tap V filter, so need double BW if use V filter | ||
920 | * (*) Tiling mode on T30 and DDR3 requires double BW | ||
921 | */ | ||
922 | static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc, | ||
923 | struct tegra_dc_win *w) | ||
924 | { | ||
925 | unsigned long ret; | ||
926 | int tiled_windows_bw_multiplier; | ||
927 | unsigned long bpp; | ||
928 | |||
929 | if (!WIN_IS_ENABLED(w)) | ||
930 | return 0; | ||
931 | |||
932 | if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 || | ||
933 | w->out_w == 0 || w->out_h == 0) | ||
934 | return 0; | ||
935 | |||
936 | tiled_windows_bw_multiplier = | ||
937 | tegra_mc_get_tiled_memory_bandwidth_multiplier(); | ||
938 | |||
939 | /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel, | ||
940 | * but the size reported by tegra_dc_fmt_bpp for the planar version | ||
941 | * is of the luma plane's size only. */ | ||
942 | bpp = tegra_dc_is_yuv_planar(w->fmt) ? | ||
943 | 2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt); | ||
944 | /* perform calculations with most significant bits of pixel clock | ||
945 | * to prevent overflow of long. */ | ||
946 | ret = (unsigned long)(dc->mode.pclk >> 16) * | ||
947 | bpp / 8 * | ||
948 | (win_use_v_filter(w) ? 2 : 1) * dfixed_trunc(w->w) / w->out_w * | ||
949 | (WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1); | ||
950 | |||
951 | /* | ||
952 | * Assuming 48% efficiency: i.e. if we calculate we need 70MBps, we | ||
953 | * will request 147MBps from EMC. | ||
954 | */ | ||
955 | ret = ret * 2 + ret / 10; | ||
956 | |||
957 | /* if overflowed */ | ||
958 | if (ret > (1UL << 31)) | ||
959 | return ULONG_MAX; | ||
960 | |||
961 | return ret << 16; /* restore the scaling we did above */ | ||
962 | } | ||
963 | |||
964 | static unsigned long tegra_dc_get_bandwidth( | ||
965 | struct tegra_dc_win *windows[], int n) | ||
966 | { | ||
967 | int i; | ||
968 | |||
969 | BUG_ON(n > DC_N_WINDOWS); | ||
970 | |||
971 | /* emc rate and latency allowance both need to know per window | ||
972 | * bandwidths */ | ||
973 | for (i = 0; i < n; i++) { | ||
974 | struct tegra_dc_win *w = windows[i]; | ||
975 | if (w) | ||
976 | w->new_bandwidth = tegra_dc_calc_win_bandwidth(w->dc, w); | ||
977 | } | ||
978 | |||
979 | return tegra_dc_find_max_bandwidth(windows, n); | ||
980 | } | ||
981 | |||
982 | /* to save power, call when display memory clients would be idle */ | ||
983 | static void tegra_dc_clear_bandwidth(struct tegra_dc *dc) | ||
984 | { | ||
985 | if (tegra_is_clk_enabled(dc->emc_clk)) | ||
986 | clk_disable(dc->emc_clk); | ||
987 | dc->emc_clk_rate = 0; | ||
988 | } | ||
989 | |||
990 | static void tegra_dc_program_bandwidth(struct tegra_dc *dc) | ||
991 | { | ||
992 | unsigned i; | ||
993 | |||
994 | if (dc->emc_clk_rate != dc->new_emc_clk_rate) { | ||
995 | /* going from 0 to non-zero */ | ||
996 | if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk)) | ||
997 | clk_enable(dc->emc_clk); | ||
998 | |||
999 | dc->emc_clk_rate = dc->new_emc_clk_rate; | ||
1000 | clk_set_rate(dc->emc_clk, dc->emc_clk_rate); | ||
1001 | |||
1002 | if (!dc->new_emc_clk_rate) /* going from non-zero to 0 */ | ||
1003 | clk_disable(dc->emc_clk); | ||
1004 | } | ||
1005 | |||
1006 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
1007 | struct tegra_dc_win *w = &dc->windows[i]; | ||
1008 | if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0) | ||
1009 | tegra_dc_set_latency_allowance(dc, w); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | static int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n) | ||
1014 | { | ||
1015 | unsigned long new_rate; | ||
1016 | struct tegra_dc *dc; | ||
1017 | |||
1018 | if (!use_dynamic_emc) | ||
1019 | return 0; | ||
1020 | |||
1021 | dc = windows[0]->dc; | ||
1022 | |||
1023 | /* calculate the new rate based on this POST */ | ||
1024 | new_rate = tegra_dc_get_bandwidth(windows, n); | ||
1025 | new_rate = EMC_BW_TO_FREQ(new_rate); | ||
1026 | |||
1027 | if (tegra_dc_has_multiple_dc()) | ||
1028 | new_rate = ULONG_MAX; | ||
1029 | |||
1030 | dc->new_emc_clk_rate = new_rate; | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int, | ||
1036 | bool v, unsigned Bpp) | ||
1037 | { | ||
1038 | /* | ||
1039 | * min(round((prescaled_size_in_pixels - 1) * 0x1000 / | ||
1040 | * (post_scaled_size_in_pixels - 1)), MAX) | ||
1041 | * Where the value of MAX is as follows: | ||
1042 | * For V_DDA_INCREMENT: 15.0 (0xF000) | ||
1043 | * For H_DDA_INCREMENT: 4.0 (0x4000) for 4 Bytes/pix formats. | ||
1044 | * 8.0 (0x8000) for 2 Bytes/pix formats. | ||
1045 | */ | ||
1046 | |||
1047 | fixed20_12 out = dfixed_init(out_int); | ||
1048 | u32 dda_inc; | ||
1049 | int max; | ||
1050 | |||
1051 | if (v) { | ||
1052 | max = 15; | ||
1053 | } else { | ||
1054 | switch (Bpp) { | ||
1055 | default: | ||
1056 | WARN_ON_ONCE(1); | ||
1057 | /* fallthrough */ | ||
1058 | case 4: | ||
1059 | max = 4; | ||
1060 | break; | ||
1061 | case 2: | ||
1062 | max = 8; | ||
1063 | break; | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | out.full = max_t(u32, out.full - dfixed_const(1), dfixed_const(1)); | ||
1068 | in.full -= dfixed_const(1); | ||
1069 | |||
1070 | dda_inc = dfixed_div(in, out); | ||
1071 | |||
1072 | dda_inc = min_t(u32, dda_inc, dfixed_const(max)); | ||
1073 | |||
1074 | return dda_inc; | ||
1075 | } | ||
1076 | |||
1077 | static inline u32 compute_initial_dda(fixed20_12 in) | ||
1078 | { | ||
1079 | return dfixed_frac(in); | ||
1080 | } | ||
1081 | |||
1082 | /* does not support updating windows on multiple dcs in one call */ | ||
1083 | int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) | ||
1084 | { | ||
1085 | struct tegra_dc *dc; | ||
1086 | unsigned long update_mask = GENERAL_ACT_REQ; | ||
1087 | unsigned long val; | ||
1088 | bool update_blend = false; | ||
1089 | int i; | ||
1090 | |||
1091 | dc = windows[0]->dc; | ||
1092 | |||
1093 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { | ||
1094 | /* Acquire one_shot_lock to avoid race condition between | ||
1095 | * cancellation of old delayed work and schedule of new | ||
1096 | * delayed work. */ | ||
1097 | mutex_lock(&dc->one_shot_lock); | ||
1098 | cancel_delayed_work_sync(&dc->one_shot_work); | ||
1099 | } | ||
1100 | mutex_lock(&dc->lock); | ||
1101 | |||
1102 | if (!dc->enabled) { | ||
1103 | mutex_unlock(&dc->lock); | ||
1104 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
1105 | mutex_unlock(&dc->one_shot_lock); | ||
1106 | return -EFAULT; | ||
1107 | } | ||
1108 | |||
1109 | if (no_vsync) | ||
1110 | tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE, DC_CMD_STATE_ACCESS); | ||
1111 | else | ||
1112 | tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS); | ||
1113 | |||
1114 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
1115 | tegra_dc_writel(dc, WINDOW_A_SELECT << i, | ||
1116 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
1117 | tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS); | ||
1118 | if (!no_vsync) | ||
1119 | update_mask |= WIN_A_ACT_REQ << i; | ||
1120 | } | ||
1121 | |||
1122 | for (i = 0; i < n; i++) { | ||
1123 | struct tegra_dc_win *win = windows[i]; | ||
1124 | unsigned h_dda; | ||
1125 | unsigned v_dda; | ||
1126 | fixed20_12 h_offset, v_offset; | ||
1127 | bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0; | ||
1128 | bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0; | ||
1129 | bool yuvp = tegra_dc_is_yuv_planar(win->fmt); | ||
1130 | unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8; | ||
1131 | /* Bytes per pixel of bandwidth, used for dda_inc calculation */ | ||
1132 | unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1); | ||
1133 | const bool filter_h = win_use_h_filter(win); | ||
1134 | const bool filter_v = win_use_v_filter(win); | ||
1135 | |||
1136 | if (win->z != dc->blend.z[win->idx]) { | ||
1137 | dc->blend.z[win->idx] = win->z; | ||
1138 | update_blend = true; | ||
1139 | } | ||
1140 | if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) != | ||
1141 | dc->blend.flags[win->idx]) { | ||
1142 | dc->blend.flags[win->idx] = | ||
1143 | win->flags & TEGRA_WIN_BLEND_FLAGS_MASK; | ||
1144 | update_blend = true; | ||
1145 | } | ||
1146 | |||
1147 | tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx, | ||
1148 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
1149 | |||
1150 | if (!no_vsync) | ||
1151 | update_mask |= WIN_A_ACT_REQ << win->idx; | ||
1152 | |||
1153 | if (!WIN_IS_ENABLED(win)) { | ||
1154 | tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS); | ||
1155 | continue; | ||
1156 | } | ||
1157 | |||
1158 | tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH); | ||
1159 | tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); | ||
1160 | |||
1161 | tegra_dc_writel(dc, | ||
1162 | V_POSITION(win->out_y) | H_POSITION(win->out_x), | ||
1163 | DC_WIN_POSITION); | ||
1164 | tegra_dc_writel(dc, | ||
1165 | V_SIZE(win->out_h) | H_SIZE(win->out_w), | ||
1166 | DC_WIN_SIZE); | ||
1167 | tegra_dc_writel(dc, | ||
1168 | V_PRESCALED_SIZE(dfixed_trunc(win->h)) | | ||
1169 | H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp), | ||
1170 | DC_WIN_PRESCALED_SIZE); | ||
1171 | |||
1172 | h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw); | ||
1173 | v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw); | ||
1174 | tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda), | ||
1175 | DC_WIN_DDA_INCREMENT); | ||
1176 | h_dda = compute_initial_dda(win->x); | ||
1177 | v_dda = compute_initial_dda(win->y); | ||
1178 | tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); | ||
1179 | tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); | ||
1180 | |||
1181 | tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); | ||
1182 | tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); | ||
1183 | tegra_dc_writel(dc, | ||
1184 | (unsigned long)win->phys_addr, | ||
1185 | DC_WINBUF_START_ADDR); | ||
1186 | |||
1187 | if (!yuvp) { | ||
1188 | tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE); | ||
1189 | } else { | ||
1190 | tegra_dc_writel(dc, | ||
1191 | (unsigned long)win->phys_addr_u, | ||
1192 | DC_WINBUF_START_ADDR_U); | ||
1193 | tegra_dc_writel(dc, | ||
1194 | (unsigned long)win->phys_addr_v, | ||
1195 | DC_WINBUF_START_ADDR_V); | ||
1196 | tegra_dc_writel(dc, | ||
1197 | LINE_STRIDE(win->stride) | | ||
1198 | UV_LINE_STRIDE(win->stride_uv), | ||
1199 | DC_WIN_LINE_STRIDE); | ||
1200 | } | ||
1201 | |||
1202 | h_offset = win->x; | ||
1203 | if (invert_h) { | ||
1204 | h_offset.full += win->w.full - dfixed_const(1); | ||
1205 | } | ||
1206 | |||
1207 | v_offset = win->y; | ||
1208 | if (invert_v) { | ||
1209 | v_offset.full += win->h.full - dfixed_const(1); | ||
1210 | } | ||
1211 | |||
1212 | tegra_dc_writel(dc, dfixed_trunc(h_offset) * Bpp, | ||
1213 | DC_WINBUF_ADDR_H_OFFSET); | ||
1214 | tegra_dc_writel(dc, dfixed_trunc(v_offset), | ||
1215 | DC_WINBUF_ADDR_V_OFFSET); | ||
1216 | |||
1217 | if (WIN_IS_TILED(win)) | ||
1218 | tegra_dc_writel(dc, | ||
1219 | DC_WIN_BUFFER_ADDR_MODE_TILE | | ||
1220 | DC_WIN_BUFFER_ADDR_MODE_TILE_UV, | ||
1221 | DC_WIN_BUFFER_ADDR_MODE); | ||
1222 | else | ||
1223 | tegra_dc_writel(dc, | ||
1224 | DC_WIN_BUFFER_ADDR_MODE_LINEAR | | ||
1225 | DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV, | ||
1226 | DC_WIN_BUFFER_ADDR_MODE); | ||
1227 | |||
1228 | val = WIN_ENABLE; | ||
1229 | if (yuvp) | ||
1230 | val |= CSC_ENABLE; | ||
1231 | else if (tegra_dc_fmt_bpp(win->fmt) < 24) | ||
1232 | val |= COLOR_EXPAND; | ||
1233 | |||
1234 | if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE) | ||
1235 | val |= CP_ENABLE; | ||
1236 | |||
1237 | if (filter_h) | ||
1238 | val |= H_FILTER_ENABLE; | ||
1239 | if (filter_v) | ||
1240 | val |= V_FILTER_ENABLE; | ||
1241 | |||
1242 | if (invert_h) | ||
1243 | val |= H_DIRECTION_DECREMENT; | ||
1244 | if (invert_v) | ||
1245 | val |= V_DIRECTION_DECREMENT; | ||
1246 | |||
1247 | tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS); | ||
1248 | |||
1249 | win->dirty = no_vsync ? 0 : 1; | ||
1250 | |||
1251 | dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d " | ||
1252 | "out_x=%u out_y=%u out_w=%u out_h=%u " | ||
1253 | "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d", | ||
1254 | __func__, win->idx, win->z, | ||
1255 | dfixed_trunc(win->x), dfixed_trunc(win->y), | ||
1256 | dfixed_trunc(win->w), dfixed_trunc(win->h), | ||
1257 | win->out_x, win->out_y, win->out_w, win->out_h, | ||
1258 | win->fmt, yuvp, Bpp, filter_h, filter_v); | ||
1259 | } | ||
1260 | |||
1261 | if (update_blend) { | ||
1262 | tegra_dc_set_blending(dc, &dc->blend); | ||
1263 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
1264 | if (!no_vsync) | ||
1265 | dc->windows[i].dirty = 1; | ||
1266 | update_mask |= WIN_A_ACT_REQ << i; | ||
1267 | } | ||
1268 | } | ||
1269 | |||
1270 | tegra_dc_set_dynamic_emc(windows, n); | ||
1271 | |||
1272 | tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL); | ||
1273 | |||
1274 | tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS); | ||
1275 | if (!no_vsync) { | ||
1276 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
1277 | val |= (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); | ||
1278 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
1279 | } else { | ||
1280 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
1281 | val &= ~(FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); | ||
1282 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
1283 | } | ||
1284 | |||
1285 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
1286 | schedule_delayed_work(&dc->one_shot_work, | ||
1287 | msecs_to_jiffies(dc->one_shot_delay_ms)); | ||
1288 | |||
1289 | /* update EMC clock if calculated bandwidth has changed */ | ||
1290 | tegra_dc_program_bandwidth(dc); | ||
1291 | |||
1292 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
1293 | update_mask |= NC_HOST_TRIG; | ||
1294 | |||
1295 | tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); | ||
1296 | |||
1297 | mutex_unlock(&dc->lock); | ||
1298 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
1299 | mutex_unlock(&dc->one_shot_lock); | ||
1300 | |||
1301 | return 0; | ||
1302 | } | ||
1303 | EXPORT_SYMBOL(tegra_dc_update_windows); | ||
1304 | |||
1305 | u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc, int i) | ||
1306 | { | ||
1307 | return dc->syncpt[i].id; | ||
1308 | } | ||
1309 | EXPORT_SYMBOL(tegra_dc_get_syncpt_id); | ||
1310 | |||
1311 | u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i) | ||
1312 | { | ||
1313 | u32 max; | ||
1314 | |||
1315 | mutex_lock(&dc->lock); | ||
1316 | max = nvhost_syncpt_incr_max(&nvhost_get_host(dc->ndev)->syncpt, | ||
1317 | dc->syncpt[i].id, ((dc->enabled) ? 1 : 0)); | ||
1318 | dc->syncpt[i].max = max; | ||
1319 | mutex_unlock(&dc->lock); | ||
1320 | |||
1321 | return max; | ||
1322 | } | ||
1323 | |||
1324 | void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val) | ||
1325 | { | ||
1326 | mutex_lock(&dc->lock); | ||
1327 | if ( dc->enabled ) | ||
1328 | while (dc->syncpt[i].min < val) { | ||
1329 | dc->syncpt[i].min++; | ||
1330 | nvhost_syncpt_cpu_incr( | ||
1331 | &nvhost_get_host(dc->ndev)->syncpt, | ||
1332 | dc->syncpt[i].id); | ||
1333 | } | ||
1334 | mutex_unlock(&dc->lock); | ||
1335 | } | ||
1336 | |||
1337 | static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[], | ||
1338 | int n) | ||
1339 | { | ||
1340 | int i; | ||
1341 | |||
1342 | for (i = 0; i < n; i++) { | ||
1343 | if (windows[i]->dirty) | ||
1344 | return false; | ||
1345 | } | ||
1346 | |||
1347 | return true; | ||
1348 | } | ||
1349 | |||
1350 | /* does not support syncing windows on multiple dcs in one call */ | ||
1351 | int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n) | ||
1352 | { | ||
1353 | if (n < 1 || n > DC_N_WINDOWS) | ||
1354 | return -EINVAL; | ||
1355 | |||
1356 | if (!windows[0]->dc->enabled) | ||
1357 | return -EFAULT; | ||
1358 | |||
1359 | #ifdef CONFIG_TEGRA_SIMULATION_PLATFORM | ||
1360 | /* Don't want to timeout on simulator */ | ||
1361 | return wait_event_interruptible(windows[0]->dc->wq, | ||
1362 | tegra_dc_windows_are_clean(windows, n)); | ||
1363 | #else | ||
1364 | return wait_event_interruptible_timeout(windows[0]->dc->wq, | ||
1365 | tegra_dc_windows_are_clean(windows, n), | ||
1366 | HZ); | ||
1367 | #endif | ||
1368 | } | ||
1369 | EXPORT_SYMBOL(tegra_dc_sync_windows); | ||
1370 | |||
1371 | static unsigned long tegra_dc_clk_get_rate(struct tegra_dc *dc) | ||
1372 | { | ||
1373 | #ifdef CONFIG_TEGRA_SILICON_PLATFORM | ||
1374 | return clk_get_rate(dc->clk); | ||
1375 | #else | ||
1376 | return 27000000; | ||
1377 | #endif | ||
1378 | } | ||
1379 | |||
1380 | static unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk) | ||
1381 | { | ||
1382 | unsigned long rate; | ||
1383 | unsigned long div; | ||
1384 | |||
1385 | rate = tegra_dc_clk_get_rate(dc); | ||
1386 | |||
1387 | div = DIV_ROUND_CLOSEST(rate * 2, pclk); | ||
1388 | |||
1389 | if (div < 2) | ||
1390 | return 0; | ||
1391 | |||
1392 | return rate * 2 / div; | ||
1393 | } | ||
1394 | |||
1395 | static unsigned long tegra_dc_pclk_predict_rate(struct clk *parent, int pclk) | ||
1396 | { | ||
1397 | unsigned long rate; | ||
1398 | unsigned long div; | ||
1399 | |||
1400 | rate = clk_get_rate(parent); | ||
1401 | |||
1402 | div = DIV_ROUND_CLOSEST(rate * 2, pclk); | ||
1403 | |||
1404 | if (div < 2) | ||
1405 | return 0; | ||
1406 | |||
1407 | return rate * 2 / div; | ||
1408 | } | ||
1409 | |||
1410 | void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk) | ||
1411 | { | ||
1412 | int pclk; | ||
1413 | |||
1414 | if (dc->out->type == TEGRA_DC_OUT_RGB) { | ||
1415 | unsigned long rate; | ||
1416 | struct clk *parent_clk = | ||
1417 | clk_get_sys(NULL, dc->out->parent_clk ? : "pll_p"); | ||
1418 | |||
1419 | if (dc->out->parent_clk_backup && | ||
1420 | (parent_clk == clk_get_sys(NULL, "pll_p"))) { | ||
1421 | rate = tegra_dc_pclk_predict_rate( | ||
1422 | parent_clk, dc->mode.pclk); | ||
1423 | /* use pll_d as last resort */ | ||
1424 | if (rate < (dc->mode.pclk / 100 * 99) || | ||
1425 | rate > (dc->mode.pclk / 100 * 109)) | ||
1426 | parent_clk = clk_get_sys( | ||
1427 | NULL, dc->out->parent_clk_backup); | ||
1428 | } | ||
1429 | |||
1430 | if (clk_get_parent(clk) != parent_clk) | ||
1431 | clk_set_parent(clk, parent_clk); | ||
1432 | |||
1433 | if (parent_clk != clk_get_sys(NULL, "pll_p")) { | ||
1434 | struct clk *base_clk = clk_get_parent(parent_clk); | ||
1435 | |||
1436 | /* Assuming either pll_d or pll_d2 is used */ | ||
1437 | rate = dc->mode.pclk * 2; | ||
1438 | |||
1439 | if (rate != clk_get_rate(base_clk)) | ||
1440 | clk_set_rate(base_clk, rate); | ||
1441 | } | ||
1442 | } | ||
1443 | |||
1444 | if (dc->out->type == TEGRA_DC_OUT_HDMI) { | ||
1445 | unsigned long rate; | ||
1446 | struct clk *parent_clk = | ||
1447 | clk_get_sys(NULL, dc->out->parent_clk ? : "pll_d_out0"); | ||
1448 | struct clk *base_clk = clk_get_parent(parent_clk); | ||
1449 | |||
1450 | /* | ||
1451 | * Providing dynamic frequency rate setting for T20/T30 HDMI. | ||
1452 | * The required rate needs to be setup at 4x multiplier, | ||
1453 | * as out0 is 1/2 of the actual PLL output. | ||
1454 | */ | ||
1455 | |||
1456 | rate = dc->mode.pclk * 4; | ||
1457 | if (rate != clk_get_rate(base_clk)) | ||
1458 | clk_set_rate(base_clk, rate); | ||
1459 | |||
1460 | if (clk_get_parent(clk) != parent_clk) | ||
1461 | clk_set_parent(clk, parent_clk); | ||
1462 | } | ||
1463 | |||
1464 | if (dc->out->type == TEGRA_DC_OUT_DSI) { | ||
1465 | unsigned long rate; | ||
1466 | struct clk *parent_clk; | ||
1467 | struct clk *base_clk; | ||
1468 | |||
1469 | if (clk == dc->clk) { | ||
1470 | parent_clk = clk_get_sys(NULL, | ||
1471 | dc->out->parent_clk ? : "pll_d_out0"); | ||
1472 | base_clk = clk_get_parent(parent_clk); | ||
1473 | tegra_clk_cfg_ex(base_clk, | ||
1474 | TEGRA_CLK_PLLD_DSI_OUT_ENB, 1); | ||
1475 | } else { | ||
1476 | if (dc->pdata->default_out->dsi->dsi_instance) { | ||
1477 | parent_clk = clk_get_sys(NULL, | ||
1478 | dc->out->parent_clk ? : "pll_d2_out0"); | ||
1479 | base_clk = clk_get_parent(parent_clk); | ||
1480 | tegra_clk_cfg_ex(base_clk, | ||
1481 | TEGRA_CLK_PLLD_CSI_OUT_ENB, 1); | ||
1482 | } else { | ||
1483 | parent_clk = clk_get_sys(NULL, | ||
1484 | dc->out->parent_clk ? : "pll_d_out0"); | ||
1485 | base_clk = clk_get_parent(parent_clk); | ||
1486 | tegra_clk_cfg_ex(base_clk, | ||
1487 | TEGRA_CLK_PLLD_DSI_OUT_ENB, 1); | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1491 | rate = dc->mode.pclk * dc->shift_clk_div * 2; | ||
1492 | if (rate != clk_get_rate(base_clk)) | ||
1493 | clk_set_rate(base_clk, rate); | ||
1494 | |||
1495 | if (clk_get_parent(clk) != parent_clk) | ||
1496 | clk_set_parent(clk, parent_clk); | ||
1497 | } | ||
1498 | |||
1499 | pclk = tegra_dc_pclk_round_rate(dc, dc->mode.pclk); | ||
1500 | tegra_dvfs_set_rate(clk, pclk); | ||
1501 | } | ||
1502 | |||
1503 | /* return non-zero if constraint is violated */ | ||
1504 | static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href) | ||
1505 | { | ||
1506 | long a, b; | ||
1507 | |||
1508 | /* Constraint 5: H_REF_TO_SYNC >= 0 */ | ||
1509 | a = 0; | ||
1510 | |||
1511 | /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */ | ||
1512 | b = mode->h_front_porch - 1; | ||
1513 | |||
1514 | /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */ | ||
1515 | if (a + mode->h_sync_width + mode->h_back_porch <= 11) | ||
1516 | a = 1 + 11 - mode->h_sync_width - mode->h_back_porch; | ||
1517 | /* check Constraint 1 and 6 */ | ||
1518 | if (a > b) | ||
1519 | return 1; | ||
1520 | |||
1521 | /* Constraint 4: H_SYNC_WIDTH >= 1 */ | ||
1522 | if (mode->h_sync_width < 1) | ||
1523 | return 4; | ||
1524 | |||
1525 | /* Constraint 7: H_DISP_ACTIVE >= 16 */ | ||
1526 | if (mode->h_active < 16) | ||
1527 | return 7; | ||
1528 | |||
1529 | if (href) { | ||
1530 | if (b > a && a % 2) | ||
1531 | *href = a + 1; /* use smallest even value */ | ||
1532 | else | ||
1533 | *href = a; /* even or only possible value */ | ||
1534 | } | ||
1535 | |||
1536 | return 0; | ||
1537 | } | ||
1538 | |||
1539 | static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref) | ||
1540 | { | ||
1541 | long a; | ||
1542 | a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */ | ||
1543 | |||
1544 | /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */ | ||
1545 | if (a + mode->v_sync_width + mode->v_back_porch <= 1) | ||
1546 | a = 1 + 1 - mode->v_sync_width - mode->v_back_porch; | ||
1547 | |||
1548 | /* Constraint 6 */ | ||
1549 | if (mode->v_front_porch < a + 1) | ||
1550 | a = mode->v_front_porch - 1; | ||
1551 | |||
1552 | /* Constraint 4: V_SYNC_WIDTH >= 1 */ | ||
1553 | if (mode->v_sync_width < 1) | ||
1554 | return 4; | ||
1555 | |||
1556 | /* Constraint 7: V_DISP_ACTIVE >= 16 */ | ||
1557 | if (mode->v_active < 16) | ||
1558 | return 7; | ||
1559 | |||
1560 | if (vref) | ||
1561 | *vref = a; | ||
1562 | return 0; | ||
1563 | } | ||
1564 | |||
1565 | static int calc_ref_to_sync(struct tegra_dc_mode *mode) | ||
1566 | { | ||
1567 | int ret; | ||
1568 | ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync); | ||
1569 | if (ret) | ||
1570 | return ret; | ||
1571 | ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync); | ||
1572 | if (ret) | ||
1573 | return ret; | ||
1574 | |||
1575 | return 0; | ||
1576 | } | ||
1577 | |||
1578 | static bool check_ref_to_sync(struct tegra_dc_mode *mode) | ||
1579 | { | ||
1580 | /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11. */ | ||
1581 | if (mode->h_ref_to_sync + mode->h_sync_width + mode->h_back_porch <= 11) | ||
1582 | return false; | ||
1583 | |||
1584 | /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1. */ | ||
1585 | if (mode->v_ref_to_sync + mode->v_sync_width + mode->v_back_porch <= 1) | ||
1586 | return false; | ||
1587 | |||
1588 | /* Constraint 3: V_FRONT_PORCH + V_SYNC_WIDTH + V_BACK_PORCH > 1 | ||
1589 | * (vertical blank). */ | ||
1590 | if (mode->v_front_porch + mode->v_sync_width + mode->v_back_porch <= 1) | ||
1591 | return false; | ||
1592 | |||
1593 | /* Constraint 4: V_SYNC_WIDTH >= 1; H_SYNC_WIDTH >= 1. */ | ||
1594 | if (mode->v_sync_width < 1 || mode->h_sync_width < 1) | ||
1595 | return false; | ||
1596 | |||
1597 | /* Constraint 5: V_REF_TO_SYNC >= 1; H_REF_TO_SYNC >= 0. */ | ||
1598 | if (mode->v_ref_to_sync < 1 || mode->h_ref_to_sync < 0) | ||
1599 | return false; | ||
1600 | |||
1601 | /* Constraint 6: V_FRONT_PORT >= (V_REF_TO_SYNC + 1); | ||
1602 | * H_FRONT_PORT >= (H_REF_TO_SYNC + 1). */ | ||
1603 | if (mode->v_front_porch < mode->v_ref_to_sync + 1 || | ||
1604 | mode->h_front_porch < mode->h_ref_to_sync + 1) | ||
1605 | return false; | ||
1606 | |||
1607 | /* Constraint 7: H_DISP_ACTIVE >= 16; V_DISP_ACTIVE >= 16. */ | ||
1608 | if (mode->h_active < 16 || mode->v_active < 16) | ||
1609 | return false; | ||
1610 | |||
1611 | return true; | ||
1612 | } | ||
1613 | |||
1614 | #ifdef DEBUG | ||
1615 | /* return in 1000ths of a Hertz */ | ||
1616 | static int calc_refresh(const struct tegra_dc_mode *m) | ||
1617 | { | ||
1618 | long h_total, v_total, refresh; | ||
1619 | h_total = m->h_active + m->h_front_porch + m->h_back_porch + | ||
1620 | m->h_sync_width; | ||
1621 | v_total = m->v_active + m->v_front_porch + m->v_back_porch + | ||
1622 | m->v_sync_width; | ||
1623 | refresh = m->pclk / h_total; | ||
1624 | refresh *= 1000; | ||
1625 | refresh /= v_total; | ||
1626 | return refresh; | ||
1627 | } | ||
1628 | |||
1629 | static void print_mode(struct tegra_dc *dc, | ||
1630 | const struct tegra_dc_mode *mode, const char *note) | ||
1631 | { | ||
1632 | if (mode) { | ||
1633 | int refresh = calc_refresh(dc, mode); | ||
1634 | dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n", | ||
1635 | note ? note : "", | ||
1636 | mode->h_active, mode->v_active, | ||
1637 | refresh / 1000, refresh % 1000, | ||
1638 | mode->pclk); | ||
1639 | } | ||
1640 | } | ||
1641 | #else /* !DEBUG */ | ||
1642 | static inline void print_mode(struct tegra_dc *dc, | ||
1643 | const struct tegra_dc_mode *mode, const char *note) { } | ||
1644 | #endif /* DEBUG */ | ||
1645 | |||
1646 | static inline void enable_dc_irq(unsigned int irq) | ||
1647 | { | ||
1648 | #ifndef CONFIG_TEGRA_FPGA_PLATFORM | ||
1649 | enable_irq(irq); | ||
1650 | #else | ||
1651 | /* Always disable DC interrupts on FPGA. */ | ||
1652 | disable_irq(irq); | ||
1653 | #endif | ||
1654 | } | ||
1655 | |||
1656 | static inline void disable_dc_irq(unsigned int irq) | ||
1657 | { | ||
1658 | disable_irq(irq); | ||
1659 | } | ||
1660 | |||
1661 | static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode) | ||
1662 | { | ||
1663 | unsigned long val; | ||
1664 | unsigned long rate; | ||
1665 | unsigned long div; | ||
1666 | unsigned long pclk; | ||
1667 | |||
1668 | print_mode(dc, mode, __func__); | ||
1669 | |||
1670 | /* use default EMC rate when switching modes */ | ||
1671 | dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc); | ||
1672 | tegra_dc_program_bandwidth(dc); | ||
1673 | |||
1674 | tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); | ||
1675 | tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16), | ||
1676 | DC_DISP_REF_TO_SYNC); | ||
1677 | tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16), | ||
1678 | DC_DISP_SYNC_WIDTH); | ||
1679 | tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16), | ||
1680 | DC_DISP_BACK_PORCH); | ||
1681 | tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16), | ||
1682 | DC_DISP_DISP_ACTIVE); | ||
1683 | tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16), | ||
1684 | DC_DISP_FRONT_PORCH); | ||
1685 | |||
1686 | tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL, | ||
1687 | DC_DISP_DATA_ENABLE_OPTIONS); | ||
1688 | |||
1689 | /* TODO: MIPI/CRT/HDMI clock cals */ | ||
1690 | |||
1691 | val = DISP_DATA_FORMAT_DF1P1C; | ||
1692 | |||
1693 | if (dc->out->align == TEGRA_DC_ALIGN_MSB) | ||
1694 | val |= DISP_DATA_ALIGNMENT_MSB; | ||
1695 | else | ||
1696 | val |= DISP_DATA_ALIGNMENT_LSB; | ||
1697 | |||
1698 | if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE) | ||
1699 | val |= DISP_DATA_ORDER_RED_BLUE; | ||
1700 | else | ||
1701 | val |= DISP_DATA_ORDER_BLUE_RED; | ||
1702 | |||
1703 | tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL); | ||
1704 | |||
1705 | rate = tegra_dc_clk_get_rate(dc); | ||
1706 | |||
1707 | pclk = tegra_dc_pclk_round_rate(dc, mode->pclk); | ||
1708 | if (pclk < (mode->pclk / 100 * 99) || | ||
1709 | pclk > (mode->pclk / 100 * 109)) { | ||
1710 | dev_err(&dc->ndev->dev, | ||
1711 | "can't divide %ld clock to %d -1/+9%% %ld %d %d\n", | ||
1712 | rate, mode->pclk, | ||
1713 | pclk, (mode->pclk / 100 * 99), | ||
1714 | (mode->pclk / 100 * 109)); | ||
1715 | return -EINVAL; | ||
1716 | } | ||
1717 | |||
1718 | div = (rate * 2 / pclk) - 2; | ||
1719 | |||
1720 | tegra_dc_writel(dc, 0x00010001, | ||
1721 | DC_DISP_SHIFT_CLOCK_OPTIONS); | ||
1722 | tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div), | ||
1723 | DC_DISP_DISP_CLOCK_CONTROL); | ||
1724 | |||
1725 | #ifdef CONFIG_SWITCH | ||
1726 | switch_set_state(&dc->modeset_switch, | ||
1727 | (mode->h_active << 16) | mode->v_active); | ||
1728 | #endif | ||
1729 | |||
1730 | tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); | ||
1731 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
1732 | |||
1733 | return 0; | ||
1734 | } | ||
1735 | |||
1736 | |||
1737 | int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode) | ||
1738 | { | ||
1739 | memcpy(&dc->mode, mode, sizeof(dc->mode)); | ||
1740 | |||
1741 | print_mode(dc, mode, __func__); | ||
1742 | |||
1743 | return 0; | ||
1744 | } | ||
1745 | EXPORT_SYMBOL(tegra_dc_set_mode); | ||
1746 | |||
1747 | int tegra_dc_set_fb_mode(struct tegra_dc *dc, | ||
1748 | const struct fb_videomode *fbmode, bool stereo_mode) | ||
1749 | { | ||
1750 | struct tegra_dc_mode mode; | ||
1751 | |||
1752 | if (!fbmode->pixclock) | ||
1753 | return -EINVAL; | ||
1754 | |||
1755 | mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000; | ||
1756 | mode.h_sync_width = fbmode->hsync_len; | ||
1757 | mode.v_sync_width = fbmode->vsync_len; | ||
1758 | mode.h_back_porch = fbmode->left_margin; | ||
1759 | mode.v_back_porch = fbmode->upper_margin; | ||
1760 | mode.h_active = fbmode->xres; | ||
1761 | mode.v_active = fbmode->yres; | ||
1762 | mode.h_front_porch = fbmode->right_margin; | ||
1763 | mode.v_front_porch = fbmode->lower_margin; | ||
1764 | mode.stereo_mode = stereo_mode; | ||
1765 | if (dc->out->type == TEGRA_DC_OUT_HDMI) { | ||
1766 | /* HDMI controller requires h_ref=1, v_ref=1 */ | ||
1767 | mode.h_ref_to_sync = 1; | ||
1768 | mode.v_ref_to_sync = 1; | ||
1769 | } else { | ||
1770 | calc_ref_to_sync(&mode); | ||
1771 | } | ||
1772 | if (!check_ref_to_sync(&mode)) { | ||
1773 | dev_err(&dc->ndev->dev, | ||
1774 | "Display timing doesn't meet restrictions.\n"); | ||
1775 | return -EINVAL; | ||
1776 | } | ||
1777 | dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n", | ||
1778 | mode.h_active, mode.v_active, mode.pclk, | ||
1779 | mode.h_ref_to_sync, mode.v_ref_to_sync | ||
1780 | ); | ||
1781 | |||
1782 | #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
1783 | /* Double the pixel clock and update v_active only for frame packed mode */ | ||
1784 | if (mode.stereo_mode) { | ||
1785 | mode.pclk *= 2; | ||
1786 | /* total v_active = yres*2 + activespace */ | ||
1787 | mode.v_active = fbmode->yres*2 + | ||
1788 | fbmode->vsync_len + | ||
1789 | fbmode->upper_margin + | ||
1790 | fbmode->lower_margin; | ||
1791 | } | ||
1792 | #endif | ||
1793 | |||
1794 | mode.flags = 0; | ||
1795 | |||
1796 | if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT)) | ||
1797 | mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC; | ||
1798 | |||
1799 | if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT)) | ||
1800 | mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC; | ||
1801 | |||
1802 | return tegra_dc_set_mode(dc, &mode); | ||
1803 | } | ||
1804 | EXPORT_SYMBOL(tegra_dc_set_fb_mode); | ||
1805 | |||
1806 | void | ||
1807 | tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg) | ||
1808 | { | ||
1809 | unsigned int ctrl; | ||
1810 | unsigned long out_sel; | ||
1811 | unsigned long cmd_state; | ||
1812 | |||
1813 | mutex_lock(&dc->lock); | ||
1814 | if (!dc->enabled) { | ||
1815 | mutex_unlock(&dc->lock); | ||
1816 | return; | ||
1817 | } | ||
1818 | |||
1819 | ctrl = ((cfg->period << PM_PERIOD_SHIFT) | | ||
1820 | (cfg->clk_div << PM_CLK_DIVIDER_SHIFT) | | ||
1821 | cfg->clk_select); | ||
1822 | |||
1823 | /* The new value should be effected immediately */ | ||
1824 | cmd_state = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); | ||
1825 | tegra_dc_writel(dc, (cmd_state | (1 << 2)), DC_CMD_STATE_ACCESS); | ||
1826 | |||
1827 | if (cfg->switch_to_sfio && cfg->gpio_conf_to_sfio) | ||
1828 | cfg->switch_to_sfio(cfg->gpio_conf_to_sfio); | ||
1829 | else | ||
1830 | dev_err(&dc->ndev->dev, "Error: Need gpio_conf_to_sfio\n"); | ||
1831 | |||
1832 | switch (cfg->which_pwm) { | ||
1833 | case TEGRA_PWM_PM0: | ||
1834 | /* Select the LM0 on PM0 */ | ||
1835 | out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5); | ||
1836 | out_sel &= ~(7 << 0); | ||
1837 | out_sel |= (3 << 0); | ||
1838 | tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5); | ||
1839 | tegra_dc_writel(dc, ctrl, DC_COM_PM0_CONTROL); | ||
1840 | tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM0_DUTY_CYCLE); | ||
1841 | break; | ||
1842 | case TEGRA_PWM_PM1: | ||
1843 | /* Select the LM1 on PM1 */ | ||
1844 | out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5); | ||
1845 | out_sel &= ~(7 << 4); | ||
1846 | out_sel |= (3 << 4); | ||
1847 | tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5); | ||
1848 | tegra_dc_writel(dc, ctrl, DC_COM_PM1_CONTROL); | ||
1849 | tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM1_DUTY_CYCLE); | ||
1850 | break; | ||
1851 | default: | ||
1852 | dev_err(&dc->ndev->dev, "Error: Need which_pwm\n"); | ||
1853 | break; | ||
1854 | } | ||
1855 | tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS); | ||
1856 | mutex_unlock(&dc->lock); | ||
1857 | } | ||
1858 | EXPORT_SYMBOL(tegra_dc_config_pwm); | ||
1859 | |||
1860 | void tegra_dc_set_out_pin_polars(struct tegra_dc *dc, | ||
1861 | const struct tegra_dc_out_pin *pins, | ||
1862 | const unsigned int n_pins) | ||
1863 | { | ||
1864 | unsigned int i; | ||
1865 | |||
1866 | int name; | ||
1867 | int pol; | ||
1868 | |||
1869 | u32 pol1, pol3; | ||
1870 | |||
1871 | u32 set1, unset1; | ||
1872 | u32 set3, unset3; | ||
1873 | |||
1874 | set1 = set3 = unset1 = unset3 = 0; | ||
1875 | |||
1876 | for (i = 0; i < n_pins; i++) { | ||
1877 | name = (pins + i)->name; | ||
1878 | pol = (pins + i)->pol; | ||
1879 | |||
1880 | /* set polarity by name */ | ||
1881 | switch (name) { | ||
1882 | case TEGRA_DC_OUT_PIN_DATA_ENABLE: | ||
1883 | if (pol == TEGRA_DC_OUT_PIN_POL_LOW) | ||
1884 | set3 |= LSPI_OUTPUT_POLARITY_LOW; | ||
1885 | else | ||
1886 | unset3 |= LSPI_OUTPUT_POLARITY_LOW; | ||
1887 | break; | ||
1888 | case TEGRA_DC_OUT_PIN_H_SYNC: | ||
1889 | if (pol == TEGRA_DC_OUT_PIN_POL_LOW) | ||
1890 | set1 |= LHS_OUTPUT_POLARITY_LOW; | ||
1891 | else | ||
1892 | unset1 |= LHS_OUTPUT_POLARITY_LOW; | ||
1893 | break; | ||
1894 | case TEGRA_DC_OUT_PIN_V_SYNC: | ||
1895 | if (pol == TEGRA_DC_OUT_PIN_POL_LOW) | ||
1896 | set1 |= LVS_OUTPUT_POLARITY_LOW; | ||
1897 | else | ||
1898 | unset1 |= LVS_OUTPUT_POLARITY_LOW; | ||
1899 | break; | ||
1900 | case TEGRA_DC_OUT_PIN_PIXEL_CLOCK: | ||
1901 | if (pol == TEGRA_DC_OUT_PIN_POL_LOW) | ||
1902 | set1 |= LSC0_OUTPUT_POLARITY_LOW; | ||
1903 | else | ||
1904 | unset1 |= LSC0_OUTPUT_POLARITY_LOW; | ||
1905 | break; | ||
1906 | default: | ||
1907 | printk("Invalid argument in function %s\n", | ||
1908 | __FUNCTION__); | ||
1909 | break; | ||
1910 | } | ||
1911 | } | ||
1912 | |||
1913 | pol1 = DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL; | ||
1914 | pol3 = DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL; | ||
1915 | |||
1916 | pol1 |= set1; | ||
1917 | pol1 &= ~unset1; | ||
1918 | |||
1919 | pol3 |= set3; | ||
1920 | pol3 &= ~unset3; | ||
1921 | |||
1922 | tegra_dc_writel(dc, pol1, DC_COM_PIN_OUTPUT_POLARITY1); | ||
1923 | tegra_dc_writel(dc, pol3, DC_COM_PIN_OUTPUT_POLARITY3); | ||
1924 | } | ||
1925 | |||
1926 | static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out) | ||
1927 | { | ||
1928 | dc->out = out; | ||
1929 | |||
1930 | if (out->n_modes > 0) | ||
1931 | tegra_dc_set_mode(dc, &dc->out->modes[0]); | ||
1932 | |||
1933 | switch (out->type) { | ||
1934 | case TEGRA_DC_OUT_RGB: | ||
1935 | dc->out_ops = &tegra_dc_rgb_ops; | ||
1936 | break; | ||
1937 | |||
1938 | case TEGRA_DC_OUT_HDMI: | ||
1939 | dc->out_ops = &tegra_dc_hdmi_ops; | ||
1940 | break; | ||
1941 | |||
1942 | case TEGRA_DC_OUT_DSI: | ||
1943 | dc->out_ops = &tegra_dc_dsi_ops; | ||
1944 | break; | ||
1945 | |||
1946 | default: | ||
1947 | dc->out_ops = NULL; | ||
1948 | break; | ||
1949 | } | ||
1950 | |||
1951 | if (dc->out_ops && dc->out_ops->init) | ||
1952 | dc->out_ops->init(dc); | ||
1953 | |||
1954 | } | ||
1955 | |||
1956 | unsigned tegra_dc_get_out_height(const struct tegra_dc *dc) | ||
1957 | { | ||
1958 | if (dc->out) | ||
1959 | return dc->out->height; | ||
1960 | else | ||
1961 | return 0; | ||
1962 | } | ||
1963 | EXPORT_SYMBOL(tegra_dc_get_out_height); | ||
1964 | |||
1965 | unsigned tegra_dc_get_out_width(const struct tegra_dc *dc) | ||
1966 | { | ||
1967 | if (dc->out) | ||
1968 | return dc->out->width; | ||
1969 | else | ||
1970 | return 0; | ||
1971 | } | ||
1972 | EXPORT_SYMBOL(tegra_dc_get_out_width); | ||
1973 | |||
1974 | unsigned tegra_dc_get_out_max_pixclock(const struct tegra_dc *dc) | ||
1975 | { | ||
1976 | if (dc->out && dc->out->max_pixclock) | ||
1977 | return dc->out->max_pixclock; | ||
1978 | else | ||
1979 | return 0; | ||
1980 | } | ||
1981 | EXPORT_SYMBOL(tegra_dc_get_out_max_pixclock); | ||
1982 | |||
1983 | void tegra_dc_enable_crc(struct tegra_dc *dc) | ||
1984 | { | ||
1985 | u32 val; | ||
1986 | tegra_dc_io_start(dc); | ||
1987 | |||
1988 | val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA | | ||
1989 | CRC_ENABLE_ENABLE; | ||
1990 | tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL); | ||
1991 | tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); | ||
1992 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
1993 | } | ||
1994 | |||
1995 | void tegra_dc_disable_crc(struct tegra_dc *dc) | ||
1996 | { | ||
1997 | tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL); | ||
1998 | tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); | ||
1999 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
2000 | |||
2001 | tegra_dc_io_end(dc); | ||
2002 | } | ||
2003 | |||
2004 | u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc) | ||
2005 | { | ||
2006 | int crc = 0; | ||
2007 | |||
2008 | if(!dc) { | ||
2009 | dev_err(&dc->ndev->dev, "Failed to get dc.\n"); | ||
2010 | goto crc_error; | ||
2011 | } | ||
2012 | |||
2013 | /* TODO: Replace mdelay with code to sync VBlANK, since | ||
2014 | * DC_COM_CRC_CHECKSUM_LATCHED is available after VBLANK */ | ||
2015 | mdelay(TEGRA_CRC_LATCHED_DELAY); | ||
2016 | |||
2017 | crc = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM_LATCHED); | ||
2018 | crc_error: | ||
2019 | return crc; | ||
2020 | } | ||
2021 | |||
2022 | static void tegra_dc_vblank(struct work_struct *work) | ||
2023 | { | ||
2024 | struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work); | ||
2025 | bool nvsd_updated = false; | ||
2026 | |||
2027 | mutex_lock(&dc->lock); | ||
2028 | |||
2029 | /* Update the SD brightness */ | ||
2030 | if (dc->enabled && dc->out->sd_settings) | ||
2031 | nvsd_updated = nvsd_update_brightness(dc); | ||
2032 | |||
2033 | mutex_unlock(&dc->lock); | ||
2034 | |||
2035 | /* Do the actual brightness update outside of the mutex */ | ||
2036 | if (nvsd_updated && dc->out->sd_settings && | ||
2037 | dc->out->sd_settings->bl_device) { | ||
2038 | |||
2039 | struct platform_device *pdev = dc->out->sd_settings->bl_device; | ||
2040 | struct backlight_device *bl = platform_get_drvdata(pdev); | ||
2041 | if (bl) | ||
2042 | backlight_update_status(bl); | ||
2043 | } | ||
2044 | } | ||
2045 | |||
2046 | /* Must acquire dc lock and dc one-shot lock before invoking this function. | ||
2047 | * Acquire dc one-shot lock first and then dc lock. */ | ||
2048 | void tegra_dc_host_trigger(struct tegra_dc *dc) | ||
2049 | { | ||
2050 | /* We release the lock here to prevent deadlock between | ||
2051 | * cancel_delayed_work_sync and one-shot work. */ | ||
2052 | mutex_unlock(&dc->lock); | ||
2053 | |||
2054 | cancel_delayed_work_sync(&dc->one_shot_work); | ||
2055 | mutex_lock(&dc->lock); | ||
2056 | |||
2057 | schedule_delayed_work(&dc->one_shot_work, | ||
2058 | msecs_to_jiffies(dc->one_shot_delay_ms)); | ||
2059 | tegra_dc_program_bandwidth(dc); | ||
2060 | tegra_dc_writel(dc, NC_HOST_TRIG, DC_CMD_STATE_CONTROL); | ||
2061 | } | ||
2062 | |||
2063 | static void tegra_dc_one_shot_worker(struct work_struct *work) | ||
2064 | { | ||
2065 | struct tegra_dc *dc = container_of( | ||
2066 | to_delayed_work(work), struct tegra_dc, one_shot_work); | ||
2067 | mutex_lock(&dc->lock); | ||
2068 | /* memory client has gone idle */ | ||
2069 | tegra_dc_clear_bandwidth(dc); | ||
2070 | mutex_unlock(&dc->lock); | ||
2071 | } | ||
2072 | |||
2073 | /* return an arbitrarily large number if count overflow occurs. | ||
2074 | * make it a nice base-10 number to show up in stats output */ | ||
2075 | static u64 tegra_dc_underflow_count(struct tegra_dc *dc, unsigned reg) | ||
2076 | { | ||
2077 | unsigned count = tegra_dc_readl(dc, reg); | ||
2078 | tegra_dc_writel(dc, 0, reg); | ||
2079 | return ((count & 0x80000000) == 0) ? count : 10000000000ll; | ||
2080 | } | ||
2081 | |||
2082 | static void tegra_dc_underflow_handler(struct tegra_dc *dc) | ||
2083 | { | ||
2084 | u32 val; | ||
2085 | int i; | ||
2086 | |||
2087 | dc->stats.underflows++; | ||
2088 | if (dc->underflow_mask & WIN_A_UF_INT) | ||
2089 | dc->stats.underflows_a += tegra_dc_underflow_count(dc, | ||
2090 | DC_WINBUF_AD_UFLOW_STATUS); | ||
2091 | if (dc->underflow_mask & WIN_B_UF_INT) | ||
2092 | dc->stats.underflows_b += tegra_dc_underflow_count(dc, | ||
2093 | DC_WINBUF_BD_UFLOW_STATUS); | ||
2094 | if (dc->underflow_mask & WIN_C_UF_INT) | ||
2095 | dc->stats.underflows_c += tegra_dc_underflow_count(dc, | ||
2096 | DC_WINBUF_CD_UFLOW_STATUS); | ||
2097 | |||
2098 | /* Check for any underflow reset conditions */ | ||
2099 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
2100 | if (dc->underflow_mask & (WIN_A_UF_INT << i)) { | ||
2101 | dc->windows[i].underflows++; | ||
2102 | |||
2103 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
2104 | if (dc->windows[i].underflows > 4) | ||
2105 | schedule_work(&dc->reset_work); | ||
2106 | #endif | ||
2107 | } else { | ||
2108 | dc->windows[i].underflows = 0; | ||
2109 | } | ||
2110 | } | ||
2111 | |||
2112 | /* Clear the underflow mask now that we've checked it. */ | ||
2113 | tegra_dc_writel(dc, dc->underflow_mask, DC_CMD_INT_STATUS); | ||
2114 | dc->underflow_mask = 0; | ||
2115 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
2116 | tegra_dc_writel(dc, val | ALL_UF_INT, DC_CMD_INT_MASK); | ||
2117 | } | ||
2118 | |||
2119 | #ifndef CONFIG_TEGRA_FPGA_PLATFORM | ||
2120 | static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc) | ||
2121 | { | ||
2122 | #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM | ||
2123 | u32 val; | ||
2124 | |||
2125 | val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); | ||
2126 | if (val & (WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE)) | ||
2127 | return true; | ||
2128 | #endif | ||
2129 | return false; | ||
2130 | } | ||
2131 | |||
2132 | static void tegra_dc_trigger_windows(struct tegra_dc *dc) | ||
2133 | { | ||
2134 | u32 val, i; | ||
2135 | u32 completed = 0; | ||
2136 | u32 dirty = 0; | ||
2137 | |||
2138 | val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); | ||
2139 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
2140 | #ifdef CONFIG_TEGRA_SIMULATION_PLATFORM | ||
2141 | /* FIXME: this is not needed when the simulator | ||
2142 | clears WIN_x_UPDATE bits as in HW */ | ||
2143 | dc->windows[i].dirty = 0; | ||
2144 | completed = 1; | ||
2145 | #else | ||
2146 | if (!(val & (WIN_A_UPDATE << i))) { | ||
2147 | dc->windows[i].dirty = 0; | ||
2148 | completed = 1; | ||
2149 | } else { | ||
2150 | dirty = 1; | ||
2151 | } | ||
2152 | #endif | ||
2153 | } | ||
2154 | |||
2155 | if (!dirty) { | ||
2156 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
2157 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
2158 | val &= ~V_BLANK_INT; | ||
2159 | else | ||
2160 | val &= ~FRAME_END_INT; | ||
2161 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
2162 | } | ||
2163 | |||
2164 | if (completed) { | ||
2165 | if (!dirty) { | ||
2166 | /* With the last completed window, go ahead | ||
2167 | and enable the vblank interrupt for nvsd. */ | ||
2168 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
2169 | val |= V_BLANK_INT; | ||
2170 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
2171 | } | ||
2172 | |||
2173 | wake_up(&dc->wq); | ||
2174 | } | ||
2175 | } | ||
2176 | |||
2177 | static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status) | ||
2178 | { | ||
2179 | if (status & V_BLANK_INT) { | ||
2180 | /* Sync up windows. */ | ||
2181 | tegra_dc_trigger_windows(dc); | ||
2182 | |||
2183 | /* Schedule any additional bottom-half vblank actvities. */ | ||
2184 | schedule_work(&dc->vblank_work); | ||
2185 | } | ||
2186 | |||
2187 | if (status & FRAME_END_INT) { | ||
2188 | /* Mark the frame_end as complete. */ | ||
2189 | if (!completion_done(&dc->frame_end_complete)) | ||
2190 | complete(&dc->frame_end_complete); | ||
2191 | } | ||
2192 | } | ||
2193 | |||
2194 | static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status) | ||
2195 | { | ||
2196 | if (status & V_BLANK_INT) { | ||
2197 | /* Schedule any additional bottom-half vblank actvities. */ | ||
2198 | schedule_work(&dc->vblank_work); | ||
2199 | |||
2200 | /* All windows updated. Mask subsequent V_BLANK interrupts */ | ||
2201 | if (!tegra_dc_windows_are_dirty(dc)) { | ||
2202 | u32 val; | ||
2203 | |||
2204 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
2205 | val &= ~V_BLANK_INT; | ||
2206 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
2207 | } | ||
2208 | } | ||
2209 | |||
2210 | if (status & FRAME_END_INT) { | ||
2211 | /* Mark the frame_end as complete. */ | ||
2212 | if (!completion_done(&dc->frame_end_complete)) | ||
2213 | complete(&dc->frame_end_complete); | ||
2214 | |||
2215 | tegra_dc_trigger_windows(dc); | ||
2216 | } | ||
2217 | } | ||
2218 | #endif | ||
2219 | |||
2220 | static irqreturn_t tegra_dc_irq(int irq, void *ptr) | ||
2221 | { | ||
2222 | #ifndef CONFIG_TEGRA_FPGA_PLATFORM | ||
2223 | struct tegra_dc *dc = ptr; | ||
2224 | unsigned long status; | ||
2225 | unsigned long underflow_mask; | ||
2226 | u32 val; | ||
2227 | |||
2228 | if (!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)) { | ||
2229 | WARN(1, "IRQ when DC not powered!\n"); | ||
2230 | tegra_dc_io_start(dc); | ||
2231 | status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); | ||
2232 | tegra_dc_writel(dc, status, DC_CMD_INT_STATUS); | ||
2233 | tegra_dc_io_end(dc); | ||
2234 | return IRQ_HANDLED; | ||
2235 | } | ||
2236 | |||
2237 | /* clear all status flags except underflow, save those for the worker */ | ||
2238 | status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); | ||
2239 | tegra_dc_writel(dc, status & ~ALL_UF_INT, DC_CMD_INT_STATUS); | ||
2240 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
2241 | tegra_dc_writel(dc, val & ~ALL_UF_INT, DC_CMD_INT_MASK); | ||
2242 | |||
2243 | /* | ||
2244 | * Overlays can get thier internal state corrupted during and underflow | ||
2245 | * condition. The only way to fix this state is to reset the DC. | ||
2246 | * if we get 4 consecutive frames with underflows, assume we're | ||
2247 | * hosed and reset. | ||
2248 | */ | ||
2249 | underflow_mask = status & ALL_UF_INT; | ||
2250 | |||
2251 | /* Check underflow */ | ||
2252 | if (underflow_mask) { | ||
2253 | dc->underflow_mask |= underflow_mask; | ||
2254 | schedule_delayed_work(&dc->underflow_work, | ||
2255 | msecs_to_jiffies(1)); | ||
2256 | } | ||
2257 | |||
2258 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
2259 | tegra_dc_one_shot_irq(dc, status); | ||
2260 | else | ||
2261 | tegra_dc_continuous_irq(dc, status); | ||
2262 | |||
2263 | return IRQ_HANDLED; | ||
2264 | #else /* CONFIG_TEGRA_FPGA_PLATFORM */ | ||
2265 | return IRQ_NONE; | ||
2266 | #endif /* !CONFIG_TEGRA_FPGA_PLATFORM */ | ||
2267 | } | ||
2268 | |||
2269 | static void tegra_dc_set_color_control(struct tegra_dc *dc) | ||
2270 | { | ||
2271 | u32 color_control; | ||
2272 | |||
2273 | switch (dc->out->depth) { | ||
2274 | case 3: | ||
2275 | color_control = BASE_COLOR_SIZE111; | ||
2276 | break; | ||
2277 | |||
2278 | case 6: | ||
2279 | color_control = BASE_COLOR_SIZE222; | ||
2280 | break; | ||
2281 | |||
2282 | case 8: | ||
2283 | color_control = BASE_COLOR_SIZE332; | ||
2284 | break; | ||
2285 | |||
2286 | case 9: | ||
2287 | color_control = BASE_COLOR_SIZE333; | ||
2288 | break; | ||
2289 | |||
2290 | case 12: | ||
2291 | color_control = BASE_COLOR_SIZE444; | ||
2292 | break; | ||
2293 | |||
2294 | case 15: | ||
2295 | color_control = BASE_COLOR_SIZE555; | ||
2296 | break; | ||
2297 | |||
2298 | case 16: | ||
2299 | color_control = BASE_COLOR_SIZE565; | ||
2300 | break; | ||
2301 | |||
2302 | case 18: | ||
2303 | color_control = BASE_COLOR_SIZE666; | ||
2304 | break; | ||
2305 | |||
2306 | default: | ||
2307 | color_control = BASE_COLOR_SIZE888; | ||
2308 | break; | ||
2309 | } | ||
2310 | |||
2311 | switch (dc->out->dither) { | ||
2312 | case TEGRA_DC_DISABLE_DITHER: | ||
2313 | color_control |= DITHER_CONTROL_DISABLE; | ||
2314 | break; | ||
2315 | case TEGRA_DC_ORDERED_DITHER: | ||
2316 | color_control |= DITHER_CONTROL_ORDERED; | ||
2317 | break; | ||
2318 | case TEGRA_DC_ERRDIFF_DITHER: | ||
2319 | /* The line buffer for error-diffusion dither is limited | ||
2320 | * to 1280 pixels per line. This limits the maximum | ||
2321 | * horizontal active area size to 1280 pixels when error | ||
2322 | * diffusion is enabled. | ||
2323 | */ | ||
2324 | BUG_ON(dc->mode.h_active > 1280); | ||
2325 | color_control |= DITHER_CONTROL_ERRDIFF; | ||
2326 | break; | ||
2327 | } | ||
2328 | |||
2329 | tegra_dc_writel(dc, color_control, DC_DISP_DISP_COLOR_CONTROL); | ||
2330 | } | ||
2331 | |||
2332 | static u32 get_syncpt(struct tegra_dc *dc, int idx) | ||
2333 | { | ||
2334 | u32 syncpt_id; | ||
2335 | |||
2336 | switch (dc->ndev->id) { | ||
2337 | case 0: | ||
2338 | switch (idx) { | ||
2339 | case 0: | ||
2340 | syncpt_id = NVSYNCPT_DISP0_A; | ||
2341 | break; | ||
2342 | case 1: | ||
2343 | syncpt_id = NVSYNCPT_DISP0_B; | ||
2344 | break; | ||
2345 | case 2: | ||
2346 | syncpt_id = NVSYNCPT_DISP0_C; | ||
2347 | break; | ||
2348 | default: | ||
2349 | BUG(); | ||
2350 | break; | ||
2351 | } | ||
2352 | break; | ||
2353 | case 1: | ||
2354 | switch (idx) { | ||
2355 | case 0: | ||
2356 | syncpt_id = NVSYNCPT_DISP1_A; | ||
2357 | break; | ||
2358 | case 1: | ||
2359 | syncpt_id = NVSYNCPT_DISP1_B; | ||
2360 | break; | ||
2361 | case 2: | ||
2362 | syncpt_id = NVSYNCPT_DISP1_C; | ||
2363 | break; | ||
2364 | default: | ||
2365 | BUG(); | ||
2366 | break; | ||
2367 | } | ||
2368 | break; | ||
2369 | default: | ||
2370 | BUG(); | ||
2371 | break; | ||
2372 | } | ||
2373 | |||
2374 | return syncpt_id; | ||
2375 | } | ||
2376 | |||
2377 | static int tegra_dc_init(struct tegra_dc *dc) | ||
2378 | { | ||
2379 | int i; | ||
2380 | |||
2381 | tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
2382 | if (dc->ndev->id == 0) { | ||
2383 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0A, | ||
2384 | TEGRA_MC_PRIO_MED); | ||
2385 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0B, | ||
2386 | TEGRA_MC_PRIO_MED); | ||
2387 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0C, | ||
2388 | TEGRA_MC_PRIO_MED); | ||
2389 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY1B, | ||
2390 | TEGRA_MC_PRIO_MED); | ||
2391 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAYHC, | ||
2392 | TEGRA_MC_PRIO_HIGH); | ||
2393 | } else if (dc->ndev->id == 1) { | ||
2394 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0AB, | ||
2395 | TEGRA_MC_PRIO_MED); | ||
2396 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0BB, | ||
2397 | TEGRA_MC_PRIO_MED); | ||
2398 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0CB, | ||
2399 | TEGRA_MC_PRIO_MED); | ||
2400 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY1BB, | ||
2401 | TEGRA_MC_PRIO_MED); | ||
2402 | tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAYHCB, | ||
2403 | TEGRA_MC_PRIO_HIGH); | ||
2404 | } | ||
2405 | tegra_dc_writel(dc, 0x00000100 | dc->vblank_syncpt, | ||
2406 | DC_CMD_CONT_SYNCPT_VSYNC); | ||
2407 | tegra_dc_writel(dc, 0x00004700, DC_CMD_INT_TYPE); | ||
2408 | tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY); | ||
2409 | tegra_dc_writel(dc, 0x00202020, DC_DISP_MEM_HIGH_PRIORITY); | ||
2410 | tegra_dc_writel(dc, 0x00010101, DC_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
2411 | |||
2412 | /* enable interrupts for vblank, frame_end and underflows */ | ||
2413 | tegra_dc_writel(dc, (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT), | ||
2414 | DC_CMD_INT_ENABLE); | ||
2415 | tegra_dc_writel(dc, ALL_UF_INT, DC_CMD_INT_MASK); | ||
2416 | |||
2417 | tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR); | ||
2418 | |||
2419 | tegra_dc_set_color_control(dc); | ||
2420 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
2421 | struct tegra_dc_win *win = &dc->windows[i]; | ||
2422 | tegra_dc_writel(dc, WINDOW_A_SELECT << i, | ||
2423 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
2424 | tegra_dc_set_csc(dc, &win->csc); | ||
2425 | tegra_dc_set_lut(dc, win); | ||
2426 | tegra_dc_set_scaling_filter(dc); | ||
2427 | } | ||
2428 | |||
2429 | |||
2430 | for (i = 0; i < dc->n_windows; i++) { | ||
2431 | u32 syncpt = get_syncpt(dc, i); | ||
2432 | |||
2433 | dc->syncpt[i].id = syncpt; | ||
2434 | |||
2435 | dc->syncpt[i].min = dc->syncpt[i].max = | ||
2436 | nvhost_syncpt_read(&nvhost_get_host(dc->ndev)->syncpt, | ||
2437 | syncpt); | ||
2438 | } | ||
2439 | |||
2440 | print_mode(dc, &dc->mode, __func__); | ||
2441 | |||
2442 | if (dc->mode.pclk) | ||
2443 | if (tegra_dc_program_mode(dc, &dc->mode)) | ||
2444 | return -EINVAL; | ||
2445 | |||
2446 | /* Initialize SD AFTER the modeset. | ||
2447 | nvsd_init handles the sd_settings = NULL case. */ | ||
2448 | nvsd_init(dc, dc->out->sd_settings); | ||
2449 | |||
2450 | return 0; | ||
2451 | } | ||
2452 | |||
2453 | static bool _tegra_dc_controller_enable(struct tegra_dc *dc) | ||
2454 | { | ||
2455 | int failed_init = 0; | ||
2456 | |||
2457 | if (dc->out->enable) | ||
2458 | dc->out->enable(); | ||
2459 | |||
2460 | tegra_dc_setup_clk(dc, dc->clk); | ||
2461 | clk_enable(dc->clk); | ||
2462 | |||
2463 | /* do not accept interrupts during initialization */ | ||
2464 | tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE); | ||
2465 | tegra_dc_writel(dc, 0, DC_CMD_INT_MASK); | ||
2466 | |||
2467 | enable_dc_irq(dc->irq); | ||
2468 | |||
2469 | failed_init = tegra_dc_init(dc); | ||
2470 | if (failed_init) { | ||
2471 | _tegra_dc_controller_disable(dc); | ||
2472 | return false; | ||
2473 | } | ||
2474 | |||
2475 | if (dc->out_ops && dc->out_ops->enable) | ||
2476 | dc->out_ops->enable(dc); | ||
2477 | |||
2478 | if (dc->out->postpoweron) | ||
2479 | dc->out->postpoweron(); | ||
2480 | |||
2481 | /* force a full blending update */ | ||
2482 | dc->blend.z[0] = -1; | ||
2483 | |||
2484 | tegra_dc_ext_enable(dc->ext); | ||
2485 | |||
2486 | return true; | ||
2487 | } | ||
2488 | |||
2489 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
2490 | static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc) | ||
2491 | { | ||
2492 | bool ret = true; | ||
2493 | |||
2494 | if (dc->out->enable) | ||
2495 | dc->out->enable(); | ||
2496 | |||
2497 | tegra_dc_setup_clk(dc, dc->clk); | ||
2498 | clk_enable(dc->clk); | ||
2499 | |||
2500 | if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) { | ||
2501 | mutex_lock(&tegra_dcs[1]->lock); | ||
2502 | disable_irq(tegra_dcs[1]->irq); | ||
2503 | } else if (dc->ndev->id == 1 && tegra_dcs[0] != NULL) { | ||
2504 | mutex_lock(&tegra_dcs[0]->lock); | ||
2505 | disable_irq(tegra_dcs[0]->irq); | ||
2506 | } | ||
2507 | |||
2508 | msleep(5); | ||
2509 | tegra_periph_reset_assert(dc->clk); | ||
2510 | msleep(2); | ||
2511 | #ifdef CONFIG_TEGRA_SILICON_PLATFORM | ||
2512 | tegra_periph_reset_deassert(dc->clk); | ||
2513 | msleep(1); | ||
2514 | #endif | ||
2515 | |||
2516 | if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) { | ||
2517 | enable_dc_irq(tegra_dcs[1]->irq); | ||
2518 | mutex_unlock(&tegra_dcs[1]->lock); | ||
2519 | } else if (dc->ndev->id == 1 && tegra_dcs[0] != NULL) { | ||
2520 | enable_dc_irq(tegra_dcs[0]->irq); | ||
2521 | mutex_unlock(&tegra_dcs[0]->lock); | ||
2522 | } | ||
2523 | |||
2524 | enable_dc_irq(dc->irq); | ||
2525 | |||
2526 | if (tegra_dc_init(dc)) { | ||
2527 | dev_err(&dc->ndev->dev, "cannot initialize\n"); | ||
2528 | ret = false; | ||
2529 | } | ||
2530 | |||
2531 | if (dc->out_ops && dc->out_ops->enable) | ||
2532 | dc->out_ops->enable(dc); | ||
2533 | |||
2534 | if (dc->out->postpoweron) | ||
2535 | dc->out->postpoweron(); | ||
2536 | |||
2537 | /* force a full blending update */ | ||
2538 | dc->blend.z[0] = -1; | ||
2539 | |||
2540 | tegra_dc_ext_enable(dc->ext); | ||
2541 | |||
2542 | if (!ret) { | ||
2543 | dev_err(&dc->ndev->dev, "initialization failed,disabling"); | ||
2544 | _tegra_dc_controller_disable(dc); | ||
2545 | } | ||
2546 | |||
2547 | return ret; | ||
2548 | } | ||
2549 | #endif | ||
2550 | |||
2551 | static bool _tegra_dc_enable(struct tegra_dc *dc) | ||
2552 | { | ||
2553 | if (dc->mode.pclk == 0) | ||
2554 | return false; | ||
2555 | |||
2556 | if (!dc->out) | ||
2557 | return false; | ||
2558 | |||
2559 | tegra_dc_io_start(dc); | ||
2560 | |||
2561 | return _tegra_dc_controller_enable(dc); | ||
2562 | } | ||
2563 | |||
2564 | void tegra_dc_enable(struct tegra_dc *dc) | ||
2565 | { | ||
2566 | mutex_lock(&dc->lock); | ||
2567 | |||
2568 | if (!dc->enabled) | ||
2569 | dc->enabled = _tegra_dc_enable(dc); | ||
2570 | |||
2571 | mutex_unlock(&dc->lock); | ||
2572 | } | ||
2573 | |||
2574 | static void _tegra_dc_controller_disable(struct tegra_dc *dc) | ||
2575 | { | ||
2576 | unsigned i; | ||
2577 | |||
2578 | if (dc->out_ops && dc->out_ops->disable) | ||
2579 | dc->out_ops->disable(dc); | ||
2580 | |||
2581 | tegra_dc_writel(dc, 0, DC_CMD_INT_MASK); | ||
2582 | tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE); | ||
2583 | disable_irq(dc->irq); | ||
2584 | |||
2585 | tegra_dc_clear_bandwidth(dc); | ||
2586 | clk_disable(dc->clk); | ||
2587 | tegra_dvfs_set_rate(dc->clk, 0); | ||
2588 | |||
2589 | if (dc->out && dc->out->disable) | ||
2590 | dc->out->disable(); | ||
2591 | |||
2592 | for (i = 0; i < dc->n_windows; i++) { | ||
2593 | struct tegra_dc_win *w = &dc->windows[i]; | ||
2594 | |||
2595 | /* reset window bandwidth */ | ||
2596 | w->bandwidth = 0; | ||
2597 | w->new_bandwidth = 0; | ||
2598 | |||
2599 | /* disable windows */ | ||
2600 | w->flags &= ~TEGRA_WIN_FLAG_ENABLED; | ||
2601 | |||
2602 | /* flush any pending syncpt waits */ | ||
2603 | while (dc->syncpt[i].min < dc->syncpt[i].max) { | ||
2604 | dc->syncpt[i].min++; | ||
2605 | nvhost_syncpt_cpu_incr( | ||
2606 | &nvhost_get_host(dc->ndev)->syncpt, | ||
2607 | dc->syncpt[i].id); | ||
2608 | } | ||
2609 | } | ||
2610 | } | ||
2611 | |||
2612 | void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable) | ||
2613 | { | ||
2614 | #if 0 /* underflow interrupt is already enabled by dc reset worker */ | ||
2615 | u32 val; | ||
2616 | if (dc->enabled) { | ||
2617 | val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE); | ||
2618 | if (enable) | ||
2619 | val |= (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT); | ||
2620 | else | ||
2621 | val &= ~(WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT); | ||
2622 | tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE); | ||
2623 | } | ||
2624 | #endif | ||
2625 | } | ||
2626 | |||
2627 | bool tegra_dc_stats_get(struct tegra_dc *dc) | ||
2628 | { | ||
2629 | #if 0 /* right now it is always enabled */ | ||
2630 | u32 val; | ||
2631 | bool res; | ||
2632 | |||
2633 | if (dc->enabled) { | ||
2634 | val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE); | ||
2635 | res = !!(val & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)); | ||
2636 | } else { | ||
2637 | res = false; | ||
2638 | } | ||
2639 | |||
2640 | return res; | ||
2641 | #endif | ||
2642 | return true; | ||
2643 | } | ||
2644 | |||
2645 | /* make the screen blank by disabling all windows */ | ||
2646 | void tegra_dc_blank(struct tegra_dc *dc) | ||
2647 | { | ||
2648 | struct tegra_dc_win *dcwins[DC_N_WINDOWS]; | ||
2649 | unsigned i; | ||
2650 | |||
2651 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
2652 | dcwins[i] = tegra_dc_get_window(dc, i); | ||
2653 | dcwins[i]->flags &= ~TEGRA_WIN_FLAG_ENABLED; | ||
2654 | } | ||
2655 | |||
2656 | tegra_dc_update_windows(dcwins, DC_N_WINDOWS); | ||
2657 | tegra_dc_sync_windows(dcwins, DC_N_WINDOWS); | ||
2658 | } | ||
2659 | |||
2660 | static void _tegra_dc_disable(struct tegra_dc *dc) | ||
2661 | { | ||
2662 | _tegra_dc_controller_disable(dc); | ||
2663 | tegra_dc_io_end(dc); | ||
2664 | } | ||
2665 | |||
2666 | void tegra_dc_disable(struct tegra_dc *dc) | ||
2667 | { | ||
2668 | tegra_dc_ext_disable(dc->ext); | ||
2669 | |||
2670 | /* it's important that new underflow work isn't scheduled before the | ||
2671 | * lock is acquired. */ | ||
2672 | cancel_delayed_work_sync(&dc->underflow_work); | ||
2673 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { | ||
2674 | mutex_lock(&dc->one_shot_lock); | ||
2675 | cancel_delayed_work_sync(&dc->one_shot_work); | ||
2676 | } | ||
2677 | |||
2678 | mutex_lock(&dc->lock); | ||
2679 | |||
2680 | if (dc->enabled) { | ||
2681 | dc->enabled = false; | ||
2682 | |||
2683 | if (!dc->suspended) | ||
2684 | _tegra_dc_disable(dc); | ||
2685 | } | ||
2686 | |||
2687 | #ifdef CONFIG_SWITCH | ||
2688 | switch_set_state(&dc->modeset_switch, 0); | ||
2689 | #endif | ||
2690 | |||
2691 | mutex_unlock(&dc->lock); | ||
2692 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) | ||
2693 | mutex_unlock(&dc->one_shot_lock); | ||
2694 | } | ||
2695 | |||
2696 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
2697 | static void tegra_dc_reset_worker(struct work_struct *work) | ||
2698 | { | ||
2699 | struct tegra_dc *dc = | ||
2700 | container_of(work, struct tegra_dc, reset_work); | ||
2701 | |||
2702 | unsigned long val = 0; | ||
2703 | |||
2704 | mutex_lock(&shared_lock); | ||
2705 | |||
2706 | dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n"); | ||
2707 | |||
2708 | tegra_dc_ext_disable(dc->ext); | ||
2709 | |||
2710 | mutex_lock(&dc->lock); | ||
2711 | |||
2712 | if (dc->enabled == false) | ||
2713 | goto unlock; | ||
2714 | |||
2715 | dc->enabled = false; | ||
2716 | |||
2717 | /* | ||
2718 | * off host read bus | ||
2719 | */ | ||
2720 | val = tegra_dc_readl(dc, DC_CMD_CONT_SYNCPT_VSYNC); | ||
2721 | val &= ~(0x00000100); | ||
2722 | tegra_dc_writel(dc, val, DC_CMD_CONT_SYNCPT_VSYNC); | ||
2723 | |||
2724 | /* | ||
2725 | * set DC to STOP mode | ||
2726 | */ | ||
2727 | tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); | ||
2728 | |||
2729 | msleep(10); | ||
2730 | |||
2731 | _tegra_dc_controller_disable(dc); | ||
2732 | |||
2733 | /* _tegra_dc_controller_reset_enable deasserts reset */ | ||
2734 | _tegra_dc_controller_reset_enable(dc); | ||
2735 | |||
2736 | dc->enabled = true; | ||
2737 | unlock: | ||
2738 | mutex_unlock(&dc->lock); | ||
2739 | mutex_unlock(&shared_lock); | ||
2740 | } | ||
2741 | #endif | ||
2742 | |||
2743 | static void tegra_dc_underflow_worker(struct work_struct *work) | ||
2744 | { | ||
2745 | struct tegra_dc *dc = container_of( | ||
2746 | to_delayed_work(work), struct tegra_dc, underflow_work); | ||
2747 | |||
2748 | mutex_lock(&dc->lock); | ||
2749 | if (dc->enabled) { | ||
2750 | tegra_dc_underflow_handler(dc); | ||
2751 | } | ||
2752 | mutex_unlock(&dc->lock); | ||
2753 | } | ||
2754 | |||
2755 | #ifdef CONFIG_SWITCH | ||
2756 | static ssize_t switch_modeset_print_mode(struct switch_dev *sdev, char *buf) | ||
2757 | { | ||
2758 | struct tegra_dc *dc = | ||
2759 | container_of(sdev, struct tegra_dc, modeset_switch); | ||
2760 | |||
2761 | if (!sdev->state) | ||
2762 | return sprintf(buf, "offline\n"); | ||
2763 | |||
2764 | return sprintf(buf, "%dx%d\n", dc->mode.h_active, dc->mode.v_active); | ||
2765 | } | ||
2766 | #endif | ||
2767 | |||
2768 | static int tegra_dc_probe(struct nvhost_device *ndev) | ||
2769 | { | ||
2770 | struct tegra_dc *dc; | ||
2771 | struct clk *clk; | ||
2772 | struct clk *emc_clk; | ||
2773 | struct resource *res; | ||
2774 | struct resource *base_res; | ||
2775 | struct resource *fb_mem = NULL; | ||
2776 | int ret = 0; | ||
2777 | void __iomem *base; | ||
2778 | int irq; | ||
2779 | int i; | ||
2780 | |||
2781 | if (!ndev->dev.platform_data) { | ||
2782 | dev_err(&ndev->dev, "no platform data\n"); | ||
2783 | return -ENOENT; | ||
2784 | } | ||
2785 | |||
2786 | dc = kzalloc(sizeof(struct tegra_dc), GFP_KERNEL); | ||
2787 | if (!dc) { | ||
2788 | dev_err(&ndev->dev, "can't allocate memory for tegra_dc\n"); | ||
2789 | return -ENOMEM; | ||
2790 | } | ||
2791 | |||
2792 | irq = nvhost_get_irq_byname(ndev, "irq"); | ||
2793 | if (irq <= 0) { | ||
2794 | dev_err(&ndev->dev, "no irq\n"); | ||
2795 | ret = -ENOENT; | ||
2796 | goto err_free; | ||
2797 | } | ||
2798 | |||
2799 | res = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "regs"); | ||
2800 | if (!res) { | ||
2801 | dev_err(&ndev->dev, "no mem resource\n"); | ||
2802 | ret = -ENOENT; | ||
2803 | goto err_free; | ||
2804 | } | ||
2805 | |||
2806 | base_res = request_mem_region(res->start, resource_size(res), ndev->name); | ||
2807 | if (!base_res) { | ||
2808 | dev_err(&ndev->dev, "request_mem_region failed\n"); | ||
2809 | ret = -EBUSY; | ||
2810 | goto err_free; | ||
2811 | } | ||
2812 | |||
2813 | base = ioremap(res->start, resource_size(res)); | ||
2814 | if (!base) { | ||
2815 | dev_err(&ndev->dev, "registers can't be mapped\n"); | ||
2816 | ret = -EBUSY; | ||
2817 | goto err_release_resource_reg; | ||
2818 | } | ||
2819 | |||
2820 | fb_mem = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "fbmem"); | ||
2821 | |||
2822 | clk = clk_get(&ndev->dev, NULL); | ||
2823 | if (IS_ERR_OR_NULL(clk)) { | ||
2824 | dev_err(&ndev->dev, "can't get clock\n"); | ||
2825 | ret = -ENOENT; | ||
2826 | goto err_iounmap_reg; | ||
2827 | } | ||
2828 | |||
2829 | emc_clk = clk_get(&ndev->dev, "emc"); | ||
2830 | if (IS_ERR_OR_NULL(emc_clk)) { | ||
2831 | dev_err(&ndev->dev, "can't get emc clock\n"); | ||
2832 | ret = -ENOENT; | ||
2833 | goto err_put_clk; | ||
2834 | } | ||
2835 | |||
2836 | dc->clk = clk; | ||
2837 | dc->emc_clk = emc_clk; | ||
2838 | dc->shift_clk_div = 1; | ||
2839 | /* Initialize one shot work delay, it will be assigned by dsi | ||
2840 | * according to refresh rate later. */ | ||
2841 | dc->one_shot_delay_ms = 40; | ||
2842 | |||
2843 | dc->base_res = base_res; | ||
2844 | dc->base = base; | ||
2845 | dc->irq = irq; | ||
2846 | dc->ndev = ndev; | ||
2847 | dc->pdata = ndev->dev.platform_data; | ||
2848 | |||
2849 | /* | ||
2850 | * The emc is a shared clock, it will be set based on | ||
2851 | * the requirements for each user on the bus. | ||
2852 | */ | ||
2853 | dc->emc_clk_rate = 0; | ||
2854 | |||
2855 | if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) | ||
2856 | dc->enabled = true; | ||
2857 | |||
2858 | mutex_init(&dc->lock); | ||
2859 | mutex_init(&dc->one_shot_lock); | ||
2860 | init_completion(&dc->frame_end_complete); | ||
2861 | init_waitqueue_head(&dc->wq); | ||
2862 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
2863 | INIT_WORK(&dc->reset_work, tegra_dc_reset_worker); | ||
2864 | #endif | ||
2865 | INIT_WORK(&dc->vblank_work, tegra_dc_vblank); | ||
2866 | INIT_DELAYED_WORK(&dc->underflow_work, tegra_dc_underflow_worker); | ||
2867 | INIT_DELAYED_WORK(&dc->one_shot_work, tegra_dc_one_shot_worker); | ||
2868 | |||
2869 | tegra_dc_init_lut_defaults(&dc->fb_lut); | ||
2870 | |||
2871 | dc->n_windows = DC_N_WINDOWS; | ||
2872 | for (i = 0; i < dc->n_windows; i++) { | ||
2873 | struct tegra_dc_win *win = &dc->windows[i]; | ||
2874 | win->idx = i; | ||
2875 | win->dc = dc; | ||
2876 | tegra_dc_init_csc_defaults(&win->csc); | ||
2877 | tegra_dc_init_lut_defaults(&win->lut); | ||
2878 | } | ||
2879 | |||
2880 | ret = tegra_dc_set(dc, ndev->id); | ||
2881 | if (ret < 0) { | ||
2882 | dev_err(&ndev->dev, "can't add dc\n"); | ||
2883 | goto err_free_irq; | ||
2884 | } | ||
2885 | |||
2886 | nvhost_set_drvdata(ndev, dc); | ||
2887 | |||
2888 | #ifdef CONFIG_SWITCH | ||
2889 | dc->modeset_switch.name = dev_name(&ndev->dev); | ||
2890 | dc->modeset_switch.state = 0; | ||
2891 | dc->modeset_switch.print_state = switch_modeset_print_mode; | ||
2892 | switch_dev_register(&dc->modeset_switch); | ||
2893 | #endif | ||
2894 | |||
2895 | if (dc->pdata->default_out) | ||
2896 | tegra_dc_set_out(dc, dc->pdata->default_out); | ||
2897 | else | ||
2898 | dev_err(&ndev->dev, "No default output specified. Leaving output disabled.\n"); | ||
2899 | |||
2900 | dc->vblank_syncpt = (dc->ndev->id == 0) ? | ||
2901 | NVSYNCPT_VBLANK0 : NVSYNCPT_VBLANK1; | ||
2902 | |||
2903 | dc->ext = tegra_dc_ext_register(ndev, dc); | ||
2904 | if (IS_ERR_OR_NULL(dc->ext)) { | ||
2905 | dev_warn(&ndev->dev, "Failed to enable Tegra DC extensions.\n"); | ||
2906 | dc->ext = NULL; | ||
2907 | } | ||
2908 | |||
2909 | /* interrupt handler must be registered before tegra_fb_register() */ | ||
2910 | if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED, | ||
2911 | dev_name(&ndev->dev), dc)) { | ||
2912 | dev_err(&ndev->dev, "request_irq %d failed\n", irq); | ||
2913 | ret = -EBUSY; | ||
2914 | goto err_put_emc_clk; | ||
2915 | } | ||
2916 | |||
2917 | /* hack to balance enable_irq calls in _tegra_dc_enable() */ | ||
2918 | disable_dc_irq(dc->irq); | ||
2919 | |||
2920 | mutex_lock(&dc->lock); | ||
2921 | if (dc->enabled) | ||
2922 | _tegra_dc_enable(dc); | ||
2923 | mutex_unlock(&dc->lock); | ||
2924 | |||
2925 | tegra_dc_create_debugfs(dc); | ||
2926 | |||
2927 | dev_info(&ndev->dev, "probed\n"); | ||
2928 | |||
2929 | if (dc->pdata->fb) { | ||
2930 | if (dc->pdata->fb->bits_per_pixel == -1) { | ||
2931 | unsigned long fmt; | ||
2932 | tegra_dc_writel(dc, | ||
2933 | WINDOW_A_SELECT << dc->pdata->fb->win, | ||
2934 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
2935 | |||
2936 | fmt = tegra_dc_readl(dc, DC_WIN_COLOR_DEPTH); | ||
2937 | dc->pdata->fb->bits_per_pixel = | ||
2938 | tegra_dc_fmt_bpp(fmt); | ||
2939 | } | ||
2940 | |||
2941 | dc->fb = tegra_fb_register(ndev, dc, dc->pdata->fb, fb_mem); | ||
2942 | if (IS_ERR_OR_NULL(dc->fb)) | ||
2943 | dc->fb = NULL; | ||
2944 | } | ||
2945 | |||
2946 | if (dc->out && dc->out->hotplug_init) | ||
2947 | dc->out->hotplug_init(); | ||
2948 | |||
2949 | if (dc->out_ops && dc->out_ops->detect) | ||
2950 | dc->out_ops->detect(dc); | ||
2951 | else | ||
2952 | dc->connected = true; | ||
2953 | |||
2954 | tegra_dc_create_sysfs(&dc->ndev->dev); | ||
2955 | |||
2956 | return 0; | ||
2957 | |||
2958 | err_free_irq: | ||
2959 | free_irq(irq, dc); | ||
2960 | err_put_emc_clk: | ||
2961 | clk_put(emc_clk); | ||
2962 | err_put_clk: | ||
2963 | clk_put(clk); | ||
2964 | err_iounmap_reg: | ||
2965 | iounmap(base); | ||
2966 | if (fb_mem) | ||
2967 | release_resource(fb_mem); | ||
2968 | err_release_resource_reg: | ||
2969 | release_resource(base_res); | ||
2970 | err_free: | ||
2971 | kfree(dc); | ||
2972 | |||
2973 | return ret; | ||
2974 | } | ||
2975 | |||
2976 | static int tegra_dc_remove(struct nvhost_device *ndev) | ||
2977 | { | ||
2978 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
2979 | |||
2980 | tegra_dc_remove_sysfs(&dc->ndev->dev); | ||
2981 | tegra_dc_remove_debugfs(dc); | ||
2982 | |||
2983 | if (dc->fb) { | ||
2984 | tegra_fb_unregister(dc->fb); | ||
2985 | if (dc->fb_mem) | ||
2986 | release_resource(dc->fb_mem); | ||
2987 | } | ||
2988 | |||
2989 | tegra_dc_ext_disable(dc->ext); | ||
2990 | |||
2991 | if (dc->ext) | ||
2992 | tegra_dc_ext_unregister(dc->ext); | ||
2993 | |||
2994 | if (dc->enabled) | ||
2995 | _tegra_dc_disable(dc); | ||
2996 | |||
2997 | #ifdef CONFIG_SWITCH | ||
2998 | switch_dev_unregister(&dc->modeset_switch); | ||
2999 | #endif | ||
3000 | free_irq(dc->irq, dc); | ||
3001 | clk_put(dc->emc_clk); | ||
3002 | clk_put(dc->clk); | ||
3003 | iounmap(dc->base); | ||
3004 | if (dc->fb_mem) | ||
3005 | release_resource(dc->base_res); | ||
3006 | kfree(dc); | ||
3007 | tegra_dc_set(NULL, ndev->id); | ||
3008 | return 0; | ||
3009 | } | ||
3010 | |||
3011 | #ifdef CONFIG_PM | ||
3012 | static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state) | ||
3013 | { | ||
3014 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
3015 | |||
3016 | dev_info(&ndev->dev, "suspend\n"); | ||
3017 | |||
3018 | tegra_dc_ext_disable(dc->ext); | ||
3019 | |||
3020 | mutex_lock(&dc->lock); | ||
3021 | |||
3022 | if (dc->out_ops && dc->out_ops->suspend) | ||
3023 | dc->out_ops->suspend(dc); | ||
3024 | |||
3025 | if (dc->enabled) { | ||
3026 | _tegra_dc_disable(dc); | ||
3027 | |||
3028 | dc->suspended = true; | ||
3029 | } | ||
3030 | |||
3031 | if (dc->out && dc->out->postsuspend) { | ||
3032 | dc->out->postsuspend(); | ||
3033 | if (dc->out->type && dc->out->type == TEGRA_DC_OUT_HDMI) | ||
3034 | /* | ||
3035 | * avoid resume event due to voltage falling | ||
3036 | */ | ||
3037 | msleep(100); | ||
3038 | } | ||
3039 | |||
3040 | mutex_unlock(&dc->lock); | ||
3041 | |||
3042 | return 0; | ||
3043 | } | ||
3044 | |||
3045 | static int tegra_dc_resume(struct nvhost_device *ndev) | ||
3046 | { | ||
3047 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
3048 | |||
3049 | dev_info(&ndev->dev, "resume\n"); | ||
3050 | |||
3051 | mutex_lock(&dc->lock); | ||
3052 | dc->suspended = false; | ||
3053 | |||
3054 | if (dc->enabled) | ||
3055 | _tegra_dc_enable(dc); | ||
3056 | |||
3057 | if (dc->out && dc->out->hotplug_init) | ||
3058 | dc->out->hotplug_init(); | ||
3059 | |||
3060 | if (dc->out_ops && dc->out_ops->resume) | ||
3061 | dc->out_ops->resume(dc); | ||
3062 | mutex_unlock(&dc->lock); | ||
3063 | |||
3064 | return 0; | ||
3065 | } | ||
3066 | |||
3067 | #endif /* CONFIG_PM */ | ||
3068 | |||
3069 | extern int suspend_set(const char *val, struct kernel_param *kp) | ||
3070 | { | ||
3071 | if (!strcmp(val, "dump")) | ||
3072 | dump_regs(tegra_dcs[0]); | ||
3073 | #ifdef CONFIG_PM | ||
3074 | else if (!strcmp(val, "suspend")) | ||
3075 | tegra_dc_suspend(tegra_dcs[0]->ndev, PMSG_SUSPEND); | ||
3076 | else if (!strcmp(val, "resume")) | ||
3077 | tegra_dc_resume(tegra_dcs[0]->ndev); | ||
3078 | #endif | ||
3079 | |||
3080 | return 0; | ||
3081 | } | ||
3082 | |||
3083 | extern int suspend_get(char *buffer, struct kernel_param *kp) | ||
3084 | { | ||
3085 | return 0; | ||
3086 | } | ||
3087 | |||
3088 | int suspend; | ||
3089 | |||
3090 | module_param_call(suspend, suspend_set, suspend_get, &suspend, 0644); | ||
3091 | |||
3092 | struct nvhost_driver tegra_dc_driver = { | ||
3093 | .driver = { | ||
3094 | .name = "tegradc", | ||
3095 | .owner = THIS_MODULE, | ||
3096 | }, | ||
3097 | .probe = tegra_dc_probe, | ||
3098 | .remove = tegra_dc_remove, | ||
3099 | #ifdef CONFIG_PM | ||
3100 | .suspend = tegra_dc_suspend, | ||
3101 | .resume = tegra_dc_resume, | ||
3102 | #endif | ||
3103 | }; | ||
3104 | |||
3105 | static int __init tegra_dc_module_init(void) | ||
3106 | { | ||
3107 | int ret = tegra_dc_ext_module_init(); | ||
3108 | if (ret) | ||
3109 | return ret; | ||
3110 | return nvhost_driver_register(&tegra_dc_driver); | ||
3111 | } | ||
3112 | |||
3113 | static void __exit tegra_dc_module_exit(void) | ||
3114 | { | ||
3115 | nvhost_driver_unregister(&tegra_dc_driver); | ||
3116 | tegra_dc_ext_module_exit(); | ||
3117 | } | ||
3118 | |||
3119 | module_exit(tegra_dc_module_exit); | ||
3120 | module_init(tegra_dc_module_init); | ||
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h new file mode 100644 index 00000000000..a10e648debc --- /dev/null +++ b/drivers/video/tegra/dc/dc_priv.h | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dc_priv.h | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H | ||
19 | #define __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H | ||
20 | |||
21 | #include <linux/io.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <linux/completion.h> | ||
25 | #include <linux/switch.h> | ||
26 | |||
27 | #include <mach/dc.h> | ||
28 | |||
29 | #include "../host/dev.h" | ||
30 | #include "../host/host1x/host1x_syncpt.h" | ||
31 | |||
32 | #include <mach/tegra_dc_ext.h> | ||
33 | |||
34 | #define WIN_IS_TILED(win) ((win)->flags & TEGRA_WIN_FLAG_TILED) | ||
35 | #define WIN_IS_ENABLED(win) ((win)->flags & TEGRA_WIN_FLAG_ENABLED) | ||
36 | |||
37 | #define NEED_UPDATE_EMC_ON_EVERY_FRAME (windows_idle_detection_time == 0) | ||
38 | |||
39 | /* DDR: 8 bytes transfer per clock */ | ||
40 | #define DDR_BW_TO_FREQ(bw) ((bw) / 8) | ||
41 | |||
42 | #if defined(CONFIG_TEGRA_EMC_TO_DDR_CLOCK) | ||
43 | #define EMC_BW_TO_FREQ(bw) (DDR_BW_TO_FREQ(bw) * CONFIG_TEGRA_EMC_TO_DDR_CLOCK) | ||
44 | #else | ||
45 | #define EMC_BW_TO_FREQ(bw) (DDR_BW_TO_FREQ(bw) * 2) | ||
46 | #endif | ||
47 | |||
48 | struct tegra_dc; | ||
49 | |||
50 | struct tegra_dc_blend { | ||
51 | unsigned z[DC_N_WINDOWS]; | ||
52 | unsigned flags[DC_N_WINDOWS]; | ||
53 | }; | ||
54 | |||
55 | struct tegra_dc_out_ops { | ||
56 | /* initialize output. dc clocks are not on at this point */ | ||
57 | int (*init)(struct tegra_dc *dc); | ||
58 | /* destroy output. dc clocks are not on at this point */ | ||
59 | void (*destroy)(struct tegra_dc *dc); | ||
60 | /* detect connected display. can sleep.*/ | ||
61 | bool (*detect)(struct tegra_dc *dc); | ||
62 | /* enable output. dc clocks are on at this point */ | ||
63 | void (*enable)(struct tegra_dc *dc); | ||
64 | /* disable output. dc clocks are on at this point */ | ||
65 | void (*disable)(struct tegra_dc *dc); | ||
66 | |||
67 | /* suspend output. dc clocks are on at this point */ | ||
68 | void (*suspend)(struct tegra_dc *dc); | ||
69 | /* resume output. dc clocks are on at this point */ | ||
70 | void (*resume)(struct tegra_dc *dc); | ||
71 | }; | ||
72 | |||
73 | struct tegra_dc { | ||
74 | struct nvhost_device *ndev; | ||
75 | struct tegra_dc_platform_data *pdata; | ||
76 | |||
77 | struct resource *base_res; | ||
78 | void __iomem *base; | ||
79 | int irq; | ||
80 | |||
81 | struct clk *clk; | ||
82 | struct clk *emc_clk; | ||
83 | int emc_clk_rate; | ||
84 | int new_emc_clk_rate; | ||
85 | u32 shift_clk_div; | ||
86 | |||
87 | bool connected; | ||
88 | bool enabled; | ||
89 | bool suspended; | ||
90 | |||
91 | struct tegra_dc_out *out; | ||
92 | struct tegra_dc_out_ops *out_ops; | ||
93 | void *out_data; | ||
94 | |||
95 | struct tegra_dc_mode mode; | ||
96 | |||
97 | struct tegra_dc_win windows[DC_N_WINDOWS]; | ||
98 | struct tegra_dc_blend blend; | ||
99 | int n_windows; | ||
100 | |||
101 | wait_queue_head_t wq; | ||
102 | |||
103 | struct mutex lock; | ||
104 | struct mutex one_shot_lock; | ||
105 | |||
106 | struct resource *fb_mem; | ||
107 | struct tegra_fb_info *fb; | ||
108 | |||
109 | struct { | ||
110 | u32 id; | ||
111 | u32 min; | ||
112 | u32 max; | ||
113 | } syncpt[DC_N_WINDOWS]; | ||
114 | u32 vblank_syncpt; | ||
115 | |||
116 | unsigned long underflow_mask; | ||
117 | struct work_struct reset_work; | ||
118 | |||
119 | #ifdef CONFIG_SWITCH | ||
120 | struct switch_dev modeset_switch; | ||
121 | #endif | ||
122 | |||
123 | struct completion frame_end_complete; | ||
124 | |||
125 | struct work_struct vblank_work; | ||
126 | |||
127 | struct { | ||
128 | u64 underflows; | ||
129 | u64 underflows_a; | ||
130 | u64 underflows_b; | ||
131 | u64 underflows_c; | ||
132 | } stats; | ||
133 | |||
134 | struct tegra_dc_ext *ext; | ||
135 | |||
136 | #ifdef CONFIG_DEBUG_FS | ||
137 | struct dentry *debugdir; | ||
138 | #endif | ||
139 | struct tegra_dc_lut fb_lut; | ||
140 | struct delayed_work underflow_work; | ||
141 | u32 one_shot_delay_ms; | ||
142 | struct delayed_work one_shot_work; | ||
143 | }; | ||
144 | |||
145 | static inline void tegra_dc_io_start(struct tegra_dc *dc) | ||
146 | { | ||
147 | nvhost_module_busy(nvhost_get_host(dc->ndev)->dev); | ||
148 | } | ||
149 | |||
150 | static inline void tegra_dc_io_end(struct tegra_dc *dc) | ||
151 | { | ||
152 | nvhost_module_idle(nvhost_get_host(dc->ndev)->dev); | ||
153 | } | ||
154 | |||
155 | static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, | ||
156 | unsigned long reg) | ||
157 | { | ||
158 | BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)); | ||
159 | return readl(dc->base + reg * 4); | ||
160 | } | ||
161 | |||
162 | static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val, | ||
163 | unsigned long reg) | ||
164 | { | ||
165 | BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)); | ||
166 | writel(val, dc->base + reg * 4); | ||
167 | } | ||
168 | |||
169 | static inline void _tegra_dc_write_table(struct tegra_dc *dc, const u32 *table, | ||
170 | unsigned len) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | for (i = 0; i < len; i++) | ||
175 | tegra_dc_writel(dc, table[i * 2 + 1], table[i * 2]); | ||
176 | } | ||
177 | |||
178 | #define tegra_dc_write_table(dc, table) \ | ||
179 | _tegra_dc_write_table(dc, table, ARRAY_SIZE(table) / 2) | ||
180 | |||
181 | static inline void tegra_dc_set_outdata(struct tegra_dc *dc, void *data) | ||
182 | { | ||
183 | dc->out_data = data; | ||
184 | } | ||
185 | |||
186 | static inline void *tegra_dc_get_outdata(struct tegra_dc *dc) | ||
187 | { | ||
188 | return dc->out_data; | ||
189 | } | ||
190 | |||
191 | static inline unsigned long tegra_dc_get_default_emc_clk_rate( | ||
192 | struct tegra_dc *dc) | ||
193 | { | ||
194 | return dc->pdata->emc_clk_rate ? dc->pdata->emc_clk_rate : ULONG_MAX; | ||
195 | } | ||
196 | |||
197 | void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk); | ||
198 | |||
199 | extern struct tegra_dc_out_ops tegra_dc_rgb_ops; | ||
200 | extern struct tegra_dc_out_ops tegra_dc_hdmi_ops; | ||
201 | extern struct tegra_dc_out_ops tegra_dc_dsi_ops; | ||
202 | |||
203 | /* defined in dc_sysfs.c, used by dc.c */ | ||
204 | void __devexit tegra_dc_remove_sysfs(struct device *dev); | ||
205 | void tegra_dc_create_sysfs(struct device *dev); | ||
206 | |||
207 | /* defined in dc.c, used by dc_sysfs.c */ | ||
208 | void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable); | ||
209 | bool tegra_dc_stats_get(struct tegra_dc *dc); | ||
210 | |||
211 | /* defined in dc.c, used by dc_sysfs.c */ | ||
212 | u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc); | ||
213 | void tegra_dc_enable_crc(struct tegra_dc *dc); | ||
214 | void tegra_dc_disable_crc(struct tegra_dc *dc); | ||
215 | |||
216 | void tegra_dc_set_out_pin_polars(struct tegra_dc *dc, | ||
217 | const struct tegra_dc_out_pin *pins, | ||
218 | const unsigned int n_pins); | ||
219 | #endif | ||
220 | |||
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h new file mode 100644 index 00000000000..22379a19408 --- /dev/null +++ b/drivers/video/tegra/dc/dc_reg.h | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dc_reg.h | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * Copyright (C) 2010-2011 NVIDIA Corporation | ||
8 | * | ||
9 | * This software is licensed under the terms of the GNU General Public | ||
10 | * License version 2, as published by the Free Software Foundation, and | ||
11 | * may be copied, distributed, and modified under those terms. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H | ||
21 | #define __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H | ||
22 | |||
23 | #define DC_CMD_GENERAL_INCR_SYNCPT 0x000 | ||
24 | #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001 | ||
25 | #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002 | ||
26 | #define DC_CMD_WIN_A_INCR_SYNCPT 0x008 | ||
27 | #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009 | ||
28 | #define DC_CMD_WIN_A_INCR_SYNCPT_ERROR 0x00a | ||
29 | #define DC_CMD_WIN_B_INCR_SYNCPT 0x010 | ||
30 | #define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL 0x011 | ||
31 | #define DC_CMD_WIN_B_INCR_SYNCPT_ERROR 0x012 | ||
32 | #define DC_CMD_WIN_C_INCR_SYNCPT 0x018 | ||
33 | #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019 | ||
34 | #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a | ||
35 | #define DC_CMD_CONT_SYNCPT_VSYNC 0x028 | ||
36 | #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 | ||
37 | #define MSF_POLARITY_HIGH (0 << 0) | ||
38 | #define MSF_POLARITY_LOW (1 << 0) | ||
39 | #define MSF_DISABLE (0 << 1) | ||
40 | #define MSF_ENABLE (1 << 1) | ||
41 | #define MSF_LSPI (0 << 2) | ||
42 | #define MSF_LDC (1 << 2) | ||
43 | #define MSF_LSDI (2 << 2) | ||
44 | |||
45 | #define DC_CMD_DISPLAY_COMMAND 0x032 | ||
46 | #define DISP_COMMAND_RAISE (1 << 0) | ||
47 | #define DISP_CTRL_MODE_STOP (0 << 5) | ||
48 | #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) | ||
49 | #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) | ||
50 | #define DISP_COMMAND_RAISE_VECTOR(x) (((x) & 0x1f) << 22) | ||
51 | #define DISP_COMMAND_RAISE_CHANNEL_ID(x) (((x) & 0xf) << 27) | ||
52 | |||
53 | #define DC_CMD_SIGNAL_RAISE 0x033 | ||
54 | #define DC_CMD_DISPLAY_POWER_CONTROL 0x036 | ||
55 | #define PW0_ENABLE (1 << 0) | ||
56 | #define PW1_ENABLE (1 << 2) | ||
57 | #define PW2_ENABLE (1 << 4) | ||
58 | #define PW3_ENABLE (1 << 6) | ||
59 | #define PW4_ENABLE (1 << 8) | ||
60 | #define PM0_ENABLE (1 << 16) | ||
61 | #define PM1_ENABLE (1 << 18) | ||
62 | #define SPI_ENABLE (1 << 24) | ||
63 | #define HSPI_ENABLE (1 << 25) | ||
64 | |||
65 | #define DC_CMD_INT_STATUS 0x037 | ||
66 | #define DC_CMD_INT_MASK 0x038 | ||
67 | #define DC_CMD_INT_ENABLE 0x039 | ||
68 | #define DC_CMD_INT_TYPE 0x03a | ||
69 | #define DC_CMD_INT_POLARITY 0x03b | ||
70 | #define CTXSW_INT (1 << 0) | ||
71 | #define FRAME_END_INT (1 << 1) | ||
72 | #define V_BLANK_INT (1 << 2) | ||
73 | #define H_BLANK_INT (1 << 3) | ||
74 | #define V_PULSE3_INT (1 << 4) | ||
75 | #define SPI_BUSY_INT (1 << 7) | ||
76 | #define WIN_A_UF_INT (1 << 8) | ||
77 | #define WIN_B_UF_INT (1 << 9) | ||
78 | #define WIN_C_UF_INT (1 << 10) | ||
79 | #define MSF_INT (1 << 12) | ||
80 | #define SSF_INT (1 << 13) | ||
81 | #define WIN_A_OF_INT (1 << 14) | ||
82 | #define WIN_B_OF_INT (1 << 15) | ||
83 | #define WIN_C_OF_INT (1 << 16) | ||
84 | #define GPIO_0_INT (1 << 18) | ||
85 | #define GPIO_1_INT (1 << 19) | ||
86 | #define GPIO_2_INT (1 << 20) | ||
87 | |||
88 | #define DC_CMD_SIGNAL_RAISE1 0x03c | ||
89 | #define DC_CMD_SIGNAL_RAISE2 0x03d | ||
90 | #define DC_CMD_SIGNAL_RAISE3 0x03e | ||
91 | #define DC_CMD_STATE_ACCESS 0x040 | ||
92 | #define READ_MUX_ASSEMBLY (0 << 0) | ||
93 | #define READ_MUX_ACTIVE (1 << 0) | ||
94 | #define WRITE_MUX_ASSEMBLY (0 << 2) | ||
95 | #define WRITE_MUX_ACTIVE (1 << 2) | ||
96 | |||
97 | #define DC_CMD_STATE_CONTROL 0x041 | ||
98 | #define GENERAL_ACT_REQ (1 << 0) | ||
99 | #define WIN_A_ACT_REQ (1 << 1) | ||
100 | #define WIN_B_ACT_REQ (1 << 2) | ||
101 | #define WIN_C_ACT_REQ (1 << 3) | ||
102 | #define GENERAL_UPDATE (1 << 8) | ||
103 | #define WIN_A_UPDATE (1 << 9) | ||
104 | #define WIN_B_UPDATE (1 << 10) | ||
105 | #define WIN_C_UPDATE (1 << 11) | ||
106 | #define NC_HOST_TRIG (1 << 24) | ||
107 | |||
108 | #define DC_CMD_DISPLAY_WINDOW_HEADER 0x042 | ||
109 | #define WINDOW_A_SELECT (1 << 4) | ||
110 | #define WINDOW_B_SELECT (1 << 5) | ||
111 | #define WINDOW_C_SELECT (1 << 6) | ||
112 | |||
113 | #define DC_CMD_REG_ACT_CONTROL 0x043 | ||
114 | |||
115 | #define DC_COM_CRC_CONTROL 0x300 | ||
116 | #define CRC_ALWAYS_ENABLE (1 << 3) | ||
117 | #define CRC_ALWAYS_DISABLE (0 << 3) | ||
118 | #define CRC_INPUT_DATA_ACTIVE_DATA (1 << 2) | ||
119 | #define CRC_INPUT_DATA_FULL_FRAME (0 << 2) | ||
120 | #define CRC_WAIT_TWO_VSYNC (1 << 1) | ||
121 | #define CRC_WAIT_ONE_VSYNC (0 << 1) | ||
122 | #define CRC_ENABLE_ENABLE (1 << 0) | ||
123 | #define CRC_ENABLE_DISABLE (0 << 0) | ||
124 | #define DC_COM_CRC_CHECKSUM 0x301 | ||
125 | #define DC_COM_PIN_OUTPUT_ENABLE0 0x302 | ||
126 | #define DC_COM_PIN_OUTPUT_ENABLE1 0x303 | ||
127 | #define DC_COM_PIN_OUTPUT_ENABLE2 0x304 | ||
128 | #define DC_COM_PIN_OUTPUT_ENABLE3 0x305 | ||
129 | #define PIN_OUTPUT_LSPI_OUTPUT_EN (1 << 8) | ||
130 | #define PIN_OUTPUT_LSPI_OUTPUT_DIS (1 << 8) | ||
131 | #define DC_COM_PIN_OUTPUT_POLARITY0 0x306 | ||
132 | |||
133 | #define DC_COM_PIN_OUTPUT_POLARITY1 0x307 | ||
134 | #define LHS_OUTPUT_POLARITY_LOW (1 << 30) | ||
135 | #define LVS_OUTPUT_POLARITY_LOW (1 << 28) | ||
136 | #define LSC0_OUTPUT_POLARITY_LOW (1 << 24) | ||
137 | |||
138 | #define DC_COM_PIN_OUTPUT_POLARITY2 0x308 | ||
139 | |||
140 | #define DC_COM_PIN_OUTPUT_POLARITY3 0x309 | ||
141 | #define LSPI_OUTPUT_POLARITY_LOW (1 << 8) | ||
142 | |||
143 | #define DC_COM_PIN_OUTPUT_DATA0 0x30a | ||
144 | #define DC_COM_PIN_OUTPUT_DATA1 0x30b | ||
145 | #define DC_COM_PIN_OUTPUT_DATA2 0x30c | ||
146 | #define DC_COM_PIN_OUTPUT_DATA3 0x30d | ||
147 | #define DC_COM_PIN_INPUT_ENABLE0 0x30e | ||
148 | #define DC_COM_PIN_INPUT_ENABLE1 0x30f | ||
149 | #define DC_COM_PIN_INPUT_ENABLE2 0x310 | ||
150 | #define DC_COM_PIN_INPUT_ENABLE3 0x311 | ||
151 | #define PIN_INPUT_LSPI_INPUT_EN (1 << 8) | ||
152 | #define PIN_INPUT_LSPI_INPUT_DIS (1 << 8) | ||
153 | #define DC_COM_PIN_INPUT_DATA0 0x312 | ||
154 | #define DC_COM_PIN_INPUT_DATA1 0x313 | ||
155 | #define DC_COM_PIN_OUTPUT_SELECT0 0x314 | ||
156 | #define DC_COM_PIN_OUTPUT_SELECT1 0x315 | ||
157 | #define DC_COM_PIN_OUTPUT_SELECT2 0x316 | ||
158 | #define DC_COM_PIN_OUTPUT_SELECT3 0x317 | ||
159 | #define DC_COM_PIN_OUTPUT_SELECT4 0x318 | ||
160 | #define DC_COM_PIN_OUTPUT_SELECT5 0x319 | ||
161 | #define DC_COM_PIN_OUTPUT_SELECT6 0x31a | ||
162 | |||
163 | #define PIN5_LM1_LCD_M1_OUTPUT_MASK (7 << 4) | ||
164 | #define PIN5_LM1_LCD_M1_OUTPUT_M1 (0 << 4) | ||
165 | #define PIN5_LM1_LCD_M1_OUTPUT_LD21 (2 << 4) | ||
166 | #define PIN5_LM1_LCD_M1_OUTPUT_PM1 (3 << 4) | ||
167 | |||
168 | #define PIN1_LHS_OUTPUT (1 << 30) | ||
169 | #define PIN1_LVS_OUTPUT (1 << 28) | ||
170 | |||
171 | #define DC_COM_PIN_MISC_CONTROL 0x31b | ||
172 | #define DC_COM_PM0_CONTROL 0x31c | ||
173 | #define DC_COM_PM0_DUTY_CYCLE 0x31d | ||
174 | #define DC_COM_PM1_CONTROL 0x31e | ||
175 | #define DC_COM_PM1_DUTY_CYCLE 0x31f | ||
176 | |||
177 | #define PM_PERIOD_SHIFT 18 | ||
178 | #define PM_CLK_DIVIDER_SHIFT 4 | ||
179 | |||
180 | #define DC_COM_SPI_CONTROL 0x320 | ||
181 | #define DC_COM_SPI_START_BYTE 0x321 | ||
182 | #define DC_COM_HSPI_WRITE_DATA_AB 0x322 | ||
183 | #define DC_COM_HSPI_WRITE_DATA_CD 0x323 | ||
184 | #define DC_COM_HSPI_CS_DC 0x324 | ||
185 | #define DC_COM_SCRATCH_REGISTER_A 0x325 | ||
186 | #define DC_COM_SCRATCH_REGISTER_B 0x326 | ||
187 | #define DC_COM_GPIO_CTRL 0x327 | ||
188 | #define DC_COM_GPIO_DEBOUNCE_COUNTER 0x328 | ||
189 | #define DC_COM_CRC_CHECKSUM_LATCHED 0x329 | ||
190 | |||
191 | #define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400 | ||
192 | #define H_PULSE_0_ENABLE (1 << 8) | ||
193 | #define H_PULSE_1_ENABLE (1 << 10) | ||
194 | #define H_PULSE_2_ENABLE (1 << 12) | ||
195 | #define V_PULSE_0_ENABLE (1 << 16) | ||
196 | #define V_PULSE_1_ENABLE (1 << 18) | ||
197 | #define V_PULSE_2_ENABLE (1 << 19) | ||
198 | #define V_PULSE_3_ENABLE (1 << 20) | ||
199 | #define M0_ENABLE (1 << 24) | ||
200 | #define M1_ENABLE (1 << 26) | ||
201 | |||
202 | #define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401 | ||
203 | #define DI_ENABLE (1 << 16) | ||
204 | #define PP_ENABLE (1 << 18) | ||
205 | |||
206 | #define DC_DISP_DISP_WIN_OPTIONS 0x402 | ||
207 | #define CURSOR_ENABLE (1 << 16) | ||
208 | #define TVO_ENABLE (1 << 28) | ||
209 | #define DSI_ENABLE (1 << 29) | ||
210 | #define HDMI_ENABLE (1 << 30) | ||
211 | |||
212 | #define DC_DISP_MEM_HIGH_PRIORITY 0x403 | ||
213 | #define DC_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 | ||
214 | #define DC_DISP_DISP_TIMING_OPTIONS 0x405 | ||
215 | #define VSYNC_H_POSITION(x) ((x) & 0xfff) | ||
216 | |||
217 | #define DC_DISP_REF_TO_SYNC 0x406 | ||
218 | #define DC_DISP_SYNC_WIDTH 0x407 | ||
219 | #define DC_DISP_BACK_PORCH 0x408 | ||
220 | #define DC_DISP_DISP_ACTIVE 0x409 | ||
221 | #define DC_DISP_FRONT_PORCH 0x40a | ||
222 | #define DC_DISP_H_PULSE0_CONTROL 0x40b | ||
223 | #define DC_DISP_H_PULSE0_POSITION_A 0x40c | ||
224 | #define DC_DISP_H_PULSE0_POSITION_B 0x40d | ||
225 | #define DC_DISP_H_PULSE0_POSITION_C 0x40e | ||
226 | #define DC_DISP_H_PULSE0_POSITION_D 0x40f | ||
227 | #define DC_DISP_H_PULSE1_CONTROL 0x410 | ||
228 | #define DC_DISP_H_PULSE1_POSITION_A 0x411 | ||
229 | #define DC_DISP_H_PULSE1_POSITION_B 0x412 | ||
230 | #define DC_DISP_H_PULSE1_POSITION_C 0x413 | ||
231 | #define DC_DISP_H_PULSE1_POSITION_D 0x414 | ||
232 | #define DC_DISP_H_PULSE2_CONTROL 0x415 | ||
233 | #define DC_DISP_H_PULSE2_POSITION_A 0x416 | ||
234 | #define DC_DISP_H_PULSE2_POSITION_B 0x417 | ||
235 | #define DC_DISP_H_PULSE2_POSITION_C 0x418 | ||
236 | #define DC_DISP_H_PULSE2_POSITION_D 0x419 | ||
237 | #define DC_DISP_V_PULSE0_CONTROL 0x41a | ||
238 | #define DC_DISP_V_PULSE0_POSITION_A 0x41b | ||
239 | #define DC_DISP_V_PULSE0_POSITION_B 0x41c | ||
240 | #define DC_DISP_V_PULSE0_POSITION_C 0x41d | ||
241 | #define DC_DISP_V_PULSE1_CONTROL 0x41e | ||
242 | #define DC_DISP_V_PULSE1_POSITION_A 0x41f | ||
243 | #define DC_DISP_V_PULSE1_POSITION_B 0x420 | ||
244 | #define DC_DISP_V_PULSE1_POSITION_C 0x421 | ||
245 | #define DC_DISP_V_PULSE2_CONTROL 0x422 | ||
246 | #define DC_DISP_V_PULSE2_POSITION_A 0x423 | ||
247 | #define DC_DISP_V_PULSE3_CONTROL 0x424 | ||
248 | #define DC_DISP_V_PULSE3_POSITION_A 0x425 | ||
249 | #define DC_DISP_M0_CONTROL 0x426 | ||
250 | #define DC_DISP_M1_CONTROL 0x427 | ||
251 | #define DC_DISP_DI_CONTROL 0x428 | ||
252 | #define DC_DISP_PP_CONTROL 0x429 | ||
253 | #define DC_DISP_PP_SELECT_A 0x42a | ||
254 | #define DC_DISP_PP_SELECT_B 0x42b | ||
255 | #define DC_DISP_PP_SELECT_C 0x42c | ||
256 | #define DC_DISP_PP_SELECT_D 0x42d | ||
257 | |||
258 | #define PULSE_MODE_NORMAL (0 << 3) | ||
259 | #define PULSE_MODE_ONE_CLOCK (1 << 3) | ||
260 | #define PULSE_POLARITY_HIGH (0 << 4) | ||
261 | #define PULSE_POLARITY_LOW (1 << 4) | ||
262 | #define PULSE_QUAL_ALWAYS (0 << 6) | ||
263 | #define PULSE_QUAL_VACTIVE (2 << 6) | ||
264 | #define PULSE_QUAL_VACTIVE1 (3 << 6) | ||
265 | #define PULSE_LAST_START_A (0 << 8) | ||
266 | #define PULSE_LAST_END_A (1 << 8) | ||
267 | #define PULSE_LAST_START_B (2 << 8) | ||
268 | #define PULSE_LAST_END_B (3 << 8) | ||
269 | #define PULSE_LAST_START_C (4 << 8) | ||
270 | #define PULSE_LAST_END_C (5 << 8) | ||
271 | #define PULSE_LAST_START_D (6 << 8) | ||
272 | #define PULSE_LAST_END_D (7 << 8) | ||
273 | |||
274 | #define PULSE_START(x) ((x) & 0xfff) | ||
275 | #define PULSE_END(x) (((x) & 0xfff) << 16) | ||
276 | |||
277 | #define DC_DISP_DISP_CLOCK_CONTROL 0x42e | ||
278 | #define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) | ||
279 | #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) | ||
280 | #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) | ||
281 | #define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) | ||
282 | #define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) | ||
283 | #define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) | ||
284 | #define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) | ||
285 | #define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) | ||
286 | #define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) | ||
287 | #define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) | ||
288 | #define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) | ||
289 | #define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) | ||
290 | #define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) | ||
291 | #define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) | ||
292 | |||
293 | #define DC_DISP_DISP_INTERFACE_CONTROL 0x42f | ||
294 | #define DISP_DATA_FORMAT_DF1P1C (0 << 0) | ||
295 | #define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) | ||
296 | #define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) | ||
297 | #define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) | ||
298 | #define DISP_DATA_FORMAT_DF2S (5 << 0) | ||
299 | #define DISP_DATA_FORMAT_DF3S (6 << 0) | ||
300 | #define DISP_DATA_FORMAT_DFSPI (7 << 0) | ||
301 | #define DISP_DATA_FORMAT_DF1P3C24B (8 << 0) | ||
302 | #define DISP_DATA_FORMAT_DF1P3C18B (9 << 0) | ||
303 | #define DISP_DATA_ALIGNMENT_MSB (0 << 8) | ||
304 | #define DISP_DATA_ALIGNMENT_LSB (1 << 8) | ||
305 | #define DISP_DATA_ORDER_RED_BLUE (0 << 9) | ||
306 | #define DISP_DATA_ORDER_BLUE_RED (1 << 9) | ||
307 | |||
308 | #define DC_DISP_DISP_COLOR_CONTROL 0x430 | ||
309 | #define BASE_COLOR_SIZE666 (0 << 0) | ||
310 | #define BASE_COLOR_SIZE111 (1 << 0) | ||
311 | #define BASE_COLOR_SIZE222 (2 << 0) | ||
312 | #define BASE_COLOR_SIZE333 (3 << 0) | ||
313 | #define BASE_COLOR_SIZE444 (4 << 0) | ||
314 | #define BASE_COLOR_SIZE555 (5 << 0) | ||
315 | #define BASE_COLOR_SIZE565 (6 << 0) | ||
316 | #define BASE_COLOR_SIZE332 (7 << 0) | ||
317 | #define BASE_COLOR_SIZE888 (8 << 0) | ||
318 | |||
319 | #define DITHER_CONTROL_DISABLE (0 << 8) | ||
320 | #define DITHER_CONTROL_ORDERED (2 << 8) | ||
321 | #define DITHER_CONTROL_ERRDIFF (3 << 8) | ||
322 | |||
323 | #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 | ||
324 | #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 | ||
325 | #define DE_SELECT_ACTIVE_BLANK 0x0 | ||
326 | #define DE_SELECT_ACTIVE 0x1 | ||
327 | #define DE_SELECT_ACTIVE_IS 0x2 | ||
328 | #define DE_CONTROL_ONECLK (0 << 2) | ||
329 | #define DE_CONTROL_NORMAL (1 << 2) | ||
330 | #define DE_CONTROL_EARLY_EXT (2 << 2) | ||
331 | #define DE_CONTROL_EARLY (3 << 2) | ||
332 | #define DE_CONTROL_ACTIVE_BLANK (4 << 2) | ||
333 | |||
334 | #define DC_DISP_SERIAL_INTERFACE_OPTIONS 0x433 | ||
335 | #define DC_DISP_LCD_SPI_OPTIONS 0x434 | ||
336 | #define DC_DISP_BORDER_COLOR 0x435 | ||
337 | #define DC_DISP_COLOR_KEY0_LOWER 0x436 | ||
338 | #define DC_DISP_COLOR_KEY0_UPPER 0x437 | ||
339 | #define DC_DISP_COLOR_KEY1_LOWER 0x438 | ||
340 | #define DC_DISP_COLOR_KEY1_UPPER 0x439 | ||
341 | |||
342 | #define DC_DISP_CURSOR_FOREGROUND 0x43c | ||
343 | #define DC_DISP_CURSOR_BACKGROUND 0x43d | ||
344 | #define CURSOR_COLOR(_r, _g, _b) ((_r) | ((_g) << 8) | ((_b) << 16)) | ||
345 | |||
346 | #define DC_DISP_CURSOR_START_ADDR 0x43e | ||
347 | #define DC_DISP_CURSOR_START_ADDR_NS 0x43f | ||
348 | #define CURSOR_START_ADDR_MASK (((1 << 22) - 1) << 10) | ||
349 | #define CURSOR_START_ADDR(_addr) ((_addr) >> 10) | ||
350 | #define CURSOR_SIZE_64 (1 << 24) | ||
351 | |||
352 | #define DC_DISP_CURSOR_POSITION 0x440 | ||
353 | #define CURSOR_POSITION(_x, _y) \ | ||
354 | (((_x) & ((1 << 16) - 1)) | \ | ||
355 | (((_y) & ((1 << 16) - 1)) << 16)) | ||
356 | |||
357 | #define DC_DISP_CURSOR_POSITION_NS 0x441 | ||
358 | #define DC_DISP_INIT_SEQ_CONTROL 0x442 | ||
359 | #define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443 | ||
360 | #define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444 | ||
361 | #define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445 | ||
362 | #define DC_DISP_SPI_INIT_SEQ_DATA_D 0x446 | ||
363 | #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 | ||
364 | #define DC_DISP_MCCIF_DISPLAY0A_HYST 0x481 | ||
365 | #define DC_DISP_MCCIF_DISPLAY0B_HYST 0x482 | ||
366 | #define DC_DISP_MCCIF_DISPLAY0C_HYST 0x483 | ||
367 | #define DC_DISP_MCCIF_DISPLAY1B_HYST 0x484 | ||
368 | #define DC_DISP_DAC_CRT_CTRL 0x4c0 | ||
369 | #define DC_DISP_DISP_MISC_CONTROL 0x4c1 | ||
370 | |||
371 | #define DC_WIN_COLOR_PALETTE(x) (0x500 + (x)) | ||
372 | |||
373 | #define DC_WIN_PALETTE_COLOR_EXT 0x600 | ||
374 | #define DC_WIN_H_FILTER_P(x) (0x601 + (x)) | ||
375 | #define DC_WIN_CSC_YOF 0x611 | ||
376 | #define DC_WIN_CSC_KYRGB 0x612 | ||
377 | #define DC_WIN_CSC_KUR 0x613 | ||
378 | #define DC_WIN_CSC_KVR 0x614 | ||
379 | #define DC_WIN_CSC_KUG 0x615 | ||
380 | #define DC_WIN_CSC_KVG 0x616 | ||
381 | #define DC_WIN_CSC_KUB 0x617 | ||
382 | #define DC_WIN_CSC_KVB 0x618 | ||
383 | #define DC_WIN_V_FILTER_P(x) (0x619 + (x)) | ||
384 | #define DC_WIN_WIN_OPTIONS 0x700 | ||
385 | #define H_DIRECTION_INCREMENT (0 << 0) | ||
386 | #define H_DIRECTION_DECREMENT (1 << 0) | ||
387 | #define V_DIRECTION_INCREMENT (0 << 2) | ||
388 | #define V_DIRECTION_DECREMENT (1 << 2) | ||
389 | #define COLOR_EXPAND (1 << 6) | ||
390 | #define H_FILTER_ENABLE (1 << 8) | ||
391 | #define V_FILTER_ENABLE (1 << 10) | ||
392 | #define CP_ENABLE (1 << 16) | ||
393 | #define CSC_ENABLE (1 << 18) | ||
394 | #define DV_ENABLE (1 << 20) | ||
395 | #define WIN_ENABLE (1 << 30) | ||
396 | |||
397 | #define DC_WIN_BYTE_SWAP 0x701 | ||
398 | #define BYTE_SWAP_NOSWAP 0 | ||
399 | #define BYTE_SWAP_SWAP2 1 | ||
400 | #define BYTE_SWAP_SWAP4 2 | ||
401 | #define BYTE_SWAP_SWAP4HW 3 | ||
402 | |||
403 | #define DC_WIN_BUFFER_CONTROL 0x702 | ||
404 | #define BUFFER_CONTROL_HOST 0 | ||
405 | #define BUFFER_CONTROL_VI 1 | ||
406 | #define BUFFER_CONTROL_EPP 2 | ||
407 | #define BUFFER_CONTROL_MPEGE 3 | ||
408 | #define BUFFER_CONTROL_SB2D 4 | ||
409 | |||
410 | #define DC_WIN_COLOR_DEPTH 0x703 | ||
411 | |||
412 | #define DC_WIN_POSITION 0x704 | ||
413 | #define H_POSITION(x) (((x) & 0xfff) << 0) | ||
414 | #define V_POSITION(x) (((x) & 0xfff) << 16) | ||
415 | |||
416 | #define DC_WIN_SIZE 0x705 | ||
417 | #define H_SIZE(x) (((x) & 0xfff) << 0) | ||
418 | #define V_SIZE(x) (((x) & 0xfff) << 16) | ||
419 | |||
420 | #define DC_WIN_PRESCALED_SIZE 0x706 | ||
421 | #define H_PRESCALED_SIZE(x) (((x) & 0x3fff) << 0) | ||
422 | #define V_PRESCALED_SIZE(x) (((x) & 0xfff) << 16) | ||
423 | |||
424 | #define DC_WIN_H_INITIAL_DDA 0x707 | ||
425 | #define DC_WIN_V_INITIAL_DDA 0x708 | ||
426 | #define DC_WIN_DDA_INCREMENT 0x709 | ||
427 | #define H_DDA_INC(x) (((x) & 0xffff) << 0) | ||
428 | #define V_DDA_INC(x) (((x) & 0xffff) << 16) | ||
429 | |||
430 | #define DC_WIN_LINE_STRIDE 0x70a | ||
431 | #define LINE_STRIDE(x) (x) | ||
432 | #define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16) | ||
433 | #define DC_WIN_BUF_STRIDE 0x70b | ||
434 | #define DC_WIN_UV_BUF_STRIDE 0x70c | ||
435 | #define DC_WIN_BUFFER_ADDR_MODE 0x70d | ||
436 | #define DC_WIN_BUFFER_ADDR_MODE_LINEAR (0 << 0) | ||
437 | #define DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV (0 << 16) | ||
438 | #define DC_WIN_BUFFER_ADDR_MODE_TILE (1 << 0) | ||
439 | #define DC_WIN_BUFFER_ADDR_MODE_TILE_UV (1 << 16) | ||
440 | #define DC_WIN_DV_CONTROL 0x70e | ||
441 | #define DC_WIN_BLEND_NOKEY 0x70f | ||
442 | #define DC_WIN_BLEND_1WIN 0x710 | ||
443 | #define DC_WIN_BLEND_2WIN_X 0x711 | ||
444 | #define DC_WIN_BLEND_2WIN_Y 0x712 | ||
445 | #define DC_WIN_BLEND_3WIN_XY 0x713 | ||
446 | #define CKEY_NOKEY (0 << 0) | ||
447 | #define CKEY_KEY0 (1 << 0) | ||
448 | #define CKEY_KEY1 (2 << 0) | ||
449 | #define CKEY_KEY01 (3 << 0) | ||
450 | #define BLEND_CONTROL_FIX (0 << 2) | ||
451 | #define BLEND_CONTROL_ALPHA (1 << 2) | ||
452 | #define BLEND_CONTROL_DEPENDANT (2 << 2) | ||
453 | #define BLEND_CONTROL_PREMULT (3 << 2) | ||
454 | #define BLEND_WEIGHT0(x) (((x) & 0xff) << 8) | ||
455 | #define BLEND_WEIGHT1(x) (((x) & 0xff) << 16) | ||
456 | #define BLEND(key, control, weight0, weight1) \ | ||
457 | (CKEY_ ## key | BLEND_CONTROL_ ## control | \ | ||
458 | BLEND_WEIGHT0(weight0) | BLEND_WEIGHT1(weight1)) | ||
459 | |||
460 | |||
461 | #define DC_WIN_HP_FETCH_CONTROL 0x714 | ||
462 | #define DC_WINBUF_START_ADDR 0x800 | ||
463 | #define DC_WINBUF_START_ADDR_NS 0x801 | ||
464 | #define DC_WINBUF_START_ADDR_U 0x802 | ||
465 | #define DC_WINBUF_START_ADDR_U_NS 0x803 | ||
466 | #define DC_WINBUF_START_ADDR_V 0x804 | ||
467 | #define DC_WINBUF_START_ADDR_V_NS 0x805 | ||
468 | #define DC_WINBUF_ADDR_H_OFFSET 0x806 | ||
469 | #define DC_WINBUF_ADDR_H_OFFSET_NS 0x807 | ||
470 | #define DC_WINBUF_ADDR_V_OFFSET 0x808 | ||
471 | #define DC_WINBUF_ADDR_V_OFFSET_NS 0x809 | ||
472 | #define DC_WINBUF_UFLOW_STATUS 0x80a | ||
473 | |||
474 | /* direct versions of DC_WINBUF_UFLOW_STATUS */ | ||
475 | #define DC_WINBUF_AD_UFLOW_STATUS 0xbca | ||
476 | #define DC_WINBUF_BD_UFLOW_STATUS 0xdca | ||
477 | #define DC_WINBUF_CD_UFLOW_STATUS 0xfca | ||
478 | |||
479 | #define DC_DISP_SD_CONTROL 0x4c2 | ||
480 | #define SD_ENABLE_NORMAL (1 << 0) | ||
481 | #define SD_ENABLE_ONESHOT (2 << 0) | ||
482 | #define SD_USE_VID_LUMA (1 << 2) | ||
483 | #define SD_BIN_WIDTH_ONE (0 << 3) | ||
484 | #define SD_BIN_WIDTH_TWO (1 << 3) | ||
485 | #define SD_BIN_WIDTH_FOUR (2 << 3) | ||
486 | #define SD_BIN_WIDTH_EIGHT (3 << 3) | ||
487 | #define SD_BIN_WIDTH_MASK (3 << 3) | ||
488 | #define SD_AGGRESSIVENESS(x) (((x) & 0x7) << 5) | ||
489 | #define SD_HW_UPDATE_DLY(x) (((x) & 0x3) << 8) | ||
490 | #define SD_ONESHOT_ENABLE (1 << 10) | ||
491 | #define SD_CORRECTION_MODE_AUTO (0 << 11) | ||
492 | #define SD_CORRECTION_MODE_MAN (1 << 11) | ||
493 | |||
494 | #define NUM_BIN_WIDTHS 4 | ||
495 | #define STEPS_PER_AGG_LVL 64 | ||
496 | #define STEPS_PER_AGG_CHG_LOG2 5 | ||
497 | #define STEPS_PER_AGG_CHG (1<<STEPS_PER_AGG_CHG_LOG2) | ||
498 | #define ADJ_PHASE_STEP 8 | ||
499 | #define K_STEP 4 | ||
500 | |||
501 | #define DC_DISP_SD_CSC_COEFF 0x4c3 | ||
502 | #define SD_CSC_COEFF_R(x) (((x) & 0xf) << 4) | ||
503 | #define SD_CSC_COEFF_G(x) (((x) & 0xf) << 12) | ||
504 | #define SD_CSC_COEFF_B(x) (((x) & 0xf) << 20) | ||
505 | |||
506 | #define DC_DISP_SD_LUT(i) (0x4c4 + i) | ||
507 | #define DC_DISP_SD_LUT_NUM 9 | ||
508 | #define SD_LUT_R(x) (((x) & 0xff) << 0) | ||
509 | #define SD_LUT_G(x) (((x) & 0xff) << 8) | ||
510 | #define SD_LUT_B(x) (((x) & 0xff) << 16) | ||
511 | |||
512 | #define DC_DISP_SD_FLICKER_CONTROL 0x4cd | ||
513 | #define SD_FC_TIME_LIMIT(x) (((x) & 0xff) << 0) | ||
514 | #define SD_FC_THRESHOLD(x) (((x) & 0xff) << 8) | ||
515 | |||
516 | #define DC_DISP_SD_PIXEL_COUNT 0x4ce | ||
517 | |||
518 | #define DC_DISP_SD_HISTOGRAM(i) (0x4cf + i) | ||
519 | #define DC_DISP_SD_HISTOGRAM_NUM 8 | ||
520 | #define SD_HISTOGRAM_BIN_0(val) (((val) & (0xff << 0)) >> 0) | ||
521 | #define SD_HISTOGRAM_BIN_1(val) (((val) & (0xff << 8)) >> 8) | ||
522 | #define SD_HISTOGRAM_BIN_2(val) (((val) & (0xff << 16)) >> 16) | ||
523 | #define SD_HISTOGRAM_BIN_3(val) (((val) & (0xff << 24)) >> 24) | ||
524 | |||
525 | #define DC_DISP_SD_BL_PARAMETERS 0x4d7 | ||
526 | #define SD_BLP_TIME_CONSTANT(x) (((x) & 0x7ff) << 0) | ||
527 | #define SD_BLP_STEP(x) (((x) & 0xff) << 16) | ||
528 | |||
529 | #define DC_DISP_SD_BL_TF(i) (0x4d8 + i) | ||
530 | #define DC_DISP_SD_BL_TF_NUM 4 | ||
531 | #define SD_BL_TF_POINT_0(x) (((x) & 0xff) << 0) | ||
532 | #define SD_BL_TF_POINT_1(x) (((x) & 0xff) << 8) | ||
533 | #define SD_BL_TF_POINT_2(x) (((x) & 0xff) << 16) | ||
534 | #define SD_BL_TF_POINT_3(x) (((x) & 0xff) << 24) | ||
535 | |||
536 | #define DC_DISP_SD_BL_CONTROL 0x4dc | ||
537 | #define SD_BLC_MODE_MAN (0 << 0) | ||
538 | #define SD_BLC_MODE_AUTO (1 << 1) | ||
539 | #define SD_BLC_BRIGHTNESS(val) (((val) & (0xff << 8)) >> 8) | ||
540 | |||
541 | #define DC_DISP_SD_HW_K_VALUES 0x4dd | ||
542 | #define SD_HW_K_R(val) (((val) & (0x3ff << 0)) >> 0) | ||
543 | #define SD_HW_K_G(val) (((val) & (0x3ff << 10)) >> 10) | ||
544 | #define SD_HW_K_B(val) (((val) & (0x3ff << 20)) >> 20) | ||
545 | |||
546 | #define DC_DISP_SD_MAN_K_VALUES 0x4de | ||
547 | #define SD_MAN_K_R(x) (((x) & 0x3ff) << 0) | ||
548 | #define SD_MAN_K_G(x) (((x) & 0x3ff) << 10) | ||
549 | #define SD_MAN_K_B(x) (((x) & 0x3ff) << 20) | ||
550 | |||
551 | #define NUM_AGG_PRI_LVLS 4 | ||
552 | #define SD_AGG_PRI_LVL(x) ((x) >> 3) | ||
553 | #define SD_GET_AGG(x) ((x) & 0x7) | ||
554 | |||
555 | #endif | ||
diff --git a/drivers/video/tegra/dc/dc_sysfs.c b/drivers/video/tegra/dc/dc_sysfs.c new file mode 100644 index 00000000000..6bb18382e6e --- /dev/null +++ b/drivers/video/tegra/dc/dc_sysfs.c | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dc_sysfs.c | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/kernel.h> | ||
23 | |||
24 | #include <mach/dc.h> | ||
25 | #include <mach/fb.h> | ||
26 | |||
27 | #include "dc_reg.h" | ||
28 | #include "dc_priv.h" | ||
29 | #include "nvsd.h" | ||
30 | |||
31 | static ssize_t mode_show(struct device *device, | ||
32 | struct device_attribute *attr, char *buf) | ||
33 | { | ||
34 | struct nvhost_device *ndev = to_nvhost_device(device); | ||
35 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
36 | struct tegra_dc_mode *m; | ||
37 | ssize_t res; | ||
38 | |||
39 | mutex_lock(&dc->lock); | ||
40 | m = &dc->mode; | ||
41 | res = snprintf(buf, PAGE_SIZE, | ||
42 | "pclk: %d\n" | ||
43 | "h_ref_to_sync: %d\n" | ||
44 | "v_ref_to_sync: %d\n" | ||
45 | "h_sync_width: %d\n" | ||
46 | "v_sync_width: %d\n" | ||
47 | "h_back_porch: %d\n" | ||
48 | "v_back_porch: %d\n" | ||
49 | "h_active: %d\n" | ||
50 | "v_active: %d\n" | ||
51 | "h_front_porch: %d\n" | ||
52 | "v_front_porch: %d\n" | ||
53 | "stereo_mode: %d\n", | ||
54 | m->pclk, m->h_ref_to_sync, m->v_ref_to_sync, | ||
55 | m->h_sync_width, m->v_sync_width, | ||
56 | m->h_back_porch, m->v_back_porch, | ||
57 | m->h_active, m->v_active, | ||
58 | m->h_front_porch, m->v_front_porch, | ||
59 | m->stereo_mode); | ||
60 | mutex_unlock(&dc->lock); | ||
61 | |||
62 | return res; | ||
63 | } | ||
64 | |||
65 | static DEVICE_ATTR(mode, S_IRUGO, mode_show, NULL); | ||
66 | |||
67 | static ssize_t stats_enable_show(struct device *dev, | ||
68 | struct device_attribute *attr, char *buf) | ||
69 | { | ||
70 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
71 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
72 | bool enabled; | ||
73 | |||
74 | if (mutex_lock_killable(&dc->lock)) | ||
75 | return -EINTR; | ||
76 | enabled = tegra_dc_stats_get(dc); | ||
77 | mutex_unlock(&dc->lock); | ||
78 | |||
79 | return snprintf(buf, PAGE_SIZE, "%d", enabled); | ||
80 | } | ||
81 | |||
82 | static ssize_t stats_enable_store(struct device *dev, | ||
83 | struct device_attribute *attr, const char *buf, size_t count) | ||
84 | { | ||
85 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
86 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
87 | unsigned long val = 0; | ||
88 | |||
89 | if (strict_strtoul(buf, 10, &val) < 0) | ||
90 | return -EINVAL; | ||
91 | |||
92 | if (mutex_lock_killable(&dc->lock)) | ||
93 | return -EINTR; | ||
94 | tegra_dc_stats_enable(dc, !!val); | ||
95 | mutex_unlock(&dc->lock); | ||
96 | |||
97 | return count; | ||
98 | } | ||
99 | |||
100 | static DEVICE_ATTR(stats_enable, S_IRUGO|S_IWUSR, | ||
101 | stats_enable_show, stats_enable_store); | ||
102 | |||
103 | static ssize_t enable_show(struct device *device, | ||
104 | struct device_attribute *attr, char *buf) | ||
105 | { | ||
106 | struct nvhost_device *ndev = to_nvhost_device(device); | ||
107 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
108 | ssize_t res; | ||
109 | |||
110 | mutex_lock(&dc->lock); | ||
111 | res = snprintf(buf, PAGE_SIZE, "%d\n", dc->enabled); | ||
112 | mutex_unlock(&dc->lock); | ||
113 | return res; | ||
114 | } | ||
115 | |||
116 | static ssize_t enable_store(struct device *dev, | ||
117 | struct device_attribute *attr, const char *buf, size_t count) | ||
118 | { | ||
119 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
120 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
121 | unsigned long val = 0; | ||
122 | |||
123 | if (strict_strtoul(buf, 10, &val) < 0) | ||
124 | return -EINVAL; | ||
125 | |||
126 | if (val) { | ||
127 | tegra_dc_enable(dc); | ||
128 | } else { | ||
129 | tegra_dc_disable(dc); | ||
130 | } | ||
131 | |||
132 | return count; | ||
133 | } | ||
134 | |||
135 | static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, enable_show, enable_store); | ||
136 | |||
137 | static ssize_t crc_checksum_latched_show(struct device *device, | ||
138 | struct device_attribute *attr, char *buf) | ||
139 | { | ||
140 | struct nvhost_device *ndev = to_nvhost_device(device); | ||
141 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
142 | |||
143 | u32 crc; | ||
144 | |||
145 | if (!dc->enabled) { | ||
146 | dev_err(&dc->ndev->dev, "Failed to get dc.\n"); | ||
147 | return -EFAULT; | ||
148 | } | ||
149 | |||
150 | crc = tegra_dc_read_checksum_latched(dc); | ||
151 | |||
152 | return snprintf(buf, PAGE_SIZE, "%u", crc); | ||
153 | } | ||
154 | |||
155 | static ssize_t crc_checksum_latched_store(struct device *dev, | ||
156 | struct device_attribute *attr, const char *buf, size_t count) | ||
157 | { | ||
158 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
159 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
160 | unsigned long val = 0; | ||
161 | |||
162 | if (!dc->enabled) { | ||
163 | dev_err(&dc->ndev->dev, "Failed to get dc.\n"); | ||
164 | return -EFAULT; | ||
165 | } | ||
166 | |||
167 | if (strict_strtoul(buf, 10, &val) < 0) | ||
168 | return -EINVAL; | ||
169 | |||
170 | if (val == 1) { | ||
171 | tegra_dc_enable_crc(dc); | ||
172 | dev_err(&dc->ndev->dev, "crc is enabled.\n"); | ||
173 | } else if (val == 0) { | ||
174 | tegra_dc_disable_crc(dc); | ||
175 | dev_err(&dc->ndev->dev, "crc is disabled.\n"); | ||
176 | } else | ||
177 | dev_err(&dc->ndev->dev, "Invalid input.\n"); | ||
178 | |||
179 | return count; | ||
180 | } | ||
181 | static DEVICE_ATTR(crc_checksum_latched, S_IRUGO|S_IWUSR, | ||
182 | crc_checksum_latched_show, crc_checksum_latched_store); | ||
183 | |||
184 | #define ORIENTATION_PORTRAIT "portrait" | ||
185 | #define ORIENTATION_LANDSCAPE "landscape" | ||
186 | |||
187 | static ssize_t orientation_3d_show(struct device *dev, | ||
188 | struct device_attribute *attr, char *buf) | ||
189 | { | ||
190 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
191 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
192 | struct tegra_dc_out *dc_out = dc->out; | ||
193 | const char *orientation; | ||
194 | switch (dc_out->stereo->orientation) { | ||
195 | case TEGRA_DC_STEREO_LANDSCAPE: | ||
196 | orientation = ORIENTATION_LANDSCAPE; | ||
197 | break; | ||
198 | case TEGRA_DC_STEREO_PORTRAIT: | ||
199 | orientation = ORIENTATION_PORTRAIT; | ||
200 | break; | ||
201 | default: | ||
202 | pr_err("Invalid value is stored for stereo_orientation.\n"); | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | return snprintf(buf, PAGE_SIZE, "%s\n", orientation); | ||
206 | } | ||
207 | |||
208 | static ssize_t orientation_3d_store(struct device *dev, | ||
209 | struct device_attribute *attr, const char *buf, size_t cnt) | ||
210 | { | ||
211 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
212 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
213 | struct tegra_dc_out *dc_out = dc->out; | ||
214 | struct tegra_stereo_out *stereo = dc_out->stereo; | ||
215 | int orientation; | ||
216 | |||
217 | if (0 == strncmp(buf, ORIENTATION_PORTRAIT, | ||
218 | min(cnt, ARRAY_SIZE(ORIENTATION_PORTRAIT) - 1))) { | ||
219 | orientation = TEGRA_DC_STEREO_PORTRAIT; | ||
220 | } else if (0 == strncmp(buf, ORIENTATION_LANDSCAPE, | ||
221 | min(cnt, ARRAY_SIZE(ORIENTATION_LANDSCAPE) - 1))) { | ||
222 | orientation = TEGRA_DC_STEREO_LANDSCAPE; | ||
223 | } else { | ||
224 | pr_err("Invalid property value for stereo_orientation.\n"); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | stereo->orientation = orientation; | ||
228 | stereo->set_orientation(orientation); | ||
229 | return cnt; | ||
230 | } | ||
231 | |||
232 | static DEVICE_ATTR(stereo_orientation, | ||
233 | S_IRUGO|S_IWUSR, orientation_3d_show, orientation_3d_store); | ||
234 | |||
235 | #define MODE_2D "2d" | ||
236 | #define MODE_3D "3d" | ||
237 | |||
238 | static ssize_t mode_3d_show(struct device *dev, | ||
239 | struct device_attribute *attr, char *buf) | ||
240 | { | ||
241 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
242 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
243 | struct tegra_dc_out *dc_out = dc->out; | ||
244 | const char *mode; | ||
245 | switch (dc_out->stereo->mode_2d_3d) { | ||
246 | case TEGRA_DC_STEREO_MODE_2D: | ||
247 | mode = MODE_2D; | ||
248 | break; | ||
249 | case TEGRA_DC_STEREO_MODE_3D: | ||
250 | mode = MODE_3D; | ||
251 | break; | ||
252 | default: | ||
253 | pr_err("Invalid value is stored for stereo_mode.\n"); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | return snprintf(buf, PAGE_SIZE, "%s\n", mode); | ||
257 | } | ||
258 | |||
259 | static ssize_t mode_3d_store(struct device *dev, | ||
260 | struct device_attribute *attr, const char *buf, size_t cnt) | ||
261 | { | ||
262 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
263 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
264 | struct tegra_dc_out *dc_out = dc->out; | ||
265 | struct tegra_stereo_out *stereo = dc_out->stereo; | ||
266 | int mode; | ||
267 | |||
268 | if (0 == strncmp(buf, MODE_2D, min(cnt, ARRAY_SIZE(MODE_2D) - 1))) { | ||
269 | mode = TEGRA_DC_STEREO_MODE_2D; | ||
270 | } else if (0 == strncmp(buf, MODE_3D, | ||
271 | min(cnt, ARRAY_SIZE(MODE_3D) - 1))) { | ||
272 | mode = TEGRA_DC_STEREO_MODE_3D; | ||
273 | } else { | ||
274 | pr_err("Invalid property value for stereo_mode.\n"); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | stereo->mode_2d_3d = mode; | ||
278 | stereo->set_mode(mode); | ||
279 | return cnt; | ||
280 | } | ||
281 | |||
282 | static DEVICE_ATTR(stereo_mode, | ||
283 | S_IRUGO|S_IWUSR, mode_3d_show, mode_3d_store); | ||
284 | |||
285 | void __devexit tegra_dc_remove_sysfs(struct device *dev) | ||
286 | { | ||
287 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
288 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
289 | struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; | ||
290 | |||
291 | device_remove_file(dev, &dev_attr_mode); | ||
292 | device_remove_file(dev, &dev_attr_enable); | ||
293 | device_remove_file(dev, &dev_attr_stats_enable); | ||
294 | device_remove_file(dev, &dev_attr_crc_checksum_latched); | ||
295 | |||
296 | if (dc->out->stereo) { | ||
297 | device_remove_file(dev, &dev_attr_stereo_orientation); | ||
298 | device_remove_file(dev, &dev_attr_stereo_mode); | ||
299 | } | ||
300 | |||
301 | if (sd_settings) | ||
302 | nvsd_remove_sysfs(dev); | ||
303 | } | ||
304 | |||
305 | void tegra_dc_create_sysfs(struct device *dev) | ||
306 | { | ||
307 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
308 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
309 | struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; | ||
310 | int error = 0; | ||
311 | |||
312 | error |= device_create_file(dev, &dev_attr_mode); | ||
313 | error |= device_create_file(dev, &dev_attr_enable); | ||
314 | error |= device_create_file(dev, &dev_attr_stats_enable); | ||
315 | error |= device_create_file(dev, &dev_attr_crc_checksum_latched); | ||
316 | |||
317 | if (dc->out->stereo) { | ||
318 | error |= device_create_file(dev, &dev_attr_stereo_orientation); | ||
319 | error |= device_create_file(dev, &dev_attr_stereo_mode); | ||
320 | } | ||
321 | |||
322 | if (sd_settings) | ||
323 | error |= nvsd_create_sysfs(dev); | ||
324 | |||
325 | if (error) | ||
326 | dev_err(&ndev->dev, "Failed to create sysfs attributes!\n"); | ||
327 | } | ||
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c new file mode 100644 index 00000000000..c33d6e0a58b --- /dev/null +++ b/drivers/video/tegra/dc/dsi.c | |||
@@ -0,0 +1,3042 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dsi.c | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/fb.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | |||
28 | #include <mach/clk.h> | ||
29 | #include <mach/dc.h> | ||
30 | #include <mach/fb.h> | ||
31 | #include <mach/csi.h> | ||
32 | #include <linux/nvhost.h> | ||
33 | |||
34 | #include "dc_reg.h" | ||
35 | #include "dc_priv.h" | ||
36 | #include "dsi_regs.h" | ||
37 | #include "dsi.h" | ||
38 | |||
39 | #define DSI_USE_SYNC_POINTS 1 | ||
40 | #define S_TO_MS(x) (1000 * (x)) | ||
41 | |||
42 | #define DSI_MODULE_NOT_INIT 0x0 | ||
43 | #define DSI_MODULE_INIT 0x1 | ||
44 | |||
45 | #define DSI_LPHS_NOT_INIT 0x0 | ||
46 | #define DSI_LPHS_IN_LP_MODE 0x1 | ||
47 | #define DSI_LPHS_IN_HS_MODE 0x2 | ||
48 | |||
49 | #define DSI_VIDEO_TYPE_NOT_INIT 0x0 | ||
50 | #define DSI_VIDEO_TYPE_VIDEO_MODE 0x1 | ||
51 | #define DSI_VIDEO_TYPE_CMD_MODE 0x2 | ||
52 | |||
53 | #define DSI_DRIVEN_MODE_NOT_INIT 0x0 | ||
54 | #define DSI_DRIVEN_MODE_DC 0x1 | ||
55 | #define DSI_DRIVEN_MODE_HOST 0x2 | ||
56 | |||
57 | #define DSI_PHYCLK_OUT_DIS 0x0 | ||
58 | #define DSI_PHYCLK_OUT_EN 0x1 | ||
59 | |||
60 | #define DSI_PHYCLK_NOT_INIT 0x0 | ||
61 | #define DSI_PHYCLK_CONTINUOUS 0x1 | ||
62 | #define DSI_PHYCLK_TX_ONLY 0x2 | ||
63 | |||
64 | #define DSI_CLK_BURST_NOT_INIT 0x0 | ||
65 | #define DSI_CLK_BURST_NONE_BURST 0x1 | ||
66 | #define DSI_CLK_BURST_BURST_MODE 0x2 | ||
67 | |||
68 | #define DSI_DC_STREAM_DISABLE 0x0 | ||
69 | #define DSI_DC_STREAM_ENABLE 0x1 | ||
70 | |||
71 | #define DSI_LP_OP_NOT_INIT 0x0 | ||
72 | #define DSI_LP_OP_WRITE 0x1 | ||
73 | #define DSI_LP_OP_READ 0x2 | ||
74 | |||
75 | static bool enable_read_debug; | ||
76 | module_param(enable_read_debug, bool, 0644); | ||
77 | MODULE_PARM_DESC(enable_read_debug, | ||
78 | "Enable to print read fifo and return packet type"); | ||
79 | |||
80 | struct dsi_status { | ||
81 | unsigned init:2; | ||
82 | |||
83 | unsigned lphs:2; | ||
84 | |||
85 | unsigned vtype:2; | ||
86 | unsigned driven:2; | ||
87 | |||
88 | unsigned clk_out:2; | ||
89 | unsigned clk_mode:2; | ||
90 | unsigned clk_burst:2; | ||
91 | |||
92 | unsigned lp_op:2; | ||
93 | |||
94 | unsigned dc_stream:1; | ||
95 | }; | ||
96 | |||
97 | /* source of video data */ | ||
98 | enum { | ||
99 | TEGRA_DSI_DRIVEN_BY_DC, | ||
100 | TEGRA_DSI_DRIVEN_BY_HOST, | ||
101 | }; | ||
102 | |||
103 | struct tegra_dc_dsi_data { | ||
104 | struct tegra_dc *dc; | ||
105 | void __iomem *base; | ||
106 | struct resource *base_res; | ||
107 | |||
108 | struct clk *dc_clk; | ||
109 | struct clk *dsi_clk; | ||
110 | bool clk_ref; | ||
111 | |||
112 | struct mutex lock; | ||
113 | |||
114 | /* data from board info */ | ||
115 | struct tegra_dsi_out info; | ||
116 | |||
117 | struct dsi_status status; | ||
118 | |||
119 | struct dsi_phy_timing_inclk phy_timing; | ||
120 | |||
121 | u8 driven_mode; | ||
122 | u8 controller_index; | ||
123 | |||
124 | u8 pixel_scaler_mul; | ||
125 | u8 pixel_scaler_div; | ||
126 | |||
127 | u32 default_shift_clk_div; | ||
128 | u32 default_pixel_clk_khz; | ||
129 | u32 default_hs_clk_khz; | ||
130 | |||
131 | u32 shift_clk_div; | ||
132 | u32 target_hs_clk_khz; | ||
133 | u32 target_lp_clk_khz; | ||
134 | |||
135 | u32 syncpt_id; | ||
136 | u32 syncpt_val; | ||
137 | |||
138 | u16 current_bit_clk_ns; | ||
139 | u32 current_dsi_clk_khz; | ||
140 | |||
141 | u32 dsi_control_val; | ||
142 | |||
143 | bool ulpm; | ||
144 | bool enabled; | ||
145 | }; | ||
146 | |||
147 | const u32 dsi_pkt_seq_reg[NUMOF_PKT_SEQ] = { | ||
148 | DSI_PKT_SEQ_0_LO, | ||
149 | DSI_PKT_SEQ_0_HI, | ||
150 | DSI_PKT_SEQ_1_LO, | ||
151 | DSI_PKT_SEQ_1_HI, | ||
152 | DSI_PKT_SEQ_2_LO, | ||
153 | DSI_PKT_SEQ_2_HI, | ||
154 | DSI_PKT_SEQ_3_LO, | ||
155 | DSI_PKT_SEQ_3_HI, | ||
156 | DSI_PKT_SEQ_4_LO, | ||
157 | DSI_PKT_SEQ_4_HI, | ||
158 | DSI_PKT_SEQ_5_LO, | ||
159 | DSI_PKT_SEQ_5_HI, | ||
160 | }; | ||
161 | |||
162 | const u32 dsi_pkt_seq_video_non_burst_syne[NUMOF_PKT_SEQ] = { | ||
163 | PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
164 | 0, | ||
165 | PKT_ID0(CMD_VE) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
166 | 0, | ||
167 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
168 | 0, | ||
169 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(1) | | ||
170 | PKT_ID2(CMD_HE) | PKT_LEN2(0), | ||
171 | PKT_ID3(CMD_BLNK) | PKT_LEN3(2) | PKT_ID4(CMD_RGB) | PKT_LEN4(3) | | ||
172 | PKT_ID5(CMD_BLNK) | PKT_LEN5(4), | ||
173 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
174 | 0, | ||
175 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(1) | | ||
176 | PKT_ID2(CMD_HE) | PKT_LEN2(0), | ||
177 | PKT_ID3(CMD_BLNK) | PKT_LEN3(2) | PKT_ID4(CMD_RGB) | PKT_LEN4(3) | | ||
178 | PKT_ID5(CMD_BLNK) | PKT_LEN5(4), | ||
179 | }; | ||
180 | |||
181 | const u32 dsi_pkt_seq_video_non_burst[NUMOF_PKT_SEQ] = { | ||
182 | PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
183 | 0, | ||
184 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
185 | 0, | ||
186 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
187 | 0, | ||
188 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2) | | ||
189 | PKT_ID2(CMD_RGB) | PKT_LEN2(3), | ||
190 | PKT_ID3(CMD_BLNK) | PKT_LEN3(4), | ||
191 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
192 | 0, | ||
193 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2) | | ||
194 | PKT_ID2(CMD_RGB) | PKT_LEN2(3), | ||
195 | PKT_ID3(CMD_BLNK) | PKT_LEN3(4), | ||
196 | }; | ||
197 | |||
198 | static const u32 dsi_pkt_seq_video_burst[NUMOF_PKT_SEQ] = { | ||
199 | PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP, | ||
200 | 0, | ||
201 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP, | ||
202 | 0, | ||
203 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP, | ||
204 | 0, | ||
205 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)| | ||
206 | PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP, | ||
207 | PKT_ID0(CMD_EOT) | PKT_LEN0(7), | ||
208 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP, | ||
209 | 0, | ||
210 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)| | ||
211 | PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP, | ||
212 | PKT_ID0(CMD_EOT) | PKT_LEN0(7), | ||
213 | }; | ||
214 | |||
215 | static const u32 dsi_pkt_seq_video_burst_no_eot[NUMOF_PKT_SEQ] = { | ||
216 | PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
217 | 0, | ||
218 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
219 | 0, | ||
220 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
221 | 0, | ||
222 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)| | ||
223 | PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP, | ||
224 | PKT_ID0(CMD_EOT) | PKT_LEN0(0), | ||
225 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP, | ||
226 | 0, | ||
227 | PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)| | ||
228 | PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP, | ||
229 | PKT_ID0(CMD_EOT) | PKT_LEN0(0), | ||
230 | }; | ||
231 | |||
232 | /* TODO: verify with hw about this format */ | ||
233 | const u32 dsi_pkt_seq_cmd_mode[NUMOF_PKT_SEQ] = { | ||
234 | 0, | ||
235 | 0, | ||
236 | 0, | ||
237 | 0, | ||
238 | 0, | ||
239 | 0, | ||
240 | PKT_ID0(CMD_LONGW) | PKT_LEN0(3) | PKT_ID1(CMD_EOT) | PKT_LEN1(7), | ||
241 | 0, | ||
242 | 0, | ||
243 | 0, | ||
244 | PKT_ID0(CMD_LONGW) | PKT_LEN0(3) | PKT_ID1(CMD_EOT) | PKT_LEN1(7), | ||
245 | 0, | ||
246 | }; | ||
247 | |||
248 | const u32 init_reg[] = { | ||
249 | DSI_INT_ENABLE, | ||
250 | DSI_INT_STATUS, | ||
251 | DSI_INT_MASK, | ||
252 | DSI_INIT_SEQ_DATA_0, | ||
253 | DSI_INIT_SEQ_DATA_1, | ||
254 | DSI_INIT_SEQ_DATA_2, | ||
255 | DSI_INIT_SEQ_DATA_3, | ||
256 | DSI_INIT_SEQ_DATA_4, | ||
257 | DSI_INIT_SEQ_DATA_5, | ||
258 | DSI_INIT_SEQ_DATA_6, | ||
259 | DSI_INIT_SEQ_DATA_7, | ||
260 | DSI_DCS_CMDS, | ||
261 | DSI_PKT_SEQ_0_LO, | ||
262 | DSI_PKT_SEQ_1_LO, | ||
263 | DSI_PKT_SEQ_2_LO, | ||
264 | DSI_PKT_SEQ_3_LO, | ||
265 | DSI_PKT_SEQ_4_LO, | ||
266 | DSI_PKT_SEQ_5_LO, | ||
267 | DSI_PKT_SEQ_0_HI, | ||
268 | DSI_PKT_SEQ_1_HI, | ||
269 | DSI_PKT_SEQ_2_HI, | ||
270 | DSI_PKT_SEQ_3_HI, | ||
271 | DSI_PKT_SEQ_4_HI, | ||
272 | DSI_PKT_SEQ_5_HI, | ||
273 | DSI_CONTROL, | ||
274 | DSI_HOST_DSI_CONTROL, | ||
275 | DSI_PAD_CONTROL, | ||
276 | DSI_PAD_CONTROL_CD, | ||
277 | DSI_SOL_DELAY, | ||
278 | DSI_MAX_THRESHOLD, | ||
279 | DSI_TRIGGER, | ||
280 | DSI_TX_CRC, | ||
281 | DSI_INIT_SEQ_CONTROL, | ||
282 | DSI_PKT_LEN_0_1, | ||
283 | DSI_PKT_LEN_2_3, | ||
284 | DSI_PKT_LEN_4_5, | ||
285 | DSI_PKT_LEN_6_7, | ||
286 | }; | ||
287 | |||
288 | inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg) | ||
289 | { | ||
290 | BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev)); | ||
291 | return readl(dsi->base + reg * 4); | ||
292 | } | ||
293 | EXPORT_SYMBOL(tegra_dsi_readl); | ||
294 | |||
295 | inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi, u32 val, u32 reg) | ||
296 | { | ||
297 | BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev)); | ||
298 | writel(val, dsi->base + reg * 4); | ||
299 | } | ||
300 | EXPORT_SYMBOL(tegra_dsi_writel); | ||
301 | |||
302 | static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi) | ||
303 | { | ||
304 | u32 val; | ||
305 | int ret; | ||
306 | |||
307 | ret = 0; | ||
308 | |||
309 | dsi->syncpt_val = nvhost_syncpt_read( | ||
310 | &nvhost_get_host(dsi->dc->ndev)->syncpt, | ||
311 | dsi->syncpt_id); | ||
312 | |||
313 | val = DSI_INCR_SYNCPT_COND(OP_DONE) | | ||
314 | DSI_INCR_SYNCPT_INDX(dsi->syncpt_id); | ||
315 | tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT); | ||
316 | |||
317 | /* TODO: Use interrupt rather than polling */ | ||
318 | ret = nvhost_syncpt_wait(&nvhost_get_host(dsi->dc->ndev)->syncpt, | ||
319 | dsi->syncpt_id, dsi->syncpt_val + 1); | ||
320 | if (ret < 0) { | ||
321 | dev_err(&dsi->dc->ndev->dev, "DSI sync point failure\n"); | ||
322 | goto fail; | ||
323 | } | ||
324 | |||
325 | (dsi->syncpt_val)++; | ||
326 | return 0; | ||
327 | fail: | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | static u32 tegra_dsi_get_hs_clk_rate(struct tegra_dc_dsi_data *dsi) | ||
332 | { | ||
333 | u32 dsi_clock_rate_khz; | ||
334 | |||
335 | switch (dsi->info.video_burst_mode) { | ||
336 | case TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED: | ||
337 | case TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED: | ||
338 | case TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED: | ||
339 | case TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED: | ||
340 | /* Calculate DSI HS clock rate for DSI burst mode */ | ||
341 | dsi_clock_rate_khz = dsi->default_pixel_clk_khz * | ||
342 | dsi->shift_clk_div; | ||
343 | break; | ||
344 | case TEGRA_DSI_VIDEO_NONE_BURST_MODE: | ||
345 | case TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END: | ||
346 | case TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED: | ||
347 | default: | ||
348 | /* Clock rate is default DSI clock rate for non-burst mode */ | ||
349 | dsi_clock_rate_khz = dsi->default_hs_clk_khz; | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | return dsi_clock_rate_khz; | ||
354 | } | ||
355 | |||
356 | static u32 tegra_dsi_get_lp_clk_rate(struct tegra_dc_dsi_data *dsi, u8 lp_op) | ||
357 | { | ||
358 | u32 dsi_clock_rate_khz; | ||
359 | |||
360 | if (dsi->info.enable_hs_clock_on_lp_cmd_mode) | ||
361 | if (dsi->info.hs_clk_in_lp_cmd_mode_freq_khz) | ||
362 | dsi_clock_rate_khz = | ||
363 | dsi->info.hs_clk_in_lp_cmd_mode_freq_khz; | ||
364 | else | ||
365 | dsi_clock_rate_khz = tegra_dsi_get_hs_clk_rate(dsi); | ||
366 | else | ||
367 | if (lp_op == DSI_LP_OP_READ) | ||
368 | dsi_clock_rate_khz = | ||
369 | dsi->info.lp_read_cmd_mode_freq_khz; | ||
370 | else | ||
371 | dsi_clock_rate_khz = | ||
372 | dsi->info.lp_cmd_mode_freq_khz; | ||
373 | |||
374 | return dsi_clock_rate_khz; | ||
375 | } | ||
376 | |||
377 | static u32 tegra_dsi_get_shift_clk_div(struct tegra_dc_dsi_data *dsi) | ||
378 | { | ||
379 | u32 shift_clk_div; | ||
380 | u32 max_shift_clk_div; | ||
381 | u32 burst_width; | ||
382 | u32 burst_width_max; | ||
383 | |||
384 | /* Get the real value of default shift_clk_div. default_shift_clk_div | ||
385 | * holds the real value of shift_clk_div. | ||
386 | */ | ||
387 | shift_clk_div = dsi->default_shift_clk_div; | ||
388 | |||
389 | /* Calculate shift_clk_div which can matche the video_burst_mode. */ | ||
390 | if (dsi->info.video_burst_mode >= | ||
391 | TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED) { | ||
392 | /* The max_shift_clk_div is multiplied by 10 to save the | ||
393 | * fraction | ||
394 | */ | ||
395 | if (dsi->info.max_panel_freq_khz >= dsi->default_hs_clk_khz) | ||
396 | max_shift_clk_div = dsi->info.max_panel_freq_khz | ||
397 | * shift_clk_div * 10 / dsi->default_hs_clk_khz; | ||
398 | else | ||
399 | max_shift_clk_div = shift_clk_div * 10; | ||
400 | |||
401 | burst_width = dsi->info.video_burst_mode | ||
402 | - TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED; | ||
403 | burst_width_max = TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED | ||
404 | - TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED; | ||
405 | |||
406 | shift_clk_div = (max_shift_clk_div - shift_clk_div * 10) * | ||
407 | burst_width / (burst_width_max * 10) + shift_clk_div; | ||
408 | } | ||
409 | |||
410 | return shift_clk_div; | ||
411 | } | ||
412 | |||
413 | static void tegra_dsi_init_sw(struct tegra_dc *dc, | ||
414 | struct tegra_dc_dsi_data *dsi) | ||
415 | { | ||
416 | u32 h_width_pixels; | ||
417 | u32 v_width_lines; | ||
418 | u32 pixel_clk_hz; | ||
419 | u32 byte_clk_hz; | ||
420 | u32 plld_clk_mhz; | ||
421 | |||
422 | switch (dsi->info.pixel_format) { | ||
423 | case TEGRA_DSI_PIXEL_FORMAT_16BIT_P: | ||
424 | /* 2 bytes per pixel */ | ||
425 | dsi->pixel_scaler_mul = 2; | ||
426 | dsi->pixel_scaler_div = 1; | ||
427 | break; | ||
428 | case TEGRA_DSI_PIXEL_FORMAT_18BIT_P: | ||
429 | /* 2.25 bytes per pixel */ | ||
430 | dsi->pixel_scaler_mul = 9; | ||
431 | dsi->pixel_scaler_div = 4; | ||
432 | break; | ||
433 | case TEGRA_DSI_PIXEL_FORMAT_18BIT_NP: | ||
434 | case TEGRA_DSI_PIXEL_FORMAT_24BIT_P: | ||
435 | /* 3 bytes per pixel */ | ||
436 | dsi->pixel_scaler_mul = 3; | ||
437 | dsi->pixel_scaler_div = 1; | ||
438 | break; | ||
439 | default: | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | dsi->controller_index = dc->ndev->id; | ||
444 | dsi->ulpm = false; | ||
445 | dsi->enabled = false; | ||
446 | dsi->clk_ref = false; | ||
447 | |||
448 | dsi->dsi_control_val = | ||
449 | DSI_CONTROL_VIRTUAL_CHANNEL(dsi->info.virtual_channel) | | ||
450 | DSI_CONTROL_NUM_DATA_LANES(dsi->info.n_data_lanes - 1) | | ||
451 | DSI_CONTROL_VID_SOURCE(dsi->controller_index) | | ||
452 | DSI_CONTROL_DATA_FORMAT(dsi->info.pixel_format); | ||
453 | |||
454 | /* Below we are going to calculate dsi and dc clock rate. | ||
455 | * Calcuate the horizontal and vertical width. | ||
456 | */ | ||
457 | h_width_pixels = dc->mode.h_back_porch + dc->mode.h_front_porch + | ||
458 | dc->mode.h_sync_width + dc->mode.h_active; | ||
459 | v_width_lines = dc->mode.v_back_porch + dc->mode.v_front_porch + | ||
460 | dc->mode.v_sync_width + dc->mode.v_active; | ||
461 | |||
462 | /* Calculate minimum required pixel rate. */ | ||
463 | pixel_clk_hz = h_width_pixels * v_width_lines * dsi->info.refresh_rate; | ||
464 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { | ||
465 | if (dsi->info.rated_refresh_rate >= dsi->info.refresh_rate) | ||
466 | dev_info(&dc->ndev->dev, "DSI: measured refresh rate " | ||
467 | "should be larger than rated refresh rate.\n"); | ||
468 | dc->mode.rated_pclk = h_width_pixels * v_width_lines * | ||
469 | dsi->info.rated_refresh_rate; | ||
470 | } | ||
471 | |||
472 | /* Calculate minimum byte rate on DSI interface. */ | ||
473 | byte_clk_hz = (pixel_clk_hz * dsi->pixel_scaler_mul) / | ||
474 | (dsi->pixel_scaler_div * dsi->info.n_data_lanes); | ||
475 | |||
476 | /* Round up to multiple of mega hz. */ | ||
477 | plld_clk_mhz = DIV_ROUND_UP((byte_clk_hz * NUMOF_BIT_PER_BYTE), | ||
478 | 1000000); | ||
479 | |||
480 | /* Calculate default real shift_clk_div. */ | ||
481 | dsi->default_shift_clk_div = (NUMOF_BIT_PER_BYTE / 2) * | ||
482 | dsi->pixel_scaler_mul / (dsi->pixel_scaler_div * | ||
483 | dsi->info.n_data_lanes); | ||
484 | /* Calculate default DSI hs clock. DSI interface is double data rate. | ||
485 | * Data is transferred on both rising and falling edge of clk, div by 2 | ||
486 | * to get the actual clock rate. | ||
487 | */ | ||
488 | dsi->default_hs_clk_khz = plld_clk_mhz * 1000 / 2; | ||
489 | dsi->default_pixel_clk_khz = plld_clk_mhz * 1000 / 2 | ||
490 | / dsi->default_shift_clk_div; | ||
491 | |||
492 | /* Get the actual shift_clk_div and clock rates. */ | ||
493 | dsi->shift_clk_div = tegra_dsi_get_shift_clk_div(dsi); | ||
494 | dsi->target_lp_clk_khz = | ||
495 | tegra_dsi_get_lp_clk_rate(dsi, DSI_LP_OP_WRITE); | ||
496 | dsi->target_hs_clk_khz = tegra_dsi_get_hs_clk_rate(dsi); | ||
497 | |||
498 | dev_info(&dc->ndev->dev, "DSI: HS clock rate is %d\n", | ||
499 | dsi->target_hs_clk_khz); | ||
500 | |||
501 | dsi->controller_index = dc->ndev->id; | ||
502 | |||
503 | #if DSI_USE_SYNC_POINTS | ||
504 | dsi->syncpt_id = NVSYNCPT_DSI; | ||
505 | #endif | ||
506 | |||
507 | /* | ||
508 | * Force video clock to be continuous mode if | ||
509 | * enable_hs_clock_on_lp_cmd_mode is set | ||
510 | */ | ||
511 | if (dsi->info.enable_hs_clock_on_lp_cmd_mode) { | ||
512 | if (dsi->info.video_clock_mode != | ||
513 | TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS) | ||
514 | dev_warn(&dc->ndev->dev, | ||
515 | "Force clock continuous mode\n"); | ||
516 | |||
517 | dsi->info.video_clock_mode = TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS; | ||
518 | } | ||
519 | |||
520 | } | ||
521 | |||
522 | #define SELECT_T_PHY(platform_t_phy_ns, default_phy, clk_ns, hw_inc) ( \ | ||
523 | (platform_t_phy_ns) ? ( \ | ||
524 | ((DSI_CONVERT_T_PHY_NS_TO_T_PHY(platform_t_phy_ns, clk_ns, hw_inc)) < 0 ? 0 : \ | ||
525 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY(platform_t_phy_ns, clk_ns, hw_inc)))) : \ | ||
526 | ((default_phy) < 0 ? 0 : (default_phy))) | ||
527 | |||
528 | static void tegra_dsi_get_clk_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
529 | struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns) | ||
530 | { | ||
531 | phy_timing_clk->t_tlpx = SELECT_T_PHY( | ||
532 | dsi->info.phy_timing.t_tlpx_ns, | ||
533 | T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC); | ||
534 | |||
535 | phy_timing_clk->t_clktrail = SELECT_T_PHY( | ||
536 | dsi->info.phy_timing.t_clktrail_ns, | ||
537 | T_CLKTRAIL_DEFAULT(clk_ns), clk_ns, T_CLKTRAIL_HW_INC); | ||
538 | |||
539 | phy_timing_clk->t_clkpost = SELECT_T_PHY( | ||
540 | dsi->info.phy_timing.t_clkpost_ns, | ||
541 | T_CLKPOST_DEFAULT(clk_ns), clk_ns, T_CLKPOST_HW_INC); | ||
542 | |||
543 | phy_timing_clk->t_clkzero = SELECT_T_PHY( | ||
544 | dsi->info.phy_timing.t_clkzero_ns, | ||
545 | T_CLKZERO_DEFAULT(clk_ns), clk_ns, T_CLKZERO_HW_INC); | ||
546 | |||
547 | phy_timing_clk->t_clkprepare = SELECT_T_PHY( | ||
548 | dsi->info.phy_timing.t_clkprepare_ns, | ||
549 | T_CLKPREPARE_DEFAULT(clk_ns), clk_ns, T_CLKPREPARE_HW_INC); | ||
550 | |||
551 | phy_timing_clk->t_clkpre = SELECT_T_PHY( | ||
552 | dsi->info.phy_timing.t_clkpre_ns, | ||
553 | T_CLKPRE_DEFAULT, clk_ns, T_CLKPRE_HW_INC); | ||
554 | } | ||
555 | |||
556 | static void tegra_dsi_get_hs_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
557 | struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns) | ||
558 | { | ||
559 | phy_timing_clk->t_tlpx = SELECT_T_PHY( | ||
560 | dsi->info.phy_timing.t_tlpx_ns, | ||
561 | T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC); | ||
562 | |||
563 | phy_timing_clk->t_hsdexit = SELECT_T_PHY( | ||
564 | dsi->info.phy_timing.t_hsdexit_ns, | ||
565 | T_HSEXIT_DEFAULT(clk_ns), clk_ns, T_HSEXIT_HW_INC); | ||
566 | |||
567 | phy_timing_clk->t_hstrail = SELECT_T_PHY( | ||
568 | dsi->info.phy_timing.t_hstrail_ns, | ||
569 | T_HSTRAIL_DEFAULT(clk_ns), clk_ns, T_HSTRAIL_HW_INC); | ||
570 | |||
571 | phy_timing_clk->t_datzero = SELECT_T_PHY( | ||
572 | dsi->info.phy_timing.t_datzero_ns, | ||
573 | T_DATZERO_DEFAULT(clk_ns), clk_ns, T_DATZERO_HW_INC); | ||
574 | |||
575 | phy_timing_clk->t_hsprepare = SELECT_T_PHY( | ||
576 | dsi->info.phy_timing.t_hsprepare_ns, | ||
577 | T_HSPREPARE_DEFAULT(clk_ns), clk_ns, T_HSPREPARE_HW_INC); | ||
578 | } | ||
579 | |||
580 | static void tegra_dsi_get_escape_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
581 | struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns) | ||
582 | { | ||
583 | phy_timing_clk->t_tlpx = SELECT_T_PHY( | ||
584 | dsi->info.phy_timing.t_tlpx_ns, | ||
585 | T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC); | ||
586 | } | ||
587 | |||
588 | static void tegra_dsi_get_bta_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
589 | struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns) | ||
590 | { | ||
591 | phy_timing_clk->t_tlpx = SELECT_T_PHY( | ||
592 | dsi->info.phy_timing.t_tlpx_ns, | ||
593 | T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC); | ||
594 | |||
595 | phy_timing_clk->t_taget = SELECT_T_PHY( | ||
596 | dsi->info.phy_timing.t_taget_ns, | ||
597 | T_TAGET_DEFAULT(clk_ns), clk_ns, T_TAGET_HW_INC); | ||
598 | |||
599 | phy_timing_clk->t_tasure = SELECT_T_PHY( | ||
600 | dsi->info.phy_timing.t_tasure_ns, | ||
601 | T_TASURE_DEFAULT(clk_ns), clk_ns, T_TASURE_HW_INC); | ||
602 | |||
603 | phy_timing_clk->t_tago = SELECT_T_PHY( | ||
604 | dsi->info.phy_timing.t_tago_ns, | ||
605 | T_TAGO_DEFAULT(clk_ns), clk_ns, T_TAGO_HW_INC); | ||
606 | } | ||
607 | |||
608 | static void tegra_dsi_get_ulps_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
609 | struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns) | ||
610 | { | ||
611 | phy_timing_clk->t_tlpx = SELECT_T_PHY( | ||
612 | dsi->info.phy_timing.t_tlpx_ns, | ||
613 | T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC); | ||
614 | |||
615 | phy_timing_clk->t_wakeup = SELECT_T_PHY( | ||
616 | dsi->info.phy_timing.t_wakeup_ns, | ||
617 | T_WAKEUP_DEFAULT, clk_ns, T_WAKEUP_HW_INC); | ||
618 | } | ||
619 | |||
620 | #undef SELECT_T_PHY | ||
621 | |||
622 | static void tegra_dsi_get_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
623 | struct dsi_phy_timing_inclk *phy_timing_clk, | ||
624 | u32 clk_ns, u8 lphs) | ||
625 | { | ||
626 | if (lphs == DSI_LPHS_IN_HS_MODE) { | ||
627 | tegra_dsi_get_clk_phy_timing(dsi, phy_timing_clk, clk_ns); | ||
628 | tegra_dsi_get_hs_phy_timing(dsi, phy_timing_clk, clk_ns); | ||
629 | } else { | ||
630 | /* default is LP mode */ | ||
631 | tegra_dsi_get_escape_phy_timing(dsi, phy_timing_clk, clk_ns); | ||
632 | tegra_dsi_get_bta_phy_timing(dsi, phy_timing_clk, clk_ns); | ||
633 | tegra_dsi_get_ulps_phy_timing(dsi, phy_timing_clk, clk_ns); | ||
634 | if (dsi->info.enable_hs_clock_on_lp_cmd_mode) | ||
635 | tegra_dsi_get_clk_phy_timing | ||
636 | (dsi, phy_timing_clk, clk_ns); | ||
637 | } | ||
638 | } | ||
639 | |||
640 | static int tegra_dsi_mipi_phy_timing_range(struct tegra_dc_dsi_data *dsi, | ||
641 | struct dsi_phy_timing_inclk *phy_timing, | ||
642 | u32 clk_ns, u8 lphs) | ||
643 | { | ||
644 | #define CHECK_RANGE(val, min, max) ( \ | ||
645 | ((min) == NOT_DEFINED ? 0 : (val) < (min)) || \ | ||
646 | ((max) == NOT_DEFINED ? 0 : (val) > (max)) ? -EINVAL : 0) | ||
647 | |||
648 | int err = 0; | ||
649 | |||
650 | err = CHECK_RANGE( | ||
651 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
652 | phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC), | ||
653 | MIPI_T_TLPX_NS_MIN, MIPI_T_TLPX_NS_MAX); | ||
654 | if (err < 0) { | ||
655 | dev_warn(&dsi->dc->ndev->dev, | ||
656 | "dsi: Tlpx mipi range violated\n"); | ||
657 | goto fail; | ||
658 | } | ||
659 | |||
660 | if (lphs == DSI_LPHS_IN_HS_MODE) { | ||
661 | err = CHECK_RANGE( | ||
662 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
663 | phy_timing->t_hsdexit, clk_ns, T_HSEXIT_HW_INC), | ||
664 | MIPI_T_HSEXIT_NS_MIN, MIPI_T_HSEXIT_NS_MAX); | ||
665 | if (err < 0) { | ||
666 | dev_warn(&dsi->dc->ndev->dev, | ||
667 | "dsi: HsExit mipi range violated\n"); | ||
668 | goto fail; | ||
669 | } | ||
670 | |||
671 | err = CHECK_RANGE( | ||
672 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
673 | phy_timing->t_hstrail, clk_ns, T_HSTRAIL_HW_INC), | ||
674 | MIPI_T_HSTRAIL_NS_MIN(clk_ns), MIPI_T_HSTRAIL_NS_MAX); | ||
675 | if (err < 0) { | ||
676 | dev_warn(&dsi->dc->ndev->dev, | ||
677 | "dsi: HsTrail mipi range violated\n"); | ||
678 | goto fail; | ||
679 | } | ||
680 | |||
681 | err = CHECK_RANGE( | ||
682 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
683 | phy_timing->t_datzero, clk_ns, T_DATZERO_HW_INC), | ||
684 | MIPI_T_HSZERO_NS_MIN, MIPI_T_HSZERO_NS_MAX); | ||
685 | if (err < 0) { | ||
686 | dev_warn(&dsi->dc->ndev->dev, | ||
687 | "dsi: HsZero mipi range violated\n"); | ||
688 | goto fail; | ||
689 | } | ||
690 | |||
691 | err = CHECK_RANGE( | ||
692 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
693 | phy_timing->t_hsprepare, clk_ns, T_HSPREPARE_HW_INC), | ||
694 | MIPI_T_HSPREPARE_NS_MIN(clk_ns), | ||
695 | MIPI_T_HSPREPARE_NS_MAX(clk_ns)); | ||
696 | if (err < 0) { | ||
697 | dev_warn(&dsi->dc->ndev->dev, | ||
698 | "dsi: HsPrepare mipi range violated\n"); | ||
699 | goto fail; | ||
700 | } | ||
701 | |||
702 | err = CHECK_RANGE( | ||
703 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
704 | phy_timing->t_hsprepare, clk_ns, T_HSPREPARE_HW_INC) + | ||
705 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
706 | phy_timing->t_datzero, clk_ns, T_DATZERO_HW_INC), | ||
707 | MIPI_T_HSPREPARE_ADD_HSZERO_NS_MIN(clk_ns), | ||
708 | MIPI_T_HSPREPARE_ADD_HSZERO_NS_MAX); | ||
709 | if (err < 0) { | ||
710 | dev_warn(&dsi->dc->ndev->dev, | ||
711 | "dsi: HsPrepare + HsZero mipi range violated\n"); | ||
712 | goto fail; | ||
713 | } | ||
714 | } else { | ||
715 | /* default is LP mode */ | ||
716 | err = CHECK_RANGE( | ||
717 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
718 | phy_timing->t_wakeup, clk_ns, T_WAKEUP_HW_INC), | ||
719 | MIPI_T_WAKEUP_NS_MIN, MIPI_T_WAKEUP_NS_MAX); | ||
720 | if (err < 0) { | ||
721 | dev_warn(&dsi->dc->ndev->dev, | ||
722 | "dsi: WakeUp mipi range violated\n"); | ||
723 | goto fail; | ||
724 | } | ||
725 | |||
726 | err = CHECK_RANGE( | ||
727 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
728 | phy_timing->t_tasure, clk_ns, T_TASURE_HW_INC), | ||
729 | MIPI_T_TASURE_NS_MIN(DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
730 | phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC)), | ||
731 | MIPI_T_TASURE_NS_MAX(DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
732 | phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC))); | ||
733 | if (err < 0) { | ||
734 | dev_warn(&dsi->dc->ndev->dev, | ||
735 | "dsi: TaSure mipi range violated\n"); | ||
736 | goto fail; | ||
737 | } | ||
738 | } | ||
739 | |||
740 | if (lphs == DSI_LPHS_IN_HS_MODE || | ||
741 | dsi->info.enable_hs_clock_on_lp_cmd_mode) { | ||
742 | err = CHECK_RANGE( | ||
743 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
744 | phy_timing->t_clktrail, clk_ns, T_CLKTRAIL_HW_INC), | ||
745 | MIPI_T_CLKTRAIL_NS_MIN, MIPI_T_CLKTRAIL_NS_MAX); | ||
746 | if (err < 0) { | ||
747 | dev_warn(&dsi->dc->ndev->dev, | ||
748 | "dsi: ClkTrail mipi range violated\n"); | ||
749 | goto fail; | ||
750 | } | ||
751 | |||
752 | err = CHECK_RANGE( | ||
753 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
754 | phy_timing->t_clkpost, clk_ns, T_CLKPOST_HW_INC), | ||
755 | MIPI_T_CLKPOST_NS_MIN(clk_ns), MIPI_T_CLKPOST_NS_MAX); | ||
756 | if (err < 0) { | ||
757 | dev_warn(&dsi->dc->ndev->dev, | ||
758 | "dsi: ClkPost mipi range violated\n"); | ||
759 | goto fail; | ||
760 | } | ||
761 | |||
762 | err = CHECK_RANGE( | ||
763 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
764 | phy_timing->t_clkzero, clk_ns, T_CLKZERO_HW_INC), | ||
765 | MIPI_T_CLKZERO_NS_MIN, MIPI_T_CLKZERO_NS_MAX); | ||
766 | if (err < 0) { | ||
767 | dev_warn(&dsi->dc->ndev->dev, | ||
768 | "dsi: ClkZero mipi range violated\n"); | ||
769 | goto fail; | ||
770 | } | ||
771 | |||
772 | err = CHECK_RANGE( | ||
773 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
774 | phy_timing->t_clkprepare, clk_ns, T_CLKPREPARE_HW_INC), | ||
775 | MIPI_T_CLKPREPARE_NS_MIN, MIPI_T_CLKPREPARE_NS_MAX); | ||
776 | if (err < 0) { | ||
777 | dev_warn(&dsi->dc->ndev->dev, | ||
778 | "dsi: ClkPrepare mipi range violated\n"); | ||
779 | goto fail; | ||
780 | } | ||
781 | |||
782 | err = CHECK_RANGE( | ||
783 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
784 | phy_timing->t_clkpre, clk_ns, T_CLKPRE_HW_INC), | ||
785 | MIPI_T_CLKPRE_NS_MIN, MIPI_T_CLKPRE_NS_MAX); | ||
786 | if (err < 0) { | ||
787 | dev_warn(&dsi->dc->ndev->dev, | ||
788 | "dsi: ClkPre mipi range violated\n"); | ||
789 | goto fail; | ||
790 | } | ||
791 | |||
792 | err = CHECK_RANGE( | ||
793 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
794 | phy_timing->t_clkprepare, clk_ns, T_CLKPREPARE_HW_INC) + | ||
795 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
796 | phy_timing->t_clkzero, clk_ns, T_CLKZERO_HW_INC), | ||
797 | MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MIN, | ||
798 | MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MAX); | ||
799 | if (err < 0) { | ||
800 | dev_warn(&dsi->dc->ndev->dev, | ||
801 | "dsi: ClkPrepare + ClkZero mipi range violated\n"); | ||
802 | goto fail; | ||
803 | } | ||
804 | } | ||
805 | fail: | ||
806 | #undef CHECK_RANGE | ||
807 | return err; | ||
808 | } | ||
809 | |||
810 | static int tegra_dsi_hs_phy_len(struct tegra_dc_dsi_data *dsi, | ||
811 | struct dsi_phy_timing_inclk *phy_timing, | ||
812 | u32 clk_ns, u8 lphs) | ||
813 | { | ||
814 | u32 hs_t_phy_ns; | ||
815 | u32 clk_t_phy_ns; | ||
816 | u32 t_phy_ns; | ||
817 | u32 h_blank_ns; | ||
818 | struct tegra_dc_mode *modes; | ||
819 | u32 t_pix_ns; | ||
820 | int err = 0; | ||
821 | |||
822 | if (!(lphs == DSI_LPHS_IN_HS_MODE)) | ||
823 | goto fail; | ||
824 | |||
825 | modes = dsi->dc->out->modes; | ||
826 | t_pix_ns = clk_ns * BITS_PER_BYTE * | ||
827 | dsi->pixel_scaler_mul / dsi->pixel_scaler_div; | ||
828 | |||
829 | hs_t_phy_ns = | ||
830 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
831 | phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC) + | ||
832 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
833 | phy_timing->t_hsprepare, clk_ns, T_HSPREPARE_HW_INC) + | ||
834 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
835 | phy_timing->t_datzero, clk_ns, T_DATZERO_HW_INC) + | ||
836 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
837 | phy_timing->t_hstrail, clk_ns, T_HSTRAIL_HW_INC) + | ||
838 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
839 | phy_timing->t_hsdexit, clk_ns, T_HSEXIT_HW_INC); | ||
840 | |||
841 | clk_t_phy_ns = | ||
842 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
843 | phy_timing->t_clkpost, clk_ns, T_CLKPOST_HW_INC) + | ||
844 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
845 | phy_timing->t_clktrail, clk_ns, T_CLKTRAIL_HW_INC) + | ||
846 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
847 | phy_timing->t_hsdexit, clk_ns, T_HSEXIT_HW_INC) + | ||
848 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
849 | phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC) + | ||
850 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
851 | phy_timing->t_clkprepare, clk_ns, T_CLKPREPARE_HW_INC) + | ||
852 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
853 | phy_timing->t_clkzero, clk_ns, T_CLKZERO_HW_INC) + | ||
854 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
855 | phy_timing->t_clkpre, clk_ns, T_CLKPRE_HW_INC); | ||
856 | |||
857 | h_blank_ns = t_pix_ns * (modes->h_sync_width + modes->h_back_porch + | ||
858 | modes->h_front_porch); | ||
859 | |||
860 | /* Extra tlpx and byte cycle required by dsi HW */ | ||
861 | t_phy_ns = dsi->info.n_data_lanes * (hs_t_phy_ns + clk_t_phy_ns + | ||
862 | DSI_CONVERT_T_PHY_TO_T_PHY_NS( | ||
863 | phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC) + | ||
864 | clk_ns * BITS_PER_BYTE); | ||
865 | |||
866 | if (h_blank_ns < t_phy_ns) { | ||
867 | err = -EINVAL; | ||
868 | dev_err(&dsi->dc->ndev->dev, | ||
869 | "dsi: Hblank is smaller than HS trans phy timing\n"); | ||
870 | goto fail; | ||
871 | } | ||
872 | |||
873 | return 0; | ||
874 | fail: | ||
875 | return err; | ||
876 | } | ||
877 | |||
878 | static int tegra_dsi_constraint_phy_timing(struct tegra_dc_dsi_data *dsi, | ||
879 | struct dsi_phy_timing_inclk *phy_timing, | ||
880 | u32 clk_ns, u8 lphs) | ||
881 | { | ||
882 | int err = 0; | ||
883 | |||
884 | err = tegra_dsi_mipi_phy_timing_range(dsi, phy_timing, clk_ns, lphs); | ||
885 | if (err < 0) { | ||
886 | dev_warn(&dsi->dc->ndev->dev, "dsi: mipi range violated\n"); | ||
887 | goto fail; | ||
888 | } | ||
889 | |||
890 | err = tegra_dsi_hs_phy_len(dsi, phy_timing, clk_ns, lphs); | ||
891 | if (err < 0) { | ||
892 | dev_err(&dsi->dc->ndev->dev, "dsi: Hblank too short\n"); | ||
893 | goto fail; | ||
894 | } | ||
895 | |||
896 | /* TODO: add more contraints */ | ||
897 | fail: | ||
898 | return err; | ||
899 | } | ||
900 | |||
901 | static void tegra_dsi_set_phy_timing(struct tegra_dc_dsi_data *dsi, u8 lphs) | ||
902 | { | ||
903 | u32 val; | ||
904 | struct dsi_phy_timing_inclk phy_timing = dsi->phy_timing; | ||
905 | |||
906 | tegra_dsi_get_phy_timing | ||
907 | (dsi, &phy_timing, dsi->current_bit_clk_ns, lphs); | ||
908 | |||
909 | tegra_dsi_constraint_phy_timing(dsi, &phy_timing, | ||
910 | dsi->current_bit_clk_ns, lphs); | ||
911 | |||
912 | val = DSI_PHY_TIMING_0_THSDEXIT(phy_timing.t_hsdexit) | | ||
913 | DSI_PHY_TIMING_0_THSTRAIL(phy_timing.t_hstrail) | | ||
914 | DSI_PHY_TIMING_0_TDATZERO(phy_timing.t_datzero) | | ||
915 | DSI_PHY_TIMING_0_THSPREPR(phy_timing.t_hsprepare); | ||
916 | tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_0); | ||
917 | |||
918 | val = DSI_PHY_TIMING_1_TCLKTRAIL(phy_timing.t_clktrail) | | ||
919 | DSI_PHY_TIMING_1_TCLKPOST(phy_timing.t_clkpost) | | ||
920 | DSI_PHY_TIMING_1_TCLKZERO(phy_timing.t_clkzero) | | ||
921 | DSI_PHY_TIMING_1_TTLPX(phy_timing.t_tlpx); | ||
922 | tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_1); | ||
923 | |||
924 | val = DSI_PHY_TIMING_2_TCLKPREPARE(phy_timing.t_clkprepare) | | ||
925 | DSI_PHY_TIMING_2_TCLKPRE(phy_timing.t_clkpre) | | ||
926 | DSI_PHY_TIMING_2_TWAKEUP(phy_timing.t_wakeup); | ||
927 | tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_2); | ||
928 | |||
929 | val = DSI_BTA_TIMING_TTAGET(phy_timing.t_taget) | | ||
930 | DSI_BTA_TIMING_TTASURE(phy_timing.t_tasure) | | ||
931 | DSI_BTA_TIMING_TTAGO(phy_timing.t_tago); | ||
932 | tegra_dsi_writel(dsi, val, DSI_BTA_TIMING); | ||
933 | |||
934 | dsi->phy_timing = phy_timing; | ||
935 | } | ||
936 | |||
937 | static u32 tegra_dsi_sol_delay_burst(struct tegra_dc *dc, | ||
938 | struct tegra_dc_dsi_data *dsi) | ||
939 | { | ||
940 | u32 dsi_to_pixel_clk_ratio; | ||
941 | u32 temp; | ||
942 | u32 temp1; | ||
943 | u32 mipi_clk_adj_kHz; | ||
944 | u32 sol_delay; | ||
945 | struct tegra_dc_mode *dc_modes = &dc->mode; | ||
946 | |||
947 | /* Get Fdsi/Fpixel ration (note: Fdsi is in bit format) */ | ||
948 | dsi_to_pixel_clk_ratio = (dsi->current_dsi_clk_khz * 2 + | ||
949 | dsi->default_pixel_clk_khz - 1) / dsi->default_pixel_clk_khz; | ||
950 | |||
951 | /* Convert Fdsi to byte format */ | ||
952 | dsi_to_pixel_clk_ratio *= 1000/8; | ||
953 | |||
954 | /* Multiplying by 1000 so that we don't loose the fraction part */ | ||
955 | temp = dc_modes->h_active * 1000; | ||
956 | temp1 = dc_modes->h_active + dc_modes->h_back_porch + | ||
957 | dc_modes->h_sync_width; | ||
958 | |||
959 | sol_delay = temp1 * dsi_to_pixel_clk_ratio - | ||
960 | temp * dsi->pixel_scaler_mul / | ||
961 | (dsi->pixel_scaler_div * dsi->info.n_data_lanes); | ||
962 | |||
963 | /* Do rounding on sol delay */ | ||
964 | sol_delay = (sol_delay + 1000 - 1)/1000; | ||
965 | |||
966 | /* TODO: | ||
967 | * 1. find out the correct sol fifo depth to use | ||
968 | * 2. verify with hw about the clamping function | ||
969 | */ | ||
970 | if (sol_delay > (480 * 4)) { | ||
971 | sol_delay = (480 * 4); | ||
972 | mipi_clk_adj_kHz = sol_delay + | ||
973 | (dc_modes->h_active * dsi->pixel_scaler_mul) / | ||
974 | (dsi->info.n_data_lanes * dsi->pixel_scaler_div); | ||
975 | |||
976 | mipi_clk_adj_kHz *= (dsi->default_pixel_clk_khz / temp1); | ||
977 | |||
978 | mipi_clk_adj_kHz *= 4; | ||
979 | } | ||
980 | |||
981 | dsi->target_hs_clk_khz = mipi_clk_adj_kHz; | ||
982 | |||
983 | return sol_delay; | ||
984 | } | ||
985 | |||
986 | static void tegra_dsi_set_sol_delay(struct tegra_dc *dc, | ||
987 | struct tegra_dc_dsi_data *dsi) | ||
988 | { | ||
989 | u32 sol_delay; | ||
990 | |||
991 | if (dsi->info.video_burst_mode == TEGRA_DSI_VIDEO_NONE_BURST_MODE || | ||
992 | dsi->info.video_burst_mode == | ||
993 | TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END) { | ||
994 | #define VIDEO_FIFO_LATENCY_PIXEL_CLK 8 | ||
995 | sol_delay = VIDEO_FIFO_LATENCY_PIXEL_CLK * | ||
996 | dsi->pixel_scaler_mul / dsi->pixel_scaler_div; | ||
997 | #undef VIDEO_FIFO_LATENCY_PIXEL_CLK | ||
998 | dsi->status.clk_burst = DSI_CLK_BURST_NONE_BURST; | ||
999 | } else { | ||
1000 | sol_delay = tegra_dsi_sol_delay_burst(dc, dsi); | ||
1001 | dsi->status.clk_burst = DSI_CLK_BURST_BURST_MODE; | ||
1002 | } | ||
1003 | |||
1004 | tegra_dsi_writel(dsi, DSI_SOL_DELAY_SOL_DELAY(sol_delay), | ||
1005 | DSI_SOL_DELAY); | ||
1006 | } | ||
1007 | |||
1008 | static void tegra_dsi_set_timeout(struct tegra_dc_dsi_data *dsi) | ||
1009 | { | ||
1010 | u32 val; | ||
1011 | u32 bytes_per_frame; | ||
1012 | u32 timeout = 0; | ||
1013 | |||
1014 | /* TODO: verify the following equation */ | ||
1015 | bytes_per_frame = dsi->current_dsi_clk_khz * 1000 * 2 / | ||
1016 | (dsi->info.refresh_rate * 8); | ||
1017 | timeout = bytes_per_frame / DSI_CYCLE_COUNTER_VALUE; | ||
1018 | timeout = (timeout + DSI_HTX_TO_MARGIN) & 0xffff; | ||
1019 | |||
1020 | val = DSI_TIMEOUT_0_LRXH_TO(DSI_LRXH_TO_VALUE) | | ||
1021 | DSI_TIMEOUT_0_HTX_TO(timeout); | ||
1022 | tegra_dsi_writel(dsi, val, DSI_TIMEOUT_0); | ||
1023 | |||
1024 | if (dsi->info.panel_reset_timeout_msec) | ||
1025 | timeout = (dsi->info.panel_reset_timeout_msec * 1000*1000) | ||
1026 | / dsi->current_bit_clk_ns; | ||
1027 | else | ||
1028 | timeout = DSI_PR_TO_VALUE; | ||
1029 | |||
1030 | val = DSI_TIMEOUT_1_PR_TO(timeout) | | ||
1031 | DSI_TIMEOUT_1_TA_TO(DSI_TA_TO_VALUE); | ||
1032 | tegra_dsi_writel(dsi, val, DSI_TIMEOUT_1); | ||
1033 | |||
1034 | val = DSI_TO_TALLY_P_RESET_STATUS(IN_RESET) | | ||
1035 | DSI_TO_TALLY_TA_TALLY(DSI_TA_TALLY_VALUE)| | ||
1036 | DSI_TO_TALLY_LRXH_TALLY(DSI_LRXH_TALLY_VALUE)| | ||
1037 | DSI_TO_TALLY_HTX_TALLY(DSI_HTX_TALLY_VALUE); | ||
1038 | tegra_dsi_writel(dsi, val, DSI_TO_TALLY); | ||
1039 | } | ||
1040 | |||
1041 | static void tegra_dsi_setup_video_mode_pkt_length(struct tegra_dc *dc, | ||
1042 | struct tegra_dc_dsi_data *dsi) | ||
1043 | { | ||
1044 | u32 val; | ||
1045 | u32 hact_pkt_len; | ||
1046 | u32 hsa_pkt_len; | ||
1047 | u32 hbp_pkt_len; | ||
1048 | u32 hfp_pkt_len; | ||
1049 | |||
1050 | hact_pkt_len = dc->mode.h_active * dsi->pixel_scaler_mul / | ||
1051 | dsi->pixel_scaler_div; | ||
1052 | hsa_pkt_len = dc->mode.h_sync_width * dsi->pixel_scaler_mul / | ||
1053 | dsi->pixel_scaler_div; | ||
1054 | hbp_pkt_len = dc->mode.h_back_porch * dsi->pixel_scaler_mul / | ||
1055 | dsi->pixel_scaler_div; | ||
1056 | hfp_pkt_len = dc->mode.h_front_porch * dsi->pixel_scaler_mul / | ||
1057 | dsi->pixel_scaler_div; | ||
1058 | |||
1059 | if (dsi->info.video_burst_mode != | ||
1060 | TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END) | ||
1061 | hbp_pkt_len += hsa_pkt_len; | ||
1062 | |||
1063 | hsa_pkt_len -= DSI_HSYNC_BLNK_PKT_OVERHEAD; | ||
1064 | hbp_pkt_len -= DSI_HBACK_PORCH_PKT_OVERHEAD; | ||
1065 | hfp_pkt_len -= DSI_HFRONT_PORCH_PKT_OVERHEAD; | ||
1066 | |||
1067 | val = DSI_PKT_LEN_0_1_LENGTH_0(0) | | ||
1068 | DSI_PKT_LEN_0_1_LENGTH_1(hsa_pkt_len); | ||
1069 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_0_1); | ||
1070 | |||
1071 | val = DSI_PKT_LEN_2_3_LENGTH_2(hbp_pkt_len) | | ||
1072 | DSI_PKT_LEN_2_3_LENGTH_3(hact_pkt_len); | ||
1073 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_2_3); | ||
1074 | |||
1075 | val = DSI_PKT_LEN_4_5_LENGTH_4(hfp_pkt_len) | | ||
1076 | DSI_PKT_LEN_4_5_LENGTH_5(0); | ||
1077 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_4_5); | ||
1078 | |||
1079 | val = DSI_PKT_LEN_6_7_LENGTH_6(0) | DSI_PKT_LEN_6_7_LENGTH_7(0); | ||
1080 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_6_7); | ||
1081 | } | ||
1082 | |||
1083 | static void tegra_dsi_setup_cmd_mode_pkt_length(struct tegra_dc *dc, | ||
1084 | struct tegra_dc_dsi_data *dsi) | ||
1085 | { | ||
1086 | unsigned long val; | ||
1087 | unsigned long act_bytes; | ||
1088 | |||
1089 | act_bytes = dc->mode.h_active * dsi->pixel_scaler_mul / | ||
1090 | dsi->pixel_scaler_div + 1; | ||
1091 | |||
1092 | val = DSI_PKT_LEN_0_1_LENGTH_0(0) | DSI_PKT_LEN_0_1_LENGTH_1(0); | ||
1093 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_0_1); | ||
1094 | |||
1095 | val = DSI_PKT_LEN_2_3_LENGTH_2(0) | DSI_PKT_LEN_2_3_LENGTH_3(act_bytes); | ||
1096 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_2_3); | ||
1097 | |||
1098 | val = DSI_PKT_LEN_4_5_LENGTH_4(0) | DSI_PKT_LEN_4_5_LENGTH_5(act_bytes); | ||
1099 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_4_5); | ||
1100 | |||
1101 | val = DSI_PKT_LEN_6_7_LENGTH_6(0) | DSI_PKT_LEN_6_7_LENGTH_7(0x0f0f); | ||
1102 | tegra_dsi_writel(dsi, val, DSI_PKT_LEN_6_7); | ||
1103 | } | ||
1104 | |||
1105 | static void tegra_dsi_set_pkt_length(struct tegra_dc *dc, | ||
1106 | struct tegra_dc_dsi_data *dsi) | ||
1107 | { | ||
1108 | if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) | ||
1109 | return; | ||
1110 | |||
1111 | if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_VIDEO_MODE) | ||
1112 | tegra_dsi_setup_video_mode_pkt_length(dc, dsi); | ||
1113 | else | ||
1114 | tegra_dsi_setup_cmd_mode_pkt_length(dc, dsi); | ||
1115 | } | ||
1116 | |||
1117 | static void tegra_dsi_set_pkt_seq(struct tegra_dc *dc, | ||
1118 | struct tegra_dc_dsi_data *dsi) | ||
1119 | { | ||
1120 | const u32 *pkt_seq; | ||
1121 | u32 rgb_info; | ||
1122 | u32 pkt_seq_3_5_rgb_lo; | ||
1123 | u32 pkt_seq_3_5_rgb_hi; | ||
1124 | u32 val; | ||
1125 | u32 reg; | ||
1126 | u8 i; | ||
1127 | |||
1128 | if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) | ||
1129 | return; | ||
1130 | |||
1131 | switch (dsi->info.pixel_format) { | ||
1132 | case TEGRA_DSI_PIXEL_FORMAT_16BIT_P: | ||
1133 | rgb_info = CMD_RGB_16BPP; | ||
1134 | break; | ||
1135 | case TEGRA_DSI_PIXEL_FORMAT_18BIT_P: | ||
1136 | rgb_info = CMD_RGB_18BPP; | ||
1137 | break; | ||
1138 | case TEGRA_DSI_PIXEL_FORMAT_18BIT_NP: | ||
1139 | rgb_info = CMD_RGB_18BPPNP; | ||
1140 | break; | ||
1141 | case TEGRA_DSI_PIXEL_FORMAT_24BIT_P: | ||
1142 | default: | ||
1143 | rgb_info = CMD_RGB_24BPP; | ||
1144 | break; | ||
1145 | } | ||
1146 | |||
1147 | pkt_seq_3_5_rgb_lo = 0; | ||
1148 | pkt_seq_3_5_rgb_hi = 0; | ||
1149 | if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE) | ||
1150 | pkt_seq = dsi_pkt_seq_cmd_mode; | ||
1151 | else { | ||
1152 | switch (dsi->info.video_burst_mode) { | ||
1153 | case TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED: | ||
1154 | case TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED: | ||
1155 | case TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED: | ||
1156 | case TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED: | ||
1157 | case TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED: | ||
1158 | pkt_seq_3_5_rgb_lo = | ||
1159 | DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info); | ||
1160 | if (!dsi->info.no_pkt_seq_eot) | ||
1161 | pkt_seq = dsi_pkt_seq_video_burst; | ||
1162 | else | ||
1163 | pkt_seq = dsi_pkt_seq_video_burst_no_eot; | ||
1164 | break; | ||
1165 | case TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END: | ||
1166 | pkt_seq_3_5_rgb_hi = | ||
1167 | DSI_PKT_SEQ_3_HI_PKT_34_ID(rgb_info); | ||
1168 | pkt_seq = dsi_pkt_seq_video_non_burst_syne; | ||
1169 | break; | ||
1170 | case TEGRA_DSI_VIDEO_NONE_BURST_MODE: | ||
1171 | default: | ||
1172 | pkt_seq_3_5_rgb_lo = | ||
1173 | DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info); | ||
1174 | pkt_seq = dsi_pkt_seq_video_non_burst; | ||
1175 | break; | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | for (i = 0; i < NUMOF_PKT_SEQ; i++) { | ||
1180 | val = pkt_seq[i]; | ||
1181 | reg = dsi_pkt_seq_reg[i]; | ||
1182 | if ((reg == DSI_PKT_SEQ_3_LO) || (reg == DSI_PKT_SEQ_5_LO)) | ||
1183 | val |= pkt_seq_3_5_rgb_lo; | ||
1184 | if ((reg == DSI_PKT_SEQ_3_HI) || (reg == DSI_PKT_SEQ_5_HI)) | ||
1185 | val |= pkt_seq_3_5_rgb_hi; | ||
1186 | tegra_dsi_writel(dsi, val, reg); | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | static void tegra_dsi_reset_underflow_overflow | ||
1191 | (struct tegra_dc_dsi_data *dsi) | ||
1192 | { | ||
1193 | u32 val; | ||
1194 | |||
1195 | val = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1196 | val &= (DSI_STATUS_LB_OVERFLOW(0x1) | DSI_STATUS_LB_UNDERFLOW(0x1)); | ||
1197 | if (val) { | ||
1198 | if (val & DSI_STATUS_LB_OVERFLOW(0x1)) | ||
1199 | dev_warn(&dsi->dc->ndev->dev, | ||
1200 | "dsi: video fifo overflow. Resetting flag\n"); | ||
1201 | if (val & DSI_STATUS_LB_UNDERFLOW(0x1)) | ||
1202 | dev_warn(&dsi->dc->ndev->dev, | ||
1203 | "dsi: video fifo underflow. Resetting flag\n"); | ||
1204 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
1205 | val |= DSI_HOST_CONTROL_FIFO_STAT_RESET(0x1); | ||
1206 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
1207 | udelay(5); | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | static void tegra_dsi_stop_dc_stream(struct tegra_dc *dc, | ||
1212 | struct tegra_dc_dsi_data *dsi) | ||
1213 | { | ||
1214 | tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); | ||
1215 | tegra_dc_writel(dc, 0, DC_DISP_DISP_WIN_OPTIONS); | ||
1216 | tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); | ||
1217 | tegra_dc_writel(dc, GENERAL_ACT_REQ , DC_CMD_STATE_CONTROL); | ||
1218 | |||
1219 | dsi->status.dc_stream = DSI_DC_STREAM_DISABLE; | ||
1220 | } | ||
1221 | |||
1222 | static void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc, | ||
1223 | struct tegra_dc_dsi_data *dsi) | ||
1224 | { | ||
1225 | int val; | ||
1226 | long timeout; | ||
1227 | u32 frame_period = DIV_ROUND_UP(S_TO_MS(1), dsi->info.refresh_rate); | ||
1228 | |||
1229 | /* stop dc */ | ||
1230 | tegra_dsi_stop_dc_stream(dc, dsi); | ||
1231 | |||
1232 | /* enable frame end interrupt */ | ||
1233 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
1234 | val |= FRAME_END_INT; | ||
1235 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
1236 | |||
1237 | /* wait for frame_end completion. | ||
1238 | * timeout is 2 frame duration to accomodate for | ||
1239 | * internal delay. | ||
1240 | */ | ||
1241 | timeout = wait_for_completion_interruptible_timeout( | ||
1242 | &dc->frame_end_complete, | ||
1243 | msecs_to_jiffies(2 * frame_period)); | ||
1244 | |||
1245 | /* disable frame end interrupt */ | ||
1246 | val = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
1247 | val &= ~FRAME_END_INT; | ||
1248 | tegra_dc_writel(dc, val, DC_CMD_INT_MASK); | ||
1249 | |||
1250 | if (timeout == 0) | ||
1251 | dev_warn(&dc->ndev->dev, | ||
1252 | "DC doesn't stop at end of frame.\n"); | ||
1253 | |||
1254 | tegra_dsi_reset_underflow_overflow(dsi); | ||
1255 | } | ||
1256 | |||
1257 | static void tegra_dsi_start_dc_stream(struct tegra_dc *dc, | ||
1258 | struct tegra_dc_dsi_data *dsi) | ||
1259 | { | ||
1260 | u32 val; | ||
1261 | |||
1262 | tegra_dc_writel(dc, DSI_ENABLE, DC_DISP_DISP_WIN_OPTIONS); | ||
1263 | |||
1264 | /* TODO: clean up */ | ||
1265 | tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
1266 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, | ||
1267 | DC_CMD_DISPLAY_POWER_CONTROL); | ||
1268 | |||
1269 | /* Configure one-shot mode or continuous mode */ | ||
1270 | if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { | ||
1271 | /* disable LSPI/LCD_DE output */ | ||
1272 | val = PIN_OUTPUT_LSPI_OUTPUT_DIS; | ||
1273 | tegra_dc_writel(dc, val, DC_COM_PIN_OUTPUT_ENABLE3); | ||
1274 | |||
1275 | /* enable MSF & set MSF polarity */ | ||
1276 | val = MSF_ENABLE | MSF_LSPI; | ||
1277 | if (!dsi->info.te_polarity_low) | ||
1278 | val |= MSF_POLARITY_HIGH; | ||
1279 | else | ||
1280 | val |= MSF_POLARITY_LOW; | ||
1281 | tegra_dc_writel(dc, val, DC_CMD_DISPLAY_COMMAND_OPTION0); | ||
1282 | |||
1283 | /* set non-continuous mode */ | ||
1284 | tegra_dc_writel(dc, DISP_CTRL_MODE_NC_DISPLAY, | ||
1285 | DC_CMD_DISPLAY_COMMAND); | ||
1286 | tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); | ||
1287 | tegra_dc_writel(dc, GENERAL_ACT_REQ | NC_HOST_TRIG, | ||
1288 | DC_CMD_STATE_CONTROL); | ||
1289 | } else { | ||
1290 | /* set continuous mode */ | ||
1291 | tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, | ||
1292 | DC_CMD_DISPLAY_COMMAND); | ||
1293 | tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); | ||
1294 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
1295 | } | ||
1296 | |||
1297 | dsi->status.dc_stream = DSI_DC_STREAM_ENABLE; | ||
1298 | } | ||
1299 | |||
1300 | static void tegra_dsi_set_dc_clk(struct tegra_dc *dc, | ||
1301 | struct tegra_dc_dsi_data *dsi) | ||
1302 | { | ||
1303 | u32 shift_clk_div_register; | ||
1304 | u32 val; | ||
1305 | |||
1306 | /* Get the corresponding register value of shift_clk_div. */ | ||
1307 | shift_clk_div_register = dsi->shift_clk_div * 2 - 2; | ||
1308 | |||
1309 | #ifndef CONFIG_TEGRA_SILICON_PLATFORM | ||
1310 | shift_clk_div_register = 1; | ||
1311 | #endif | ||
1312 | |||
1313 | /* TODO: find out if PCD3 option is required */ | ||
1314 | val = PIXEL_CLK_DIVIDER_PCD1 | | ||
1315 | SHIFT_CLK_DIVIDER(shift_clk_div_register); | ||
1316 | tegra_dc_writel(dc, val, DC_DISP_DISP_CLOCK_CONTROL); | ||
1317 | } | ||
1318 | |||
1319 | static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc, | ||
1320 | struct tegra_dc_dsi_data *dsi, u32 clk) | ||
1321 | { | ||
1322 | u32 rm; | ||
1323 | |||
1324 | /* Round up to MHz */ | ||
1325 | rm = clk % 1000; | ||
1326 | if (rm != 0) | ||
1327 | clk -= rm; | ||
1328 | |||
1329 | /* Set up pixel clock */ | ||
1330 | dc->shift_clk_div = dsi->shift_clk_div; | ||
1331 | dc->mode.pclk = (clk * 1000) / dsi->shift_clk_div; | ||
1332 | /* TODO: Define one shot work delay in board file. */ | ||
1333 | /* Since for one-shot mode, refresh rate is usually set larger than | ||
1334 | * expected refresh rate, it needs at least 3 frame period. Less | ||
1335 | * delay one shot work is, more powering saving we have. */ | ||
1336 | dc->one_shot_delay_ms = 4 * | ||
1337 | DIV_ROUND_UP(S_TO_MS(1), dsi->info.refresh_rate); | ||
1338 | |||
1339 | /* Enable DSI clock */ | ||
1340 | tegra_dc_setup_clk(dc, dsi->dsi_clk); | ||
1341 | if (!dsi->clk_ref) { | ||
1342 | dsi->clk_ref = true; | ||
1343 | clk_enable(dsi->dsi_clk); | ||
1344 | tegra_periph_reset_deassert(dsi->dsi_clk); | ||
1345 | } | ||
1346 | dsi->current_dsi_clk_khz = clk_get_rate(dsi->dsi_clk) / 1000; | ||
1347 | dsi->current_bit_clk_ns = 1000*1000 / (dsi->current_dsi_clk_khz * 2); | ||
1348 | } | ||
1349 | |||
1350 | static void tegra_dsi_hs_clk_out_enable(struct tegra_dc_dsi_data *dsi) | ||
1351 | { | ||
1352 | u32 val; | ||
1353 | |||
1354 | val = tegra_dsi_readl(dsi, DSI_CONTROL); | ||
1355 | val &= ~DSI_CONTROL_HS_CLK_CTRL(1); | ||
1356 | |||
1357 | if (dsi->info.video_clock_mode == TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS) { | ||
1358 | val |= DSI_CONTROL_HS_CLK_CTRL(CONTINUOUS); | ||
1359 | dsi->status.clk_mode = DSI_PHYCLK_CONTINUOUS; | ||
1360 | } else { | ||
1361 | val |= DSI_CONTROL_HS_CLK_CTRL(TX_ONLY); | ||
1362 | dsi->status.clk_mode = DSI_PHYCLK_TX_ONLY; | ||
1363 | } | ||
1364 | tegra_dsi_writel(dsi, val, DSI_CONTROL); | ||
1365 | |||
1366 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
1367 | val &= ~DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(1); | ||
1368 | val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_HIGH); | ||
1369 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
1370 | |||
1371 | dsi->status.clk_out = DSI_PHYCLK_OUT_EN; | ||
1372 | } | ||
1373 | |||
1374 | static void tegra_dsi_hs_clk_out_enable_in_lp(struct tegra_dc_dsi_data *dsi) | ||
1375 | { | ||
1376 | u32 val; | ||
1377 | tegra_dsi_hs_clk_out_enable(dsi); | ||
1378 | |||
1379 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
1380 | val &= ~DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(1); | ||
1381 | val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW); | ||
1382 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
1383 | } | ||
1384 | |||
1385 | static void tegra_dsi_hs_clk_out_disable(struct tegra_dc *dc, | ||
1386 | struct tegra_dc_dsi_data *dsi) | ||
1387 | { | ||
1388 | u32 val; | ||
1389 | |||
1390 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
1391 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
1392 | |||
1393 | tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_POWER_CONTROL); | ||
1394 | /* stabilization delay */ | ||
1395 | udelay(300); | ||
1396 | |||
1397 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
1398 | val &= ~DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(1); | ||
1399 | val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW); | ||
1400 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
1401 | |||
1402 | tegra_dsi_writel(dsi, TEGRA_DSI_ENABLE, DSI_POWER_CONTROL); | ||
1403 | /* stabilization delay */ | ||
1404 | udelay(300); | ||
1405 | |||
1406 | dsi->status.clk_mode = DSI_PHYCLK_NOT_INIT; | ||
1407 | dsi->status.clk_out = DSI_PHYCLK_OUT_DIS; | ||
1408 | } | ||
1409 | |||
1410 | static void tegra_dsi_set_control_reg_lp(struct tegra_dc_dsi_data *dsi) | ||
1411 | { | ||
1412 | u32 dsi_control; | ||
1413 | u32 host_dsi_control; | ||
1414 | u32 max_threshold; | ||
1415 | |||
1416 | dsi_control = dsi->dsi_control_val | DSI_CTRL_HOST_DRIVEN; | ||
1417 | host_dsi_control = HOST_DSI_CTRL_COMMON | | ||
1418 | HOST_DSI_CTRL_HOST_DRIVEN | | ||
1419 | DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW); | ||
1420 | max_threshold = DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_HOST_FIFO_DEPTH); | ||
1421 | |||
1422 | tegra_dsi_writel(dsi, max_threshold, DSI_MAX_THRESHOLD); | ||
1423 | tegra_dsi_writel(dsi, dsi_control, DSI_CONTROL); | ||
1424 | tegra_dsi_writel(dsi, host_dsi_control, DSI_HOST_DSI_CONTROL); | ||
1425 | |||
1426 | dsi->status.driven = DSI_DRIVEN_MODE_HOST; | ||
1427 | dsi->status.clk_burst = DSI_CLK_BURST_NOT_INIT; | ||
1428 | dsi->status.vtype = DSI_VIDEO_TYPE_NOT_INIT; | ||
1429 | } | ||
1430 | |||
1431 | static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi) | ||
1432 | { | ||
1433 | u32 dsi_control; | ||
1434 | u32 host_dsi_control; | ||
1435 | u32 max_threshold; | ||
1436 | u32 dcs_cmd; | ||
1437 | |||
1438 | dsi_control = dsi->dsi_control_val; | ||
1439 | host_dsi_control = HOST_DSI_CTRL_COMMON; | ||
1440 | max_threshold = 0; | ||
1441 | dcs_cmd = 0; | ||
1442 | |||
1443 | if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) { | ||
1444 | dsi_control |= DSI_CTRL_HOST_DRIVEN; | ||
1445 | host_dsi_control |= HOST_DSI_CTRL_HOST_DRIVEN; | ||
1446 | max_threshold = | ||
1447 | DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_HOST_FIFO_DEPTH); | ||
1448 | dsi->status.driven = DSI_DRIVEN_MODE_HOST; | ||
1449 | } else { | ||
1450 | dsi_control |= DSI_CTRL_DC_DRIVEN; | ||
1451 | host_dsi_control |= HOST_DSI_CTRL_DC_DRIVEN; | ||
1452 | max_threshold = | ||
1453 | DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_VIDEO_FIFO_DEPTH); | ||
1454 | dsi->status.driven = DSI_DRIVEN_MODE_DC; | ||
1455 | } | ||
1456 | |||
1457 | if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE) { | ||
1458 | dsi_control |= DSI_CTRL_CMD_MODE; | ||
1459 | dcs_cmd = DSI_DCS_CMDS_LT5_DCS_CMD(DSI_WRITE_MEMORY_START)| | ||
1460 | DSI_DCS_CMDS_LT3_DCS_CMD(DSI_WRITE_MEMORY_CONTINUE); | ||
1461 | dsi->status.vtype = DSI_VIDEO_TYPE_CMD_MODE; | ||
1462 | |||
1463 | } else { | ||
1464 | dsi_control |= DSI_CTRL_VIDEO_MODE; | ||
1465 | dsi->status.vtype = DSI_VIDEO_TYPE_VIDEO_MODE; | ||
1466 | } | ||
1467 | |||
1468 | tegra_dsi_writel(dsi, max_threshold, DSI_MAX_THRESHOLD); | ||
1469 | tegra_dsi_writel(dsi, dcs_cmd, DSI_DCS_CMDS); | ||
1470 | tegra_dsi_writel(dsi, dsi_control, DSI_CONTROL); | ||
1471 | tegra_dsi_writel(dsi, host_dsi_control, DSI_HOST_DSI_CONTROL); | ||
1472 | } | ||
1473 | |||
1474 | static void tegra_dsi_pad_calibration(struct tegra_dc_dsi_data *dsi) | ||
1475 | { | ||
1476 | u32 val; | ||
1477 | |||
1478 | val = DSI_PAD_CONTROL_PAD_LPUPADJ(0x1) | | ||
1479 | DSI_PAD_CONTROL_PAD_LPDNADJ(0x1) | | ||
1480 | DSI_PAD_CONTROL_PAD_PREEMP_EN(0x1) | | ||
1481 | DSI_PAD_CONTROL_PAD_SLEWDNADJ(0x6) | | ||
1482 | DSI_PAD_CONTROL_PAD_SLEWUPADJ(0x6); | ||
1483 | if (!dsi->ulpm) { | ||
1484 | val |= DSI_PAD_CONTROL_PAD_PDIO(0) | | ||
1485 | DSI_PAD_CONTROL_PAD_PDIO_CLK(0) | | ||
1486 | DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_DISABLE); | ||
1487 | } else { | ||
1488 | val |= DSI_PAD_CONTROL_PAD_PDIO(0x3) | | ||
1489 | DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) | | ||
1490 | DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE); | ||
1491 | } | ||
1492 | tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL); | ||
1493 | |||
1494 | val = MIPI_CAL_TERMOSA(0x4); | ||
1495 | tegra_vi_csi_writel(val, CSI_CILA_MIPI_CAL_CONFIG_0); | ||
1496 | |||
1497 | val = MIPI_CAL_TERMOSB(0x4); | ||
1498 | tegra_vi_csi_writel(val, CSI_CILB_MIPI_CAL_CONFIG_0); | ||
1499 | |||
1500 | val = MIPI_CAL_HSPUOSD(0x3) | MIPI_CAL_HSPDOSD(0x4); | ||
1501 | tegra_vi_csi_writel(val, CSI_DSI_MIPI_CAL_CONFIG); | ||
1502 | |||
1503 | val = PAD_DRIV_DN_REF(0x5) | PAD_DRIV_UP_REF(0x7); | ||
1504 | tegra_vi_csi_writel(val, CSI_MIPIBIAS_PAD_CONFIG); | ||
1505 | |||
1506 | val = PAD_CIL_PDVREG(0x0); | ||
1507 | tegra_vi_csi_writel(val, CSI_CIL_PAD_CONFIG); | ||
1508 | } | ||
1509 | |||
1510 | static int tegra_dsi_init_hw(struct tegra_dc *dc, | ||
1511 | struct tegra_dc_dsi_data *dsi) | ||
1512 | { | ||
1513 | u32 i; | ||
1514 | |||
1515 | tegra_dsi_writel(dsi, | ||
1516 | DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE), | ||
1517 | DSI_POWER_CONTROL); | ||
1518 | /* stabilization delay */ | ||
1519 | udelay(300); | ||
1520 | |||
1521 | tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz); | ||
1522 | if (dsi->info.dsi_instance) { | ||
1523 | /* TODO:Set the misc register*/ | ||
1524 | } | ||
1525 | |||
1526 | /* TODO: only need to change the timing for bta */ | ||
1527 | tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_LP_MODE); | ||
1528 | |||
1529 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
1530 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
1531 | |||
1532 | /* Initializing DSI registers */ | ||
1533 | for (i = 0; i < ARRAY_SIZE(init_reg); i++) | ||
1534 | tegra_dsi_writel(dsi, 0, init_reg[i]); | ||
1535 | |||
1536 | tegra_dsi_writel(dsi, dsi->dsi_control_val, DSI_CONTROL); | ||
1537 | |||
1538 | tegra_dsi_pad_calibration(dsi); | ||
1539 | |||
1540 | tegra_dsi_writel(dsi, | ||
1541 | DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE), | ||
1542 | DSI_POWER_CONTROL); | ||
1543 | /* stabilization delay */ | ||
1544 | udelay(300); | ||
1545 | |||
1546 | dsi->status.init = DSI_MODULE_INIT; | ||
1547 | dsi->status.lphs = DSI_LPHS_NOT_INIT; | ||
1548 | dsi->status.vtype = DSI_VIDEO_TYPE_NOT_INIT; | ||
1549 | dsi->status.driven = DSI_DRIVEN_MODE_NOT_INIT; | ||
1550 | dsi->status.clk_out = DSI_PHYCLK_OUT_DIS; | ||
1551 | dsi->status.clk_mode = DSI_PHYCLK_NOT_INIT; | ||
1552 | dsi->status.clk_burst = DSI_CLK_BURST_NOT_INIT; | ||
1553 | dsi->status.dc_stream = DSI_DC_STREAM_DISABLE; | ||
1554 | dsi->status.lp_op = DSI_LP_OP_NOT_INIT; | ||
1555 | |||
1556 | return 0; | ||
1557 | } | ||
1558 | |||
1559 | static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc, | ||
1560 | struct tegra_dc_dsi_data *dsi, u8 lp_op) | ||
1561 | { | ||
1562 | int err; | ||
1563 | |||
1564 | if (dsi->status.init != DSI_MODULE_INIT) { | ||
1565 | err = -EPERM; | ||
1566 | goto fail; | ||
1567 | } | ||
1568 | |||
1569 | if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE && | ||
1570 | dsi->status.lp_op == lp_op) | ||
1571 | goto success; | ||
1572 | |||
1573 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
1574 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
1575 | |||
1576 | /* disable/enable hs clk according to enable_hs_clock_on_lp_cmd_mode */ | ||
1577 | if ((dsi->status.clk_out == DSI_PHYCLK_OUT_EN) && | ||
1578 | (!dsi->info.enable_hs_clock_on_lp_cmd_mode)) | ||
1579 | tegra_dsi_hs_clk_out_disable(dc, dsi); | ||
1580 | |||
1581 | dsi->target_lp_clk_khz = tegra_dsi_get_lp_clk_rate(dsi, lp_op); | ||
1582 | if (dsi->current_dsi_clk_khz != dsi->target_lp_clk_khz) { | ||
1583 | tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz); | ||
1584 | tegra_dsi_set_timeout(dsi); | ||
1585 | } | ||
1586 | |||
1587 | tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_LP_MODE); | ||
1588 | |||
1589 | tegra_dsi_set_control_reg_lp(dsi); | ||
1590 | |||
1591 | if ((dsi->status.clk_out == DSI_PHYCLK_OUT_DIS) && | ||
1592 | (dsi->info.enable_hs_clock_on_lp_cmd_mode)) | ||
1593 | tegra_dsi_hs_clk_out_enable_in_lp(dsi); | ||
1594 | |||
1595 | dsi->status.lphs = DSI_LPHS_IN_LP_MODE; | ||
1596 | dsi->status.lp_op = lp_op; | ||
1597 | success: | ||
1598 | err = 0; | ||
1599 | fail: | ||
1600 | return err; | ||
1601 | } | ||
1602 | |||
1603 | static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc, | ||
1604 | struct tegra_dc_dsi_data *dsi) | ||
1605 | { | ||
1606 | int err; | ||
1607 | |||
1608 | if (dsi->status.init != DSI_MODULE_INIT) { | ||
1609 | err = -EPERM; | ||
1610 | goto fail; | ||
1611 | } | ||
1612 | |||
1613 | if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE) | ||
1614 | goto success; | ||
1615 | |||
1616 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
1617 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
1618 | |||
1619 | if ((dsi->status.clk_out == DSI_PHYCLK_OUT_EN) && | ||
1620 | (!dsi->info.enable_hs_clock_on_lp_cmd_mode)) | ||
1621 | tegra_dsi_hs_clk_out_disable(dc, dsi); | ||
1622 | |||
1623 | if (dsi->current_dsi_clk_khz != dsi->target_hs_clk_khz) { | ||
1624 | tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_hs_clk_khz); | ||
1625 | tegra_dsi_set_timeout(dsi); | ||
1626 | } | ||
1627 | |||
1628 | tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_HS_MODE); | ||
1629 | |||
1630 | if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_DC) { | ||
1631 | tegra_dsi_set_pkt_seq(dc, dsi); | ||
1632 | tegra_dsi_set_pkt_length(dc, dsi); | ||
1633 | tegra_dsi_set_sol_delay(dc, dsi); | ||
1634 | tegra_dsi_set_dc_clk(dc, dsi); | ||
1635 | } | ||
1636 | |||
1637 | tegra_dsi_set_control_reg_hs(dsi); | ||
1638 | |||
1639 | if (dsi->status.clk_out == DSI_PHYCLK_OUT_DIS || | ||
1640 | dsi->info.enable_hs_clock_on_lp_cmd_mode) | ||
1641 | tegra_dsi_hs_clk_out_enable(dsi); | ||
1642 | |||
1643 | dsi->status.lphs = DSI_LPHS_IN_HS_MODE; | ||
1644 | success: | ||
1645 | dsi->status.lp_op = DSI_LP_OP_NOT_INIT; | ||
1646 | err = 0; | ||
1647 | fail: | ||
1648 | return err; | ||
1649 | } | ||
1650 | |||
1651 | static bool tegra_dsi_write_busy(struct tegra_dc_dsi_data *dsi) | ||
1652 | { | ||
1653 | u32 timeout = 0; | ||
1654 | bool retVal = true; | ||
1655 | |||
1656 | while (timeout <= DSI_MAX_COMMAND_DELAY_USEC) { | ||
1657 | if (!(DSI_TRIGGER_HOST_TRIGGER(0x1) & | ||
1658 | tegra_dsi_readl(dsi, DSI_TRIGGER))) { | ||
1659 | retVal = false; | ||
1660 | break; | ||
1661 | } | ||
1662 | udelay(DSI_COMMAND_DELAY_STEPS_USEC); | ||
1663 | timeout += DSI_COMMAND_DELAY_STEPS_USEC; | ||
1664 | } | ||
1665 | |||
1666 | return retVal; | ||
1667 | } | ||
1668 | |||
1669 | static bool tegra_dsi_read_busy(struct tegra_dc_dsi_data *dsi) | ||
1670 | { | ||
1671 | u32 timeout = 0; | ||
1672 | bool retVal = true; | ||
1673 | |||
1674 | while (timeout < DSI_STATUS_POLLING_DURATION_USEC) { | ||
1675 | if (!(DSI_HOST_DSI_CONTROL_IMM_BTA(0x1) & | ||
1676 | tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL))) { | ||
1677 | retVal = false; | ||
1678 | break; | ||
1679 | } | ||
1680 | udelay(DSI_STATUS_POLLING_DELAY_USEC); | ||
1681 | timeout += DSI_STATUS_POLLING_DELAY_USEC; | ||
1682 | } | ||
1683 | |||
1684 | return retVal; | ||
1685 | } | ||
1686 | |||
1687 | static bool tegra_dsi_host_busy(struct tegra_dc_dsi_data *dsi) | ||
1688 | { | ||
1689 | int err = 0; | ||
1690 | |||
1691 | if (tegra_dsi_write_busy(dsi)) { | ||
1692 | err = -EBUSY; | ||
1693 | dev_err(&dsi->dc->ndev->dev, | ||
1694 | "DSI trigger bit already set\n"); | ||
1695 | goto fail; | ||
1696 | } | ||
1697 | |||
1698 | if (tegra_dsi_read_busy(dsi)) { | ||
1699 | err = -EBUSY; | ||
1700 | dev_err(&dsi->dc->ndev->dev, | ||
1701 | "DSI immediate bta bit already set\n"); | ||
1702 | goto fail; | ||
1703 | } | ||
1704 | fail: | ||
1705 | return (err < 0 ? true : false); | ||
1706 | } | ||
1707 | |||
1708 | static void tegra_dsi_soft_reset(struct tegra_dc_dsi_data *dsi) | ||
1709 | { | ||
1710 | u32 trigger; | ||
1711 | u32 status; | ||
1712 | |||
1713 | tegra_dsi_writel(dsi, | ||
1714 | DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE), | ||
1715 | DSI_POWER_CONTROL); | ||
1716 | /* stabilization delay */ | ||
1717 | udelay(300); | ||
1718 | |||
1719 | tegra_dsi_writel(dsi, | ||
1720 | DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE), | ||
1721 | DSI_POWER_CONTROL); | ||
1722 | /* stabilization delay */ | ||
1723 | udelay(300); | ||
1724 | |||
1725 | /* dsi HW does not clear host trigger bit automatically | ||
1726 | * on dsi interface disable if host fifo is empty | ||
1727 | */ | ||
1728 | trigger = tegra_dsi_readl(dsi, DSI_TRIGGER); | ||
1729 | status = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1730 | if (trigger & DSI_TRIGGER_HOST_TRIGGER(0x1) && | ||
1731 | status & DSI_STATUS_IDLE(0x1)) { | ||
1732 | trigger &= ~(DSI_TRIGGER_HOST_TRIGGER(0x1)); | ||
1733 | tegra_dsi_writel(dsi, trigger, DSI_TRIGGER); | ||
1734 | } | ||
1735 | } | ||
1736 | |||
1737 | static void tegra_dsi_reset_read_count(struct tegra_dc_dsi_data *dsi) | ||
1738 | { | ||
1739 | u32 val; | ||
1740 | |||
1741 | val = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1742 | val &= DSI_STATUS_RD_FIFO_COUNT(0x1f); | ||
1743 | if (val) { | ||
1744 | dev_warn(&dsi->dc->ndev->dev, | ||
1745 | "DSI read count not zero, resetting\n"); | ||
1746 | tegra_dsi_soft_reset(dsi); | ||
1747 | } | ||
1748 | } | ||
1749 | |||
1750 | static struct dsi_status *tegra_dsi_save_state_switch_to_host_cmd_mode( | ||
1751 | struct tegra_dc_dsi_data *dsi, | ||
1752 | struct tegra_dc *dc, | ||
1753 | u8 lp_op) | ||
1754 | { | ||
1755 | struct dsi_status *init_status; | ||
1756 | int err; | ||
1757 | |||
1758 | init_status = kzalloc(sizeof(*init_status), GFP_KERNEL); | ||
1759 | if (!init_status) | ||
1760 | return ERR_PTR(-ENOMEM); | ||
1761 | |||
1762 | *init_status = dsi->status; | ||
1763 | |||
1764 | if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE) { | ||
1765 | if (dsi->status.driven == DSI_DRIVEN_MODE_DC) { | ||
1766 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
1767 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
1768 | dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_HOST; | ||
1769 | if (dsi->info.hs_cmd_mode_supported) { | ||
1770 | err = tegra_dsi_set_to_hs_mode(dc, dsi); | ||
1771 | if (err < 0) { | ||
1772 | dev_err(&dc->ndev->dev, | ||
1773 | "Switch to HS host mode failed\n"); | ||
1774 | goto fail; | ||
1775 | } | ||
1776 | } | ||
1777 | } | ||
1778 | if (!dsi->info.hs_cmd_mode_supported) { | ||
1779 | err = | ||
1780 | tegra_dsi_set_to_lp_mode(dc, dsi, lp_op); | ||
1781 | if (err < 0) { | ||
1782 | dev_err(&dc->ndev->dev, | ||
1783 | "DSI failed to go to LP mode\n"); | ||
1784 | goto fail; | ||
1785 | } | ||
1786 | } | ||
1787 | } else if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE) { | ||
1788 | if (dsi->status.lp_op != lp_op) { | ||
1789 | err = tegra_dsi_set_to_lp_mode(dc, dsi, lp_op); | ||
1790 | if (err < 0) { | ||
1791 | dev_err(&dc->ndev->dev, | ||
1792 | "DSI failed to go to LP mode\n"); | ||
1793 | goto fail; | ||
1794 | } | ||
1795 | } | ||
1796 | } | ||
1797 | |||
1798 | return init_status; | ||
1799 | fail: | ||
1800 | kfree(init_status); | ||
1801 | return ERR_PTR(err); | ||
1802 | } | ||
1803 | |||
1804 | static struct dsi_status *tegra_dsi_prepare_host_transmission( | ||
1805 | struct tegra_dc *dc, | ||
1806 | struct tegra_dc_dsi_data *dsi, | ||
1807 | u8 lp_op) | ||
1808 | { | ||
1809 | int err = 0; | ||
1810 | struct dsi_status *init_status; | ||
1811 | |||
1812 | if (dsi->status.init != DSI_MODULE_INIT || | ||
1813 | dsi->ulpm) { | ||
1814 | err = -EPERM; | ||
1815 | goto fail; | ||
1816 | } | ||
1817 | |||
1818 | if (tegra_dsi_host_busy(dsi)) { | ||
1819 | tegra_dsi_soft_reset(dsi); | ||
1820 | if (tegra_dsi_host_busy(dsi)) { | ||
1821 | err = -EBUSY; | ||
1822 | dev_err(&dc->ndev->dev, "DSI host busy\n"); | ||
1823 | goto fail; | ||
1824 | } | ||
1825 | } | ||
1826 | |||
1827 | if (lp_op == DSI_LP_OP_READ) | ||
1828 | tegra_dsi_reset_read_count(dsi); | ||
1829 | |||
1830 | if (dsi->status.lphs == DSI_LPHS_NOT_INIT) { | ||
1831 | err = tegra_dsi_set_to_lp_mode(dc, dsi, lp_op); | ||
1832 | if (err < 0) { | ||
1833 | dev_err(&dc->ndev->dev, "Failed to config LP write\n"); | ||
1834 | goto fail; | ||
1835 | } | ||
1836 | } | ||
1837 | |||
1838 | init_status = tegra_dsi_save_state_switch_to_host_cmd_mode | ||
1839 | (dsi, dc, lp_op); | ||
1840 | if (IS_ERR_OR_NULL(init_status)) { | ||
1841 | err = PTR_ERR(init_status); | ||
1842 | dev_err(&dc->ndev->dev, "DSI state saving failed\n"); | ||
1843 | goto fail; | ||
1844 | } | ||
1845 | |||
1846 | return init_status; | ||
1847 | fail: | ||
1848 | return ERR_PTR(err); | ||
1849 | } | ||
1850 | |||
1851 | static int tegra_dsi_restore_state(struct tegra_dc *dc, | ||
1852 | struct tegra_dc_dsi_data *dsi, | ||
1853 | struct dsi_status *init_status) | ||
1854 | { | ||
1855 | bool switch_back_to_dc_mode = false; | ||
1856 | bool switch_back_to_hs_mode = false; | ||
1857 | bool restart_dc_stream; | ||
1858 | int err = 0; | ||
1859 | |||
1860 | switch_back_to_dc_mode = (dsi->status.driven == | ||
1861 | DSI_DRIVEN_MODE_HOST && | ||
1862 | init_status->driven == | ||
1863 | DSI_DRIVEN_MODE_DC); | ||
1864 | switch_back_to_hs_mode = (dsi->status.lphs == | ||
1865 | DSI_LPHS_IN_LP_MODE && | ||
1866 | init_status->lphs == | ||
1867 | DSI_LPHS_IN_HS_MODE); | ||
1868 | restart_dc_stream = (dsi->status.dc_stream == | ||
1869 | DSI_DC_STREAM_DISABLE && | ||
1870 | init_status->dc_stream == | ||
1871 | DSI_DC_STREAM_ENABLE); | ||
1872 | |||
1873 | if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE && | ||
1874 | init_status->lphs == DSI_LPHS_IN_LP_MODE) { | ||
1875 | if (dsi->status.lp_op != init_status->lp_op) { | ||
1876 | err = | ||
1877 | tegra_dsi_set_to_lp_mode(dc, dsi, init_status->lp_op); | ||
1878 | if (err < 0) { | ||
1879 | dev_err(&dc->ndev->dev, | ||
1880 | "Failed to config LP mode\n"); | ||
1881 | goto fail; | ||
1882 | } | ||
1883 | } | ||
1884 | goto success; | ||
1885 | } | ||
1886 | |||
1887 | if (switch_back_to_dc_mode) | ||
1888 | dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC; | ||
1889 | if (switch_back_to_dc_mode || switch_back_to_hs_mode) { | ||
1890 | err = tegra_dsi_set_to_hs_mode(dc, dsi); | ||
1891 | if (err < 0) { | ||
1892 | dev_err(&dc->ndev->dev, "Failed to config HS mode\n"); | ||
1893 | goto fail; | ||
1894 | } | ||
1895 | } | ||
1896 | if (restart_dc_stream) | ||
1897 | tegra_dsi_start_dc_stream(dc, dsi); | ||
1898 | |||
1899 | success: | ||
1900 | fail: | ||
1901 | kfree(init_status); | ||
1902 | return err; | ||
1903 | } | ||
1904 | |||
1905 | static int tegra_dsi_host_trigger(struct tegra_dc_dsi_data *dsi) | ||
1906 | { | ||
1907 | int status = 0; | ||
1908 | |||
1909 | if (tegra_dsi_readl(dsi, DSI_TRIGGER)) { | ||
1910 | status = -EBUSY; | ||
1911 | goto fail; | ||
1912 | } | ||
1913 | |||
1914 | tegra_dsi_writel(dsi, | ||
1915 | DSI_TRIGGER_HOST_TRIGGER(TEGRA_DSI_ENABLE), DSI_TRIGGER); | ||
1916 | |||
1917 | #if DSI_USE_SYNC_POINTS | ||
1918 | status = tegra_dsi_syncpt(dsi); | ||
1919 | if (status < 0) { | ||
1920 | dev_err(&dsi->dc->ndev->dev, | ||
1921 | "DSI syncpt for host trigger failed\n"); | ||
1922 | goto fail; | ||
1923 | } | ||
1924 | #else | ||
1925 | if (tegra_dsi_write_busy(dsi)) { | ||
1926 | status = -EBUSY; | ||
1927 | dev_err(&dsi->dc->ndev->dev, | ||
1928 | "Timeout waiting on write completion\n"); | ||
1929 | } | ||
1930 | #endif | ||
1931 | |||
1932 | fail: | ||
1933 | return status; | ||
1934 | } | ||
1935 | |||
1936 | static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi, | ||
1937 | u8 *pdata, u8 data_id, u16 data_len) | ||
1938 | { | ||
1939 | u8 virtual_channel; | ||
1940 | u8 *pval; | ||
1941 | u32 val; | ||
1942 | int err; | ||
1943 | |||
1944 | err = 0; | ||
1945 | |||
1946 | virtual_channel = dsi->info.virtual_channel << | ||
1947 | DSI_VIR_CHANNEL_BIT_POSITION; | ||
1948 | |||
1949 | /* always use hw for ecc */ | ||
1950 | val = (virtual_channel | data_id) << 0 | | ||
1951 | data_len << 8; | ||
1952 | tegra_dsi_writel(dsi, val, DSI_WR_DATA); | ||
1953 | |||
1954 | /* if pdata != NULL, pkt type is long pkt */ | ||
1955 | if (pdata != NULL) { | ||
1956 | while (data_len) { | ||
1957 | if (data_len >= 4) { | ||
1958 | val = ((u32 *) pdata)[0]; | ||
1959 | data_len -= 4; | ||
1960 | pdata += 4; | ||
1961 | } else { | ||
1962 | val = 0; | ||
1963 | pval = (u8 *) &val; | ||
1964 | do | ||
1965 | *pval++ = *pdata++; | ||
1966 | while (--data_len); | ||
1967 | } | ||
1968 | tegra_dsi_writel(dsi, val, DSI_WR_DATA); | ||
1969 | } | ||
1970 | } | ||
1971 | |||
1972 | err = tegra_dsi_host_trigger(dsi); | ||
1973 | if (err < 0) | ||
1974 | dev_err(&dsi->dc->ndev->dev, "DSI host trigger failed\n"); | ||
1975 | |||
1976 | return err; | ||
1977 | } | ||
1978 | |||
1979 | int tegra_dsi_write_data(struct tegra_dc *dc, | ||
1980 | struct tegra_dc_dsi_data *dsi, | ||
1981 | u8 *pdata, u8 data_id, u16 data_len) | ||
1982 | { | ||
1983 | int err = 0; | ||
1984 | struct dsi_status *init_status; | ||
1985 | |||
1986 | tegra_dc_io_start(dc); | ||
1987 | |||
1988 | init_status = tegra_dsi_prepare_host_transmission( | ||
1989 | dc, dsi, DSI_LP_OP_WRITE); | ||
1990 | if (IS_ERR_OR_NULL(init_status)) { | ||
1991 | err = PTR_ERR(init_status); | ||
1992 | dev_err(&dc->ndev->dev, "DSI host config failed\n"); | ||
1993 | goto fail; | ||
1994 | } | ||
1995 | |||
1996 | err = _tegra_dsi_write_data(dsi, pdata, data_id, data_len); | ||
1997 | fail: | ||
1998 | err = tegra_dsi_restore_state(dc, dsi, init_status); | ||
1999 | if (err < 0) | ||
2000 | dev_err(&dc->ndev->dev, "Failed to restore prev state\n"); | ||
2001 | tegra_dc_io_end(dc); | ||
2002 | return err; | ||
2003 | } | ||
2004 | EXPORT_SYMBOL(tegra_dsi_write_data); | ||
2005 | |||
2006 | static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc, | ||
2007 | struct tegra_dc_dsi_data *dsi, | ||
2008 | struct tegra_dsi_cmd *cmd, | ||
2009 | u32 n_cmd) | ||
2010 | { | ||
2011 | u32 i; | ||
2012 | int err; | ||
2013 | |||
2014 | err = 0; | ||
2015 | for (i = 0; i < n_cmd; i++) { | ||
2016 | struct tegra_dsi_cmd *cur_cmd; | ||
2017 | cur_cmd = &cmd[i]; | ||
2018 | |||
2019 | if (cur_cmd->cmd_type == TEGRA_DSI_DELAY_MS) | ||
2020 | mdelay(cur_cmd->sp_len_dly.delay_ms); | ||
2021 | else { | ||
2022 | err = tegra_dsi_write_data(dc, dsi, | ||
2023 | cur_cmd->pdata, | ||
2024 | cur_cmd->data_id, | ||
2025 | cur_cmd->sp_len_dly.data_len); | ||
2026 | if (err < 0) | ||
2027 | break; | ||
2028 | } | ||
2029 | } | ||
2030 | return err; | ||
2031 | } | ||
2032 | |||
2033 | static u8 get_8bit_ecc(u32 header) | ||
2034 | { | ||
2035 | char ecc_parity[24] = { | ||
2036 | 0x07, 0x0b, 0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19, | ||
2037 | 0x1a, 0x1c, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, | ||
2038 | 0x31, 0x32, 0x34, 0x38, 0x1f, 0x2f, 0x37, 0x3b | ||
2039 | }; | ||
2040 | u8 ecc_byte; | ||
2041 | int i; | ||
2042 | |||
2043 | ecc_byte = 0; | ||
2044 | for (i = 0; i < 24; i++) | ||
2045 | ecc_byte ^= ((header >> i) & 1) ? ecc_parity[i] : 0x00; | ||
2046 | |||
2047 | return ecc_byte; | ||
2048 | } | ||
2049 | |||
2050 | /* This function is written to send DCS short write (1 parameter) only. | ||
2051 | * This means the cmd will contain only 1 byte of index and 1 byte of value. | ||
2052 | * The data type ID is fixed at 0x15 and the ECC is calculated based on the | ||
2053 | * data in pdata. | ||
2054 | * The command will be sent by hardware every frame. | ||
2055 | * pdata should contain both the index + value for each cmd. | ||
2056 | * data_len will be the total number of bytes in pdata. | ||
2057 | */ | ||
2058 | int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len) | ||
2059 | { | ||
2060 | u8 ecc8bits = 0, data_len_orig = 0; | ||
2061 | u32 val = 0, pkthdr = 0; | ||
2062 | int err = 0, count = 0; | ||
2063 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); | ||
2064 | |||
2065 | data_len_orig = data_len; | ||
2066 | if (pdata != NULL) { | ||
2067 | while (data_len) { | ||
2068 | if (data_len >= 2) { | ||
2069 | pkthdr = (CMD_SHORTW | | ||
2070 | (((u16 *)pdata)[0]) << 8 | 0x00 << 24); | ||
2071 | ecc8bits = get_8bit_ecc(pkthdr); | ||
2072 | val = (pkthdr | (ecc8bits << 24)); | ||
2073 | data_len -= 2; | ||
2074 | pdata += 2; | ||
2075 | count++; | ||
2076 | } | ||
2077 | switch (count) { | ||
2078 | case 1: | ||
2079 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0); | ||
2080 | break; | ||
2081 | case 2: | ||
2082 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_1); | ||
2083 | break; | ||
2084 | case 3: | ||
2085 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_2); | ||
2086 | break; | ||
2087 | case 4: | ||
2088 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_3); | ||
2089 | break; | ||
2090 | case 5: | ||
2091 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_4); | ||
2092 | break; | ||
2093 | case 6: | ||
2094 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_5); | ||
2095 | break; | ||
2096 | case 7: | ||
2097 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_6); | ||
2098 | break; | ||
2099 | case 8: | ||
2100 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_7); | ||
2101 | break; | ||
2102 | default: | ||
2103 | err = 1; | ||
2104 | break; | ||
2105 | } | ||
2106 | } | ||
2107 | } | ||
2108 | |||
2109 | val = DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(data_len_orig * 2) | ||
2110 | | DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(1); | ||
2111 | tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL); | ||
2112 | |||
2113 | return err; | ||
2114 | } | ||
2115 | EXPORT_SYMBOL(tegra_dsi_send_panel_short_cmd); | ||
2116 | |||
2117 | static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi) | ||
2118 | { | ||
2119 | u32 val; | ||
2120 | u32 poll_time; | ||
2121 | int err; | ||
2122 | |||
2123 | poll_time = 0; | ||
2124 | err = 0; | ||
2125 | |||
2126 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
2127 | val |= DSI_HOST_DSI_CONTROL_IMM_BTA(TEGRA_DSI_ENABLE); | ||
2128 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
2129 | |||
2130 | #if DSI_USE_SYNC_POINTS | ||
2131 | /* FIXME: Workaround for nvhost_syncpt_read */ | ||
2132 | dsi->syncpt_val = nvhost_syncpt_update_min( | ||
2133 | &nvhost_get_host(dsi->dc->ndev)->syncpt, | ||
2134 | dsi->syncpt_id); | ||
2135 | |||
2136 | val = DSI_INCR_SYNCPT_COND(OP_DONE) | | ||
2137 | DSI_INCR_SYNCPT_INDX(dsi->syncpt_id); | ||
2138 | tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT); | ||
2139 | |||
2140 | /* TODO: Use interrupt rather than polling */ | ||
2141 | err = nvhost_syncpt_wait(&nvhost_get_host(dsi->dc->ndev)->syncpt, | ||
2142 | dsi->syncpt_id, dsi->syncpt_val + 1); | ||
2143 | if (err < 0) | ||
2144 | dev_err(&dsi->dc->ndev->dev, | ||
2145 | "DSI sync point failure\n"); | ||
2146 | else | ||
2147 | (dsi->syncpt_val)++; | ||
2148 | #else | ||
2149 | if (tegra_dsi_read_busy(dsi)) { | ||
2150 | err = -EBUSY; | ||
2151 | dev_err(&dsi->dc->ndev->dev, | ||
2152 | "Timeout wating on read completion\n"); | ||
2153 | } | ||
2154 | #endif | ||
2155 | |||
2156 | return err; | ||
2157 | } | ||
2158 | |||
2159 | static int tegra_dsi_parse_read_response(struct tegra_dc *dc, | ||
2160 | u32 rd_fifo_cnt, u8 *read_fifo) | ||
2161 | { | ||
2162 | int err; | ||
2163 | u32 payload_size; | ||
2164 | |||
2165 | payload_size = 0; | ||
2166 | err = 0; | ||
2167 | |||
2168 | switch (read_fifo[0]) { | ||
2169 | case DSI_ESCAPE_CMD: | ||
2170 | dev_info(&dc->ndev->dev, "escape cmd[0x%x]\n", read_fifo[0]); | ||
2171 | break; | ||
2172 | case DSI_ACK_NO_ERR: | ||
2173 | dev_info(&dc->ndev->dev, | ||
2174 | "Panel ack, no err[0x%x]\n", read_fifo[0]); | ||
2175 | return err; | ||
2176 | default: | ||
2177 | dev_info(&dc->ndev->dev, "Invalid read response\n"); | ||
2178 | break; | ||
2179 | } | ||
2180 | |||
2181 | switch (read_fifo[4] & 0xff) { | ||
2182 | case GEN_LONG_RD_RES: | ||
2183 | /* Fall through */ | ||
2184 | case DCS_LONG_RD_RES: | ||
2185 | payload_size = (read_fifo[5] | | ||
2186 | (read_fifo[6] << 8)) & 0xFFFF; | ||
2187 | dev_info(&dc->ndev->dev, "Long read response Packet\n" | ||
2188 | "payload_size[0x%x]\n", payload_size); | ||
2189 | break; | ||
2190 | case GEN_1_BYTE_SHORT_RD_RES: | ||
2191 | /* Fall through */ | ||
2192 | case DCS_1_BYTE_SHORT_RD_RES: | ||
2193 | payload_size = 1; | ||
2194 | dev_info(&dc->ndev->dev, "Short read response Packet\n" | ||
2195 | "payload_size[0x%x]\n", payload_size); | ||
2196 | break; | ||
2197 | case GEN_2_BYTE_SHORT_RD_RES: | ||
2198 | /* Fall through */ | ||
2199 | case DCS_2_BYTE_SHORT_RD_RES: | ||
2200 | payload_size = 2; | ||
2201 | dev_info(&dc->ndev->dev, "Short read response Packet\n" | ||
2202 | "payload_size[0x%x]\n", payload_size); | ||
2203 | break; | ||
2204 | case ACK_ERR_RES: | ||
2205 | payload_size = 2; | ||
2206 | dev_info(&dc->ndev->dev, "Acknowledge error report response\n" | ||
2207 | "Packet payload_size[0x%x]\n", payload_size); | ||
2208 | break; | ||
2209 | default: | ||
2210 | dev_info(&dc->ndev->dev, "Invalid response packet\n"); | ||
2211 | err = -EINVAL; | ||
2212 | break; | ||
2213 | } | ||
2214 | return err; | ||
2215 | } | ||
2216 | |||
2217 | static int tegra_dsi_read_fifo(struct tegra_dc *dc, | ||
2218 | struct tegra_dc_dsi_data *dsi, | ||
2219 | u8 *read_fifo) | ||
2220 | { | ||
2221 | u32 val; | ||
2222 | u32 i; | ||
2223 | u32 poll_time = 0; | ||
2224 | u32 rd_fifo_cnt; | ||
2225 | int err = 0; | ||
2226 | u8 *read_fifo_cp = read_fifo; | ||
2227 | |||
2228 | while (poll_time < DSI_DELAY_FOR_READ_FIFO) { | ||
2229 | mdelay(1); | ||
2230 | val = tegra_dsi_readl(dsi, DSI_STATUS); | ||
2231 | rd_fifo_cnt = val & DSI_STATUS_RD_FIFO_COUNT(0x1f); | ||
2232 | if (rd_fifo_cnt << 2 > DSI_READ_FIFO_DEPTH) | ||
2233 | dev_err(&dc->ndev->dev, | ||
2234 | "DSI RD_FIFO_CNT is greater than RD_FIFO_DEPTH\n"); | ||
2235 | break; | ||
2236 | poll_time++; | ||
2237 | } | ||
2238 | |||
2239 | if (rd_fifo_cnt == 0) { | ||
2240 | dev_info(&dc->ndev->dev, | ||
2241 | "DSI RD_FIFO_CNT is zero\n"); | ||
2242 | err = -EINVAL; | ||
2243 | goto fail; | ||
2244 | } | ||
2245 | |||
2246 | if (val & (DSI_STATUS_LB_UNDERFLOW(0x1) | | ||
2247 | DSI_STATUS_LB_OVERFLOW(0x1))) { | ||
2248 | dev_warn(&dc->ndev->dev, | ||
2249 | "DSI overflow/underflow error\n"); | ||
2250 | } | ||
2251 | |||
2252 | /* Read data from FIFO */ | ||
2253 | for (i = 0; i < rd_fifo_cnt; i++) { | ||
2254 | val = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
2255 | if (enable_read_debug) | ||
2256 | dev_info(&dc->ndev->dev, | ||
2257 | "Read data[%d]: 0x%x\n", i, val); | ||
2258 | memcpy(read_fifo, &val, 4); | ||
2259 | read_fifo += 4; | ||
2260 | } | ||
2261 | |||
2262 | /* Make sure all the data is read from the FIFO */ | ||
2263 | val = tegra_dsi_readl(dsi, DSI_STATUS); | ||
2264 | val &= DSI_STATUS_RD_FIFO_COUNT(0x1f); | ||
2265 | if (val) | ||
2266 | dev_err(&dc->ndev->dev, "DSI FIFO_RD_CNT not zero" | ||
2267 | " even after reading FIFO_RD_CNT words from read fifo\n"); | ||
2268 | |||
2269 | if (enable_read_debug) { | ||
2270 | err = | ||
2271 | tegra_dsi_parse_read_response(dc, rd_fifo_cnt, read_fifo_cp); | ||
2272 | if (err < 0) | ||
2273 | dev_warn(&dc->ndev->dev, "Unexpected read data\n"); | ||
2274 | } | ||
2275 | fail: | ||
2276 | return err; | ||
2277 | } | ||
2278 | |||
2279 | int tegra_dsi_read_data(struct tegra_dc *dc, | ||
2280 | struct tegra_dc_dsi_data *dsi, | ||
2281 | u32 max_ret_payload_size, | ||
2282 | u32 panel_reg_addr, u8 *read_data) | ||
2283 | { | ||
2284 | int err = 0; | ||
2285 | struct dsi_status *init_status; | ||
2286 | |||
2287 | tegra_dc_io_start(dc); | ||
2288 | |||
2289 | init_status = tegra_dsi_prepare_host_transmission( | ||
2290 | dc, dsi, DSI_LP_OP_WRITE); | ||
2291 | if (IS_ERR_OR_NULL(init_status)) { | ||
2292 | err = PTR_ERR(init_status); | ||
2293 | dev_err(&dc->ndev->dev, "DSI host config failed\n"); | ||
2294 | goto fail; | ||
2295 | } | ||
2296 | |||
2297 | /* Set max return payload size in words */ | ||
2298 | err = _tegra_dsi_write_data(dsi, NULL, | ||
2299 | dsi_command_max_return_pkt_size, | ||
2300 | max_ret_payload_size); | ||
2301 | if (err < 0) { | ||
2302 | dev_err(&dc->ndev->dev, | ||
2303 | "DSI write failed\n"); | ||
2304 | goto fail; | ||
2305 | } | ||
2306 | |||
2307 | /* DCS to read given panel register */ | ||
2308 | err = _tegra_dsi_write_data(dsi, NULL, | ||
2309 | dsi_command_dcs_read_with_no_params, | ||
2310 | panel_reg_addr); | ||
2311 | if (err < 0) { | ||
2312 | dev_err(&dc->ndev->dev, | ||
2313 | "DSI write failed\n"); | ||
2314 | goto fail; | ||
2315 | } | ||
2316 | |||
2317 | tegra_dsi_reset_read_count(dsi); | ||
2318 | |||
2319 | if (dsi->status.lp_op == DSI_LP_OP_WRITE) { | ||
2320 | err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_READ); | ||
2321 | if (err < 0) { | ||
2322 | dev_err(&dc->ndev->dev, | ||
2323 | "DSI failed to go to LP read mode\n"); | ||
2324 | goto fail; | ||
2325 | } | ||
2326 | } | ||
2327 | |||
2328 | err = tegra_dsi_bta(dsi); | ||
2329 | if (err < 0) { | ||
2330 | dev_err(&dc->ndev->dev, | ||
2331 | "DSI IMM BTA timeout\n"); | ||
2332 | goto fail; | ||
2333 | } | ||
2334 | |||
2335 | err = tegra_dsi_read_fifo(dc, dsi, read_data); | ||
2336 | if (err < 0) { | ||
2337 | dev_err(&dc->ndev->dev, "DSI read fifo failure\n"); | ||
2338 | goto fail; | ||
2339 | } | ||
2340 | fail: | ||
2341 | err = tegra_dsi_restore_state(dc, dsi, init_status); | ||
2342 | if (err < 0) | ||
2343 | dev_err(&dc->ndev->dev, "Failed to restore prev state\n"); | ||
2344 | tegra_dc_io_end(dc); | ||
2345 | return err; | ||
2346 | } | ||
2347 | EXPORT_SYMBOL(tegra_dsi_read_data); | ||
2348 | |||
2349 | int tegra_dsi_panel_sanity_check(struct tegra_dc *dc, | ||
2350 | struct tegra_dc_dsi_data *dsi) | ||
2351 | { | ||
2352 | int err = 0; | ||
2353 | u8 read_fifo[DSI_READ_FIFO_DEPTH]; | ||
2354 | struct dsi_status *init_status; | ||
2355 | static struct tegra_dsi_cmd dsi_nop_cmd = | ||
2356 | DSI_CMD_SHORT(0x05, 0x0, 0x0); | ||
2357 | |||
2358 | tegra_dc_io_start(dc); | ||
2359 | |||
2360 | init_status = tegra_dsi_prepare_host_transmission( | ||
2361 | dc, dsi, DSI_LP_OP_WRITE); | ||
2362 | if (IS_ERR_OR_NULL(init_status)) { | ||
2363 | err = PTR_ERR(init_status); | ||
2364 | dev_err(&dc->ndev->dev, "DSI host config failed\n"); | ||
2365 | goto fail; | ||
2366 | } | ||
2367 | |||
2368 | err = _tegra_dsi_write_data(dsi, NULL, dsi_nop_cmd.data_id, 0x0); | ||
2369 | if (err < 0) { | ||
2370 | dev_err(&dc->ndev->dev, "DSI nop write failed\n"); | ||
2371 | goto fail; | ||
2372 | } | ||
2373 | |||
2374 | tegra_dsi_reset_read_count(dsi); | ||
2375 | |||
2376 | if (dsi->status.lp_op == DSI_LP_OP_WRITE) { | ||
2377 | err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_READ); | ||
2378 | if (err < 0) { | ||
2379 | dev_err(&dc->ndev->dev, | ||
2380 | "DSI failed to go to LP read mode\n"); | ||
2381 | goto fail; | ||
2382 | } | ||
2383 | } | ||
2384 | |||
2385 | err = tegra_dsi_bta(dsi); | ||
2386 | if (err < 0) { | ||
2387 | dev_err(&dc->ndev->dev, "DSI BTA failed\n"); | ||
2388 | goto fail; | ||
2389 | } | ||
2390 | |||
2391 | err = tegra_dsi_read_fifo(dc, dsi, read_fifo); | ||
2392 | if (err < 0) { | ||
2393 | dev_err(&dc->ndev->dev, "DSI read fifo failure\n"); | ||
2394 | goto fail; | ||
2395 | } | ||
2396 | |||
2397 | if (read_fifo[0] != DSI_ACK_NO_ERR) { | ||
2398 | dev_warn(&dc->ndev->dev, | ||
2399 | "Ack no error trigger message not received\n"); | ||
2400 | err = -EAGAIN; | ||
2401 | } | ||
2402 | fail: | ||
2403 | err = tegra_dsi_restore_state(dc, dsi, init_status); | ||
2404 | if (err < 0) | ||
2405 | dev_err(&dc->ndev->dev, "Failed to restore prev state\n"); | ||
2406 | tegra_dc_io_end(dc); | ||
2407 | return err; | ||
2408 | } | ||
2409 | EXPORT_SYMBOL(tegra_dsi_panel_sanity_check); | ||
2410 | |||
2411 | static int tegra_dsi_enter_ulpm(struct tegra_dc_dsi_data *dsi) | ||
2412 | { | ||
2413 | u32 val; | ||
2414 | int ret; | ||
2415 | |||
2416 | ret = 0; | ||
2417 | |||
2418 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
2419 | val &= ~DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(3); | ||
2420 | val |= DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(ENTER_ULPM); | ||
2421 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
2422 | |||
2423 | #if DSI_USE_SYNC_POINTS | ||
2424 | ret = tegra_dsi_syncpt(dsi); | ||
2425 | if (ret < 0) { | ||
2426 | dev_err(&dsi->dc->ndev->dev, | ||
2427 | "DSI syncpt for ulpm enter failed\n"); | ||
2428 | goto fail; | ||
2429 | } | ||
2430 | #else | ||
2431 | /* TODO: Find exact delay required */ | ||
2432 | mdelay(10); | ||
2433 | #endif | ||
2434 | dsi->ulpm = true; | ||
2435 | fail: | ||
2436 | return ret; | ||
2437 | } | ||
2438 | |||
2439 | static int tegra_dsi_exit_ulpm(struct tegra_dc_dsi_data *dsi) | ||
2440 | { | ||
2441 | u32 val; | ||
2442 | int ret; | ||
2443 | |||
2444 | ret = 0; | ||
2445 | |||
2446 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
2447 | val &= ~DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(3); | ||
2448 | val |= DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(EXIT_ULPM); | ||
2449 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
2450 | |||
2451 | #if DSI_USE_SYNC_POINTS | ||
2452 | ret = tegra_dsi_syncpt(dsi); | ||
2453 | if (ret < 0) { | ||
2454 | dev_err(&dsi->dc->ndev->dev, | ||
2455 | "DSI syncpt for ulpm exit failed\n"); | ||
2456 | goto fail; | ||
2457 | } | ||
2458 | #else | ||
2459 | /* TODO: Find exact delay required */ | ||
2460 | mdelay(10); | ||
2461 | #endif | ||
2462 | dsi->ulpm = false; | ||
2463 | |||
2464 | val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL); | ||
2465 | val &= ~DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(0x3); | ||
2466 | val |= DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(NORMAL); | ||
2467 | tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL); | ||
2468 | fail: | ||
2469 | return ret; | ||
2470 | |||
2471 | } | ||
2472 | |||
2473 | static void tegra_dc_dsi_enable(struct tegra_dc *dc) | ||
2474 | { | ||
2475 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); | ||
2476 | int err; | ||
2477 | u32 val; | ||
2478 | |||
2479 | tegra_dc_io_start(dc); | ||
2480 | mutex_lock(&dsi->lock); | ||
2481 | |||
2482 | /* Stop DC stream before configuring DSI registers | ||
2483 | * to avoid visible glitches on panel during transition | ||
2484 | * from bootloader to kernel driver | ||
2485 | */ | ||
2486 | tegra_dsi_stop_dc_stream(dc, dsi); | ||
2487 | |||
2488 | if (dsi->enabled) { | ||
2489 | if (dsi->ulpm) { | ||
2490 | if (tegra_dsi_exit_ulpm(dsi) < 0) { | ||
2491 | dev_err(&dc->ndev->dev, | ||
2492 | "DSI failed to exit ulpm\n"); | ||
2493 | goto fail; | ||
2494 | } | ||
2495 | } | ||
2496 | |||
2497 | if (dsi->info.panel_reset) { | ||
2498 | err = tegra_dsi_send_panel_cmd(dc, dsi, | ||
2499 | dsi->info.dsi_init_cmd, | ||
2500 | dsi->info.n_init_cmd); | ||
2501 | if (err < 0) { | ||
2502 | dev_err(&dc->ndev->dev, | ||
2503 | "dsi: error sending dsi init cmd\n"); | ||
2504 | goto fail; | ||
2505 | } | ||
2506 | } else if (dsi->info.dsi_late_resume_cmd) { | ||
2507 | err = tegra_dsi_send_panel_cmd(dc, dsi, | ||
2508 | dsi->info.dsi_late_resume_cmd, | ||
2509 | dsi->info.n_late_resume_cmd); | ||
2510 | if (err < 0) { | ||
2511 | dev_err(&dc->ndev->dev, | ||
2512 | "dsi: error sending late resume cmd\n"); | ||
2513 | goto fail; | ||
2514 | } | ||
2515 | } | ||
2516 | } else { | ||
2517 | err = tegra_dsi_init_hw(dc, dsi); | ||
2518 | if (err < 0) { | ||
2519 | dev_err(&dc->ndev->dev, | ||
2520 | "dsi: not able to init dsi hardware\n"); | ||
2521 | goto fail; | ||
2522 | } | ||
2523 | |||
2524 | if (dsi->ulpm) { | ||
2525 | if (tegra_dsi_enter_ulpm(dsi) < 0) { | ||
2526 | dev_err(&dc->ndev->dev, | ||
2527 | "DSI failed to enter ulpm\n"); | ||
2528 | goto fail; | ||
2529 | } | ||
2530 | |||
2531 | val = tegra_dsi_readl(dsi, DSI_PAD_CONTROL); | ||
2532 | |||
2533 | /* erase bits we're about to set */ | ||
2534 | val &= ~(DSI_PAD_CONTROL_PAD_PDIO(0x3) | | ||
2535 | DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) | | ||
2536 | DSI_PAD_CONTROL_PAD_PULLDN_ENAB(0x1)); | ||
2537 | |||
2538 | val |= (DSI_PAD_CONTROL_PAD_PDIO(0) | | ||
2539 | DSI_PAD_CONTROL_PAD_PDIO_CLK(0) | | ||
2540 | DSI_PAD_CONTROL_PAD_PULLDN_ENAB | ||
2541 | (TEGRA_DSI_DISABLE)); | ||
2542 | |||
2543 | tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL); | ||
2544 | if (tegra_dsi_exit_ulpm(dsi) < 0) { | ||
2545 | dev_err(&dc->ndev->dev, | ||
2546 | "DSI failed to exit ulpm\n"); | ||
2547 | goto fail; | ||
2548 | } | ||
2549 | } | ||
2550 | |||
2551 | err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE); | ||
2552 | if (err < 0) { | ||
2553 | dev_err(&dc->ndev->dev, | ||
2554 | "dsi: not able to set to lp mode\n"); | ||
2555 | goto fail; | ||
2556 | } | ||
2557 | |||
2558 | err = tegra_dsi_send_panel_cmd(dc, dsi, dsi->info.dsi_init_cmd, | ||
2559 | dsi->info.n_init_cmd); | ||
2560 | if (err < 0) { | ||
2561 | dev_err(&dc->ndev->dev, | ||
2562 | "dsi: error while sending dsi init cmd\n"); | ||
2563 | goto fail; | ||
2564 | } | ||
2565 | |||
2566 | err = tegra_dsi_set_to_hs_mode(dc, dsi); | ||
2567 | if (err < 0) { | ||
2568 | dev_err(&dc->ndev->dev, | ||
2569 | "dsi: not able to set to hs mode\n"); | ||
2570 | goto fail; | ||
2571 | } | ||
2572 | |||
2573 | dsi->enabled = true; | ||
2574 | } | ||
2575 | |||
2576 | if (dsi->status.driven == DSI_DRIVEN_MODE_DC) | ||
2577 | tegra_dsi_start_dc_stream(dc, dsi); | ||
2578 | fail: | ||
2579 | mutex_unlock(&dsi->lock); | ||
2580 | tegra_dc_io_end(dc); | ||
2581 | } | ||
2582 | |||
2583 | static void _tegra_dc_dsi_init(struct tegra_dc *dc) | ||
2584 | { | ||
2585 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); | ||
2586 | |||
2587 | tegra_dsi_init_sw(dc, dsi); | ||
2588 | /* TODO: Configure the CSI pad configuration */ | ||
2589 | } | ||
2590 | |||
2591 | static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd *src, | ||
2592 | struct tegra_dsi_cmd *dst, u16 n_cmd) | ||
2593 | { | ||
2594 | u16 i; | ||
2595 | u16 len; | ||
2596 | |||
2597 | memcpy(dst, src, sizeof(*dst) * n_cmd); | ||
2598 | |||
2599 | for (i = 0; i < n_cmd; i++) | ||
2600 | if (src[i].pdata) { | ||
2601 | len = sizeof(*src[i].pdata) * | ||
2602 | src[i].sp_len_dly.data_len; | ||
2603 | dst[i].pdata = kzalloc(len, GFP_KERNEL); | ||
2604 | if (!dst[i].pdata) | ||
2605 | goto free_cmd_pdata; | ||
2606 | memcpy(dst[i].pdata, src[i].pdata, len); | ||
2607 | } | ||
2608 | |||
2609 | return 0; | ||
2610 | |||
2611 | free_cmd_pdata: | ||
2612 | for (--i; i >= 0; i--) | ||
2613 | if (dst[i].pdata) | ||
2614 | kfree(dst[i].pdata); | ||
2615 | return -ENOMEM; | ||
2616 | } | ||
2617 | |||
2618 | static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi, | ||
2619 | struct tegra_dsi_out *p_dsi) | ||
2620 | { | ||
2621 | struct tegra_dsi_cmd *p_init_cmd; | ||
2622 | struct tegra_dsi_cmd *p_early_suspend_cmd; | ||
2623 | struct tegra_dsi_cmd *p_late_resume_cmd; | ||
2624 | struct tegra_dsi_cmd *p_suspend_cmd; | ||
2625 | int err; | ||
2626 | |||
2627 | if (p_dsi->n_data_lanes > MAX_DSI_DATA_LANES) | ||
2628 | return -EINVAL; | ||
2629 | |||
2630 | p_init_cmd = kzalloc(sizeof(*p_init_cmd) * | ||
2631 | p_dsi->n_init_cmd, GFP_KERNEL); | ||
2632 | if (!p_init_cmd) | ||
2633 | return -ENOMEM; | ||
2634 | |||
2635 | if (p_dsi->dsi_early_suspend_cmd) { | ||
2636 | p_early_suspend_cmd = kzalloc(sizeof(*p_early_suspend_cmd) * | ||
2637 | p_dsi->n_early_suspend_cmd, | ||
2638 | GFP_KERNEL); | ||
2639 | if (!p_early_suspend_cmd) { | ||
2640 | err = -ENOMEM; | ||
2641 | goto err_free_init_cmd; | ||
2642 | } | ||
2643 | } | ||
2644 | |||
2645 | if (p_dsi->dsi_late_resume_cmd) { | ||
2646 | p_late_resume_cmd = kzalloc(sizeof(*p_late_resume_cmd) * | ||
2647 | p_dsi->n_late_resume_cmd, | ||
2648 | GFP_KERNEL); | ||
2649 | if (!p_late_resume_cmd) { | ||
2650 | err = -ENOMEM; | ||
2651 | goto err_free_p_early_suspend_cmd; | ||
2652 | } | ||
2653 | } | ||
2654 | |||
2655 | p_suspend_cmd = kzalloc(sizeof(*p_suspend_cmd) * p_dsi->n_suspend_cmd, | ||
2656 | GFP_KERNEL); | ||
2657 | if (!p_suspend_cmd) { | ||
2658 | err = -ENOMEM; | ||
2659 | goto err_free_p_late_resume_cmd; | ||
2660 | } | ||
2661 | |||
2662 | memcpy(&dsi->info, p_dsi, sizeof(dsi->info)); | ||
2663 | |||
2664 | /* Copy panel init cmd */ | ||
2665 | err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_init_cmd, | ||
2666 | p_init_cmd, p_dsi->n_init_cmd); | ||
2667 | if (err < 0) | ||
2668 | goto err_free; | ||
2669 | dsi->info.dsi_init_cmd = p_init_cmd; | ||
2670 | |||
2671 | /* Copy panel early suspend cmd */ | ||
2672 | if (p_dsi->dsi_early_suspend_cmd) { | ||
2673 | err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_early_suspend_cmd, | ||
2674 | p_early_suspend_cmd, | ||
2675 | p_dsi->n_early_suspend_cmd); | ||
2676 | if (err < 0) | ||
2677 | goto err_free; | ||
2678 | dsi->info.dsi_early_suspend_cmd = p_early_suspend_cmd; | ||
2679 | } | ||
2680 | |||
2681 | /* Copy panel late resume cmd */ | ||
2682 | if (p_dsi->dsi_late_resume_cmd) { | ||
2683 | err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_late_resume_cmd, | ||
2684 | p_late_resume_cmd, | ||
2685 | p_dsi->n_late_resume_cmd); | ||
2686 | if (err < 0) | ||
2687 | goto err_free; | ||
2688 | dsi->info.dsi_late_resume_cmd = p_late_resume_cmd; | ||
2689 | } | ||
2690 | |||
2691 | /* Copy panel suspend cmd */ | ||
2692 | err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_suspend_cmd, p_suspend_cmd, | ||
2693 | p_dsi->n_suspend_cmd); | ||
2694 | if (err < 0) | ||
2695 | goto err_free; | ||
2696 | dsi->info.dsi_suspend_cmd = p_suspend_cmd; | ||
2697 | |||
2698 | if (!dsi->info.panel_reset_timeout_msec) | ||
2699 | dsi->info.panel_reset_timeout_msec = | ||
2700 | DEFAULT_PANEL_RESET_TIMEOUT; | ||
2701 | |||
2702 | if (!dsi->info.panel_buffer_size_byte) | ||
2703 | dsi->info.panel_buffer_size_byte = DEFAULT_PANEL_BUFFER_BYTE; | ||
2704 | |||
2705 | if (!dsi->info.max_panel_freq_khz) { | ||
2706 | dsi->info.max_panel_freq_khz = DEFAULT_MAX_DSI_PHY_CLK_KHZ; | ||
2707 | |||
2708 | if (dsi->info.video_burst_mode > | ||
2709 | TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END){ | ||
2710 | dev_err(&dsi->dc->ndev->dev, "DSI: max_panel_freq_khz" | ||
2711 | "is not set for DSI burst mode.\n"); | ||
2712 | dsi->info.video_burst_mode = | ||
2713 | TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED; | ||
2714 | } | ||
2715 | } | ||
2716 | |||
2717 | if (!dsi->info.lp_cmd_mode_freq_khz) | ||
2718 | dsi->info.lp_cmd_mode_freq_khz = DEFAULT_LP_CMD_MODE_CLK_KHZ; | ||
2719 | |||
2720 | if (!dsi->info.chip_id || !dsi->info.chip_rev) | ||
2721 | dev_warn(&dsi->dc->ndev->dev, | ||
2722 | "DSI: Failed to get chip info\n"); | ||
2723 | |||
2724 | if (!dsi->info.lp_read_cmd_mode_freq_khz) | ||
2725 | dsi->info.lp_read_cmd_mode_freq_khz = | ||
2726 | dsi->info.lp_cmd_mode_freq_khz; | ||
2727 | |||
2728 | /* host mode is for testing only */ | ||
2729 | dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC; | ||
2730 | return 0; | ||
2731 | |||
2732 | err_free: | ||
2733 | kfree(p_suspend_cmd); | ||
2734 | err_free_p_late_resume_cmd: | ||
2735 | kfree(p_late_resume_cmd); | ||
2736 | err_free_p_early_suspend_cmd: | ||
2737 | kfree(p_early_suspend_cmd); | ||
2738 | err_free_init_cmd: | ||
2739 | kfree(p_init_cmd); | ||
2740 | return err; | ||
2741 | } | ||
2742 | |||
2743 | static int tegra_dc_dsi_init(struct tegra_dc *dc) | ||
2744 | { | ||
2745 | struct tegra_dc_dsi_data *dsi; | ||
2746 | struct resource *res; | ||
2747 | struct resource *base_res; | ||
2748 | void __iomem *base; | ||
2749 | struct clk *dc_clk = NULL; | ||
2750 | struct clk *dsi_clk = NULL; | ||
2751 | struct tegra_dsi_out *dsi_pdata; | ||
2752 | int err; | ||
2753 | |||
2754 | err = 0; | ||
2755 | |||
2756 | dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); | ||
2757 | if (!dsi) | ||
2758 | return -ENOMEM; | ||
2759 | |||
2760 | res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, | ||
2761 | "dsi_regs"); | ||
2762 | if (!res) { | ||
2763 | dev_err(&dc->ndev->dev, "dsi: no mem resource\n"); | ||
2764 | err = -ENOENT; | ||
2765 | goto err_free_dsi; | ||
2766 | } | ||
2767 | |||
2768 | base_res = request_mem_region(res->start, resource_size(res), | ||
2769 | dc->ndev->name); | ||
2770 | if (!base_res) { | ||
2771 | dev_err(&dc->ndev->dev, "dsi: request_mem_region failed\n"); | ||
2772 | err = -EBUSY; | ||
2773 | goto err_free_dsi; | ||
2774 | } | ||
2775 | |||
2776 | base = ioremap(res->start, resource_size(res)); | ||
2777 | if (!base) { | ||
2778 | dev_err(&dc->ndev->dev, "dsi: registers can't be mapped\n"); | ||
2779 | err = -EBUSY; | ||
2780 | goto err_release_regs; | ||
2781 | } | ||
2782 | |||
2783 | dsi_pdata = dc->pdata->default_out->dsi; | ||
2784 | if (!dsi_pdata) { | ||
2785 | dev_err(&dc->ndev->dev, "dsi: dsi data not available\n"); | ||
2786 | goto err_release_regs; | ||
2787 | } | ||
2788 | |||
2789 | if (dsi_pdata->dsi_instance) | ||
2790 | dsi_clk = clk_get(&dc->ndev->dev, "dsib"); | ||
2791 | else | ||
2792 | dsi_clk = clk_get(&dc->ndev->dev, "dsia"); | ||
2793 | |||
2794 | if (IS_ERR_OR_NULL(dsi_clk)) { | ||
2795 | dev_err(&dc->ndev->dev, "dsi: can't get clock\n"); | ||
2796 | err = -EBUSY; | ||
2797 | goto err_release_regs; | ||
2798 | } | ||
2799 | |||
2800 | dc_clk = clk_get_sys(dev_name(&dc->ndev->dev), NULL); | ||
2801 | if (IS_ERR_OR_NULL(dc_clk)) { | ||
2802 | dev_err(&dc->ndev->dev, "dsi: dc clock %s unavailable\n", | ||
2803 | dev_name(&dc->ndev->dev)); | ||
2804 | err = -EBUSY; | ||
2805 | goto err_clk_put; | ||
2806 | } | ||
2807 | |||
2808 | mutex_init(&dsi->lock); | ||
2809 | dsi->dc = dc; | ||
2810 | dsi->base = base; | ||
2811 | dsi->base_res = base_res; | ||
2812 | dsi->dc_clk = dc_clk; | ||
2813 | dsi->dsi_clk = dsi_clk; | ||
2814 | |||
2815 | err = tegra_dc_dsi_cp_info(dsi, dsi_pdata); | ||
2816 | if (err < 0) | ||
2817 | goto err_dsi_data; | ||
2818 | |||
2819 | tegra_dc_set_outdata(dc, dsi); | ||
2820 | _tegra_dc_dsi_init(dc); | ||
2821 | |||
2822 | return 0; | ||
2823 | |||
2824 | err_dsi_data: | ||
2825 | err_clk_put: | ||
2826 | clk_put(dsi_clk); | ||
2827 | err_release_regs: | ||
2828 | release_resource(base_res); | ||
2829 | err_free_dsi: | ||
2830 | kfree(dsi); | ||
2831 | |||
2832 | return err; | ||
2833 | } | ||
2834 | |||
2835 | static void tegra_dc_dsi_destroy(struct tegra_dc *dc) | ||
2836 | { | ||
2837 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); | ||
2838 | u16 i; | ||
2839 | u32 val; | ||
2840 | |||
2841 | mutex_lock(&dsi->lock); | ||
2842 | |||
2843 | /* free up the pdata */ | ||
2844 | for (i = 0; i < dsi->info.n_init_cmd; i++) { | ||
2845 | if (dsi->info.dsi_init_cmd[i].pdata) | ||
2846 | kfree(dsi->info.dsi_init_cmd[i].pdata); | ||
2847 | } | ||
2848 | kfree(dsi->info.dsi_init_cmd); | ||
2849 | |||
2850 | /* Disable dc stream */ | ||
2851 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
2852 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
2853 | |||
2854 | /* Disable dsi phy clock */ | ||
2855 | if (dsi->status.clk_out == DSI_PHYCLK_OUT_EN) | ||
2856 | tegra_dsi_hs_clk_out_disable(dc, dsi); | ||
2857 | |||
2858 | val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE); | ||
2859 | tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL); | ||
2860 | |||
2861 | iounmap(dsi->base); | ||
2862 | release_resource(dsi->base_res); | ||
2863 | |||
2864 | clk_put(dsi->dc_clk); | ||
2865 | clk_put(dsi->dsi_clk); | ||
2866 | |||
2867 | mutex_unlock(&dsi->lock); | ||
2868 | |||
2869 | mutex_destroy(&dsi->lock); | ||
2870 | kfree(dsi); | ||
2871 | } | ||
2872 | |||
2873 | static int tegra_dsi_deep_sleep(struct tegra_dc *dc, | ||
2874 | struct tegra_dc_dsi_data *dsi) | ||
2875 | { | ||
2876 | int err = 0; | ||
2877 | int val; | ||
2878 | struct clk *parent_clk = NULL; | ||
2879 | struct clk *base_clk = NULL; | ||
2880 | |||
2881 | if (!dsi->enabled) { | ||
2882 | err = -EPERM; | ||
2883 | goto fail; | ||
2884 | } | ||
2885 | |||
2886 | err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE); | ||
2887 | if (err < 0) { | ||
2888 | dev_err(&dc->ndev->dev, | ||
2889 | "DSI failed to go to LP mode\n"); | ||
2890 | goto fail; | ||
2891 | } | ||
2892 | |||
2893 | /* Suspend panel */ | ||
2894 | err = tegra_dsi_send_panel_cmd(dc, dsi, | ||
2895 | dsi->info.dsi_suspend_cmd, | ||
2896 | dsi->info.n_suspend_cmd); | ||
2897 | if (err < 0) { | ||
2898 | dev_err(&dc->ndev->dev, | ||
2899 | "dsi: Error sending suspend cmd\n"); | ||
2900 | goto fail; | ||
2901 | } | ||
2902 | |||
2903 | if (!dsi->ulpm) { | ||
2904 | err = tegra_dsi_enter_ulpm(dsi); | ||
2905 | if (err < 0) { | ||
2906 | dev_err(&dc->ndev->dev, | ||
2907 | "DSI failed to enter ulpm\n"); | ||
2908 | goto fail; | ||
2909 | } | ||
2910 | } | ||
2911 | |||
2912 | /* | ||
2913 | * Suspend pad | ||
2914 | * It is ok to overwrite previous value of DSI_PAD_CONTROL reg | ||
2915 | * because it will be restored properly in resume sequence | ||
2916 | */ | ||
2917 | val = DSI_PAD_CONTROL_PAD_PDIO(0x3) | | ||
2918 | DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) | | ||
2919 | DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE); | ||
2920 | tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL); | ||
2921 | |||
2922 | /* Suspend core-logic */ | ||
2923 | val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE); | ||
2924 | tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL); | ||
2925 | |||
2926 | /* Disable dsi fast and slow clock */ | ||
2927 | parent_clk = clk_get_parent(dsi->dsi_clk); | ||
2928 | base_clk = clk_get_parent(parent_clk); | ||
2929 | if (dsi->info.dsi_instance) | ||
2930 | tegra_clk_cfg_ex(base_clk, | ||
2931 | TEGRA_CLK_PLLD_CSI_OUT_ENB, | ||
2932 | 0); | ||
2933 | else | ||
2934 | tegra_clk_cfg_ex(base_clk, | ||
2935 | TEGRA_CLK_PLLD_DSI_OUT_ENB, | ||
2936 | 0); | ||
2937 | |||
2938 | /* Disable dsi source clock */ | ||
2939 | clk_disable(dsi->dsi_clk); | ||
2940 | |||
2941 | dsi->clk_ref = false; | ||
2942 | dsi->enabled = false; | ||
2943 | |||
2944 | return 0; | ||
2945 | fail: | ||
2946 | return err; | ||
2947 | } | ||
2948 | |||
2949 | static void tegra_dc_dsi_disable(struct tegra_dc *dc) | ||
2950 | { | ||
2951 | int err; | ||
2952 | struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc); | ||
2953 | |||
2954 | tegra_dc_io_start(dc); | ||
2955 | mutex_lock(&dsi->lock); | ||
2956 | |||
2957 | if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) | ||
2958 | tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi); | ||
2959 | |||
2960 | if (dsi->info.power_saving_suspend) { | ||
2961 | if (tegra_dsi_deep_sleep(dc, dsi) < 0) { | ||
2962 | dev_err(&dc->ndev->dev, | ||
2963 | "DSI failed to enter deep sleep\n"); | ||
2964 | goto fail; | ||
2965 | } | ||
2966 | } else { | ||
2967 | if (dsi->info.dsi_early_suspend_cmd) { | ||
2968 | err = tegra_dsi_send_panel_cmd(dc, dsi, | ||
2969 | dsi->info.dsi_early_suspend_cmd, | ||
2970 | dsi->info.n_early_suspend_cmd); | ||
2971 | if (err < 0) { | ||
2972 | dev_err(&dc->ndev->dev, | ||
2973 | "dsi: Error sending early suspend cmd\n"); | ||
2974 | goto fail; | ||
2975 | } | ||
2976 | } | ||
2977 | |||
2978 | if (!dsi->ulpm) { | ||
2979 | if (tegra_dsi_enter_ulpm(dsi) < 0) { | ||
2980 | dev_err(&dc->ndev->dev, | ||
2981 | "DSI failed to enter ulpm\n"); | ||
2982 | goto fail; | ||
2983 | } | ||
2984 | } | ||
2985 | } | ||
2986 | |||
2987 | fail: | ||
2988 | mutex_unlock(&dsi->lock); | ||
2989 | tegra_dc_io_end(dc); | ||
2990 | } | ||
2991 | |||
2992 | #ifdef CONFIG_PM | ||
2993 | static void tegra_dc_dsi_suspend(struct tegra_dc *dc) | ||
2994 | { | ||
2995 | struct tegra_dc_dsi_data *dsi; | ||
2996 | |||
2997 | dsi = tegra_dc_get_outdata(dc); | ||
2998 | |||
2999 | if (!dsi->enabled) | ||
3000 | return; | ||
3001 | |||
3002 | tegra_dc_io_start(dc); | ||
3003 | mutex_lock(&dsi->lock); | ||
3004 | |||
3005 | if (!dsi->info.power_saving_suspend) { | ||
3006 | if (dsi->ulpm) { | ||
3007 | if (tegra_dsi_exit_ulpm(dsi) < 0) { | ||
3008 | dev_err(&dc->ndev->dev, | ||
3009 | "DSI failed to exit ulpm"); | ||
3010 | goto fail; | ||
3011 | } | ||
3012 | } | ||
3013 | |||
3014 | if (tegra_dsi_deep_sleep(dc, dsi) < 0) { | ||
3015 | dev_err(&dc->ndev->dev, | ||
3016 | "DSI failed to enter deep sleep\n"); | ||
3017 | goto fail; | ||
3018 | } | ||
3019 | } | ||
3020 | fail: | ||
3021 | mutex_unlock(&dsi->lock); | ||
3022 | tegra_dc_io_end(dc); | ||
3023 | } | ||
3024 | |||
3025 | static void tegra_dc_dsi_resume(struct tegra_dc *dc) | ||
3026 | { | ||
3027 | /* Not required since tegra_dc_dsi_enable | ||
3028 | * will reconfigure the controller from scratch | ||
3029 | */ | ||
3030 | } | ||
3031 | #endif | ||
3032 | |||
3033 | struct tegra_dc_out_ops tegra_dc_dsi_ops = { | ||
3034 | .init = tegra_dc_dsi_init, | ||
3035 | .destroy = tegra_dc_dsi_destroy, | ||
3036 | .enable = tegra_dc_dsi_enable, | ||
3037 | .disable = tegra_dc_dsi_disable, | ||
3038 | #ifdef CONFIG_PM | ||
3039 | .suspend = tegra_dc_dsi_suspend, | ||
3040 | .resume = tegra_dc_dsi_resume, | ||
3041 | #endif | ||
3042 | }; | ||
diff --git a/drivers/video/tegra/dc/dsi.h b/drivers/video/tegra/dc/dsi.h new file mode 100644 index 00000000000..18ea9c959e8 --- /dev/null +++ b/drivers/video/tegra/dc/dsi.h | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dsi.h | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_DSI_H__ | ||
18 | #define __DRIVERS_VIDEO_TEGRA_DC_DSI_H__ | ||
19 | |||
20 | /* source of video data */ | ||
21 | enum { | ||
22 | TEGRA_DSI_VIDEO_DRIVEN_BY_DC, | ||
23 | TEGRA_DSI_VIDEO_DRIVEN_BY_HOST, | ||
24 | }; | ||
25 | |||
26 | /* Max number of data lanes supported */ | ||
27 | #define MAX_DSI_DATA_LANES 2 | ||
28 | /* Default Peripheral reset timeout */ | ||
29 | #define DSI_PR_TO_VALUE 0x2000 | ||
30 | |||
31 | /* DCS commands for command mode */ | ||
32 | #define DSI_ENTER_PARTIAL_MODE 0x12 | ||
33 | #define DSI_SET_PIXEL_FORMAT 0x3A | ||
34 | #define DSI_AREA_COLOR_MODE 0x4C | ||
35 | #define DSI_SET_PARTIAL_AREA 0x30 | ||
36 | #define DSI_SET_PAGE_ADDRESS 0x2B | ||
37 | #define DSI_SET_ADDRESS_MODE 0x36 | ||
38 | #define DSI_SET_COLUMN_ADDRESS 0x2A | ||
39 | #define DSI_WRITE_MEMORY_START 0x2C | ||
40 | #define DSI_WRITE_MEMORY_CONTINUE 0x3C | ||
41 | #define DSI_MAX_COMMAND_DELAY_USEC 250000 | ||
42 | #define DSI_COMMAND_DELAY_STEPS_USEC 10 | ||
43 | |||
44 | /* Trigger message */ | ||
45 | #define DSI_ESCAPE_CMD 0x87 | ||
46 | #define DSI_ACK_NO_ERR 0x84 | ||
47 | |||
48 | /* DSI return packet types */ | ||
49 | #define GEN_LONG_RD_RES 0x1A | ||
50 | #define DCS_LONG_RD_RES 0x1C | ||
51 | #define GEN_1_BYTE_SHORT_RD_RES 0x11 | ||
52 | #define DCS_1_BYTE_SHORT_RD_RES 0x21 | ||
53 | #define GEN_2_BYTE_SHORT_RD_RES 0x12 | ||
54 | #define DCS_2_BYTE_SHORT_RD_RES 0x22 | ||
55 | #define ACK_ERR_RES 0x02 | ||
56 | |||
57 | /* End of Transmit command for HS mode */ | ||
58 | #define DSI_CMD_HS_EOT_PACKAGE 0x000F0F08 | ||
59 | |||
60 | /* Delay required after issuing the trigger*/ | ||
61 | #define DSI_COMMAND_COMPLETION_DELAY_USEC 5 | ||
62 | |||
63 | #define DSI_DELAY_FOR_READ_FIFO 5 | ||
64 | |||
65 | /* Dsi virtual channel bit position, refer to the DSI specs */ | ||
66 | #define DSI_VIR_CHANNEL_BIT_POSITION 6 | ||
67 | |||
68 | /* DSI packet commands from Host to peripherals */ | ||
69 | enum { | ||
70 | dsi_command_v_sync_start = 0x01, | ||
71 | dsi_command_v_sync_end = 0x11, | ||
72 | dsi_command_h_sync_start = 0x21, | ||
73 | dsi_command_h_sync_end = 0x31, | ||
74 | dsi_command_end_of_transaction = 0x08, | ||
75 | dsi_command_blanking = 0x19, | ||
76 | dsi_command_null_packet = 0x09, | ||
77 | dsi_command_h_active_length_16bpp = 0x0E, | ||
78 | dsi_command_h_active_length_18bpp = 0x1E, | ||
79 | dsi_command_h_active_length_18bpp_np = 0x2E, | ||
80 | dsi_command_h_active_length_24bpp = 0x3E, | ||
81 | dsi_command_h_sync_active = dsi_command_blanking, | ||
82 | dsi_command_h_back_porch = dsi_command_blanking, | ||
83 | dsi_command_h_front_porch = dsi_command_blanking, | ||
84 | dsi_command_writ_no_param = 0x05, | ||
85 | dsi_command_long_write = 0x39, | ||
86 | dsi_command_max_return_pkt_size = 0x37, | ||
87 | dsi_command_generic_read_request_with_2_param = 0x24, | ||
88 | dsi_command_dcs_read_with_no_params = 0x06, | ||
89 | }; | ||
90 | |||
91 | /* Maximum polling time for reading the dsi status register */ | ||
92 | #define DSI_STATUS_POLLING_DURATION_USEC 100000 | ||
93 | #define DSI_STATUS_POLLING_DELAY_USEC 100 | ||
94 | |||
95 | /* | ||
96 | * Horizontal Sync Blank Packet Over head | ||
97 | * DSI_overhead = size_of(HS packet header) | ||
98 | * + size_of(BLANK packet header) + size_of(checksum) | ||
99 | * DSI_overhead = 4 + 4 + 2 = 10 | ||
100 | */ | ||
101 | #define DSI_HSYNC_BLNK_PKT_OVERHEAD 10 | ||
102 | |||
103 | /* | ||
104 | * Horizontal Front Porch Packet Overhead | ||
105 | * DSI_overhead = size_of(checksum) | ||
106 | * + size_of(BLANK packet header) + size_of(checksum) | ||
107 | * DSI_overhead = 2 + 4 + 2 = 8 | ||
108 | */ | ||
109 | #define DSI_HFRONT_PORCH_PKT_OVERHEAD 8 | ||
110 | |||
111 | /* | ||
112 | * Horizontal Back Porch Packet | ||
113 | * DSI_overhead = size_of(HE packet header) | ||
114 | * + size_of(BLANK packet header) + size_of(checksum) | ||
115 | * + size_of(RGB packet header) | ||
116 | * DSI_overhead = 4 + 4 + 2 + 4 = 14 | ||
117 | */ | ||
118 | #define DSI_HBACK_PORCH_PKT_OVERHEAD 14 | ||
119 | |||
120 | /* Additional Hs TX timeout margin */ | ||
121 | #define DSI_HTX_TO_MARGIN 720 | ||
122 | |||
123 | #define DSI_CYCLE_COUNTER_VALUE 512 | ||
124 | |||
125 | #define DSI_LRXH_TO_VALUE 0x2000 | ||
126 | |||
127 | /* Turn around timeout terminal count */ | ||
128 | #define DSI_TA_TO_VALUE 0x2000 | ||
129 | |||
130 | /* Turn around timeout tally */ | ||
131 | #define DSI_TA_TALLY_VALUE 0x0 | ||
132 | /* LP Rx timeout tally */ | ||
133 | #define DSI_LRXH_TALLY_VALUE 0x0 | ||
134 | /* HS Tx Timeout tally */ | ||
135 | #define DSI_HTX_TALLY_VALUE 0x0 | ||
136 | |||
137 | /* DSI Power control settle time 10 micro seconds */ | ||
138 | #define DSI_POWER_CONTROL_SETTLE_TIME_US 10 | ||
139 | |||
140 | #define DSI_HOST_FIFO_DEPTH 64 | ||
141 | #define DSI_VIDEO_FIFO_DEPTH 480 | ||
142 | #define DSI_READ_FIFO_DEPTH (32 << 2) | ||
143 | |||
144 | #define NUMOF_BIT_PER_BYTE 8 | ||
145 | #define DEFAULT_LP_CMD_MODE_CLK_KHZ 10000 | ||
146 | #define DEFAULT_MAX_DSI_PHY_CLK_KHZ (500*1000) | ||
147 | #define DEFAULT_PANEL_RESET_TIMEOUT 2 | ||
148 | #define DEFAULT_PANEL_BUFFER_BYTE 512 | ||
149 | |||
150 | /* | ||
151 | * TODO: are DSI_HOST_DSI_CONTROL_CRC_RESET(RESET_CRC) and | ||
152 | * DSI_HOST_DSI_CONTROL_HOST_TX_TRIG_SRC(IMMEDIATE) required for everyone? | ||
153 | */ | ||
154 | #define HOST_DSI_CTRL_COMMON \ | ||
155 | (DSI_HOST_DSI_CONTROL_PHY_CLK_DIV(DSI_PHY_CLK_DIV1) | \ | ||
156 | DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(NORMAL) | \ | ||
157 | DSI_HOST_DSI_CONTROL_PERIPH_RESET(TEGRA_DSI_DISABLE) | \ | ||
158 | DSI_HOST_DSI_CONTROL_RAW_DATA(TEGRA_DSI_DISABLE) | \ | ||
159 | DSI_HOST_DSI_CONTROL_IMM_BTA(TEGRA_DSI_DISABLE) | \ | ||
160 | DSI_HOST_DSI_CONTROL_PKT_BTA(TEGRA_DSI_DISABLE) | \ | ||
161 | DSI_HOST_DSI_CONTROL_CS_ENABLE(TEGRA_DSI_ENABLE) | \ | ||
162 | DSI_HOST_DSI_CONTROL_ECC_ENABLE(TEGRA_DSI_ENABLE) | \ | ||
163 | DSI_HOST_DSI_CONTROL_PKT_WR_FIFO_SEL(HOST_ONLY)) | ||
164 | |||
165 | #define HOST_DSI_CTRL_HOST_DRIVEN \ | ||
166 | (DSI_HOST_DSI_CONTROL_CRC_RESET(RESET_CRC) | \ | ||
167 | DSI_HOST_DSI_CONTROL_HOST_TX_TRIG_SRC(IMMEDIATE)) | ||
168 | |||
169 | #define HOST_DSI_CTRL_DC_DRIVEN 0 | ||
170 | |||
171 | #define DSI_CTRL_HOST_DRIVEN (DSI_CONTROL_VID_ENABLE(TEGRA_DSI_DISABLE) | \ | ||
172 | DSI_CONTROL_HOST_ENABLE(TEGRA_DSI_ENABLE)) | ||
173 | |||
174 | #define DSI_CTRL_DC_DRIVEN (DSI_CONTROL_VID_TX_TRIG_SRC(SOL) | \ | ||
175 | DSI_CONTROL_VID_ENABLE(TEGRA_DSI_ENABLE) | \ | ||
176 | DSI_CONTROL_HOST_ENABLE(TEGRA_DSI_DISABLE)) | ||
177 | |||
178 | #define DSI_CTRL_CMD_MODE (DSI_CONTROL_VID_DCS_ENABLE(TEGRA_DSI_ENABLE)) | ||
179 | |||
180 | #define DSI_CTRL_VIDEO_MODE (DSI_CONTROL_VID_DCS_ENABLE(TEGRA_DSI_DISABLE)) | ||
181 | |||
182 | |||
183 | enum { | ||
184 | CMD_VS = 0x01, | ||
185 | CMD_VE = 0x11, | ||
186 | |||
187 | CMD_HS = 0x21, | ||
188 | CMD_HE = 0x31, | ||
189 | |||
190 | CMD_EOT = 0x08, | ||
191 | CMD_NULL = 0x09, | ||
192 | CMD_SHORTW = 0x15, | ||
193 | CMD_BLNK = 0x19, | ||
194 | CMD_LONGW = 0x39, | ||
195 | |||
196 | CMD_RGB = 0x00, | ||
197 | CMD_RGB_16BPP = 0x0E, | ||
198 | CMD_RGB_18BPP = 0x1E, | ||
199 | CMD_RGB_18BPPNP = 0x2E, | ||
200 | CMD_RGB_24BPP = 0x3E, | ||
201 | }; | ||
202 | |||
203 | #define PKT_ID0(id) (DSI_PKT_SEQ_0_LO_PKT_00_ID(id) | \ | ||
204 | DSI_PKT_SEQ_1_LO_PKT_10_EN(TEGRA_DSI_ENABLE)) | ||
205 | #define PKT_LEN0(len) (DSI_PKT_SEQ_0_LO_PKT_00_SIZE(len)) | ||
206 | |||
207 | #define PKT_ID1(id) (DSI_PKT_SEQ_0_LO_PKT_01_ID(id) | \ | ||
208 | DSI_PKT_SEQ_1_LO_PKT_11_EN(TEGRA_DSI_ENABLE)) | ||
209 | #define PKT_LEN1(len) (DSI_PKT_SEQ_0_LO_PKT_01_SIZE(len)) | ||
210 | |||
211 | #define PKT_ID2(id) (DSI_PKT_SEQ_0_LO_PKT_02_ID(id) | \ | ||
212 | DSI_PKT_SEQ_1_LO_PKT_12_EN(TEGRA_DSI_ENABLE)) | ||
213 | #define PKT_LEN2(len) (DSI_PKT_SEQ_0_LO_PKT_02_SIZE(len)) | ||
214 | |||
215 | #define PKT_ID3(id) (DSI_PKT_SEQ_0_HI_PKT_03_ID(id) | \ | ||
216 | DSI_PKT_SEQ_1_HI_PKT_13_EN(TEGRA_DSI_ENABLE)) | ||
217 | #define PKT_LEN3(len) (DSI_PKT_SEQ_0_HI_PKT_03_SIZE(len)) | ||
218 | |||
219 | #define PKT_ID4(id) (DSI_PKT_SEQ_0_HI_PKT_04_ID(id) | \ | ||
220 | DSI_PKT_SEQ_1_HI_PKT_14_EN(TEGRA_DSI_ENABLE)) | ||
221 | #define PKT_LEN4(len) (DSI_PKT_SEQ_0_HI_PKT_04_SIZE(len)) | ||
222 | |||
223 | #define PKT_ID5(id) (DSI_PKT_SEQ_0_HI_PKT_05_ID(id) | \ | ||
224 | DSI_PKT_SEQ_1_HI_PKT_15_EN(TEGRA_DSI_ENABLE)) | ||
225 | #define PKT_LEN5(len) (DSI_PKT_SEQ_0_HI_PKT_05_SIZE(len)) | ||
226 | |||
227 | #define PKT_LP (DSI_PKT_SEQ_0_LO_SEQ_0_FORCE_LP(TEGRA_DSI_ENABLE)) | ||
228 | |||
229 | #define NUMOF_PKT_SEQ 12 | ||
230 | |||
231 | /* Mipi v1.00.00 phy timing range */ | ||
232 | #define NOT_DEFINED -1 | ||
233 | #define MIPI_T_HSEXIT_NS_MIN 100 | ||
234 | #define MIPI_T_HSEXIT_NS_MAX NOT_DEFINED | ||
235 | #define MIPI_T_HSTRAIL_NS_MIN(clk_ns) max((8 * (clk_ns)), (60 + 4 * (clk_ns))) | ||
236 | #define MIPI_T_HSTRAIL_NS_MAX NOT_DEFINED | ||
237 | #define MIPI_T_HSZERO_NS_MIN NOT_DEFINED | ||
238 | #define MIPI_T_HSZERO_NS_MAX NOT_DEFINED | ||
239 | #define MIPI_T_HSPREPARE_NS_MIN(clk_ns) (40 + 4 * (clk_ns)) | ||
240 | #define MIPI_T_HSPREPARE_NS_MAX(clk_ns) (85 + 6 * (clk_ns)) | ||
241 | #define MIPI_T_CLKTRAIL_NS_MIN 60 | ||
242 | #define MIPI_T_CLKTRAIL_NS_MAX NOT_DEFINED | ||
243 | #define MIPI_T_CLKPOST_NS_MIN(clk_ns) (60 + 52 * (clk_ns)) | ||
244 | #define MIPI_T_CLKPOST_NS_MAX NOT_DEFINED | ||
245 | #define MIPI_T_CLKZERO_NS_MIN NOT_DEFINED | ||
246 | #define MIPI_T_CLKZERO_NS_MAX NOT_DEFINED | ||
247 | #define MIPI_T_TLPX_NS_MIN 50 | ||
248 | #define MIPI_T_TLPX_NS_MAX NOT_DEFINED | ||
249 | #define MIPI_T_CLKPREPARE_NS_MIN 38 | ||
250 | #define MIPI_T_CLKPREPARE_NS_MAX 95 | ||
251 | #define MIPI_T_CLKPRE_NS_MIN 8 | ||
252 | #define MIPI_T_CLKPRE_NS_MAX NOT_DEFINED | ||
253 | #define MIPI_T_WAKEUP_NS_MIN 1 | ||
254 | #define MIPI_T_WAKEUP_NS_MAX NOT_DEFINED | ||
255 | #define MIPI_T_TASURE_NS_MIN(tlpx_ns) (tlpx_ns) | ||
256 | #define MIPI_T_TASURE_NS_MAX(tlpx_ns) (2 * (tlpx_ns)) | ||
257 | #define MIPI_T_HSPREPARE_ADD_HSZERO_NS_MIN(clk_ns) (145 + 10 * (clk_ns)) | ||
258 | #define MIPI_T_HSPREPARE_ADD_HSZERO_NS_MAX NOT_DEFINED | ||
259 | #define MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MIN 300 | ||
260 | #define MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MAX NOT_DEFINED | ||
261 | |||
262 | #define DSI_TBYTE(clk_ns) ((clk_ns) * (BITS_PER_BYTE)) | ||
263 | #define DSI_CONVERT_T_PHY_NS_TO_T_PHY(t_phy_ns, clk_ns, hw_inc) \ | ||
264 | ((int)((DIV_ROUND_CLOSEST((t_phy_ns), \ | ||
265 | (DSI_TBYTE(clk_ns)))) - (hw_inc))) | ||
266 | |||
267 | #define DSI_CONVERT_T_PHY_TO_T_PHY_NS(t_phy, clk_ns, hw_inc) \ | ||
268 | (((t_phy) + (hw_inc)) * (DSI_TBYTE(clk_ns))) | ||
269 | |||
270 | /* Default phy timing in ns */ | ||
271 | #define T_HSEXIT_NS_DEFAULT 120 | ||
272 | #define T_HSTRAIL_NS_DEFAULT(clk_ns) \ | ||
273 | max((8 * (clk_ns)), (60 + 4 * (clk_ns))) | ||
274 | |||
275 | #define T_DATZERO_NS_DEFAULT(clk_ns) (145 + 5 * (clk_ns)) | ||
276 | #define T_HSPREPARE_NS_DEFAULT(clk_ns) (65 + 5 * (clk_ns)) | ||
277 | #define T_CLKTRAIL_NS_DEFAULT 80 | ||
278 | #define T_CLKPOST_NS_DEFAULT(clk_ns) (70 + 52 * (clk_ns)) | ||
279 | #define T_CLKZERO_NS_DEFAULT 260 | ||
280 | #define T_TLPX_NS_DEFAULT 60 | ||
281 | #define T_CLKPREPARE_NS_DEFAULT 65 | ||
282 | #define T_TAGO_NS_DEFAULT (4 * (T_TLPX_NS_DEFAULT)) | ||
283 | #define T_TASURE_NS_DEFAULT (2 * (T_TLPX_NS_DEFAULT)) | ||
284 | #define T_TAGET_NS_DEFAULT (5 * (T_TLPX_NS_DEFAULT)) | ||
285 | |||
286 | /* HW increment to phy register values */ | ||
287 | #define T_HSEXIT_HW_INC 1 | ||
288 | #define T_HSTRAIL_HW_INC 0 | ||
289 | #define T_DATZERO_HW_INC 3 | ||
290 | #define T_HSPREPARE_HW_INC 1 | ||
291 | #define T_CLKTRAIL_HW_INC 1 | ||
292 | #define T_CLKPOST_HW_INC 1 | ||
293 | #define T_CLKZERO_HW_INC 1 | ||
294 | #define T_TLPX_HW_INC 1 | ||
295 | #define T_CLKPREPARE_HW_INC 1 | ||
296 | #define T_TAGO_HW_INC 1 | ||
297 | #define T_TASURE_HW_INC 1 | ||
298 | #define T_TAGET_HW_INC 1 | ||
299 | #define T_CLKPRE_HW_INC 1 | ||
300 | #define T_WAKEUP_HW_INC 1 | ||
301 | |||
302 | /* Default phy timing reg values */ | ||
303 | #define T_HSEXIT_DEFAULT(clk_ns) \ | ||
304 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
305 | T_HSEXIT_NS_DEFAULT, clk_ns, T_HSEXIT_HW_INC)) | ||
306 | |||
307 | #define T_HSTRAIL_DEFAULT(clk_ns) \ | ||
308 | (3 + (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
309 | T_HSTRAIL_NS_DEFAULT(clk_ns), clk_ns, T_HSTRAIL_HW_INC))) | ||
310 | |||
311 | #define T_DATZERO_DEFAULT(clk_ns) \ | ||
312 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
313 | T_DATZERO_NS_DEFAULT(clk_ns), clk_ns, T_DATZERO_HW_INC)) | ||
314 | |||
315 | #define T_HSPREPARE_DEFAULT(clk_ns) \ | ||
316 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
317 | T_HSPREPARE_NS_DEFAULT(clk_ns), clk_ns, T_HSPREPARE_HW_INC)) | ||
318 | |||
319 | #define T_CLKTRAIL_DEFAULT(clk_ns) \ | ||
320 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
321 | T_CLKTRAIL_NS_DEFAULT, clk_ns, T_CLKTRAIL_HW_INC)) | ||
322 | |||
323 | #define T_CLKPOST_DEFAULT(clk_ns) \ | ||
324 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
325 | T_CLKPOST_NS_DEFAULT(clk_ns), clk_ns, T_CLKPOST_HW_INC)) | ||
326 | |||
327 | #define T_CLKZERO_DEFAULT(clk_ns) \ | ||
328 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
329 | T_CLKZERO_NS_DEFAULT, clk_ns, T_CLKZERO_HW_INC)) | ||
330 | |||
331 | #define T_TLPX_DEFAULT(clk_ns) \ | ||
332 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
333 | T_TLPX_NS_DEFAULT, clk_ns, T_TLPX_HW_INC)) | ||
334 | |||
335 | #define T_CLKPREPARE_DEFAULT(clk_ns) \ | ||
336 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
337 | T_CLKPREPARE_NS_DEFAULT, clk_ns, T_CLKPREPARE_HW_INC)) | ||
338 | |||
339 | #define T_CLKPRE_DEFAULT 0x1 | ||
340 | #define T_WAKEUP_DEFAULT 0x7f | ||
341 | |||
342 | #define T_TAGO_DEFAULT(clk_ns) \ | ||
343 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
344 | T_TAGO_NS_DEFAULT, clk_ns, T_TAGO_HW_INC)) | ||
345 | |||
346 | #define T_TASURE_DEFAULT(clk_ns) \ | ||
347 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
348 | T_TASURE_NS_DEFAULT, clk_ns, T_TASURE_HW_INC)) | ||
349 | |||
350 | #define T_TAGET_DEFAULT(clk_ns) \ | ||
351 | (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \ | ||
352 | T_TAGET_NS_DEFAULT, clk_ns, T_TAGET_HW_INC)) | ||
353 | |||
354 | /* Defines the DSI phy timing parameters */ | ||
355 | struct dsi_phy_timing_inclk { | ||
356 | unsigned t_hsdexit; | ||
357 | unsigned t_hstrail; | ||
358 | unsigned t_hsprepare; | ||
359 | unsigned t_datzero; | ||
360 | |||
361 | unsigned t_clktrail; | ||
362 | unsigned t_clkpost; | ||
363 | unsigned t_clkzero; | ||
364 | unsigned t_tlpx; | ||
365 | |||
366 | unsigned t_clkpre; | ||
367 | unsigned t_clkprepare; | ||
368 | unsigned t_wakeup; | ||
369 | |||
370 | unsigned t_taget; | ||
371 | unsigned t_tasure; | ||
372 | unsigned t_tago; | ||
373 | }; | ||
374 | |||
375 | #endif | ||
diff --git a/drivers/video/tegra/dc/dsi_regs.h b/drivers/video/tegra/dc/dsi_regs.h new file mode 100644 index 00000000000..203ac32bd92 --- /dev/null +++ b/drivers/video/tegra/dc/dsi_regs.h | |||
@@ -0,0 +1,351 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dsi_regs.h | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_DSI_REG_H__ | ||
18 | #define __DRIVERS_VIDEO_TEGRA_DC_DSI_REG_H__ | ||
19 | |||
20 | enum { | ||
21 | TEGRA_DSI_DISABLE, | ||
22 | TEGRA_DSI_ENABLE, | ||
23 | }; | ||
24 | |||
25 | /* These are word offsets from base (not byte offsets) */ | ||
26 | enum { | ||
27 | OP_DONE = 1, | ||
28 | }; | ||
29 | #define DSI_INCR_SYNCPT 0x00 | ||
30 | #define DSI_INCR_SYNCPT_COND(x) (((x) & 0xff) << 8) | ||
31 | #define DSI_INCR_SYNCPT_INDX(x) (((x) & 0xff) << 0) | ||
32 | |||
33 | #define DSI_INCR_SYNCPT_CNTRL 0x01 | ||
34 | #define DSI_INCR_SYNCPT_ERROR 0x02 | ||
35 | #define DSI_CTXSW 0x08 | ||
36 | #define DSI_RD_DATA 0x09 | ||
37 | #define DSI_WR_DATA 0x0a | ||
38 | |||
39 | #define DSI_POWER_CONTROL 0x0b | ||
40 | #define DSI_POWER_CONTROL_LEG_DSI_ENABLE(x) (((x) & 0x1) << 0) | ||
41 | |||
42 | #define DSI_INT_ENABLE 0x0c | ||
43 | #define DSI_INT_STATUS 0x0d | ||
44 | #define DSI_INT_MASK 0x0e | ||
45 | |||
46 | #define DSI_HOST_DSI_CONTROL 0x0f | ||
47 | enum { | ||
48 | RESET_CRC = 1, | ||
49 | }; | ||
50 | #define DSI_HOST_CONTROL_FIFO_STAT_RESET(x) (((x) & 0x1) << 21) | ||
51 | #define DSI_HOST_DSI_CONTROL_CRC_RESET(x) (((x) & 0x1) << 20) | ||
52 | enum { | ||
53 | DSI_PHY_CLK_DIV1, | ||
54 | DSI_PHY_CLK_DIV2, | ||
55 | }; | ||
56 | #define DSI_HOST_DSI_CONTROL_PHY_CLK_DIV(x) (((x) & 0x7) << 16) | ||
57 | enum { | ||
58 | SOL, | ||
59 | FIFO_LEVEL, | ||
60 | IMMEDIATE, | ||
61 | }; | ||
62 | #define DSI_HOST_DSI_CONTROL_HOST_TX_TRIG_SRC(x) (((x) & 0x3) << 12) | ||
63 | enum { | ||
64 | NORMAL, | ||
65 | ENTER_ULPM, | ||
66 | EXIT_ULPM, | ||
67 | }; | ||
68 | #define DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(x) (((x) & 0x3) << 8) | ||
69 | #define DSI_HOST_DSI_CONTROL_PERIPH_RESET(x) (((x) & 0x1) << 7) | ||
70 | #define DSI_HOST_DSI_CONTROL_RAW_DATA(x) (((x) & 0x1) << 6) | ||
71 | enum { | ||
72 | TEGRA_DSI_LOW, | ||
73 | TEGRA_DSI_HIGH, | ||
74 | }; | ||
75 | #define DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(x) (((x) & 0x1) << 5) | ||
76 | enum { | ||
77 | HOST_ONLY, | ||
78 | VIDEO_HOST, | ||
79 | }; | ||
80 | #define DSI_HOST_DSI_CONTROL_PKT_WR_FIFO_SEL(x) (((x) & 0x1) << 4) | ||
81 | #define DSI_HOST_DSI_CONTROL_IMM_BTA(x) (((x) & 0x1) << 3) | ||
82 | #define DSI_HOST_DSI_CONTROL_PKT_BTA(x) (((x) & 0x1) << 2) | ||
83 | #define DSI_HOST_DSI_CONTROL_CS_ENABLE(x) (((x) & 0x1) << 1) | ||
84 | #define DSI_HOST_DSI_CONTROL_ECC_ENABLE(x) (((x) & 0x1) << 0) | ||
85 | |||
86 | #define DSI_CONTROL 0x10 | ||
87 | #define DSI_CONTROL_DBG_ENABLE(x) (((x) & 0x1) << 31) | ||
88 | enum { | ||
89 | CONTINUOUS, | ||
90 | TX_ONLY, | ||
91 | }; | ||
92 | #define DSI_CONTROL_HS_CLK_CTRL(x) (((x) & 0x1) << 20) | ||
93 | #define DSI_CONTROL_VIRTUAL_CHANNEL(x) (((x) & 0x3) << 16) | ||
94 | #define DSI_CONTROL_DATA_FORMAT(x) (((x) & 0x3) << 12) | ||
95 | #define DSI_CONTROL_VID_TX_TRIG_SRC(x) (((x) & 0x3) << 8) | ||
96 | #define DSI_CONTROL_NUM_DATA_LANES(x) (((x) & 0x3) << 4) | ||
97 | #define DSI_CONTROL_VID_DCS_ENABLE(x) (((x) & 0x1) << 3) | ||
98 | #define DSI_CONTROL_VID_SOURCE(x) (((x) & 0x1) << 2) | ||
99 | #define DSI_CONTROL_VID_ENABLE(x) (((x) & 0x1) << 1) | ||
100 | #define DSI_CONTROL_HOST_ENABLE(x) (((x) & 0x1) << 0) | ||
101 | |||
102 | #define DSI_SOL_DELAY 0x11 | ||
103 | #define DSI_SOL_DELAY_SOL_DELAY(x) (((x) & 0xffff) << 0) | ||
104 | |||
105 | #define DSI_MAX_THRESHOLD 0x12 | ||
106 | #define DSI_MAX_THRESHOLD_MAX_THRESHOLD(x) (((x) & 0xffff) << 0) | ||
107 | |||
108 | #define DSI_TRIGGER 0x13 | ||
109 | #define DSI_TRIGGER_HOST_TRIGGER(x) (((x) & 0x1) << 1) | ||
110 | #define DSI_TRIGGER_VID_TRIGGER(x) (((x) & 0x1) << 0) | ||
111 | |||
112 | #define DSI_TX_CRC 0x14 | ||
113 | #define DSI_TX_CRC_TX_CRC(x) (((x) & 0xffffffff) << 0) | ||
114 | |||
115 | #define DSI_STATUS 0x15 | ||
116 | #define DSI_STATUS_IDLE(x) (((x) & 0x1) << 10) | ||
117 | #define DSI_STATUS_LB_UNDERFLOW(x) (((x) & 0x1) << 9) | ||
118 | #define DSI_STATUS_LB_OVERFLOW(x) (((x) & 0x1) << 8) | ||
119 | #define DSI_STATUS_RD_FIFO_COUNT(x) (((x) & 0x1f) << 0) | ||
120 | |||
121 | #define DSI_INIT_SEQ_CONTROL 0x1a | ||
122 | #define DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(x) \ | ||
123 | (((x) & 0x3f) << 8) | ||
124 | #define DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(x) \ | ||
125 | (((x) & 0xff) << 0) | ||
126 | |||
127 | #define DSI_INIT_SEQ_DATA_0 0x1b | ||
128 | #define DSI_INIT_SEQ_DATA_1 0x1c | ||
129 | #define DSI_INIT_SEQ_DATA_2 0x1d | ||
130 | #define DSI_INIT_SEQ_DATA_3 0x1e | ||
131 | #define DSI_INIT_SEQ_DATA_4 0x1f | ||
132 | #define DSI_INIT_SEQ_DATA_5 0x20 | ||
133 | #define DSI_INIT_SEQ_DATA_6 0x21 | ||
134 | #define DSI_INIT_SEQ_DATA_7 0x22 | ||
135 | |||
136 | #define DSI_PKT_SEQ_0_LO 0x23 | ||
137 | #define DSI_PKT_SEQ_0_LO_SEQ_0_FORCE_LP(x) (((x) & 0x1) << 30) | ||
138 | #define DSI_PKT_SEQ_0_LO_PKT_02_EN(x) (((x) & 0x1) << 29) | ||
139 | #define DSI_PKT_SEQ_0_LO_PKT_02_ID(x) (((x) & 0x3f) << 23) | ||
140 | #define DSI_PKT_SEQ_0_LO_PKT_02_SIZE(x) (((x) & 0x7) << 20) | ||
141 | #define DSI_PKT_SEQ_0_LO_PKT_01_EN(x) (((x) & 0x1) << 19) | ||
142 | #define DSI_PKT_SEQ_0_LO_PKT_01_ID(x) (((x) & 0x3f) << 13) | ||
143 | #define DSI_PKT_SEQ_0_LO_PKT_01_SIZE(x) (((x) & 0x7) << 10) | ||
144 | #define DSI_PKT_SEQ_0_LO_PKT_00_EN(x) (((x) & 0x1) << 9) | ||
145 | #define DSI_PKT_SEQ_0_LO_PKT_00_ID(x) (((x) & 0x3f) << 3) | ||
146 | #define DSI_PKT_SEQ_0_LO_PKT_00_SIZE(x) (((x) & 0x7) << 0) | ||
147 | |||
148 | #define DSI_PKT_SEQ_0_HI 0x24 | ||
149 | #define DSI_PKT_SEQ_0_HI_PKT_05_EN(x) (((x) & 0x1) << 29) | ||
150 | #define DSI_PKT_SEQ_0_HI_PKT_05_ID(x) (((x) & 0x3f) << 23) | ||
151 | #define DSI_PKT_SEQ_0_HI_PKT_05_SIZE(x) (((x) & 0x7) << 20) | ||
152 | #define DSI_PKT_SEQ_0_HI_PKT_04_EN(x) (((x) & 0x1) << 19) | ||
153 | #define DSI_PKT_SEQ_0_HI_PKT_04_ID(x) (((x) & 0x3f) << 13) | ||
154 | #define DSI_PKT_SEQ_0_HI_PKT_04_SIZE(x) (((x) & 0x7) << 10) | ||
155 | #define DSI_PKT_SEQ_0_HI_PKT_03_EN(x) (((x) & 0x1) << 9) | ||
156 | #define DSI_PKT_SEQ_0_HI_PKT_03_ID(x) (((x) & 0x3f) << 3) | ||
157 | #define DSI_PKT_SEQ_0_HI_PKT_03_SIZE(x) (((x) & 0x7) << 0) | ||
158 | |||
159 | #define DSI_PKT_SEQ_1_LO 0x25 | ||
160 | #define DSI_PKT_SEQ_1_LO_SEQ_1_FORCE_LP(x) (((x) & 0x1) << 30) | ||
161 | #define DSI_PKT_SEQ_1_LO_PKT_12_EN(x) (((x) & 0x1) << 29) | ||
162 | #define DSI_PKT_SEQ_1_LO_PKT_12_ID(x) (((x) & 0x3f) << 23) | ||
163 | #define DSI_PKT_SEQ_1_LO_PKT_12_SIZE(x) (((x) & 0x7) << 20) | ||
164 | #define DSI_PKT_SEQ_1_LO_PKT_11_EN(x) (((x) & 0x1) << 19) | ||
165 | #define DSI_PKT_SEQ_1_LO_PKT_11_ID(x) (((x) & 0x3f) << 13) | ||
166 | #define DSI_PKT_SEQ_1_LO_PKT_11_SIZE(x) (((x) & 0x7) << 10) | ||
167 | #define DSI_PKT_SEQ_1_LO_PKT_10_EN(x) (((x) & 0x1) << 9) | ||
168 | #define DSI_PKT_SEQ_1_LO_PKT_10_ID(x) (((x) & 0x3f) << 3) | ||
169 | #define DSI_PKT_SEQ_1_LO_PKT_10_SIZE(x) (((x) & 0x7) << 0) | ||
170 | |||
171 | #define DSI_PKT_SEQ_1_HI 0x26 | ||
172 | #define DSI_PKT_SEQ_1_HI_PKT_15_EN(x) (((x) & 0x1) << 29) | ||
173 | #define DSI_PKT_SEQ_1_HI_PKT_15_ID(x) (((x) & 0x3f) << 23) | ||
174 | #define DSI_PKT_SEQ_1_HI_PKT_15_SIZE(x) (((x) & 0x7) << 20) | ||
175 | #define DSI_PKT_SEQ_1_HI_PKT_14_EN(x) (((x) & 0x1) << 19) | ||
176 | #define DSI_PKT_SEQ_1_HI_PKT_14_ID(x) (((x) & 0x3f) << 13) | ||
177 | #define DSI_PKT_SEQ_1_HI_PKT_14_SIZE(x) (((x) & 0x7) << 10) | ||
178 | #define DSI_PKT_SEQ_1_HI_PKT_13_EN(x) (((x) & 0x1) << 9) | ||
179 | #define DSI_PKT_SEQ_1_HI_PKT_13_ID(x) (((x) & 0x3f) << 3) | ||
180 | #define DSI_PKT_SEQ_1_HI_PKT_13_SIZE(x) (((x) & 0x7) << 0) | ||
181 | |||
182 | #define DSI_PKT_SEQ_2_LO 0x27 | ||
183 | #define DSI_PKT_SEQ_2_LO_SEQ_2_FORCE_LP(x) (((x) & 0x1) << 30) | ||
184 | #define DSI_PKT_SEQ_2_LO_PKT_22_EN(x) (((x) & 0x1) << 29) | ||
185 | #define DSI_PKT_SEQ_2_LO_PKT_22_ID(x) (((x) & 0x3f) << 23) | ||
186 | #define DSI_PKT_SEQ_2_LO_PKT_22_SIZE(x) (((x) & 0x7) << 20) | ||
187 | #define DSI_PKT_SEQ_2_LO_PKT_21_EN(x) (((x) & 0x1) << 19) | ||
188 | #define DSI_PKT_SEQ_2_LO_PKT_21_ID(x) (((x) & 0x3f) << 13) | ||
189 | #define DSI_PKT_SEQ_2_LO_PKT_21_SIZE(x) (((x) & 0x7) << 10) | ||
190 | #define DSI_PKT_SEQ_2_LO_PKT_20_EN(x) (((x) & 0x1) << 9) | ||
191 | #define DSI_PKT_SEQ_2_LO_PKT_20_ID(x) (((x) & 0x3f) << 3) | ||
192 | #define DSI_PKT_SEQ_2_LO_PKT_20_SIZE(x) (((x) & 0x7) << 0) | ||
193 | |||
194 | #define DSI_PKT_SEQ_2_HI 0x28 | ||
195 | #define DSI_PKT_SEQ_2_HI_PKT_25_EN(x) (((x) & 0x1) << 29) | ||
196 | #define DSI_PKT_SEQ_2_HI_PKT_25_ID(x) (((x) & 0x3f) << 23) | ||
197 | #define DSI_PKT_SEQ_2_HI_PKT_25_SIZE(x) (((x) & 0x7) << 20) | ||
198 | #define DSI_PKT_SEQ_2_HI_PKT_24_EN(x) (((x) & 0x1) << 19) | ||
199 | #define DSI_PKT_SEQ_2_HI_PKT_24_ID(x) (((x) & 0x3f) << 13) | ||
200 | #define DSI_PKT_SEQ_2_HI_PKT_24_SIZE(x) (((x) & 0x7) << 10) | ||
201 | #define DSI_PKT_SEQ_2_HI_PKT_23_EN(x) (((x) & 0x1) << 9) | ||
202 | #define DSI_PKT_SEQ_2_HI_PKT_23_ID(x) (((x) & 0x3f) << 3) | ||
203 | #define DSI_PKT_SEQ_2_HI_PKT_23_SIZE(x) (((x) & 0x7) << 0) | ||
204 | |||
205 | #define DSI_PKT_SEQ_3_LO 0x29 | ||
206 | #define DSI_PKT_SEQ_3_LO_SEQ_3_FORCE_LP(x) (((x) & 0x1) << 30) | ||
207 | #define DSI_PKT_SEQ_3_LO_PKT_32_EN(x) (((x) & 0x1) << 29) | ||
208 | #define DSI_PKT_SEQ_3_LO_PKT_32_ID(x) (((x) & 0x3f) << 23) | ||
209 | #define DSI_PKT_SEQ_3_LO_PKT_32_SIZE(x) (((x) & 0x7) << 20) | ||
210 | #define DSI_PKT_SEQ_3_LO_PKT_31_EN(x) (((x) & 0x1) << 19) | ||
211 | #define DSI_PKT_SEQ_3_LO_PKT_31_ID(x) (((x) & 0x3f) << 13) | ||
212 | #define DSI_PKT_SEQ_3_LO_PKT_31_SIZE(x) (((x) & 0x7) << 10) | ||
213 | #define DSI_PKT_SEQ_3_LO_PKT_30_EN(x) (((x) & 0x1) << 9) | ||
214 | #define DSI_PKT_SEQ_3_LO_PKT_30_ID(x) (((x) & 0x3f) << 3) | ||
215 | #define DSI_PKT_SEQ_3_LO_PKT_30_SIZE(x) (((x) & 0x7) << 0) | ||
216 | |||
217 | #define DSI_PKT_SEQ_3_HI 0x2a | ||
218 | #define DSI_PKT_SEQ_3_HI_PKT_35_EN(x) (((x) & 0x1) << 29) | ||
219 | #define DSI_PKT_SEQ_3_HI_PKT_35_ID(x) (((x) & 0x3f) << 23) | ||
220 | #define DSI_PKT_SEQ_3_HI_PKT_35_SIZE(x) (((x) & 0x7) << 20) | ||
221 | #define DSI_PKT_SEQ_3_HI_PKT_34_EN(x) (((x) & 0x1) << 19) | ||
222 | #define DSI_PKT_SEQ_3_HI_PKT_34_ID(x) (((x) & 0x3f) << 13) | ||
223 | #define DSI_PKT_SEQ_3_HI_PKT_34_SIZE(x) (((x) & 0x7) << 10) | ||
224 | #define DSI_PKT_SEQ_3_HI_PKT_33_EN(x) (((x) & 0x1) << 9) | ||
225 | #define DSI_PKT_SEQ_3_HI_PKT_33_ID(x) (((x) & 0x3f) << 3) | ||
226 | #define DSI_PKT_SEQ_3_HI_PKT_33_SIZE(x) (((x) & 0x7) << 0) | ||
227 | |||
228 | #define DSI_PKT_SEQ_4_LO 0x2b | ||
229 | #define DSI_PKT_SEQ_4_LO_SEQ_4_FORCE_LP(x) (((x) & 0x1) << 30) | ||
230 | #define DSI_PKT_SEQ_4_LO_PKT_42_EN(x) (((x) & 0x1) << 29) | ||
231 | #define DSI_PKT_SEQ_4_LO_PKT_42_ID(x) (((x) & 0x3f) << 23) | ||
232 | #define DSI_PKT_SEQ_4_LO_PKT_42_SIZE(x) (((x) & 0x7) << 20) | ||
233 | #define DSI_PKT_SEQ_4_LO_PKT_41_EN(x) (((x) & 0x1) << 19) | ||
234 | #define DSI_PKT_SEQ_4_LO_PKT_41_ID(x) (((x) & 0x3f) << 13) | ||
235 | #define DSI_PKT_SEQ_4_LO_PKT_41_SIZE(x) (((x) & 0x7) << 10) | ||
236 | #define DSI_PKT_SEQ_4_LO_PKT_40_EN(x) (((x) & 0x1) << 9) | ||
237 | #define DSI_PKT_SEQ_4_LO_PKT_40_ID(x) (((x) & 0x3f) << 3) | ||
238 | #define DSI_PKT_SEQ_4_LO_PKT_40_SIZE(x) (((x) & 0x7) << 0) | ||
239 | |||
240 | #define DSI_PKT_SEQ_4_HI 0x2c | ||
241 | #define DSI_PKT_SEQ_4_HI_PKT_45_EN(x) (((x) & 0x1) << 29) | ||
242 | #define DSI_PKT_SEQ_4_HI_PKT_45_ID(x) (((x) & 0x3f) << 23) | ||
243 | #define DSI_PKT_SEQ_4_HI_PKT_45_SIZE(x) (((x) & 0x7) << 20) | ||
244 | #define DSI_PKT_SEQ_4_HI_PKT_44_EN(x) (((x) & 0x1) << 19) | ||
245 | #define DSI_PKT_SEQ_4_HI_PKT_44_ID(x) (((x) & 0x3f) << 13) | ||
246 | #define DSI_PKT_SEQ_4_HI_PKT_44_SIZE(x) (((x) & 0x7) << 10) | ||
247 | #define DSI_PKT_SEQ_4_HI_PKT_43_EN(x) (((x) & 0x1) << 9) | ||
248 | #define DSI_PKT_SEQ_4_HI_PKT_43_ID(x) (((x) & 0x3f) << 3) | ||
249 | #define DSI_PKT_SEQ_4_HI_PKT_43_SIZE(x) (((x) & 0x7) << 0) | ||
250 | |||
251 | #define DSI_PKT_SEQ_5_LO 0x2d | ||
252 | #define DSI_PKT_SEQ_5_LO_SEQ_5_FORCE_LP(x) (((x) & 0x1) << 30) | ||
253 | #define DSI_PKT_SEQ_5_LO_PKT_52_EN(x) (((x) & 0x1) << 29) | ||
254 | #define DSI_PKT_SEQ_5_LO_PKT_52_ID(x) (((x) & 0x3f) << 23) | ||
255 | #define DSI_PKT_SEQ_5_LO_PKT_52_SIZE(x) (((x) & 0x7) << 20) | ||
256 | #define DSI_PKT_SEQ_5_LO_PKT_51_EN(x) (((x) & 0x1) << 19) | ||
257 | #define DSI_PKT_SEQ_5_LO_PKT_51_ID(x) (((x) & 0x3f) << 13) | ||
258 | #define DSI_PKT_SEQ_5_LO_PKT_51_SIZE(x) (((x) & 0x7) << 10) | ||
259 | #define DSI_PKT_SEQ_5_LO_PKT_50_EN(x) (((x) & 0x1) << 9) | ||
260 | #define DSI_PKT_SEQ_5_LO_PKT_50_ID(x) (((x) & 0x3f) << 3) | ||
261 | #define DSI_PKT_SEQ_5_LO_PKT_50_SIZE(x) (((x) & 0x7) << 0) | ||
262 | |||
263 | #define DSI_PKT_SEQ_5_HI 0x2e | ||
264 | #define DSI_PKT_SEQ_5_HI_PKT_55_EN(x) (((x) & 0x1) << 29) | ||
265 | #define DSI_PKT_SEQ_5_HI_PKT_55_ID(x) (((x) & 0x3f) << 23) | ||
266 | #define DSI_PKT_SEQ_5_HI_PKT_55_SIZE(x) (((x) & 0x7) << 20) | ||
267 | #define DSI_PKT_SEQ_5_HI_PKT_54_EN(x) (((x) & 0x1) << 19) | ||
268 | #define DSI_PKT_SEQ_5_HI_PKT_54_ID(x) (((x) & 0x3f) << 13) | ||
269 | #define DSI_PKT_SEQ_5_HI_PKT_54_SIZE(x) (((x) & 0x7) << 10) | ||
270 | #define DSI_PKT_SEQ_5_HI_PKT_53_EN(x) (((x) & 0x1) << 9) | ||
271 | #define DSI_PKT_SEQ_5_HI_PKT_53_ID(x) (((x) & 0x3f) << 3) | ||
272 | #define DSI_PKT_SEQ_5_HI_PKT_53_SIZE(x) (((x) & 0x7) << 0) | ||
273 | |||
274 | #define DSI_DCS_CMDS 0x33 | ||
275 | #define DSI_DCS_CMDS_LT5_DCS_CMD(x) (((x) & 0xff) << 8) | ||
276 | #define DSI_DCS_CMDS_LT3_DCS_CMD(x) (((x) & 0xff) << 0) | ||
277 | |||
278 | #define DSI_PKT_LEN_0_1 0x34 | ||
279 | #define DSI_PKT_LEN_0_1_LENGTH_1(x) (((x) & 0xffff) << 16) | ||
280 | #define DSI_PKT_LEN_0_1_LENGTH_0(x) (((x) & 0xffff) << 0) | ||
281 | |||
282 | #define DSI_PKT_LEN_2_3 0x35 | ||
283 | #define DSI_PKT_LEN_2_3_LENGTH_3(x) (((x) & 0xffff) << 16) | ||
284 | #define DSI_PKT_LEN_2_3_LENGTH_2(x) (((x) & 0xffff) << 0) | ||
285 | |||
286 | |||
287 | #define DSI_PKT_LEN_4_5 0x36 | ||
288 | #define DSI_PKT_LEN_4_5_LENGTH_5(x) (((x) & 0xffff) << 16) | ||
289 | #define DSI_PKT_LEN_4_5_LENGTH_4(x) (((x) & 0xffff) << 0) | ||
290 | |||
291 | #define DSI_PKT_LEN_6_7 0x37 | ||
292 | #define DSI_PKT_LEN_6_7_LENGTH_7(x) (((x) & 0xffff) << 16) | ||
293 | #define DSI_PKT_LEN_6_7_LENGTH_6(x) (((x) & 0xffff) << 0) | ||
294 | |||
295 | #define DSI_PHY_TIMING_0 0x3c | ||
296 | #define DSI_PHY_TIMING_0_THSDEXIT(x) (((x) & 0xff) << 24) | ||
297 | #define DSI_PHY_TIMING_0_THSTRAIL(x) (((x) & 0xff) << 16) | ||
298 | #define DSI_PHY_TIMING_0_TDATZERO(x) (((x) & 0xff) << 8) | ||
299 | #define DSI_PHY_TIMING_0_THSPREPR(x) (((x) & 0xff) << 0) | ||
300 | |||
301 | #define DSI_PHY_TIMING_1 0x3d | ||
302 | #define DSI_PHY_TIMING_1_TCLKTRAIL(x) (((x) & 0xff) << 24) | ||
303 | #define DSI_PHY_TIMING_1_TCLKPOST(x) (((x) & 0xff) << 16) | ||
304 | #define DSI_PHY_TIMING_1_TCLKZERO(x) (((x) & 0xff) << 8) | ||
305 | #define DSI_PHY_TIMING_1_TTLPX(x) (((x) & 0xff) << 0) | ||
306 | |||
307 | #define DSI_PHY_TIMING_2 0x3e | ||
308 | #define DSI_PHY_TIMING_2_TCLKPREPARE(x) (((x) & 0xff) << 16) | ||
309 | #define DSI_PHY_TIMING_2_TCLKPRE(x) (((x) & 0xff) << 8) | ||
310 | #define DSI_PHY_TIMING_2_TWAKEUP(x) (((x) & 0xff) << 0) | ||
311 | |||
312 | #define DSI_BTA_TIMING 0x3f | ||
313 | #define DSI_BTA_TIMING_TTAGET(x) (((x) & 0xff) << 16) | ||
314 | #define DSI_BTA_TIMING_TTASURE(x) (((x) & 0xff) << 8) | ||
315 | #define DSI_BTA_TIMING_TTAGO(x) (((x) & 0xff) << 0) | ||
316 | |||
317 | |||
318 | #define DSI_TIMEOUT_0 0x44 | ||
319 | #define DSI_TIMEOUT_0_LRXH_TO(x) (((x) & 0xffff) << 16) | ||
320 | #define DSI_TIMEOUT_0_HTX_TO(x) (((x) & 0xffff) << 0) | ||
321 | |||
322 | #define DSI_TIMEOUT_1 0x45 | ||
323 | #define DSI_TIMEOUT_1_PR_TO(x) (((x) & 0xffff) << 16) | ||
324 | #define DSI_TIMEOUT_1_TA_TO(x) (((x) & 0xffff) << 0) | ||
325 | |||
326 | #define DSI_TO_TALLY 0x46 | ||
327 | enum { | ||
328 | IN_RESET, | ||
329 | READY, | ||
330 | }; | ||
331 | #define DSI_TO_TALLY_P_RESET_STATUS(x) (((x) & 0x1) << 24) | ||
332 | #define DSI_TO_TALLY_TA_TALLY(x) (((x) & 0xff) << 16) | ||
333 | #define DSI_TO_TALLY_LRXH_TALLY(x) (((x) & 0xff) << 8) | ||
334 | #define DSI_TO_TALLY_HTX_TALLY(x) (((x) & 0xff) << 0) | ||
335 | |||
336 | #define DSI_PAD_CONTROL 0x4b | ||
337 | #define DSI_PAD_CONTROL_PAD_PULLDN_ENAB(x) (((x) & 0x1) << 28) | ||
338 | #define DSI_PAD_CONTROL_PAD_SLEWUPADJ(x) (((x) & 0x7) << 24) | ||
339 | #define DSI_PAD_CONTROL_PAD_SLEWDNADJ(x) (((x) & 0x7) << 20) | ||
340 | #define DSI_PAD_CONTROL_PAD_PREEMP_EN(x) (((x) & 0x1) << 19) | ||
341 | #define DSI_PAD_CONTROL_PAD_PDIO_CLK(x) (((x) & 0x1) << 18) | ||
342 | #define DSI_PAD_CONTROL_PAD_PDIO(x) (((x) & 0x3) << 16) | ||
343 | #define DSI_PAD_CONTROL_PAD_LPUPADJ(x) (((x) & 0x3) << 14) | ||
344 | #define DSI_PAD_CONTROL_PAD_LPDNADJ(x) (((x) & 0x3) << 12) | ||
345 | |||
346 | #define DSI_PAD_CONTROL_CD 0x4c | ||
347 | #define DSI_PAD_CD_STATUS 0x4d | ||
348 | #define DSI_VID_MODE_CONTROL 0x4e | ||
349 | |||
350 | #endif | ||
351 | |||
diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c new file mode 100644 index 00000000000..fbcf2cc8e37 --- /dev/null +++ b/drivers/video/tegra/dc/edid.c | |||
@@ -0,0 +1,619 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/edid.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * Copyright (C) 2010-2011 NVIDIA Corporation | ||
8 | * | ||
9 | * This software is licensed under the terms of the GNU General Public | ||
10 | * License version 2, as published by the Free Software Foundation, and | ||
11 | * may be copied, distributed, and modified under those terms. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | |||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/fb.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | |||
27 | #include "edid.h" | ||
28 | |||
29 | struct tegra_edid_pvt { | ||
30 | struct kref refcnt; | ||
31 | struct tegra_edid_hdmi_eld eld; | ||
32 | bool support_stereo; | ||
33 | bool support_underscan; | ||
34 | /* Note: dc_edid must remain the last member */ | ||
35 | struct tegra_dc_edid dc_edid; | ||
36 | }; | ||
37 | |||
38 | struct tegra_edid { | ||
39 | struct i2c_client *client; | ||
40 | struct i2c_board_info info; | ||
41 | int bus; | ||
42 | |||
43 | struct tegra_edid_pvt *data; | ||
44 | |||
45 | struct mutex lock; | ||
46 | }; | ||
47 | |||
48 | #if defined(DEBUG) || defined(CONFIG_DEBUG_FS) | ||
49 | static int tegra_edid_show(struct seq_file *s, void *unused) | ||
50 | { | ||
51 | struct tegra_edid *edid = s->private; | ||
52 | struct tegra_dc_edid *data; | ||
53 | u8 *buf; | ||
54 | int i; | ||
55 | |||
56 | data = tegra_edid_get_data(edid); | ||
57 | if (!data) { | ||
58 | seq_printf(s, "No EDID\n"); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | buf = data->buf; | ||
63 | |||
64 | for (i = 0; i < data->len; i++) { | ||
65 | if (i % 16 == 0) | ||
66 | seq_printf(s, "edid[%03x] =", i); | ||
67 | |||
68 | seq_printf(s, " %02x", buf[i]); | ||
69 | |||
70 | if (i % 16 == 15) | ||
71 | seq_printf(s, "\n"); | ||
72 | } | ||
73 | |||
74 | tegra_edid_put_data(data); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | #endif | ||
79 | |||
80 | #ifdef CONFIG_DEBUG_FS | ||
81 | static int tegra_edid_debug_open(struct inode *inode, struct file *file) | ||
82 | { | ||
83 | return single_open(file, tegra_edid_show, inode->i_private); | ||
84 | } | ||
85 | |||
86 | static const struct file_operations tegra_edid_debug_fops = { | ||
87 | .open = tegra_edid_debug_open, | ||
88 | .read = seq_read, | ||
89 | .llseek = seq_lseek, | ||
90 | .release = single_release, | ||
91 | }; | ||
92 | |||
93 | void tegra_edid_debug_add(struct tegra_edid *edid) | ||
94 | { | ||
95 | char name[] = "edidX"; | ||
96 | |||
97 | snprintf(name, sizeof(name), "edid%1d", edid->bus); | ||
98 | debugfs_create_file(name, S_IRUGO, NULL, edid, &tegra_edid_debug_fops); | ||
99 | } | ||
100 | #else | ||
101 | void tegra_edid_debug_add(struct tegra_edid *edid) | ||
102 | { | ||
103 | } | ||
104 | #endif | ||
105 | |||
106 | #ifdef DEBUG | ||
107 | static char tegra_edid_dump_buff[16 * 1024]; | ||
108 | |||
109 | static void tegra_edid_dump(struct tegra_edid *edid) | ||
110 | { | ||
111 | struct seq_file s; | ||
112 | int i; | ||
113 | char c; | ||
114 | |||
115 | memset(&s, 0x0, sizeof(s)); | ||
116 | |||
117 | s.buf = tegra_edid_dump_buff; | ||
118 | s.size = sizeof(tegra_edid_dump_buff); | ||
119 | s.private = edid; | ||
120 | |||
121 | tegra_edid_show(&s, NULL); | ||
122 | |||
123 | i = 0; | ||
124 | while (i < s.count ) { | ||
125 | if ((s.count - i) > 256) { | ||
126 | c = s.buf[i + 256]; | ||
127 | s.buf[i + 256] = 0; | ||
128 | printk("%s", s.buf + i); | ||
129 | s.buf[i + 256] = c; | ||
130 | } else { | ||
131 | printk("%s", s.buf + i); | ||
132 | } | ||
133 | i += 256; | ||
134 | } | ||
135 | } | ||
136 | #else | ||
137 | static void tegra_edid_dump(struct tegra_edid *edid) | ||
138 | { | ||
139 | } | ||
140 | #endif | ||
141 | |||
142 | int tegra_edid_read_block(struct tegra_edid *edid, int block, u8 *data) | ||
143 | { | ||
144 | u8 block_buf[] = {block >> 1}; | ||
145 | u8 cmd_buf[] = {(block & 0x1) * 128}; | ||
146 | int status; | ||
147 | struct i2c_msg msg[] = { | ||
148 | { | ||
149 | .addr = 0x30, | ||
150 | .flags = 0, | ||
151 | .len = 1, | ||
152 | .buf = block_buf, | ||
153 | }, | ||
154 | { | ||
155 | .addr = 0x50, | ||
156 | .flags = 0, | ||
157 | .len = 1, | ||
158 | .buf = cmd_buf, | ||
159 | }, | ||
160 | { | ||
161 | .addr = 0x50, | ||
162 | .flags = I2C_M_RD, | ||
163 | .len = 128, | ||
164 | .buf = data, | ||
165 | }}; | ||
166 | struct i2c_msg *m; | ||
167 | int msg_len; | ||
168 | |||
169 | if (block > 1) { | ||
170 | msg_len = 3; | ||
171 | m = msg; | ||
172 | } else { | ||
173 | msg_len = 2; | ||
174 | m = &msg[1]; | ||
175 | } | ||
176 | |||
177 | status = i2c_transfer(edid->client->adapter, m, msg_len); | ||
178 | |||
179 | if (status < 0) | ||
180 | return status; | ||
181 | |||
182 | if (status != msg_len) | ||
183 | return -EIO; | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | int tegra_edid_parse_ext_block(const u8 *raw, int idx, | ||
189 | struct tegra_edid_pvt *edid) | ||
190 | { | ||
191 | const u8 *ptr; | ||
192 | u8 tmp; | ||
193 | u8 code; | ||
194 | int len; | ||
195 | int i; | ||
196 | bool basic_audio = false; | ||
197 | |||
198 | ptr = &raw[0]; | ||
199 | |||
200 | /* If CEA 861 block get info for eld struct */ | ||
201 | if (edid && ptr) { | ||
202 | if (*ptr <= 3) | ||
203 | edid->eld.eld_ver = 0x02; | ||
204 | edid->eld.cea_edid_ver = ptr[1]; | ||
205 | |||
206 | /* check for basic audio support in CEA 861 block */ | ||
207 | if(raw[3] & (1<<6)) { | ||
208 | /* For basic audio, set spk_alloc to Left+Right. | ||
209 | * If there is a Speaker Alloc block this will | ||
210 | * get over written with that value */ | ||
211 | basic_audio = true; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if (raw[3] & 0x80) | ||
216 | edid->support_underscan = 1; | ||
217 | else | ||
218 | edid->support_underscan = 0; | ||
219 | |||
220 | ptr = &raw[4]; | ||
221 | |||
222 | while (ptr < &raw[idx]) { | ||
223 | tmp = *ptr; | ||
224 | len = tmp & 0x1f; | ||
225 | |||
226 | /* HDMI Specification v1.4a, section 8.3.2: | ||
227 | * see Table 8-16 for HDMI VSDB format. | ||
228 | * data blocks have tags in top 3 bits: | ||
229 | * tag code 2: video data block | ||
230 | * tag code 3: vendor specific data block | ||
231 | */ | ||
232 | code = (tmp >> 5) & 0x7; | ||
233 | switch (code) { | ||
234 | case 1: | ||
235 | { | ||
236 | edid->eld.sad_count = len; | ||
237 | edid->eld.conn_type = 0x00; | ||
238 | edid->eld.support_hdcp = 0x00; | ||
239 | for (i = 0; (i < len) && (i < ELD_MAX_SAD); i ++) | ||
240 | edid->eld.sad[i] = ptr[i + 1]; | ||
241 | len++; | ||
242 | ptr += len; /* adding the header */ | ||
243 | /* Got an audio data block so enable audio */ | ||
244 | if(basic_audio == true) | ||
245 | edid->eld.spk_alloc = 1; | ||
246 | break; | ||
247 | } | ||
248 | /* case 2 is commented out for now */ | ||
249 | case 3: | ||
250 | { | ||
251 | int j = 0; | ||
252 | |||
253 | if ((ptr[1] == 0x03) && | ||
254 | (ptr[2] == 0x0c) && | ||
255 | (ptr[3] == 0)) { | ||
256 | edid->eld.port_id[0] = ptr[4]; | ||
257 | edid->eld.port_id[1] = ptr[5]; | ||
258 | } | ||
259 | if ((len >= 8) && | ||
260 | (ptr[1] == 0x03) && | ||
261 | (ptr[2] == 0x0c) && | ||
262 | (ptr[3] == 0)) { | ||
263 | j = 8; | ||
264 | tmp = ptr[j++]; | ||
265 | /* HDMI_Video_present? */ | ||
266 | if (tmp & 0x20) { | ||
267 | /* Latency_Fields_present? */ | ||
268 | if (tmp & 0x80) | ||
269 | j += 2; | ||
270 | /* I_Latency_Fields_present? */ | ||
271 | if (tmp & 0x40) | ||
272 | j += 2; | ||
273 | /* 3D_present? */ | ||
274 | if (j <= len && (ptr[j] & 0x80)) | ||
275 | edid->support_stereo = 1; | ||
276 | } | ||
277 | } | ||
278 | if ((len > 5) && | ||
279 | (ptr[1] == 0x03) && | ||
280 | (ptr[2] == 0x0c) && | ||
281 | (ptr[3] == 0)) { | ||
282 | |||
283 | edid->eld.support_ai = (ptr[6] & 0x80); | ||
284 | } | ||
285 | |||
286 | if ((len > 9) && | ||
287 | (ptr[1] == 0x03) && | ||
288 | (ptr[2] == 0x0c) && | ||
289 | (ptr[3] == 0)) { | ||
290 | |||
291 | edid->eld.aud_synch_delay = ptr[10]; | ||
292 | } | ||
293 | len++; | ||
294 | ptr += len; /* adding the header */ | ||
295 | break; | ||
296 | } | ||
297 | case 4: | ||
298 | { | ||
299 | edid->eld.spk_alloc = ptr[1]; | ||
300 | len++; | ||
301 | ptr += len; /* adding the header */ | ||
302 | break; | ||
303 | } | ||
304 | default: | ||
305 | len++; /* len does not include header */ | ||
306 | ptr += len; | ||
307 | break; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | int tegra_edid_mode_support_stereo(struct fb_videomode *mode) | ||
315 | { | ||
316 | if (!mode) | ||
317 | return 0; | ||
318 | |||
319 | if (mode->xres == 1280 && | ||
320 | mode->yres == 720 && | ||
321 | ((mode->refresh == 60) || (mode->refresh == 50))) | ||
322 | return 1; | ||
323 | |||
324 | /* Disabling 1080p stereo mode due to bug 869099. */ | ||
325 | /* Must re-enable this to 1 once it is fixed. */ | ||
326 | if (mode->xres == 1920 && mode->yres == 1080 && mode->refresh == 24) | ||
327 | return 0; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static void data_release(struct kref *ref) | ||
333 | { | ||
334 | struct tegra_edid_pvt *data = | ||
335 | container_of(ref, struct tegra_edid_pvt, refcnt); | ||
336 | vfree(data); | ||
337 | } | ||
338 | |||
339 | int tegra_edid_get_monspecs_test(struct tegra_edid *edid, | ||
340 | struct fb_monspecs *specs, unsigned char *edid_ptr) | ||
341 | { | ||
342 | int i, j, ret; | ||
343 | int extension_blocks; | ||
344 | struct tegra_edid_pvt *new_data, *old_data; | ||
345 | u8 *data; | ||
346 | |||
347 | new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt)); | ||
348 | if (!new_data) | ||
349 | return -ENOMEM; | ||
350 | |||
351 | kref_init(&new_data->refcnt); | ||
352 | |||
353 | new_data->support_stereo = 0; | ||
354 | new_data->support_underscan = 0; | ||
355 | |||
356 | data = new_data->dc_edid.buf; | ||
357 | memcpy(data, edid_ptr, 128); | ||
358 | |||
359 | memset(specs, 0x0, sizeof(struct fb_monspecs)); | ||
360 | memset(&new_data->eld, 0x0, sizeof(new_data->eld)); | ||
361 | fb_edid_to_monspecs(data, specs); | ||
362 | if (specs->modedb == NULL) { | ||
363 | ret = -EINVAL; | ||
364 | goto fail; | ||
365 | } | ||
366 | |||
367 | memcpy(new_data->eld.monitor_name, specs->monitor, | ||
368 | sizeof(specs->monitor)); | ||
369 | |||
370 | new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1; | ||
371 | new_data->eld.product_id[0] = data[0x8]; | ||
372 | new_data->eld.product_id[1] = data[0x9]; | ||
373 | new_data->eld.manufacture_id[0] = data[0xA]; | ||
374 | new_data->eld.manufacture_id[1] = data[0xB]; | ||
375 | |||
376 | extension_blocks = data[0x7e]; | ||
377 | for (i = 1; i <= extension_blocks; i++) { | ||
378 | memcpy(data+128, edid_ptr+128, 128); | ||
379 | |||
380 | if (data[i * 128] == 0x2) { | ||
381 | fb_edid_add_monspecs(data + i * 128, specs); | ||
382 | |||
383 | tegra_edid_parse_ext_block(data + i * 128, | ||
384 | data[i * 128 + 2], new_data); | ||
385 | |||
386 | if (new_data->support_stereo) { | ||
387 | for (j = 0; j < specs->modedb_len; j++) { | ||
388 | if (tegra_edid_mode_support_stereo( | ||
389 | &specs->modedb[j])) | ||
390 | specs->modedb[j].vmode |= | ||
391 | #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
392 | FB_VMODE_STEREO_FRAME_PACK; | ||
393 | #else | ||
394 | FB_VMODE_STEREO_LEFT_RIGHT; | ||
395 | #endif | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | new_data->dc_edid.len = i * 128; | ||
402 | |||
403 | mutex_lock(&edid->lock); | ||
404 | old_data = edid->data; | ||
405 | edid->data = new_data; | ||
406 | mutex_unlock(&edid->lock); | ||
407 | |||
408 | if (old_data) | ||
409 | kref_put(&old_data->refcnt, data_release); | ||
410 | |||
411 | tegra_edid_dump(edid); | ||
412 | return 0; | ||
413 | fail: | ||
414 | vfree(new_data); | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs) | ||
419 | { | ||
420 | int i; | ||
421 | int j; | ||
422 | int ret; | ||
423 | int extension_blocks; | ||
424 | struct tegra_edid_pvt *new_data, *old_data; | ||
425 | u8 *data; | ||
426 | |||
427 | new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt)); | ||
428 | if (!new_data) | ||
429 | return -ENOMEM; | ||
430 | |||
431 | kref_init(&new_data->refcnt); | ||
432 | |||
433 | new_data->support_stereo = 0; | ||
434 | |||
435 | data = new_data->dc_edid.buf; | ||
436 | |||
437 | ret = tegra_edid_read_block(edid, 0, data); | ||
438 | if (ret) | ||
439 | goto fail; | ||
440 | |||
441 | memset(specs, 0x0, sizeof(struct fb_monspecs)); | ||
442 | memset(&new_data->eld, 0x0, sizeof(new_data->eld)); | ||
443 | fb_edid_to_monspecs(data, specs); | ||
444 | if (specs->modedb == NULL) { | ||
445 | ret = -EINVAL; | ||
446 | goto fail; | ||
447 | } | ||
448 | memcpy(new_data->eld.monitor_name, specs->monitor, sizeof(specs->monitor)); | ||
449 | new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1; | ||
450 | new_data->eld.product_id[0] = data[0x8]; | ||
451 | new_data->eld.product_id[1] = data[0x9]; | ||
452 | new_data->eld.manufacture_id[0] = data[0xA]; | ||
453 | new_data->eld.manufacture_id[1] = data[0xB]; | ||
454 | |||
455 | extension_blocks = data[0x7e]; | ||
456 | |||
457 | for (i = 1; i <= extension_blocks; i++) { | ||
458 | ret = tegra_edid_read_block(edid, i, data + i * 128); | ||
459 | if (ret < 0) | ||
460 | break; | ||
461 | |||
462 | if (data[i * 128] == 0x2) { | ||
463 | fb_edid_add_monspecs(data + i * 128, specs); | ||
464 | |||
465 | tegra_edid_parse_ext_block(data + i * 128, | ||
466 | data[i * 128 + 2], new_data); | ||
467 | |||
468 | if (new_data->support_stereo) { | ||
469 | for (j = 0; j < specs->modedb_len; j++) { | ||
470 | if (tegra_edid_mode_support_stereo( | ||
471 | &specs->modedb[j])) | ||
472 | specs->modedb[j].vmode |= | ||
473 | #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
474 | FB_VMODE_STEREO_FRAME_PACK; | ||
475 | #else | ||
476 | FB_VMODE_STEREO_LEFT_RIGHT; | ||
477 | #endif | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | |||
483 | new_data->dc_edid.len = i * 128; | ||
484 | |||
485 | mutex_lock(&edid->lock); | ||
486 | old_data = edid->data; | ||
487 | edid->data = new_data; | ||
488 | mutex_unlock(&edid->lock); | ||
489 | |||
490 | if (old_data) | ||
491 | kref_put(&old_data->refcnt, data_release); | ||
492 | |||
493 | tegra_edid_dump(edid); | ||
494 | return 0; | ||
495 | |||
496 | fail: | ||
497 | vfree(new_data); | ||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | int tegra_edid_underscan_supported(struct tegra_edid *edid) | ||
502 | { | ||
503 | if ((!edid) || (!edid->data)) | ||
504 | return 0; | ||
505 | |||
506 | return edid->data->support_underscan; | ||
507 | } | ||
508 | |||
509 | int tegra_edid_get_eld(struct tegra_edid *edid, struct tegra_edid_hdmi_eld *elddata) | ||
510 | { | ||
511 | if (!elddata || !edid->data) | ||
512 | return -EFAULT; | ||
513 | |||
514 | memcpy(elddata,&edid->data->eld,sizeof(struct tegra_edid_hdmi_eld)); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | struct tegra_edid *tegra_edid_create(int bus) | ||
520 | { | ||
521 | struct tegra_edid *edid; | ||
522 | struct i2c_adapter *adapter; | ||
523 | int err; | ||
524 | |||
525 | edid = kzalloc(sizeof(struct tegra_edid), GFP_KERNEL); | ||
526 | if (!edid) | ||
527 | return ERR_PTR(-ENOMEM); | ||
528 | |||
529 | mutex_init(&edid->lock); | ||
530 | strlcpy(edid->info.type, "tegra_edid", sizeof(edid->info.type)); | ||
531 | edid->bus = bus; | ||
532 | edid->info.addr = 0x50; | ||
533 | edid->info.platform_data = edid; | ||
534 | |||
535 | adapter = i2c_get_adapter(bus); | ||
536 | if (!adapter) { | ||
537 | pr_err("can't get adpater for bus %d\n", bus); | ||
538 | err = -EBUSY; | ||
539 | goto free_edid; | ||
540 | } | ||
541 | |||
542 | edid->client = i2c_new_device(adapter, &edid->info); | ||
543 | i2c_put_adapter(adapter); | ||
544 | |||
545 | if (!edid->client) { | ||
546 | pr_err("can't create new device\n"); | ||
547 | err = -EBUSY; | ||
548 | goto free_edid; | ||
549 | } | ||
550 | |||
551 | tegra_edid_debug_add(edid); | ||
552 | |||
553 | return edid; | ||
554 | |||
555 | free_edid: | ||
556 | kfree(edid); | ||
557 | |||
558 | return ERR_PTR(err); | ||
559 | } | ||
560 | |||
561 | void tegra_edid_destroy(struct tegra_edid *edid) | ||
562 | { | ||
563 | i2c_release_client(edid->client); | ||
564 | if (edid->data) | ||
565 | kref_put(&edid->data->refcnt, data_release); | ||
566 | kfree(edid); | ||
567 | } | ||
568 | |||
569 | struct tegra_dc_edid *tegra_edid_get_data(struct tegra_edid *edid) | ||
570 | { | ||
571 | struct tegra_edid_pvt *data; | ||
572 | |||
573 | mutex_lock(&edid->lock); | ||
574 | data = edid->data; | ||
575 | if (data) | ||
576 | kref_get(&data->refcnt); | ||
577 | mutex_unlock(&edid->lock); | ||
578 | |||
579 | return data ? &data->dc_edid : NULL; | ||
580 | } | ||
581 | |||
582 | void tegra_edid_put_data(struct tegra_dc_edid *data) | ||
583 | { | ||
584 | struct tegra_edid_pvt *pvt; | ||
585 | |||
586 | if (!data) | ||
587 | return; | ||
588 | |||
589 | pvt = container_of(data, struct tegra_edid_pvt, dc_edid); | ||
590 | |||
591 | kref_put(&pvt->refcnt, data_release); | ||
592 | } | ||
593 | |||
594 | static const struct i2c_device_id tegra_edid_id[] = { | ||
595 | { "tegra_edid", 0 }, | ||
596 | { } | ||
597 | }; | ||
598 | |||
599 | MODULE_DEVICE_TABLE(i2c, tegra_edid_id); | ||
600 | |||
601 | static struct i2c_driver tegra_edid_driver = { | ||
602 | .id_table = tegra_edid_id, | ||
603 | .driver = { | ||
604 | .name = "tegra_edid", | ||
605 | }, | ||
606 | }; | ||
607 | |||
608 | static int __init tegra_edid_init(void) | ||
609 | { | ||
610 | return i2c_add_driver(&tegra_edid_driver); | ||
611 | } | ||
612 | |||
613 | static void __exit tegra_edid_exit(void) | ||
614 | { | ||
615 | i2c_del_driver(&tegra_edid_driver); | ||
616 | } | ||
617 | |||
618 | module_init(tegra_edid_init); | ||
619 | module_exit(tegra_edid_exit); | ||
diff --git a/drivers/video/tegra/dc/edid.h b/drivers/video/tegra/dc/edid.h new file mode 100644 index 00000000000..77db36f4adb --- /dev/null +++ b/drivers/video/tegra/dc/edid.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/edid.h | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_EDID_H | ||
19 | #define __DRIVERS_VIDEO_TEGRA_DC_EDID_H | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/wait.h> | ||
23 | #include <mach/dc.h> | ||
24 | |||
25 | #define ELD_MAX_MNL 16 | ||
26 | #define ELD_MAX_SAD 16 | ||
27 | struct tegra_edid; | ||
28 | |||
29 | /* | ||
30 | * ELD: EDID Like Data | ||
31 | */ | ||
32 | struct tegra_edid_hdmi_eld { | ||
33 | u8 baseline_len; | ||
34 | u8 eld_ver; | ||
35 | u8 cea_edid_ver; | ||
36 | char monitor_name[ELD_MAX_MNL + 1]; | ||
37 | u8 mnl; | ||
38 | u8 manufacture_id[2]; | ||
39 | u8 product_id[2]; | ||
40 | u8 port_id[8]; | ||
41 | u8 support_hdcp; | ||
42 | u8 support_ai; | ||
43 | u8 conn_type; | ||
44 | u8 aud_synch_delay; | ||
45 | u8 spk_alloc; | ||
46 | u8 sad_count; | ||
47 | u8 sad[ELD_MAX_SAD]; | ||
48 | }; | ||
49 | |||
50 | struct tegra_edid *tegra_edid_create(int bus); | ||
51 | void tegra_edid_destroy(struct tegra_edid *edid); | ||
52 | |||
53 | int tegra_edid_get_monspecs_test(struct tegra_edid *edid, | ||
54 | struct fb_monspecs *specs, u8 *edid_ptr); | ||
55 | int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs); | ||
56 | int tegra_edid_get_eld(struct tegra_edid *edid, struct tegra_edid_hdmi_eld *elddata); | ||
57 | |||
58 | struct tegra_dc_edid *tegra_edid_get_data(struct tegra_edid *edid); | ||
59 | void tegra_edid_put_data(struct tegra_dc_edid *data); | ||
60 | |||
61 | int tegra_edid_underscan_supported(struct tegra_edid *edid); | ||
62 | #endif | ||
diff --git a/drivers/video/tegra/dc/ext/Makefile b/drivers/video/tegra/dc/ext/Makefile new file mode 100644 index 00000000000..19860ab5db1 --- /dev/null +++ b/drivers/video/tegra/dc/ext/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-y += dev.o | ||
2 | obj-y += util.o | ||
3 | obj-y += cursor.o | ||
4 | obj-y += events.o | ||
5 | obj-y += control.o | ||
diff --git a/drivers/video/tegra/dc/ext/control.c b/drivers/video/tegra/dc/ext/control.c new file mode 100644 index 00000000000..9caf3e11c16 --- /dev/null +++ b/drivers/video/tegra/dc/ext/control.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/ext/control.c | ||
3 | * | ||
4 | * Copyright (C) 2011, NVIDIA Corporation | ||
5 | * | ||
6 | * Author: Robert Morell <rmorell@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/device.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/file.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | |||
27 | #include "tegra_dc_ext_priv.h" | ||
28 | |||
29 | static struct tegra_dc_ext_control g_control; | ||
30 | |||
31 | int tegra_dc_ext_process_hotplug(int output) | ||
32 | { | ||
33 | return tegra_dc_ext_queue_hotplug(&g_control, output); | ||
34 | } | ||
35 | |||
36 | static int | ||
37 | get_output_properties(struct tegra_dc_ext_control_output_properties *properties) | ||
38 | { | ||
39 | struct tegra_dc *dc; | ||
40 | |||
41 | /* TODO: this should be more dynamic */ | ||
42 | if (properties->handle > 2) | ||
43 | return -EINVAL; | ||
44 | |||
45 | switch (properties->handle) { | ||
46 | case 0: | ||
47 | properties->type = TEGRA_DC_EXT_LVDS; | ||
48 | break; | ||
49 | case 1: | ||
50 | properties->type = TEGRA_DC_EXT_HDMI; | ||
51 | break; | ||
52 | default: | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | |||
56 | properties->associated_head = properties->handle; | ||
57 | properties->head_mask = (1 << properties->associated_head); | ||
58 | |||
59 | dc = tegra_dc_get_dc(properties->associated_head); | ||
60 | properties->connected = tegra_dc_get_connected(dc); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int get_output_edid(struct tegra_dc_ext_control_output_edid *edid) | ||
66 | { | ||
67 | struct tegra_dc *dc; | ||
68 | size_t user_size = edid->size; | ||
69 | struct tegra_dc_edid *dc_edid = NULL; | ||
70 | int ret; | ||
71 | |||
72 | /* TODO: this should be more dynamic */ | ||
73 | if (edid->handle > 2) | ||
74 | return -EINVAL; | ||
75 | |||
76 | dc = tegra_dc_get_dc(edid->handle); | ||
77 | |||
78 | dc_edid = tegra_dc_get_edid(dc); | ||
79 | if (IS_ERR(dc_edid)) | ||
80 | return PTR_ERR(dc_edid); | ||
81 | |||
82 | if (!dc_edid) { | ||
83 | edid->size = 0; | ||
84 | } else { | ||
85 | edid->size = dc_edid->len; | ||
86 | |||
87 | if (user_size < edid->size) { | ||
88 | ret = -EFBIG; | ||
89 | goto done; | ||
90 | } | ||
91 | |||
92 | if (copy_to_user(edid->data, dc_edid->buf, edid->size)) { | ||
93 | ret = -EFAULT; | ||
94 | goto done; | ||
95 | } | ||
96 | |||
97 | } | ||
98 | |||
99 | done: | ||
100 | if (dc_edid) | ||
101 | tegra_dc_put_edid(dc_edid); | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | static int set_event_mask(struct tegra_dc_ext_control_user *user, u32 mask) | ||
107 | { | ||
108 | struct list_head *list, *tmp; | ||
109 | |||
110 | if (mask & ~TEGRA_DC_EXT_EVENT_MASK_ALL) | ||
111 | return -EINVAL; | ||
112 | |||
113 | mutex_lock(&user->lock); | ||
114 | |||
115 | user->event_mask = mask; | ||
116 | |||
117 | list_for_each_safe(list, tmp, &user->event_list) { | ||
118 | struct tegra_dc_ext_event_list *ev_list; | ||
119 | ev_list = list_entry(list, struct tegra_dc_ext_event_list, | ||
120 | list); | ||
121 | if (!(mask & ev_list->event.type)) { | ||
122 | list_del(list); | ||
123 | kfree(ev_list); | ||
124 | } | ||
125 | } | ||
126 | mutex_unlock(&user->lock); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int get_capabilities(struct tegra_dc_ext_control_capabilities *caps) | ||
132 | { | ||
133 | caps->caps = TEGRA_DC_EXT_CAPABILITIES; | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static long tegra_dc_ext_control_ioctl(struct file *filp, unsigned int cmd, | ||
138 | unsigned long arg) | ||
139 | { | ||
140 | void __user *user_arg = (void __user *)arg; | ||
141 | struct tegra_dc_ext_control_user *user = filp->private_data; | ||
142 | |||
143 | switch (cmd) { | ||
144 | case TEGRA_DC_EXT_CONTROL_GET_NUM_OUTPUTS: | ||
145 | { | ||
146 | u32 num = tegra_dc_ext_get_num_outputs(); | ||
147 | |||
148 | if (copy_to_user(user_arg, &num, sizeof(num))) | ||
149 | return -EFAULT; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | case TEGRA_DC_EXT_CONTROL_GET_OUTPUT_PROPERTIES: | ||
154 | { | ||
155 | struct tegra_dc_ext_control_output_properties args; | ||
156 | int ret; | ||
157 | |||
158 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
159 | return -EFAULT; | ||
160 | |||
161 | ret = get_output_properties(&args); | ||
162 | |||
163 | if (copy_to_user(user_arg, &args, sizeof(args))) | ||
164 | return -EFAULT; | ||
165 | |||
166 | return ret; | ||
167 | } | ||
168 | case TEGRA_DC_EXT_CONTROL_GET_OUTPUT_EDID: | ||
169 | { | ||
170 | struct tegra_dc_ext_control_output_edid args; | ||
171 | int ret; | ||
172 | |||
173 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
174 | return -EFAULT; | ||
175 | |||
176 | ret = get_output_edid(&args); | ||
177 | |||
178 | if (copy_to_user(user_arg, &args, sizeof(args))) | ||
179 | return -EFAULT; | ||
180 | |||
181 | return ret; | ||
182 | } | ||
183 | case TEGRA_DC_EXT_CONTROL_SET_EVENT_MASK: | ||
184 | return set_event_mask(user, (u32) arg); | ||
185 | case TEGRA_DC_EXT_CONTROL_GET_CAPABILITIES: | ||
186 | { | ||
187 | struct tegra_dc_ext_control_capabilities args; | ||
188 | int ret; | ||
189 | |||
190 | ret = get_capabilities(&args); | ||
191 | |||
192 | if (copy_to_user(user_arg, &args, sizeof(args))) | ||
193 | return -EFAULT; | ||
194 | |||
195 | return ret; | ||
196 | } | ||
197 | default: | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static int tegra_dc_ext_control_open(struct inode *inode, struct file *filp) | ||
203 | { | ||
204 | struct tegra_dc_ext_control_user *user; | ||
205 | struct tegra_dc_ext_control *control; | ||
206 | |||
207 | user = kzalloc(sizeof(*user), GFP_KERNEL); | ||
208 | if (!user) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | control = container_of(inode->i_cdev, struct tegra_dc_ext_control, | ||
212 | cdev); | ||
213 | user->control = control;; | ||
214 | |||
215 | INIT_LIST_HEAD(&user->event_list); | ||
216 | mutex_init(&user->lock); | ||
217 | |||
218 | filp->private_data = user; | ||
219 | |||
220 | mutex_lock(&control->lock); | ||
221 | list_add(&user->list, &control->users); | ||
222 | mutex_unlock(&control->lock); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int tegra_dc_ext_control_release(struct inode *inode, struct file *filp) | ||
228 | { | ||
229 | struct tegra_dc_ext_control_user *user = filp->private_data; | ||
230 | struct tegra_dc_ext_control *control = user->control; | ||
231 | |||
232 | /* This will free any pending events for this user */ | ||
233 | set_event_mask(user, 0); | ||
234 | |||
235 | mutex_lock(&control->lock); | ||
236 | list_del(&user->list); | ||
237 | mutex_unlock(&control->lock); | ||
238 | |||
239 | kfree(user); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static const struct file_operations tegra_dc_ext_event_devops = { | ||
245 | .owner = THIS_MODULE, | ||
246 | .open = tegra_dc_ext_control_open, | ||
247 | .release = tegra_dc_ext_control_release, | ||
248 | .read = tegra_dc_ext_event_read, | ||
249 | .poll = tegra_dc_ext_event_poll, | ||
250 | .unlocked_ioctl = tegra_dc_ext_control_ioctl, | ||
251 | }; | ||
252 | |||
253 | int tegra_dc_ext_control_init(void) | ||
254 | { | ||
255 | struct tegra_dc_ext_control *control = &g_control; | ||
256 | int ret; | ||
257 | |||
258 | cdev_init(&control->cdev, &tegra_dc_ext_event_devops); | ||
259 | control->cdev.owner = THIS_MODULE; | ||
260 | ret = cdev_add(&control->cdev, tegra_dc_ext_devno, 1); | ||
261 | if (ret) | ||
262 | return ret; | ||
263 | |||
264 | control->dev = device_create(tegra_dc_ext_class, | ||
265 | NULL, | ||
266 | tegra_dc_ext_devno, | ||
267 | NULL, | ||
268 | "tegra_dc_ctrl"); | ||
269 | if (IS_ERR(control->dev)) { | ||
270 | ret = PTR_ERR(control->dev); | ||
271 | cdev_del(&control->cdev); | ||
272 | } | ||
273 | |||
274 | mutex_init(&control->lock); | ||
275 | |||
276 | INIT_LIST_HEAD(&control->users); | ||
277 | |||
278 | return ret; | ||
279 | } | ||
diff --git a/drivers/video/tegra/dc/ext/cursor.c b/drivers/video/tegra/dc/ext/cursor.c new file mode 100644 index 00000000000..d8fa5fd8e6d --- /dev/null +++ b/drivers/video/tegra/dc/ext/cursor.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/ext/cursor.c | ||
3 | * | ||
4 | * Copyright (C) 2011, NVIDIA Corporation | ||
5 | * | ||
6 | * Author: Robert Morell <rmorell@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | */ | ||
18 | |||
19 | #include <video/tegra_dc_ext.h> | ||
20 | |||
21 | #include "tegra_dc_ext_priv.h" | ||
22 | |||
23 | /* ugh */ | ||
24 | #include "../dc_priv.h" | ||
25 | #include "../dc_reg.h" | ||
26 | |||
27 | int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user) | ||
28 | { | ||
29 | struct tegra_dc_ext *ext = user->ext; | ||
30 | int ret = 0; | ||
31 | |||
32 | mutex_lock(&ext->cursor.lock); | ||
33 | |||
34 | if (!ext->cursor.user) | ||
35 | ext->cursor.user = user; | ||
36 | else if (ext->cursor.user != user) | ||
37 | ret = -EBUSY; | ||
38 | |||
39 | mutex_unlock(&ext->cursor.lock); | ||
40 | |||
41 | return ret; | ||
42 | } | ||
43 | |||
44 | int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user) | ||
45 | { | ||
46 | struct tegra_dc_ext *ext = user->ext; | ||
47 | int ret = 0; | ||
48 | |||
49 | mutex_lock(&ext->cursor.lock); | ||
50 | |||
51 | if (ext->cursor.user == user) | ||
52 | ext->cursor.user = 0; | ||
53 | else | ||
54 | ret = -EACCES; | ||
55 | |||
56 | mutex_unlock(&ext->cursor.lock); | ||
57 | |||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | static void set_cursor_image_hw(struct tegra_dc *dc, | ||
62 | struct tegra_dc_ext_cursor_image *args, | ||
63 | dma_addr_t phys_addr) | ||
64 | { | ||
65 | tegra_dc_writel(dc, | ||
66 | CURSOR_COLOR(args->foreground.r, | ||
67 | args->foreground.g, | ||
68 | args->foreground.b), | ||
69 | DC_DISP_CURSOR_FOREGROUND); | ||
70 | tegra_dc_writel(dc, | ||
71 | CURSOR_COLOR(args->background.r, | ||
72 | args->background.g, | ||
73 | args->background.b), | ||
74 | DC_DISP_CURSOR_BACKGROUND); | ||
75 | |||
76 | BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK); | ||
77 | |||
78 | tegra_dc_writel(dc, | ||
79 | CURSOR_START_ADDR(((unsigned long) phys_addr)) | | ||
80 | ((args->flags & TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) ? | ||
81 | CURSOR_SIZE_64 : 0), | ||
82 | DC_DISP_CURSOR_START_ADDR); | ||
83 | } | ||
84 | |||
85 | int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user, | ||
86 | struct tegra_dc_ext_cursor_image *args) | ||
87 | { | ||
88 | struct tegra_dc_ext *ext = user->ext; | ||
89 | struct tegra_dc *dc = ext->dc; | ||
90 | struct nvmap_handle_ref *handle, *old_handle; | ||
91 | dma_addr_t phys_addr; | ||
92 | u32 size; | ||
93 | int ret; | ||
94 | |||
95 | if (!user->nvmap) | ||
96 | return -EFAULT; | ||
97 | |||
98 | size = args->flags & (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 | | ||
99 | TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64); | ||
100 | |||
101 | if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 && | ||
102 | size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) | ||
103 | return -EINVAL; | ||
104 | |||
105 | mutex_lock(&ext->cursor.lock); | ||
106 | |||
107 | if (ext->cursor.user != user) { | ||
108 | ret = -EACCES; | ||
109 | goto unlock; | ||
110 | } | ||
111 | |||
112 | if (!ext->enabled) { | ||
113 | ret = -ENXIO; | ||
114 | goto unlock; | ||
115 | } | ||
116 | |||
117 | old_handle = ext->cursor.cur_handle; | ||
118 | |||
119 | ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr); | ||
120 | if (ret) | ||
121 | goto unlock; | ||
122 | |||
123 | ext->cursor.cur_handle = handle; | ||
124 | |||
125 | mutex_lock(&dc->lock); | ||
126 | |||
127 | set_cursor_image_hw(dc, args, phys_addr); | ||
128 | |||
129 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
130 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
131 | |||
132 | /* XXX sync here? */ | ||
133 | |||
134 | mutex_unlock(&dc->lock); | ||
135 | |||
136 | mutex_unlock(&ext->cursor.lock); | ||
137 | |||
138 | if (old_handle) { | ||
139 | nvmap_unpin(ext->nvmap, old_handle); | ||
140 | nvmap_free(ext->nvmap, old_handle); | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | |||
145 | unlock: | ||
146 | mutex_unlock(&ext->cursor.lock); | ||
147 | |||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user, | ||
152 | struct tegra_dc_ext_cursor *args) | ||
153 | { | ||
154 | struct tegra_dc_ext *ext = user->ext; | ||
155 | struct tegra_dc *dc = ext->dc; | ||
156 | u32 win_options; | ||
157 | bool enable; | ||
158 | int ret; | ||
159 | |||
160 | mutex_lock(&ext->cursor.lock); | ||
161 | |||
162 | if (ext->cursor.user != user) { | ||
163 | ret = -EACCES; | ||
164 | goto unlock; | ||
165 | } | ||
166 | |||
167 | if (!ext->enabled) { | ||
168 | ret = -ENXIO; | ||
169 | goto unlock; | ||
170 | } | ||
171 | |||
172 | enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE); | ||
173 | |||
174 | mutex_lock(&dc->lock); | ||
175 | |||
176 | win_options = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); | ||
177 | if (!!(win_options & CURSOR_ENABLE) != enable) { | ||
178 | win_options &= ~CURSOR_ENABLE; | ||
179 | if (enable) | ||
180 | win_options |= CURSOR_ENABLE; | ||
181 | tegra_dc_writel(dc, win_options, DC_DISP_DISP_WIN_OPTIONS); | ||
182 | } | ||
183 | |||
184 | tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y), | ||
185 | DC_DISP_CURSOR_POSITION); | ||
186 | |||
187 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
188 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
189 | |||
190 | /* TODO: need to sync here? hopefully can avoid this, but need to | ||
191 | * figure out interaction w/ rest of GENERAL_ACT_REQ */ | ||
192 | |||
193 | mutex_unlock(&dc->lock); | ||
194 | |||
195 | mutex_unlock(&ext->cursor.lock); | ||
196 | |||
197 | return 0; | ||
198 | |||
199 | unlock: | ||
200 | mutex_unlock(&ext->cursor.lock); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c new file mode 100644 index 00000000000..04553e77839 --- /dev/null +++ b/drivers/video/tegra/dc/ext/dev.c | |||
@@ -0,0 +1,975 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/dev.c | ||
3 | * | ||
4 | * Copyright (C) 2011-2012, NVIDIA Corporation | ||
5 | * | ||
6 | * Author: Robert Morell <rmorell@nvidia.com> | ||
7 | * Some code based on fbdev extensions written by: | ||
8 | * Erik Gilling <konkers@android.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/file.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | |||
27 | #include <video/tegra_dc_ext.h> | ||
28 | |||
29 | #include <mach/dc.h> | ||
30 | #include <mach/nvmap.h> | ||
31 | #include <mach/tegra_dc_ext.h> | ||
32 | |||
33 | /* XXX ew */ | ||
34 | #include "../dc_priv.h" | ||
35 | /* XXX ew 2 */ | ||
36 | #include "../../host/dev.h" | ||
37 | /* XXX ew 3 */ | ||
38 | #include "../../nvmap/nvmap.h" | ||
39 | #include "tegra_dc_ext_priv.h" | ||
40 | |||
41 | int tegra_dc_ext_devno; | ||
42 | struct class *tegra_dc_ext_class; | ||
43 | static int head_count; | ||
44 | |||
45 | struct tegra_dc_ext_flip_win { | ||
46 | struct tegra_dc_ext_flip_windowattr attr; | ||
47 | struct nvmap_handle_ref *handle[TEGRA_DC_NUM_PLANES]; | ||
48 | dma_addr_t phys_addr; | ||
49 | dma_addr_t phys_addr_u; | ||
50 | dma_addr_t phys_addr_v; | ||
51 | u32 syncpt_max; | ||
52 | }; | ||
53 | |||
54 | struct tegra_dc_ext_flip_data { | ||
55 | struct tegra_dc_ext *ext; | ||
56 | struct work_struct work; | ||
57 | struct tegra_dc_ext_flip_win win[DC_N_WINDOWS]; | ||
58 | }; | ||
59 | |||
60 | int tegra_dc_ext_get_num_outputs(void) | ||
61 | { | ||
62 | /* TODO: decouple output count from head count */ | ||
63 | return head_count; | ||
64 | } | ||
65 | |||
66 | static int tegra_dc_ext_set_nvmap_fd(struct tegra_dc_ext_user *user, | ||
67 | int fd) | ||
68 | { | ||
69 | struct nvmap_client *nvmap = NULL; | ||
70 | |||
71 | if (fd >= 0) { | ||
72 | nvmap = nvmap_client_get_file(fd); | ||
73 | if (IS_ERR(nvmap)) | ||
74 | return PTR_ERR(nvmap); | ||
75 | } | ||
76 | |||
77 | if (user->nvmap) | ||
78 | nvmap_client_put(user->nvmap); | ||
79 | |||
80 | user->nvmap = nvmap; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int tegra_dc_ext_get_window(struct tegra_dc_ext_user *user, | ||
86 | unsigned int n) | ||
87 | { | ||
88 | struct tegra_dc_ext *ext = user->ext; | ||
89 | struct tegra_dc_ext_win *win; | ||
90 | int ret = 0; | ||
91 | |||
92 | if (n >= DC_N_WINDOWS) | ||
93 | return -EINVAL; | ||
94 | |||
95 | win = &ext->win[n]; | ||
96 | |||
97 | mutex_lock(&win->lock); | ||
98 | |||
99 | if (!win->user) | ||
100 | win->user = user; | ||
101 | else if (win->user != user) | ||
102 | ret = -EBUSY; | ||
103 | |||
104 | mutex_unlock(&win->lock); | ||
105 | |||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user, | ||
110 | unsigned int n) | ||
111 | { | ||
112 | struct tegra_dc_ext *ext = user->ext; | ||
113 | struct tegra_dc_ext_win *win; | ||
114 | int ret = 0; | ||
115 | |||
116 | if (n >= DC_N_WINDOWS) | ||
117 | return -EINVAL; | ||
118 | |||
119 | win = &ext->win[n]; | ||
120 | |||
121 | mutex_lock(&win->lock); | ||
122 | |||
123 | if (win->user == user) { | ||
124 | flush_workqueue(win->flip_wq); | ||
125 | win->user = 0; | ||
126 | } else { | ||
127 | ret = -EACCES; | ||
128 | } | ||
129 | |||
130 | mutex_unlock(&win->lock); | ||
131 | |||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | static void set_enable(struct tegra_dc_ext *ext, bool en) | ||
136 | { | ||
137 | int i; | ||
138 | |||
139 | /* | ||
140 | * Take all locks to make sure any flip requests or cursor moves are | ||
141 | * out of their critical sections | ||
142 | */ | ||
143 | for (i = 0; i < ext->dc->n_windows; i++) | ||
144 | mutex_lock(&ext->win[i].lock); | ||
145 | mutex_lock(&ext->cursor.lock); | ||
146 | |||
147 | ext->enabled = en; | ||
148 | |||
149 | mutex_unlock(&ext->cursor.lock); | ||
150 | for (i = ext->dc->n_windows - 1; i >= 0 ; i--) | ||
151 | mutex_unlock(&ext->win[i].lock); | ||
152 | } | ||
153 | |||
154 | void tegra_dc_ext_enable(struct tegra_dc_ext *ext) | ||
155 | { | ||
156 | set_enable(ext, true); | ||
157 | } | ||
158 | |||
159 | void tegra_dc_ext_disable(struct tegra_dc_ext *ext) | ||
160 | { | ||
161 | int i; | ||
162 | set_enable(ext, false); | ||
163 | |||
164 | /* | ||
165 | * Flush the flip queue -- note that this must be called with dc->lock | ||
166 | * unlocked or else it will hang. | ||
167 | */ | ||
168 | for (i = 0; i < ext->dc->n_windows; i++) { | ||
169 | struct tegra_dc_ext_win *win = &ext->win[i]; | ||
170 | |||
171 | flush_workqueue(win->flip_wq); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext, | ||
176 | struct tegra_dc_win *win, | ||
177 | const struct tegra_dc_ext_flip_win *flip_win) | ||
178 | { | ||
179 | struct tegra_dc_ext_win *ext_win = &ext->win[win->idx]; | ||
180 | |||
181 | if (flip_win->handle[TEGRA_DC_Y] == NULL) { | ||
182 | win->flags = 0; | ||
183 | memset(ext_win->cur_handle, 0, sizeof(ext_win->cur_handle)); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | win->flags = TEGRA_WIN_FLAG_ENABLED; | ||
188 | if (flip_win->attr.blend == TEGRA_DC_EXT_BLEND_PREMULT) | ||
189 | win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT; | ||
190 | else if (flip_win->attr.blend == TEGRA_DC_EXT_BLEND_COVERAGE) | ||
191 | win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE; | ||
192 | if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_TILED) | ||
193 | win->flags |= TEGRA_WIN_FLAG_TILED; | ||
194 | if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_H) | ||
195 | win->flags |= TEGRA_WIN_FLAG_INVERT_H; | ||
196 | if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_V) | ||
197 | win->flags |= TEGRA_WIN_FLAG_INVERT_V; | ||
198 | win->fmt = flip_win->attr.pixformat; | ||
199 | win->x.full = flip_win->attr.x; | ||
200 | win->y.full = flip_win->attr.y; | ||
201 | win->w.full = flip_win->attr.w; | ||
202 | win->h.full = flip_win->attr.h; | ||
203 | /* XXX verify that this doesn't go outside display's active region */ | ||
204 | win->out_x = flip_win->attr.out_x; | ||
205 | win->out_y = flip_win->attr.out_y; | ||
206 | win->out_w = flip_win->attr.out_w; | ||
207 | win->out_h = flip_win->attr.out_h; | ||
208 | win->z = flip_win->attr.z; | ||
209 | memcpy(ext_win->cur_handle, flip_win->handle, | ||
210 | sizeof(ext_win->cur_handle)); | ||
211 | |||
212 | /* XXX verify that this won't read outside of the surface */ | ||
213 | win->phys_addr = flip_win->phys_addr + flip_win->attr.offset; | ||
214 | |||
215 | win->phys_addr_u = flip_win->handle[TEGRA_DC_U] ? | ||
216 | flip_win->phys_addr_u : flip_win->phys_addr; | ||
217 | win->phys_addr_u += flip_win->attr.offset_u; | ||
218 | |||
219 | win->phys_addr_v = flip_win->handle[TEGRA_DC_V] ? | ||
220 | flip_win->phys_addr_v : flip_win->phys_addr; | ||
221 | win->phys_addr_v += flip_win->attr.offset_v; | ||
222 | |||
223 | win->stride = flip_win->attr.stride; | ||
224 | win->stride_uv = flip_win->attr.stride_uv; | ||
225 | |||
226 | if ((s32)flip_win->attr.pre_syncpt_id >= 0) { | ||
227 | nvhost_syncpt_wait_timeout( | ||
228 | &nvhost_get_host(ext->dc->ndev)->syncpt, | ||
229 | flip_win->attr.pre_syncpt_id, | ||
230 | flip_win->attr.pre_syncpt_val, | ||
231 | msecs_to_jiffies(500), NULL); | ||
232 | } | ||
233 | |||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static void tegra_dc_ext_flip_worker(struct work_struct *work) | ||
239 | { | ||
240 | struct tegra_dc_ext_flip_data *data = | ||
241 | container_of(work, struct tegra_dc_ext_flip_data, work); | ||
242 | struct tegra_dc_ext *ext = data->ext; | ||
243 | struct tegra_dc_win *wins[DC_N_WINDOWS]; | ||
244 | struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS * | ||
245 | TEGRA_DC_NUM_PLANES]; | ||
246 | struct nvmap_handle_ref *old_handle; | ||
247 | int i, nr_unpin = 0, nr_win = 0; | ||
248 | bool skip_flip = false; | ||
249 | |||
250 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
251 | struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; | ||
252 | int index = flip_win->attr.index; | ||
253 | struct tegra_dc_win *win; | ||
254 | struct tegra_dc_ext_win *ext_win; | ||
255 | |||
256 | if (index < 0) | ||
257 | continue; | ||
258 | |||
259 | win = tegra_dc_get_window(ext->dc, index); | ||
260 | ext_win = &ext->win[index]; | ||
261 | |||
262 | if (!(atomic_dec_and_test(&ext_win->nr_pending_flips)) && | ||
263 | (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR)) | ||
264 | skip_flip = true; | ||
265 | |||
266 | if (win->flags & TEGRA_WIN_FLAG_ENABLED) { | ||
267 | int j; | ||
268 | for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) { | ||
269 | if (skip_flip) | ||
270 | old_handle = flip_win->handle[j]; | ||
271 | else | ||
272 | old_handle = ext_win->cur_handle[j]; | ||
273 | |||
274 | if (!old_handle) | ||
275 | continue; | ||
276 | |||
277 | unpin_handles[nr_unpin++] = old_handle; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | if (!skip_flip) | ||
282 | tegra_dc_ext_set_windowattr(ext, win, &data->win[i]); | ||
283 | |||
284 | wins[nr_win++] = win; | ||
285 | } | ||
286 | |||
287 | if (!skip_flip) { | ||
288 | tegra_dc_update_windows(wins, nr_win); | ||
289 | /* TODO: implement swapinterval here */ | ||
290 | tegra_dc_sync_windows(wins, nr_win); | ||
291 | } | ||
292 | |||
293 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
294 | struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; | ||
295 | int index = flip_win->attr.index; | ||
296 | |||
297 | if (index < 0) | ||
298 | continue; | ||
299 | |||
300 | tegra_dc_incr_syncpt_min(ext->dc, index, | ||
301 | flip_win->syncpt_max); | ||
302 | } | ||
303 | |||
304 | /* unpin and deref previous front buffers */ | ||
305 | for (i = 0; i < nr_unpin; i++) { | ||
306 | nvmap_unpin(ext->nvmap, unpin_handles[i]); | ||
307 | nvmap_free(ext->nvmap, unpin_handles[i]); | ||
308 | } | ||
309 | |||
310 | kfree(data); | ||
311 | } | ||
312 | |||
313 | static int lock_windows_for_flip(struct tegra_dc_ext_user *user, | ||
314 | struct tegra_dc_ext_flip *args) | ||
315 | { | ||
316 | struct tegra_dc_ext *ext = user->ext; | ||
317 | u8 idx_mask = 0; | ||
318 | int i; | ||
319 | |||
320 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
321 | int index = args->win[i].index; | ||
322 | |||
323 | if (index < 0) | ||
324 | continue; | ||
325 | |||
326 | idx_mask |= BIT(index); | ||
327 | } | ||
328 | |||
329 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
330 | struct tegra_dc_ext_win *win; | ||
331 | |||
332 | if (!(idx_mask & BIT(i))) | ||
333 | continue; | ||
334 | |||
335 | win = &ext->win[i]; | ||
336 | |||
337 | mutex_lock(&win->lock); | ||
338 | |||
339 | if (win->user != user) | ||
340 | goto fail_unlock; | ||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | |||
345 | fail_unlock: | ||
346 | do { | ||
347 | if (!(idx_mask & BIT(i))) | ||
348 | continue; | ||
349 | |||
350 | mutex_unlock(&ext->win[i].lock); | ||
351 | } while (i--); | ||
352 | |||
353 | return -EACCES; | ||
354 | } | ||
355 | |||
356 | static void unlock_windows_for_flip(struct tegra_dc_ext_user *user, | ||
357 | struct tegra_dc_ext_flip *args) | ||
358 | { | ||
359 | struct tegra_dc_ext *ext = user->ext; | ||
360 | u8 idx_mask = 0; | ||
361 | int i; | ||
362 | |||
363 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
364 | int index = args->win[i].index; | ||
365 | |||
366 | if (index < 0) | ||
367 | continue; | ||
368 | |||
369 | idx_mask |= BIT(index); | ||
370 | } | ||
371 | |||
372 | for (i = DC_N_WINDOWS - 1; i >= 0; i--) { | ||
373 | if (!(idx_mask & BIT(i))) | ||
374 | continue; | ||
375 | |||
376 | mutex_unlock(&ext->win[i].lock); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | static int sanitize_flip_args(struct tegra_dc_ext_user *user, | ||
381 | struct tegra_dc_ext_flip *args) | ||
382 | { | ||
383 | int i, used_windows = 0; | ||
384 | |||
385 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
386 | int index = args->win[i].index; | ||
387 | |||
388 | if (index < 0) | ||
389 | continue; | ||
390 | |||
391 | if (index >= DC_N_WINDOWS) | ||
392 | return -EINVAL; | ||
393 | |||
394 | if (used_windows & BIT(index)) | ||
395 | return -EINVAL; | ||
396 | |||
397 | used_windows |= BIT(index); | ||
398 | } | ||
399 | |||
400 | if (!used_windows) | ||
401 | return -EINVAL; | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, | ||
407 | struct tegra_dc_ext_flip *args) | ||
408 | { | ||
409 | struct tegra_dc_ext *ext = user->ext; | ||
410 | struct tegra_dc_ext_flip_data *data; | ||
411 | int work_index; | ||
412 | int i, ret = 0; | ||
413 | |||
414 | #ifdef CONFIG_ANDROID | ||
415 | int index_check[DC_N_WINDOWS] = {0, }; | ||
416 | int zero_index_id = 0; | ||
417 | #endif | ||
418 | |||
419 | if (!user->nvmap) | ||
420 | return -EFAULT; | ||
421 | |||
422 | ret = sanitize_flip_args(user, args); | ||
423 | if (ret) | ||
424 | return ret; | ||
425 | |||
426 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
427 | if (!data) | ||
428 | return -ENOMEM; | ||
429 | |||
430 | INIT_WORK(&data->work, tegra_dc_ext_flip_worker); | ||
431 | data->ext = ext; | ||
432 | |||
433 | #ifdef CONFIG_ANDROID | ||
434 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
435 | index_check[i] = args->win[i].index; | ||
436 | if (index_check[i] == 0) | ||
437 | zero_index_id = i; | ||
438 | } | ||
439 | |||
440 | if (index_check[DC_N_WINDOWS - 1] != 0) { | ||
441 | struct tegra_dc_ext_flip_windowattr win_temp; | ||
442 | win_temp = args->win[DC_N_WINDOWS - 1]; | ||
443 | args->win[DC_N_WINDOWS - 1] = args->win[zero_index_id]; | ||
444 | args->win[zero_index_id] = win_temp; | ||
445 | } | ||
446 | #endif | ||
447 | |||
448 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
449 | struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; | ||
450 | int index = args->win[i].index; | ||
451 | |||
452 | memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr)); | ||
453 | |||
454 | if (index < 0) | ||
455 | continue; | ||
456 | |||
457 | ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id, | ||
458 | &flip_win->handle[TEGRA_DC_Y], | ||
459 | &flip_win->phys_addr); | ||
460 | if (ret) | ||
461 | goto fail_pin; | ||
462 | |||
463 | if (flip_win->attr.buff_id_u) { | ||
464 | ret = tegra_dc_ext_pin_window(user, | ||
465 | flip_win->attr.buff_id_u, | ||
466 | &flip_win->handle[TEGRA_DC_U], | ||
467 | &flip_win->phys_addr_u); | ||
468 | if (ret) | ||
469 | goto fail_pin; | ||
470 | } else { | ||
471 | flip_win->handle[TEGRA_DC_U] = NULL; | ||
472 | flip_win->phys_addr_u = 0; | ||
473 | } | ||
474 | |||
475 | if (flip_win->attr.buff_id_v) { | ||
476 | ret = tegra_dc_ext_pin_window(user, | ||
477 | flip_win->attr.buff_id_v, | ||
478 | &flip_win->handle[TEGRA_DC_V], | ||
479 | &flip_win->phys_addr_v); | ||
480 | if (ret) | ||
481 | goto fail_pin; | ||
482 | } else { | ||
483 | flip_win->handle[TEGRA_DC_V] = NULL; | ||
484 | flip_win->phys_addr_v = 0; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | ret = lock_windows_for_flip(user, args); | ||
489 | if (ret) | ||
490 | goto fail_pin; | ||
491 | |||
492 | if (!ext->enabled) { | ||
493 | ret = -ENXIO; | ||
494 | goto unlock; | ||
495 | } | ||
496 | |||
497 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
498 | u32 syncpt_max; | ||
499 | int index = args->win[i].index; | ||
500 | struct tegra_dc_win *win; | ||
501 | struct tegra_dc_ext_win *ext_win; | ||
502 | |||
503 | if (index < 0) | ||
504 | continue; | ||
505 | |||
506 | win = tegra_dc_get_window(ext->dc, index); | ||
507 | ext_win = &ext->win[index]; | ||
508 | |||
509 | syncpt_max = tegra_dc_incr_syncpt_max(ext->dc, index); | ||
510 | |||
511 | data->win[i].syncpt_max = syncpt_max; | ||
512 | |||
513 | /* | ||
514 | * Any of these windows' syncpoints should be equivalent for | ||
515 | * the client, so we just send back an arbitrary one of them | ||
516 | */ | ||
517 | args->post_syncpt_val = syncpt_max; | ||
518 | args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index); | ||
519 | work_index = index; | ||
520 | |||
521 | atomic_inc(&ext->win[work_index].nr_pending_flips); | ||
522 | } | ||
523 | queue_work(ext->win[work_index].flip_wq, &data->work); | ||
524 | |||
525 | unlock_windows_for_flip(user, args); | ||
526 | |||
527 | return 0; | ||
528 | |||
529 | unlock: | ||
530 | unlock_windows_for_flip(user, args); | ||
531 | |||
532 | fail_pin: | ||
533 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
534 | int j; | ||
535 | for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) { | ||
536 | if (!data->win[i].handle[j]) | ||
537 | continue; | ||
538 | |||
539 | nvmap_unpin(ext->nvmap, data->win[i].handle[j]); | ||
540 | nvmap_free(ext->nvmap, data->win[i].handle[j]); | ||
541 | } | ||
542 | } | ||
543 | kfree(data); | ||
544 | |||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user, | ||
549 | struct tegra_dc_ext_csc *new_csc) | ||
550 | { | ||
551 | unsigned int index = new_csc->win_index; | ||
552 | struct tegra_dc *dc = user->ext->dc; | ||
553 | struct tegra_dc_ext_win *ext_win; | ||
554 | struct tegra_dc_csc *csc; | ||
555 | |||
556 | if (index >= DC_N_WINDOWS) | ||
557 | return -EINVAL; | ||
558 | |||
559 | ext_win = &user->ext->win[index]; | ||
560 | csc = &dc->windows[index].csc; | ||
561 | |||
562 | mutex_lock(&ext_win->lock); | ||
563 | |||
564 | if (ext_win->user != user) { | ||
565 | mutex_unlock(&ext_win->lock); | ||
566 | return -EACCES; | ||
567 | } | ||
568 | |||
569 | csc->yof = new_csc->yof; | ||
570 | csc->kyrgb = new_csc->kyrgb; | ||
571 | csc->kur = new_csc->kur; | ||
572 | csc->kvr = new_csc->kvr; | ||
573 | csc->kug = new_csc->kug; | ||
574 | csc->kvg = new_csc->kvg; | ||
575 | csc->kub = new_csc->kub; | ||
576 | csc->kvb = new_csc->kvb; | ||
577 | |||
578 | tegra_dc_update_csc(dc, index); | ||
579 | |||
580 | mutex_unlock(&ext_win->lock); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int set_lut_channel(u16 *channel_from_user, | ||
586 | u8 *channel_to, | ||
587 | u32 start, | ||
588 | u32 len) | ||
589 | { | ||
590 | int i; | ||
591 | u16 lut16bpp[256]; | ||
592 | |||
593 | if (channel_from_user) { | ||
594 | if (copy_from_user(lut16bpp, channel_from_user, len<<1)) | ||
595 | return 1; | ||
596 | |||
597 | for (i = 0; i < len; i++) | ||
598 | channel_to[start+i] = lut16bpp[i]>>8; | ||
599 | } else { | ||
600 | for (i = 0; i < len; i++) | ||
601 | channel_to[start+i] = start+i; | ||
602 | } | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static int tegra_dc_ext_set_lut(struct tegra_dc_ext_user *user, | ||
608 | struct tegra_dc_ext_lut *new_lut) | ||
609 | { | ||
610 | int err; | ||
611 | unsigned int index = new_lut->win_index; | ||
612 | u32 start = new_lut->start; | ||
613 | u32 len = new_lut->len; | ||
614 | |||
615 | struct tegra_dc *dc = user->ext->dc; | ||
616 | struct tegra_dc_ext_win *ext_win; | ||
617 | struct tegra_dc_lut *lut; | ||
618 | |||
619 | if (index >= DC_N_WINDOWS) | ||
620 | return -EINVAL; | ||
621 | |||
622 | if ((start >= 256) || (len > 256) || ((start + len) > 256)) | ||
623 | return -EINVAL; | ||
624 | |||
625 | ext_win = &user->ext->win[index]; | ||
626 | lut = &dc->windows[index].lut; | ||
627 | |||
628 | mutex_lock(&ext_win->lock); | ||
629 | |||
630 | if (ext_win->user != user) { | ||
631 | mutex_unlock(&ext_win->lock); | ||
632 | return -EACCES; | ||
633 | } | ||
634 | |||
635 | err = set_lut_channel(new_lut->r, lut->r, start, len) | | ||
636 | set_lut_channel(new_lut->g, lut->g, start, len) | | ||
637 | set_lut_channel(new_lut->b, lut->b, start, len); | ||
638 | |||
639 | if (err) { | ||
640 | mutex_unlock(&ext_win->lock); | ||
641 | return -EFAULT; | ||
642 | } | ||
643 | |||
644 | tegra_dc_update_lut(dc, index, | ||
645 | new_lut->flags & TEGRA_DC_EXT_LUT_FLAGS_FBOVERRIDE); | ||
646 | |||
647 | mutex_unlock(&ext_win->lock); | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user) | ||
653 | { | ||
654 | struct tegra_dc *dc = user->ext->dc; | ||
655 | |||
656 | return dc->vblank_syncpt; | ||
657 | } | ||
658 | |||
659 | static int tegra_dc_ext_get_status(struct tegra_dc_ext_user *user, | ||
660 | struct tegra_dc_ext_status *status) | ||
661 | { | ||
662 | struct tegra_dc *dc = user->ext->dc; | ||
663 | |||
664 | memset(status, 0, sizeof(*status)); | ||
665 | |||
666 | if (dc->enabled) | ||
667 | status->flags |= TEGRA_DC_EXT_FLAGS_ENABLED; | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static long tegra_dc_ioctl(struct file *filp, unsigned int cmd, | ||
673 | unsigned long arg) | ||
674 | { | ||
675 | void __user *user_arg = (void __user *)arg; | ||
676 | struct tegra_dc_ext_user *user = filp->private_data; | ||
677 | |||
678 | switch (cmd) { | ||
679 | case TEGRA_DC_EXT_SET_NVMAP_FD: | ||
680 | return tegra_dc_ext_set_nvmap_fd(user, arg); | ||
681 | |||
682 | case TEGRA_DC_EXT_GET_WINDOW: | ||
683 | return tegra_dc_ext_get_window(user, arg); | ||
684 | case TEGRA_DC_EXT_PUT_WINDOW: | ||
685 | return tegra_dc_ext_put_window(user, arg); | ||
686 | |||
687 | case TEGRA_DC_EXT_FLIP: | ||
688 | { | ||
689 | struct tegra_dc_ext_flip args; | ||
690 | int ret; | ||
691 | |||
692 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
693 | return -EFAULT; | ||
694 | |||
695 | ret = tegra_dc_ext_flip(user, &args); | ||
696 | |||
697 | if (copy_to_user(user_arg, &args, sizeof(args))) | ||
698 | return -EFAULT; | ||
699 | |||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | case TEGRA_DC_EXT_GET_CURSOR: | ||
704 | return tegra_dc_ext_get_cursor(user); | ||
705 | case TEGRA_DC_EXT_PUT_CURSOR: | ||
706 | return tegra_dc_ext_put_cursor(user); | ||
707 | case TEGRA_DC_EXT_SET_CURSOR_IMAGE: | ||
708 | { | ||
709 | struct tegra_dc_ext_cursor_image args; | ||
710 | |||
711 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
712 | return -EFAULT; | ||
713 | |||
714 | return tegra_dc_ext_set_cursor_image(user, &args); | ||
715 | } | ||
716 | case TEGRA_DC_EXT_SET_CURSOR: | ||
717 | { | ||
718 | struct tegra_dc_ext_cursor args; | ||
719 | |||
720 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
721 | return -EFAULT; | ||
722 | |||
723 | return tegra_dc_ext_set_cursor(user, &args); | ||
724 | } | ||
725 | |||
726 | case TEGRA_DC_EXT_SET_CSC: | ||
727 | { | ||
728 | struct tegra_dc_ext_csc args; | ||
729 | |||
730 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
731 | return -EFAULT; | ||
732 | |||
733 | return tegra_dc_ext_set_csc(user, &args); | ||
734 | } | ||
735 | |||
736 | case TEGRA_DC_EXT_GET_VBLANK_SYNCPT: | ||
737 | { | ||
738 | u32 syncpt = tegra_dc_ext_get_vblank_syncpt(user); | ||
739 | |||
740 | if (copy_to_user(user_arg, &syncpt, sizeof(syncpt))) | ||
741 | return -EFAULT; | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | case TEGRA_DC_EXT_GET_STATUS: | ||
747 | { | ||
748 | struct tegra_dc_ext_status args; | ||
749 | int ret; | ||
750 | |||
751 | ret = tegra_dc_ext_get_status(user, &args); | ||
752 | |||
753 | if (copy_to_user(user_arg, &args, sizeof(args))) | ||
754 | return -EFAULT; | ||
755 | |||
756 | return ret; | ||
757 | } | ||
758 | |||
759 | case TEGRA_DC_EXT_SET_LUT: | ||
760 | { | ||
761 | struct tegra_dc_ext_lut args; | ||
762 | |||
763 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
764 | return -EFAULT; | ||
765 | |||
766 | return tegra_dc_ext_set_lut(user, &args); | ||
767 | } | ||
768 | |||
769 | default: | ||
770 | return -EINVAL; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | static int tegra_dc_open(struct inode *inode, struct file *filp) | ||
775 | { | ||
776 | struct tegra_dc_ext_user *user; | ||
777 | struct tegra_dc_ext *ext; | ||
778 | |||
779 | user = kzalloc(sizeof(*user), GFP_KERNEL); | ||
780 | if (!user) | ||
781 | return -ENOMEM; | ||
782 | |||
783 | ext = container_of(inode->i_cdev, struct tegra_dc_ext, cdev); | ||
784 | user->ext = ext; | ||
785 | |||
786 | filp->private_data = user; | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int tegra_dc_release(struct inode *inode, struct file *filp) | ||
792 | { | ||
793 | struct tegra_dc_ext_user *user = filp->private_data; | ||
794 | struct tegra_dc_ext *ext = user->ext; | ||
795 | unsigned int i; | ||
796 | |||
797 | for (i = 0; i < DC_N_WINDOWS; i++) { | ||
798 | if (ext->win[i].user == user) | ||
799 | tegra_dc_ext_put_window(user, i); | ||
800 | } | ||
801 | if (ext->cursor.user == user) | ||
802 | tegra_dc_ext_put_cursor(user); | ||
803 | |||
804 | if (user->nvmap) | ||
805 | nvmap_client_put(user->nvmap); | ||
806 | |||
807 | kfree(user); | ||
808 | |||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext) | ||
813 | { | ||
814 | int i, ret; | ||
815 | |||
816 | for (i = 0; i < ext->dc->n_windows; i++) { | ||
817 | struct tegra_dc_ext_win *win = &ext->win[i]; | ||
818 | char name[32]; | ||
819 | |||
820 | win->ext = ext; | ||
821 | win->idx = i; | ||
822 | |||
823 | snprintf(name, sizeof(name), "tegradc.%d/%c", | ||
824 | ext->dc->ndev->id, 'a' + i); | ||
825 | win->flip_wq = create_singlethread_workqueue(name); | ||
826 | if (!win->flip_wq) { | ||
827 | ret = -ENOMEM; | ||
828 | goto cleanup; | ||
829 | } | ||
830 | |||
831 | mutex_init(&win->lock); | ||
832 | } | ||
833 | |||
834 | return 0; | ||
835 | |||
836 | cleanup: | ||
837 | while (i--) { | ||
838 | struct tegra_dc_ext_win *win = &ext->win[i]; | ||
839 | destroy_workqueue(win->flip_wq); | ||
840 | } | ||
841 | |||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | static const struct file_operations tegra_dc_devops = { | ||
846 | .owner = THIS_MODULE, | ||
847 | .open = tegra_dc_open, | ||
848 | .release = tegra_dc_release, | ||
849 | .unlocked_ioctl = tegra_dc_ioctl, | ||
850 | }; | ||
851 | |||
852 | struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev, | ||
853 | struct tegra_dc *dc) | ||
854 | { | ||
855 | int ret; | ||
856 | struct tegra_dc_ext *ext; | ||
857 | int devno; | ||
858 | |||
859 | ext = kzalloc(sizeof(*ext), GFP_KERNEL); | ||
860 | if (!ext) | ||
861 | return ERR_PTR(-ENOMEM); | ||
862 | |||
863 | BUG_ON(!tegra_dc_ext_devno); | ||
864 | devno = tegra_dc_ext_devno + head_count + 1; | ||
865 | |||
866 | cdev_init(&ext->cdev, &tegra_dc_devops); | ||
867 | ext->cdev.owner = THIS_MODULE; | ||
868 | ret = cdev_add(&ext->cdev, devno, 1); | ||
869 | if (ret) { | ||
870 | dev_err(&ndev->dev, "Failed to create character device\n"); | ||
871 | goto cleanup_alloc; | ||
872 | } | ||
873 | |||
874 | ext->dev = device_create(tegra_dc_ext_class, | ||
875 | &ndev->dev, | ||
876 | devno, | ||
877 | NULL, | ||
878 | "tegra_dc_%d", | ||
879 | ndev->id); | ||
880 | |||
881 | if (IS_ERR(ext->dev)) { | ||
882 | ret = PTR_ERR(ext->dev); | ||
883 | goto cleanup_cdev; | ||
884 | } | ||
885 | |||
886 | ext->dc = dc; | ||
887 | |||
888 | ext->nvmap = nvmap_create_client(nvmap_dev, "tegra_dc_ext"); | ||
889 | if (!ext->nvmap) { | ||
890 | ret = -ENOMEM; | ||
891 | goto cleanup_device; | ||
892 | } | ||
893 | |||
894 | ret = tegra_dc_ext_setup_windows(ext); | ||
895 | if (ret) | ||
896 | goto cleanup_nvmap; | ||
897 | |||
898 | mutex_init(&ext->cursor.lock); | ||
899 | |||
900 | head_count++; | ||
901 | |||
902 | return ext; | ||
903 | |||
904 | cleanup_nvmap: | ||
905 | nvmap_client_put(ext->nvmap); | ||
906 | |||
907 | cleanup_device: | ||
908 | device_del(ext->dev); | ||
909 | |||
910 | cleanup_cdev: | ||
911 | cdev_del(&ext->cdev); | ||
912 | |||
913 | cleanup_alloc: | ||
914 | kfree(ext); | ||
915 | |||
916 | return ERR_PTR(ret); | ||
917 | } | ||
918 | |||
919 | void tegra_dc_ext_unregister(struct tegra_dc_ext *ext) | ||
920 | { | ||
921 | int i; | ||
922 | |||
923 | for (i = 0; i < ext->dc->n_windows; i++) { | ||
924 | struct tegra_dc_ext_win *win = &ext->win[i]; | ||
925 | |||
926 | flush_workqueue(win->flip_wq); | ||
927 | destroy_workqueue(win->flip_wq); | ||
928 | } | ||
929 | |||
930 | nvmap_client_put(ext->nvmap); | ||
931 | device_del(ext->dev); | ||
932 | cdev_del(&ext->cdev); | ||
933 | |||
934 | kfree(ext); | ||
935 | |||
936 | head_count--; | ||
937 | } | ||
938 | |||
939 | int __init tegra_dc_ext_module_init(void) | ||
940 | { | ||
941 | int ret; | ||
942 | |||
943 | tegra_dc_ext_class = class_create(THIS_MODULE, "tegra_dc_ext"); | ||
944 | if (!tegra_dc_ext_class) { | ||
945 | printk(KERN_ERR "tegra_dc_ext: failed to create class\n"); | ||
946 | return -ENOMEM; | ||
947 | } | ||
948 | |||
949 | /* Reserve one character device per head, plus the control device */ | ||
950 | ret = alloc_chrdev_region(&tegra_dc_ext_devno, | ||
951 | 0, TEGRA_MAX_DC + 1, | ||
952 | "tegra_dc_ext"); | ||
953 | if (ret) | ||
954 | goto cleanup_class; | ||
955 | |||
956 | ret = tegra_dc_ext_control_init(); | ||
957 | if (ret) | ||
958 | goto cleanup_region; | ||
959 | |||
960 | return 0; | ||
961 | |||
962 | cleanup_region: | ||
963 | unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC); | ||
964 | |||
965 | cleanup_class: | ||
966 | class_destroy(tegra_dc_ext_class); | ||
967 | |||
968 | return ret; | ||
969 | } | ||
970 | |||
971 | void __exit tegra_dc_ext_module_exit(void) | ||
972 | { | ||
973 | unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC); | ||
974 | class_destroy(tegra_dc_ext_class); | ||
975 | } | ||
diff --git a/drivers/video/tegra/dc/ext/events.c b/drivers/video/tegra/dc/ext/events.c new file mode 100644 index 00000000000..150a1501fce --- /dev/null +++ b/drivers/video/tegra/dc/ext/events.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/ext/events.c | ||
3 | * | ||
4 | * Copyright (C) 2011, NVIDIA Corporation | ||
5 | * | ||
6 | * Author: Robert Morell <rmorell@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/err.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/poll.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | |||
27 | #include "tegra_dc_ext_priv.h" | ||
28 | |||
29 | static DECLARE_WAIT_QUEUE_HEAD(event_wait); | ||
30 | |||
31 | unsigned int tegra_dc_ext_event_poll(struct file *filp, poll_table *wait) | ||
32 | { | ||
33 | struct tegra_dc_ext_control_user *user = filp->private_data; | ||
34 | unsigned int mask = 0; | ||
35 | |||
36 | poll_wait(filp, &event_wait, wait); | ||
37 | |||
38 | if (atomic_read(&user->num_events)) | ||
39 | mask |= POLLIN; | ||
40 | |||
41 | return mask; | ||
42 | } | ||
43 | |||
44 | static int get_next_event(struct tegra_dc_ext_control_user *user, | ||
45 | struct tegra_dc_ext_event_list *event, | ||
46 | bool block) | ||
47 | { | ||
48 | struct list_head *list = &user->event_list; | ||
49 | struct tegra_dc_ext_event_list *next_event; | ||
50 | int ret; | ||
51 | |||
52 | if (block) { | ||
53 | ret = wait_event_interruptible(event_wait, | ||
54 | atomic_read(&user->num_events)); | ||
55 | |||
56 | if (unlikely(ret)) { | ||
57 | if (ret == -ERESTARTSYS) | ||
58 | return -EAGAIN; | ||
59 | return ret; | ||
60 | } | ||
61 | } else { | ||
62 | if (!atomic_read(&user->num_events)) | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | mutex_lock(&user->lock); | ||
67 | |||
68 | BUG_ON(list_empty(list)); | ||
69 | next_event = list_first_entry(list, struct tegra_dc_ext_event_list, | ||
70 | list); | ||
71 | *event = *next_event; | ||
72 | list_del(&next_event->list); | ||
73 | kfree(next_event); | ||
74 | |||
75 | atomic_dec(&user->num_events); | ||
76 | |||
77 | mutex_unlock(&user->lock); | ||
78 | |||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | ssize_t tegra_dc_ext_event_read(struct file *filp, char __user *buf, | ||
83 | size_t size, loff_t *ppos) | ||
84 | { | ||
85 | struct tegra_dc_ext_control_user *user = filp->private_data; | ||
86 | struct tegra_dc_ext_event_list event_elem; | ||
87 | struct tegra_dc_ext_event *event = &event_elem.event; | ||
88 | ssize_t retval = 0, to_copy, event_size, pending; | ||
89 | loff_t previously_copied = 0; | ||
90 | char *to_copy_ptr; | ||
91 | |||
92 | if (size == 0) | ||
93 | return 0; | ||
94 | |||
95 | if (user->partial_copy) { | ||
96 | /* | ||
97 | * We didn't transfer the entire event last time, need to | ||
98 | * finish it up | ||
99 | */ | ||
100 | event_elem = user->event_to_copy; | ||
101 | previously_copied = user->partial_copy; | ||
102 | } else { | ||
103 | /* Get the next event, if any */ | ||
104 | pending = get_next_event(user, &event_elem, | ||
105 | !(filp->f_flags & O_NONBLOCK)); | ||
106 | if (pending <= 0) | ||
107 | return pending; | ||
108 | } | ||
109 | |||
110 | /* Write the event to the user */ | ||
111 | event_size = sizeof(*event) + event->data_size; | ||
112 | BUG_ON(event_size <= previously_copied); | ||
113 | event_size -= previously_copied; | ||
114 | |||
115 | to_copy_ptr = (char *)event + previously_copied; | ||
116 | to_copy = min_t(ssize_t, size, event_size); | ||
117 | if (copy_to_user(buf, to_copy_ptr, to_copy)) { | ||
118 | retval = -EFAULT; | ||
119 | to_copy = 0; | ||
120 | } | ||
121 | |||
122 | /* Note that we currently only deliver one event at a time */ | ||
123 | |||
124 | if (event_size > to_copy) { | ||
125 | /* | ||
126 | * We were only able to copy part of this event. Stash it for | ||
127 | * next time. | ||
128 | */ | ||
129 | user->event_to_copy = event_elem; | ||
130 | user->partial_copy = previously_copied + to_copy; | ||
131 | } else { | ||
132 | user->partial_copy = 0; | ||
133 | } | ||
134 | |||
135 | return to_copy ? to_copy : retval; | ||
136 | } | ||
137 | |||
138 | static int tegra_dc_ext_queue_event(struct tegra_dc_ext_control *control, | ||
139 | struct tegra_dc_ext_event *event) | ||
140 | { | ||
141 | struct list_head *cur; | ||
142 | int retval = 0; | ||
143 | |||
144 | mutex_lock(&control->lock); | ||
145 | list_for_each(cur, &control->users) { | ||
146 | struct tegra_dc_ext_control_user *user; | ||
147 | struct tegra_dc_ext_event_list *ev_list; | ||
148 | |||
149 | user = container_of(cur, struct tegra_dc_ext_control_user, | ||
150 | list); | ||
151 | mutex_lock(&user->lock); | ||
152 | |||
153 | if (!(user->event_mask & event->type)) { | ||
154 | mutex_unlock(&user->lock); | ||
155 | continue; | ||
156 | } | ||
157 | |||
158 | ev_list = kmalloc(sizeof(*ev_list), GFP_KERNEL); | ||
159 | if (!ev_list) { | ||
160 | retval = -ENOMEM; | ||
161 | mutex_unlock(&user->lock); | ||
162 | continue; | ||
163 | } | ||
164 | |||
165 | memcpy(&ev_list->event, event, | ||
166 | sizeof(*event) + event->data_size); | ||
167 | |||
168 | list_add_tail(&ev_list->list, &user->event_list); | ||
169 | |||
170 | atomic_inc(&user->num_events); | ||
171 | |||
172 | mutex_unlock(&user->lock); | ||
173 | } | ||
174 | mutex_unlock(&control->lock); | ||
175 | |||
176 | /* Is it worth it to track waiters with more granularity? */ | ||
177 | wake_up(&event_wait); | ||
178 | |||
179 | return retval; | ||
180 | } | ||
181 | |||
182 | int tegra_dc_ext_queue_hotplug(struct tegra_dc_ext_control *control, int output) | ||
183 | { | ||
184 | struct { | ||
185 | struct tegra_dc_ext_event event; | ||
186 | struct tegra_dc_ext_control_event_hotplug hotplug; | ||
187 | } __packed pack; | ||
188 | |||
189 | pack.event.type = TEGRA_DC_EXT_EVENT_HOTPLUG; | ||
190 | pack.event.data_size = sizeof(pack.hotplug); | ||
191 | |||
192 | pack.hotplug.handle = output; | ||
193 | |||
194 | tegra_dc_ext_queue_event(control, &pack.event); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h new file mode 100644 index 00000000000..95a637d5a52 --- /dev/null +++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h | ||
3 | * | ||
4 | * Copyright (C) 2011, NVIDIA Corporation | ||
5 | * | ||
6 | * Author: Robert Morell <rmorell@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | */ | ||
18 | |||
19 | #ifndef __TEGRA_DC_EXT_PRIV_H | ||
20 | #define __TEGRA_DC_EXT_PRIV_H | ||
21 | |||
22 | #include <linux/cdev.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/mutex.h> | ||
25 | #include <linux/poll.h> | ||
26 | |||
27 | #include <mach/dc.h> | ||
28 | #include <mach/nvmap.h> | ||
29 | |||
30 | #include <video/tegra_dc_ext.h> | ||
31 | |||
32 | struct tegra_dc_ext; | ||
33 | |||
34 | struct tegra_dc_ext_user { | ||
35 | struct tegra_dc_ext *ext; | ||
36 | struct nvmap_client *nvmap; | ||
37 | }; | ||
38 | |||
39 | enum { | ||
40 | TEGRA_DC_Y, | ||
41 | TEGRA_DC_U, | ||
42 | TEGRA_DC_V, | ||
43 | TEGRA_DC_NUM_PLANES, | ||
44 | }; | ||
45 | |||
46 | struct tegra_dc_ext_win { | ||
47 | struct tegra_dc_ext *ext; | ||
48 | |||
49 | int idx; | ||
50 | |||
51 | struct tegra_dc_ext_user *user; | ||
52 | |||
53 | struct mutex lock; | ||
54 | |||
55 | /* Current nvmap handle (if any) for Y, U, V planes */ | ||
56 | struct nvmap_handle_ref *cur_handle[TEGRA_DC_NUM_PLANES]; | ||
57 | |||
58 | struct workqueue_struct *flip_wq; | ||
59 | |||
60 | atomic_t nr_pending_flips; | ||
61 | }; | ||
62 | |||
63 | struct tegra_dc_ext { | ||
64 | struct tegra_dc *dc; | ||
65 | |||
66 | struct cdev cdev; | ||
67 | struct device *dev; | ||
68 | |||
69 | struct nvmap_client *nvmap; | ||
70 | |||
71 | struct tegra_dc_ext_win win[DC_N_WINDOWS]; | ||
72 | |||
73 | struct { | ||
74 | struct tegra_dc_ext_user *user; | ||
75 | struct nvmap_handle_ref *cur_handle; | ||
76 | struct mutex lock; | ||
77 | } cursor; | ||
78 | |||
79 | bool enabled; | ||
80 | }; | ||
81 | |||
82 | #define TEGRA_DC_EXT_EVENT_MASK_ALL \ | ||
83 | TEGRA_DC_EXT_EVENT_HOTPLUG | ||
84 | |||
85 | #define TEGRA_DC_EXT_EVENT_MAX_SZ 8 | ||
86 | |||
87 | struct tegra_dc_ext_event_list { | ||
88 | struct tegra_dc_ext_event event; | ||
89 | /* The data field _must_ follow the event field. */ | ||
90 | char data[TEGRA_DC_EXT_EVENT_MAX_SZ]; | ||
91 | |||
92 | struct list_head list; | ||
93 | }; | ||
94 | |||
95 | #define TEGRA_DC_EXT_CAPABILITIES \ | ||
96 | TEGRA_DC_EXT_CAPABILITIES_CURSOR_MODE | ||
97 | |||
98 | struct tegra_dc_ext_control_user { | ||
99 | struct tegra_dc_ext_control *control; | ||
100 | |||
101 | struct list_head event_list; | ||
102 | atomic_t num_events; | ||
103 | |||
104 | u32 event_mask; | ||
105 | |||
106 | struct tegra_dc_ext_event_list event_to_copy; | ||
107 | loff_t partial_copy; | ||
108 | |||
109 | struct mutex lock; | ||
110 | |||
111 | struct list_head list; | ||
112 | }; | ||
113 | |||
114 | struct tegra_dc_ext_control { | ||
115 | struct cdev cdev; | ||
116 | struct device *dev; | ||
117 | |||
118 | struct list_head users; | ||
119 | |||
120 | struct mutex lock; | ||
121 | }; | ||
122 | |||
123 | extern int tegra_dc_ext_devno; | ||
124 | extern struct class *tegra_dc_ext_class; | ||
125 | |||
126 | extern int tegra_dc_ext_pin_window(struct tegra_dc_ext_user *user, u32 id, | ||
127 | struct nvmap_handle_ref **handle, | ||
128 | dma_addr_t *phys_addr); | ||
129 | |||
130 | extern int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user); | ||
131 | extern int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user); | ||
132 | extern int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user, | ||
133 | struct tegra_dc_ext_cursor_image *); | ||
134 | extern int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user, | ||
135 | struct tegra_dc_ext_cursor *); | ||
136 | |||
137 | extern int tegra_dc_ext_control_init(void); | ||
138 | |||
139 | extern int tegra_dc_ext_queue_hotplug(struct tegra_dc_ext_control *, | ||
140 | int output); | ||
141 | extern ssize_t tegra_dc_ext_event_read(struct file *filp, char __user *buf, | ||
142 | size_t size, loff_t *ppos); | ||
143 | extern unsigned int tegra_dc_ext_event_poll(struct file *, poll_table *); | ||
144 | |||
145 | extern int tegra_dc_ext_get_num_outputs(void); | ||
146 | |||
147 | #endif /* __TEGRA_DC_EXT_PRIV_H */ | ||
diff --git a/drivers/video/tegra/dc/ext/util.c b/drivers/video/tegra/dc/ext/util.c new file mode 100644 index 00000000000..747085579f1 --- /dev/null +++ b/drivers/video/tegra/dc/ext/util.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/ext/util.c | ||
3 | * | ||
4 | * Copyright (C) 2011, NVIDIA Corporation | ||
5 | * | ||
6 | * Author: Robert Morell <rmorell@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/err.h> | ||
20 | #include <linux/types.h> | ||
21 | |||
22 | #include <mach/dc.h> | ||
23 | #include <mach/nvmap.h> | ||
24 | |||
25 | /* ugh */ | ||
26 | #include "../../nvmap/nvmap.h" | ||
27 | |||
28 | #include "tegra_dc_ext_priv.h" | ||
29 | |||
30 | int tegra_dc_ext_pin_window(struct tegra_dc_ext_user *user, u32 id, | ||
31 | struct nvmap_handle_ref **handle, | ||
32 | dma_addr_t *phys_addr) | ||
33 | { | ||
34 | struct tegra_dc_ext *ext = user->ext; | ||
35 | struct nvmap_handle_ref *win_dup; | ||
36 | struct nvmap_handle *win_handle; | ||
37 | dma_addr_t phys; | ||
38 | |||
39 | if (!id) { | ||
40 | *handle = NULL; | ||
41 | *phys_addr = -1; | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Take a reference to the buffer using the user's nvmap context, to | ||
48 | * make sure they have permissions to access it. | ||
49 | */ | ||
50 | win_handle = nvmap_get_handle_id(user->nvmap, id); | ||
51 | if (!win_handle) | ||
52 | return -EACCES; | ||
53 | |||
54 | /* | ||
55 | * Duplicate the buffer's handle into the dc_ext driver's nvmap | ||
56 | * context, to ensure that the handle won't be freed as long as it is | ||
57 | * in use by display. | ||
58 | */ | ||
59 | win_dup = nvmap_duplicate_handle_id(ext->nvmap, id); | ||
60 | |||
61 | /* Release the reference we took in the user's context above */ | ||
62 | nvmap_handle_put(win_handle); | ||
63 | |||
64 | if (IS_ERR(win_dup)) | ||
65 | return PTR_ERR(win_dup); | ||
66 | |||
67 | phys = nvmap_pin(ext->nvmap, win_dup); | ||
68 | /* XXX this isn't correct for non-pointers... */ | ||
69 | if (IS_ERR((void *)phys)) { | ||
70 | nvmap_free(ext->nvmap, win_dup); | ||
71 | return PTR_ERR((void *)phys); | ||
72 | } | ||
73 | |||
74 | *phys_addr = phys; | ||
75 | *handle = win_dup; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c new file mode 100644 index 00000000000..cb401a167fd --- /dev/null +++ b/drivers/video/tegra/dc/hdmi.c | |||
@@ -0,0 +1,2381 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/hdmi.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * Copyright (C) 2010-2011 NVIDIA Corporation | ||
8 | * | ||
9 | * This software is licensed under the terms of the GNU General Public | ||
10 | * License version 2, as published by the Free Software Foundation, and | ||
11 | * may be copied, distributed, and modified under those terms. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/clk.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/fb.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #ifdef CONFIG_SWITCH | ||
30 | #include <linux/switch.h> | ||
31 | #endif | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/device.h> | ||
36 | |||
37 | #include <mach/clk.h> | ||
38 | #include <mach/dc.h> | ||
39 | #include <mach/fb.h> | ||
40 | #include <linux/nvhost.h> | ||
41 | #include <mach/hdmi-audio.h> | ||
42 | |||
43 | #include <video/tegrafb.h> | ||
44 | |||
45 | #include "dc_reg.h" | ||
46 | #include "dc_priv.h" | ||
47 | #include "hdmi_reg.h" | ||
48 | #include "hdmi.h" | ||
49 | #include "edid.h" | ||
50 | #include "nvhdcp.h" | ||
51 | |||
52 | /* datasheet claims this will always be 216MHz */ | ||
53 | #define HDMI_AUDIOCLK_FREQ 216000000 | ||
54 | |||
55 | #define HDMI_REKEY_DEFAULT 56 | ||
56 | |||
57 | #define HDMI_ELD_RESERVED1_INDEX 1 | ||
58 | #define HDMI_ELD_RESERVED2_INDEX 3 | ||
59 | #define HDMI_ELD_VER_INDEX 0 | ||
60 | #define HDMI_ELD_BASELINE_LEN_INDEX 2 | ||
61 | #define HDMI_ELD_CEA_VER_MNL_INDEX 4 | ||
62 | #define HDMI_ELD_SAD_CNT_CON_TYP_SAI_HDCP_INDEX 5 | ||
63 | #define HDMI_ELD_AUD_SYNC_DELAY_INDEX 6 | ||
64 | #define HDMI_ELD_SPK_ALLOC_INDEX 7 | ||
65 | #define HDMI_ELD_PORT_ID_INDEX 8 | ||
66 | #define HDMI_ELD_MANF_NAME_INDEX 16 | ||
67 | #define HDMI_ELD_PRODUCT_CODE_INDEX 18 | ||
68 | #define HDMI_ELD_MONITOR_NAME_INDEX 20 | ||
69 | |||
70 | struct tegra_dc_hdmi_data { | ||
71 | struct tegra_dc *dc; | ||
72 | struct tegra_edid *edid; | ||
73 | struct tegra_edid_hdmi_eld eld; | ||
74 | struct tegra_nvhdcp *nvhdcp; | ||
75 | struct delayed_work work; | ||
76 | |||
77 | struct resource *base_res; | ||
78 | void __iomem *base; | ||
79 | struct clk *clk; | ||
80 | |||
81 | struct clk *disp1_clk; | ||
82 | struct clk *disp2_clk; | ||
83 | struct clk *hda_clk; | ||
84 | struct clk *hda2codec_clk; | ||
85 | struct clk *hda2hdmi_clk; | ||
86 | |||
87 | #ifdef CONFIG_SWITCH | ||
88 | struct switch_dev hpd_switch; | ||
89 | #endif | ||
90 | |||
91 | spinlock_t suspend_lock; | ||
92 | bool suspended; | ||
93 | bool eld_retrieved; | ||
94 | bool clk_enabled; | ||
95 | unsigned audio_freq; | ||
96 | unsigned audio_source; | ||
97 | |||
98 | bool dvi; | ||
99 | }; | ||
100 | |||
101 | struct tegra_dc_hdmi_data *dc_hdmi; | ||
102 | |||
103 | const struct fb_videomode tegra_dc_hdmi_supported_modes[] = { | ||
104 | /* 1280x720p 60hz: EIA/CEA-861-B Format 4 */ | ||
105 | { | ||
106 | .xres = 1280, | ||
107 | .yres = 720, | ||
108 | .pixclock = KHZ2PICOS(74250), | ||
109 | .hsync_len = 40, /* h_sync_width */ | ||
110 | .vsync_len = 5, /* v_sync_width */ | ||
111 | .left_margin = 220, /* h_back_porch */ | ||
112 | .upper_margin = 20, /* v_back_porch */ | ||
113 | .right_margin = 110, /* h_front_porch */ | ||
114 | .lower_margin = 5, /* v_front_porch */ | ||
115 | .vmode = FB_VMODE_NONINTERLACED, | ||
116 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
117 | }, | ||
118 | |||
119 | /* 1280x720p 60hz: EIA/CEA-861-B Format 4 (Stereo)*/ | ||
120 | { | ||
121 | .xres = 1280, | ||
122 | .yres = 720, | ||
123 | .pixclock = KHZ2PICOS(74250), | ||
124 | .hsync_len = 40, /* h_sync_width */ | ||
125 | .vsync_len = 5, /* v_sync_width */ | ||
126 | .left_margin = 220, /* h_back_porch */ | ||
127 | .upper_margin = 20, /* v_back_porch */ | ||
128 | .right_margin = 110, /* h_front_porch */ | ||
129 | .lower_margin = 5, /* v_front_porch */ | ||
130 | .vmode = FB_VMODE_NONINTERLACED | | ||
131 | #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
132 | FB_VMODE_STEREO_FRAME_PACK, | ||
133 | #else | ||
134 | FB_VMODE_STEREO_LEFT_RIGHT, | ||
135 | #endif | ||
136 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
137 | }, | ||
138 | |||
139 | /* 720x480p 59.94hz: EIA/CEA-861-B Formats 2 & 3 */ | ||
140 | { | ||
141 | .xres = 720, | ||
142 | .yres = 480, | ||
143 | .pixclock = KHZ2PICOS(27000), | ||
144 | .hsync_len = 62, /* h_sync_width */ | ||
145 | .vsync_len = 6, /* v_sync_width */ | ||
146 | .left_margin = 60, /* h_back_porch */ | ||
147 | .upper_margin = 30, /* v_back_porch */ | ||
148 | .right_margin = 16, /* h_front_porch */ | ||
149 | .lower_margin = 9, /* v_front_porch */ | ||
150 | .vmode = FB_VMODE_NONINTERLACED, | ||
151 | .sync = 0, | ||
152 | }, | ||
153 | |||
154 | /* 640x480p 60hz: EIA/CEA-861-B Format 1 */ | ||
155 | { | ||
156 | .xres = 640, | ||
157 | .yres = 480, | ||
158 | .pixclock = KHZ2PICOS(25200), | ||
159 | .hsync_len = 96, /* h_sync_width */ | ||
160 | .vsync_len = 2, /* v_sync_width */ | ||
161 | .left_margin = 48, /* h_back_porch */ | ||
162 | .upper_margin = 33, /* v_back_porch */ | ||
163 | .right_margin = 16, /* h_front_porch */ | ||
164 | .lower_margin = 10, /* v_front_porch */ | ||
165 | .vmode = FB_VMODE_NONINTERLACED, | ||
166 | .sync = 0, | ||
167 | }, | ||
168 | |||
169 | /* 720x576p 50hz EIA/CEA-861-B Formats 17 & 18 */ | ||
170 | { | ||
171 | .xres = 720, | ||
172 | .yres = 576, | ||
173 | .pixclock = KHZ2PICOS(27000), | ||
174 | .hsync_len = 64, /* h_sync_width */ | ||
175 | .vsync_len = 5, /* v_sync_width */ | ||
176 | .left_margin = 68, /* h_back_porch */ | ||
177 | .upper_margin = 39, /* v_back_porch */ | ||
178 | .right_margin = 12, /* h_front_porch */ | ||
179 | .lower_margin = 5, /* v_front_porch */ | ||
180 | .vmode = FB_VMODE_NONINTERLACED, | ||
181 | .sync = 0, | ||
182 | }, | ||
183 | |||
184 | /* 1920x1080p 23.98/24hz: EIA/CEA-861-B Format 32 (Stereo)*/ | ||
185 | { | ||
186 | .xres = 1920, | ||
187 | .yres = 1080, | ||
188 | .pixclock = KHZ2PICOS(74250), | ||
189 | .hsync_len = 44, /* h_sync_width */ | ||
190 | .vsync_len = 5, /* v_sync_width */ | ||
191 | .left_margin = 148, /* h_back_porch */ | ||
192 | .upper_margin = 36, /* v_back_porch */ | ||
193 | .right_margin = 638, /* h_front_porch */ | ||
194 | .lower_margin = 4, /* v_front_porch */ | ||
195 | .vmode = FB_VMODE_NONINTERLACED | | ||
196 | #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
197 | FB_VMODE_STEREO_FRAME_PACK, | ||
198 | #else | ||
199 | FB_VMODE_STEREO_LEFT_RIGHT, | ||
200 | #endif | ||
201 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
202 | }, | ||
203 | |||
204 | /* 1920x1080p 30Hz EIA/CEA-861-B Format 34 */ | ||
205 | { | ||
206 | .xres = 1920, | ||
207 | .yres = 1080, | ||
208 | .pixclock = KHZ2PICOS(74250), | ||
209 | .hsync_len = 44, /* h_sync_width */ | ||
210 | .vsync_len = 5, /* v_sync_width */ | ||
211 | .left_margin = 148, /* h_back_porch */ | ||
212 | .upper_margin = 36, /* v_back_porch */ | ||
213 | .right_margin = 88, /* h_front_porch */ | ||
214 | .lower_margin = 4, /* v_front_porch */ | ||
215 | .vmode = FB_VMODE_NONINTERLACED, | ||
216 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
217 | }, | ||
218 | /* 1920x1080p 59.94/60hz EIA/CEA-861-B Format 16 */ | ||
219 | { | ||
220 | .xres = 1920, | ||
221 | .yres = 1080, | ||
222 | .pixclock = KHZ2PICOS(148500), | ||
223 | .hsync_len = 44, /* h_sync_width */ | ||
224 | .vsync_len = 5, /* v_sync_width */ | ||
225 | .left_margin = 148, /* h_back_porch */ | ||
226 | .upper_margin = 36, /* v_back_porch */ | ||
227 | .right_margin = 88, /* h_front_porch */ | ||
228 | .lower_margin = 4, /* v_front_porch */ | ||
229 | .vmode = FB_VMODE_NONINTERLACED, | ||
230 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
231 | }, | ||
232 | |||
233 | /* | ||
234 | * Few VGA/SVGA modes to support monitors with lower | ||
235 | * resolutions or to support HDMI<->DVI connection | ||
236 | */ | ||
237 | |||
238 | /* 640x480p 75hz */ | ||
239 | { | ||
240 | .xres = 640, | ||
241 | .yres = 480, | ||
242 | .pixclock = KHZ2PICOS(31500), | ||
243 | .hsync_len = 96, /* h_sync_width */ | ||
244 | .vsync_len = 2, /* v_sync_width */ | ||
245 | .left_margin = 48, /* h_back_porch */ | ||
246 | .upper_margin = 32, /* v_back_porch */ | ||
247 | .right_margin = 16, /* h_front_porch */ | ||
248 | .lower_margin = 1, /* v_front_porch */ | ||
249 | .vmode = FB_VMODE_NONINTERLACED, | ||
250 | .sync = 0, | ||
251 | }, | ||
252 | /* 720x400p 59hz */ | ||
253 | { | ||
254 | .xres = 720, | ||
255 | .yres = 400, | ||
256 | .pixclock = KHZ2PICOS(35500), | ||
257 | .hsync_len = 72, /* h_sync_width */ | ||
258 | .vsync_len = 3, /* v_sync_width */ | ||
259 | .left_margin = 108, /* h_back_porch */ | ||
260 | .upper_margin = 42, /* v_back_porch */ | ||
261 | .right_margin = 36, /* h_front_porch */ | ||
262 | .lower_margin = 1, /* v_front_porch */ | ||
263 | .vmode = FB_VMODE_NONINTERLACED, | ||
264 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
265 | }, | ||
266 | /* 800x600p 60hz */ | ||
267 | { | ||
268 | .xres = 800, | ||
269 | .yres = 600, | ||
270 | .pixclock = KHZ2PICOS(40000), | ||
271 | .hsync_len = 128, /* h_sync_width */ | ||
272 | .vsync_len = 4, /* v_sync_width */ | ||
273 | .left_margin = 88, /* h_back_porch */ | ||
274 | .upper_margin = 23, /* v_back_porch */ | ||
275 | .right_margin = 40, /* h_front_porch */ | ||
276 | .lower_margin = 1, /* v_front_porch */ | ||
277 | .vmode = FB_VMODE_NONINTERLACED, | ||
278 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
279 | }, | ||
280 | /* 800x600p 75hz */ | ||
281 | { | ||
282 | .xres = 800, | ||
283 | .yres = 600, | ||
284 | .pixclock = KHZ2PICOS(49500), | ||
285 | .hsync_len = 80, /* h_sync_width */ | ||
286 | .vsync_len = 2, /* v_sync_width */ | ||
287 | .left_margin = 160, /* h_back_porch */ | ||
288 | .upper_margin = 21, /* v_back_porch */ | ||
289 | .right_margin = 16, /* h_front_porch */ | ||
290 | .lower_margin = 1, /* v_front_porch */ | ||
291 | .vmode = FB_VMODE_NONINTERLACED, | ||
292 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
293 | }, | ||
294 | /* 1024x768p 60hz */ | ||
295 | { | ||
296 | .xres = 1024, | ||
297 | .yres = 768, | ||
298 | .pixclock = KHZ2PICOS(65000), | ||
299 | .hsync_len = 136, /* h_sync_width */ | ||
300 | .vsync_len = 6, /* v_sync_width */ | ||
301 | .left_margin = 160, /* h_back_porch */ | ||
302 | .upper_margin = 29, /* v_back_porch */ | ||
303 | .right_margin = 24, /* h_front_porch */ | ||
304 | .lower_margin = 3, /* v_front_porch */ | ||
305 | .vmode = FB_VMODE_NONINTERLACED, | ||
306 | .sync = 0, | ||
307 | }, | ||
308 | /* 1024x768p 75hz */ | ||
309 | { | ||
310 | .xres = 1024, | ||
311 | .yres = 768, | ||
312 | .pixclock = KHZ2PICOS(78800), | ||
313 | .hsync_len = 96, /* h_sync_width */ | ||
314 | .vsync_len = 3, /* v_sync_width */ | ||
315 | .left_margin = 176, /* h_back_porch */ | ||
316 | .upper_margin = 28, /* v_back_porch */ | ||
317 | .right_margin = 16, /* h_front_porch */ | ||
318 | .lower_margin = 1, /* v_front_porch */ | ||
319 | .vmode = FB_VMODE_NONINTERLACED, | ||
320 | .sync = 0, | ||
321 | }, | ||
322 | /* 1152x864p 75hz */ | ||
323 | { | ||
324 | .xres = 1152, | ||
325 | .yres = 864, | ||
326 | .pixclock = KHZ2PICOS(108000), | ||
327 | .hsync_len = 128, /* h_sync_width */ | ||
328 | .vsync_len = 3, /* v_sync_width */ | ||
329 | .left_margin = 256, /* h_back_porch */ | ||
330 | .upper_margin = 32, /* v_back_porch */ | ||
331 | .right_margin = 64, /* h_front_porch */ | ||
332 | .lower_margin = 1, /* v_front_porch */ | ||
333 | .vmode = FB_VMODE_NONINTERLACED, | ||
334 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
335 | }, | ||
336 | /* 1280x800p 60hz */ | ||
337 | { | ||
338 | .xres = 1280, | ||
339 | .yres = 800, | ||
340 | .pixclock = KHZ2PICOS(83460), | ||
341 | .hsync_len = 136, /* h_sync_width */ | ||
342 | .vsync_len = 3, /* v_sync_width */ | ||
343 | .left_margin = 200, /* h_back_porch */ | ||
344 | .upper_margin = 24, /* v_back_porch */ | ||
345 | .right_margin = 64, /* h_front_porch */ | ||
346 | .lower_margin = 1, /* v_front_porch */ | ||
347 | .vmode = FB_VMODE_NONINTERLACED, | ||
348 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
349 | }, | ||
350 | /* 1280x960p 60hz */ | ||
351 | { | ||
352 | .xres = 1280, | ||
353 | .yres = 960, | ||
354 | .pixclock = KHZ2PICOS(108000), | ||
355 | .hsync_len = 136, /* h_sync_width */ | ||
356 | .vsync_len = 3, /* v_sync_width */ | ||
357 | .left_margin = 216, /* h_back_porch */ | ||
358 | .upper_margin = 30, /* v_back_porch */ | ||
359 | .right_margin = 80, /* h_front_porch */ | ||
360 | .lower_margin = 1, /* v_front_porch */ | ||
361 | .vmode = FB_VMODE_NONINTERLACED, | ||
362 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
363 | }, | ||
364 | /* 1280x1024p 60hz */ | ||
365 | { | ||
366 | .xres = 1280, | ||
367 | .yres = 1024, | ||
368 | .pixclock = KHZ2PICOS(108000), | ||
369 | .hsync_len = 112, /* h_sync_width */ | ||
370 | .vsync_len = 3, /* v_sync_width */ | ||
371 | .left_margin = 248, /* h_back_porch */ | ||
372 | .upper_margin = 38, /* v_back_porch */ | ||
373 | .right_margin = 48, /* h_front_porch */ | ||
374 | .lower_margin = 1, /* v_front_porch */ | ||
375 | .vmode = FB_VMODE_NONINTERLACED, | ||
376 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
377 | }, | ||
378 | /* 1280x1024p 75hz */ | ||
379 | { | ||
380 | .xres = 1280, | ||
381 | .yres = 1024, | ||
382 | .pixclock = KHZ2PICOS(135000), | ||
383 | .hsync_len = 144, /* h_sync_width */ | ||
384 | .vsync_len = 3, /* v_sync_width */ | ||
385 | .left_margin = 248, /* h_back_porch */ | ||
386 | .upper_margin = 38, /* v_back_porch */ | ||
387 | .right_margin = 16, /* h_front_porch */ | ||
388 | .lower_margin = 1, /* v_front_porch */ | ||
389 | .vmode = FB_VMODE_NONINTERLACED, | ||
390 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
391 | }, | ||
392 | /* 1368x768p 60hz */ | ||
393 | { | ||
394 | .xres = 1368, | ||
395 | .yres = 768, | ||
396 | .pixclock = KHZ2PICOS(85860), | ||
397 | .hsync_len = 144, /* h_sync_width */ | ||
398 | .vsync_len = 3, /* v_sync_width */ | ||
399 | .left_margin = 216, /* h_back_porch */ | ||
400 | .upper_margin = 23, /* v_back_porch */ | ||
401 | .right_margin = 72, /* h_front_porch */ | ||
402 | .lower_margin = 1, /* v_front_porch */ | ||
403 | .vmode = FB_VMODE_NONINTERLACED, | ||
404 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
405 | }, | ||
406 | /* 1440x900p 60hz */ | ||
407 | { | ||
408 | .xres = 1440, | ||
409 | .yres = 900, | ||
410 | .pixclock = KHZ2PICOS(106470), | ||
411 | .hsync_len = 152, /* h_sync_width */ | ||
412 | .vsync_len = 3, /* v_sync_width */ | ||
413 | .left_margin = 232, /* h_back_porch */ | ||
414 | .upper_margin = 28, /* v_back_porch */ | ||
415 | .right_margin = 80, /* h_front_porch */ | ||
416 | .lower_margin = 1, /* v_front_porch */ | ||
417 | .vmode = FB_VMODE_NONINTERLACED, | ||
418 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
419 | }, | ||
420 | /* 1600x1200p 60hz */ | ||
421 | { | ||
422 | .xres = 1600, | ||
423 | .yres = 1200, | ||
424 | .pixclock = KHZ2PICOS(162000), | ||
425 | .hsync_len = 192, /* h_sync_width */ | ||
426 | .vsync_len = 3, /* v_sync_width */ | ||
427 | .left_margin = 304, /* h_back_porch */ | ||
428 | .upper_margin = 46, /* v_back_porch */ | ||
429 | .right_margin = 64, /* h_front_porch */ | ||
430 | .lower_margin = 1, /* v_front_porch */ | ||
431 | .vmode = FB_VMODE_NONINTERLACED, | ||
432 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
433 | }, | ||
434 | /* 1600x1200p 75hz */ | ||
435 | { | ||
436 | .xres = 1600, | ||
437 | .yres = 1200, | ||
438 | .pixclock = KHZ2PICOS(202500), | ||
439 | .hsync_len = 192, /* h_sync_width */ | ||
440 | .vsync_len = 3, /* v_sync_width */ | ||
441 | .left_margin = 304, /* h_back_porch */ | ||
442 | .upper_margin = 46, /* v_back_porch */ | ||
443 | .right_margin = 64, /* h_front_porch */ | ||
444 | .lower_margin = 1, /* v_front_porch */ | ||
445 | .vmode = FB_VMODE_NONINTERLACED, | ||
446 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
447 | }, | ||
448 | /* 1680x1050p 59.94/60hz */ | ||
449 | { | ||
450 | .xres = 1680, | ||
451 | .yres = 1050, | ||
452 | .pixclock = KHZ2PICOS(147140), | ||
453 | .hsync_len = 184, /* h_sync_width */ | ||
454 | .vsync_len = 3, /* v_sync_width */ | ||
455 | .left_margin = 288, /* h_back_porch */ | ||
456 | .upper_margin = 33, /* v_back_porch */ | ||
457 | .right_margin = 104, /* h_front_porch */ | ||
458 | .lower_margin = 1, /* v_front_porch */ | ||
459 | .vmode = FB_VMODE_NONINTERLACED, | ||
460 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
461 | }, | ||
462 | }; | ||
463 | |||
464 | /* CVT timing representation of VESA modes*/ | ||
465 | const struct fb_videomode tegra_dc_hdmi_supported_cvt_modes[] = { | ||
466 | |||
467 | /* 640x480p 60hz */ | ||
468 | { | ||
469 | .refresh = 60, | ||
470 | .xres = 640, | ||
471 | .yres = 480, | ||
472 | .pixclock = KHZ2PICOS(23750), | ||
473 | .hsync_len = 64, /* h_sync_width */ | ||
474 | .vsync_len = 4, /* v_sync_width */ | ||
475 | .left_margin = 80, /* h_back_porch */ | ||
476 | .upper_margin = 17, /* v_back_porch */ | ||
477 | .right_margin = 16, /* h_front_porch */ | ||
478 | .lower_margin = 3, /* v_front_porch */ | ||
479 | .vmode = FB_VMODE_NONINTERLACED, | ||
480 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
481 | }, | ||
482 | /* 640x480p 75hz */ | ||
483 | { | ||
484 | .refresh = 75, | ||
485 | .xres = 640, | ||
486 | .yres = 480, | ||
487 | .pixclock = KHZ2PICOS(30750), | ||
488 | .hsync_len = 64, /* h_sync_width */ | ||
489 | .vsync_len = 4, /* v_sync_width */ | ||
490 | .left_margin = 88, /* h_back_porch */ | ||
491 | .upper_margin = 21, /* v_back_porch */ | ||
492 | .right_margin = 24, /* h_front_porch */ | ||
493 | .lower_margin = 3, /* v_front_porch */ | ||
494 | .vmode = FB_VMODE_NONINTERLACED, | ||
495 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
496 | }, | ||
497 | /* 720x400p 59hz */ | ||
498 | { | ||
499 | .refresh = 59, | ||
500 | .xres = 720, | ||
501 | .yres = 400, | ||
502 | .pixclock = KHZ2PICOS(22000), | ||
503 | .hsync_len = 64, /* h_sync_width */ | ||
504 | .vsync_len = 10, /* v_sync_width */ | ||
505 | .left_margin = 88, /* h_back_porch */ | ||
506 | .upper_margin = 14, /* v_back_porch */ | ||
507 | .right_margin = 24, /* h_front_porch */ | ||
508 | .lower_margin = 3, /* v_front_porch */ | ||
509 | .vmode = FB_VMODE_NONINTERLACED, | ||
510 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
511 | }, | ||
512 | /* 800x600p 60hz */ | ||
513 | { | ||
514 | .refresh = 60, | ||
515 | .xres = 800, | ||
516 | .yres = 600, | ||
517 | .pixclock = KHZ2PICOS(38250), | ||
518 | .hsync_len = 80, /* h_sync_width */ | ||
519 | .vsync_len = 4, /* v_sync_width */ | ||
520 | .left_margin = 112, /* h_back_porch */ | ||
521 | .upper_margin = 21, /* v_back_porch */ | ||
522 | .right_margin = 32, /* h_front_porch */ | ||
523 | .lower_margin = 3, /* v_front_porch */ | ||
524 | .vmode = FB_VMODE_NONINTERLACED, | ||
525 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
526 | }, | ||
527 | /* 800x600p 75hz */ | ||
528 | { | ||
529 | .refresh = 75, | ||
530 | .xres = 800, | ||
531 | .yres = 600, | ||
532 | .pixclock = KHZ2PICOS(49000), | ||
533 | .hsync_len = 80, /* h_sync_width */ | ||
534 | .vsync_len = 4, /* v_sync_width */ | ||
535 | .left_margin = 120, /* h_back_porch */ | ||
536 | .upper_margin = 26, /* v_back_porch */ | ||
537 | .right_margin = 40, /* h_front_porch */ | ||
538 | .lower_margin = 3, /* v_front_porch */ | ||
539 | .vmode = FB_VMODE_NONINTERLACED, | ||
540 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
541 | }, | ||
542 | /* 1024x768p 60hz */ | ||
543 | { | ||
544 | .refresh = 60, | ||
545 | .xres = 1024, | ||
546 | .yres = 768, | ||
547 | .pixclock = KHZ2PICOS(63500), | ||
548 | .hsync_len = 104, /* h_sync_width */ | ||
549 | .vsync_len = 4, /* v_sync_width */ | ||
550 | .left_margin = 152, /* h_back_porch */ | ||
551 | .upper_margin = 27, /* v_back_porch */ | ||
552 | .right_margin = 48, /* h_front_porch */ | ||
553 | .lower_margin = 3, /* v_front_porch */ | ||
554 | .vmode = FB_VMODE_NONINTERLACED, | ||
555 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
556 | }, | ||
557 | /* 1024x768p 75hz */ | ||
558 | { | ||
559 | .refresh = 75, | ||
560 | .xres = 1024, | ||
561 | .yres = 768, | ||
562 | .pixclock = KHZ2PICOS(82000), | ||
563 | .hsync_len = 104, /* h_sync_width */ | ||
564 | .vsync_len = 4, /* v_sync_width */ | ||
565 | .left_margin = 168, /* h_back_porch */ | ||
566 | .upper_margin = 34, /* v_back_porch */ | ||
567 | .right_margin = 64, /* h_front_porch */ | ||
568 | .lower_margin = 3, /* v_front_porch */ | ||
569 | .vmode = FB_VMODE_NONINTERLACED, | ||
570 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
571 | }, | ||
572 | /* 1152x864p 75hz */ | ||
573 | { | ||
574 | .refresh = 75, | ||
575 | .xres = 1152, | ||
576 | .yres = 864, | ||
577 | .pixclock = KHZ2PICOS(104500), | ||
578 | .hsync_len = 120, /* h_sync_width */ | ||
579 | .vsync_len = 10, /* v_sync_width */ | ||
580 | .left_margin = 192, /* h_back_porch */ | ||
581 | .upper_margin = 38, /* v_back_porch */ | ||
582 | .right_margin = 72, /* h_front_porch */ | ||
583 | .lower_margin = 3, /* v_front_porch */ | ||
584 | .vmode = FB_VMODE_NONINTERLACED, | ||
585 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
586 | }, | ||
587 | /* 1280x800p 60hz */ | ||
588 | { | ||
589 | .refresh = 60, | ||
590 | .xres = 1280, | ||
591 | .yres = 800, | ||
592 | .pixclock = KHZ2PICOS(83500), | ||
593 | .hsync_len = 128, /* h_sync_width */ | ||
594 | .vsync_len = 6, /* v_sync_width */ | ||
595 | .left_margin = 200, /* h_back_porch */ | ||
596 | .upper_margin = 28, /* v_back_porch */ | ||
597 | .right_margin = 72, /* h_front_porch */ | ||
598 | .lower_margin = 3, /* v_front_porch */ | ||
599 | .vmode = FB_VMODE_NONINTERLACED, | ||
600 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
601 | }, | ||
602 | /* 1280x960p 60hz */ | ||
603 | { | ||
604 | .refresh = 60, | ||
605 | .xres = 1280, | ||
606 | .yres = 960, | ||
607 | .pixclock = KHZ2PICOS(101250), | ||
608 | .hsync_len = 128, /* h_sync_width */ | ||
609 | .vsync_len = 4, /* v_sync_width */ | ||
610 | .left_margin = 208, /* h_back_porch */ | ||
611 | .upper_margin = 33, /* v_back_porch */ | ||
612 | .right_margin = 80, /* h_front_porch */ | ||
613 | .lower_margin = 3, /* v_front_porch */ | ||
614 | .vmode = FB_VMODE_NONINTERLACED, | ||
615 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
616 | }, | ||
617 | /* 1280x1024p 60hz */ | ||
618 | { | ||
619 | .refresh = 60, | ||
620 | .xres = 1280, | ||
621 | .yres = 1024, | ||
622 | .pixclock = KHZ2PICOS(109000), | ||
623 | .hsync_len = 136, /* h_sync_width */ | ||
624 | .vsync_len = 7, /* v_sync_width */ | ||
625 | .left_margin = 216, /* h_back_porch */ | ||
626 | .upper_margin = 36, /* v_back_porch */ | ||
627 | .right_margin = 80, /* h_front_porch */ | ||
628 | .lower_margin = 3, /* v_front_porch */ | ||
629 | .vmode = FB_VMODE_NONINTERLACED, | ||
630 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
631 | }, | ||
632 | |||
633 | /* 1280x1024p 75hz */ | ||
634 | { | ||
635 | .refresh = 75, | ||
636 | .xres = 1280, | ||
637 | .yres = 1024, | ||
638 | .pixclock = KHZ2PICOS(138750), | ||
639 | .hsync_len = 136, /* h_sync_width */ | ||
640 | .vsync_len = 7, /* v_sync_width */ | ||
641 | .left_margin = 224, /* h_back_porch */ | ||
642 | .upper_margin = 45, /* v_back_porch */ | ||
643 | .right_margin = 88, /* h_front_porch */ | ||
644 | .lower_margin = 3, /* v_front_porch */ | ||
645 | .vmode = FB_VMODE_NONINTERLACED, | ||
646 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
647 | }, | ||
648 | /* 1368x768p 60hz */ | ||
649 | { | ||
650 | .refresh = 60, | ||
651 | .xres = 1368, | ||
652 | .yres = 768, | ||
653 | .pixclock = KHZ2PICOS(85250), | ||
654 | .hsync_len = 136, /* h_sync_width */ | ||
655 | .vsync_len = 10, /* v_sync_width */ | ||
656 | .left_margin = 208, /* h_back_porch */ | ||
657 | .upper_margin = 27, /* v_back_porch */ | ||
658 | .right_margin = 72, /* h_front_porch */ | ||
659 | .lower_margin = 3, /* v_front_porch */ | ||
660 | .vmode = FB_VMODE_NONINTERLACED, | ||
661 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
662 | }, | ||
663 | /* 1440x900p 60hz */ | ||
664 | { | ||
665 | .refresh = 60, | ||
666 | .xres = 1440, | ||
667 | .yres = 900, | ||
668 | .pixclock = KHZ2PICOS(106500), | ||
669 | .hsync_len = 152, /* h_sync_width */ | ||
670 | .vsync_len = 6, /* v_sync_width */ | ||
671 | .left_margin = 232, /* h_back_porch */ | ||
672 | .upper_margin = 31, /* v_back_porch */ | ||
673 | .right_margin = 80, /* h_front_porch */ | ||
674 | .lower_margin = 3, /* v_front_porch */ | ||
675 | .vmode = FB_VMODE_NONINTERLACED, | ||
676 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
677 | }, | ||
678 | /* 1600x1200p 60hz */ | ||
679 | { | ||
680 | .refresh = 60, | ||
681 | .xres = 1600, | ||
682 | .yres = 1200, | ||
683 | .pixclock = KHZ2PICOS(161000), | ||
684 | .hsync_len = 168, /* h_sync_width */ | ||
685 | .vsync_len = 4, /* v_sync_width */ | ||
686 | .left_margin = 280, /* h_back_porch */ | ||
687 | .upper_margin = 42, /* v_back_porch */ | ||
688 | .right_margin = 112, /* h_front_porch */ | ||
689 | .lower_margin = 3, /* v_front_porch */ | ||
690 | .vmode = FB_VMODE_NONINTERLACED, | ||
691 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
692 | }, | ||
693 | /* 1600x1200p 75hz */ | ||
694 | { | ||
695 | .refresh = 75, | ||
696 | .xres = 1600, | ||
697 | .yres = 1200, | ||
698 | .pixclock = KHZ2PICOS(204750), | ||
699 | .hsync_len = 168, /* h_sync_width */ | ||
700 | .vsync_len = 4, /* v_sync_width */ | ||
701 | .left_margin = 288, /* h_back_porch */ | ||
702 | .upper_margin = 52, /* v_back_porch */ | ||
703 | .right_margin = 120, /* h_front_porch */ | ||
704 | .lower_margin = 3, /* v_front_porch */ | ||
705 | .vmode = FB_VMODE_NONINTERLACED, | ||
706 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
707 | }, | ||
708 | /* 1680x1050p 59.94/60hz */ | ||
709 | { | ||
710 | .refresh = 60, | ||
711 | .xres = 1680, | ||
712 | .yres = 1050, | ||
713 | .pixclock = KHZ2PICOS(140000), | ||
714 | .hsync_len = 168, /* h_sync_width */ | ||
715 | .vsync_len = 10, /* v_sync_width */ | ||
716 | .left_margin = 272, /* h_back_porch */ | ||
717 | .upper_margin = 36, /* v_back_porch */ | ||
718 | .right_margin = 104, /* h_front_porch */ | ||
719 | .lower_margin = 3, /* v_front_porch */ | ||
720 | .vmode = FB_VMODE_NONINTERLACED, | ||
721 | .sync = FB_SYNC_VERT_HIGH_ACT, | ||
722 | }, | ||
723 | }; | ||
724 | |||
725 | /* table of electrical settings, must be in acending order. */ | ||
726 | struct tdms_config { | ||
727 | int pclk; | ||
728 | u32 pll0; | ||
729 | u32 pll1; | ||
730 | u32 pe_current; /* pre-emphasis */ | ||
731 | u32 drive_current; | ||
732 | }; | ||
733 | |||
734 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
735 | const struct tdms_config tdms_config[] = { | ||
736 | { /* 480p modes */ | ||
737 | .pclk = 27000000, | ||
738 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | | ||
739 | SOR_PLL_VCOCAP(0) | SOR_PLL_TX_REG_LOAD(0), | ||
740 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE, | ||
741 | .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) | | ||
742 | PE_CURRENT1(PE_CURRENT_0_0_mA) | | ||
743 | PE_CURRENT2(PE_CURRENT_0_0_mA) | | ||
744 | PE_CURRENT3(PE_CURRENT_0_0_mA), | ||
745 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
746 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
747 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
748 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
749 | }, | ||
750 | { /* 720p modes */ | ||
751 | .pclk = 74250000, | ||
752 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | | ||
753 | SOR_PLL_VCOCAP(1) | SOR_PLL_TX_REG_LOAD(0), | ||
754 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
755 | .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) | | ||
756 | PE_CURRENT1(PE_CURRENT_5_0_mA) | | ||
757 | PE_CURRENT2(PE_CURRENT_5_0_mA) | | ||
758 | PE_CURRENT3(PE_CURRENT_5_0_mA), | ||
759 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
760 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
761 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
762 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
763 | }, | ||
764 | { /* 1080p modes */ | ||
765 | .pclk = INT_MAX, | ||
766 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | | ||
767 | SOR_PLL_VCOCAP(3) | SOR_PLL_TX_REG_LOAD(0), | ||
768 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
769 | .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) | | ||
770 | PE_CURRENT1(PE_CURRENT_5_0_mA) | | ||
771 | PE_CURRENT2(PE_CURRENT_5_0_mA) | | ||
772 | PE_CURRENT3(PE_CURRENT_5_0_mA), | ||
773 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
774 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
775 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
776 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
777 | }, | ||
778 | }; | ||
779 | #else /* CONFIG_ARCH_TEGRA_2x_SOC */ | ||
780 | const struct tdms_config tdms_config[] = { | ||
781 | { /* 480p modes */ | ||
782 | .pclk = 27000000, | ||
783 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | | ||
784 | SOR_PLL_VCOCAP(0) | SOR_PLL_TX_REG_LOAD(3), | ||
785 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE, | ||
786 | .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) | | ||
787 | PE_CURRENT1(PE_CURRENT_0_0_mA) | | ||
788 | PE_CURRENT2(PE_CURRENT_0_0_mA) | | ||
789 | PE_CURRENT3(PE_CURRENT_0_0_mA), | ||
790 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
791 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
792 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
793 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
794 | }, | ||
795 | { /* 720p modes */ | ||
796 | .pclk = 74250000, | ||
797 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | | ||
798 | SOR_PLL_VCOCAP(1) | SOR_PLL_TX_REG_LOAD(3), | ||
799 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
800 | .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) | | ||
801 | PE_CURRENT1(PE_CURRENT_6_0_mA) | | ||
802 | PE_CURRENT2(PE_CURRENT_6_0_mA) | | ||
803 | PE_CURRENT3(PE_CURRENT_6_0_mA), | ||
804 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
805 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
806 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
807 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
808 | }, | ||
809 | { /* 1080p modes */ | ||
810 | .pclk = INT_MAX, | ||
811 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL | | ||
812 | SOR_PLL_VCOCAP(1) | SOR_PLL_TX_REG_LOAD(3), | ||
813 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
814 | .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) | | ||
815 | PE_CURRENT1(PE_CURRENT_6_0_mA) | | ||
816 | PE_CURRENT2(PE_CURRENT_6_0_mA) | | ||
817 | PE_CURRENT3(PE_CURRENT_6_0_mA), | ||
818 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
819 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
820 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
821 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
822 | }, | ||
823 | }; | ||
824 | #endif | ||
825 | |||
826 | struct tegra_hdmi_audio_config { | ||
827 | unsigned pix_clock; | ||
828 | unsigned n; | ||
829 | unsigned cts; | ||
830 | unsigned aval; | ||
831 | }; | ||
832 | |||
833 | |||
834 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = { | ||
835 | {25200000, 4096, 25200, 24000}, | ||
836 | {27000000, 4096, 27000, 24000}, | ||
837 | {74250000, 4096, 74250, 24000}, | ||
838 | {148500000, 4096, 148500, 24000}, | ||
839 | {0, 0, 0}, | ||
840 | }; | ||
841 | |||
842 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = { | ||
843 | {25200000, 5880, 26250, 25000}, | ||
844 | {27000000, 5880, 28125, 25000}, | ||
845 | {74250000, 4704, 61875, 20000}, | ||
846 | {148500000, 4704, 123750, 20000}, | ||
847 | {0, 0, 0}, | ||
848 | }; | ||
849 | |||
850 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = { | ||
851 | {25200000, 6144, 25200, 24000}, | ||
852 | {27000000, 6144, 27000, 24000}, | ||
853 | {74250000, 6144, 74250, 24000}, | ||
854 | {148500000, 6144, 148500, 24000}, | ||
855 | {0, 0, 0}, | ||
856 | }; | ||
857 | |||
858 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = { | ||
859 | {25200000, 11760, 26250, 25000}, | ||
860 | {27000000, 11760, 28125, 25000}, | ||
861 | {74250000, 9408, 61875, 20000}, | ||
862 | {148500000, 9408, 123750, 20000}, | ||
863 | {0, 0, 0}, | ||
864 | }; | ||
865 | |||
866 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = { | ||
867 | {25200000, 12288, 25200, 24000}, | ||
868 | {27000000, 12288, 27000, 24000}, | ||
869 | {74250000, 12288, 74250, 24000}, | ||
870 | {148500000, 12288, 148500, 24000}, | ||
871 | {0, 0, 0}, | ||
872 | }; | ||
873 | |||
874 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = { | ||
875 | {25200000, 23520, 26250, 25000}, | ||
876 | {27000000, 23520, 28125, 25000}, | ||
877 | {74250000, 18816, 61875, 20000}, | ||
878 | {148500000, 18816, 123750, 20000}, | ||
879 | {0, 0, 0}, | ||
880 | }; | ||
881 | |||
882 | const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = { | ||
883 | {25200000, 24576, 25200, 24000}, | ||
884 | {27000000, 24576, 27000, 24000}, | ||
885 | {74250000, 24576, 74250, 24000}, | ||
886 | {148500000, 24576, 148500, 24000}, | ||
887 | {0, 0, 0}, | ||
888 | }; | ||
889 | |||
890 | static const struct tegra_hdmi_audio_config | ||
891 | *tegra_hdmi_get_audio_config(unsigned audio_freq, unsigned pix_clock) | ||
892 | { | ||
893 | const struct tegra_hdmi_audio_config *table; | ||
894 | |||
895 | switch (audio_freq) { | ||
896 | case AUDIO_FREQ_32K: | ||
897 | table = tegra_hdmi_audio_32k; | ||
898 | break; | ||
899 | case AUDIO_FREQ_44_1K: | ||
900 | table = tegra_hdmi_audio_44_1k; | ||
901 | break; | ||
902 | case AUDIO_FREQ_48K: | ||
903 | table = tegra_hdmi_audio_48k; | ||
904 | break; | ||
905 | case AUDIO_FREQ_88_2K: | ||
906 | table = tegra_hdmi_audio_88_2k; | ||
907 | break; | ||
908 | case AUDIO_FREQ_96K: | ||
909 | table = tegra_hdmi_audio_96k; | ||
910 | break; | ||
911 | case AUDIO_FREQ_176_4K: | ||
912 | table = tegra_hdmi_audio_176_4k; | ||
913 | break; | ||
914 | case AUDIO_FREQ_192K: | ||
915 | table = tegra_hdmi_audio_192k; | ||
916 | break; | ||
917 | default: | ||
918 | return NULL; | ||
919 | } | ||
920 | |||
921 | while (table->pix_clock) { | ||
922 | if (table->pix_clock == pix_clock) | ||
923 | return table; | ||
924 | table++; | ||
925 | } | ||
926 | |||
927 | return NULL; | ||
928 | } | ||
929 | |||
930 | |||
931 | unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi, | ||
932 | unsigned long reg) | ||
933 | { | ||
934 | return readl(hdmi->base + reg * 4); | ||
935 | } | ||
936 | |||
937 | void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi, | ||
938 | unsigned long val, unsigned long reg) | ||
939 | { | ||
940 | writel(val, hdmi->base + reg * 4); | ||
941 | } | ||
942 | |||
943 | static inline void tegra_hdmi_clrsetbits(struct tegra_dc_hdmi_data *hdmi, | ||
944 | unsigned long reg, unsigned long clr, | ||
945 | unsigned long set) | ||
946 | { | ||
947 | unsigned long val = tegra_hdmi_readl(hdmi, reg); | ||
948 | val &= ~clr; | ||
949 | val |= set; | ||
950 | tegra_hdmi_writel(hdmi, val, reg); | ||
951 | } | ||
952 | |||
953 | #ifdef CONFIG_DEBUG_FS | ||
954 | static int dbg_hdmi_show(struct seq_file *s, void *unused) | ||
955 | { | ||
956 | struct tegra_dc_hdmi_data *hdmi = s->private; | ||
957 | |||
958 | #define DUMP_REG(a) do { \ | ||
959 | seq_printf(s, "%-32s\t%03x\t%08lx\n", \ | ||
960 | #a, a, tegra_hdmi_readl(hdmi, a)); \ | ||
961 | } while (0) | ||
962 | |||
963 | tegra_dc_io_start(hdmi->dc); | ||
964 | clk_enable(hdmi->clk); | ||
965 | |||
966 | DUMP_REG(HDMI_CTXSW); | ||
967 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE0); | ||
968 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE1); | ||
969 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE2); | ||
970 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_MSB); | ||
971 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_LSB); | ||
972 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_MSB); | ||
973 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_LSB); | ||
974 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_MSB); | ||
975 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_LSB); | ||
976 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_MSB); | ||
977 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_LSB); | ||
978 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_MSB); | ||
979 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_LSB); | ||
980 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_MSB); | ||
981 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_LSB); | ||
982 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
983 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CMODE); | ||
984 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB); | ||
985 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB); | ||
986 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB); | ||
987 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2); | ||
988 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1); | ||
989 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_RI); | ||
990 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_MSB); | ||
991 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_LSB); | ||
992 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU0); | ||
993 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0); | ||
994 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU1); | ||
995 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU2); | ||
996 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
997 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS); | ||
998 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER); | ||
999 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW); | ||
1000 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH); | ||
1001 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
1002 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS); | ||
1003 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER); | ||
1004 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW); | ||
1005 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH); | ||
1006 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW); | ||
1007 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH); | ||
1008 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
1009 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_STATUS); | ||
1010 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_HEADER); | ||
1011 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW); | ||
1012 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH); | ||
1013 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW); | ||
1014 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH); | ||
1015 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW); | ||
1016 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH); | ||
1017 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW); | ||
1018 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH); | ||
1019 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_CTRL); | ||
1020 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW); | ||
1021 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH); | ||
1022 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | ||
1023 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | ||
1024 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW); | ||
1025 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH); | ||
1026 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW); | ||
1027 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH); | ||
1028 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW); | ||
1029 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH); | ||
1030 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW); | ||
1031 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH); | ||
1032 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW); | ||
1033 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH); | ||
1034 | DUMP_REG(HDMI_NV_PDISP_HDMI_CTRL); | ||
1035 | DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT); | ||
1036 | DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); | ||
1037 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_CTRL); | ||
1038 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_STATUS); | ||
1039 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_SUBPACK); | ||
1040 | DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1); | ||
1041 | DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2); | ||
1042 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU0); | ||
1043 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1); | ||
1044 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1_RDATA); | ||
1045 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPARE); | ||
1046 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1); | ||
1047 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2); | ||
1048 | DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_CTRL); | ||
1049 | DUMP_REG(HDMI_NV_PDISP_SOR_CAP); | ||
1050 | DUMP_REG(HDMI_NV_PDISP_SOR_PWR); | ||
1051 | DUMP_REG(HDMI_NV_PDISP_SOR_TEST); | ||
1052 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL0); | ||
1053 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL1); | ||
1054 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL2); | ||
1055 | DUMP_REG(HDMI_NV_PDISP_SOR_CSTM); | ||
1056 | DUMP_REG(HDMI_NV_PDISP_SOR_LVDS); | ||
1057 | DUMP_REG(HDMI_NV_PDISP_SOR_CRCA); | ||
1058 | DUMP_REG(HDMI_NV_PDISP_SOR_CRCB); | ||
1059 | DUMP_REG(HDMI_NV_PDISP_SOR_BLANK); | ||
1060 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_CTL); | ||
1061 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST0); | ||
1062 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST1); | ||
1063 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST2); | ||
1064 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST3); | ||
1065 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST4); | ||
1066 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST5); | ||
1067 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST6); | ||
1068 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST7); | ||
1069 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST8); | ||
1070 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST9); | ||
1071 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTA); | ||
1072 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTB); | ||
1073 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTC); | ||
1074 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTD); | ||
1075 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTE); | ||
1076 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTF); | ||
1077 | DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA0); | ||
1078 | DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA1); | ||
1079 | DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA0); | ||
1080 | DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA1); | ||
1081 | DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA0); | ||
1082 | DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA1); | ||
1083 | DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA0); | ||
1084 | DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA1); | ||
1085 | DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA0); | ||
1086 | DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA1); | ||
1087 | DUMP_REG(HDMI_NV_PDISP_SOR_TRIG); | ||
1088 | DUMP_REG(HDMI_NV_PDISP_SOR_MSCHECK); | ||
1089 | DUMP_REG(HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); | ||
1090 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG0); | ||
1091 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG1); | ||
1092 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG2); | ||
1093 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(0)); | ||
1094 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(1)); | ||
1095 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(2)); | ||
1096 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(3)); | ||
1097 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(4)); | ||
1098 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(5)); | ||
1099 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(6)); | ||
1100 | DUMP_REG(HDMI_NV_PDISP_AUDIO_PULSE_WIDTH); | ||
1101 | DUMP_REG(HDMI_NV_PDISP_AUDIO_THRESHOLD); | ||
1102 | DUMP_REG(HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
1103 | DUMP_REG(HDMI_NV_PDISP_AUDIO_N); | ||
1104 | DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_TIMING); | ||
1105 | DUMP_REG(HDMI_NV_PDISP_SOR_REFCLK); | ||
1106 | DUMP_REG(HDMI_NV_PDISP_CRC_CONTROL); | ||
1107 | DUMP_REG(HDMI_NV_PDISP_INPUT_CONTROL); | ||
1108 | DUMP_REG(HDMI_NV_PDISP_SCRATCH); | ||
1109 | DUMP_REG(HDMI_NV_PDISP_PE_CURRENT); | ||
1110 | DUMP_REG(HDMI_NV_PDISP_KEY_CTRL); | ||
1111 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG0); | ||
1112 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG1); | ||
1113 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG2); | ||
1114 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_0); | ||
1115 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_1); | ||
1116 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_2); | ||
1117 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_3); | ||
1118 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); | ||
1119 | DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX); | ||
1120 | #undef DUMP_REG | ||
1121 | |||
1122 | clk_disable(hdmi->clk); | ||
1123 | tegra_dc_io_end(hdmi->dc); | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | static int dbg_hdmi_open(struct inode *inode, struct file *file) | ||
1129 | { | ||
1130 | return single_open(file, dbg_hdmi_show, inode->i_private); | ||
1131 | } | ||
1132 | |||
1133 | static const struct file_operations dbg_fops = { | ||
1134 | .open = dbg_hdmi_open, | ||
1135 | .read = seq_read, | ||
1136 | .llseek = seq_lseek, | ||
1137 | .release = single_release, | ||
1138 | }; | ||
1139 | |||
1140 | static struct dentry *hdmidir; | ||
1141 | |||
1142 | static void tegra_dc_hdmi_debug_create(struct tegra_dc_hdmi_data *hdmi) | ||
1143 | { | ||
1144 | struct dentry *retval; | ||
1145 | |||
1146 | hdmidir = debugfs_create_dir("tegra_hdmi", NULL); | ||
1147 | if (!hdmidir) | ||
1148 | return; | ||
1149 | retval = debugfs_create_file("regs", S_IRUGO, hdmidir, hdmi, | ||
1150 | &dbg_fops); | ||
1151 | if (!retval) | ||
1152 | goto free_out; | ||
1153 | return; | ||
1154 | free_out: | ||
1155 | debugfs_remove_recursive(hdmidir); | ||
1156 | hdmidir = NULL; | ||
1157 | return; | ||
1158 | } | ||
1159 | #else | ||
1160 | static inline void tegra_dc_hdmi_debug_create(struct tegra_dc_hdmi_data *hdmi) | ||
1161 | { } | ||
1162 | #endif | ||
1163 | |||
1164 | #define PIXCLOCK_TOLERANCE 200 | ||
1165 | |||
1166 | static int tegra_dc_calc_clock_per_frame(const struct fb_videomode *mode) | ||
1167 | { | ||
1168 | return (mode->left_margin + mode->xres + | ||
1169 | mode->right_margin + mode->hsync_len) * | ||
1170 | (mode->upper_margin + mode->yres + | ||
1171 | mode->lower_margin + mode->vsync_len); | ||
1172 | } | ||
1173 | static bool tegra_dc_hdmi_mode_equal(const struct fb_videomode *mode1, | ||
1174 | const struct fb_videomode *mode2) | ||
1175 | { | ||
1176 | int clock_per_frame1 = tegra_dc_calc_clock_per_frame(mode1); | ||
1177 | int clock_per_frame2 = tegra_dc_calc_clock_per_frame(mode2); | ||
1178 | |||
1179 | /* allows up to 1Hz of pixclock difference */ | ||
1180 | return (clock_per_frame1 == clock_per_frame2 && | ||
1181 | mode1->xres == mode2->xres && | ||
1182 | mode1->yres == mode2->yres && | ||
1183 | mode1->vmode == mode2->vmode && | ||
1184 | (mode1->pixclock == mode2->pixclock || | ||
1185 | (abs(PICOS2KHZ(mode1->pixclock) - | ||
1186 | PICOS2KHZ(mode2->pixclock)) * | ||
1187 | 1000 / clock_per_frame1 <= 1))); | ||
1188 | } | ||
1189 | |||
1190 | static bool tegra_dc_hdmi_valid_pixclock(const struct tegra_dc *dc, | ||
1191 | const struct fb_videomode *mode) | ||
1192 | { | ||
1193 | unsigned max_pixclock = tegra_dc_get_out_max_pixclock(dc); | ||
1194 | if (max_pixclock) { | ||
1195 | /* this might look counter-intuitive, | ||
1196 | * but pixclock's unit is picos(not Khz) | ||
1197 | */ | ||
1198 | return mode->pixclock >= max_pixclock; | ||
1199 | } else { | ||
1200 | return true; | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | static bool tegra_dc_cvt_mode_equal(const struct fb_videomode *mode1, | ||
1205 | const struct fb_videomode *mode2) | ||
1206 | { | ||
1207 | return (mode1->xres == mode2->xres && | ||
1208 | mode1->yres == mode2->yres && | ||
1209 | mode1->refresh == mode2->refresh && | ||
1210 | mode1->vmode == mode2->vmode); | ||
1211 | } | ||
1212 | |||
1213 | static bool tegra_dc_reload_mode(struct fb_videomode *mode) | ||
1214 | { | ||
1215 | int i = 0; | ||
1216 | for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_cvt_modes); i++) { | ||
1217 | const struct fb_videomode *cvt_mode | ||
1218 | = &tegra_dc_hdmi_supported_cvt_modes[i]; | ||
1219 | if (tegra_dc_cvt_mode_equal(cvt_mode, mode)) { | ||
1220 | memcpy(mode, cvt_mode, sizeof(*mode)); | ||
1221 | return true; | ||
1222 | } | ||
1223 | } | ||
1224 | return false; | ||
1225 | } | ||
1226 | |||
1227 | |||
1228 | static bool tegra_dc_hdmi_mode_filter(const struct tegra_dc *dc, | ||
1229 | struct fb_videomode *mode) | ||
1230 | { | ||
1231 | int i; | ||
1232 | int clock_per_frame; | ||
1233 | |||
1234 | if (!mode->pixclock) | ||
1235 | return false; | ||
1236 | |||
1237 | #ifdef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
1238 | if (PICOS2KHZ(mode->pixclock) > 74250) | ||
1239 | return false; | ||
1240 | #endif | ||
1241 | |||
1242 | for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_modes); i++) { | ||
1243 | const struct fb_videomode *supported_mode | ||
1244 | = &tegra_dc_hdmi_supported_modes[i]; | ||
1245 | if (tegra_dc_hdmi_mode_equal(supported_mode, mode) && | ||
1246 | tegra_dc_hdmi_valid_pixclock(dc, supported_mode)) { | ||
1247 | if (mode->lower_margin == 1) { | ||
1248 | /* This might be the case for HDMI<->DVI | ||
1249 | * where std VESA representation will not | ||
1250 | * pass constraint V_FRONT_PORCH >= | ||
1251 | * V_REF_TO_SYNC + 1.So reload mode in | ||
1252 | * CVT timing standards. | ||
1253 | */ | ||
1254 | if (!tegra_dc_reload_mode(mode)) | ||
1255 | return false; | ||
1256 | } | ||
1257 | else | ||
1258 | memcpy(mode, supported_mode, sizeof(*mode)); | ||
1259 | |||
1260 | mode->flag = FB_MODE_IS_DETAILED; | ||
1261 | clock_per_frame = tegra_dc_calc_clock_per_frame(mode); | ||
1262 | mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000) | ||
1263 | / clock_per_frame; | ||
1264 | return true; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | return false; | ||
1269 | } | ||
1270 | |||
1271 | |||
1272 | static bool tegra_dc_hdmi_hpd(struct tegra_dc *dc) | ||
1273 | { | ||
1274 | int sense; | ||
1275 | int level; | ||
1276 | |||
1277 | level = gpio_get_value(dc->out->hotplug_gpio); | ||
1278 | |||
1279 | sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK; | ||
1280 | |||
1281 | return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) || | ||
1282 | (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level); | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | void tegra_dc_hdmi_detect_config(struct tegra_dc *dc, | ||
1287 | struct fb_monspecs *specs) | ||
1288 | { | ||
1289 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1290 | |||
1291 | /* monitors like to lie about these but they are still useful for | ||
1292 | * detecting aspect ratios | ||
1293 | */ | ||
1294 | dc->out->h_size = specs->max_x * 1000; | ||
1295 | dc->out->v_size = specs->max_y * 1000; | ||
1296 | |||
1297 | hdmi->dvi = !(specs->misc & FB_MISC_HDMI); | ||
1298 | |||
1299 | tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter); | ||
1300 | #ifdef CONFIG_SWITCH | ||
1301 | hdmi->hpd_switch.state = 0; | ||
1302 | switch_set_state(&hdmi->hpd_switch, 1); | ||
1303 | #endif | ||
1304 | dev_info(&dc->ndev->dev, "display detected\n"); | ||
1305 | |||
1306 | dc->connected = true; | ||
1307 | tegra_dc_ext_process_hotplug(dc->ndev->id); | ||
1308 | } | ||
1309 | |||
1310 | /* This function is used to enable DC1 and HDMI for the purpose of testing. */ | ||
1311 | bool tegra_dc_hdmi_detect_test(struct tegra_dc *dc, unsigned char *edid_ptr) | ||
1312 | { | ||
1313 | int err; | ||
1314 | struct fb_monspecs specs; | ||
1315 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1316 | |||
1317 | if (!hdmi || !edid_ptr) { | ||
1318 | dev_err(&dc->ndev->dev, "HDMI test failed to get arguments.\n"); | ||
1319 | return false; | ||
1320 | } | ||
1321 | |||
1322 | err = tegra_edid_get_monspecs_test(hdmi->edid, &specs, edid_ptr); | ||
1323 | if (err < 0) { | ||
1324 | dev_err(&dc->ndev->dev, "error reading edid\n"); | ||
1325 | goto fail; | ||
1326 | } | ||
1327 | |||
1328 | err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld); | ||
1329 | if (err < 0) { | ||
1330 | dev_err(&dc->ndev->dev, "error populating eld\n"); | ||
1331 | goto fail; | ||
1332 | } | ||
1333 | hdmi->eld_retrieved = true; | ||
1334 | |||
1335 | tegra_dc_hdmi_detect_config(dc, &specs); | ||
1336 | |||
1337 | return true; | ||
1338 | |||
1339 | fail: | ||
1340 | hdmi->eld_retrieved = false; | ||
1341 | #ifdef CONFIG_SWITCH | ||
1342 | switch_set_state(&hdmi->hpd_switch, 0); | ||
1343 | #endif | ||
1344 | tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0); | ||
1345 | return false; | ||
1346 | } | ||
1347 | EXPORT_SYMBOL(tegra_dc_hdmi_detect_test); | ||
1348 | |||
1349 | static bool tegra_dc_hdmi_detect(struct tegra_dc *dc) | ||
1350 | { | ||
1351 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1352 | struct fb_monspecs specs; | ||
1353 | int err; | ||
1354 | |||
1355 | if (!tegra_dc_hdmi_hpd(dc)) | ||
1356 | goto fail; | ||
1357 | |||
1358 | err = tegra_edid_get_monspecs(hdmi->edid, &specs); | ||
1359 | if (err < 0) { | ||
1360 | dev_err(&dc->ndev->dev, "error reading edid\n"); | ||
1361 | goto fail; | ||
1362 | } | ||
1363 | |||
1364 | err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld); | ||
1365 | if (err < 0) { | ||
1366 | dev_err(&dc->ndev->dev, "error populating eld\n"); | ||
1367 | goto fail; | ||
1368 | } | ||
1369 | hdmi->eld_retrieved = true; | ||
1370 | |||
1371 | tegra_dc_hdmi_detect_config(dc, &specs); | ||
1372 | |||
1373 | return true; | ||
1374 | |||
1375 | fail: | ||
1376 | hdmi->eld_retrieved = false; | ||
1377 | #ifdef CONFIG_SWITCH | ||
1378 | switch_set_state(&hdmi->hpd_switch, 0); | ||
1379 | #endif | ||
1380 | tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0); | ||
1381 | return false; | ||
1382 | } | ||
1383 | |||
1384 | |||
1385 | static void tegra_dc_hdmi_detect_worker(struct work_struct *work) | ||
1386 | { | ||
1387 | struct tegra_dc_hdmi_data *hdmi = | ||
1388 | container_of(to_delayed_work(work), struct tegra_dc_hdmi_data, work); | ||
1389 | struct tegra_dc *dc = hdmi->dc; | ||
1390 | |||
1391 | tegra_dc_enable(dc); | ||
1392 | msleep(5); | ||
1393 | if (!tegra_dc_hdmi_detect(dc)) { | ||
1394 | tegra_dc_disable(dc); | ||
1395 | tegra_fb_update_monspecs(dc->fb, NULL, NULL); | ||
1396 | |||
1397 | dc->connected = false; | ||
1398 | tegra_dc_ext_process_hotplug(dc->ndev->id); | ||
1399 | } | ||
1400 | } | ||
1401 | |||
1402 | static irqreturn_t tegra_dc_hdmi_irq(int irq, void *ptr) | ||
1403 | { | ||
1404 | struct tegra_dc *dc = ptr; | ||
1405 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1406 | unsigned long flags; | ||
1407 | |||
1408 | spin_lock_irqsave(&hdmi->suspend_lock, flags); | ||
1409 | if (!hdmi->suspended) { | ||
1410 | __cancel_delayed_work(&hdmi->work); | ||
1411 | if (tegra_dc_hdmi_hpd(dc)) | ||
1412 | queue_delayed_work(system_nrt_wq, &hdmi->work, | ||
1413 | msecs_to_jiffies(100)); | ||
1414 | else | ||
1415 | queue_delayed_work(system_nrt_wq, &hdmi->work, | ||
1416 | msecs_to_jiffies(30)); | ||
1417 | } | ||
1418 | spin_unlock_irqrestore(&hdmi->suspend_lock, flags); | ||
1419 | |||
1420 | return IRQ_HANDLED; | ||
1421 | } | ||
1422 | |||
1423 | static void tegra_dc_hdmi_suspend(struct tegra_dc *dc) | ||
1424 | { | ||
1425 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1426 | unsigned long flags; | ||
1427 | |||
1428 | tegra_nvhdcp_suspend(hdmi->nvhdcp); | ||
1429 | spin_lock_irqsave(&hdmi->suspend_lock, flags); | ||
1430 | hdmi->suspended = true; | ||
1431 | spin_unlock_irqrestore(&hdmi->suspend_lock, flags); | ||
1432 | } | ||
1433 | |||
1434 | static void tegra_dc_hdmi_resume(struct tegra_dc *dc) | ||
1435 | { | ||
1436 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1437 | unsigned long flags; | ||
1438 | |||
1439 | spin_lock_irqsave(&hdmi->suspend_lock, flags); | ||
1440 | hdmi->suspended = false; | ||
1441 | |||
1442 | if (tegra_dc_hdmi_hpd(dc)) | ||
1443 | queue_delayed_work(system_nrt_wq, &hdmi->work, | ||
1444 | msecs_to_jiffies(100)); | ||
1445 | else | ||
1446 | queue_delayed_work(system_nrt_wq, &hdmi->work, | ||
1447 | msecs_to_jiffies(30)); | ||
1448 | |||
1449 | spin_unlock_irqrestore(&hdmi->suspend_lock, flags); | ||
1450 | tegra_nvhdcp_resume(hdmi->nvhdcp); | ||
1451 | } | ||
1452 | |||
1453 | static ssize_t underscan_show(struct device *dev, | ||
1454 | struct device_attribute *attr, char *buf) | ||
1455 | { | ||
1456 | #ifdef CONFIG_SWITCH | ||
1457 | struct tegra_dc_hdmi_data *hdmi = | ||
1458 | container_of(dev_get_drvdata(dev), struct tegra_dc_hdmi_data, hpd_switch); | ||
1459 | |||
1460 | if (hdmi->edid) | ||
1461 | return sprintf(buf, "%d\n", tegra_edid_underscan_supported(hdmi->edid)); | ||
1462 | else | ||
1463 | return 0; | ||
1464 | #else | ||
1465 | return 0; | ||
1466 | #endif | ||
1467 | } | ||
1468 | |||
1469 | static DEVICE_ATTR(underscan, S_IRUGO | S_IWUSR, underscan_show, NULL); | ||
1470 | |||
1471 | static int tegra_dc_hdmi_init(struct tegra_dc *dc) | ||
1472 | { | ||
1473 | struct tegra_dc_hdmi_data *hdmi; | ||
1474 | struct resource *res; | ||
1475 | struct resource *base_res; | ||
1476 | int ret; | ||
1477 | void __iomem *base; | ||
1478 | struct clk *clk = NULL; | ||
1479 | struct clk *disp1_clk = NULL; | ||
1480 | struct clk *disp2_clk = NULL; | ||
1481 | int err; | ||
1482 | |||
1483 | hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); | ||
1484 | if (!hdmi) | ||
1485 | return -ENOMEM; | ||
1486 | |||
1487 | res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, "hdmi_regs"); | ||
1488 | if (!res) { | ||
1489 | dev_err(&dc->ndev->dev, "hdmi: no mem resource\n"); | ||
1490 | err = -ENOENT; | ||
1491 | goto err_free_hdmi; | ||
1492 | } | ||
1493 | |||
1494 | base_res = request_mem_region(res->start, resource_size(res), dc->ndev->name); | ||
1495 | if (!base_res) { | ||
1496 | dev_err(&dc->ndev->dev, "hdmi: request_mem_region failed\n"); | ||
1497 | err = -EBUSY; | ||
1498 | goto err_free_hdmi; | ||
1499 | } | ||
1500 | |||
1501 | base = ioremap(res->start, resource_size(res)); | ||
1502 | if (!base) { | ||
1503 | dev_err(&dc->ndev->dev, "hdmi: registers can't be mapped\n"); | ||
1504 | err = -EBUSY; | ||
1505 | goto err_release_resource_reg; | ||
1506 | } | ||
1507 | |||
1508 | clk = clk_get(&dc->ndev->dev, "hdmi"); | ||
1509 | if (IS_ERR_OR_NULL(clk)) { | ||
1510 | dev_err(&dc->ndev->dev, "hdmi: can't get clock\n"); | ||
1511 | err = -ENOENT; | ||
1512 | goto err_iounmap_reg; | ||
1513 | } | ||
1514 | |||
1515 | disp1_clk = clk_get_sys("tegradc.0", NULL); | ||
1516 | if (IS_ERR_OR_NULL(disp1_clk)) { | ||
1517 | dev_err(&dc->ndev->dev, "hdmi: can't disp1 clock\n"); | ||
1518 | err = -ENOENT; | ||
1519 | goto err_put_clock; | ||
1520 | } | ||
1521 | |||
1522 | disp2_clk = clk_get_sys("tegradc.1", NULL); | ||
1523 | if (IS_ERR_OR_NULL(disp2_clk)) { | ||
1524 | dev_err(&dc->ndev->dev, "hdmi: can't disp2 clock\n"); | ||
1525 | err = -ENOENT; | ||
1526 | goto err_put_clock; | ||
1527 | } | ||
1528 | |||
1529 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1530 | hdmi->hda_clk = clk_get_sys("tegra30-hda", "hda"); | ||
1531 | if (IS_ERR_OR_NULL(hdmi->hda_clk)) { | ||
1532 | dev_err(&dc->ndev->dev, "hdmi: can't get hda clock\n"); | ||
1533 | err = -ENOENT; | ||
1534 | goto err_put_clock; | ||
1535 | } | ||
1536 | |||
1537 | hdmi->hda2codec_clk = clk_get_sys("tegra30-hda", "hda2codec"); | ||
1538 | if (IS_ERR_OR_NULL(hdmi->hda2codec_clk)) { | ||
1539 | dev_err(&dc->ndev->dev, "hdmi: can't get hda2codec clock\n"); | ||
1540 | err = -ENOENT; | ||
1541 | goto err_put_clock; | ||
1542 | } | ||
1543 | |||
1544 | hdmi->hda2hdmi_clk = clk_get_sys("tegra30-hda", "hda2hdmi"); | ||
1545 | if (IS_ERR_OR_NULL(hdmi->hda2hdmi_clk)) { | ||
1546 | dev_err(&dc->ndev->dev, "hdmi: can't get hda2hdmi clock\n"); | ||
1547 | err = -ENOENT; | ||
1548 | goto err_put_clock; | ||
1549 | } | ||
1550 | #endif | ||
1551 | |||
1552 | /* TODO: support non-hotplug */ | ||
1553 | if (request_irq(gpio_to_irq(dc->out->hotplug_gpio), tegra_dc_hdmi_irq, | ||
1554 | IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
1555 | dev_name(&dc->ndev->dev), dc)) { | ||
1556 | dev_err(&dc->ndev->dev, "hdmi: request_irq %d failed\n", | ||
1557 | gpio_to_irq(dc->out->hotplug_gpio)); | ||
1558 | err = -EBUSY; | ||
1559 | goto err_put_clock; | ||
1560 | } | ||
1561 | |||
1562 | hdmi->edid = tegra_edid_create(dc->out->dcc_bus); | ||
1563 | if (IS_ERR_OR_NULL(hdmi->edid)) { | ||
1564 | dev_err(&dc->ndev->dev, "hdmi: can't create edid\n"); | ||
1565 | err = PTR_ERR(hdmi->edid); | ||
1566 | goto err_free_irq; | ||
1567 | } | ||
1568 | |||
1569 | #ifdef CONFIG_TEGRA_NVHDCP | ||
1570 | hdmi->nvhdcp = tegra_nvhdcp_create(hdmi, dc->ndev->id, | ||
1571 | dc->out->dcc_bus); | ||
1572 | if (IS_ERR_OR_NULL(hdmi->nvhdcp)) { | ||
1573 | dev_err(&dc->ndev->dev, "hdmi: can't create nvhdcp\n"); | ||
1574 | err = PTR_ERR(hdmi->nvhdcp); | ||
1575 | goto err_edid_destroy; | ||
1576 | } | ||
1577 | #else | ||
1578 | hdmi->nvhdcp = NULL; | ||
1579 | #endif | ||
1580 | |||
1581 | INIT_DELAYED_WORK(&hdmi->work, tegra_dc_hdmi_detect_worker); | ||
1582 | |||
1583 | hdmi->dc = dc; | ||
1584 | hdmi->base = base; | ||
1585 | hdmi->base_res = base_res; | ||
1586 | hdmi->clk = clk; | ||
1587 | hdmi->disp1_clk = disp1_clk; | ||
1588 | hdmi->disp2_clk = disp2_clk; | ||
1589 | hdmi->suspended = false; | ||
1590 | hdmi->eld_retrieved= false; | ||
1591 | hdmi->clk_enabled = false; | ||
1592 | hdmi->audio_freq = 44100; | ||
1593 | hdmi->audio_source = AUTO; | ||
1594 | spin_lock_init(&hdmi->suspend_lock); | ||
1595 | |||
1596 | #ifdef CONFIG_SWITCH | ||
1597 | hdmi->hpd_switch.name = "hdmi"; | ||
1598 | ret = switch_dev_register(&hdmi->hpd_switch); | ||
1599 | |||
1600 | if (!ret) | ||
1601 | ret = device_create_file(hdmi->hpd_switch.dev, | ||
1602 | &dev_attr_underscan); | ||
1603 | BUG_ON(ret != 0); | ||
1604 | #endif | ||
1605 | |||
1606 | dc->out->depth = 24; | ||
1607 | |||
1608 | tegra_dc_set_outdata(dc, hdmi); | ||
1609 | |||
1610 | dc_hdmi = hdmi; | ||
1611 | /* boards can select default content protection policy */ | ||
1612 | if (dc->out->flags & TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND) | ||
1613 | tegra_nvhdcp_set_policy(hdmi->nvhdcp, | ||
1614 | TEGRA_NVHDCP_POLICY_ON_DEMAND); | ||
1615 | else | ||
1616 | tegra_nvhdcp_set_policy(hdmi->nvhdcp, | ||
1617 | TEGRA_NVHDCP_POLICY_ALWAYS_ON); | ||
1618 | |||
1619 | tegra_dc_hdmi_debug_create(hdmi); | ||
1620 | |||
1621 | return 0; | ||
1622 | |||
1623 | err_edid_destroy: | ||
1624 | tegra_edid_destroy(hdmi->edid); | ||
1625 | err_free_irq: | ||
1626 | free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc); | ||
1627 | err_put_clock: | ||
1628 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1629 | if (!IS_ERR_OR_NULL(hdmi->hda2hdmi_clk)) | ||
1630 | clk_put(hdmi->hda2hdmi_clk); | ||
1631 | if (!IS_ERR_OR_NULL(hdmi->hda2codec_clk)) | ||
1632 | clk_put(hdmi->hda2codec_clk); | ||
1633 | if (!IS_ERR_OR_NULL(hdmi->hda_clk)) | ||
1634 | clk_put(hdmi->hda_clk); | ||
1635 | #endif | ||
1636 | if (!IS_ERR_OR_NULL(disp2_clk)) | ||
1637 | clk_put(disp2_clk); | ||
1638 | if (!IS_ERR_OR_NULL(disp1_clk)) | ||
1639 | clk_put(disp1_clk); | ||
1640 | if (!IS_ERR_OR_NULL(clk)) | ||
1641 | clk_put(clk); | ||
1642 | err_iounmap_reg: | ||
1643 | iounmap(base); | ||
1644 | err_release_resource_reg: | ||
1645 | release_resource(base_res); | ||
1646 | err_free_hdmi: | ||
1647 | kfree(hdmi); | ||
1648 | return err; | ||
1649 | } | ||
1650 | |||
1651 | static void tegra_dc_hdmi_destroy(struct tegra_dc *dc) | ||
1652 | { | ||
1653 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1654 | |||
1655 | free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc); | ||
1656 | cancel_delayed_work_sync(&hdmi->work); | ||
1657 | #ifdef CONFIG_SWITCH | ||
1658 | switch_dev_unregister(&hdmi->hpd_switch); | ||
1659 | #endif | ||
1660 | iounmap(hdmi->base); | ||
1661 | release_resource(hdmi->base_res); | ||
1662 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1663 | clk_put(hdmi->hda2hdmi_clk); | ||
1664 | clk_put(hdmi->hda2codec_clk); | ||
1665 | clk_put(hdmi->hda_clk); | ||
1666 | #endif | ||
1667 | clk_put(hdmi->clk); | ||
1668 | clk_put(hdmi->disp1_clk); | ||
1669 | clk_put(hdmi->disp2_clk); | ||
1670 | tegra_edid_destroy(hdmi->edid); | ||
1671 | tegra_nvhdcp_destroy(hdmi->nvhdcp); | ||
1672 | |||
1673 | kfree(hdmi); | ||
1674 | |||
1675 | } | ||
1676 | |||
1677 | static void tegra_dc_hdmi_setup_audio_fs_tables(struct tegra_dc *dc) | ||
1678 | { | ||
1679 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1680 | int i; | ||
1681 | unsigned freqs[] = { | ||
1682 | 32000, | ||
1683 | 44100, | ||
1684 | 48000, | ||
1685 | 88200, | ||
1686 | 96000, | ||
1687 | 176400, | ||
1688 | 192000, | ||
1689 | }; | ||
1690 | |||
1691 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { | ||
1692 | unsigned f = freqs[i]; | ||
1693 | unsigned eight_half; | ||
1694 | unsigned delta;; | ||
1695 | |||
1696 | if (f > 96000) | ||
1697 | delta = 2; | ||
1698 | else if (f > 48000) | ||
1699 | delta = 6; | ||
1700 | else | ||
1701 | delta = 9; | ||
1702 | |||
1703 | eight_half = (8 * HDMI_AUDIOCLK_FREQ) / (f * 128); | ||
1704 | tegra_hdmi_writel(hdmi, AUDIO_FS_LOW(eight_half - delta) | | ||
1705 | AUDIO_FS_HIGH(eight_half + delta), | ||
1706 | HDMI_NV_PDISP_AUDIO_FS(i)); | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1711 | static void tegra_dc_hdmi_setup_eld_buff(struct tegra_dc *dc) | ||
1712 | { | ||
1713 | int i; | ||
1714 | int j; | ||
1715 | u8 tmp; | ||
1716 | |||
1717 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1718 | |||
1719 | /* program ELD stuff */ | ||
1720 | for (i = 0; i < HDMI_ELD_MONITOR_NAME_INDEX; i++) { | ||
1721 | switch (i) { | ||
1722 | case HDMI_ELD_VER_INDEX: | ||
1723 | tmp = (hdmi->eld.eld_ver << 3); | ||
1724 | tegra_hdmi_writel(hdmi, (i << 8) | tmp, | ||
1725 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1726 | break; | ||
1727 | case HDMI_ELD_BASELINE_LEN_INDEX: | ||
1728 | break; | ||
1729 | case HDMI_ELD_CEA_VER_MNL_INDEX: | ||
1730 | tmp = (hdmi->eld.cea_edid_ver << 5); | ||
1731 | tmp |= (hdmi->eld.mnl & 0x1f); | ||
1732 | tegra_hdmi_writel(hdmi, (i << 8) | tmp, | ||
1733 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1734 | break; | ||
1735 | case HDMI_ELD_SAD_CNT_CON_TYP_SAI_HDCP_INDEX: | ||
1736 | tmp = (hdmi->eld.sad_count << 4); | ||
1737 | tmp |= (hdmi->eld.conn_type & 0xC); | ||
1738 | tmp |= (hdmi->eld.support_ai & 0x2); | ||
1739 | tmp |= (hdmi->eld.support_hdcp & 0x1); | ||
1740 | tegra_hdmi_writel(hdmi, (i << 8) | tmp, | ||
1741 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1742 | break; | ||
1743 | case HDMI_ELD_AUD_SYNC_DELAY_INDEX: | ||
1744 | tegra_hdmi_writel(hdmi, (i << 8) | (hdmi->eld.aud_synch_delay), | ||
1745 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1746 | break; | ||
1747 | case HDMI_ELD_SPK_ALLOC_INDEX: | ||
1748 | tegra_hdmi_writel(hdmi, (i << 8) | (hdmi->eld.spk_alloc), | ||
1749 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1750 | break; | ||
1751 | case HDMI_ELD_PORT_ID_INDEX: | ||
1752 | for (j = 0; j < 8;j++) { | ||
1753 | tegra_hdmi_writel(hdmi, ((i +j) << 8) | (hdmi->eld.port_id[j]), | ||
1754 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1755 | } | ||
1756 | break; | ||
1757 | case HDMI_ELD_MANF_NAME_INDEX: | ||
1758 | for (j = 0; j < 2;j++) { | ||
1759 | tegra_hdmi_writel(hdmi, ((i +j) << 8) | (hdmi->eld.manufacture_id[j]), | ||
1760 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1761 | } | ||
1762 | break; | ||
1763 | case HDMI_ELD_PRODUCT_CODE_INDEX: | ||
1764 | for (j = 0; j < 2;j++) { | ||
1765 | tegra_hdmi_writel(hdmi, ((i +j) << 8) | (hdmi->eld.product_id[j]), | ||
1766 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1767 | } | ||
1768 | break; | ||
1769 | } | ||
1770 | } | ||
1771 | for (j = 0; j < hdmi->eld.mnl;j++) { | ||
1772 | tegra_hdmi_writel(hdmi, ((j + HDMI_ELD_MONITOR_NAME_INDEX) << 8) | | ||
1773 | (hdmi->eld.monitor_name[j]), | ||
1774 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1775 | } | ||
1776 | for (j = 0; j < hdmi->eld.sad_count;j++) { | ||
1777 | tegra_hdmi_writel(hdmi, ((j + HDMI_ELD_MONITOR_NAME_INDEX + hdmi->eld.mnl) << 8) | | ||
1778 | (hdmi->eld.sad[j]), | ||
1779 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0); | ||
1780 | } | ||
1781 | /* set presence andvalid bit */ | ||
1782 | tegra_hdmi_writel(hdmi, 3, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0); | ||
1783 | } | ||
1784 | #endif | ||
1785 | |||
1786 | static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc, unsigned audio_freq, | ||
1787 | unsigned audio_source) | ||
1788 | { | ||
1789 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1790 | const struct tegra_hdmi_audio_config *config; | ||
1791 | unsigned long audio_n; | ||
1792 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1793 | unsigned long reg_addr = 0; | ||
1794 | #endif | ||
1795 | unsigned a_source = AUDIO_CNTRL0_SOURCE_SELECT_AUTO; | ||
1796 | |||
1797 | if (HDA == audio_source) | ||
1798 | a_source = AUDIO_CNTRL0_SOURCE_SELECT_HDAL; | ||
1799 | else if (SPDIF == audio_source) | ||
1800 | a_source = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; | ||
1801 | |||
1802 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1803 | tegra_hdmi_writel(hdmi,a_source | AUDIO_CNTRL0_INJECT_NULLSMPL, | ||
1804 | HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0); | ||
1805 | tegra_hdmi_writel(hdmi, | ||
1806 | AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | ||
1807 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0), | ||
1808 | HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
1809 | #else | ||
1810 | tegra_hdmi_writel(hdmi, | ||
1811 | AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | ||
1812 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0) | | ||
1813 | a_source, | ||
1814 | HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
1815 | #endif | ||
1816 | config = tegra_hdmi_get_audio_config(audio_freq, dc->mode.pclk); | ||
1817 | if (!config) { | ||
1818 | dev_err(&dc->ndev->dev, | ||
1819 | "hdmi: can't set audio to %d at %d pix_clock", | ||
1820 | audio_freq, dc->mode.pclk); | ||
1821 | return -EINVAL; | ||
1822 | } | ||
1823 | |||
1824 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL); | ||
1825 | |||
1826 | audio_n = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNALTE | | ||
1827 | AUDIO_N_VALUE(config->n - 1); | ||
1828 | tegra_hdmi_writel(hdmi, audio_n, HDMI_NV_PDISP_AUDIO_N); | ||
1829 | |||
1830 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, | ||
1831 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | ||
1832 | |||
1833 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config->cts), | ||
1834 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | ||
1835 | |||
1836 | tegra_hdmi_writel(hdmi, SPARE_HW_CTS | SPARE_FORCE_SW_CTS | | ||
1837 | SPARE_CTS_RESET_VAL(1), | ||
1838 | HDMI_NV_PDISP_HDMI_SPARE); | ||
1839 | |||
1840 | audio_n &= ~AUDIO_N_RESETF; | ||
1841 | tegra_hdmi_writel(hdmi, audio_n, HDMI_NV_PDISP_AUDIO_N); | ||
1842 | |||
1843 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1844 | switch (audio_freq) { | ||
1845 | case AUDIO_FREQ_32K: | ||
1846 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320_0; | ||
1847 | break; | ||
1848 | case AUDIO_FREQ_44_1K: | ||
1849 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441_0; | ||
1850 | break; | ||
1851 | case AUDIO_FREQ_48K: | ||
1852 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480_0; | ||
1853 | break; | ||
1854 | case AUDIO_FREQ_88_2K: | ||
1855 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882_0; | ||
1856 | break; | ||
1857 | case AUDIO_FREQ_96K: | ||
1858 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960_0; | ||
1859 | break; | ||
1860 | case AUDIO_FREQ_176_4K: | ||
1861 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764_0; | ||
1862 | break; | ||
1863 | case AUDIO_FREQ_192K: | ||
1864 | reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920_0; | ||
1865 | break; | ||
1866 | } | ||
1867 | |||
1868 | tegra_hdmi_writel(hdmi, config->aval, reg_addr); | ||
1869 | #endif | ||
1870 | tegra_dc_hdmi_setup_audio_fs_tables(dc); | ||
1871 | |||
1872 | return 0; | ||
1873 | } | ||
1874 | |||
1875 | int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_source) | ||
1876 | { | ||
1877 | struct tegra_dc_hdmi_data *hdmi = dc_hdmi; | ||
1878 | |||
1879 | if (!hdmi) | ||
1880 | return -EAGAIN; | ||
1881 | |||
1882 | /* check for know freq */ | ||
1883 | if (AUDIO_FREQ_32K == audio_freq || | ||
1884 | AUDIO_FREQ_44_1K== audio_freq || | ||
1885 | AUDIO_FREQ_48K== audio_freq || | ||
1886 | AUDIO_FREQ_88_2K== audio_freq || | ||
1887 | AUDIO_FREQ_96K== audio_freq || | ||
1888 | AUDIO_FREQ_176_4K== audio_freq || | ||
1889 | AUDIO_FREQ_192K== audio_freq) { | ||
1890 | /* If we can program HDMI, then proceed */ | ||
1891 | if (hdmi->clk_enabled) | ||
1892 | tegra_dc_hdmi_setup_audio(hdmi->dc, audio_freq,audio_source); | ||
1893 | |||
1894 | /* Store it for using it in enable */ | ||
1895 | hdmi->audio_freq = audio_freq; | ||
1896 | hdmi->audio_source = audio_source; | ||
1897 | } | ||
1898 | else | ||
1899 | return -EINVAL; | ||
1900 | |||
1901 | return 0; | ||
1902 | } | ||
1903 | EXPORT_SYMBOL(tegra_hdmi_setup_audio_freq_source); | ||
1904 | |||
1905 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
1906 | int tegra_hdmi_setup_hda_presence() | ||
1907 | { | ||
1908 | struct tegra_dc_hdmi_data *hdmi = dc_hdmi; | ||
1909 | |||
1910 | if (!hdmi) | ||
1911 | return -EAGAIN; | ||
1912 | |||
1913 | if (hdmi->clk_enabled && hdmi->eld_retrieved) { | ||
1914 | /* If HDA_PRESENCE is already set reset it */ | ||
1915 | if (tegra_hdmi_readl(hdmi, | ||
1916 | HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0)) | ||
1917 | tegra_hdmi_writel(hdmi, 0, | ||
1918 | HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0); | ||
1919 | |||
1920 | tegra_dc_hdmi_setup_eld_buff(hdmi->dc); | ||
1921 | } | ||
1922 | else | ||
1923 | return -ENODEV; | ||
1924 | |||
1925 | return 0; | ||
1926 | } | ||
1927 | EXPORT_SYMBOL(tegra_hdmi_setup_hda_presence); | ||
1928 | #endif | ||
1929 | |||
1930 | static void tegra_dc_hdmi_write_infopack(struct tegra_dc *dc, int header_reg, | ||
1931 | u8 type, u8 version, void *data, int len) | ||
1932 | { | ||
1933 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1934 | u32 subpack[2]; /* extra byte for zero padding of subpack */ | ||
1935 | int i; | ||
1936 | u8 csum; | ||
1937 | |||
1938 | /* first byte of data is the checksum */ | ||
1939 | csum = type + version + len - 1; | ||
1940 | for (i = 1; i < len; i++) | ||
1941 | csum +=((u8 *)data)[i]; | ||
1942 | ((u8 *)data)[0] = 0x100 - csum; | ||
1943 | |||
1944 | tegra_hdmi_writel(hdmi, INFOFRAME_HEADER_TYPE(type) | | ||
1945 | INFOFRAME_HEADER_VERSION(version) | | ||
1946 | INFOFRAME_HEADER_LEN(len - 1), | ||
1947 | header_reg); | ||
1948 | |||
1949 | /* The audio inforame only has one set of subpack registers. The hdmi | ||
1950 | * block pads the rest of the data as per the spec so we have to fixup | ||
1951 | * the length before filling in the subpacks. | ||
1952 | */ | ||
1953 | if (header_reg == HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER) | ||
1954 | len = 6; | ||
1955 | |||
1956 | /* each subpack 7 bytes devided into: | ||
1957 | * subpack_low - bytes 0 - 3 | ||
1958 | * subpack_high - bytes 4 - 6 (with byte 7 padded to 0x00) | ||
1959 | */ | ||
1960 | for (i = 0; i < len; i++) { | ||
1961 | int subpack_idx = i % 7; | ||
1962 | |||
1963 | if (subpack_idx == 0) | ||
1964 | memset(subpack, 0x0, sizeof(subpack)); | ||
1965 | |||
1966 | ((u8 *)subpack)[subpack_idx] = ((u8 *)data)[i]; | ||
1967 | |||
1968 | if (subpack_idx == 6 || (i + 1 == len)) { | ||
1969 | int reg = header_reg + 1 + (i / 7) * 2; | ||
1970 | |||
1971 | tegra_hdmi_writel(hdmi, subpack[0], reg); | ||
1972 | tegra_hdmi_writel(hdmi, subpack[1], reg + 1); | ||
1973 | } | ||
1974 | } | ||
1975 | } | ||
1976 | |||
1977 | static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi) | ||
1978 | { | ||
1979 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
1980 | struct hdmi_avi_infoframe avi; | ||
1981 | |||
1982 | if (dvi) { | ||
1983 | tegra_hdmi_writel(hdmi, 0x0, | ||
1984 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
1985 | return; | ||
1986 | } | ||
1987 | |||
1988 | memset(&avi, 0x0, sizeof(avi)); | ||
1989 | |||
1990 | avi.r = HDMI_AVI_R_SAME; | ||
1991 | |||
1992 | if (dc->mode.v_active == 480) { | ||
1993 | if (dc->mode.h_active == 640) { | ||
1994 | avi.m = HDMI_AVI_M_4_3; | ||
1995 | avi.vic = 1; | ||
1996 | } else { | ||
1997 | avi.m = HDMI_AVI_M_16_9; | ||
1998 | avi.vic = 3; | ||
1999 | } | ||
2000 | } else if (dc->mode.v_active == 576) { | ||
2001 | /* CEC modes 17 and 18 differ only by the pysical size of the | ||
2002 | * screen so we have to calculation the physical aspect | ||
2003 | * ratio. 4 * 10 / 3 is 13 | ||
2004 | */ | ||
2005 | if ((dc->out->h_size * 10) / dc->out->v_size > 14) { | ||
2006 | avi.m = HDMI_AVI_M_16_9; | ||
2007 | avi.vic = 18; | ||
2008 | } else { | ||
2009 | avi.m = HDMI_AVI_M_4_3; | ||
2010 | avi.vic = 17; | ||
2011 | } | ||
2012 | } else if (dc->mode.v_active == 720 || | ||
2013 | (dc->mode.v_active == 1470 && dc->mode.stereo_mode)) { | ||
2014 | /* VIC for both 720p and 720p 3D mode */ | ||
2015 | avi.m = HDMI_AVI_M_16_9; | ||
2016 | if (dc->mode.h_front_porch == 110) | ||
2017 | avi.vic = 4; /* 60 Hz */ | ||
2018 | else | ||
2019 | avi.vic = 19; /* 50 Hz */ | ||
2020 | } else if (dc->mode.v_active == 1080 || | ||
2021 | (dc->mode.v_active == 2205 && dc->mode.stereo_mode)) { | ||
2022 | /* VIC for both 1080p and 1080p 3D mode */ | ||
2023 | avi.m = HDMI_AVI_M_16_9; | ||
2024 | if (dc->mode.h_front_porch == 88) | ||
2025 | avi.vic = 16; /* 60 Hz */ | ||
2026 | else if (dc->mode.h_front_porch == 528) | ||
2027 | avi.vic = 31; /* 50 Hz */ | ||
2028 | else | ||
2029 | avi.vic = 32; /* 24 Hz */ | ||
2030 | } else { | ||
2031 | avi.m = HDMI_AVI_M_16_9; | ||
2032 | avi.vic = 0; | ||
2033 | } | ||
2034 | |||
2035 | |||
2036 | tegra_dc_hdmi_write_infopack(dc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER, | ||
2037 | HDMI_INFOFRAME_TYPE_AVI, | ||
2038 | HDMI_AVI_VERSION, | ||
2039 | &avi, sizeof(avi)); | ||
2040 | |||
2041 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | ||
2042 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
2043 | } | ||
2044 | |||
2045 | static void tegra_dc_hdmi_setup_stereo_infoframe(struct tegra_dc *dc) | ||
2046 | { | ||
2047 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
2048 | struct hdmi_stereo_infoframe stereo; | ||
2049 | u32 val; | ||
2050 | |||
2051 | if (!dc->mode.stereo_mode) { | ||
2052 | val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
2053 | val &= ~GENERIC_CTRL_ENABLE; | ||
2054 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
2055 | return; | ||
2056 | } | ||
2057 | |||
2058 | memset(&stereo, 0x0, sizeof(stereo)); | ||
2059 | |||
2060 | stereo.regid0 = 0x03; | ||
2061 | stereo.regid1 = 0x0c; | ||
2062 | stereo.regid2 = 0x00; | ||
2063 | stereo.hdmi_video_format = 2; /* 3D_Structure present */ | ||
2064 | #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT | ||
2065 | stereo._3d_structure = 0; /* frame packing */ | ||
2066 | #else | ||
2067 | stereo._3d_structure = 8; /* side-by-side (half) */ | ||
2068 | stereo._3d_ext_data = 0; /* something which fits into 00XX bit req */ | ||
2069 | #endif | ||
2070 | |||
2071 | tegra_dc_hdmi_write_infopack(dc, HDMI_NV_PDISP_HDMI_GENERIC_HEADER, | ||
2072 | HDMI_INFOFRAME_TYPE_VENDOR, | ||
2073 | HDMI_VENDOR_VERSION, | ||
2074 | &stereo, 6); | ||
2075 | |||
2076 | val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
2077 | val |= GENERIC_CTRL_ENABLE; | ||
2078 | |||
2079 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
2080 | } | ||
2081 | |||
2082 | static void tegra_dc_hdmi_setup_audio_infoframe(struct tegra_dc *dc, bool dvi) | ||
2083 | { | ||
2084 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
2085 | struct hdmi_audio_infoframe audio; | ||
2086 | |||
2087 | if (dvi) { | ||
2088 | tegra_hdmi_writel(hdmi, 0x0, | ||
2089 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
2090 | return; | ||
2091 | } | ||
2092 | |||
2093 | memset(&audio, 0x0, sizeof(audio)); | ||
2094 | |||
2095 | audio.cc = HDMI_AUDIO_CC_2; | ||
2096 | tegra_dc_hdmi_write_infopack(dc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER, | ||
2097 | HDMI_INFOFRAME_TYPE_AUDIO, | ||
2098 | HDMI_AUDIO_VERSION, | ||
2099 | &audio, sizeof(audio)); | ||
2100 | |||
2101 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | ||
2102 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
2103 | } | ||
2104 | |||
2105 | static void tegra_dc_hdmi_setup_tdms(struct tegra_dc_hdmi_data *hdmi, | ||
2106 | const struct tdms_config *tc) | ||
2107 | { | ||
2108 | tegra_hdmi_writel(hdmi, tc->pll0, HDMI_NV_PDISP_SOR_PLL0); | ||
2109 | tegra_hdmi_writel(hdmi, tc->pll1, HDMI_NV_PDISP_SOR_PLL1); | ||
2110 | |||
2111 | tegra_hdmi_writel(hdmi, tc->pe_current, HDMI_NV_PDISP_PE_CURRENT); | ||
2112 | |||
2113 | tegra_hdmi_writel(hdmi, | ||
2114 | tc->drive_current | DRIVE_CURRENT_FUSE_OVERRIDE, | ||
2115 | HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); | ||
2116 | } | ||
2117 | |||
2118 | static void tegra_dc_hdmi_enable(struct tegra_dc *dc) | ||
2119 | { | ||
2120 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
2121 | int pulse_start; | ||
2122 | int dispclk_div_8_2; | ||
2123 | int retries; | ||
2124 | int rekey; | ||
2125 | int err; | ||
2126 | unsigned long val; | ||
2127 | unsigned i; | ||
2128 | unsigned long oldrate; | ||
2129 | |||
2130 | /* enbale power, clocks, resets, etc. */ | ||
2131 | |||
2132 | /* The upstream DC needs to be clocked for accesses to HDMI to not | ||
2133 | * hard lock the system. Because we don't know if HDMI is conencted | ||
2134 | * to disp1 or disp2 we need to enable both until we set the DC mux. | ||
2135 | */ | ||
2136 | clk_enable(hdmi->disp1_clk); | ||
2137 | clk_enable(hdmi->disp2_clk); | ||
2138 | |||
2139 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
2140 | /* Enabling HDA clocks before asserting HDA PD and ELDV bits */ | ||
2141 | clk_enable(hdmi->hda_clk); | ||
2142 | clk_enable(hdmi->hda2codec_clk); | ||
2143 | clk_enable(hdmi->hda2hdmi_clk); | ||
2144 | #endif | ||
2145 | |||
2146 | /* back off multiplier before attaching to parent at new rate. */ | ||
2147 | oldrate = clk_get_rate(hdmi->clk); | ||
2148 | clk_set_rate(hdmi->clk, oldrate / 2); | ||
2149 | |||
2150 | tegra_dc_setup_clk(dc, hdmi->clk); | ||
2151 | clk_set_rate(hdmi->clk, dc->mode.pclk); | ||
2152 | |||
2153 | clk_enable(hdmi->clk); | ||
2154 | tegra_periph_reset_assert(hdmi->clk); | ||
2155 | mdelay(1); | ||
2156 | tegra_periph_reset_deassert(hdmi->clk); | ||
2157 | |||
2158 | /* TODO: copy HDCP keys from KFUSE to HDMI */ | ||
2159 | |||
2160 | /* Program display timing registers: handled by dc */ | ||
2161 | |||
2162 | /* program HDMI registers and SOR sequencer */ | ||
2163 | |||
2164 | tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); | ||
2165 | tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888, | ||
2166 | DC_DISP_DISP_COLOR_CONTROL); | ||
2167 | |||
2168 | /* video_preamble uses h_pulse2 */ | ||
2169 | pulse_start = dc->mode.h_ref_to_sync + dc->mode.h_sync_width + | ||
2170 | dc->mode.h_back_porch - 10; | ||
2171 | tegra_dc_writel(dc, H_PULSE_2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
2172 | tegra_dc_writel(dc, | ||
2173 | PULSE_MODE_NORMAL | | ||
2174 | PULSE_POLARITY_HIGH | | ||
2175 | PULSE_QUAL_VACTIVE | | ||
2176 | PULSE_LAST_END_A, | ||
2177 | DC_DISP_H_PULSE2_CONTROL); | ||
2178 | tegra_dc_writel(dc, PULSE_START(pulse_start) | PULSE_END(pulse_start + 8), | ||
2179 | DC_DISP_H_PULSE2_POSITION_A); | ||
2180 | |||
2181 | tegra_hdmi_writel(hdmi, | ||
2182 | VSYNC_WINDOW_END(0x210) | | ||
2183 | VSYNC_WINDOW_START(0x200) | | ||
2184 | VSYNC_WINDOW_ENABLE, | ||
2185 | HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); | ||
2186 | |||
2187 | tegra_hdmi_writel(hdmi, | ||
2188 | (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) | | ||
2189 | ARM_VIDEO_RANGE_LIMITED, | ||
2190 | HDMI_NV_PDISP_INPUT_CONTROL); | ||
2191 | |||
2192 | clk_disable(hdmi->disp1_clk); | ||
2193 | clk_disable(hdmi->disp2_clk); | ||
2194 | |||
2195 | dispclk_div_8_2 = clk_get_rate(hdmi->clk) / 1000000 * 4; | ||
2196 | tegra_hdmi_writel(hdmi, | ||
2197 | SOR_REFCLK_DIV_INT(dispclk_div_8_2 >> 2) | | ||
2198 | SOR_REFCLK_DIV_FRAC(dispclk_div_8_2), | ||
2199 | HDMI_NV_PDISP_SOR_REFCLK); | ||
2200 | |||
2201 | hdmi->clk_enabled = true; | ||
2202 | |||
2203 | if (!hdmi->dvi) { | ||
2204 | err = tegra_dc_hdmi_setup_audio(dc, hdmi->audio_freq, | ||
2205 | hdmi->audio_source); | ||
2206 | |||
2207 | if (err < 0) | ||
2208 | hdmi->dvi = true; | ||
2209 | } | ||
2210 | |||
2211 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
2212 | if (hdmi->eld_retrieved) | ||
2213 | tegra_dc_hdmi_setup_eld_buff(dc); | ||
2214 | #endif | ||
2215 | |||
2216 | rekey = HDMI_REKEY_DEFAULT; | ||
2217 | val = HDMI_CTRL_REKEY(rekey); | ||
2218 | val |= HDMI_CTRL_MAX_AC_PACKET((dc->mode.h_sync_width + | ||
2219 | dc->mode.h_back_porch + | ||
2220 | dc->mode.h_front_porch - | ||
2221 | rekey - 18) / 32); | ||
2222 | if (!hdmi->dvi) | ||
2223 | val |= HDMI_CTRL_ENABLE; | ||
2224 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_HDMI_CTRL); | ||
2225 | |||
2226 | if (hdmi->dvi) | ||
2227 | tegra_hdmi_writel(hdmi, 0x0, | ||
2228 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
2229 | else | ||
2230 | tegra_hdmi_writel(hdmi, GENERIC_CTRL_AUDIO, | ||
2231 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
2232 | |||
2233 | tegra_dc_hdmi_setup_avi_infoframe(dc, hdmi->dvi); | ||
2234 | tegra_dc_hdmi_setup_audio_infoframe(dc, hdmi->dvi); | ||
2235 | tegra_dc_hdmi_setup_stereo_infoframe(dc); | ||
2236 | |||
2237 | /* TMDS CONFIG */ | ||
2238 | for (i = 0; i < ARRAY_SIZE(tdms_config); i++) { | ||
2239 | if (dc->mode.pclk <= tdms_config[i].pclk) { | ||
2240 | tegra_dc_hdmi_setup_tdms(hdmi, &tdms_config[i]); | ||
2241 | break; | ||
2242 | } | ||
2243 | } | ||
2244 | |||
2245 | tegra_hdmi_writel(hdmi, | ||
2246 | SOR_SEQ_CTL_PU_PC(0) | | ||
2247 | SOR_SEQ_PU_PC_ALT(0) | | ||
2248 | SOR_SEQ_PD_PC(8) | | ||
2249 | SOR_SEQ_PD_PC_ALT(8), | ||
2250 | HDMI_NV_PDISP_SOR_SEQ_CTL); | ||
2251 | |||
2252 | val = SOR_SEQ_INST_WAIT_TIME(1) | | ||
2253 | SOR_SEQ_INST_WAIT_UNITS_VSYNC | | ||
2254 | SOR_SEQ_INST_HALT | | ||
2255 | SOR_SEQ_INST_PIN_A_LOW | | ||
2256 | SOR_SEQ_INST_PIN_B_LOW | | ||
2257 | SOR_SEQ_INST_DRIVE_PWM_OUT_LO; | ||
2258 | |||
2259 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_SEQ_INST0); | ||
2260 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_SEQ_INST8); | ||
2261 | |||
2262 | val = 0x1c800; | ||
2263 | val &= ~SOR_CSTM_ROTCLK(~0); | ||
2264 | val |= SOR_CSTM_ROTCLK(2); | ||
2265 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_CSTM); | ||
2266 | |||
2267 | |||
2268 | tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); | ||
2269 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
2270 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
2271 | |||
2272 | |||
2273 | /* start SOR */ | ||
2274 | tegra_hdmi_writel(hdmi, | ||
2275 | SOR_PWR_NORMAL_STATE_PU | | ||
2276 | SOR_PWR_NORMAL_START_NORMAL | | ||
2277 | SOR_PWR_SAFE_STATE_PD | | ||
2278 | SOR_PWR_SETTING_NEW_TRIGGER, | ||
2279 | HDMI_NV_PDISP_SOR_PWR); | ||
2280 | tegra_hdmi_writel(hdmi, | ||
2281 | SOR_PWR_NORMAL_STATE_PU | | ||
2282 | SOR_PWR_NORMAL_START_NORMAL | | ||
2283 | SOR_PWR_SAFE_STATE_PD | | ||
2284 | SOR_PWR_SETTING_NEW_DONE, | ||
2285 | HDMI_NV_PDISP_SOR_PWR); | ||
2286 | |||
2287 | retries = 1000; | ||
2288 | do { | ||
2289 | BUG_ON(--retries < 0); | ||
2290 | val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR); | ||
2291 | } while (val & SOR_PWR_SETTING_NEW_PENDING); | ||
2292 | |||
2293 | val = SOR_STATE_ASY_CRCMODE_COMPLETE | | ||
2294 | SOR_STATE_ASY_OWNER_HEAD0 | | ||
2295 | SOR_STATE_ASY_SUBOWNER_BOTH | | ||
2296 | SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A | | ||
2297 | SOR_STATE_ASY_DEPOL_POS; | ||
2298 | |||
2299 | if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC) | ||
2300 | val |= SOR_STATE_ASY_HSYNCPOL_NEG; | ||
2301 | else | ||
2302 | val |= SOR_STATE_ASY_HSYNCPOL_POS; | ||
2303 | |||
2304 | if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC) | ||
2305 | val |= SOR_STATE_ASY_VSYNCPOL_NEG; | ||
2306 | else | ||
2307 | val |= SOR_STATE_ASY_VSYNCPOL_POS; | ||
2308 | |||
2309 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE2); | ||
2310 | |||
2311 | val = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL; | ||
2312 | tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE1); | ||
2313 | |||
2314 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); | ||
2315 | tegra_hdmi_writel(hdmi, SOR_STATE_UPDATE, HDMI_NV_PDISP_SOR_STATE0); | ||
2316 | tegra_hdmi_writel(hdmi, val | SOR_STATE_ATTACHED, | ||
2317 | HDMI_NV_PDISP_SOR_STATE1); | ||
2318 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); | ||
2319 | |||
2320 | tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS); | ||
2321 | |||
2322 | tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
2323 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, | ||
2324 | DC_CMD_DISPLAY_POWER_CONTROL); | ||
2325 | |||
2326 | tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); | ||
2327 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
2328 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
2329 | |||
2330 | tegra_nvhdcp_set_plug(hdmi->nvhdcp, 1); | ||
2331 | } | ||
2332 | |||
2333 | static void tegra_dc_hdmi_disable(struct tegra_dc *dc) | ||
2334 | { | ||
2335 | struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); | ||
2336 | |||
2337 | tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0); | ||
2338 | |||
2339 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
2340 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0); | ||
2341 | /* sleep 1ms before disabling clocks to ensure HDA gets the interrupt */ | ||
2342 | msleep(1); | ||
2343 | clk_disable(hdmi->hda2hdmi_clk); | ||
2344 | clk_disable(hdmi->hda2codec_clk); | ||
2345 | clk_disable(hdmi->hda_clk); | ||
2346 | #endif | ||
2347 | tegra_periph_reset_assert(hdmi->clk); | ||
2348 | hdmi->clk_enabled = false; | ||
2349 | clk_disable(hdmi->clk); | ||
2350 | tegra_dvfs_set_rate(hdmi->clk, 0); | ||
2351 | } | ||
2352 | |||
2353 | struct tegra_dc_out_ops tegra_dc_hdmi_ops = { | ||
2354 | .init = tegra_dc_hdmi_init, | ||
2355 | .destroy = tegra_dc_hdmi_destroy, | ||
2356 | .enable = tegra_dc_hdmi_enable, | ||
2357 | .disable = tegra_dc_hdmi_disable, | ||
2358 | .detect = tegra_dc_hdmi_detect, | ||
2359 | .suspend = tegra_dc_hdmi_suspend, | ||
2360 | .resume = tegra_dc_hdmi_resume, | ||
2361 | }; | ||
2362 | |||
2363 | struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc) | ||
2364 | { | ||
2365 | struct tegra_dc_hdmi_data *hdmi; | ||
2366 | |||
2367 | /* TODO: Support EDID on non-HDMI devices */ | ||
2368 | if (dc->out->type != TEGRA_DC_OUT_HDMI) | ||
2369 | return ERR_PTR(-ENODEV); | ||
2370 | |||
2371 | hdmi = tegra_dc_get_outdata(dc); | ||
2372 | |||
2373 | return tegra_edid_get_data(hdmi->edid); | ||
2374 | } | ||
2375 | EXPORT_SYMBOL(tegra_dc_get_edid); | ||
2376 | |||
2377 | void tegra_dc_put_edid(struct tegra_dc_edid *edid) | ||
2378 | { | ||
2379 | tegra_edid_put_data(edid); | ||
2380 | } | ||
2381 | EXPORT_SYMBOL(tegra_dc_put_edid); | ||
diff --git a/drivers/video/tegra/dc/hdmi.h b/drivers/video/tegra/dc/hdmi.h new file mode 100644 index 00000000000..702ab16e87f --- /dev/null +++ b/drivers/video/tegra/dc/hdmi.h | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/hdmi.h | ||
3 | * | ||
4 | * non-tegra specific HDMI declarations | ||
5 | * | ||
6 | * Copyright (C) 2010 Google, Inc. | ||
7 | * Author: Erik Gilling <konkers@android.com> | ||
8 | * | ||
9 | * Copyright (C) 2010-2011 NVIDIA Corporation | ||
10 | * | ||
11 | * This software is licensed under the terms of the GNU General Public | ||
12 | * License version 2, as published by the Free Software Foundation, and | ||
13 | * may be copied, distributed, and modified under those terms. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_HDMI_H | ||
23 | #define __DRIVERS_VIDEO_TEGRA_DC_HDMI_H | ||
24 | |||
25 | #define HDMI_INFOFRAME_TYPE_VENDOR 0x81 | ||
26 | #define HDMI_INFOFRAME_TYPE_AVI 0x82 | ||
27 | #define HDMI_INFOFRAME_TYPE_SPD 0x83 | ||
28 | #define HDMI_INFOFRAME_TYPE_AUDIO 0x84 | ||
29 | #define HDMI_INFOFRAME_TYPE_MPEG_SRC 0x85 | ||
30 | #define HDMI_INFOFRAME_TYPE_NTSC_VBI 0x86 | ||
31 | |||
32 | /* all fields little endian */ | ||
33 | struct hdmi_avi_infoframe { | ||
34 | /* PB0 */ | ||
35 | u8 csum; | ||
36 | |||
37 | /* PB1 */ | ||
38 | unsigned s:2; /* scan information */ | ||
39 | unsigned b:2; /* bar info data valid */ | ||
40 | unsigned a:1; /* active info present */ | ||
41 | unsigned y:2; /* RGB or YCbCr */ | ||
42 | unsigned res1:1; | ||
43 | |||
44 | /* PB2 */ | ||
45 | unsigned r:4; /* active format aspect ratio */ | ||
46 | unsigned m:2; /* picture aspect ratio */ | ||
47 | unsigned c:2; /* colorimetry */ | ||
48 | |||
49 | /* PB3 */ | ||
50 | unsigned sc:2; /* scan information */ | ||
51 | unsigned q:2; /* quantization range */ | ||
52 | unsigned ec:3; /* extended colorimetry */ | ||
53 | unsigned itc:1; /* it content */ | ||
54 | |||
55 | /* PB4 */ | ||
56 | unsigned vic:7; /* video format id code */ | ||
57 | unsigned res4:1; | ||
58 | |||
59 | /* PB5 */ | ||
60 | unsigned pr:4; /* pixel repetition factor */ | ||
61 | unsigned cn:2; /* it content type*/ | ||
62 | unsigned yq:2; /* ycc quantization range */ | ||
63 | |||
64 | /* PB6-7 */ | ||
65 | u16 top_bar_end_line; | ||
66 | |||
67 | /* PB8-9 */ | ||
68 | u16 bot_bar_start_line; | ||
69 | |||
70 | /* PB10-11 */ | ||
71 | u16 left_bar_end_pixel; | ||
72 | |||
73 | /* PB12-13 */ | ||
74 | u16 right_bar_start_pixel; | ||
75 | } __attribute__((packed)); | ||
76 | |||
77 | #define HDMI_AVI_VERSION 0x02 | ||
78 | |||
79 | #define HDMI_AVI_Y_RGB 0x0 | ||
80 | #define HDMI_AVI_Y_YCBCR_422 0x1 | ||
81 | #define HDMI_AVI_Y_YCBCR_444 0x2 | ||
82 | |||
83 | #define HDMI_AVI_B_VERT 0x1 | ||
84 | #define HDMI_AVI_B_HORIZ 0x2 | ||
85 | |||
86 | #define HDMI_AVI_S_NONE 0x0 | ||
87 | #define HDMI_AVI_S_OVERSCAN 0x1 | ||
88 | #define HDMI_AVI_S_UNDERSCAN 0x2 | ||
89 | |||
90 | #define HDMI_AVI_C_NONE 0x0 | ||
91 | #define HDMI_AVI_C_SMPTE 0x1 | ||
92 | #define HDMI_AVI_C_ITU_R 0x2 | ||
93 | #define HDMI_AVI_C_EXTENDED 0x4 | ||
94 | |||
95 | #define HDMI_AVI_M_4_3 0x1 | ||
96 | #define HDMI_AVI_M_16_9 0x2 | ||
97 | |||
98 | #define HDMI_AVI_R_SAME 0x8 | ||
99 | #define HDMI_AVI_R_4_3_CENTER 0x9 | ||
100 | #define HDMI_AVI_R_16_9_CENTER 0xa | ||
101 | #define HDMI_AVI_R_14_9_CENTER 0xb | ||
102 | |||
103 | /* all fields little endian */ | ||
104 | struct hdmi_audio_infoframe { | ||
105 | /* PB0 */ | ||
106 | u8 csum; | ||
107 | |||
108 | /* PB1 */ | ||
109 | unsigned cc:3; /* channel count */ | ||
110 | unsigned res1:1; | ||
111 | unsigned ct:4; /* coding type */ | ||
112 | |||
113 | /* PB2 */ | ||
114 | unsigned ss:2; /* sample size */ | ||
115 | unsigned sf:3; /* sample frequency */ | ||
116 | unsigned res2:3; | ||
117 | |||
118 | /* PB3 */ | ||
119 | unsigned cxt:5; /* coding extention type */ | ||
120 | unsigned res3:3; | ||
121 | |||
122 | /* PB4 */ | ||
123 | u8 ca; /* channel/speaker allocation */ | ||
124 | |||
125 | /* PB5 */ | ||
126 | unsigned res5:3; | ||
127 | unsigned lsv:4; /* level shift value */ | ||
128 | unsigned dm_inh:1; /* downmix inhibit */ | ||
129 | |||
130 | /* PB6-10 reserved */ | ||
131 | u8 res6; | ||
132 | u8 res7; | ||
133 | u8 res8; | ||
134 | u8 res9; | ||
135 | u8 res10; | ||
136 | } __attribute__((packed)); | ||
137 | |||
138 | #define HDMI_AUDIO_VERSION 0x01 | ||
139 | |||
140 | #define HDMI_AUDIO_CC_STREAM 0x0 /* specified by audio stream */ | ||
141 | #define HDMI_AUDIO_CC_2 0x1 | ||
142 | #define HDMI_AUDIO_CC_3 0x2 | ||
143 | #define HDMI_AUDIO_CC_4 0x3 | ||
144 | #define HDMI_AUDIO_CC_5 0x4 | ||
145 | #define HDMI_AUDIO_CC_6 0x5 | ||
146 | #define HDMI_AUDIO_CC_7 0x6 | ||
147 | #define HDMI_AUDIO_CC_8 0x7 | ||
148 | |||
149 | #define HDMI_AUDIO_CT_STREAM 0x0 /* specified by audio stream */ | ||
150 | #define HDMI_AUDIO_CT_PCM 0x1 | ||
151 | #define HDMI_AUDIO_CT_AC3 0x2 | ||
152 | #define HDMI_AUDIO_CT_MPEG1 0x3 | ||
153 | #define HDMI_AUDIO_CT_MP3 0x4 | ||
154 | #define HDMI_AUDIO_CT_MPEG2 0x5 | ||
155 | #define HDMI_AUDIO_CT_AAC_LC 0x6 | ||
156 | #define HDMI_AUDIO_CT_DTS 0x7 | ||
157 | #define HDMI_AUDIO_CT_ATRAC 0x8 | ||
158 | #define HDMI_AUDIO_CT_DSD 0x9 | ||
159 | #define HDMI_AUDIO_CT_E_AC3 0xa | ||
160 | #define HDMI_AUDIO_CT_DTS_HD 0xb | ||
161 | #define HDMI_AUDIO_CT_MLP 0xc | ||
162 | #define HDMI_AUDIO_CT_DST 0xd | ||
163 | #define HDMI_AUDIO_CT_WMA_PRO 0xe | ||
164 | #define HDMI_AUDIO_CT_CXT 0xf | ||
165 | |||
166 | #define HDMI_AUDIO_SF_STREAM 0x0 /* specified by audio stream */ | ||
167 | #define HDMI_AUIDO_SF_32K 0x1 | ||
168 | #define HDMI_AUDIO_SF_44_1K 0x2 | ||
169 | #define HDMI_AUDIO_SF_48K 0x3 | ||
170 | #define HDMI_AUDIO_SF_88_2K 0x4 | ||
171 | #define HDMI_AUDIO_SF_96K 0x5 | ||
172 | #define HDMI_AUDIO_SF_176_4K 0x6 | ||
173 | #define HDMI_AUDIO_SF_192K 0x7 | ||
174 | |||
175 | #define HDMI_AUDIO_SS_STREAM 0x0 /* specified by audio stream */ | ||
176 | #define HDMI_AUDIO_SS_16BIT 0x1 | ||
177 | #define HDMI_AUDIO_SS_20BIT 0x2 | ||
178 | #define HDMI_AUDIO_SS_24BIT 0x3 | ||
179 | |||
180 | #define HDMI_AUDIO_CXT_CT 0x0 /* refer to coding in CT */ | ||
181 | #define HDMI_AUDIO_CXT_HE_AAC 0x1 | ||
182 | #define HDMI_AUDIO_CXT_HE_AAC_V2 0x2 | ||
183 | #define HDMI_AUDIO_CXT_MPEG_SURROUND 0x3 | ||
184 | |||
185 | /* all fields little endian */ | ||
186 | struct hdmi_stereo_infoframe { | ||
187 | /* PB0 */ | ||
188 | u8 csum; | ||
189 | |||
190 | /* PB1 */ | ||
191 | u8 regid0; | ||
192 | |||
193 | /* PB2 */ | ||
194 | u8 regid1; | ||
195 | |||
196 | /* PB3 */ | ||
197 | u8 regid2; | ||
198 | |||
199 | /* PB4 */ | ||
200 | unsigned res1:5; | ||
201 | unsigned hdmi_video_format:3; | ||
202 | |||
203 | /* PB5 */ | ||
204 | unsigned res2:4; | ||
205 | unsigned _3d_structure:4; | ||
206 | |||
207 | /* PB6*/ | ||
208 | unsigned res3:4; | ||
209 | unsigned _3d_ext_data:4; | ||
210 | |||
211 | } __attribute__((packed)); | ||
212 | |||
213 | #define HDMI_VENDOR_VERSION 0x01 | ||
214 | |||
215 | struct tegra_dc_hdmi_data; | ||
216 | |||
217 | unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi, | ||
218 | unsigned long reg); | ||
219 | void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi, | ||
220 | unsigned long val, unsigned long reg); | ||
221 | |||
222 | #endif | ||
diff --git a/drivers/video/tegra/dc/hdmi_reg.h b/drivers/video/tegra/dc/hdmi_reg.h new file mode 100644 index 00000000000..0bdda43199e --- /dev/null +++ b/drivers/video/tegra/dc/hdmi_reg.h | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/hdmi_reg.h | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_HDMI_REG_H | ||
19 | #define __DRIVERS_VIDEO_TEGRA_DC_HDMI_REG_H | ||
20 | |||
21 | #define HDMI_CTXSW 0x00 | ||
22 | #define HDMI_NV_PDISP_SOR_STATE0 0x01 | ||
23 | #define SOR_STATE_UPDATE (1 << 0) | ||
24 | |||
25 | #define HDMI_NV_PDISP_SOR_STATE1 0x02 | ||
26 | #define SOR_STATE_ASY_HEAD_OPMODE_SLEEP (0 << 0) | ||
27 | #define SOR_STATE_ASY_HEAD_OPMODE_SNOOSE (1 << 0) | ||
28 | #define SOR_STATE_ASY_HEAD_OPMODE_AWAKE (2 << 0) | ||
29 | #define SOR_STATE_ASY_ORMODE_SAFE (0 << 2) | ||
30 | #define SOR_STATE_ASY_ORMODE_NORMAL (1 << 2) | ||
31 | #define SOR_STATE_ATTACHED (1 << 3) | ||
32 | #define SOR_STATE_ARM_SHOW_VGA (1 << 4) | ||
33 | |||
34 | #define HDMI_NV_PDISP_SOR_STATE2 0x03 | ||
35 | #define SOR_STATE_ASY_OWNER_NONE (0 << 0) | ||
36 | #define SOR_STATE_ASY_OWNER_HEAD0 (1 << 0) | ||
37 | #define SOR_STATE_ASY_SUBOWNER_NONE (0 << 4) | ||
38 | #define SOR_STATE_ASY_SUBOWNER_SUBHEAD0 (1 << 4) | ||
39 | #define SOR_STATE_ASY_SUBOWNER_SUBHEAD1 (2 << 4) | ||
40 | #define SOR_STATE_ASY_SUBOWNER_BOTH (3 << 4) | ||
41 | #define SOR_STATE_ASY_CRCMODE_ACTIVE (0 << 6) | ||
42 | #define SOR_STATE_ASY_CRCMODE_COMPLETE (1 << 6) | ||
43 | #define SOR_STATE_ASY_CRCMODE_NON_ACTIVE (2 << 6) | ||
44 | #define SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A (1 << 8) | ||
45 | #define SOR_STATE_ASY_PROTOCOL_CUSTOM (15 << 8) | ||
46 | #define SOR_STATE_ASY_HSYNCPOL_POS (0 << 12) | ||
47 | #define SOR_STATE_ASY_HSYNCPOL_NEG (1 << 12) | ||
48 | #define SOR_STATE_ASY_VSYNCPOL_POS (0 << 13) | ||
49 | #define SOR_STATE_ASY_VSYNCPOL_NEG (1 << 13) | ||
50 | #define SOR_STATE_ASY_DEPOL_POS (0 << 14) | ||
51 | #define SOR_STATE_ASY_DEPOL_NEG (1 << 14) | ||
52 | |||
53 | #define HDMI_NV_PDISP_RG_HDCP_AN_MSB 0x04 | ||
54 | #define HDMI_NV_PDISP_RG_HDCP_AN_LSB 0x05 | ||
55 | #define HDMI_NV_PDISP_RG_HDCP_CN_MSB 0x06 | ||
56 | #define HDMI_NV_PDISP_RG_HDCP_CN_LSB 0x07 | ||
57 | #define HDMI_NV_PDISP_RG_HDCP_AKSV_MSB 0x08 | ||
58 | #define HDMI_NV_PDISP_RG_HDCP_AKSV_LSB 0x09 | ||
59 | #define HDMI_NV_PDISP_RG_HDCP_BKSV_MSB 0x0a | ||
60 | #define REPEATER (1 << 31) | ||
61 | #define HDMI_NV_PDISP_RG_HDCP_BKSV_LSB 0x0b | ||
62 | #define HDMI_NV_PDISP_RG_HDCP_CKSV_MSB 0x0c | ||
63 | #define HDMI_NV_PDISP_RG_HDCP_CKSV_LSB 0x0d | ||
64 | #define HDMI_NV_PDISP_RG_HDCP_DKSV_MSB 0x0e | ||
65 | #define HDMI_NV_PDISP_RG_HDCP_DKSV_LSB 0x0f | ||
66 | #define HDMI_NV_PDISP_RG_HDCP_CTRL 0x10 | ||
67 | #define HDCP_RUN_YES (1 << 0) | ||
68 | #define CRYPT_ENABLED (1 << 1) | ||
69 | #define ONEONE_ENABLED (1 << 3) | ||
70 | #define AN_VALID (1 << 8) | ||
71 | #define R0_VALID (1 << 9) | ||
72 | #define SPRIME_VALID (1 << 10) | ||
73 | #define MPRIME_VALID (1 << 11) | ||
74 | #define SROM_ERR (1 << 13) | ||
75 | #define HDMI_NV_PDISP_RG_HDCP_CMODE 0x11 | ||
76 | #define TMDS0_LINK0 (1 << 4) | ||
77 | #define READ_S (1 << 0) | ||
78 | #define READ_M (2 << 0) | ||
79 | #define HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB 0x12 | ||
80 | #define HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB 0x13 | ||
81 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB 0x14 | ||
82 | #define STATUS_CS (1 << 6) | ||
83 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2 0x15 | ||
84 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1 0x16 | ||
85 | #define HDMI_NV_PDISP_RG_HDCP_RI 0x17 | ||
86 | #define HDMI_NV_PDISP_RG_HDCP_CS_MSB 0x18 | ||
87 | #define HDMI_NV_PDISP_RG_HDCP_CS_LSB 0x19 | ||
88 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU0 0x1a | ||
89 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0 0x1b | ||
90 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU1 0x1c | ||
91 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU2 0x1d | ||
92 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL 0x1e | ||
93 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS 0x1f | ||
94 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER 0x20 | ||
95 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW 0x21 | ||
96 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH 0x22 | ||
97 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL 0x23 | ||
98 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS 0x24 | ||
99 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER 0x25 | ||
100 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW 0x26 | ||
101 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH 0x27 | ||
102 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW 0x28 | ||
103 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH 0x29 | ||
104 | #define INFOFRAME_CTRL_ENABLE (1 << 0) | ||
105 | #define INFOFRAME_CTRL_OTHER (1 << 4) | ||
106 | #define INFOFRAME_CTRL_SINGLE (1 << 8) | ||
107 | |||
108 | #define INFOFRAME_HEADER_TYPE(x) ((x) & 0xff) | ||
109 | #define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) | ||
110 | #define INFOFRAME_HEADER_LEN(x) (((x) & 0xf) << 16) | ||
111 | |||
112 | #define HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x2a | ||
113 | #define GENERIC_CTRL_ENABLE (1 << 0) | ||
114 | #define GENERIC_CTRL_OTHER (1 << 4) | ||
115 | #define GENERIC_CTRL_SINGLE (1 << 8) | ||
116 | #define GENERIC_CTRL_HBLANK (1 << 12) | ||
117 | #define GENERIC_CTRL_AUDIO (1 << 16) | ||
118 | |||
119 | #define HDMI_NV_PDISP_HDMI_GENERIC_STATUS 0x2b | ||
120 | #define HDMI_NV_PDISP_HDMI_GENERIC_HEADER 0x2c | ||
121 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW 0x2d | ||
122 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH 0x2e | ||
123 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW 0x2f | ||
124 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH 0x30 | ||
125 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW 0x31 | ||
126 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH 0x32 | ||
127 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW 0x33 | ||
128 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH 0x34 | ||
129 | #define HDMI_NV_PDISP_HDMI_ACR_CTRL 0x35 | ||
130 | #define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW 0x36 | ||
131 | #define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH 0x37 | ||
132 | #define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW 0x38 | ||
133 | #define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH 0x39 | ||
134 | #define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW 0x3a | ||
135 | #define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH 0x3b | ||
136 | #define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW 0x3c | ||
137 | #define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH 0x3d | ||
138 | #define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW 0x3e | ||
139 | #define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH 0x3f | ||
140 | #define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW 0x40 | ||
141 | #define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH 0x41 | ||
142 | #define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW 0x42 | ||
143 | #define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH 0x43 | ||
144 | #define ACR_SB3(x) (((x) & 0xff) << 8) | ||
145 | #define ACR_SB2(x) (((x) & 0xff) << 16) | ||
146 | #define ACR_SB1(x) (((x) & 0xff) << 24) | ||
147 | #define ACR_SUBPACK_CTS(x) (((x) & 0xffffff) << 8) | ||
148 | |||
149 | #define ACR_SB6(x) (((x) & 0xff) << 0) | ||
150 | #define ACR_SB5(x) (((x) & 0xff) << 8) | ||
151 | #define ACR_SB4(x) (((x) & 0xff) << 16) | ||
152 | #define ACR_ENABLE (1 << 31) | ||
153 | #define ACR_SUBPACK_N(x) ((x) & 0xffffff) | ||
154 | |||
155 | #define HDMI_NV_PDISP_HDMI_CTRL 0x44 | ||
156 | #define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0) | ||
157 | #define HDMI_CTRL_AUDIO_LAYOUT (1 << 8) | ||
158 | #define HDMI_CTRL_SAMPLE_FLAT (1 << 12) | ||
159 | #define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16) | ||
160 | #define HDMI_CTRL_ENABLE (1 << 30) | ||
161 | |||
162 | #define HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT 0x45 | ||
163 | #define HDMI_NV_PDISP_HDMI_VSYNC_WINDOW 0x46 | ||
164 | #define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0) | ||
165 | #define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16) | ||
166 | #define VSYNC_WINDOW_ENABLE (1 << 31) | ||
167 | |||
168 | #define HDMI_NV_PDISP_HDMI_GCP_CTRL 0x47 | ||
169 | #define HDMI_NV_PDISP_HDMI_GCP_STATUS 0x48 | ||
170 | #define HDMI_NV_PDISP_HDMI_GCP_SUBPACK 0x49 | ||
171 | #define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1 0x4a | ||
172 | #define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2 0x4b | ||
173 | #define HDMI_NV_PDISP_HDMI_EMU0 0x4c | ||
174 | #define HDMI_NV_PDISP_HDMI_EMU1 0x4d | ||
175 | #define HDMI_NV_PDISP_HDMI_EMU1_RDATA 0x4e | ||
176 | #define HDMI_NV_PDISP_HDMI_SPARE 0x4f | ||
177 | #define SPARE_HW_CTS (1 << 0) | ||
178 | #define SPARE_FORCE_SW_CTS (1 << 1) | ||
179 | #define SPARE_CTS_RESET_VAL(x) (((x) & 0x7) << 16) | ||
180 | #define SPARE_ACR_PRIORITY_HIGH (0 << 31) | ||
181 | #define SPARE_ACR_PRIORITY_LOW (1 << 31) | ||
182 | |||
183 | #define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1 0x50 | ||
184 | #define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2 0x51 | ||
185 | #define HDMI_NV_PDISP_HDCPRIF_ROM_CTRL 0x53 | ||
186 | #define HDMI_NV_PDISP_SOR_CAP 0x54 | ||
187 | #define HDMI_NV_PDISP_SOR_PWR 0x55 | ||
188 | #define SOR_PWR_NORMAL_STATE_PD (0 << 0) | ||
189 | #define SOR_PWR_NORMAL_STATE_PU (1 << 0) | ||
190 | #define SOR_PWR_NORMAL_START_NORMAL (0 << 1) | ||
191 | #define SOR_PWR_NORMAL_START_ALT (1 << 1) | ||
192 | #define SOR_PWR_SAFE_STATE_PD (0 << 16) | ||
193 | #define SOR_PWR_SAFE_STATE_PU (1 << 16) | ||
194 | #define SOR_PWR_SAFE_START_NORMAL (0 << 17) | ||
195 | #define SOR_PWR_SAFE_START_ALT (1 << 17) | ||
196 | #define SOR_PWR_HALT_DELAY (1 << 24) | ||
197 | #define SOR_PWR_MODE (1 << 28) | ||
198 | #define SOR_PWR_SETTING_NEW_DONE (0 << 31) | ||
199 | #define SOR_PWR_SETTING_NEW_PENDING (1 << 31) | ||
200 | #define SOR_PWR_SETTING_NEW_TRIGGER (1 << 31) | ||
201 | |||
202 | #define HDMI_NV_PDISP_SOR_TEST 0x56 | ||
203 | #define HDMI_NV_PDISP_SOR_PLL0 0x57 | ||
204 | #define SOR_PLL_PWR (1 << 0) | ||
205 | #define SOR_PLL_PDBG (1 << 1) | ||
206 | #define SOR_PLL_VCOPD (1 << 2) | ||
207 | #define SOR_PLL_PDPORT (1 << 3) | ||
208 | #define SOR_PLL_RESISTORSEL (1 << 4) | ||
209 | #define SOR_PLL_PULLDOWN (1 << 5) | ||
210 | #define SOR_PLL_VCOCAP(x) (((x) & 0xf) << 8) | ||
211 | #define SOR_PLL_BG_V17_S(x) (((x) & 0xf) << 12) | ||
212 | #define SOR_PLL_FILTER(x) (((x) & 0xf) << 16) | ||
213 | #define SOR_PLL_ICHPMP(x) (((x) & 0xf) << 24) | ||
214 | #define SOR_PLL_TX_REG_LOAD(x) (((x) & 0x3) << 28) | ||
215 | |||
216 | #define HDMI_NV_PDISP_SOR_PLL1 0x58 | ||
217 | #define SOR_PLL_TMDS_TERM_ENABLE (1 << 8) | ||
218 | #define SOR_PLL_TMDS_TERMADJ(x) (((x) & 0xf) << 9) | ||
219 | #define SOR_PLL_LOADADJ(x) (((x) & 0xf) << 20) | ||
220 | #define SOR_PLL_PE_EN (1 << 28) | ||
221 | #define SOR_PLL_HALF_FULL_PE (1 << 29) | ||
222 | #define SOR_PLL_S_D_PIN_PE (1 << 30) | ||
223 | |||
224 | #define HDMI_NV_PDISP_SOR_PLL2 0x59 | ||
225 | #define HDMI_NV_PDISP_SOR_CSTM 0x5a | ||
226 | #define SOR_CSTM_PD_TXDA_0 (1 << 0) | ||
227 | #define SOR_CSTM_PD_TXDA_1 (1 << 1) | ||
228 | #define SOR_CSTM_PD_TXDA_2 (1 << 2) | ||
229 | #define SOR_CSTM_PD_TXDA_3 (1 << 3) | ||
230 | #define SOR_CSTM_PD_TXDB_0 (1 << 4) | ||
231 | #define SOR_CSTM_PD_TXDB_1 (1 << 5) | ||
232 | #define SOR_CSTM_PD_TXDB_2 (1 << 6) | ||
233 | #define SOR_CSTM_PD_TXDB_3 (1 << 7) | ||
234 | #define SOR_CSTM_PD_TXCA (1 << 8) | ||
235 | #define SOR_CSTM_PD_TXCB (1 << 9) | ||
236 | #define SOR_CSTM_UPPER (1 << 11) | ||
237 | #define SOR_CSTM_MODE(x) (((x) & 0x3) << 12) | ||
238 | #define SOR_CSTM_LINKACTA (1 << 14) | ||
239 | #define SOR_CSTM_LINKACTB (1 << 15) | ||
240 | #define SOR_CSTM_LVDS_EN (1 << 16) | ||
241 | #define SOR_CSTM_DUP_SYNC (1 << 17) | ||
242 | #define SOR_CSTM_NEW_MODE (1 << 18) | ||
243 | #define SOR_CSTM_BALANCED (1 << 19) | ||
244 | #define SOR_CSTM_PLLDIV (1 << 21) | ||
245 | #define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24) | ||
246 | #define SOR_CSTM_ROTDAT(x) (((x) & 0x7) << 28) | ||
247 | |||
248 | #define HDMI_NV_PDISP_SOR_LVDS 0x5b | ||
249 | #define HDMI_NV_PDISP_SOR_CRCA 0x5c | ||
250 | #define HDMI_NV_PDISP_SOR_CRCB 0x5d | ||
251 | #define HDMI_NV_PDISP_SOR_BLANK 0x5e | ||
252 | #define HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f | ||
253 | #define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) << 0) | ||
254 | #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4) | ||
255 | #define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8) | ||
256 | #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12) | ||
257 | #define SOR_SEQ_PC(x) (((x) & 0xf) << 16) | ||
258 | #define SOR_SEQ_STATUS (1 << 28) | ||
259 | #define SOR_SEQ_SWITCH (1 << 30) | ||
260 | |||
261 | #define HDMI_NV_PDISP_SOR_SEQ_INST0 0x60 | ||
262 | #define HDMI_NV_PDISP_SOR_SEQ_INST1 0x61 | ||
263 | #define HDMI_NV_PDISP_SOR_SEQ_INST2 0x62 | ||
264 | #define HDMI_NV_PDISP_SOR_SEQ_INST3 0x63 | ||
265 | #define HDMI_NV_PDISP_SOR_SEQ_INST4 0x64 | ||
266 | #define HDMI_NV_PDISP_SOR_SEQ_INST5 0x65 | ||
267 | #define HDMI_NV_PDISP_SOR_SEQ_INST6 0x66 | ||
268 | #define HDMI_NV_PDISP_SOR_SEQ_INST7 0x67 | ||
269 | #define HDMI_NV_PDISP_SOR_SEQ_INST8 0x68 | ||
270 | #define HDMI_NV_PDISP_SOR_SEQ_INST9 0x69 | ||
271 | #define HDMI_NV_PDISP_SOR_SEQ_INSTA 0x6a | ||
272 | #define HDMI_NV_PDISP_SOR_SEQ_INSTB 0x6b | ||
273 | #define HDMI_NV_PDISP_SOR_SEQ_INSTC 0x6c | ||
274 | #define HDMI_NV_PDISP_SOR_SEQ_INSTD 0x6d | ||
275 | #define HDMI_NV_PDISP_SOR_SEQ_INSTE 0x6e | ||
276 | #define HDMI_NV_PDISP_SOR_SEQ_INSTF 0x6f | ||
277 | #define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0) | ||
278 | #define SOR_SEQ_INST_WAIT_UNITS_US (0 << 12) | ||
279 | #define SOR_SEQ_INST_WAIT_UNITS_MS (1 << 12) | ||
280 | #define SOR_SEQ_INST_WAIT_UNITS_VSYNC (2 << 12) | ||
281 | #define SOR_SEQ_INST_HALT (1 << 15) | ||
282 | #define SOR_SEQ_INST_PIN_A_LOW (0 << 21) | ||
283 | #define SOR_SEQ_INST_PIN_A_HIGH (1 << 21) | ||
284 | #define SOR_SEQ_INST_PIN_B_LOW (0 << 22) | ||
285 | #define SOR_SEQ_INST_PIN_B_HIGH (1 << 22) | ||
286 | #define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23) | ||
287 | #define SOR_SEQ_INST_TRISTATE_IOS (1 << 24) | ||
288 | #define SOR_SEQ_INST_SOR_SEQ_INST_BLACK_DATA (1 << 25) | ||
289 | #define SOR_SEQ_INST_BLANK_DE (1 << 26) | ||
290 | #define SOR_SEQ_INST_BLANK_H (1 << 27) | ||
291 | #define SOR_SEQ_INST_BLANK_V (1 << 28) | ||
292 | #define SOR_SEQ_INST_ASSERT_PLL_RESETV (1 << 29) | ||
293 | #define SOR_SEQ_INST_POWERDOWN_MACRO (1 << 30) | ||
294 | #define SOR_SEQ_INST_PLL_PULLDOWN (1 << 31) | ||
295 | |||
296 | #define HDMI_NV_PDISP_SOR_VCRCA0 0x72 | ||
297 | #define HDMI_NV_PDISP_SOR_VCRCA1 0x73 | ||
298 | #define HDMI_NV_PDISP_SOR_CCRCA0 0x74 | ||
299 | #define HDMI_NV_PDISP_SOR_CCRCA1 0x75 | ||
300 | #define HDMI_NV_PDISP_SOR_EDATAA0 0x76 | ||
301 | #define HDMI_NV_PDISP_SOR_EDATAA1 0x77 | ||
302 | #define HDMI_NV_PDISP_SOR_COUNTA0 0x78 | ||
303 | #define HDMI_NV_PDISP_SOR_COUNTA1 0x79 | ||
304 | #define HDMI_NV_PDISP_SOR_DEBUGA0 0x7a | ||
305 | #define HDMI_NV_PDISP_SOR_DEBUGA1 0x7b | ||
306 | #define HDMI_NV_PDISP_SOR_TRIG 0x7c | ||
307 | #define HDMI_NV_PDISP_SOR_MSCHECK 0x7d | ||
308 | #define HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x7e | ||
309 | #define DRIVE_CURRENT_LANE0(x) (((x) & 0x3f) << 0) | ||
310 | #define DRIVE_CURRENT_LANE1(x) (((x) & 0x3f) << 8) | ||
311 | #define DRIVE_CURRENT_LANE2(x) (((x) & 0x3f) << 16) | ||
312 | #define DRIVE_CURRENT_LANE3(x) (((x) & 0x3f) << 24) | ||
313 | #define DRIVE_CURRENT_FUSE_OVERRIDE (1 << 31) | ||
314 | #define DRIVE_CURRENT_1_500_mA 0x00 | ||
315 | #define DRIVE_CURRENT_1_875_mA 0x01 | ||
316 | #define DRIVE_CURRENT_2_250_mA 0x02 | ||
317 | #define DRIVE_CURRENT_2_625_mA 0x03 | ||
318 | #define DRIVE_CURRENT_3_000_mA 0x04 | ||
319 | #define DRIVE_CURRENT_3_375_mA 0x05 | ||
320 | #define DRIVE_CURRENT_3_750_mA 0x06 | ||
321 | #define DRIVE_CURRENT_4_125_mA 0x07 | ||
322 | #define DRIVE_CURRENT_4_500_mA 0x08 | ||
323 | #define DRIVE_CURRENT_4_875_mA 0x09 | ||
324 | #define DRIVE_CURRENT_5_250_mA 0x0a | ||
325 | #define DRIVE_CURRENT_5_625_mA 0x0b | ||
326 | #define DRIVE_CURRENT_6_000_mA 0x0c | ||
327 | #define DRIVE_CURRENT_6_375_mA 0x0d | ||
328 | #define DRIVE_CURRENT_6_750_mA 0x0e | ||
329 | #define DRIVE_CURRENT_7_125_mA 0x0f | ||
330 | #define DRIVE_CURRENT_7_500_mA 0x10 | ||
331 | #define DRIVE_CURRENT_7_875_mA 0x11 | ||
332 | #define DRIVE_CURRENT_8_250_mA 0x12 | ||
333 | #define DRIVE_CURRENT_8_625_mA 0x13 | ||
334 | #define DRIVE_CURRENT_9_000_mA 0x14 | ||
335 | #define DRIVE_CURRENT_9_375_mA 0x15 | ||
336 | #define DRIVE_CURRENT_9_750_mA 0x16 | ||
337 | #define DRIVE_CURRENT_10_125_mA 0x17 | ||
338 | #define DRIVE_CURRENT_10_500_mA 0x18 | ||
339 | #define DRIVE_CURRENT_10_875_mA 0x19 | ||
340 | #define DRIVE_CURRENT_11_250_mA 0x1a | ||
341 | #define DRIVE_CURRENT_11_625_mA 0x1b | ||
342 | #define DRIVE_CURRENT_12_000_mA 0x1c | ||
343 | #define DRIVE_CURRENT_12_375_mA 0x1d | ||
344 | #define DRIVE_CURRENT_12_750_mA 0x1e | ||
345 | #define DRIVE_CURRENT_13_125_mA 0x1f | ||
346 | #define DRIVE_CURRENT_13_500_mA 0x20 | ||
347 | #define DRIVE_CURRENT_13_875_mA 0x21 | ||
348 | #define DRIVE_CURRENT_14_250_mA 0x22 | ||
349 | #define DRIVE_CURRENT_14_625_mA 0x23 | ||
350 | #define DRIVE_CURRENT_15_000_mA 0x24 | ||
351 | #define DRIVE_CURRENT_15_375_mA 0x25 | ||
352 | #define DRIVE_CURRENT_15_750_mA 0x26 | ||
353 | #define DRIVE_CURRENT_16_125_mA 0x27 | ||
354 | #define DRIVE_CURRENT_16_500_mA 0x28 | ||
355 | #define DRIVE_CURRENT_16_875_mA 0x29 | ||
356 | #define DRIVE_CURRENT_17_250_mA 0x2a | ||
357 | #define DRIVE_CURRENT_17_625_mA 0x2b | ||
358 | #define DRIVE_CURRENT_18_000_mA 0x2c | ||
359 | #define DRIVE_CURRENT_18_375_mA 0x2d | ||
360 | #define DRIVE_CURRENT_18_750_mA 0x2e | ||
361 | #define DRIVE_CURRENT_19_125_mA 0x2f | ||
362 | #define DRIVE_CURRENT_19_500_mA 0x30 | ||
363 | #define DRIVE_CURRENT_19_875_mA 0x31 | ||
364 | #define DRIVE_CURRENT_20_250_mA 0x32 | ||
365 | #define DRIVE_CURRENT_20_625_mA 0x33 | ||
366 | #define DRIVE_CURRENT_21_000_mA 0x34 | ||
367 | #define DRIVE_CURRENT_21_375_mA 0x35 | ||
368 | #define DRIVE_CURRENT_21_750_mA 0x36 | ||
369 | #define DRIVE_CURRENT_22_125_mA 0x37 | ||
370 | #define DRIVE_CURRENT_22_500_mA 0x38 | ||
371 | #define DRIVE_CURRENT_22_875_mA 0x39 | ||
372 | #define DRIVE_CURRENT_23_250_mA 0x3a | ||
373 | #define DRIVE_CURRENT_23_625_mA 0x3b | ||
374 | #define DRIVE_CURRENT_24_000_mA 0x3c | ||
375 | #define DRIVE_CURRENT_24_375_mA 0x3d | ||
376 | #define DRIVE_CURRENT_24_750_mA 0x3e | ||
377 | |||
378 | #define HDMI_NV_PDISP_AUDIO_DEBUG0 0x7f | ||
379 | #define HDMI_NV_PDISP_AUDIO_DEBUG1 0x80 | ||
380 | #define HDMI_NV_PDISP_AUDIO_DEBUG2 0x81 | ||
381 | /* note: datasheet defines FS1..FS7. we have FS(0)..FS(6) */ | ||
382 | #define HDMI_NV_PDISP_AUDIO_FS(x) (0x82 + (x)) | ||
383 | #define AUDIO_FS_LOW(x) (((x) & 0xfff) << 0) | ||
384 | #define AUDIO_FS_HIGH(x) (((x) & 0xfff) << 16) | ||
385 | |||
386 | |||
387 | #define HDMI_NV_PDISP_AUDIO_PULSE_WIDTH 0x89 | ||
388 | #define HDMI_NV_PDISP_AUDIO_THRESHOLD 0x8a | ||
389 | #define HDMI_NV_PDISP_AUDIO_CNTRL0 0x8b | ||
390 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
391 | #define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0 0xac | ||
392 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0 0xbc | ||
393 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0 0xbd | ||
394 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320_0 0xbf | ||
395 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441_0 0xc0 | ||
396 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882_0 0xc1 | ||
397 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764_0 0xc2 | ||
398 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480_0 0xc3 | ||
399 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960_0 0xc4 | ||
400 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920_0 0xc5 | ||
401 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT_0 0xc6 | ||
402 | #endif | ||
403 | #define AUDIO_CNTRL0_ERROR_TOLERANCE(x) (((x) & 0xff) << 0) | ||
404 | #define AUDIO_CNTRL0_SOFT_RESET (1 << 8) | ||
405 | #define AUDIO_CNTRL0_SOFT_RESET_ALL (1 << 12) | ||
406 | #define AUDIO_CNTRL0_SAMPLING_FREQ_UNKNOWN (1 << 16) | ||
407 | #define AUDIO_CNTRL0_SAMPLING_FREQ_32K (2 << 16) | ||
408 | #define AUDIO_CNTRL0_SAMPLING_FREQ_44_1K (0 << 16) | ||
409 | #define AUDIO_CNTRL0_SAMPLING_FREQ_48K (2 << 16) | ||
410 | #define AUDIO_CNTRL0_SAMPLING_FREQ_88_2K (8 << 16) | ||
411 | #define AUDIO_CNTRL0_SAMPLING_FREQ_96K (10 << 16) | ||
412 | #define AUDIO_CNTRL0_SAMPLING_FREQ_176_4K (12 << 16) | ||
413 | #define AUDIO_CNTRL0_SAMPLING_FREQ_192K (14 << 16) | ||
414 | #define AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20) | ||
415 | #define AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20) | ||
416 | #define AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20) | ||
417 | #define AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29) | ||
418 | #define AUDIO_CNTRL0_FRAMES_PER_BLOCK(x) (((x) & 0xff) << 24) | ||
419 | |||
420 | #define HDMI_NV_PDISP_AUDIO_N 0x8c | ||
421 | #define AUDIO_N_VALUE(x) (((x) & 0xfffff) << 0) | ||
422 | #define AUDIO_N_RESETF (1 << 20) | ||
423 | #define AUDIO_N_GENERATE_NORMAL (0 << 24) | ||
424 | #define AUDIO_N_GENERATE_ALTERNALTE (1 << 24) | ||
425 | #define AUDIO_N_LOOKUP_ENABLE (1 << 28) | ||
426 | |||
427 | #define HDMI_NV_PDISP_HDCPRIF_ROM_TIMING 0x94 | ||
428 | #define HDMI_NV_PDISP_SOR_REFCLK 0x95 | ||
429 | #define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8) | ||
430 | #define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x3) << 6) | ||
431 | |||
432 | #define HDMI_NV_PDISP_CRC_CONTROL 0x96 | ||
433 | #define HDMI_NV_PDISP_INPUT_CONTROL 0x97 | ||
434 | #define HDMI_SRC_DISPLAYA (0 << 0) | ||
435 | #define HDMI_SRC_DISPLAYB (1 << 0) | ||
436 | #define ARM_VIDEO_RANGE_FULL (0 << 1) | ||
437 | #define ARM_VIDEO_RANGE_LIMITED (1 << 1) | ||
438 | |||
439 | #define HDMI_NV_PDISP_SCRATCH 0x98 | ||
440 | #define HDMI_NV_PDISP_PE_CURRENT 0x99 | ||
441 | #define PE_CURRENT0(x) (((x) & 0xf) << 0) | ||
442 | #define PE_CURRENT1(x) (((x) & 0xf) << 8) | ||
443 | #define PE_CURRENT2(x) (((x) & 0xf) << 16) | ||
444 | #define PE_CURRENT3(x) (((x) & 0xf) << 24) | ||
445 | #define PE_CURRENT_0_0_mA 0x0 | ||
446 | #define PE_CURRENT_0_5_mA 0x1 | ||
447 | #define PE_CURRENT_1_0_mA 0x2 | ||
448 | #define PE_CURRENT_1_5_mA 0x3 | ||
449 | #define PE_CURRENT_2_0_mA 0x4 | ||
450 | #define PE_CURRENT_2_5_mA 0x5 | ||
451 | #define PE_CURRENT_3_0_mA 0x6 | ||
452 | #define PE_CURRENT_3_5_mA 0x7 | ||
453 | #define PE_CURRENT_4_0_mA 0x8 | ||
454 | #define PE_CURRENT_4_5_mA 0x9 | ||
455 | #define PE_CURRENT_5_0_mA 0xa | ||
456 | #define PE_CURRENT_5_5_mA 0xb | ||
457 | #define PE_CURRENT_6_0_mA 0xc | ||
458 | #define PE_CURRENT_6_5_mA 0xd | ||
459 | #define PE_CURRENT_7_0_mA 0xe | ||
460 | #define PE_CURRENT_7_5_mA 0xf | ||
461 | |||
462 | #define HDMI_NV_PDISP_KEY_CTRL 0x9a | ||
463 | #define LOCAL_KEYS (1 << 0) | ||
464 | #define AUTOINC (1 << 1) | ||
465 | #define WRITE16 (1 << 4) | ||
466 | #define PKEY_REQUEST_RELOAD_TRIGGER (1 << 5) | ||
467 | #define PKEY_LOADED (1 << 6) | ||
468 | #define HDMI_NV_PDISP_KEY_DEBUG0 0x9b | ||
469 | #define HDMI_NV_PDISP_KEY_DEBUG1 0x9c | ||
470 | #define HDMI_NV_PDISP_KEY_DEBUG2 0x9d | ||
471 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_0 0x9e | ||
472 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_1 0x9f | ||
473 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_2 0xa0 | ||
474 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_3 0xa1 | ||
475 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG 0xa2 | ||
476 | #define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3 | ||
477 | |||
478 | #endif | ||
diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c new file mode 100644 index 00000000000..263de07a3da --- /dev/null +++ b/drivers/video/tegra/dc/nvhdcp.c | |||
@@ -0,0 +1,1259 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/nvhdcp.c | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/poll.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | #include <asm/atomic.h> | ||
27 | |||
28 | #include <mach/dc.h> | ||
29 | #include <mach/kfuse.h> | ||
30 | |||
31 | #include <video/nvhdcp.h> | ||
32 | |||
33 | #include "dc_reg.h" | ||
34 | #include "dc_priv.h" | ||
35 | #include "hdmi_reg.h" | ||
36 | #include "hdmi.h" | ||
37 | |||
38 | DECLARE_WAIT_QUEUE_HEAD(wq_worker); | ||
39 | |||
40 | /* for 0x40 Bcaps */ | ||
41 | #define BCAPS_REPEATER (1 << 6) | ||
42 | #define BCAPS_READY (1 << 5) | ||
43 | #define BCAPS_11 (1 << 1) /* used for both Bcaps and Ainfo */ | ||
44 | |||
45 | /* for 0x41 Bstatus */ | ||
46 | #define BSTATUS_MAX_DEVS_EXCEEDED (1 << 7) | ||
47 | #define BSTATUS_MAX_CASCADE_EXCEEDED (1 << 11) | ||
48 | |||
49 | #ifdef VERBOSE_DEBUG | ||
50 | #define nvhdcp_vdbg(...) \ | ||
51 | printk("nvhdcp: " __VA_ARGS__) | ||
52 | #else | ||
53 | #define nvhdcp_vdbg(...) \ | ||
54 | ({ \ | ||
55 | if(0) \ | ||
56 | printk("nvhdcp: " __VA_ARGS__); \ | ||
57 | 0; \ | ||
58 | }) | ||
59 | #endif | ||
60 | #define nvhdcp_debug(...) \ | ||
61 | pr_debug("nvhdcp: " __VA_ARGS__) | ||
62 | #define nvhdcp_err(...) \ | ||
63 | pr_err("nvhdcp: Error: " __VA_ARGS__) | ||
64 | #define nvhdcp_info(...) \ | ||
65 | pr_info("nvhdcp: " __VA_ARGS__) | ||
66 | |||
67 | |||
68 | /* for nvhdcp.state */ | ||
69 | enum tegra_nvhdcp_state { | ||
70 | STATE_OFF, | ||
71 | STATE_UNAUTHENTICATED, | ||
72 | STATE_LINK_VERIFY, | ||
73 | STATE_RENEGOTIATE, | ||
74 | }; | ||
75 | |||
76 | struct tegra_nvhdcp { | ||
77 | struct delayed_work work; | ||
78 | struct tegra_dc_hdmi_data *hdmi; | ||
79 | struct workqueue_struct *downstream_wq; | ||
80 | struct mutex lock; | ||
81 | struct miscdevice miscdev; | ||
82 | char name[12]; | ||
83 | unsigned id; | ||
84 | bool plugged; /* true if hotplug detected */ | ||
85 | atomic_t policy; /* set policy */ | ||
86 | enum tegra_nvhdcp_state state; /* STATE_xxx */ | ||
87 | struct i2c_client *client; | ||
88 | struct i2c_board_info info; | ||
89 | int bus; | ||
90 | u32 b_status; | ||
91 | u64 a_n; | ||
92 | u64 c_n; | ||
93 | u64 a_ksv; | ||
94 | u64 b_ksv; | ||
95 | u64 c_ksv; | ||
96 | u64 d_ksv; | ||
97 | u8 v_prime[20]; | ||
98 | u64 m_prime; | ||
99 | u32 num_bksv_list; | ||
100 | u64 bksv_list[TEGRA_NVHDCP_MAX_DEVS]; | ||
101 | int fail_count; | ||
102 | }; | ||
103 | |||
104 | static inline bool nvhdcp_is_plugged(struct tegra_nvhdcp *nvhdcp) | ||
105 | { | ||
106 | rmb(); | ||
107 | return nvhdcp->plugged; | ||
108 | } | ||
109 | |||
110 | static inline bool nvhdcp_set_plugged(struct tegra_nvhdcp *nvhdcp, bool plugged) | ||
111 | { | ||
112 | nvhdcp->plugged = plugged; | ||
113 | wmb(); | ||
114 | return plugged; | ||
115 | } | ||
116 | |||
117 | static int nvhdcp_i2c_read(struct tegra_nvhdcp *nvhdcp, u8 reg, | ||
118 | size_t len, void *data) | ||
119 | { | ||
120 | int status; | ||
121 | int retries = 15; | ||
122 | struct i2c_msg msg[] = { | ||
123 | { | ||
124 | .addr = 0x74 >> 1, /* primary link */ | ||
125 | .flags = 0, | ||
126 | .len = 1, | ||
127 | .buf = ®, | ||
128 | }, | ||
129 | { | ||
130 | .addr = 0x74 >> 1, /* primary link */ | ||
131 | .flags = I2C_M_RD, | ||
132 | .len = len, | ||
133 | .buf = data, | ||
134 | }, | ||
135 | }; | ||
136 | |||
137 | do { | ||
138 | if (!nvhdcp_is_plugged(nvhdcp)) { | ||
139 | nvhdcp_err("disconnect during i2c xfer\n"); | ||
140 | return -EIO; | ||
141 | } | ||
142 | status = i2c_transfer(nvhdcp->client->adapter, | ||
143 | msg, ARRAY_SIZE(msg)); | ||
144 | if ((status < 0) && (retries > 1)) | ||
145 | msleep(250); | ||
146 | } while ((status < 0) && retries--); | ||
147 | |||
148 | if (status < 0) { | ||
149 | nvhdcp_err("i2c xfer error %d\n", status); | ||
150 | return status; | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int nvhdcp_i2c_write(struct tegra_nvhdcp *nvhdcp, u8 reg, | ||
157 | size_t len, const void *data) | ||
158 | { | ||
159 | int status; | ||
160 | u8 buf[len + 1]; | ||
161 | struct i2c_msg msg[] = { | ||
162 | { | ||
163 | .addr = 0x74 >> 1, /* primary link */ | ||
164 | .flags = 0, | ||
165 | .len = len + 1, | ||
166 | .buf = buf, | ||
167 | }, | ||
168 | }; | ||
169 | int retries = 15; | ||
170 | |||
171 | buf[0] = reg; | ||
172 | memcpy(buf + 1, data, len); | ||
173 | |||
174 | do { | ||
175 | if (!nvhdcp_is_plugged(nvhdcp)) { | ||
176 | nvhdcp_err("disconnect during i2c xfer\n"); | ||
177 | return -EIO; | ||
178 | } | ||
179 | status = i2c_transfer(nvhdcp->client->adapter, | ||
180 | msg, ARRAY_SIZE(msg)); | ||
181 | if ((status < 0) && (retries > 1)) | ||
182 | msleep(250); | ||
183 | } while ((status < 0) && retries--); | ||
184 | |||
185 | if (status < 0) { | ||
186 | nvhdcp_err("i2c xfer error %d\n", status); | ||
187 | return status; | ||
188 | } | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static inline int nvhdcp_i2c_read8(struct tegra_nvhdcp *nvhdcp, u8 reg, u8 *val) | ||
194 | { | ||
195 | return nvhdcp_i2c_read(nvhdcp, reg, 1, val); | ||
196 | } | ||
197 | |||
198 | static inline int nvhdcp_i2c_write8(struct tegra_nvhdcp *nvhdcp, u8 reg, u8 val) | ||
199 | { | ||
200 | return nvhdcp_i2c_write(nvhdcp, reg, 1, &val); | ||
201 | } | ||
202 | |||
203 | static inline int nvhdcp_i2c_read16(struct tegra_nvhdcp *nvhdcp, | ||
204 | u8 reg, u16 *val) | ||
205 | { | ||
206 | u8 buf[2]; | ||
207 | int e; | ||
208 | |||
209 | e = nvhdcp_i2c_read(nvhdcp, reg, sizeof buf, buf); | ||
210 | if (e) | ||
211 | return e; | ||
212 | |||
213 | if (val) | ||
214 | *val = buf[0] | (u16)buf[1] << 8; | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int nvhdcp_i2c_read40(struct tegra_nvhdcp *nvhdcp, u8 reg, u64 *val) | ||
220 | { | ||
221 | u8 buf[5]; | ||
222 | int e, i; | ||
223 | u64 n; | ||
224 | |||
225 | e = nvhdcp_i2c_read(nvhdcp, reg, sizeof buf, buf); | ||
226 | if (e) | ||
227 | return e; | ||
228 | |||
229 | for(i = 0, n = 0; i < 5; i++ ) { | ||
230 | n <<= 8; | ||
231 | n |= buf[4 - i]; | ||
232 | } | ||
233 | |||
234 | if (val) | ||
235 | *val = n; | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int nvhdcp_i2c_write40(struct tegra_nvhdcp *nvhdcp, u8 reg, u64 val) | ||
241 | { | ||
242 | char buf[5]; | ||
243 | int i; | ||
244 | for(i = 0; i < 5; i++ ) { | ||
245 | buf[i] = val; | ||
246 | val >>= 8; | ||
247 | } | ||
248 | return nvhdcp_i2c_write(nvhdcp, reg, sizeof buf, buf); | ||
249 | } | ||
250 | |||
251 | static int nvhdcp_i2c_write64(struct tegra_nvhdcp *nvhdcp, u8 reg, u64 val) | ||
252 | { | ||
253 | char buf[8]; | ||
254 | int i; | ||
255 | for(i = 0; i < 8; i++ ) { | ||
256 | buf[i] = val; | ||
257 | val >>= 8; | ||
258 | } | ||
259 | return nvhdcp_i2c_write(nvhdcp, reg, sizeof buf, buf); | ||
260 | } | ||
261 | |||
262 | |||
263 | /* 64-bit link encryption session random number */ | ||
264 | static inline u64 get_an(struct tegra_dc_hdmi_data *hdmi) | ||
265 | { | ||
266 | u64 r; | ||
267 | r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AN_MSB) << 32; | ||
268 | r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AN_LSB); | ||
269 | return r; | ||
270 | } | ||
271 | |||
272 | /* 64-bit upstream exchange random number */ | ||
273 | static inline void set_cn(struct tegra_dc_hdmi_data *hdmi, u64 c_n) | ||
274 | { | ||
275 | tegra_hdmi_writel(hdmi, (u32)c_n, HDMI_NV_PDISP_RG_HDCP_CN_LSB); | ||
276 | tegra_hdmi_writel(hdmi, c_n >> 32, HDMI_NV_PDISP_RG_HDCP_CN_MSB); | ||
277 | } | ||
278 | |||
279 | |||
280 | /* 40-bit transmitter's key selection vector */ | ||
281 | static inline u64 get_aksv(struct tegra_dc_hdmi_data *hdmi) | ||
282 | { | ||
283 | u64 r; | ||
284 | r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AKSV_MSB) << 32; | ||
285 | r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AKSV_LSB); | ||
286 | return r; | ||
287 | } | ||
288 | |||
289 | /* 40-bit receiver's key selection vector */ | ||
290 | static inline void set_bksv(struct tegra_dc_hdmi_data *hdmi, u64 b_ksv, bool repeater) | ||
291 | { | ||
292 | if (repeater) | ||
293 | b_ksv |= (u64)REPEATER << 32; | ||
294 | tegra_hdmi_writel(hdmi, (u32)b_ksv, HDMI_NV_PDISP_RG_HDCP_BKSV_LSB); | ||
295 | tegra_hdmi_writel(hdmi, b_ksv >> 32, HDMI_NV_PDISP_RG_HDCP_BKSV_MSB); | ||
296 | } | ||
297 | |||
298 | |||
299 | /* 40-bit software's key selection vector */ | ||
300 | static inline void set_cksv(struct tegra_dc_hdmi_data *hdmi, u64 c_ksv) | ||
301 | { | ||
302 | tegra_hdmi_writel(hdmi, (u32)c_ksv, HDMI_NV_PDISP_RG_HDCP_CKSV_LSB); | ||
303 | tegra_hdmi_writel(hdmi, c_ksv >> 32, HDMI_NV_PDISP_RG_HDCP_CKSV_MSB); | ||
304 | } | ||
305 | |||
306 | /* 40-bit connection state */ | ||
307 | static inline u64 get_cs(struct tegra_dc_hdmi_data *hdmi) | ||
308 | { | ||
309 | u64 r; | ||
310 | r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CS_MSB) << 32; | ||
311 | r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CS_LSB); | ||
312 | return r; | ||
313 | } | ||
314 | |||
315 | /* 40-bit upstream key selection vector */ | ||
316 | static inline u64 get_dksv(struct tegra_dc_hdmi_data *hdmi) | ||
317 | { | ||
318 | u64 r; | ||
319 | r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_DKSV_MSB) << 32; | ||
320 | r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_DKSV_LSB); | ||
321 | return r; | ||
322 | } | ||
323 | |||
324 | /* 64-bit encrypted M0 value */ | ||
325 | static inline u64 get_mprime(struct tegra_dc_hdmi_data *hdmi) | ||
326 | { | ||
327 | u64 r; | ||
328 | r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB) << 32; | ||
329 | r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB); | ||
330 | return r; | ||
331 | } | ||
332 | |||
333 | static inline u16 get_transmitter_ri(struct tegra_dc_hdmi_data *hdmi) | ||
334 | { | ||
335 | return tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_RI); | ||
336 | } | ||
337 | |||
338 | static inline int get_receiver_ri(struct tegra_nvhdcp *nvhdcp, u16 *r) | ||
339 | { | ||
340 | return nvhdcp_i2c_read16(nvhdcp, 0x8, r); /* long read */ | ||
341 | } | ||
342 | |||
343 | static int get_bcaps(struct tegra_nvhdcp *nvhdcp, u8 *b_caps) | ||
344 | { | ||
345 | return nvhdcp_i2c_read8(nvhdcp, 0x40, b_caps); | ||
346 | } | ||
347 | |||
348 | static int get_ksvfifo(struct tegra_nvhdcp *nvhdcp, | ||
349 | unsigned num_bksv_list, u64 *ksv_list) | ||
350 | { | ||
351 | u8 *buf, *p; | ||
352 | int e; | ||
353 | unsigned i; | ||
354 | size_t buf_len = num_bksv_list * 5; | ||
355 | |||
356 | if (!ksv_list || num_bksv_list > TEGRA_NVHDCP_MAX_DEVS) | ||
357 | return -EINVAL; | ||
358 | |||
359 | if (num_bksv_list == 0) | ||
360 | return 0; | ||
361 | |||
362 | buf = kmalloc(buf_len, GFP_KERNEL); | ||
363 | if (IS_ERR_OR_NULL(buf)) | ||
364 | return -ENOMEM; | ||
365 | |||
366 | e = nvhdcp_i2c_read(nvhdcp, 0x43, buf_len, buf); | ||
367 | if (e) { | ||
368 | kfree(buf); | ||
369 | return e; | ||
370 | } | ||
371 | |||
372 | /* load 40-bit keys from repeater into array of u64 */ | ||
373 | p = buf; | ||
374 | for (i = 0; i < num_bksv_list; i++) { | ||
375 | ksv_list[i] = p[0] | ((u64)p[1] << 8) | ((u64)p[2] << 16) | ||
376 | | ((u64)p[3] << 24) | ((u64)p[4] << 32); | ||
377 | p += 5; | ||
378 | } | ||
379 | |||
380 | kfree(buf); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* get V' 160-bit SHA-1 hash from repeater */ | ||
385 | static int get_vprime(struct tegra_nvhdcp *nvhdcp, u8 *v_prime) | ||
386 | { | ||
387 | int e, i; | ||
388 | |||
389 | for (i = 0; i < 20; i += 4) { | ||
390 | e = nvhdcp_i2c_read(nvhdcp, 0x20 + i, 4, v_prime + i); | ||
391 | if (e) | ||
392 | return e; | ||
393 | } | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | |||
398 | /* set or clear RUN_YES */ | ||
399 | static void hdcp_ctrl_run(struct tegra_dc_hdmi_data *hdmi, bool v) | ||
400 | { | ||
401 | u32 ctrl; | ||
402 | |||
403 | if (v) { | ||
404 | ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
405 | ctrl |= HDCP_RUN_YES; | ||
406 | } else { | ||
407 | ctrl = 0; | ||
408 | } | ||
409 | |||
410 | tegra_hdmi_writel(hdmi, ctrl, HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
411 | } | ||
412 | |||
413 | /* wait for any bits in mask to be set in HDMI_NV_PDISP_RG_HDCP_CTRL | ||
414 | * sleeps up to 120mS */ | ||
415 | static int wait_hdcp_ctrl(struct tegra_dc_hdmi_data *hdmi, u32 mask, u32 *v) | ||
416 | { | ||
417 | int retries = 13; | ||
418 | u32 ctrl; | ||
419 | |||
420 | do { | ||
421 | ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
422 | if ((ctrl & mask)) { | ||
423 | if (v) | ||
424 | *v = ctrl; | ||
425 | break; | ||
426 | } | ||
427 | if (retries > 1) | ||
428 | msleep(10); | ||
429 | } while (--retries); | ||
430 | if (!retries) { | ||
431 | nvhdcp_err("ctrl read timeout (mask=0x%x)\n", mask); | ||
432 | return -EIO; | ||
433 | } | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /* wait for bits in mask to be set to value in HDMI_NV_PDISP_KEY_CTRL | ||
438 | * waits up to 100mS */ | ||
439 | static int wait_key_ctrl(struct tegra_dc_hdmi_data *hdmi, u32 mask, u32 value) | ||
440 | { | ||
441 | int retries = 101; | ||
442 | u32 ctrl; | ||
443 | |||
444 | do { | ||
445 | msleep(1); | ||
446 | ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_KEY_CTRL); | ||
447 | if (((ctrl ^ value) & mask) == 0) | ||
448 | break; | ||
449 | } while (--retries); | ||
450 | if (!retries) { | ||
451 | nvhdcp_err("key ctrl read timeout (mask=0x%x)\n", mask); | ||
452 | return -EIO; | ||
453 | } | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | /* check that key selection vector is well formed. | ||
458 | * NOTE: this function assumes KSV has already been checked against | ||
459 | * revocation list. | ||
460 | */ | ||
461 | static int verify_ksv(u64 k) | ||
462 | { | ||
463 | unsigned i; | ||
464 | |||
465 | /* count set bits, must be exactly 20 set to be valid */ | ||
466 | for(i = 0; k; i++) | ||
467 | k ^= k & -k; | ||
468 | |||
469 | return (i != 20) ? -EINVAL : 0; | ||
470 | } | ||
471 | |||
472 | /* get Status and Kprime signature - READ_S on TMDS0_LINK0 only */ | ||
473 | static int get_s_prime(struct tegra_nvhdcp *nvhdcp, struct tegra_nvhdcp_packet *pkt) | ||
474 | { | ||
475 | struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi; | ||
476 | u32 sp_msb, sp_lsb1, sp_lsb2; | ||
477 | int e; | ||
478 | |||
479 | /* if connection isn't authenticated ... */ | ||
480 | mutex_lock(&nvhdcp->lock); | ||
481 | if (nvhdcp->state != STATE_LINK_VERIFY) { | ||
482 | memset(pkt, 0, sizeof *pkt); | ||
483 | pkt->packet_results = TEGRA_NVHDCP_RESULT_LINK_FAILED; | ||
484 | e = 0; | ||
485 | goto err; | ||
486 | } | ||
487 | |||
488 | pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL; | ||
489 | |||
490 | /* we will be taking c_n, c_ksv as input */ | ||
491 | if (!(pkt->value_flags & TEGRA_NVHDCP_FLAG_CN) | ||
492 | || !(pkt->value_flags & TEGRA_NVHDCP_FLAG_CKSV)) { | ||
493 | nvhdcp_err("missing value_flags (0x%x)\n", pkt->value_flags); | ||
494 | e = -EINVAL; | ||
495 | goto err; | ||
496 | } | ||
497 | |||
498 | pkt->value_flags = 0; | ||
499 | |||
500 | pkt->a_ksv = nvhdcp->a_ksv; | ||
501 | pkt->a_n = nvhdcp->a_n; | ||
502 | pkt->value_flags = TEGRA_NVHDCP_FLAG_AKSV | TEGRA_NVHDCP_FLAG_AN; | ||
503 | |||
504 | nvhdcp_vdbg("%s():cn %llx cksv %llx\n", __func__, pkt->c_n, pkt->c_ksv); | ||
505 | |||
506 | set_cn(hdmi, pkt->c_n); | ||
507 | |||
508 | tegra_hdmi_writel(hdmi, TMDS0_LINK0 | READ_S, | ||
509 | HDMI_NV_PDISP_RG_HDCP_CMODE); | ||
510 | |||
511 | set_cksv(hdmi, pkt->c_ksv); | ||
512 | |||
513 | e = wait_hdcp_ctrl(hdmi, SPRIME_VALID, NULL); | ||
514 | if (e) { | ||
515 | nvhdcp_err("Sprime read timeout\n"); | ||
516 | pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL; | ||
517 | e = -EIO; | ||
518 | goto err; | ||
519 | } | ||
520 | |||
521 | msleep(50); | ||
522 | |||
523 | /* read 56-bit Sprime plus 16 status bits */ | ||
524 | sp_msb = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB); | ||
525 | sp_lsb1 = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1); | ||
526 | sp_lsb2 = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2); | ||
527 | |||
528 | /* top 8 bits of LSB2 and bottom 8 bits of MSB hold status bits. */ | ||
529 | pkt->hdcp_status = ( sp_msb << 8 ) | ( sp_lsb2 >> 24); | ||
530 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_S; | ||
531 | |||
532 | /* 56-bit Kprime */ | ||
533 | pkt->k_prime = ((u64)(sp_lsb2 & 0xffffff) << 32) | sp_lsb1; | ||
534 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_KP; | ||
535 | |||
536 | /* is connection state supported? */ | ||
537 | if (sp_msb & STATUS_CS) { | ||
538 | pkt->cs = get_cs(hdmi); | ||
539 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_CS; | ||
540 | } | ||
541 | |||
542 | /* load Dksv */ | ||
543 | pkt->d_ksv = get_dksv(hdmi); | ||
544 | if (verify_ksv(pkt->d_ksv)) { | ||
545 | nvhdcp_err("Dksv invalid!\n"); | ||
546 | pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL; | ||
547 | e = -EIO; /* treat bad Dksv as I/O error */ | ||
548 | } | ||
549 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_DKSV; | ||
550 | |||
551 | /* copy current Bksv */ | ||
552 | pkt->b_ksv = nvhdcp->b_ksv; | ||
553 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_BKSV; | ||
554 | |||
555 | pkt->packet_results = TEGRA_NVHDCP_RESULT_SUCCESS; | ||
556 | mutex_unlock(&nvhdcp->lock); | ||
557 | return 0; | ||
558 | |||
559 | err: | ||
560 | mutex_unlock(&nvhdcp->lock); | ||
561 | return e; | ||
562 | } | ||
563 | |||
564 | /* get M prime - READ_M on TMDS0_LINK0 only */ | ||
565 | static inline int get_m_prime(struct tegra_nvhdcp *nvhdcp, struct tegra_nvhdcp_packet *pkt) | ||
566 | { | ||
567 | struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi; | ||
568 | int e; | ||
569 | |||
570 | pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL; | ||
571 | |||
572 | /* if connection isn't authenticated ... */ | ||
573 | mutex_lock(&nvhdcp->lock); | ||
574 | if (nvhdcp->state != STATE_LINK_VERIFY) { | ||
575 | memset(pkt, 0, sizeof *pkt); | ||
576 | pkt->packet_results = TEGRA_NVHDCP_RESULT_LINK_FAILED; | ||
577 | e = 0; | ||
578 | goto err; | ||
579 | } | ||
580 | |||
581 | pkt->a_ksv = nvhdcp->a_ksv; | ||
582 | pkt->a_n = nvhdcp->a_n; | ||
583 | pkt->value_flags = TEGRA_NVHDCP_FLAG_AKSV | TEGRA_NVHDCP_FLAG_AN; | ||
584 | |||
585 | set_cn(hdmi, pkt->c_n); | ||
586 | |||
587 | tegra_hdmi_writel(hdmi, TMDS0_LINK0 | READ_M, | ||
588 | HDMI_NV_PDISP_RG_HDCP_CMODE); | ||
589 | |||
590 | /* Cksv write triggers Mprime update */ | ||
591 | set_cksv(hdmi, pkt->c_ksv); | ||
592 | |||
593 | e = wait_hdcp_ctrl(hdmi, MPRIME_VALID, NULL); | ||
594 | if (e) { | ||
595 | nvhdcp_err("Mprime read timeout\n"); | ||
596 | e = -EIO; | ||
597 | goto err; | ||
598 | } | ||
599 | msleep(50); | ||
600 | |||
601 | /* load Mprime */ | ||
602 | pkt->m_prime = get_mprime(hdmi); | ||
603 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_MP; | ||
604 | |||
605 | pkt->b_status = nvhdcp->b_status; | ||
606 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_BSTATUS; | ||
607 | |||
608 | /* copy most recent KSVFIFO, if it is non-zero */ | ||
609 | pkt->num_bksv_list = nvhdcp->num_bksv_list; | ||
610 | if( nvhdcp->num_bksv_list ) { | ||
611 | BUILD_BUG_ON(sizeof(pkt->bksv_list) != sizeof(nvhdcp->bksv_list)); | ||
612 | memcpy(pkt->bksv_list, nvhdcp->bksv_list, | ||
613 | nvhdcp->num_bksv_list * sizeof(*pkt->bksv_list)); | ||
614 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_BKSVLIST; | ||
615 | } | ||
616 | |||
617 | /* copy v_prime */ | ||
618 | BUILD_BUG_ON(sizeof(pkt->v_prime) != sizeof(nvhdcp->v_prime)); | ||
619 | memcpy(pkt->v_prime, nvhdcp->v_prime, sizeof(nvhdcp->v_prime)); | ||
620 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_V; | ||
621 | |||
622 | /* load Dksv */ | ||
623 | pkt->d_ksv = get_dksv(hdmi); | ||
624 | if (verify_ksv(pkt->d_ksv)) { | ||
625 | nvhdcp_err("Dksv invalid!\n"); | ||
626 | e = -EIO; | ||
627 | goto err; | ||
628 | } | ||
629 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_DKSV; | ||
630 | |||
631 | /* copy current Bksv */ | ||
632 | pkt->b_ksv = nvhdcp->b_ksv; | ||
633 | pkt->value_flags |= TEGRA_NVHDCP_FLAG_BKSV; | ||
634 | |||
635 | pkt->packet_results = TEGRA_NVHDCP_RESULT_SUCCESS; | ||
636 | mutex_unlock(&nvhdcp->lock); | ||
637 | return 0; | ||
638 | |||
639 | err: | ||
640 | mutex_unlock(&nvhdcp->lock); | ||
641 | return e; | ||
642 | } | ||
643 | |||
644 | static int load_kfuse(struct tegra_dc_hdmi_data *hdmi) | ||
645 | { | ||
646 | unsigned buf[KFUSE_DATA_SZ / 4]; | ||
647 | int e, i; | ||
648 | u32 ctrl; | ||
649 | u32 tmp; | ||
650 | int retries; | ||
651 | |||
652 | /* copy load kfuse into buffer - only needed for early Tegra parts */ | ||
653 | e = tegra_kfuse_read(buf, sizeof buf); | ||
654 | if (e) { | ||
655 | nvhdcp_err("Kfuse read failure\n"); | ||
656 | return e; | ||
657 | } | ||
658 | |||
659 | /* write the kfuse to HDMI SRAM */ | ||
660 | |||
661 | tegra_hdmi_writel(hdmi, 1, HDMI_NV_PDISP_KEY_CTRL); /* LOAD_KEYS */ | ||
662 | |||
663 | /* issue a reload */ | ||
664 | ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_KEY_CTRL); | ||
665 | tegra_hdmi_writel(hdmi, ctrl | PKEY_REQUEST_RELOAD_TRIGGER | ||
666 | | LOCAL_KEYS , HDMI_NV_PDISP_KEY_CTRL); | ||
667 | |||
668 | e = wait_key_ctrl(hdmi, PKEY_LOADED, PKEY_LOADED); | ||
669 | if (e) { | ||
670 | nvhdcp_err("key reload timeout\n"); | ||
671 | return -EIO; | ||
672 | } | ||
673 | |||
674 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_KEY_SKEY_INDEX); | ||
675 | |||
676 | /* wait for SRAM to be cleared */ | ||
677 | retries = 6; | ||
678 | do { | ||
679 | tmp = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_KEY_DEBUG0); | ||
680 | if ((tmp & 1) == 0) break; | ||
681 | if (retries > 1) | ||
682 | mdelay(1); | ||
683 | } while (--retries); | ||
684 | if (!retries) { | ||
685 | nvhdcp_err("key SRAM clear timeout\n"); | ||
686 | return -EIO; | ||
687 | } | ||
688 | |||
689 | for (i = 0; i < KFUSE_DATA_SZ / 4; i += 4) { | ||
690 | |||
691 | /* load 128-bits*/ | ||
692 | tegra_hdmi_writel(hdmi, buf[i], HDMI_NV_PDISP_KEY_HDCP_KEY_0); | ||
693 | tegra_hdmi_writel(hdmi, buf[i+1], HDMI_NV_PDISP_KEY_HDCP_KEY_1); | ||
694 | tegra_hdmi_writel(hdmi, buf[i+2], HDMI_NV_PDISP_KEY_HDCP_KEY_2); | ||
695 | tegra_hdmi_writel(hdmi, buf[i+3], HDMI_NV_PDISP_KEY_HDCP_KEY_3); | ||
696 | |||
697 | /* trigger LOAD_HDCP_KEY */ | ||
698 | tegra_hdmi_writel(hdmi, 0x100, HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); | ||
699 | |||
700 | tmp = LOCAL_KEYS | WRITE16; | ||
701 | if (i) | ||
702 | tmp |= AUTOINC; | ||
703 | tegra_hdmi_writel(hdmi, tmp, HDMI_NV_PDISP_KEY_CTRL); | ||
704 | |||
705 | /* wait for WRITE16 to complete */ | ||
706 | e = wait_key_ctrl(hdmi, 0x10, 0); /* WRITE16 */ | ||
707 | if (e) { | ||
708 | nvhdcp_err("key write timeout\n"); | ||
709 | return -EIO; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int verify_link(struct tegra_nvhdcp *nvhdcp, bool wait_ri) | ||
717 | { | ||
718 | struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi; | ||
719 | int retries = 3; | ||
720 | u16 old, rx, tx; | ||
721 | int e; | ||
722 | |||
723 | old = 0; | ||
724 | rx = 0; | ||
725 | tx = 0; | ||
726 | /* retry 3 times to deal with I2C link issues */ | ||
727 | do { | ||
728 | if (wait_ri) | ||
729 | old = get_transmitter_ri(hdmi); | ||
730 | |||
731 | e = get_receiver_ri(nvhdcp, &rx); | ||
732 | if (!e) { | ||
733 | if (!rx) { | ||
734 | nvhdcp_err("Ri is 0!\n"); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | tx = get_transmitter_ri(hdmi); | ||
739 | } else { | ||
740 | rx = ~tx; | ||
741 | msleep(50); | ||
742 | } | ||
743 | |||
744 | } while (wait_ri && --retries && old != tx); | ||
745 | |||
746 | nvhdcp_debug("R0 Ri poll:rx=0x%04x tx=0x%04x\n", rx, tx); | ||
747 | |||
748 | if (!nvhdcp_is_plugged(nvhdcp)) { | ||
749 | nvhdcp_err("aborting verify links - lost hdmi connection\n"); | ||
750 | return -EIO; | ||
751 | } | ||
752 | |||
753 | if (rx != tx) | ||
754 | return -EINVAL; | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int get_repeater_info(struct tegra_nvhdcp *nvhdcp) | ||
760 | { | ||
761 | int e, retries; | ||
762 | u8 b_caps; | ||
763 | u16 b_status; | ||
764 | |||
765 | nvhdcp_vdbg("repeater found:fetching repeater info\n"); | ||
766 | |||
767 | /* wait up to 5 seconds for READY on repeater */ | ||
768 | retries = 51; | ||
769 | do { | ||
770 | if (!nvhdcp_is_plugged(nvhdcp)) { | ||
771 | nvhdcp_err("disconnect while waiting for repeater\n"); | ||
772 | return -EIO; | ||
773 | } | ||
774 | |||
775 | e = get_bcaps(nvhdcp, &b_caps); | ||
776 | if (!e && (b_caps & BCAPS_READY)) { | ||
777 | nvhdcp_debug("Bcaps READY from repeater\n"); | ||
778 | break; | ||
779 | } | ||
780 | if (retries > 1) | ||
781 | msleep(100); | ||
782 | } while (--retries); | ||
783 | if (!retries) { | ||
784 | nvhdcp_err("repeater Bcaps read timeout\n"); | ||
785 | return -ETIMEDOUT; | ||
786 | } | ||
787 | |||
788 | memset(nvhdcp->v_prime, 0, sizeof nvhdcp->v_prime); | ||
789 | e = get_vprime(nvhdcp, nvhdcp->v_prime); | ||
790 | if (e) { | ||
791 | nvhdcp_err("repeater Vprime read failure!\n"); | ||
792 | return e; | ||
793 | } | ||
794 | |||
795 | e = nvhdcp_i2c_read16(nvhdcp, 0x41, &b_status); | ||
796 | if (e) { | ||
797 | nvhdcp_err("Bstatus read failure!\n"); | ||
798 | return e; | ||
799 | } | ||
800 | |||
801 | if (b_status & BSTATUS_MAX_DEVS_EXCEEDED) { | ||
802 | nvhdcp_err("repeater:max devices (0x%04x)\n", b_status); | ||
803 | return -EINVAL; | ||
804 | } | ||
805 | |||
806 | if (b_status & BSTATUS_MAX_CASCADE_EXCEEDED) { | ||
807 | nvhdcp_err("repeater:max cascade (0x%04x)\n", b_status); | ||
808 | return -EINVAL; | ||
809 | } | ||
810 | |||
811 | nvhdcp->b_status = b_status; | ||
812 | nvhdcp->num_bksv_list = b_status & 0x7f; | ||
813 | nvhdcp_vdbg("Bstatus 0x%x (devices: %d)\n", | ||
814 | b_status, nvhdcp->num_bksv_list); | ||
815 | |||
816 | memset(nvhdcp->bksv_list, 0, sizeof nvhdcp->bksv_list); | ||
817 | e = get_ksvfifo(nvhdcp, nvhdcp->num_bksv_list, nvhdcp->bksv_list); | ||
818 | if (e) { | ||
819 | nvhdcp_err("repeater:could not read KSVFIFO (err %d)\n", e); | ||
820 | return e; | ||
821 | } | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static void nvhdcp_downstream_worker(struct work_struct *work) | ||
827 | { | ||
828 | struct tegra_nvhdcp *nvhdcp = | ||
829 | container_of(to_delayed_work(work), struct tegra_nvhdcp, work); | ||
830 | struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi; | ||
831 | int e; | ||
832 | u8 b_caps; | ||
833 | u32 tmp; | ||
834 | u32 res; | ||
835 | |||
836 | nvhdcp_vdbg("%s():started thread %s\n", __func__, nvhdcp->name); | ||
837 | |||
838 | mutex_lock(&nvhdcp->lock); | ||
839 | if (nvhdcp->state == STATE_OFF) { | ||
840 | nvhdcp_err("nvhdcp failure - giving up\n"); | ||
841 | goto err; | ||
842 | } | ||
843 | nvhdcp->state = STATE_UNAUTHENTICATED; | ||
844 | |||
845 | /* check plug state to terminate early in case flush_workqueue() */ | ||
846 | if (!nvhdcp_is_plugged(nvhdcp)) { | ||
847 | nvhdcp_err("worker started while unplugged!\n"); | ||
848 | goto lost_hdmi; | ||
849 | } | ||
850 | nvhdcp_vdbg("%s():hpd=%d\n", __func__, nvhdcp->plugged); | ||
851 | |||
852 | nvhdcp->a_ksv = 0; | ||
853 | nvhdcp->b_ksv = 0; | ||
854 | nvhdcp->a_n = 0; | ||
855 | |||
856 | e = get_bcaps(nvhdcp, &b_caps); | ||
857 | if (e) { | ||
858 | nvhdcp_err("Bcaps read failure\n"); | ||
859 | goto failure; | ||
860 | } | ||
861 | |||
862 | nvhdcp_vdbg("read Bcaps = 0x%02x\n", b_caps); | ||
863 | |||
864 | nvhdcp_vdbg("kfuse loading ...\n"); | ||
865 | |||
866 | /* repeater flag in Bskv must be configured before loading fuses */ | ||
867 | set_bksv(hdmi, 0, (b_caps & BCAPS_REPEATER)); | ||
868 | |||
869 | e = load_kfuse(hdmi); | ||
870 | if (e) { | ||
871 | nvhdcp_err("kfuse could not be loaded\n"); | ||
872 | goto failure; | ||
873 | } | ||
874 | |||
875 | hdcp_ctrl_run(hdmi, 1); | ||
876 | |||
877 | nvhdcp_vdbg("wait AN_VALID ...\n"); | ||
878 | |||
879 | /* wait for hardware to generate HDCP values */ | ||
880 | e = wait_hdcp_ctrl(hdmi, AN_VALID | SROM_ERR, &res); | ||
881 | if (e) { | ||
882 | nvhdcp_err("An key generation timeout\n"); | ||
883 | goto failure; | ||
884 | } | ||
885 | if (res & SROM_ERR) { | ||
886 | nvhdcp_err("SROM error\n"); | ||
887 | goto failure; | ||
888 | } | ||
889 | |||
890 | msleep(25); | ||
891 | |||
892 | nvhdcp->a_ksv = get_aksv(hdmi); | ||
893 | nvhdcp->a_n = get_an(hdmi); | ||
894 | nvhdcp_vdbg("Aksv is 0x%016llx\n", nvhdcp->a_ksv); | ||
895 | nvhdcp_vdbg("An is 0x%016llx\n", nvhdcp->a_n); | ||
896 | if (verify_ksv(nvhdcp->a_ksv)) { | ||
897 | nvhdcp_err("Aksv verify failure! (0x%016llx)\n", nvhdcp->a_ksv); | ||
898 | goto disable; | ||
899 | } | ||
900 | |||
901 | /* write Ainfo to receiver - set 1.1 only if b_caps supports it */ | ||
902 | e = nvhdcp_i2c_write8(nvhdcp, 0x15, b_caps & BCAPS_11); | ||
903 | if (e) { | ||
904 | nvhdcp_err("Ainfo write failure\n"); | ||
905 | goto failure; | ||
906 | } | ||
907 | |||
908 | /* write An to receiver */ | ||
909 | e = nvhdcp_i2c_write64(nvhdcp, 0x18, nvhdcp->a_n); | ||
910 | if (e) { | ||
911 | nvhdcp_err("An write failure\n"); | ||
912 | goto failure; | ||
913 | } | ||
914 | |||
915 | nvhdcp_vdbg("wrote An = 0x%016llx\n", nvhdcp->a_n); | ||
916 | |||
917 | /* write Aksv to receiver - triggers auth sequence */ | ||
918 | e = nvhdcp_i2c_write40(nvhdcp, 0x10, nvhdcp->a_ksv); | ||
919 | if (e) { | ||
920 | nvhdcp_err("Aksv write failure\n"); | ||
921 | goto failure; | ||
922 | } | ||
923 | |||
924 | nvhdcp_vdbg("wrote Aksv = 0x%010llx\n", nvhdcp->a_ksv); | ||
925 | |||
926 | /* bail out if unplugged in the middle of negotiation */ | ||
927 | if (!nvhdcp_is_plugged(nvhdcp)) | ||
928 | goto lost_hdmi; | ||
929 | |||
930 | /* get Bksv from receiver */ | ||
931 | e = nvhdcp_i2c_read40(nvhdcp, 0x00, &nvhdcp->b_ksv); | ||
932 | if (e) { | ||
933 | nvhdcp_err("Bksv read failure\n"); | ||
934 | goto failure; | ||
935 | } | ||
936 | nvhdcp_vdbg("Bksv is 0x%016llx\n", nvhdcp->b_ksv); | ||
937 | if (verify_ksv(nvhdcp->b_ksv)) { | ||
938 | nvhdcp_err("Bksv verify failure!\n"); | ||
939 | goto failure; | ||
940 | } | ||
941 | |||
942 | nvhdcp_vdbg("read Bksv = 0x%010llx from device\n", nvhdcp->b_ksv); | ||
943 | |||
944 | set_bksv(hdmi, nvhdcp->b_ksv, (b_caps & BCAPS_REPEATER)); | ||
945 | |||
946 | nvhdcp_vdbg("loaded Bksv into controller\n"); | ||
947 | |||
948 | e = wait_hdcp_ctrl(hdmi, R0_VALID, NULL); | ||
949 | if (e) { | ||
950 | nvhdcp_err("R0 read failure!\n"); | ||
951 | goto failure; | ||
952 | } | ||
953 | |||
954 | nvhdcp_vdbg("R0 valid\n"); | ||
955 | |||
956 | msleep(100); /* can't read R0' within 100ms of writing Aksv */ | ||
957 | |||
958 | nvhdcp_vdbg("verifying links ...\n"); | ||
959 | |||
960 | e = verify_link(nvhdcp, false); | ||
961 | if (e) { | ||
962 | nvhdcp_err("link verification failed err %d\n", e); | ||
963 | goto failure; | ||
964 | } | ||
965 | |||
966 | /* if repeater then get repeater info */ | ||
967 | if (b_caps & BCAPS_REPEATER) { | ||
968 | e = get_repeater_info(nvhdcp); | ||
969 | if (e) { | ||
970 | nvhdcp_err("get repeater info failed\n"); | ||
971 | goto failure; | ||
972 | } | ||
973 | } | ||
974 | |||
975 | tmp = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
976 | tmp |= CRYPT_ENABLED; | ||
977 | if (b_caps & BCAPS_11) /* HDCP 1.1 ? */ | ||
978 | tmp |= ONEONE_ENABLED; | ||
979 | tegra_hdmi_writel(hdmi, tmp, HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
980 | |||
981 | nvhdcp_vdbg("CRYPT enabled\n"); | ||
982 | |||
983 | nvhdcp->state = STATE_LINK_VERIFY; | ||
984 | nvhdcp_info("link verified!\n"); | ||
985 | |||
986 | while (1) { | ||
987 | if (!nvhdcp_is_plugged(nvhdcp)) | ||
988 | goto lost_hdmi; | ||
989 | |||
990 | if (nvhdcp->state != STATE_LINK_VERIFY) | ||
991 | goto failure; | ||
992 | |||
993 | e = verify_link(nvhdcp, true); | ||
994 | if (e) { | ||
995 | nvhdcp_err("link verification failed err %d\n", e); | ||
996 | goto failure; | ||
997 | } | ||
998 | mutex_unlock(&nvhdcp->lock); | ||
999 | wait_event_interruptible_timeout(wq_worker, | ||
1000 | !nvhdcp_is_plugged(nvhdcp), msecs_to_jiffies(1500)); | ||
1001 | mutex_lock(&nvhdcp->lock); | ||
1002 | |||
1003 | } | ||
1004 | |||
1005 | failure: | ||
1006 | nvhdcp->fail_count++; | ||
1007 | if(nvhdcp->fail_count > 5) { | ||
1008 | nvhdcp_err("nvhdcp failure - too many failures, giving up!\n"); | ||
1009 | } else { | ||
1010 | nvhdcp_err("nvhdcp failure - renegotiating in 1 second\n"); | ||
1011 | if (!nvhdcp_is_plugged(nvhdcp)) | ||
1012 | goto lost_hdmi; | ||
1013 | queue_delayed_work(nvhdcp->downstream_wq, &nvhdcp->work, | ||
1014 | msecs_to_jiffies(1000)); | ||
1015 | } | ||
1016 | |||
1017 | lost_hdmi: | ||
1018 | nvhdcp->state = STATE_UNAUTHENTICATED; | ||
1019 | hdcp_ctrl_run(hdmi, 0); | ||
1020 | |||
1021 | err: | ||
1022 | mutex_unlock(&nvhdcp->lock); | ||
1023 | return; | ||
1024 | disable: | ||
1025 | nvhdcp->state = STATE_OFF; | ||
1026 | nvhdcp_set_plugged(nvhdcp, false); | ||
1027 | mutex_unlock(&nvhdcp->lock); | ||
1028 | return; | ||
1029 | } | ||
1030 | |||
1031 | static int tegra_nvhdcp_on(struct tegra_nvhdcp *nvhdcp) | ||
1032 | { | ||
1033 | nvhdcp->state = STATE_UNAUTHENTICATED; | ||
1034 | if (nvhdcp_is_plugged(nvhdcp)) { | ||
1035 | nvhdcp->fail_count = 0; | ||
1036 | queue_delayed_work(nvhdcp->downstream_wq, &nvhdcp->work, | ||
1037 | msecs_to_jiffies(100)); | ||
1038 | } | ||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | static int tegra_nvhdcp_off(struct tegra_nvhdcp *nvhdcp) | ||
1043 | { | ||
1044 | mutex_lock(&nvhdcp->lock); | ||
1045 | nvhdcp->state = STATE_OFF; | ||
1046 | nvhdcp_set_plugged(nvhdcp, false); | ||
1047 | mutex_unlock(&nvhdcp->lock); | ||
1048 | wake_up_interruptible(&wq_worker); | ||
1049 | flush_workqueue(nvhdcp->downstream_wq); | ||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd) | ||
1054 | { | ||
1055 | nvhdcp_debug("hdmi hotplug detected (hpd = %d)\n", hpd); | ||
1056 | |||
1057 | if (hpd) { | ||
1058 | nvhdcp_set_plugged(nvhdcp, true); | ||
1059 | tegra_nvhdcp_on(nvhdcp); | ||
1060 | } else { | ||
1061 | tegra_nvhdcp_off(nvhdcp); | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol) | ||
1066 | { | ||
1067 | if (pol == TEGRA_NVHDCP_POLICY_ALWAYS_ON) { | ||
1068 | nvhdcp_info("using \"always on\" policy.\n"); | ||
1069 | if (atomic_xchg(&nvhdcp->policy, pol) != pol) { | ||
1070 | /* policy changed, start working */ | ||
1071 | tegra_nvhdcp_on(nvhdcp); | ||
1072 | } | ||
1073 | } else { | ||
1074 | /* unsupported policy */ | ||
1075 | return -EINVAL; | ||
1076 | } | ||
1077 | |||
1078 | return 0; | ||
1079 | } | ||
1080 | |||
1081 | static int tegra_nvhdcp_renegotiate(struct tegra_nvhdcp *nvhdcp) | ||
1082 | { | ||
1083 | mutex_lock(&nvhdcp->lock); | ||
1084 | nvhdcp->state = STATE_RENEGOTIATE; | ||
1085 | mutex_unlock(&nvhdcp->lock); | ||
1086 | tegra_nvhdcp_on(nvhdcp); | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp) | ||
1091 | { | ||
1092 | if (!nvhdcp) return; | ||
1093 | tegra_nvhdcp_off(nvhdcp); | ||
1094 | } | ||
1095 | |||
1096 | void tegra_nvhdcp_resume(struct tegra_nvhdcp *nvhdcp) | ||
1097 | { | ||
1098 | if (!nvhdcp) return; | ||
1099 | tegra_nvhdcp_renegotiate(nvhdcp); | ||
1100 | } | ||
1101 | |||
1102 | static long nvhdcp_dev_ioctl(struct file *filp, | ||
1103 | unsigned int cmd, unsigned long arg) | ||
1104 | { | ||
1105 | struct tegra_nvhdcp *nvhdcp = filp->private_data; | ||
1106 | struct tegra_nvhdcp_packet *pkt; | ||
1107 | int e = -ENOTTY; | ||
1108 | |||
1109 | switch (cmd) { | ||
1110 | case TEGRAIO_NVHDCP_ON: | ||
1111 | return tegra_nvhdcp_on(nvhdcp); | ||
1112 | |||
1113 | case TEGRAIO_NVHDCP_OFF: | ||
1114 | return tegra_nvhdcp_off(nvhdcp); | ||
1115 | |||
1116 | case TEGRAIO_NVHDCP_SET_POLICY: | ||
1117 | return tegra_nvhdcp_set_policy(nvhdcp, arg); | ||
1118 | |||
1119 | case TEGRAIO_NVHDCP_READ_M: | ||
1120 | pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); | ||
1121 | if (!pkt) | ||
1122 | return -ENOMEM; | ||
1123 | if (copy_from_user(pkt, (void __user *)arg, sizeof(*pkt))) { | ||
1124 | e = -EFAULT; | ||
1125 | goto kfree_pkt; | ||
1126 | } | ||
1127 | e = get_m_prime(nvhdcp, pkt); | ||
1128 | if (copy_to_user((void __user *)arg, pkt, sizeof(*pkt))) { | ||
1129 | e = -EFAULT; | ||
1130 | goto kfree_pkt; | ||
1131 | } | ||
1132 | kfree(pkt); | ||
1133 | return e; | ||
1134 | |||
1135 | case TEGRAIO_NVHDCP_READ_S: | ||
1136 | pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); | ||
1137 | if (!pkt) | ||
1138 | return -ENOMEM; | ||
1139 | if (copy_from_user(pkt, (void __user *)arg, sizeof(*pkt))) { | ||
1140 | e = -EFAULT; | ||
1141 | goto kfree_pkt; | ||
1142 | } | ||
1143 | e = get_s_prime(nvhdcp, pkt); | ||
1144 | if (copy_to_user((void __user *)arg, pkt, sizeof(*pkt))) { | ||
1145 | e = -EFAULT; | ||
1146 | goto kfree_pkt; | ||
1147 | } | ||
1148 | kfree(pkt); | ||
1149 | return e; | ||
1150 | |||
1151 | case TEGRAIO_NVHDCP_RENEGOTIATE: | ||
1152 | e = tegra_nvhdcp_renegotiate(nvhdcp); | ||
1153 | break; | ||
1154 | } | ||
1155 | |||
1156 | return e; | ||
1157 | kfree_pkt: | ||
1158 | kfree(pkt); | ||
1159 | return e; | ||
1160 | } | ||
1161 | |||
1162 | static int nvhdcp_dev_open(struct inode *inode, struct file *filp) | ||
1163 | { | ||
1164 | struct miscdevice *miscdev = filp->private_data; | ||
1165 | struct tegra_nvhdcp *nvhdcp = | ||
1166 | container_of(miscdev, struct tegra_nvhdcp, miscdev); | ||
1167 | filp->private_data = nvhdcp; | ||
1168 | return 0; | ||
1169 | } | ||
1170 | |||
1171 | static int nvhdcp_dev_release(struct inode *inode, struct file *filp) | ||
1172 | { | ||
1173 | filp->private_data = NULL; | ||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | static const struct file_operations nvhdcp_fops = { | ||
1178 | .owner = THIS_MODULE, | ||
1179 | .llseek = no_llseek, | ||
1180 | .unlocked_ioctl = nvhdcp_dev_ioctl, | ||
1181 | .open = nvhdcp_dev_open, | ||
1182 | .release = nvhdcp_dev_release, | ||
1183 | }; | ||
1184 | |||
1185 | /* we only support one AP right now, so should only call this once. */ | ||
1186 | struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi, | ||
1187 | int id, int bus) | ||
1188 | { | ||
1189 | static struct tegra_nvhdcp *nvhdcp; /* prevent multiple calls */ | ||
1190 | struct i2c_adapter *adapter; | ||
1191 | int e; | ||
1192 | |||
1193 | if (nvhdcp) | ||
1194 | return ERR_PTR(-EMFILE); | ||
1195 | |||
1196 | nvhdcp = kzalloc(sizeof(*nvhdcp), GFP_KERNEL); | ||
1197 | if (!nvhdcp) | ||
1198 | return ERR_PTR(-ENOMEM); | ||
1199 | |||
1200 | nvhdcp->id = id; | ||
1201 | snprintf(nvhdcp->name, sizeof(nvhdcp->name), "nvhdcp%u", id); | ||
1202 | nvhdcp->hdmi = hdmi; | ||
1203 | mutex_init(&nvhdcp->lock); | ||
1204 | |||
1205 | strlcpy(nvhdcp->info.type, nvhdcp->name, sizeof(nvhdcp->info.type)); | ||
1206 | nvhdcp->bus = bus; | ||
1207 | nvhdcp->info.addr = 0x74 >> 1; | ||
1208 | nvhdcp->info.platform_data = nvhdcp; | ||
1209 | nvhdcp->fail_count = 0; | ||
1210 | |||
1211 | adapter = i2c_get_adapter(bus); | ||
1212 | if (!adapter) { | ||
1213 | nvhdcp_err("can't get adapter for bus %d\n", bus); | ||
1214 | e = -EBUSY; | ||
1215 | goto free_nvhdcp; | ||
1216 | } | ||
1217 | |||
1218 | nvhdcp->client = i2c_new_device(adapter, &nvhdcp->info); | ||
1219 | i2c_put_adapter(adapter); | ||
1220 | |||
1221 | if (!nvhdcp->client) { | ||
1222 | nvhdcp_err("can't create new device\n"); | ||
1223 | e = -EBUSY; | ||
1224 | goto free_nvhdcp; | ||
1225 | } | ||
1226 | |||
1227 | nvhdcp->state = STATE_UNAUTHENTICATED; | ||
1228 | |||
1229 | nvhdcp->downstream_wq = create_singlethread_workqueue(nvhdcp->name); | ||
1230 | INIT_DELAYED_WORK(&nvhdcp->work, nvhdcp_downstream_worker); | ||
1231 | |||
1232 | nvhdcp->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
1233 | nvhdcp->miscdev.name = nvhdcp->name; | ||
1234 | nvhdcp->miscdev.fops = &nvhdcp_fops; | ||
1235 | |||
1236 | e = misc_register(&nvhdcp->miscdev); | ||
1237 | if (e) | ||
1238 | goto free_workqueue; | ||
1239 | |||
1240 | nvhdcp_vdbg("%s(): created misc device %s\n", __func__, nvhdcp->name); | ||
1241 | |||
1242 | return nvhdcp; | ||
1243 | free_workqueue: | ||
1244 | destroy_workqueue(nvhdcp->downstream_wq); | ||
1245 | i2c_release_client(nvhdcp->client); | ||
1246 | free_nvhdcp: | ||
1247 | kfree(nvhdcp); | ||
1248 | nvhdcp_err("unable to create device.\n"); | ||
1249 | return ERR_PTR(e); | ||
1250 | } | ||
1251 | |||
1252 | void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp) | ||
1253 | { | ||
1254 | misc_deregister(&nvhdcp->miscdev); | ||
1255 | tegra_nvhdcp_off(nvhdcp); | ||
1256 | destroy_workqueue(nvhdcp->downstream_wq); | ||
1257 | i2c_release_client(nvhdcp->client); | ||
1258 | kfree(nvhdcp); | ||
1259 | } | ||
diff --git a/drivers/video/tegra/dc/nvhdcp.h b/drivers/video/tegra/dc/nvhdcp.h new file mode 100644 index 00000000000..90ea0be36d1 --- /dev/null +++ b/drivers/video/tegra/dc/nvhdcp.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/nvhdcp.h | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_NVHDCP_H | ||
18 | #define __DRIVERS_VIDEO_TEGRA_DC_NVHDCP_H | ||
19 | #include <video/nvhdcp.h> | ||
20 | |||
21 | struct tegra_nvhdcp; | ||
22 | #ifdef CONFIG_TEGRA_NVHDCP | ||
23 | void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd); | ||
24 | int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol); | ||
25 | void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp); | ||
26 | void tegra_nvhdcp_resume(struct tegra_nvhdcp *nvhdcp); | ||
27 | struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi, | ||
28 | int id, int bus); | ||
29 | void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp); | ||
30 | #else | ||
31 | inline void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd) { } | ||
32 | inline int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | inline void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp) { } | ||
37 | inline void tegra_nvhdcp_resume(struct tegra_nvhdcp *nvhdcp) { } | ||
38 | inline struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi, | ||
39 | int id, int bus) | ||
40 | { | ||
41 | return NULL; | ||
42 | } | ||
43 | inline void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp) { } | ||
44 | #endif | ||
45 | |||
46 | #endif | ||
diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c new file mode 100644 index 00000000000..a2f3ece6ae7 --- /dev/null +++ b/drivers/video/tegra/dc/nvsd.c | |||
@@ -0,0 +1,906 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/nvsd.c | ||
3 | * | ||
4 | * Copyright (c) 2010-2012, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <mach/dc.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/backlight.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include "dc_reg.h" | ||
26 | #include "dc_priv.h" | ||
27 | #include "nvsd.h" | ||
28 | |||
29 | /* Elements for sysfs access */ | ||
30 | #define NVSD_ATTR(__name) static struct kobj_attribute nvsd_attr_##__name = \ | ||
31 | __ATTR(__name, S_IRUGO|S_IWUSR, nvsd_settings_show, nvsd_settings_store) | ||
32 | #define NVSD_ATTRS_ENTRY(__name) (&nvsd_attr_##__name.attr) | ||
33 | #define IS_NVSD_ATTR(__name) (attr == &nvsd_attr_##__name) | ||
34 | |||
35 | static ssize_t nvsd_settings_show(struct kobject *kobj, | ||
36 | struct kobj_attribute *attr, char *buf); | ||
37 | |||
38 | static ssize_t nvsd_settings_store(struct kobject *kobj, | ||
39 | struct kobj_attribute *attr, const char *buf, size_t count); | ||
40 | |||
41 | static ssize_t nvsd_registers_show(struct kobject *kobj, | ||
42 | struct kobj_attribute *attr, char *buf); | ||
43 | |||
44 | NVSD_ATTR(enable); | ||
45 | NVSD_ATTR(aggressiveness); | ||
46 | NVSD_ATTR(phase_in_settings); | ||
47 | NVSD_ATTR(phase_in_adjustments); | ||
48 | NVSD_ATTR(bin_width); | ||
49 | NVSD_ATTR(hw_update_delay); | ||
50 | NVSD_ATTR(use_vid_luma); | ||
51 | NVSD_ATTR(coeff); | ||
52 | NVSD_ATTR(blp_time_constant); | ||
53 | NVSD_ATTR(blp_step); | ||
54 | NVSD_ATTR(fc_time_limit); | ||
55 | NVSD_ATTR(fc_threshold); | ||
56 | NVSD_ATTR(lut); | ||
57 | NVSD_ATTR(bltf); | ||
58 | static struct kobj_attribute nvsd_attr_registers = | ||
59 | __ATTR(registers, S_IRUGO, nvsd_registers_show, NULL); | ||
60 | |||
61 | static struct attribute *nvsd_attrs[] = { | ||
62 | NVSD_ATTRS_ENTRY(enable), | ||
63 | NVSD_ATTRS_ENTRY(aggressiveness), | ||
64 | NVSD_ATTRS_ENTRY(phase_in_settings), | ||
65 | NVSD_ATTRS_ENTRY(phase_in_adjustments), | ||
66 | NVSD_ATTRS_ENTRY(bin_width), | ||
67 | NVSD_ATTRS_ENTRY(hw_update_delay), | ||
68 | NVSD_ATTRS_ENTRY(use_vid_luma), | ||
69 | NVSD_ATTRS_ENTRY(coeff), | ||
70 | NVSD_ATTRS_ENTRY(blp_time_constant), | ||
71 | NVSD_ATTRS_ENTRY(blp_step), | ||
72 | NVSD_ATTRS_ENTRY(fc_time_limit), | ||
73 | NVSD_ATTRS_ENTRY(fc_threshold), | ||
74 | NVSD_ATTRS_ENTRY(lut), | ||
75 | NVSD_ATTRS_ENTRY(bltf), | ||
76 | NVSD_ATTRS_ENTRY(registers), | ||
77 | NULL, | ||
78 | }; | ||
79 | |||
80 | static struct attribute_group nvsd_attr_group = { | ||
81 | .attrs = nvsd_attrs, | ||
82 | }; | ||
83 | |||
84 | static struct kobject *nvsd_kobj; | ||
85 | |||
86 | /* shared brightness variable */ | ||
87 | static atomic_t *sd_brightness = NULL; | ||
88 | /* shared boolean for manual K workaround */ | ||
89 | static atomic_t man_k_until_blank = ATOMIC_INIT(0); | ||
90 | |||
91 | static u8 nvsd_get_bw_idx(struct tegra_dc_sd_settings *settings) | ||
92 | { | ||
93 | u8 bw; | ||
94 | |||
95 | switch (settings->bin_width) { | ||
96 | default: | ||
97 | case -1: | ||
98 | /* A -1 bin-width indicates 'automatic' | ||
99 | based upon aggressiveness. */ | ||
100 | settings->bin_width = -1; | ||
101 | switch (settings->aggressiveness) { | ||
102 | default: | ||
103 | case 0: | ||
104 | case 1: | ||
105 | bw = SD_BIN_WIDTH_ONE; | ||
106 | break; | ||
107 | case 2: | ||
108 | case 3: | ||
109 | case 4: | ||
110 | bw = SD_BIN_WIDTH_TWO; | ||
111 | break; | ||
112 | case 5: | ||
113 | bw = SD_BIN_WIDTH_FOUR; | ||
114 | break; | ||
115 | } | ||
116 | break; | ||
117 | case 1: | ||
118 | bw = SD_BIN_WIDTH_ONE; | ||
119 | break; | ||
120 | case 2: | ||
121 | bw = SD_BIN_WIDTH_TWO; | ||
122 | break; | ||
123 | case 4: | ||
124 | bw = SD_BIN_WIDTH_FOUR; | ||
125 | break; | ||
126 | case 8: | ||
127 | bw = SD_BIN_WIDTH_EIGHT; | ||
128 | break; | ||
129 | } | ||
130 | return bw >> 3; | ||
131 | |||
132 | } | ||
133 | |||
134 | static bool nvsd_phase_in_adjustments(struct tegra_dc *dc, | ||
135 | struct tegra_dc_sd_settings *settings) | ||
136 | { | ||
137 | u8 step, cur_sd_brightness; | ||
138 | u16 target_k, cur_k; | ||
139 | u32 man_k, val; | ||
140 | |||
141 | cur_sd_brightness = atomic_read(sd_brightness); | ||
142 | |||
143 | target_k = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); | ||
144 | target_k = SD_HW_K_R(target_k); | ||
145 | cur_k = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES); | ||
146 | cur_k = SD_HW_K_R(cur_k); | ||
147 | |||
148 | /* read brightness value */ | ||
149 | val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL); | ||
150 | val = SD_BLC_BRIGHTNESS(val); | ||
151 | |||
152 | step = settings->phase_adj_step; | ||
153 | if (cur_sd_brightness != val || target_k != cur_k) { | ||
154 | if (!step) | ||
155 | step = ADJ_PHASE_STEP; | ||
156 | |||
157 | /* Phase in Backlight and Pixel K | ||
158 | every ADJ_PHASE_STEP frames*/ | ||
159 | if ((step-- & ADJ_PHASE_STEP) == ADJ_PHASE_STEP) { | ||
160 | |||
161 | if (val != cur_sd_brightness) | ||
162 | val > cur_sd_brightness ? | ||
163 | (cur_sd_brightness++) : | ||
164 | (cur_sd_brightness--); | ||
165 | |||
166 | if (target_k != cur_k) { | ||
167 | if (target_k > cur_k) | ||
168 | cur_k += K_STEP; | ||
169 | else | ||
170 | cur_k -= K_STEP; | ||
171 | } | ||
172 | |||
173 | /* Set manual k value */ | ||
174 | man_k = SD_MAN_K_R(cur_k) | | ||
175 | SD_MAN_K_G(cur_k) | SD_MAN_K_B(cur_k); | ||
176 | tegra_dc_writel(dc, man_k, DC_DISP_SD_MAN_K_VALUES); | ||
177 | /* Set manual brightness value */ | ||
178 | atomic_set(sd_brightness, cur_sd_brightness); | ||
179 | } | ||
180 | settings->phase_adj_step = step; | ||
181 | return true; | ||
182 | } else | ||
183 | return false; | ||
184 | } | ||
185 | |||
186 | /* phase in the luts based on the current and max step */ | ||
187 | static void nvsd_phase_in_luts(struct tegra_dc_sd_settings *settings, | ||
188 | struct tegra_dc *dc) | ||
189 | { | ||
190 | u32 val; | ||
191 | u8 bw_idx; | ||
192 | int i; | ||
193 | u16 phase_settings_step = settings->phase_settings_step; | ||
194 | u16 num_phase_in_steps = settings->num_phase_in_steps; | ||
195 | |||
196 | bw_idx = nvsd_get_bw_idx(settings); | ||
197 | |||
198 | /* Phase in Final LUT */ | ||
199 | for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) { | ||
200 | val = SD_LUT_R((settings->lut[bw_idx][i].r * | ||
201 | phase_settings_step)/num_phase_in_steps) | | ||
202 | SD_LUT_G((settings->lut[bw_idx][i].g * | ||
203 | phase_settings_step)/num_phase_in_steps) | | ||
204 | SD_LUT_B((settings->lut[bw_idx][i].b * | ||
205 | phase_settings_step)/num_phase_in_steps); | ||
206 | |||
207 | tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i)); | ||
208 | } | ||
209 | /* Phase in Final BLTF */ | ||
210 | for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) { | ||
211 | val = SD_BL_TF_POINT_0(255-((255-settings->bltf[bw_idx][i][0]) | ||
212 | * phase_settings_step)/num_phase_in_steps) | | ||
213 | SD_BL_TF_POINT_1(255-((255-settings->bltf[bw_idx][i][1]) | ||
214 | * phase_settings_step)/num_phase_in_steps) | | ||
215 | SD_BL_TF_POINT_2(255-((255-settings->bltf[bw_idx][i][2]) | ||
216 | * phase_settings_step)/num_phase_in_steps) | | ||
217 | SD_BL_TF_POINT_3(255-((255-settings->bltf[bw_idx][i][3]) | ||
218 | * phase_settings_step)/num_phase_in_steps); | ||
219 | |||
220 | tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i)); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /* handle the commands that may be invoked for phase_in_settings */ | ||
225 | static void nvsd_cmd_handler(struct tegra_dc_sd_settings *settings, | ||
226 | struct tegra_dc *dc) | ||
227 | { | ||
228 | u32 val; | ||
229 | u8 bw_idx, bw; | ||
230 | |||
231 | if (settings->cmd & ENABLE) { | ||
232 | settings->phase_settings_step++; | ||
233 | if (settings->phase_settings_step >= | ||
234 | settings->num_phase_in_steps) | ||
235 | settings->cmd &= ~ENABLE; | ||
236 | |||
237 | nvsd_phase_in_luts(settings, dc); | ||
238 | } | ||
239 | if (settings->cmd & DISABLE) { | ||
240 | settings->phase_settings_step--; | ||
241 | nvsd_phase_in_luts(settings, dc); | ||
242 | if (settings->phase_settings_step == 0) { | ||
243 | /* finish up aggressiveness phase in */ | ||
244 | if (settings->cmd & AGG_CHG) | ||
245 | settings->aggressiveness = settings->final_agg; | ||
246 | settings->cmd = NO_CMD; | ||
247 | settings->enable = 0; | ||
248 | nvsd_init(dc, settings); | ||
249 | } | ||
250 | } | ||
251 | if (settings->cmd & AGG_CHG) { | ||
252 | if (settings->aggressiveness == settings->final_agg) | ||
253 | settings->cmd &= ~AGG_CHG; | ||
254 | if ((settings->cur_agg_step++ & (STEPS_PER_AGG_CHG - 1)) == 0) { | ||
255 | settings->final_agg > settings->aggressiveness ? | ||
256 | settings->aggressiveness++ : | ||
257 | settings->aggressiveness--; | ||
258 | |||
259 | /* Update aggressiveness value in HW */ | ||
260 | val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); | ||
261 | val &= ~SD_AGGRESSIVENESS(0x7); | ||
262 | val |= SD_AGGRESSIVENESS(settings->aggressiveness); | ||
263 | |||
264 | /* Adjust bin_width for automatic setting */ | ||
265 | if (settings->bin_width == -1) { | ||
266 | bw_idx = nvsd_get_bw_idx(settings); | ||
267 | |||
268 | bw = bw_idx << 3; | ||
269 | |||
270 | val &= ~SD_BIN_WIDTH_MASK; | ||
271 | val |= bw; | ||
272 | } | ||
273 | tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); | ||
274 | |||
275 | nvsd_phase_in_luts(settings, dc); | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | static bool nvsd_update_enable(struct tegra_dc_sd_settings *settings, | ||
281 | int enable_val) | ||
282 | { | ||
283 | |||
284 | if (enable_val != 1 && enable_val != 0) | ||
285 | return false; | ||
286 | |||
287 | if (!settings->cmd && settings->enable != enable_val) { | ||
288 | settings->num_phase_in_steps = | ||
289 | STEPS_PER_AGG_LVL*settings->aggressiveness; | ||
290 | settings->phase_settings_step = enable_val ? | ||
291 | 0 : settings->num_phase_in_steps; | ||
292 | } | ||
293 | |||
294 | if (settings->enable != enable_val || settings->cmd & DISABLE) { | ||
295 | settings->cmd &= ~(ENABLE | DISABLE); | ||
296 | if (!settings->enable && enable_val) | ||
297 | settings->cmd |= PHASE_IN; | ||
298 | settings->cmd |= enable_val ? ENABLE : DISABLE; | ||
299 | return true; | ||
300 | } | ||
301 | |||
302 | return false; | ||
303 | } | ||
304 | |||
305 | static bool nvsd_update_agg(struct tegra_dc_sd_settings *settings, int agg_val) | ||
306 | { | ||
307 | int i; | ||
308 | int pri_lvl = SD_AGG_PRI_LVL(agg_val); | ||
309 | int agg_lvl = SD_GET_AGG(agg_val); | ||
310 | struct tegra_dc_sd_agg_priorities *sd_agg_priorities = | ||
311 | &settings->agg_priorities; | ||
312 | |||
313 | if (agg_lvl > 5 || agg_lvl < 0) | ||
314 | return false; | ||
315 | else if (agg_lvl == 0 && pri_lvl == 0) | ||
316 | return false; | ||
317 | |||
318 | if (pri_lvl >= 0 && pri_lvl < 4) | ||
319 | sd_agg_priorities->agg[pri_lvl] = agg_lvl; | ||
320 | |||
321 | for (i = NUM_AGG_PRI_LVLS - 1; i >= 0; i--) { | ||
322 | if (sd_agg_priorities->agg[i]) | ||
323 | break; | ||
324 | } | ||
325 | |||
326 | sd_agg_priorities->pri_lvl = i; | ||
327 | pri_lvl = i; | ||
328 | agg_lvl = sd_agg_priorities->agg[i]; | ||
329 | |||
330 | if (settings->phase_in_settings && settings->enable && | ||
331 | settings->aggressiveness != agg_lvl) { | ||
332 | |||
333 | settings->final_agg = agg_lvl; | ||
334 | settings->cmd |= AGG_CHG; | ||
335 | settings->cur_agg_step = 0; | ||
336 | return true; | ||
337 | } else if (settings->aggressiveness != agg_lvl) { | ||
338 | settings->aggressiveness = agg_lvl; | ||
339 | return true; | ||
340 | } | ||
341 | |||
342 | return false; | ||
343 | } | ||
344 | |||
345 | /* Functional initialization */ | ||
346 | void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) | ||
347 | { | ||
348 | u32 i = 0; | ||
349 | u32 val = 0; | ||
350 | u32 bw_idx = 0; | ||
351 | /* TODO: check if HW says SD's available */ | ||
352 | |||
353 | /* If SD's not present or disabled, clear the register and return. */ | ||
354 | if (!settings || settings->enable == 0) { | ||
355 | /* clear the brightness val, too. */ | ||
356 | if (sd_brightness) | ||
357 | atomic_set(sd_brightness, 255); | ||
358 | |||
359 | sd_brightness = NULL; | ||
360 | |||
361 | if (settings) | ||
362 | settings->phase_settings_step = 0; | ||
363 | tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL); | ||
364 | return; | ||
365 | } | ||
366 | |||
367 | dev_dbg(&dc->ndev->dev, "NVSD Init:\n"); | ||
368 | |||
369 | /* init agg_priorities */ | ||
370 | if (!settings->agg_priorities.agg[0]) | ||
371 | settings->agg_priorities.agg[0] = settings->aggressiveness; | ||
372 | |||
373 | /* WAR: Settings will not be valid until the next flip. | ||
374 | * Thus, set manual K to either HW's current value (if | ||
375 | * we're already enabled) or a non-effective value (if | ||
376 | * we're about to enable). */ | ||
377 | val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); | ||
378 | |||
379 | if (val & SD_ENABLE_NORMAL) | ||
380 | i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); | ||
381 | else | ||
382 | i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */ | ||
383 | |||
384 | tegra_dc_writel(dc, i, DC_DISP_SD_MAN_K_VALUES); | ||
385 | /* Enable manual correction mode here so that changing the | ||
386 | * settings won't immediately impact display dehavior. */ | ||
387 | val |= SD_CORRECTION_MODE_MAN; | ||
388 | tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); | ||
389 | |||
390 | bw_idx = nvsd_get_bw_idx(settings); | ||
391 | |||
392 | /* Write LUT */ | ||
393 | if (!settings->cmd) { | ||
394 | dev_dbg(&dc->ndev->dev, " LUT:\n"); | ||
395 | |||
396 | for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) { | ||
397 | val = SD_LUT_R(settings->lut[bw_idx][i].r) | | ||
398 | SD_LUT_G(settings->lut[bw_idx][i].g) | | ||
399 | SD_LUT_B(settings->lut[bw_idx][i].b); | ||
400 | tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i)); | ||
401 | |||
402 | dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | /* Write BL TF */ | ||
407 | if (!settings->cmd) { | ||
408 | dev_dbg(&dc->ndev->dev, " BL_TF:\n"); | ||
409 | |||
410 | for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) { | ||
411 | val = SD_BL_TF_POINT_0(settings->bltf[bw_idx][i][0]) | | ||
412 | SD_BL_TF_POINT_1(settings->bltf[bw_idx][i][1]) | | ||
413 | SD_BL_TF_POINT_2(settings->bltf[bw_idx][i][2]) | | ||
414 | SD_BL_TF_POINT_3(settings->bltf[bw_idx][i][3]); | ||
415 | |||
416 | tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i)); | ||
417 | |||
418 | dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val); | ||
419 | } | ||
420 | } else if ((settings->cmd & PHASE_IN)) { | ||
421 | settings->cmd &= ~PHASE_IN; | ||
422 | /* Write NO_OP values for BLTF */ | ||
423 | for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) { | ||
424 | val = SD_BL_TF_POINT_0(0xFF) | | ||
425 | SD_BL_TF_POINT_1(0xFF) | | ||
426 | SD_BL_TF_POINT_2(0xFF) | | ||
427 | SD_BL_TF_POINT_3(0xFF); | ||
428 | |||
429 | tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i)); | ||
430 | |||
431 | dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | /* Set step correctly on init */ | ||
436 | if (!settings->cmd && settings->phase_in_settings) { | ||
437 | settings->num_phase_in_steps = STEPS_PER_AGG_LVL * | ||
438 | settings->aggressiveness; | ||
439 | settings->phase_settings_step = settings->enable ? | ||
440 | settings->num_phase_in_steps : 0; | ||
441 | } | ||
442 | |||
443 | /* Write Coeff */ | ||
444 | val = SD_CSC_COEFF_R(settings->coeff.r) | | ||
445 | SD_CSC_COEFF_G(settings->coeff.g) | | ||
446 | SD_CSC_COEFF_B(settings->coeff.b); | ||
447 | tegra_dc_writel(dc, val, DC_DISP_SD_CSC_COEFF); | ||
448 | dev_dbg(&dc->ndev->dev, " COEFF: 0x%08x\n", val); | ||
449 | |||
450 | /* Write BL Params */ | ||
451 | val = SD_BLP_TIME_CONSTANT(settings->blp.time_constant) | | ||
452 | SD_BLP_STEP(settings->blp.step); | ||
453 | tegra_dc_writel(dc, val, DC_DISP_SD_BL_PARAMETERS); | ||
454 | dev_dbg(&dc->ndev->dev, " BLP: 0x%08x\n", val); | ||
455 | |||
456 | /* Write Auto/Manual PWM */ | ||
457 | val = (settings->use_auto_pwm) ? SD_BLC_MODE_AUTO : SD_BLC_MODE_MAN; | ||
458 | tegra_dc_writel(dc, val, DC_DISP_SD_BL_CONTROL); | ||
459 | dev_dbg(&dc->ndev->dev, " BL_CONTROL: 0x%08x\n", val); | ||
460 | |||
461 | /* Write Flicker Control */ | ||
462 | val = SD_FC_TIME_LIMIT(settings->fc.time_limit) | | ||
463 | SD_FC_THRESHOLD(settings->fc.threshold); | ||
464 | tegra_dc_writel(dc, val, DC_DISP_SD_FLICKER_CONTROL); | ||
465 | dev_dbg(&dc->ndev->dev, " FLICKER_CONTROL: 0x%08x\n", val); | ||
466 | |||
467 | /* Manage SD Control */ | ||
468 | val = 0; | ||
469 | /* Stay in manual correction mode until the next flip. */ | ||
470 | val |= SD_CORRECTION_MODE_MAN; | ||
471 | /* Enable / One-Shot */ | ||
472 | val |= (settings->enable == 2) ? | ||
473 | (SD_ENABLE_ONESHOT | SD_ONESHOT_ENABLE) : | ||
474 | SD_ENABLE_NORMAL; | ||
475 | /* HW Update Delay */ | ||
476 | val |= SD_HW_UPDATE_DLY(settings->hw_update_delay); | ||
477 | /* Video Luma */ | ||
478 | val |= (settings->use_vid_luma) ? SD_USE_VID_LUMA : 0; | ||
479 | /* Aggressiveness */ | ||
480 | val |= SD_AGGRESSIVENESS(settings->aggressiveness); | ||
481 | /* Bin Width (value derived from bw_idx) */ | ||
482 | val |= bw_idx << 3; | ||
483 | /* Finally, Write SD Control */ | ||
484 | tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); | ||
485 | dev_dbg(&dc->ndev->dev, " SD_CONTROL: 0x%08x\n", val); | ||
486 | |||
487 | /* set the brightness pointer */ | ||
488 | sd_brightness = settings->sd_brightness; | ||
489 | |||
490 | /* note that we're in manual K until the next flip */ | ||
491 | atomic_set(&man_k_until_blank, 1); | ||
492 | } | ||
493 | |||
494 | /* Periodic update */ | ||
495 | bool nvsd_update_brightness(struct tegra_dc *dc) | ||
496 | { | ||
497 | u32 val = 0; | ||
498 | int cur_sd_brightness; | ||
499 | struct tegra_dc_sd_settings *settings = dc->out->sd_settings; | ||
500 | |||
501 | if (sd_brightness) { | ||
502 | if (atomic_read(&man_k_until_blank) && | ||
503 | !settings->phase_in_adjustments) { | ||
504 | val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); | ||
505 | val &= ~SD_CORRECTION_MODE_MAN; | ||
506 | tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); | ||
507 | atomic_set(&man_k_until_blank, 0); | ||
508 | } | ||
509 | |||
510 | if (settings->cmd) | ||
511 | nvsd_cmd_handler(settings, dc); | ||
512 | |||
513 | /* nvsd_cmd_handler may turn off didim */ | ||
514 | if (!settings->enable) | ||
515 | return true; | ||
516 | |||
517 | cur_sd_brightness = atomic_read(sd_brightness); | ||
518 | |||
519 | /* read brightness value */ | ||
520 | val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL); | ||
521 | val = SD_BLC_BRIGHTNESS(val); | ||
522 | |||
523 | if (settings->phase_in_adjustments) { | ||
524 | return nvsd_phase_in_adjustments(dc, settings); | ||
525 | } else if (val != (u32)cur_sd_brightness) { | ||
526 | /* set brightness value and note the update */ | ||
527 | atomic_set(sd_brightness, (int)val); | ||
528 | return true; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | /* No update needed. */ | ||
533 | return false; | ||
534 | } | ||
535 | |||
536 | static ssize_t nvsd_lut_show(struct tegra_dc_sd_settings *sd_settings, | ||
537 | char *buf, ssize_t res) | ||
538 | { | ||
539 | u32 i; | ||
540 | u32 j; | ||
541 | |||
542 | for (i = 0; i < NUM_BIN_WIDTHS; i++) { | ||
543 | res += snprintf(buf + res, PAGE_SIZE - res, | ||
544 | "Bin Width: %d\n", 1 << i); | ||
545 | |||
546 | for (j = 0; j < DC_DISP_SD_LUT_NUM; j++) { | ||
547 | res += snprintf(buf + res, | ||
548 | PAGE_SIZE - res, | ||
549 | "%d: R: %3d / G: %3d / B: %3d\n", | ||
550 | j, | ||
551 | sd_settings->lut[i][j].r, | ||
552 | sd_settings->lut[i][j].g, | ||
553 | sd_settings->lut[i][j].b); | ||
554 | } | ||
555 | } | ||
556 | return res; | ||
557 | } | ||
558 | |||
559 | static ssize_t nvsd_bltf_show(struct tegra_dc_sd_settings *sd_settings, | ||
560 | char *buf, ssize_t res) | ||
561 | { | ||
562 | u32 i; | ||
563 | u32 j; | ||
564 | |||
565 | for (i = 0; i < NUM_BIN_WIDTHS; i++) { | ||
566 | res += snprintf(buf + res, PAGE_SIZE - res, | ||
567 | "Bin Width: %d\n", 1 << i); | ||
568 | |||
569 | for (j = 0; j < DC_DISP_SD_BL_TF_NUM; j++) { | ||
570 | res += snprintf(buf + res, | ||
571 | PAGE_SIZE - res, | ||
572 | "%d: 0: %3d / 1: %3d / 2: %3d / 3: %3d\n", | ||
573 | j, | ||
574 | sd_settings->bltf[i][j][0], | ||
575 | sd_settings->bltf[i][j][1], | ||
576 | sd_settings->bltf[i][j][2], | ||
577 | sd_settings->bltf[i][j][3]); | ||
578 | } | ||
579 | } | ||
580 | return res; | ||
581 | } | ||
582 | |||
583 | /* Sysfs accessors */ | ||
584 | static ssize_t nvsd_settings_show(struct kobject *kobj, | ||
585 | struct kobj_attribute *attr, char *buf) | ||
586 | { | ||
587 | struct device *dev = container_of((kobj->parent), struct device, kobj); | ||
588 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
589 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
590 | struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; | ||
591 | ssize_t res = 0; | ||
592 | |||
593 | if (sd_settings) { | ||
594 | if (IS_NVSD_ATTR(enable)) | ||
595 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
596 | sd_settings->enable); | ||
597 | else if (IS_NVSD_ATTR(aggressiveness)) | ||
598 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
599 | sd_settings->aggressiveness); | ||
600 | else if (IS_NVSD_ATTR(phase_in_settings)) | ||
601 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
602 | sd_settings->phase_in_settings); | ||
603 | else if (IS_NVSD_ATTR(phase_in_adjustments)) | ||
604 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
605 | sd_settings->phase_in_adjustments); | ||
606 | else if (IS_NVSD_ATTR(bin_width)) | ||
607 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
608 | sd_settings->bin_width); | ||
609 | else if (IS_NVSD_ATTR(hw_update_delay)) | ||
610 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
611 | sd_settings->hw_update_delay); | ||
612 | else if (IS_NVSD_ATTR(use_vid_luma)) | ||
613 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
614 | sd_settings->use_vid_luma); | ||
615 | else if (IS_NVSD_ATTR(coeff)) | ||
616 | res = snprintf(buf, PAGE_SIZE, | ||
617 | "R: %d / G: %d / B: %d\n", | ||
618 | sd_settings->coeff.r, | ||
619 | sd_settings->coeff.g, | ||
620 | sd_settings->coeff.b); | ||
621 | else if (IS_NVSD_ATTR(blp_time_constant)) | ||
622 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
623 | sd_settings->blp.time_constant); | ||
624 | else if (IS_NVSD_ATTR(blp_step)) | ||
625 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
626 | sd_settings->blp.step); | ||
627 | else if (IS_NVSD_ATTR(fc_time_limit)) | ||
628 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
629 | sd_settings->fc.time_limit); | ||
630 | else if (IS_NVSD_ATTR(fc_threshold)) | ||
631 | res = snprintf(buf, PAGE_SIZE, "%d\n", | ||
632 | sd_settings->fc.threshold); | ||
633 | else if (IS_NVSD_ATTR(lut)) | ||
634 | res = nvsd_lut_show(sd_settings, buf, res); | ||
635 | else if (IS_NVSD_ATTR(bltf)) | ||
636 | res = nvsd_bltf_show(sd_settings, buf, res); | ||
637 | else | ||
638 | res = -EINVAL; | ||
639 | } else { | ||
640 | /* This shouldn't be reachable. But just in case... */ | ||
641 | res = -EINVAL; | ||
642 | } | ||
643 | |||
644 | return res; | ||
645 | } | ||
646 | |||
647 | #define nvsd_check_and_update(_min, _max, _varname) { \ | ||
648 | int val = simple_strtol(buf, NULL, 10); \ | ||
649 | if (val >= _min && val <= _max) { \ | ||
650 | sd_settings->_varname = val; \ | ||
651 | settings_updated = true; \ | ||
652 | } } | ||
653 | |||
654 | #define nvsd_get_multi(_ele, _num, _act, _min, _max) { \ | ||
655 | char *b, *c, *orig_b; \ | ||
656 | b = orig_b = kstrdup(buf, GFP_KERNEL); \ | ||
657 | for (_act = 0; _act < _num; _act++) { \ | ||
658 | if (!b) \ | ||
659 | break; \ | ||
660 | b = strim(b); \ | ||
661 | c = strsep(&b, " "); \ | ||
662 | if (!strlen(c)) \ | ||
663 | break; \ | ||
664 | _ele[_act] = simple_strtol(c, NULL, 10); \ | ||
665 | if (_ele[_act] < _min || _ele[_act] > _max) \ | ||
666 | break; \ | ||
667 | } \ | ||
668 | if (orig_b) \ | ||
669 | kfree(orig_b); \ | ||
670 | } | ||
671 | |||
672 | static int nvsd_lut_store(struct tegra_dc_sd_settings *sd_settings, | ||
673 | const char *buf) | ||
674 | { | ||
675 | int ele[3 * DC_DISP_SD_LUT_NUM * NUM_BIN_WIDTHS]; | ||
676 | int i = 0; | ||
677 | int j = 0; | ||
678 | int num = 3 * DC_DISP_SD_LUT_NUM * NUM_BIN_WIDTHS; | ||
679 | |||
680 | nvsd_get_multi(ele, num, i, 0, 255); | ||
681 | |||
682 | if (i != num) | ||
683 | return -EINVAL; | ||
684 | |||
685 | for (i = 0; i < NUM_BIN_WIDTHS; i++) { | ||
686 | for (j = 0; j < DC_DISP_SD_LUT_NUM; j++) { | ||
687 | sd_settings->lut[i][j].r = | ||
688 | ele[i * NUM_BIN_WIDTHS + j * 3 + 0]; | ||
689 | sd_settings->lut[i][j].g = | ||
690 | ele[i * NUM_BIN_WIDTHS + j * 3 + 1]; | ||
691 | sd_settings->lut[i][j].b = | ||
692 | ele[i * NUM_BIN_WIDTHS + j * 3 + 2]; | ||
693 | } | ||
694 | } | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int nvsd_bltf_store(struct tegra_dc_sd_settings *sd_settings, | ||
699 | const char *buf) | ||
700 | { | ||
701 | int ele[4 * DC_DISP_SD_BL_TF_NUM * NUM_BIN_WIDTHS]; | ||
702 | int i = 0, j = 0, num = ARRAY_SIZE(ele); | ||
703 | |||
704 | nvsd_get_multi(ele, num, i, 0, 255); | ||
705 | |||
706 | if (i != num) | ||
707 | return -EINVAL; | ||
708 | |||
709 | for (i = 0; i < NUM_BIN_WIDTHS; i++) { | ||
710 | for (j = 0; j < DC_DISP_SD_BL_TF_NUM; j++) { | ||
711 | size_t base = (i * NUM_BIN_WIDTHS * | ||
712 | DC_DISP_SD_BL_TF_NUM) + (j * 4); | ||
713 | sd_settings->bltf[i][j][0] = ele[base + 0]; | ||
714 | sd_settings->bltf[i][j][1] = ele[base + 1]; | ||
715 | sd_settings->bltf[i][j][2] = ele[base + 2]; | ||
716 | sd_settings->bltf[i][j][3] = ele[base + 3]; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static ssize_t nvsd_settings_store(struct kobject *kobj, | ||
724 | struct kobj_attribute *attr, const char *buf, size_t count) | ||
725 | { | ||
726 | struct device *dev = container_of((kobj->parent), struct device, kobj); | ||
727 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
728 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
729 | struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; | ||
730 | ssize_t res = count; | ||
731 | bool settings_updated = false; | ||
732 | long int result; | ||
733 | int err; | ||
734 | |||
735 | if (sd_settings) { | ||
736 | if (IS_NVSD_ATTR(enable)) { | ||
737 | if (sd_settings->phase_in_settings) { | ||
738 | err = strict_strtol(buf, 10, &result); | ||
739 | if (err) | ||
740 | return err; | ||
741 | |||
742 | if (nvsd_update_enable(sd_settings, result)) | ||
743 | nvsd_check_and_update(1, 1, enable); | ||
744 | |||
745 | } else { | ||
746 | nvsd_check_and_update(0, 1, enable); | ||
747 | } | ||
748 | } else if (IS_NVSD_ATTR(aggressiveness)) { | ||
749 | err = strict_strtol(buf, 10, &result); | ||
750 | if (err) | ||
751 | return err; | ||
752 | |||
753 | if (nvsd_update_agg(sd_settings, result) | ||
754 | && !sd_settings->phase_in_settings) | ||
755 | settings_updated = true; | ||
756 | |||
757 | } else if (IS_NVSD_ATTR(phase_in_settings)) { | ||
758 | nvsd_check_and_update(0, 1, phase_in_settings); | ||
759 | } else if (IS_NVSD_ATTR(phase_in_adjustments)) { | ||
760 | nvsd_check_and_update(0, 1, phase_in_adjustments); | ||
761 | } else if (IS_NVSD_ATTR(bin_width)) { | ||
762 | nvsd_check_and_update(0, 8, bin_width); | ||
763 | } else if (IS_NVSD_ATTR(hw_update_delay)) { | ||
764 | nvsd_check_and_update(0, 2, hw_update_delay); | ||
765 | } else if (IS_NVSD_ATTR(use_vid_luma)) { | ||
766 | nvsd_check_and_update(0, 1, use_vid_luma); | ||
767 | } else if (IS_NVSD_ATTR(coeff)) { | ||
768 | int ele[3], i = 0, num = 3; | ||
769 | nvsd_get_multi(ele, num, i, 0, 15); | ||
770 | |||
771 | if (i == num) { | ||
772 | sd_settings->coeff.r = ele[0]; | ||
773 | sd_settings->coeff.g = ele[1]; | ||
774 | sd_settings->coeff.b = ele[2]; | ||
775 | settings_updated = true; | ||
776 | } else { | ||
777 | res = -EINVAL; | ||
778 | } | ||
779 | } else if (IS_NVSD_ATTR(blp_time_constant)) { | ||
780 | nvsd_check_and_update(0, 1024, blp.time_constant); | ||
781 | } else if (IS_NVSD_ATTR(blp_step)) { | ||
782 | nvsd_check_and_update(0, 255, blp.step); | ||
783 | } else if (IS_NVSD_ATTR(fc_time_limit)) { | ||
784 | nvsd_check_and_update(0, 255, fc.time_limit); | ||
785 | } else if (IS_NVSD_ATTR(fc_threshold)) { | ||
786 | nvsd_check_and_update(0, 255, fc.threshold); | ||
787 | } else if (IS_NVSD_ATTR(lut)) { | ||
788 | if (nvsd_lut_store(sd_settings, buf)) | ||
789 | res = -EINVAL; | ||
790 | else | ||
791 | settings_updated = true; | ||
792 | } else if (IS_NVSD_ATTR(bltf)) { | ||
793 | if (nvsd_bltf_store(sd_settings, buf)) | ||
794 | res = -EINVAL; | ||
795 | else | ||
796 | settings_updated = true; | ||
797 | } else { | ||
798 | res = -EINVAL; | ||
799 | } | ||
800 | |||
801 | /* Re-init if our settings were updated. */ | ||
802 | if (settings_updated) { | ||
803 | mutex_lock(&dc->lock); | ||
804 | if (!dc->enabled) { | ||
805 | mutex_unlock(&dc->lock); | ||
806 | return -ENODEV; | ||
807 | } | ||
808 | mutex_unlock(&dc->lock); | ||
809 | |||
810 | nvsd_init(dc, sd_settings); | ||
811 | |||
812 | /* Update backlight state IFF we're disabling! */ | ||
813 | if (!sd_settings->enable && sd_settings->bl_device) { | ||
814 | /* Do the actual brightness update outside of | ||
815 | * the mutex */ | ||
816 | struct platform_device *pdev = | ||
817 | sd_settings->bl_device; | ||
818 | struct backlight_device *bl = | ||
819 | platform_get_drvdata(pdev); | ||
820 | |||
821 | if (bl) | ||
822 | backlight_update_status(bl); | ||
823 | } | ||
824 | } | ||
825 | } else { | ||
826 | /* This shouldn't be reachable. But just in case... */ | ||
827 | res = -EINVAL; | ||
828 | } | ||
829 | |||
830 | return res; | ||
831 | } | ||
832 | |||
833 | #define NVSD_PRINT_REG(__name) { \ | ||
834 | u32 val = tegra_dc_readl(dc, __name); \ | ||
835 | res += snprintf(buf + res, PAGE_SIZE - res, #__name ": 0x%08x\n", \ | ||
836 | val); \ | ||
837 | } | ||
838 | |||
839 | #define NVSD_PRINT_REG_ARRAY(__name) { \ | ||
840 | u32 val = 0, i = 0; \ | ||
841 | res += snprintf(buf + res, PAGE_SIZE - res, #__name ":\n"); \ | ||
842 | for (i = 0; i < __name##_NUM; i++) { \ | ||
843 | val = tegra_dc_readl(dc, __name(i)); \ | ||
844 | res += snprintf(buf + res, PAGE_SIZE - res, " %d: 0x%08x\n", \ | ||
845 | i, val); \ | ||
846 | } \ | ||
847 | } | ||
848 | |||
849 | static ssize_t nvsd_registers_show(struct kobject *kobj, | ||
850 | struct kobj_attribute *attr, char *buf) | ||
851 | { | ||
852 | struct device *dev = container_of((kobj->parent), struct device, kobj); | ||
853 | struct nvhost_device *ndev = to_nvhost_device(dev); | ||
854 | struct tegra_dc *dc = nvhost_get_drvdata(ndev); | ||
855 | ssize_t res = 0; | ||
856 | |||
857 | mutex_lock(&dc->lock); | ||
858 | if (!dc->enabled) { | ||
859 | mutex_unlock(&dc->lock); | ||
860 | return -ENODEV; | ||
861 | } | ||
862 | |||
863 | mutex_unlock(&dc->lock); | ||
864 | NVSD_PRINT_REG(DC_DISP_SD_CONTROL); | ||
865 | NVSD_PRINT_REG(DC_DISP_SD_CSC_COEFF); | ||
866 | NVSD_PRINT_REG_ARRAY(DC_DISP_SD_LUT); | ||
867 | NVSD_PRINT_REG(DC_DISP_SD_FLICKER_CONTROL); | ||
868 | NVSD_PRINT_REG(DC_DISP_SD_PIXEL_COUNT); | ||
869 | NVSD_PRINT_REG_ARRAY(DC_DISP_SD_HISTOGRAM); | ||
870 | NVSD_PRINT_REG(DC_DISP_SD_BL_PARAMETERS); | ||
871 | NVSD_PRINT_REG_ARRAY(DC_DISP_SD_BL_TF); | ||
872 | NVSD_PRINT_REG(DC_DISP_SD_BL_CONTROL); | ||
873 | NVSD_PRINT_REG(DC_DISP_SD_HW_K_VALUES); | ||
874 | NVSD_PRINT_REG(DC_DISP_SD_MAN_K_VALUES); | ||
875 | |||
876 | return res; | ||
877 | } | ||
878 | |||
879 | /* Sysfs initializer */ | ||
880 | int nvsd_create_sysfs(struct device *dev) | ||
881 | { | ||
882 | int retval = 0; | ||
883 | |||
884 | nvsd_kobj = kobject_create_and_add("smartdimmer", &dev->kobj); | ||
885 | |||
886 | if (!nvsd_kobj) | ||
887 | return -ENOMEM; | ||
888 | |||
889 | retval = sysfs_create_group(nvsd_kobj, &nvsd_attr_group); | ||
890 | |||
891 | if (retval) { | ||
892 | kobject_put(nvsd_kobj); | ||
893 | dev_err(dev, "%s: failed to create attributes\n", __func__); | ||
894 | } | ||
895 | |||
896 | return retval; | ||
897 | } | ||
898 | |||
899 | /* Sysfs destructor */ | ||
900 | void __devexit nvsd_remove_sysfs(struct device *dev) | ||
901 | { | ||
902 | if (nvsd_kobj) { | ||
903 | sysfs_remove_group(nvsd_kobj, &nvsd_attr_group); | ||
904 | kobject_put(nvsd_kobj); | ||
905 | } | ||
906 | } | ||
diff --git a/drivers/video/tegra/dc/nvsd.h b/drivers/video/tegra/dc/nvsd.h new file mode 100644 index 00000000000..f7fc4a1ead6 --- /dev/null +++ b/drivers/video/tegra/dc/nvsd.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/nvsd.h | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
5 | * | ||
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 | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_TEGRA_DC_NVSD_H | ||
18 | #define __DRIVERS_VIDEO_TEGRA_DC_NVSD_H | ||
19 | |||
20 | void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings); | ||
21 | bool nvsd_update_brightness(struct tegra_dc *dc); | ||
22 | int nvsd_create_sysfs(struct device *dev); | ||
23 | void __devexit nvsd_remove_sysfs(struct device *dev); | ||
24 | |||
25 | #endif | ||
diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c new file mode 100644 index 00000000000..2112643058f --- /dev/null +++ b/drivers/video/tegra/dc/rgb.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/dc/rgb.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Erik Gilling <konkers@android.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | |||
20 | #include <mach/dc.h> | ||
21 | |||
22 | #include "dc_reg.h" | ||
23 | #include "dc_priv.h" | ||
24 | |||
25 | |||
26 | static const u32 tegra_dc_rgb_enable_partial_pintable[] = { | ||
27 | DC_COM_PIN_OUTPUT_ENABLE0, 0x00000000, | ||
28 | DC_COM_PIN_OUTPUT_ENABLE1, 0x00000000, | ||
29 | DC_COM_PIN_OUTPUT_ENABLE2, 0x00000000, | ||
30 | DC_COM_PIN_OUTPUT_ENABLE3, 0x00000000, | ||
31 | DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000, | ||
32 | DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000, | ||
33 | DC_COM_PIN_OUTPUT_DATA0, 0x00000000, | ||
34 | DC_COM_PIN_OUTPUT_DATA1, 0x00000000, | ||
35 | DC_COM_PIN_OUTPUT_DATA2, 0x00000000, | ||
36 | DC_COM_PIN_OUTPUT_DATA3, 0x00000000, | ||
37 | }; | ||
38 | |||
39 | static const u32 tegra_dc_rgb_enable_pintable[] = { | ||
40 | DC_COM_PIN_OUTPUT_ENABLE0, 0x00000000, | ||
41 | DC_COM_PIN_OUTPUT_ENABLE1, 0x00000000, | ||
42 | DC_COM_PIN_OUTPUT_ENABLE2, 0x00000000, | ||
43 | DC_COM_PIN_OUTPUT_ENABLE3, 0x00000000, | ||
44 | DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000, | ||
45 | DC_COM_PIN_OUTPUT_POLARITY1, 0x01000000, | ||
46 | DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000, | ||
47 | DC_COM_PIN_OUTPUT_POLARITY3, 0x00000000, | ||
48 | DC_COM_PIN_OUTPUT_DATA0, 0x00000000, | ||
49 | DC_COM_PIN_OUTPUT_DATA1, 0x00000000, | ||
50 | DC_COM_PIN_OUTPUT_DATA2, 0x00000000, | ||
51 | DC_COM_PIN_OUTPUT_DATA3, 0x00000000, | ||
52 | }; | ||
53 | |||
54 | static const u32 tegra_dc_rgb_enable_out_sel_pintable[] = { | ||
55 | DC_COM_PIN_OUTPUT_SELECT0, 0x00000000, | ||
56 | DC_COM_PIN_OUTPUT_SELECT1, 0x00000000, | ||
57 | DC_COM_PIN_OUTPUT_SELECT2, 0x00000000, | ||
58 | #ifdef CONFIG_TEGRA_SILICON_PLATFORM | ||
59 | DC_COM_PIN_OUTPUT_SELECT3, 0x00000000, | ||
60 | #else | ||
61 | /* The display panel sub-board used on FPGA platforms (panel 86) | ||
62 | is non-standard. It expects the Data Enable signal on the WR | ||
63 | pin instead of the DE pin. */ | ||
64 | DC_COM_PIN_OUTPUT_SELECT3, 0x00200000, | ||
65 | #endif | ||
66 | DC_COM_PIN_OUTPUT_SELECT4, 0x00210222, | ||
67 | DC_COM_PIN_OUTPUT_SELECT5, 0x00002200, | ||
68 | DC_COM_PIN_OUTPUT_SELECT6, 0x00020000, | ||
69 | }; | ||
70 | |||
71 | static const u32 tegra_dc_rgb_disable_pintable[] = { | ||
72 | DC_COM_PIN_OUTPUT_ENABLE0, 0x55555555, | ||
73 | DC_COM_PIN_OUTPUT_ENABLE1, 0x55150005, | ||
74 | DC_COM_PIN_OUTPUT_ENABLE2, 0x55555555, | ||
75 | DC_COM_PIN_OUTPUT_ENABLE3, 0x55555555, | ||
76 | DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000, | ||
77 | DC_COM_PIN_OUTPUT_POLARITY1, 0x00000000, | ||
78 | DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000, | ||
79 | DC_COM_PIN_OUTPUT_POLARITY3, 0x00000000, | ||
80 | DC_COM_PIN_OUTPUT_DATA0, 0xaaaaaaaa, | ||
81 | DC_COM_PIN_OUTPUT_DATA1, 0xaaaaaaaa, | ||
82 | DC_COM_PIN_OUTPUT_DATA2, 0xaaaaaaaa, | ||
83 | DC_COM_PIN_OUTPUT_DATA3, 0xaaaaaaaa, | ||
84 | DC_COM_PIN_OUTPUT_SELECT0, 0x00000000, | ||
85 | DC_COM_PIN_OUTPUT_SELECT1, 0x00000000, | ||
86 | DC_COM_PIN_OUTPUT_SELECT2, 0x00000000, | ||
87 | DC_COM_PIN_OUTPUT_SELECT3, 0x00000000, | ||
88 | DC_COM_PIN_OUTPUT_SELECT4, 0x00000000, | ||
89 | DC_COM_PIN_OUTPUT_SELECT5, 0x00000000, | ||
90 | DC_COM_PIN_OUTPUT_SELECT6, 0x00000000, | ||
91 | }; | ||
92 | |||
93 | void tegra_dc_rgb_enable(struct tegra_dc *dc) | ||
94 | { | ||
95 | int i; | ||
96 | u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)]; | ||
97 | |||
98 | tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
99 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE, | ||
100 | DC_CMD_DISPLAY_POWER_CONTROL); | ||
101 | |||
102 | tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); | ||
103 | |||
104 | if (dc->out->out_pins) { | ||
105 | tegra_dc_set_out_pin_polars(dc, dc->out->out_pins, | ||
106 | dc->out->n_out_pins); | ||
107 | tegra_dc_write_table(dc, tegra_dc_rgb_enable_partial_pintable); | ||
108 | } else { | ||
109 | tegra_dc_write_table(dc, tegra_dc_rgb_enable_pintable); | ||
110 | } | ||
111 | |||
112 | memcpy(out_sel_pintable, tegra_dc_rgb_enable_out_sel_pintable, | ||
113 | sizeof(tegra_dc_rgb_enable_out_sel_pintable)); | ||
114 | |||
115 | if (dc->out && dc->out->out_sel_configs) { | ||
116 | u8 *out_sels = dc->out->out_sel_configs; | ||
117 | for (i = 0; i < dc->out->n_out_sel_configs; i++) { | ||
118 | switch (out_sels[i]) { | ||
119 | case TEGRA_PIN_OUT_CONFIG_SEL_LM1_M1: | ||
120 | out_sel_pintable[5*2+1] = | ||
121 | (out_sel_pintable[5*2+1] & | ||
122 | ~PIN5_LM1_LCD_M1_OUTPUT_MASK) | | ||
123 | PIN5_LM1_LCD_M1_OUTPUT_M1; | ||
124 | break; | ||
125 | case TEGRA_PIN_OUT_CONFIG_SEL_LM1_LD21: | ||
126 | out_sel_pintable[5*2+1] = | ||
127 | (out_sel_pintable[5*2+1] & | ||
128 | ~PIN5_LM1_LCD_M1_OUTPUT_MASK) | | ||
129 | PIN5_LM1_LCD_M1_OUTPUT_LD21; | ||
130 | break; | ||
131 | case TEGRA_PIN_OUT_CONFIG_SEL_LM1_PM1: | ||
132 | out_sel_pintable[5*2+1] = | ||
133 | (out_sel_pintable[5*2+1] & | ||
134 | ~PIN5_LM1_LCD_M1_OUTPUT_MASK) | | ||
135 | PIN5_LM1_LCD_M1_OUTPUT_PM1; | ||
136 | break; | ||
137 | default: | ||
138 | dev_err(&dc->ndev->dev, | ||
139 | "Invalid pin config[%d]: %d\n", | ||
140 | i, out_sels[i]); | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | tegra_dc_write_table(dc, out_sel_pintable); | ||
147 | } | ||
148 | |||
149 | void tegra_dc_rgb_disable(struct tegra_dc *dc) | ||
150 | { | ||
151 | tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL); | ||
152 | |||
153 | tegra_dc_write_table(dc, tegra_dc_rgb_disable_pintable); | ||
154 | } | ||
155 | |||
156 | struct tegra_dc_out_ops tegra_dc_rgb_ops = { | ||
157 | .enable = tegra_dc_rgb_enable, | ||
158 | .disable = tegra_dc_rgb_disable, | ||
159 | }; | ||
160 | |||