blob: 575a8cbd35337b2719195b733485c4d04aee580c [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#include "drmP.h"
18#include "drm_edid.h"
19#include "drm_crtc_helper.h"
20
21#include "regs-hdmi.h"
22
23#include <linux/kernel.h>
24#include <linux/spinlock.h>
25#include <linux/wait.h>
26#include <linux/i2c.h>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/irq.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/clk.h>
34#include <linux/regulator/consumer.h>
35
36#include <drm/exynos_drm.h>
37
38#include "exynos_drm_drv.h"
39#include "exynos_drm_hdmi.h"
40
41#include "exynos_hdmi.h"
42
43#define HDMI_OVERLAY_NUMBER 3
Inki Dae1de425b2012-03-16 18:47:04 +090044#define MAX_WIDTH 1920
45#define MAX_HEIGHT 1080
Seung-Woo Kimd8408322011-12-21 17:39:39 +090046#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
47
Joonyoung Shim590f4182012-03-16 18:47:14 +090048struct hdmi_resources {
49 struct clk *hdmi;
50 struct clk *sclk_hdmi;
51 struct clk *sclk_pixel;
52 struct clk *sclk_hdmiphy;
53 struct clk *hdmiphy;
54 struct regulator_bulk_data *regul_bulk;
55 int regul_count;
56};
57
58struct hdmi_context {
59 struct device *dev;
60 struct drm_device *drm_dev;
61 struct fb_videomode *default_timing;
62 unsigned int is_v13:1;
63 unsigned int default_win;
64 unsigned int default_bpp;
65 bool hpd_handle;
66 bool enabled;
67
68 struct resource *regs_res;
69 void __iomem *regs;
70 unsigned int irq;
71 struct workqueue_struct *wq;
72 struct work_struct hotplug_work;
73
74 struct i2c_client *ddc_port;
75 struct i2c_client *hdmiphy_port;
76
77 /* current hdmiphy conf index */
78 int cur_conf;
79
80 struct hdmi_resources res;
81 void *parent_ctx;
82};
83
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +090084/* HDMI Version 1.3 */
85static const u8 hdmiphy_v13_conf27[32] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +090086 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
87 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
88 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
89 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
90};
91
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +090092static const u8 hdmiphy_v13_conf27_027[32] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +090093 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
94 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
95 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
96 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
97};
98
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +090099static const u8 hdmiphy_v13_conf74_175[32] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900100 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
101 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
102 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
103 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
104};
105
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900106static const u8 hdmiphy_v13_conf74_25[32] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900107 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
108 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
109 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
110 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
111};
112
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900113static const u8 hdmiphy_v13_conf148_5[32] = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900114 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
115 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
116 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
117 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
118};
119
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900120struct hdmi_v13_tg_regs {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900121 u8 cmd;
122 u8 h_fsz_l;
123 u8 h_fsz_h;
124 u8 hact_st_l;
125 u8 hact_st_h;
126 u8 hact_sz_l;
127 u8 hact_sz_h;
128 u8 v_fsz_l;
129 u8 v_fsz_h;
130 u8 vsync_l;
131 u8 vsync_h;
132 u8 vsync2_l;
133 u8 vsync2_h;
134 u8 vact_st_l;
135 u8 vact_st_h;
136 u8 vact_sz_l;
137 u8 vact_sz_h;
138 u8 field_chg_l;
139 u8 field_chg_h;
140 u8 vact_st2_l;
141 u8 vact_st2_h;
142 u8 vsync_top_hdmi_l;
143 u8 vsync_top_hdmi_h;
144 u8 vsync_bot_hdmi_l;
145 u8 vsync_bot_hdmi_h;
146 u8 field_top_hdmi_l;
147 u8 field_top_hdmi_h;
148 u8 field_bot_hdmi_l;
149 u8 field_bot_hdmi_h;
150};
151
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900152struct hdmi_v13_core_regs {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900153 u8 h_blank[2];
154 u8 v_blank[3];
155 u8 h_v_line[3];
156 u8 vsync_pol[1];
157 u8 int_pro_mode[1];
158 u8 v_blank_f[3];
159 u8 h_sync_gen[3];
160 u8 v_sync_gen1[3];
161 u8 v_sync_gen2[3];
162 u8 v_sync_gen3[3];
163};
164
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900165struct hdmi_v13_preset_conf {
166 struct hdmi_v13_core_regs core;
167 struct hdmi_v13_tg_regs tg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900168};
169
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900170struct hdmi_v13_conf {
171 int width;
172 int height;
173 int vrefresh;
174 bool interlace;
175 const u8 *hdmiphy_data;
176 const struct hdmi_v13_preset_conf *conf;
177};
178
179static const struct hdmi_v13_preset_conf hdmi_v13_conf_480p = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900180 .core = {
181 .h_blank = {0x8a, 0x00},
182 .v_blank = {0x0d, 0x6a, 0x01},
183 .h_v_line = {0x0d, 0xa2, 0x35},
184 .vsync_pol = {0x01},
185 .int_pro_mode = {0x00},
186 .v_blank_f = {0x00, 0x00, 0x00},
187 .h_sync_gen = {0x0e, 0x30, 0x11},
188 .v_sync_gen1 = {0x0f, 0x90, 0x00},
189 /* other don't care */
190 },
191 .tg = {
192 0x00, /* cmd */
193 0x5a, 0x03, /* h_fsz */
194 0x8a, 0x00, 0xd0, 0x02, /* hact */
195 0x0d, 0x02, /* v_fsz */
196 0x01, 0x00, 0x33, 0x02, /* vsync */
197 0x2d, 0x00, 0xe0, 0x01, /* vact */
198 0x33, 0x02, /* field_chg */
199 0x49, 0x02, /* vact_st2 */
200 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
201 0x01, 0x00, 0x33, 0x02, /* field top/bot */
202 },
203};
204
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900205static const struct hdmi_v13_preset_conf hdmi_v13_conf_720p60 = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900206 .core = {
207 .h_blank = {0x72, 0x01},
208 .v_blank = {0xee, 0xf2, 0x00},
209 .h_v_line = {0xee, 0x22, 0x67},
210 .vsync_pol = {0x00},
211 .int_pro_mode = {0x00},
212 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
213 .h_sync_gen = {0x6c, 0x50, 0x02},
214 .v_sync_gen1 = {0x0a, 0x50, 0x00},
215 .v_sync_gen2 = {0x01, 0x10, 0x00},
216 .v_sync_gen3 = {0x01, 0x10, 0x00},
217 /* other don't care */
218 },
219 .tg = {
220 0x00, /* cmd */
221 0x72, 0x06, /* h_fsz */
222 0x71, 0x01, 0x01, 0x05, /* hact */
223 0xee, 0x02, /* v_fsz */
224 0x01, 0x00, 0x33, 0x02, /* vsync */
225 0x1e, 0x00, 0xd0, 0x02, /* vact */
226 0x33, 0x02, /* field_chg */
227 0x49, 0x02, /* vact_st2 */
228 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
229 0x01, 0x00, 0x33, 0x02, /* field top/bot */
230 },
231};
232
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900233static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i50 = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900234 .core = {
235 .h_blank = {0xd0, 0x02},
236 .v_blank = {0x32, 0xB2, 0x00},
237 .h_v_line = {0x65, 0x04, 0xa5},
238 .vsync_pol = {0x00},
239 .int_pro_mode = {0x01},
240 .v_blank_f = {0x49, 0x2A, 0x23},
241 .h_sync_gen = {0x0E, 0xEA, 0x08},
242 .v_sync_gen1 = {0x07, 0x20, 0x00},
243 .v_sync_gen2 = {0x39, 0x42, 0x23},
244 .v_sync_gen3 = {0x38, 0x87, 0x73},
245 /* other don't care */
246 },
247 .tg = {
248 0x00, /* cmd */
249 0x50, 0x0A, /* h_fsz */
250 0xCF, 0x02, 0x81, 0x07, /* hact */
251 0x65, 0x04, /* v_fsz */
252 0x01, 0x00, 0x33, 0x02, /* vsync */
253 0x16, 0x00, 0x1c, 0x02, /* vact */
254 0x33, 0x02, /* field_chg */
255 0x49, 0x02, /* vact_st2 */
256 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
257 0x01, 0x00, 0x33, 0x02, /* field top/bot */
258 },
259};
260
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900261static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p50 = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900262 .core = {
263 .h_blank = {0xd0, 0x02},
264 .v_blank = {0x65, 0x6c, 0x01},
265 .h_v_line = {0x65, 0x04, 0xa5},
266 .vsync_pol = {0x00},
267 .int_pro_mode = {0x00},
268 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
269 .h_sync_gen = {0x0e, 0xea, 0x08},
270 .v_sync_gen1 = {0x09, 0x40, 0x00},
271 .v_sync_gen2 = {0x01, 0x10, 0x00},
272 .v_sync_gen3 = {0x01, 0x10, 0x00},
273 /* other don't care */
274 },
275 .tg = {
276 0x00, /* cmd */
277 0x50, 0x0A, /* h_fsz */
278 0xCF, 0x02, 0x81, 0x07, /* hact */
279 0x65, 0x04, /* v_fsz */
280 0x01, 0x00, 0x33, 0x02, /* vsync */
281 0x2d, 0x00, 0x38, 0x04, /* vact */
282 0x33, 0x02, /* field_chg */
283 0x48, 0x02, /* vact_st2 */
284 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
285 0x01, 0x00, 0x33, 0x02, /* field top/bot */
286 },
287};
288
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900289static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i60 = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900290 .core = {
291 .h_blank = {0x18, 0x01},
292 .v_blank = {0x32, 0xB2, 0x00},
293 .h_v_line = {0x65, 0x84, 0x89},
294 .vsync_pol = {0x00},
295 .int_pro_mode = {0x01},
296 .v_blank_f = {0x49, 0x2A, 0x23},
297 .h_sync_gen = {0x56, 0x08, 0x02},
298 .v_sync_gen1 = {0x07, 0x20, 0x00},
299 .v_sync_gen2 = {0x39, 0x42, 0x23},
300 .v_sync_gen3 = {0xa4, 0x44, 0x4a},
301 /* other don't care */
302 },
303 .tg = {
304 0x00, /* cmd */
305 0x98, 0x08, /* h_fsz */
306 0x17, 0x01, 0x81, 0x07, /* hact */
307 0x65, 0x04, /* v_fsz */
308 0x01, 0x00, 0x33, 0x02, /* vsync */
309 0x16, 0x00, 0x1c, 0x02, /* vact */
310 0x33, 0x02, /* field_chg */
311 0x49, 0x02, /* vact_st2 */
312 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
313 0x01, 0x00, 0x33, 0x02, /* field top/bot */
314 },
315};
316
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900317static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p60 = {
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900318 .core = {
319 .h_blank = {0x18, 0x01},
320 .v_blank = {0x65, 0x6c, 0x01},
321 .h_v_line = {0x65, 0x84, 0x89},
322 .vsync_pol = {0x00},
323 .int_pro_mode = {0x00},
324 .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
325 .h_sync_gen = {0x56, 0x08, 0x02},
326 .v_sync_gen1 = {0x09, 0x40, 0x00},
327 .v_sync_gen2 = {0x01, 0x10, 0x00},
328 .v_sync_gen3 = {0x01, 0x10, 0x00},
329 /* other don't care */
330 },
331 .tg = {
332 0x00, /* cmd */
333 0x98, 0x08, /* h_fsz */
334 0x17, 0x01, 0x81, 0x07, /* hact */
335 0x65, 0x04, /* v_fsz */
336 0x01, 0x00, 0x33, 0x02, /* vsync */
337 0x2d, 0x00, 0x38, 0x04, /* vact */
338 0x33, 0x02, /* field_chg */
339 0x48, 0x02, /* vact_st2 */
340 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
341 0x01, 0x00, 0x33, 0x02, /* field top/bot */
342 },
343};
344
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900345static const struct hdmi_v13_conf hdmi_v13_confs[] = {
346 { 1280, 720, 60, false, hdmiphy_v13_conf74_25, &hdmi_v13_conf_720p60 },
347 { 1280, 720, 50, false, hdmiphy_v13_conf74_25, &hdmi_v13_conf_720p60 },
348 { 720, 480, 60, false, hdmiphy_v13_conf27_027, &hdmi_v13_conf_480p },
349 { 1920, 1080, 50, true, hdmiphy_v13_conf74_25, &hdmi_v13_conf_1080i50 },
350 { 1920, 1080, 50, false, hdmiphy_v13_conf148_5,
351 &hdmi_v13_conf_1080p50 },
352 { 1920, 1080, 60, true, hdmiphy_v13_conf74_25, &hdmi_v13_conf_1080i60 },
353 { 1920, 1080, 60, false, hdmiphy_v13_conf148_5,
354 &hdmi_v13_conf_1080p60 },
355};
356
357/* HDMI Version 1.4 */
358static const u8 hdmiphy_conf27_027[32] = {
359 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
360 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
361 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
362 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
363};
364
365static const u8 hdmiphy_conf74_25[32] = {
366 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
367 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
368 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
369 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
370};
371
372static const u8 hdmiphy_conf148_5[32] = {
373 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
374 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
375 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
376 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
377};
378
379struct hdmi_tg_regs {
380 u8 cmd;
381 u8 h_fsz_l;
382 u8 h_fsz_h;
383 u8 hact_st_l;
384 u8 hact_st_h;
385 u8 hact_sz_l;
386 u8 hact_sz_h;
387 u8 v_fsz_l;
388 u8 v_fsz_h;
389 u8 vsync_l;
390 u8 vsync_h;
391 u8 vsync2_l;
392 u8 vsync2_h;
393 u8 vact_st_l;
394 u8 vact_st_h;
395 u8 vact_sz_l;
396 u8 vact_sz_h;
397 u8 field_chg_l;
398 u8 field_chg_h;
399 u8 vact_st2_l;
400 u8 vact_st2_h;
401 u8 vact_st3_l;
402 u8 vact_st3_h;
403 u8 vact_st4_l;
404 u8 vact_st4_h;
405 u8 vsync_top_hdmi_l;
406 u8 vsync_top_hdmi_h;
407 u8 vsync_bot_hdmi_l;
408 u8 vsync_bot_hdmi_h;
409 u8 field_top_hdmi_l;
410 u8 field_top_hdmi_h;
411 u8 field_bot_hdmi_l;
412 u8 field_bot_hdmi_h;
413 u8 tg_3d;
414};
415
416struct hdmi_core_regs {
417 u8 h_blank[2];
418 u8 v2_blank[2];
419 u8 v1_blank[2];
420 u8 v_line[2];
421 u8 h_line[2];
422 u8 hsync_pol[1];
423 u8 vsync_pol[1];
424 u8 int_pro_mode[1];
425 u8 v_blank_f0[2];
426 u8 v_blank_f1[2];
427 u8 h_sync_start[2];
428 u8 h_sync_end[2];
429 u8 v_sync_line_bef_2[2];
430 u8 v_sync_line_bef_1[2];
431 u8 v_sync_line_aft_2[2];
432 u8 v_sync_line_aft_1[2];
433 u8 v_sync_line_aft_pxl_2[2];
434 u8 v_sync_line_aft_pxl_1[2];
435 u8 v_blank_f2[2]; /* for 3D mode */
436 u8 v_blank_f3[2]; /* for 3D mode */
437 u8 v_blank_f4[2]; /* for 3D mode */
438 u8 v_blank_f5[2]; /* for 3D mode */
439 u8 v_sync_line_aft_3[2];
440 u8 v_sync_line_aft_4[2];
441 u8 v_sync_line_aft_5[2];
442 u8 v_sync_line_aft_6[2];
443 u8 v_sync_line_aft_pxl_3[2];
444 u8 v_sync_line_aft_pxl_4[2];
445 u8 v_sync_line_aft_pxl_5[2];
446 u8 v_sync_line_aft_pxl_6[2];
447 u8 vact_space_1[2];
448 u8 vact_space_2[2];
449 u8 vact_space_3[2];
450 u8 vact_space_4[2];
451 u8 vact_space_5[2];
452 u8 vact_space_6[2];
453};
454
455struct hdmi_preset_conf {
456 struct hdmi_core_regs core;
457 struct hdmi_tg_regs tg;
458};
459
460struct hdmi_conf {
461 int width;
462 int height;
463 int vrefresh;
464 bool interlace;
465 const u8 *hdmiphy_data;
466 const struct hdmi_preset_conf *conf;
467};
468
469static const struct hdmi_preset_conf hdmi_conf_480p60 = {
470 .core = {
471 .h_blank = {0x8a, 0x00},
472 .v2_blank = {0x0d, 0x02},
473 .v1_blank = {0x2d, 0x00},
474 .v_line = {0x0d, 0x02},
475 .h_line = {0x5a, 0x03},
476 .hsync_pol = {0x01},
477 .vsync_pol = {0x01},
478 .int_pro_mode = {0x00},
479 .v_blank_f0 = {0xff, 0xff},
480 .v_blank_f1 = {0xff, 0xff},
481 .h_sync_start = {0x0e, 0x00},
482 .h_sync_end = {0x4c, 0x00},
483 .v_sync_line_bef_2 = {0x0f, 0x00},
484 .v_sync_line_bef_1 = {0x09, 0x00},
485 .v_sync_line_aft_2 = {0xff, 0xff},
486 .v_sync_line_aft_1 = {0xff, 0xff},
487 .v_sync_line_aft_pxl_2 = {0xff, 0xff},
488 .v_sync_line_aft_pxl_1 = {0xff, 0xff},
489 .v_blank_f2 = {0xff, 0xff},
490 .v_blank_f3 = {0xff, 0xff},
491 .v_blank_f4 = {0xff, 0xff},
492 .v_blank_f5 = {0xff, 0xff},
493 .v_sync_line_aft_3 = {0xff, 0xff},
494 .v_sync_line_aft_4 = {0xff, 0xff},
495 .v_sync_line_aft_5 = {0xff, 0xff},
496 .v_sync_line_aft_6 = {0xff, 0xff},
497 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
498 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
499 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
500 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
501 .vact_space_1 = {0xff, 0xff},
502 .vact_space_2 = {0xff, 0xff},
503 .vact_space_3 = {0xff, 0xff},
504 .vact_space_4 = {0xff, 0xff},
505 .vact_space_5 = {0xff, 0xff},
506 .vact_space_6 = {0xff, 0xff},
507 /* other don't care */
508 },
509 .tg = {
510 0x00, /* cmd */
511 0x5a, 0x03, /* h_fsz */
512 0x8a, 0x00, 0xd0, 0x02, /* hact */
513 0x0d, 0x02, /* v_fsz */
514 0x01, 0x00, 0x33, 0x02, /* vsync */
515 0x2d, 0x00, 0xe0, 0x01, /* vact */
516 0x33, 0x02, /* field_chg */
517 0x48, 0x02, /* vact_st2 */
518 0x00, 0x00, /* vact_st3 */
519 0x00, 0x00, /* vact_st4 */
520 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
521 0x01, 0x00, 0x33, 0x02, /* field top/bot */
522 0x00, /* 3d FP */
523 },
524};
525
526static const struct hdmi_preset_conf hdmi_conf_720p50 = {
527 .core = {
528 .h_blank = {0xbc, 0x02},
529 .v2_blank = {0xee, 0x02},
530 .v1_blank = {0x1e, 0x00},
531 .v_line = {0xee, 0x02},
532 .h_line = {0xbc, 0x07},
533 .hsync_pol = {0x00},
534 .vsync_pol = {0x00},
535 .int_pro_mode = {0x00},
536 .v_blank_f0 = {0xff, 0xff},
537 .v_blank_f1 = {0xff, 0xff},
538 .h_sync_start = {0xb6, 0x01},
539 .h_sync_end = {0xde, 0x01},
540 .v_sync_line_bef_2 = {0x0a, 0x00},
541 .v_sync_line_bef_1 = {0x05, 0x00},
542 .v_sync_line_aft_2 = {0xff, 0xff},
543 .v_sync_line_aft_1 = {0xff, 0xff},
544 .v_sync_line_aft_pxl_2 = {0xff, 0xff},
545 .v_sync_line_aft_pxl_1 = {0xff, 0xff},
546 .v_blank_f2 = {0xff, 0xff},
547 .v_blank_f3 = {0xff, 0xff},
548 .v_blank_f4 = {0xff, 0xff},
549 .v_blank_f5 = {0xff, 0xff},
550 .v_sync_line_aft_3 = {0xff, 0xff},
551 .v_sync_line_aft_4 = {0xff, 0xff},
552 .v_sync_line_aft_5 = {0xff, 0xff},
553 .v_sync_line_aft_6 = {0xff, 0xff},
554 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
555 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
556 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
557 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
558 .vact_space_1 = {0xff, 0xff},
559 .vact_space_2 = {0xff, 0xff},
560 .vact_space_3 = {0xff, 0xff},
561 .vact_space_4 = {0xff, 0xff},
562 .vact_space_5 = {0xff, 0xff},
563 .vact_space_6 = {0xff, 0xff},
564 /* other don't care */
565 },
566 .tg = {
567 0x00, /* cmd */
568 0xbc, 0x07, /* h_fsz */
569 0xbc, 0x02, 0x00, 0x05, /* hact */
570 0xee, 0x02, /* v_fsz */
571 0x01, 0x00, 0x33, 0x02, /* vsync */
572 0x1e, 0x00, 0xd0, 0x02, /* vact */
573 0x33, 0x02, /* field_chg */
574 0x48, 0x02, /* vact_st2 */
575 0x00, 0x00, /* vact_st3 */
576 0x00, 0x00, /* vact_st4 */
577 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
578 0x01, 0x00, 0x33, 0x02, /* field top/bot */
579 0x00, /* 3d FP */
580 },
581};
582
583static const struct hdmi_preset_conf hdmi_conf_720p60 = {
584 .core = {
585 .h_blank = {0x72, 0x01},
586 .v2_blank = {0xee, 0x02},
587 .v1_blank = {0x1e, 0x00},
588 .v_line = {0xee, 0x02},
589 .h_line = {0x72, 0x06},
590 .hsync_pol = {0x00},
591 .vsync_pol = {0x00},
592 .int_pro_mode = {0x00},
593 .v_blank_f0 = {0xff, 0xff},
594 .v_blank_f1 = {0xff, 0xff},
595 .h_sync_start = {0x6c, 0x00},
596 .h_sync_end = {0x94, 0x00},
597 .v_sync_line_bef_2 = {0x0a, 0x00},
598 .v_sync_line_bef_1 = {0x05, 0x00},
599 .v_sync_line_aft_2 = {0xff, 0xff},
600 .v_sync_line_aft_1 = {0xff, 0xff},
601 .v_sync_line_aft_pxl_2 = {0xff, 0xff},
602 .v_sync_line_aft_pxl_1 = {0xff, 0xff},
603 .v_blank_f2 = {0xff, 0xff},
604 .v_blank_f3 = {0xff, 0xff},
605 .v_blank_f4 = {0xff, 0xff},
606 .v_blank_f5 = {0xff, 0xff},
607 .v_sync_line_aft_3 = {0xff, 0xff},
608 .v_sync_line_aft_4 = {0xff, 0xff},
609 .v_sync_line_aft_5 = {0xff, 0xff},
610 .v_sync_line_aft_6 = {0xff, 0xff},
611 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
612 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
613 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
614 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
615 .vact_space_1 = {0xff, 0xff},
616 .vact_space_2 = {0xff, 0xff},
617 .vact_space_3 = {0xff, 0xff},
618 .vact_space_4 = {0xff, 0xff},
619 .vact_space_5 = {0xff, 0xff},
620 .vact_space_6 = {0xff, 0xff},
621 /* other don't care */
622 },
623 .tg = {
624 0x00, /* cmd */
625 0x72, 0x06, /* h_fsz */
626 0x72, 0x01, 0x00, 0x05, /* hact */
627 0xee, 0x02, /* v_fsz */
628 0x01, 0x00, 0x33, 0x02, /* vsync */
629 0x1e, 0x00, 0xd0, 0x02, /* vact */
630 0x33, 0x02, /* field_chg */
631 0x48, 0x02, /* vact_st2 */
632 0x00, 0x00, /* vact_st3 */
633 0x00, 0x00, /* vact_st4 */
634 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
635 0x01, 0x00, 0x33, 0x02, /* field top/bot */
636 0x00, /* 3d FP */
637 },
638};
639
640static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
641 .core = {
642 .h_blank = {0xd0, 0x02},
643 .v2_blank = {0x32, 0x02},
644 .v1_blank = {0x16, 0x00},
645 .v_line = {0x65, 0x04},
646 .h_line = {0x50, 0x0a},
647 .hsync_pol = {0x00},
648 .vsync_pol = {0x00},
649 .int_pro_mode = {0x01},
650 .v_blank_f0 = {0x49, 0x02},
651 .v_blank_f1 = {0x65, 0x04},
652 .h_sync_start = {0x0e, 0x02},
653 .h_sync_end = {0x3a, 0x02},
654 .v_sync_line_bef_2 = {0x07, 0x00},
655 .v_sync_line_bef_1 = {0x02, 0x00},
656 .v_sync_line_aft_2 = {0x39, 0x02},
657 .v_sync_line_aft_1 = {0x34, 0x02},
658 .v_sync_line_aft_pxl_2 = {0x38, 0x07},
659 .v_sync_line_aft_pxl_1 = {0x38, 0x07},
660 .v_blank_f2 = {0xff, 0xff},
661 .v_blank_f3 = {0xff, 0xff},
662 .v_blank_f4 = {0xff, 0xff},
663 .v_blank_f5 = {0xff, 0xff},
664 .v_sync_line_aft_3 = {0xff, 0xff},
665 .v_sync_line_aft_4 = {0xff, 0xff},
666 .v_sync_line_aft_5 = {0xff, 0xff},
667 .v_sync_line_aft_6 = {0xff, 0xff},
668 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
669 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
670 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
671 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
672 .vact_space_1 = {0xff, 0xff},
673 .vact_space_2 = {0xff, 0xff},
674 .vact_space_3 = {0xff, 0xff},
675 .vact_space_4 = {0xff, 0xff},
676 .vact_space_5 = {0xff, 0xff},
677 .vact_space_6 = {0xff, 0xff},
678 /* other don't care */
679 },
680 .tg = {
681 0x00, /* cmd */
682 0x50, 0x0a, /* h_fsz */
683 0xd0, 0x02, 0x80, 0x07, /* hact */
684 0x65, 0x04, /* v_fsz */
685 0x01, 0x00, 0x33, 0x02, /* vsync */
686 0x16, 0x00, 0x1c, 0x02, /* vact */
687 0x33, 0x02, /* field_chg */
688 0x49, 0x02, /* vact_st2 */
689 0x00, 0x00, /* vact_st3 */
690 0x00, 0x00, /* vact_st4 */
691 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
692 0x01, 0x00, 0x33, 0x02, /* field top/bot */
693 0x00, /* 3d FP */
694 },
695};
696
697static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
698 .core = {
699 .h_blank = {0x18, 0x01},
700 .v2_blank = {0x32, 0x02},
701 .v1_blank = {0x16, 0x00},
702 .v_line = {0x65, 0x04},
703 .h_line = {0x98, 0x08},
704 .hsync_pol = {0x00},
705 .vsync_pol = {0x00},
706 .int_pro_mode = {0x01},
707 .v_blank_f0 = {0x49, 0x02},
708 .v_blank_f1 = {0x65, 0x04},
709 .h_sync_start = {0x56, 0x00},
710 .h_sync_end = {0x82, 0x00},
711 .v_sync_line_bef_2 = {0x07, 0x00},
712 .v_sync_line_bef_1 = {0x02, 0x00},
713 .v_sync_line_aft_2 = {0x39, 0x02},
714 .v_sync_line_aft_1 = {0x34, 0x02},
715 .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
716 .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
717 .v_blank_f2 = {0xff, 0xff},
718 .v_blank_f3 = {0xff, 0xff},
719 .v_blank_f4 = {0xff, 0xff},
720 .v_blank_f5 = {0xff, 0xff},
721 .v_sync_line_aft_3 = {0xff, 0xff},
722 .v_sync_line_aft_4 = {0xff, 0xff},
723 .v_sync_line_aft_5 = {0xff, 0xff},
724 .v_sync_line_aft_6 = {0xff, 0xff},
725 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
726 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
727 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
728 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
729 .vact_space_1 = {0xff, 0xff},
730 .vact_space_2 = {0xff, 0xff},
731 .vact_space_3 = {0xff, 0xff},
732 .vact_space_4 = {0xff, 0xff},
733 .vact_space_5 = {0xff, 0xff},
734 .vact_space_6 = {0xff, 0xff},
735 /* other don't care */
736 },
737 .tg = {
738 0x00, /* cmd */
739 0x98, 0x08, /* h_fsz */
740 0x18, 0x01, 0x80, 0x07, /* hact */
741 0x65, 0x04, /* v_fsz */
742 0x01, 0x00, 0x33, 0x02, /* vsync */
743 0x16, 0x00, 0x1c, 0x02, /* vact */
744 0x33, 0x02, /* field_chg */
745 0x49, 0x02, /* vact_st2 */
746 0x00, 0x00, /* vact_st3 */
747 0x00, 0x00, /* vact_st4 */
748 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
749 0x01, 0x00, 0x33, 0x02, /* field top/bot */
750 0x00, /* 3d FP */
751 },
752};
753
754static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
755 .core = {
756 .h_blank = {0xd0, 0x02},
757 .v2_blank = {0x65, 0x04},
758 .v1_blank = {0x2d, 0x00},
759 .v_line = {0x65, 0x04},
760 .h_line = {0x50, 0x0a},
761 .hsync_pol = {0x00},
762 .vsync_pol = {0x00},
763 .int_pro_mode = {0x00},
764 .v_blank_f0 = {0xff, 0xff},
765 .v_blank_f1 = {0xff, 0xff},
766 .h_sync_start = {0x0e, 0x02},
767 .h_sync_end = {0x3a, 0x02},
768 .v_sync_line_bef_2 = {0x09, 0x00},
769 .v_sync_line_bef_1 = {0x04, 0x00},
770 .v_sync_line_aft_2 = {0xff, 0xff},
771 .v_sync_line_aft_1 = {0xff, 0xff},
772 .v_sync_line_aft_pxl_2 = {0xff, 0xff},
773 .v_sync_line_aft_pxl_1 = {0xff, 0xff},
774 .v_blank_f2 = {0xff, 0xff},
775 .v_blank_f3 = {0xff, 0xff},
776 .v_blank_f4 = {0xff, 0xff},
777 .v_blank_f5 = {0xff, 0xff},
778 .v_sync_line_aft_3 = {0xff, 0xff},
779 .v_sync_line_aft_4 = {0xff, 0xff},
780 .v_sync_line_aft_5 = {0xff, 0xff},
781 .v_sync_line_aft_6 = {0xff, 0xff},
782 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
783 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
784 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
785 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
786 .vact_space_1 = {0xff, 0xff},
787 .vact_space_2 = {0xff, 0xff},
788 .vact_space_3 = {0xff, 0xff},
789 .vact_space_4 = {0xff, 0xff},
790 .vact_space_5 = {0xff, 0xff},
791 .vact_space_6 = {0xff, 0xff},
792 /* other don't care */
793 },
794 .tg = {
795 0x00, /* cmd */
796 0x50, 0x0a, /* h_fsz */
797 0xd0, 0x02, 0x80, 0x07, /* hact */
798 0x65, 0x04, /* v_fsz */
799 0x01, 0x00, 0x33, 0x02, /* vsync */
800 0x2d, 0x00, 0x38, 0x04, /* vact */
801 0x33, 0x02, /* field_chg */
802 0x48, 0x02, /* vact_st2 */
803 0x00, 0x00, /* vact_st3 */
804 0x00, 0x00, /* vact_st4 */
805 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
806 0x01, 0x00, 0x33, 0x02, /* field top/bot */
807 0x00, /* 3d FP */
808 },
809};
810
811static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
812 .core = {
813 .h_blank = {0x18, 0x01},
814 .v2_blank = {0x65, 0x04},
815 .v1_blank = {0x2d, 0x00},
816 .v_line = {0x65, 0x04},
817 .h_line = {0x98, 0x08},
818 .hsync_pol = {0x00},
819 .vsync_pol = {0x00},
820 .int_pro_mode = {0x00},
821 .v_blank_f0 = {0xff, 0xff},
822 .v_blank_f1 = {0xff, 0xff},
823 .h_sync_start = {0x56, 0x00},
824 .h_sync_end = {0x82, 0x00},
825 .v_sync_line_bef_2 = {0x09, 0x00},
826 .v_sync_line_bef_1 = {0x04, 0x00},
827 .v_sync_line_aft_2 = {0xff, 0xff},
828 .v_sync_line_aft_1 = {0xff, 0xff},
829 .v_sync_line_aft_pxl_2 = {0xff, 0xff},
830 .v_sync_line_aft_pxl_1 = {0xff, 0xff},
831 .v_blank_f2 = {0xff, 0xff},
832 .v_blank_f3 = {0xff, 0xff},
833 .v_blank_f4 = {0xff, 0xff},
834 .v_blank_f5 = {0xff, 0xff},
835 .v_sync_line_aft_3 = {0xff, 0xff},
836 .v_sync_line_aft_4 = {0xff, 0xff},
837 .v_sync_line_aft_5 = {0xff, 0xff},
838 .v_sync_line_aft_6 = {0xff, 0xff},
839 .v_sync_line_aft_pxl_3 = {0xff, 0xff},
840 .v_sync_line_aft_pxl_4 = {0xff, 0xff},
841 .v_sync_line_aft_pxl_5 = {0xff, 0xff},
842 .v_sync_line_aft_pxl_6 = {0xff, 0xff},
843 /* other don't care */
844 },
845 .tg = {
846 0x00, /* cmd */
847 0x98, 0x08, /* h_fsz */
848 0x18, 0x01, 0x80, 0x07, /* hact */
849 0x65, 0x04, /* v_fsz */
850 0x01, 0x00, 0x33, 0x02, /* vsync */
851 0x2d, 0x00, 0x38, 0x04, /* vact */
852 0x33, 0x02, /* field_chg */
853 0x48, 0x02, /* vact_st2 */
854 0x00, 0x00, /* vact_st3 */
855 0x00, 0x00, /* vact_st4 */
856 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
857 0x01, 0x00, 0x33, 0x02, /* field top/bot */
858 0x00, /* 3d FP */
859 },
860};
861
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900862static const struct hdmi_conf hdmi_confs[] = {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900863 { 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p60 },
864 { 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p50 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900865 { 1280, 720, 60, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900866 { 1920, 1080, 50, true, hdmiphy_conf74_25, &hdmi_conf_1080i50 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900867 { 1920, 1080, 60, true, hdmiphy_conf74_25, &hdmi_conf_1080i60 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900868 { 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900869 { 1920, 1080, 60, false, hdmiphy_conf148_5, &hdmi_conf_1080p60 },
870};
871
872
873static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
874{
875 return readl(hdata->regs + reg_id);
876}
877
878static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
879 u32 reg_id, u8 value)
880{
881 writeb(value, hdata->regs + reg_id);
882}
883
884static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
885 u32 reg_id, u32 value, u32 mask)
886{
887 u32 old = readl(hdata->regs + reg_id);
888 value = (value & mask) | (old & ~mask);
889 writel(value, hdata->regs + reg_id);
890}
891
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900892static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900893{
894#define DUMPREG(reg_id) \
895 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
896 readl(hdata->regs + reg_id))
897 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
898 DUMPREG(HDMI_INTC_FLAG);
899 DUMPREG(HDMI_INTC_CON);
900 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900901 DUMPREG(HDMI_V13_PHY_RSTOUT);
902 DUMPREG(HDMI_V13_PHY_VPLL);
903 DUMPREG(HDMI_V13_PHY_CMU);
904 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900905
906 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
907 DUMPREG(HDMI_CON_0);
908 DUMPREG(HDMI_CON_1);
909 DUMPREG(HDMI_CON_2);
910 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900911 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900912 DUMPREG(HDMI_STATUS_EN);
913 DUMPREG(HDMI_HPD);
914 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900915 DUMPREG(HDMI_V13_HPD_GEN);
916 DUMPREG(HDMI_V13_DC_CONTROL);
917 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900918
919 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
920 DUMPREG(HDMI_H_BLANK_0);
921 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900922 DUMPREG(HDMI_V13_V_BLANK_0);
923 DUMPREG(HDMI_V13_V_BLANK_1);
924 DUMPREG(HDMI_V13_V_BLANK_2);
925 DUMPREG(HDMI_V13_H_V_LINE_0);
926 DUMPREG(HDMI_V13_H_V_LINE_1);
927 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900928 DUMPREG(HDMI_VSYNC_POL);
929 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900930 DUMPREG(HDMI_V13_V_BLANK_F_0);
931 DUMPREG(HDMI_V13_V_BLANK_F_1);
932 DUMPREG(HDMI_V13_V_BLANK_F_2);
933 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
934 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
935 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
936 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
937 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
938 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
939 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
940 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
941 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
942 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
943 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
944 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900945
946 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
947 DUMPREG(HDMI_TG_CMD);
948 DUMPREG(HDMI_TG_H_FSZ_L);
949 DUMPREG(HDMI_TG_H_FSZ_H);
950 DUMPREG(HDMI_TG_HACT_ST_L);
951 DUMPREG(HDMI_TG_HACT_ST_H);
952 DUMPREG(HDMI_TG_HACT_SZ_L);
953 DUMPREG(HDMI_TG_HACT_SZ_H);
954 DUMPREG(HDMI_TG_V_FSZ_L);
955 DUMPREG(HDMI_TG_V_FSZ_H);
956 DUMPREG(HDMI_TG_VSYNC_L);
957 DUMPREG(HDMI_TG_VSYNC_H);
958 DUMPREG(HDMI_TG_VSYNC2_L);
959 DUMPREG(HDMI_TG_VSYNC2_H);
960 DUMPREG(HDMI_TG_VACT_ST_L);
961 DUMPREG(HDMI_TG_VACT_ST_H);
962 DUMPREG(HDMI_TG_VACT_SZ_L);
963 DUMPREG(HDMI_TG_VACT_SZ_H);
964 DUMPREG(HDMI_TG_FIELD_CHG_L);
965 DUMPREG(HDMI_TG_FIELD_CHG_H);
966 DUMPREG(HDMI_TG_VACT_ST2_L);
967 DUMPREG(HDMI_TG_VACT_ST2_H);
968 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
969 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
970 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
971 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
972 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
973 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
974 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
975 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
976#undef DUMPREG
977}
978
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900979static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
980{
981 int i;
982
983#define DUMPREG(reg_id) \
984 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
985 readl(hdata->regs + reg_id))
986
987 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
988 DUMPREG(HDMI_INTC_CON);
989 DUMPREG(HDMI_INTC_FLAG);
990 DUMPREG(HDMI_HPD_STATUS);
991 DUMPREG(HDMI_INTC_CON_1);
992 DUMPREG(HDMI_INTC_FLAG_1);
993 DUMPREG(HDMI_PHY_STATUS_0);
994 DUMPREG(HDMI_PHY_STATUS_PLL);
995 DUMPREG(HDMI_PHY_CON_0);
996 DUMPREG(HDMI_PHY_RSTOUT);
997 DUMPREG(HDMI_PHY_VPLL);
998 DUMPREG(HDMI_PHY_CMU);
999 DUMPREG(HDMI_CORE_RSTOUT);
1000
1001 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
1002 DUMPREG(HDMI_CON_0);
1003 DUMPREG(HDMI_CON_1);
1004 DUMPREG(HDMI_CON_2);
1005 DUMPREG(HDMI_SYS_STATUS);
1006 DUMPREG(HDMI_PHY_STATUS_0);
1007 DUMPREG(HDMI_STATUS_EN);
1008 DUMPREG(HDMI_HPD);
1009 DUMPREG(HDMI_MODE_SEL);
1010 DUMPREG(HDMI_ENC_EN);
1011 DUMPREG(HDMI_DC_CONTROL);
1012 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
1013
1014 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
1015 DUMPREG(HDMI_H_BLANK_0);
1016 DUMPREG(HDMI_H_BLANK_1);
1017 DUMPREG(HDMI_V2_BLANK_0);
1018 DUMPREG(HDMI_V2_BLANK_1);
1019 DUMPREG(HDMI_V1_BLANK_0);
1020 DUMPREG(HDMI_V1_BLANK_1);
1021 DUMPREG(HDMI_V_LINE_0);
1022 DUMPREG(HDMI_V_LINE_1);
1023 DUMPREG(HDMI_H_LINE_0);
1024 DUMPREG(HDMI_H_LINE_1);
1025 DUMPREG(HDMI_HSYNC_POL);
1026
1027 DUMPREG(HDMI_VSYNC_POL);
1028 DUMPREG(HDMI_INT_PRO_MODE);
1029 DUMPREG(HDMI_V_BLANK_F0_0);
1030 DUMPREG(HDMI_V_BLANK_F0_1);
1031 DUMPREG(HDMI_V_BLANK_F1_0);
1032 DUMPREG(HDMI_V_BLANK_F1_1);
1033
1034 DUMPREG(HDMI_H_SYNC_START_0);
1035 DUMPREG(HDMI_H_SYNC_START_1);
1036 DUMPREG(HDMI_H_SYNC_END_0);
1037 DUMPREG(HDMI_H_SYNC_END_1);
1038
1039 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
1040 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
1041 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
1042 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
1043
1044 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
1045 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
1046 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
1047 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
1048
1049 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
1050 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
1051 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
1052 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
1053
1054 DUMPREG(HDMI_V_BLANK_F2_0);
1055 DUMPREG(HDMI_V_BLANK_F2_1);
1056 DUMPREG(HDMI_V_BLANK_F3_0);
1057 DUMPREG(HDMI_V_BLANK_F3_1);
1058 DUMPREG(HDMI_V_BLANK_F4_0);
1059 DUMPREG(HDMI_V_BLANK_F4_1);
1060 DUMPREG(HDMI_V_BLANK_F5_0);
1061 DUMPREG(HDMI_V_BLANK_F5_1);
1062
1063 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
1064 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
1065 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
1066 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
1067 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
1068 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
1069 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
1070 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
1071
1072 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
1073 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
1074 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
1075 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
1076 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
1077 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
1078 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
1079 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
1080
1081 DUMPREG(HDMI_VACT_SPACE_1_0);
1082 DUMPREG(HDMI_VACT_SPACE_1_1);
1083 DUMPREG(HDMI_VACT_SPACE_2_0);
1084 DUMPREG(HDMI_VACT_SPACE_2_1);
1085 DUMPREG(HDMI_VACT_SPACE_3_0);
1086 DUMPREG(HDMI_VACT_SPACE_3_1);
1087 DUMPREG(HDMI_VACT_SPACE_4_0);
1088 DUMPREG(HDMI_VACT_SPACE_4_1);
1089 DUMPREG(HDMI_VACT_SPACE_5_0);
1090 DUMPREG(HDMI_VACT_SPACE_5_1);
1091 DUMPREG(HDMI_VACT_SPACE_6_0);
1092 DUMPREG(HDMI_VACT_SPACE_6_1);
1093
1094 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
1095 DUMPREG(HDMI_TG_CMD);
1096 DUMPREG(HDMI_TG_H_FSZ_L);
1097 DUMPREG(HDMI_TG_H_FSZ_H);
1098 DUMPREG(HDMI_TG_HACT_ST_L);
1099 DUMPREG(HDMI_TG_HACT_ST_H);
1100 DUMPREG(HDMI_TG_HACT_SZ_L);
1101 DUMPREG(HDMI_TG_HACT_SZ_H);
1102 DUMPREG(HDMI_TG_V_FSZ_L);
1103 DUMPREG(HDMI_TG_V_FSZ_H);
1104 DUMPREG(HDMI_TG_VSYNC_L);
1105 DUMPREG(HDMI_TG_VSYNC_H);
1106 DUMPREG(HDMI_TG_VSYNC2_L);
1107 DUMPREG(HDMI_TG_VSYNC2_H);
1108 DUMPREG(HDMI_TG_VACT_ST_L);
1109 DUMPREG(HDMI_TG_VACT_ST_H);
1110 DUMPREG(HDMI_TG_VACT_SZ_L);
1111 DUMPREG(HDMI_TG_VACT_SZ_H);
1112 DUMPREG(HDMI_TG_FIELD_CHG_L);
1113 DUMPREG(HDMI_TG_FIELD_CHG_H);
1114 DUMPREG(HDMI_TG_VACT_ST2_L);
1115 DUMPREG(HDMI_TG_VACT_ST2_H);
1116 DUMPREG(HDMI_TG_VACT_ST3_L);
1117 DUMPREG(HDMI_TG_VACT_ST3_H);
1118 DUMPREG(HDMI_TG_VACT_ST4_L);
1119 DUMPREG(HDMI_TG_VACT_ST4_H);
1120 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
1121 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
1122 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
1123 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
1124 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
1125 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
1126 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
1127 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
1128 DUMPREG(HDMI_TG_3D);
1129
1130 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
1131 DUMPREG(HDMI_AVI_CON);
1132 DUMPREG(HDMI_AVI_HEADER0);
1133 DUMPREG(HDMI_AVI_HEADER1);
1134 DUMPREG(HDMI_AVI_HEADER2);
1135 DUMPREG(HDMI_AVI_CHECK_SUM);
1136 DUMPREG(HDMI_VSI_CON);
1137 DUMPREG(HDMI_VSI_HEADER0);
1138 DUMPREG(HDMI_VSI_HEADER1);
1139 DUMPREG(HDMI_VSI_HEADER2);
1140 for (i = 0; i < 7; ++i)
1141 DUMPREG(HDMI_VSI_DATA(i));
1142
1143#undef DUMPREG
1144}
1145
1146static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
1147{
1148 if (hdata->is_v13)
1149 hdmi_v13_regs_dump(hdata, prefix);
1150 else
1151 hdmi_v14_regs_dump(hdata, prefix);
1152}
1153
1154static int hdmi_v13_conf_index(struct drm_display_mode *mode)
1155{
1156 int i;
1157
1158 for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
1159 if (hdmi_v13_confs[i].width == mode->hdisplay &&
1160 hdmi_v13_confs[i].height == mode->vdisplay &&
1161 hdmi_v13_confs[i].vrefresh == mode->vrefresh &&
1162 hdmi_v13_confs[i].interlace ==
1163 ((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
1164 true : false))
1165 return i;
1166
Inki Dae1de425b2012-03-16 18:47:04 +09001167 return -EINVAL;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001168}
1169
1170static int hdmi_v14_conf_index(struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001171{
1172 int i;
1173
1174 for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
1175 if (hdmi_confs[i].width == mode->hdisplay &&
1176 hdmi_confs[i].height == mode->vdisplay &&
1177 hdmi_confs[i].vrefresh == mode->vrefresh &&
1178 hdmi_confs[i].interlace ==
1179 ((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
1180 true : false))
1181 return i;
1182
Inki Dae1de425b2012-03-16 18:47:04 +09001183 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001184}
1185
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001186static int hdmi_conf_index(struct hdmi_context *hdata,
1187 struct drm_display_mode *mode)
1188{
1189 if (hdata->is_v13)
1190 return hdmi_v13_conf_index(mode);
Inki Dae1de425b2012-03-16 18:47:04 +09001191
1192 return hdmi_v14_conf_index(mode);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001193}
1194
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001195static bool hdmi_is_connected(void *ctx)
1196{
1197 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1198 u32 val = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
1199
1200 if (val)
1201 return true;
1202
1203 return false;
1204}
1205
1206static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
1207 u8 *edid, int len)
1208{
1209 struct edid *raw_edid;
1210 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1211
1212 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1213
1214 if (!hdata->ddc_port)
1215 return -ENODEV;
1216
1217 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
1218 if (raw_edid) {
1219 memcpy(edid, raw_edid, min((1 + raw_edid->extensions)
1220 * EDID_LENGTH, len));
1221 DRM_DEBUG_KMS("width[%d] x height[%d]\n",
1222 raw_edid->width_cm, raw_edid->height_cm);
1223 } else {
1224 return -ENODEV;
1225 }
1226
1227 return 0;
1228}
1229
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001230static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001231{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001232 int i;
1233
Inki Dae1de425b2012-03-16 18:47:04 +09001234 DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
1235 check_timing->xres, check_timing->yres,
1236 check_timing->refresh, (check_timing->vmode &
1237 FB_VMODE_INTERLACED) ? true : false);
1238
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001239 for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
1240 if (hdmi_v13_confs[i].width == check_timing->xres &&
1241 hdmi_v13_confs[i].height == check_timing->yres &&
1242 hdmi_v13_confs[i].vrefresh == check_timing->refresh &&
1243 hdmi_v13_confs[i].interlace ==
1244 ((check_timing->vmode & FB_VMODE_INTERLACED) ?
1245 true : false))
Inki Dae1de425b2012-03-16 18:47:04 +09001246 return 0;
1247
1248 /* TODO */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001249
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001250 return -EINVAL;
1251}
1252
1253static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
1254{
1255 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001256
Inki Dae1de425b2012-03-16 18:47:04 +09001257 DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
1258 check_timing->xres, check_timing->yres,
1259 check_timing->refresh, (check_timing->vmode &
1260 FB_VMODE_INTERLACED) ? true : false);
1261
1262 for (i = 0; i < ARRAY_SIZE(hdmi_confs); i++)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001263 if (hdmi_confs[i].width == check_timing->xres &&
1264 hdmi_confs[i].height == check_timing->yres &&
1265 hdmi_confs[i].vrefresh == check_timing->refresh &&
1266 hdmi_confs[i].interlace ==
1267 ((check_timing->vmode & FB_VMODE_INTERLACED) ?
1268 true : false))
Inki Dae1de425b2012-03-16 18:47:04 +09001269 return 0;
1270
1271 /* TODO */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001272
1273 return -EINVAL;
1274}
1275
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001276static int hdmi_check_timing(void *ctx, void *timing)
1277{
1278 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1279 struct fb_videomode *check_timing = timing;
1280
1281 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1282
1283 DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", check_timing->xres,
1284 check_timing->yres, check_timing->refresh,
1285 check_timing->vmode);
1286
1287 if (hdata->is_v13)
1288 return hdmi_v13_check_timing(check_timing);
1289 else
1290 return hdmi_v14_check_timing(check_timing);
1291}
1292
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001293static int hdmi_display_power_on(void *ctx, int mode)
1294{
1295 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1296
1297 switch (mode) {
1298 case DRM_MODE_DPMS_ON:
1299 DRM_DEBUG_KMS("hdmi [on]\n");
1300 break;
1301 case DRM_MODE_DPMS_STANDBY:
1302 break;
1303 case DRM_MODE_DPMS_SUSPEND:
1304 break;
1305 case DRM_MODE_DPMS_OFF:
1306 DRM_DEBUG_KMS("hdmi [off]\n");
1307 break;
1308 default:
1309 break;
1310 }
1311
1312 return 0;
1313}
1314
1315static struct exynos_hdmi_display_ops display_ops = {
1316 .is_connected = hdmi_is_connected,
1317 .get_edid = hdmi_get_edid,
1318 .check_timing = hdmi_check_timing,
1319 .power_on = hdmi_display_power_on,
1320};
1321
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001322static void hdmi_set_acr(u32 freq, u8 *acr)
1323{
1324 u32 n, cts;
1325
1326 switch (freq) {
1327 case 32000:
1328 n = 4096;
1329 cts = 27000;
1330 break;
1331 case 44100:
1332 n = 6272;
1333 cts = 30000;
1334 break;
1335 case 88200:
1336 n = 12544;
1337 cts = 30000;
1338 break;
1339 case 176400:
1340 n = 25088;
1341 cts = 30000;
1342 break;
1343 case 48000:
1344 n = 6144;
1345 cts = 27000;
1346 break;
1347 case 96000:
1348 n = 12288;
1349 cts = 27000;
1350 break;
1351 case 192000:
1352 n = 24576;
1353 cts = 27000;
1354 break;
1355 default:
1356 n = 0;
1357 cts = 0;
1358 break;
1359 }
1360
1361 acr[1] = cts >> 16;
1362 acr[2] = cts >> 8 & 0xff;
1363 acr[3] = cts & 0xff;
1364
1365 acr[4] = n >> 16;
1366 acr[5] = n >> 8 & 0xff;
1367 acr[6] = n & 0xff;
1368}
1369
1370static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1371{
1372 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1373 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1374 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1375 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1376 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1377 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1378 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1379 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1380 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1381
1382 if (hdata->is_v13)
1383 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1384 else
1385 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1386}
1387
1388static void hdmi_audio_init(struct hdmi_context *hdata)
1389{
1390 u32 sample_rate, bits_per_sample, frame_size_code;
1391 u32 data_num, bit_ch, sample_frq;
1392 u32 val;
1393 u8 acr[7];
1394
1395 sample_rate = 44100;
1396 bits_per_sample = 16;
1397 frame_size_code = 0;
1398
1399 switch (bits_per_sample) {
1400 case 20:
1401 data_num = 2;
1402 bit_ch = 1;
1403 break;
1404 case 24:
1405 data_num = 3;
1406 bit_ch = 1;
1407 break;
1408 default:
1409 data_num = 1;
1410 bit_ch = 0;
1411 break;
1412 }
1413
1414 hdmi_set_acr(sample_rate, acr);
1415 hdmi_reg_acr(hdata, acr);
1416
1417 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1418 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1419 | HDMI_I2S_MUX_ENABLE);
1420
1421 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1422 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1423
1424 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1425
1426 sample_frq = (sample_rate == 44100) ? 0 :
1427 (sample_rate == 48000) ? 2 :
1428 (sample_rate == 32000) ? 3 :
1429 (sample_rate == 96000) ? 0xa : 0x0;
1430
1431 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1432 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1433
1434 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1435 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1436
1437 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1438 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1439 | HDMI_I2S_SEL_LRCK(6));
1440 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1441 | HDMI_I2S_SEL_SDATA2(4));
1442 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1443 | HDMI_I2S_SEL_SDATA2(2));
1444 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1445
1446 /* I2S_CON_1 & 2 */
1447 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1448 | HDMI_I2S_L_CH_LOW_POL);
1449 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1450 | HDMI_I2S_SET_BIT_CH(bit_ch)
1451 | HDMI_I2S_SET_SDATA_BIT(data_num)
1452 | HDMI_I2S_BASIC_FORMAT);
1453
1454 /* Configure register related to CUV information */
1455 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1456 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1457 | HDMI_I2S_COPYRIGHT
1458 | HDMI_I2S_LINEAR_PCM
1459 | HDMI_I2S_CONSUMER_FORMAT);
1460 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1461 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1462 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1463 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1464 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1465 HDMI_I2S_ORG_SMP_FREQ_44_1
1466 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1467 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1468
1469 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1470}
1471
1472static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1473{
1474 u32 mod;
1475
1476 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
1477 if (mod & HDMI_DVI_MODE_EN)
1478 return;
1479
1480 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1481 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1482 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1483}
1484
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001485static void hdmi_conf_reset(struct hdmi_context *hdata)
1486{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001487 u32 reg;
1488
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001489 /* disable hpd handle for drm */
1490 hdata->hpd_handle = false;
1491
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001492 if (hdata->is_v13)
1493 reg = HDMI_V13_CORE_RSTOUT;
1494 else
1495 reg = HDMI_CORE_RSTOUT;
1496
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001497 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001498 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001499 mdelay(10);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001500 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001501 mdelay(10);
1502
1503 /* enable hpd handle for drm */
1504 hdata->hpd_handle = true;
1505}
1506
1507static void hdmi_conf_init(struct hdmi_context *hdata)
1508{
1509 /* disable hpd handle for drm */
1510 hdata->hpd_handle = false;
1511
1512 /* enable HPD interrupts */
1513 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1514 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
1515 mdelay(10);
1516 hdmi_reg_writemask(hdata, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
1517 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
1518
1519 /* choose HDMI mode */
1520 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1521 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1522 /* disable bluescreen */
1523 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001524
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001525 if (hdata->is_v13) {
1526 /* choose bluescreen (fecal) color */
1527 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1528 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1529 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1530
1531 /* enable AVI packet every vsync, fixes purple line problem */
1532 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1533 /* force RGB, look to CEA-861-D, table 7 for more detail */
1534 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1535 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1536
1537 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1538 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1539 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1540 } else {
1541 /* enable AVI packet every vsync, fixes purple line problem */
1542 hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
1543 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 2 << 5);
1544 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1545 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001546
1547 /* enable hpd handle for drm */
1548 hdata->hpd_handle = true;
1549}
1550
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001551static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001552{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001553 const struct hdmi_v13_preset_conf *conf =
1554 hdmi_v13_confs[hdata->cur_conf].conf;
1555 const struct hdmi_v13_core_regs *core = &conf->core;
1556 const struct hdmi_v13_tg_regs *tg = &conf->tg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001557 int tries;
1558
1559 /* setting core registers */
1560 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1561 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001562 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1563 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1564 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1565 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1566 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1567 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001568 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1569 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001570 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1571 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1572 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1573 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1574 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1575 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1576 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1577 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1578 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1579 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1580 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1581 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1582 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1583 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1584 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001585 /* Timing generator registers */
1586 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
1587 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
1588 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
1589 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
1590 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
1591 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
1592 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
1593 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
1594 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
1595 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
1596 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
1597 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
1598 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
1599 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
1600 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
1601 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
1602 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
1603 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
1604 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
1605 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
1606 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
1607 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
1608 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
1609 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
1610 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
1611 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
1612 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
1613 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
1614
1615 /* waiting for HDMIPHY's PLL to get to steady state */
1616 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001617 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001618 if (val & HDMI_PHY_STATUS_READY)
1619 break;
1620 mdelay(1);
1621 }
1622 /* steady state not achieved */
1623 if (tries == 0) {
1624 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1625 hdmi_regs_dump(hdata, "timing apply");
1626 }
1627
1628 clk_disable(hdata->res.sclk_hdmi);
1629 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
1630 clk_enable(hdata->res.sclk_hdmi);
1631
1632 /* enable HDMI and timing generator */
1633 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1634 if (core->int_pro_mode[0])
1635 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1636 HDMI_FIELD_EN);
1637 else
1638 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1639}
1640
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001641static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
1642{
1643 const struct hdmi_preset_conf *conf = hdmi_confs[hdata->cur_conf].conf;
1644 const struct hdmi_core_regs *core = &conf->core;
1645 const struct hdmi_tg_regs *tg = &conf->tg;
1646 int tries;
1647
1648 /* setting core registers */
1649 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1650 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1651 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1652 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1653 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1654 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1655 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1656 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1657 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1658 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1659 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1660 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1661 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1662 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1663 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1664 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1665 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1666 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1667 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1668 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1669 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1670 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1671 core->v_sync_line_bef_2[0]);
1672 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1673 core->v_sync_line_bef_2[1]);
1674 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1675 core->v_sync_line_bef_1[0]);
1676 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1677 core->v_sync_line_bef_1[1]);
1678 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1679 core->v_sync_line_aft_2[0]);
1680 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1681 core->v_sync_line_aft_2[1]);
1682 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1683 core->v_sync_line_aft_1[0]);
1684 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1685 core->v_sync_line_aft_1[1]);
1686 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1687 core->v_sync_line_aft_pxl_2[0]);
1688 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1689 core->v_sync_line_aft_pxl_2[1]);
1690 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1691 core->v_sync_line_aft_pxl_1[0]);
1692 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1693 core->v_sync_line_aft_pxl_1[1]);
1694 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1695 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1696 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1697 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1698 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1699 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1700 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1701 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1702 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1703 core->v_sync_line_aft_3[0]);
1704 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1705 core->v_sync_line_aft_3[1]);
1706 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1707 core->v_sync_line_aft_4[0]);
1708 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1709 core->v_sync_line_aft_4[1]);
1710 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1711 core->v_sync_line_aft_5[0]);
1712 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1713 core->v_sync_line_aft_5[1]);
1714 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1715 core->v_sync_line_aft_6[0]);
1716 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1717 core->v_sync_line_aft_6[1]);
1718 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1719 core->v_sync_line_aft_pxl_3[0]);
1720 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1721 core->v_sync_line_aft_pxl_3[1]);
1722 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1723 core->v_sync_line_aft_pxl_4[0]);
1724 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1725 core->v_sync_line_aft_pxl_4[1]);
1726 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1727 core->v_sync_line_aft_pxl_5[0]);
1728 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1729 core->v_sync_line_aft_pxl_5[1]);
1730 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1731 core->v_sync_line_aft_pxl_6[0]);
1732 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1733 core->v_sync_line_aft_pxl_6[1]);
1734 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1735 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1736 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1737 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1738 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1739 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1740 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1741 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1742 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1743 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1744 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1745 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1746
1747 /* Timing generator registers */
1748 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
1749 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
1750 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
1751 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
1752 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
1753 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
1754 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
1755 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
1756 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
1757 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
1758 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
1759 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
1760 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
1761 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
1762 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
1763 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
1764 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
1765 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
1766 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
1767 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
1768 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3_l);
1769 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3_h);
1770 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4_l);
1771 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4_h);
1772 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
1773 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
1774 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
1775 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
1776 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
1777 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
1778 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
1779 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
1780 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d);
1781
1782 /* waiting for HDMIPHY's PLL to get to steady state */
1783 for (tries = 100; tries; --tries) {
1784 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1785 if (val & HDMI_PHY_STATUS_READY)
1786 break;
1787 mdelay(1);
1788 }
1789 /* steady state not achieved */
1790 if (tries == 0) {
1791 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1792 hdmi_regs_dump(hdata, "timing apply");
1793 }
1794
1795 clk_disable(hdata->res.sclk_hdmi);
1796 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
1797 clk_enable(hdata->res.sclk_hdmi);
1798
1799 /* enable HDMI and timing generator */
1800 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1801 if (core->int_pro_mode[0])
1802 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1803 HDMI_FIELD_EN);
1804 else
1805 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1806}
1807
1808static void hdmi_timing_apply(struct hdmi_context *hdata)
1809{
1810 if (hdata->is_v13)
1811 hdmi_v13_timing_apply(hdata);
1812 else
1813 hdmi_v14_timing_apply(hdata);
1814}
1815
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001816static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1817{
1818 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001819 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001820
1821 clk_disable(hdata->res.sclk_hdmi);
1822 clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
1823 clk_enable(hdata->res.sclk_hdmi);
1824
1825 /* operation mode */
1826 buffer[0] = 0x1f;
1827 buffer[1] = 0x00;
1828
1829 if (hdata->hdmiphy_port)
1830 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1831
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001832 if (hdata->is_v13)
1833 reg = HDMI_V13_PHY_RSTOUT;
1834 else
1835 reg = HDMI_PHY_RSTOUT;
1836
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001837 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001838 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001839 mdelay(10);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001840 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001841 mdelay(10);
1842}
1843
1844static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1845{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001846 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001847 u8 buffer[32];
1848 u8 operation[2];
1849 u8 read_buffer[32] = {0, };
1850 int ret;
1851 int i;
1852
1853 if (!hdata->hdmiphy_port) {
1854 DRM_ERROR("hdmiphy is not attached\n");
1855 return;
1856 }
1857
1858 /* pixel clock */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001859 if (hdata->is_v13)
1860 hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data;
1861 else
1862 hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data;
1863
1864 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001865 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1866 if (ret != 32) {
1867 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1868 return;
1869 }
1870
1871 mdelay(10);
1872
1873 /* operation mode */
1874 operation[0] = 0x1f;
1875 operation[1] = 0x80;
1876
1877 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1878 if (ret != 2) {
1879 DRM_ERROR("failed to enable hdmiphy\n");
1880 return;
1881 }
1882
1883 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1884 if (ret < 0) {
1885 DRM_ERROR("failed to read hdmiphy config\n");
1886 return;
1887 }
1888
1889 for (i = 0; i < ret; i++)
1890 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1891 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1892}
1893
1894static void hdmi_conf_apply(struct hdmi_context *hdata)
1895{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001896 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1897
1898 hdmiphy_conf_reset(hdata);
1899 hdmiphy_conf_apply(hdata);
1900
1901 hdmi_conf_reset(hdata);
1902 hdmi_conf_init(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001903 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001904
1905 /* setting core registers */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001906 hdmi_timing_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001907 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001908
1909 hdmi_regs_dump(hdata, "start");
1910}
1911
Inki Dae1de425b2012-03-16 18:47:04 +09001912static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector,
1913 struct drm_display_mode *mode,
1914 struct drm_display_mode *adjusted_mode)
1915{
1916 struct drm_display_mode *m;
1917 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1918 int index;
1919
1920 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1921
1922 drm_mode_set_crtcinfo(adjusted_mode, 0);
1923
1924 if (hdata->is_v13)
1925 index = hdmi_v13_conf_index(adjusted_mode);
1926 else
1927 index = hdmi_v14_conf_index(adjusted_mode);
1928
1929 /* just return if user desired mode exists. */
1930 if (index >= 0)
1931 return;
1932
1933 /*
1934 * otherwise, find the most suitable mode among modes and change it
1935 * to adjusted_mode.
1936 */
1937 list_for_each_entry(m, &connector->modes, head) {
1938 if (hdata->is_v13)
1939 index = hdmi_v13_conf_index(m);
1940 else
1941 index = hdmi_v14_conf_index(m);
1942
1943 if (index >= 0) {
1944 DRM_INFO("desired mode doesn't exist so\n");
1945 DRM_INFO("use the most suitable mode among modes.\n");
1946 memcpy(adjusted_mode, m, sizeof(*m));
1947 break;
1948 }
1949 }
1950}
1951
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952static void hdmi_mode_set(void *ctx, void *mode)
1953{
1954 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1955 int conf_idx;
1956
1957 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1958
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001959 conf_idx = hdmi_conf_index(hdata, mode);
1960 if (conf_idx >= 0)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001961 hdata->cur_conf = conf_idx;
1962 else
1963 DRM_DEBUG_KMS("not supported mode\n");
1964}
1965
Inki Dae1de425b2012-03-16 18:47:04 +09001966static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1967 unsigned int *height)
1968{
1969 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1970
1971 *width = MAX_WIDTH;
1972 *height = MAX_HEIGHT;
1973}
1974
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001975static void hdmi_commit(void *ctx)
1976{
1977 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1978
1979 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1980
1981 hdmi_conf_apply(hdata);
1982
1983 hdata->enabled = true;
1984}
1985
1986static void hdmi_disable(void *ctx)
1987{
1988 struct hdmi_context *hdata = (struct hdmi_context *)ctx;
1989
1990 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1991
1992 if (hdata->enabled) {
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001993 hdmi_audio_control(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994 hdmiphy_conf_reset(hdata);
1995 hdmi_conf_reset(hdata);
1996 }
1997}
1998
1999static struct exynos_hdmi_manager_ops manager_ops = {
Inki Dae1de425b2012-03-16 18:47:04 +09002000 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002001 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09002002 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002003 .commit = hdmi_commit,
2004 .disable = hdmi_disable,
2005};
2006
2007/*
2008 * Handle hotplug events outside the interrupt handler proper.
2009 */
2010static void hdmi_hotplug_func(struct work_struct *work)
2011{
2012 struct hdmi_context *hdata =
2013 container_of(work, struct hdmi_context, hotplug_work);
2014 struct exynos_drm_hdmi_context *ctx =
2015 (struct exynos_drm_hdmi_context *)hdata->parent_ctx;
2016
2017 drm_helper_hpd_irq_event(ctx->drm_dev);
2018}
2019
2020static irqreturn_t hdmi_irq_handler(int irq, void *arg)
2021{
2022 struct exynos_drm_hdmi_context *ctx = arg;
2023 struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx;
2024 u32 intc_flag;
2025
2026 intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
2027 /* clearing flags for HPD plug/unplug */
2028 if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
2029 DRM_DEBUG_KMS("unplugged, handling:%d\n", hdata->hpd_handle);
2030 hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
2031 HDMI_INTC_FLAG_HPD_UNPLUG);
2032 }
2033 if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
2034 DRM_DEBUG_KMS("plugged, handling:%d\n", hdata->hpd_handle);
2035 hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
2036 HDMI_INTC_FLAG_HPD_PLUG);
2037 }
2038
2039 if (ctx->drm_dev && hdata->hpd_handle)
2040 queue_work(hdata->wq, &hdata->hotplug_work);
2041
2042 return IRQ_HANDLED;
2043}
2044
2045static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
2046{
2047 struct device *dev = hdata->dev;
2048 struct hdmi_resources *res = &hdata->res;
2049 static char *supply[] = {
2050 "hdmi-en",
2051 "vdd",
2052 "vdd_osc",
2053 "vdd_pll",
2054 };
2055 int i, ret;
2056
2057 DRM_DEBUG_KMS("HDMI resource init\n");
2058
2059 memset(res, 0, sizeof *res);
2060
2061 /* get clocks, power */
2062 res->hdmi = clk_get(dev, "hdmi");
2063 if (IS_ERR_OR_NULL(res->hdmi)) {
2064 DRM_ERROR("failed to get clock 'hdmi'\n");
2065 goto fail;
2066 }
2067 res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
2068 if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
2069 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
2070 goto fail;
2071 }
2072 res->sclk_pixel = clk_get(dev, "sclk_pixel");
2073 if (IS_ERR_OR_NULL(res->sclk_pixel)) {
2074 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
2075 goto fail;
2076 }
2077 res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
2078 if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
2079 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
2080 goto fail;
2081 }
2082 res->hdmiphy = clk_get(dev, "hdmiphy");
2083 if (IS_ERR_OR_NULL(res->hdmiphy)) {
2084 DRM_ERROR("failed to get clock 'hdmiphy'\n");
2085 goto fail;
2086 }
2087
2088 clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
2089
2090 res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
2091 sizeof res->regul_bulk[0], GFP_KERNEL);
2092 if (!res->regul_bulk) {
2093 DRM_ERROR("failed to get memory for regulators\n");
2094 goto fail;
2095 }
2096 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2097 res->regul_bulk[i].supply = supply[i];
2098 res->regul_bulk[i].consumer = NULL;
2099 }
2100 ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
2101 if (ret) {
2102 DRM_ERROR("failed to get regulators\n");
2103 goto fail;
2104 }
2105 res->regul_count = ARRAY_SIZE(supply);
2106
2107 return 0;
2108fail:
2109 DRM_ERROR("HDMI resource init - failed\n");
2110 return -ENODEV;
2111}
2112
2113static int hdmi_resources_cleanup(struct hdmi_context *hdata)
2114{
2115 struct hdmi_resources *res = &hdata->res;
2116
2117 regulator_bulk_free(res->regul_count, res->regul_bulk);
2118 /* kfree is NULL-safe */
2119 kfree(res->regul_bulk);
2120 if (!IS_ERR_OR_NULL(res->hdmiphy))
2121 clk_put(res->hdmiphy);
2122 if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
2123 clk_put(res->sclk_hdmiphy);
2124 if (!IS_ERR_OR_NULL(res->sclk_pixel))
2125 clk_put(res->sclk_pixel);
2126 if (!IS_ERR_OR_NULL(res->sclk_hdmi))
2127 clk_put(res->sclk_hdmi);
2128 if (!IS_ERR_OR_NULL(res->hdmi))
2129 clk_put(res->hdmi);
2130 memset(res, 0, sizeof *res);
2131
2132 return 0;
2133}
2134
2135static void hdmi_resource_poweron(struct hdmi_context *hdata)
2136{
2137 struct hdmi_resources *res = &hdata->res;
2138
2139 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
2140
2141 /* turn HDMI power on */
2142 regulator_bulk_enable(res->regul_count, res->regul_bulk);
2143 /* power-on hdmi physical interface */
2144 clk_enable(res->hdmiphy);
2145 /* turn clocks on */
2146 clk_enable(res->hdmi);
2147 clk_enable(res->sclk_hdmi);
2148
2149 hdmiphy_conf_reset(hdata);
2150 hdmi_conf_reset(hdata);
2151 hdmi_conf_init(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09002152 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002153}
2154
2155static void hdmi_resource_poweroff(struct hdmi_context *hdata)
2156{
2157 struct hdmi_resources *res = &hdata->res;
2158
2159 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
2160
2161 /* turn clocks off */
2162 clk_disable(res->sclk_hdmi);
2163 clk_disable(res->hdmi);
2164 /* power-off hdmiphy */
2165 clk_disable(res->hdmiphy);
2166 /* turn HDMI power off */
2167 regulator_bulk_disable(res->regul_count, res->regul_bulk);
2168}
2169
2170static int hdmi_runtime_suspend(struct device *dev)
2171{
2172 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2173
2174 DRM_DEBUG_KMS("%s\n", __func__);
2175
2176 hdmi_resource_poweroff((struct hdmi_context *)ctx->ctx);
2177
2178 return 0;
2179}
2180
2181static int hdmi_runtime_resume(struct device *dev)
2182{
2183 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2184
2185 DRM_DEBUG_KMS("%s\n", __func__);
2186
2187 hdmi_resource_poweron((struct hdmi_context *)ctx->ctx);
2188
2189 return 0;
2190}
2191
2192static const struct dev_pm_ops hdmi_pm_ops = {
2193 .runtime_suspend = hdmi_runtime_suspend,
2194 .runtime_resume = hdmi_runtime_resume,
2195};
2196
2197static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
2198
2199void hdmi_attach_ddc_client(struct i2c_client *ddc)
2200{
2201 if (ddc)
2202 hdmi_ddc = ddc;
2203}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002204
2205void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
2206{
2207 if (hdmiphy)
2208 hdmi_hdmiphy = hdmiphy;
2209}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002210
2211static int __devinit hdmi_probe(struct platform_device *pdev)
2212{
2213 struct device *dev = &pdev->dev;
2214 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
2215 struct hdmi_context *hdata;
2216 struct exynos_drm_hdmi_pdata *pdata;
2217 struct resource *res;
2218 int ret;
2219
2220 DRM_DEBUG_KMS("[%d]\n", __LINE__);
2221
2222 pdata = pdev->dev.platform_data;
2223 if (!pdata) {
2224 DRM_ERROR("no platform data specified\n");
2225 return -EINVAL;
2226 }
2227
2228 drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
2229 if (!drm_hdmi_ctx) {
2230 DRM_ERROR("failed to allocate common hdmi context.\n");
2231 return -ENOMEM;
2232 }
2233
2234 hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
2235 if (!hdata) {
2236 DRM_ERROR("out of memory\n");
2237 kfree(drm_hdmi_ctx);
2238 return -ENOMEM;
2239 }
2240
2241 drm_hdmi_ctx->ctx = (void *)hdata;
2242 hdata->parent_ctx = (void *)drm_hdmi_ctx;
2243
2244 platform_set_drvdata(pdev, drm_hdmi_ctx);
2245
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09002246 hdata->is_v13 = pdata->is_v13;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002247 hdata->default_win = pdata->default_win;
2248 hdata->default_timing = &pdata->timing;
2249 hdata->default_bpp = pdata->bpp;
2250 hdata->dev = dev;
2251
2252 ret = hdmi_resources_init(hdata);
2253 if (ret) {
2254 ret = -EINVAL;
2255 goto err_data;
2256 }
2257
2258 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2259 if (!res) {
2260 DRM_ERROR("failed to find registers\n");
2261 ret = -ENOENT;
2262 goto err_resource;
2263 }
2264
2265 hdata->regs_res = request_mem_region(res->start, resource_size(res),
2266 dev_name(dev));
2267 if (!hdata->regs_res) {
2268 DRM_ERROR("failed to claim register region\n");
2269 ret = -ENOENT;
2270 goto err_resource;
2271 }
2272
2273 hdata->regs = ioremap(res->start, resource_size(res));
2274 if (!hdata->regs) {
2275 DRM_ERROR("failed to map registers\n");
2276 ret = -ENXIO;
2277 goto err_req_region;
2278 }
2279
2280 /* DDC i2c driver */
2281 if (i2c_add_driver(&ddc_driver)) {
2282 DRM_ERROR("failed to register ddc i2c driver\n");
2283 ret = -ENOENT;
2284 goto err_iomap;
2285 }
2286
2287 hdata->ddc_port = hdmi_ddc;
2288
2289 /* hdmiphy i2c driver */
2290 if (i2c_add_driver(&hdmiphy_driver)) {
2291 DRM_ERROR("failed to register hdmiphy i2c driver\n");
2292 ret = -ENOENT;
2293 goto err_ddc;
2294 }
2295
2296 hdata->hdmiphy_port = hdmi_hdmiphy;
2297
2298 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
2299 if (res == NULL) {
2300 DRM_ERROR("get interrupt resource failed.\n");
2301 ret = -ENXIO;
2302 goto err_hdmiphy;
2303 }
2304
2305 /* create workqueue and hotplug work */
2306 hdata->wq = alloc_workqueue("exynos-drm-hdmi",
2307 WQ_UNBOUND | WQ_NON_REENTRANT, 1);
2308 if (hdata->wq == NULL) {
2309 DRM_ERROR("Failed to create workqueue.\n");
2310 ret = -ENOMEM;
2311 goto err_hdmiphy;
2312 }
2313 INIT_WORK(&hdata->hotplug_work, hdmi_hotplug_func);
2314
2315 /* register hpd interrupt */
2316 ret = request_irq(res->start, hdmi_irq_handler, 0, "drm_hdmi",
2317 drm_hdmi_ctx);
2318 if (ret) {
2319 DRM_ERROR("request interrupt failed.\n");
2320 goto err_workqueue;
2321 }
2322 hdata->irq = res->start;
2323
2324 /* register specific callbacks to common hdmi. */
2325 exynos_drm_display_ops_register(&display_ops);
2326 exynos_drm_manager_ops_register(&manager_ops);
2327
2328 hdmi_resource_poweron(hdata);
2329
2330 return 0;
2331
2332err_workqueue:
2333 destroy_workqueue(hdata->wq);
2334err_hdmiphy:
2335 i2c_del_driver(&hdmiphy_driver);
2336err_ddc:
2337 i2c_del_driver(&ddc_driver);
2338err_iomap:
2339 iounmap(hdata->regs);
2340err_req_region:
Seung-Woo Kim485bc542011-12-22 11:30:09 +09002341 release_mem_region(hdata->regs_res->start,
2342 resource_size(hdata->regs_res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002343err_resource:
2344 hdmi_resources_cleanup(hdata);
2345err_data:
2346 kfree(hdata);
2347 kfree(drm_hdmi_ctx);
2348 return ret;
2349}
2350
2351static int __devexit hdmi_remove(struct platform_device *pdev)
2352{
2353 struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
2354 struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx;
2355
2356 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
2357
2358 hdmi_resource_poweroff(hdata);
2359
2360 disable_irq(hdata->irq);
2361 free_irq(hdata->irq, hdata);
2362
2363 cancel_work_sync(&hdata->hotplug_work);
2364 destroy_workqueue(hdata->wq);
2365
2366 hdmi_resources_cleanup(hdata);
2367
2368 iounmap(hdata->regs);
2369
Seung-Woo Kim485bc542011-12-22 11:30:09 +09002370 release_mem_region(hdata->regs_res->start,
2371 resource_size(hdata->regs_res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002372
2373 /* hdmiphy i2c driver */
2374 i2c_del_driver(&hdmiphy_driver);
2375 /* DDC i2c driver */
2376 i2c_del_driver(&ddc_driver);
2377
2378 kfree(hdata);
2379
2380 return 0;
2381}
2382
2383struct platform_driver hdmi_driver = {
2384 .probe = hdmi_probe,
2385 .remove = __devexit_p(hdmi_remove),
2386 .driver = {
2387 .name = "exynos4-hdmi",
2388 .owner = THIS_MODULE,
2389 .pm = &hdmi_pm_ops,
2390 },
2391};