xref: /linux/drivers/gpu/drm/exynos/exynos_hdmi.c (revision b43ab901d671e3e3cad425ea5e9a3c74e266dcdd)
1 /*
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
44 #define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
45 
46 static const u8 hdmiphy_conf27[32] = {
47 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
48 	0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
49 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
50 	0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
51 };
52 
53 static const u8 hdmiphy_conf27_027[32] = {
54 	0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
55 	0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
56 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
57 	0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
58 };
59 
60 static const u8 hdmiphy_conf74_175[32] = {
61 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
62 	0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
63 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
64 	0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
65 };
66 
67 static const u8 hdmiphy_conf74_25[32] = {
68 	0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
69 	0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
70 	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
71 	0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
72 };
73 
74 static const u8 hdmiphy_conf148_5[32] = {
75 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
76 	0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
77 	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
78 	0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
79 };
80 
81 struct hdmi_tg_regs {
82 	u8 cmd;
83 	u8 h_fsz_l;
84 	u8 h_fsz_h;
85 	u8 hact_st_l;
86 	u8 hact_st_h;
87 	u8 hact_sz_l;
88 	u8 hact_sz_h;
89 	u8 v_fsz_l;
90 	u8 v_fsz_h;
91 	u8 vsync_l;
92 	u8 vsync_h;
93 	u8 vsync2_l;
94 	u8 vsync2_h;
95 	u8 vact_st_l;
96 	u8 vact_st_h;
97 	u8 vact_sz_l;
98 	u8 vact_sz_h;
99 	u8 field_chg_l;
100 	u8 field_chg_h;
101 	u8 vact_st2_l;
102 	u8 vact_st2_h;
103 	u8 vsync_top_hdmi_l;
104 	u8 vsync_top_hdmi_h;
105 	u8 vsync_bot_hdmi_l;
106 	u8 vsync_bot_hdmi_h;
107 	u8 field_top_hdmi_l;
108 	u8 field_top_hdmi_h;
109 	u8 field_bot_hdmi_l;
110 	u8 field_bot_hdmi_h;
111 };
112 
113 struct hdmi_core_regs {
114 	u8 h_blank[2];
115 	u8 v_blank[3];
116 	u8 h_v_line[3];
117 	u8 vsync_pol[1];
118 	u8 int_pro_mode[1];
119 	u8 v_blank_f[3];
120 	u8 h_sync_gen[3];
121 	u8 v_sync_gen1[3];
122 	u8 v_sync_gen2[3];
123 	u8 v_sync_gen3[3];
124 };
125 
126 struct hdmi_preset_conf {
127 	struct hdmi_core_regs core;
128 	struct hdmi_tg_regs tg;
129 };
130 
131 static const struct hdmi_preset_conf hdmi_conf_480p = {
132 	.core = {
133 		.h_blank = {0x8a, 0x00},
134 		.v_blank = {0x0d, 0x6a, 0x01},
135 		.h_v_line = {0x0d, 0xa2, 0x35},
136 		.vsync_pol = {0x01},
137 		.int_pro_mode = {0x00},
138 		.v_blank_f = {0x00, 0x00, 0x00},
139 		.h_sync_gen = {0x0e, 0x30, 0x11},
140 		.v_sync_gen1 = {0x0f, 0x90, 0x00},
141 		/* other don't care */
142 	},
143 	.tg = {
144 		0x00, /* cmd */
145 		0x5a, 0x03, /* h_fsz */
146 		0x8a, 0x00, 0xd0, 0x02, /* hact */
147 		0x0d, 0x02, /* v_fsz */
148 		0x01, 0x00, 0x33, 0x02, /* vsync */
149 		0x2d, 0x00, 0xe0, 0x01, /* vact */
150 		0x33, 0x02, /* field_chg */
151 		0x49, 0x02, /* vact_st2 */
152 		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
153 		0x01, 0x00, 0x33, 0x02, /* field top/bot */
154 	},
155 };
156 
157 static const struct hdmi_preset_conf hdmi_conf_720p60 = {
158 	.core = {
159 		.h_blank = {0x72, 0x01},
160 		.v_blank = {0xee, 0xf2, 0x00},
161 		.h_v_line = {0xee, 0x22, 0x67},
162 		.vsync_pol = {0x00},
163 		.int_pro_mode = {0x00},
164 		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
165 		.h_sync_gen = {0x6c, 0x50, 0x02},
166 		.v_sync_gen1 = {0x0a, 0x50, 0x00},
167 		.v_sync_gen2 = {0x01, 0x10, 0x00},
168 		.v_sync_gen3 = {0x01, 0x10, 0x00},
169 		/* other don't care */
170 	},
171 	.tg = {
172 		0x00, /* cmd */
173 		0x72, 0x06, /* h_fsz */
174 		0x71, 0x01, 0x01, 0x05, /* hact */
175 		0xee, 0x02, /* v_fsz */
176 		0x01, 0x00, 0x33, 0x02, /* vsync */
177 		0x1e, 0x00, 0xd0, 0x02, /* vact */
178 		0x33, 0x02, /* field_chg */
179 		0x49, 0x02, /* vact_st2 */
180 		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
181 		0x01, 0x00, 0x33, 0x02, /* field top/bot */
182 	},
183 };
184 
185 static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
186 	.core = {
187 		.h_blank = {0xd0, 0x02},
188 		.v_blank = {0x32, 0xB2, 0x00},
189 		.h_v_line = {0x65, 0x04, 0xa5},
190 		.vsync_pol = {0x00},
191 		.int_pro_mode = {0x01},
192 		.v_blank_f = {0x49, 0x2A, 0x23},
193 		.h_sync_gen = {0x0E, 0xEA, 0x08},
194 		.v_sync_gen1 = {0x07, 0x20, 0x00},
195 		.v_sync_gen2 = {0x39, 0x42, 0x23},
196 		.v_sync_gen3 = {0x38, 0x87, 0x73},
197 		/* other don't care */
198 	},
199 	.tg = {
200 		0x00, /* cmd */
201 		0x50, 0x0A, /* h_fsz */
202 		0xCF, 0x02, 0x81, 0x07, /* hact */
203 		0x65, 0x04, /* v_fsz */
204 		0x01, 0x00, 0x33, 0x02, /* vsync */
205 		0x16, 0x00, 0x1c, 0x02, /* vact */
206 		0x33, 0x02, /* field_chg */
207 		0x49, 0x02, /* vact_st2 */
208 		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
209 		0x01, 0x00, 0x33, 0x02, /* field top/bot */
210 	},
211 };
212 
213 static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
214 	.core = {
215 		.h_blank = {0xd0, 0x02},
216 		.v_blank = {0x65, 0x6c, 0x01},
217 		.h_v_line = {0x65, 0x04, 0xa5},
218 		.vsync_pol = {0x00},
219 		.int_pro_mode = {0x00},
220 		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
221 		.h_sync_gen = {0x0e, 0xea, 0x08},
222 		.v_sync_gen1 = {0x09, 0x40, 0x00},
223 		.v_sync_gen2 = {0x01, 0x10, 0x00},
224 		.v_sync_gen3 = {0x01, 0x10, 0x00},
225 		/* other don't care */
226 	},
227 	.tg = {
228 		0x00, /* cmd */
229 		0x50, 0x0A, /* h_fsz */
230 		0xCF, 0x02, 0x81, 0x07, /* hact */
231 		0x65, 0x04, /* v_fsz */
232 		0x01, 0x00, 0x33, 0x02, /* vsync */
233 		0x2d, 0x00, 0x38, 0x04, /* vact */
234 		0x33, 0x02, /* field_chg */
235 		0x48, 0x02, /* vact_st2 */
236 		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
237 		0x01, 0x00, 0x33, 0x02, /* field top/bot */
238 	},
239 };
240 
241 static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
242 	.core = {
243 		.h_blank = {0x18, 0x01},
244 		.v_blank = {0x32, 0xB2, 0x00},
245 		.h_v_line = {0x65, 0x84, 0x89},
246 		.vsync_pol = {0x00},
247 		.int_pro_mode = {0x01},
248 		.v_blank_f = {0x49, 0x2A, 0x23},
249 		.h_sync_gen = {0x56, 0x08, 0x02},
250 		.v_sync_gen1 = {0x07, 0x20, 0x00},
251 		.v_sync_gen2 = {0x39, 0x42, 0x23},
252 		.v_sync_gen3 = {0xa4, 0x44, 0x4a},
253 		/* other don't care */
254 	},
255 	.tg = {
256 		0x00, /* cmd */
257 		0x98, 0x08, /* h_fsz */
258 		0x17, 0x01, 0x81, 0x07, /* hact */
259 		0x65, 0x04, /* v_fsz */
260 		0x01, 0x00, 0x33, 0x02, /* vsync */
261 		0x16, 0x00, 0x1c, 0x02, /* vact */
262 		0x33, 0x02, /* field_chg */
263 		0x49, 0x02, /* vact_st2 */
264 		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
265 		0x01, 0x00, 0x33, 0x02, /* field top/bot */
266 	},
267 };
268 
269 static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
270 	.core = {
271 		.h_blank = {0x18, 0x01},
272 		.v_blank = {0x65, 0x6c, 0x01},
273 		.h_v_line = {0x65, 0x84, 0x89},
274 		.vsync_pol = {0x00},
275 		.int_pro_mode = {0x00},
276 		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
277 		.h_sync_gen = {0x56, 0x08, 0x02},
278 		.v_sync_gen1 = {0x09, 0x40, 0x00},
279 		.v_sync_gen2 = {0x01, 0x10, 0x00},
280 		.v_sync_gen3 = {0x01, 0x10, 0x00},
281 		/* other don't care */
282 	},
283 	.tg = {
284 		0x00, /* cmd */
285 		0x98, 0x08, /* h_fsz */
286 		0x17, 0x01, 0x81, 0x07, /* hact */
287 		0x65, 0x04, /* v_fsz */
288 		0x01, 0x00, 0x33, 0x02, /* vsync */
289 		0x2d, 0x00, 0x38, 0x04, /* vact */
290 		0x33, 0x02, /* field_chg */
291 		0x48, 0x02, /* vact_st2 */
292 		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
293 		0x01, 0x00, 0x33, 0x02, /* field top/bot */
294 	},
295 };
296 
297 static const struct hdmi_conf hdmi_confs[] = {
298 	{ 1280, 720, 60, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
299 	{ 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
300 	{ 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p },
301 	{ 1920, 1080, 50, true, hdmiphy_conf74_25, &hdmi_conf_1080i50 },
302 	{ 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
303 	{ 1920, 1080, 60, true, hdmiphy_conf74_25, &hdmi_conf_1080i60 },
304 	{ 1920, 1080, 60, false, hdmiphy_conf148_5, &hdmi_conf_1080p60 },
305 };
306 
307 
308 static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
309 {
310 	return readl(hdata->regs + reg_id);
311 }
312 
313 static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
314 				 u32 reg_id, u8 value)
315 {
316 	writeb(value, hdata->regs + reg_id);
317 }
318 
319 static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
320 				 u32 reg_id, u32 value, u32 mask)
321 {
322 	u32 old = readl(hdata->regs + reg_id);
323 	value = (value & mask) | (old & ~mask);
324 	writel(value, hdata->regs + reg_id);
325 }
326 
327 static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
328 {
329 #define DUMPREG(reg_id) \
330 	DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
331 	readl(hdata->regs + reg_id))
332 	DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
333 	DUMPREG(HDMI_INTC_FLAG);
334 	DUMPREG(HDMI_INTC_CON);
335 	DUMPREG(HDMI_HPD_STATUS);
336 	DUMPREG(HDMI_PHY_RSTOUT);
337 	DUMPREG(HDMI_PHY_VPLL);
338 	DUMPREG(HDMI_PHY_CMU);
339 	DUMPREG(HDMI_CORE_RSTOUT);
340 
341 	DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
342 	DUMPREG(HDMI_CON_0);
343 	DUMPREG(HDMI_CON_1);
344 	DUMPREG(HDMI_CON_2);
345 	DUMPREG(HDMI_SYS_STATUS);
346 	DUMPREG(HDMI_PHY_STATUS);
347 	DUMPREG(HDMI_STATUS_EN);
348 	DUMPREG(HDMI_HPD);
349 	DUMPREG(HDMI_MODE_SEL);
350 	DUMPREG(HDMI_HPD_GEN);
351 	DUMPREG(HDMI_DC_CONTROL);
352 	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
353 
354 	DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
355 	DUMPREG(HDMI_H_BLANK_0);
356 	DUMPREG(HDMI_H_BLANK_1);
357 	DUMPREG(HDMI_V_BLANK_0);
358 	DUMPREG(HDMI_V_BLANK_1);
359 	DUMPREG(HDMI_V_BLANK_2);
360 	DUMPREG(HDMI_H_V_LINE_0);
361 	DUMPREG(HDMI_H_V_LINE_1);
362 	DUMPREG(HDMI_H_V_LINE_2);
363 	DUMPREG(HDMI_VSYNC_POL);
364 	DUMPREG(HDMI_INT_PRO_MODE);
365 	DUMPREG(HDMI_V_BLANK_F_0);
366 	DUMPREG(HDMI_V_BLANK_F_1);
367 	DUMPREG(HDMI_V_BLANK_F_2);
368 	DUMPREG(HDMI_H_SYNC_GEN_0);
369 	DUMPREG(HDMI_H_SYNC_GEN_1);
370 	DUMPREG(HDMI_H_SYNC_GEN_2);
371 	DUMPREG(HDMI_V_SYNC_GEN_1_0);
372 	DUMPREG(HDMI_V_SYNC_GEN_1_1);
373 	DUMPREG(HDMI_V_SYNC_GEN_1_2);
374 	DUMPREG(HDMI_V_SYNC_GEN_2_0);
375 	DUMPREG(HDMI_V_SYNC_GEN_2_1);
376 	DUMPREG(HDMI_V_SYNC_GEN_2_2);
377 	DUMPREG(HDMI_V_SYNC_GEN_3_0);
378 	DUMPREG(HDMI_V_SYNC_GEN_3_1);
379 	DUMPREG(HDMI_V_SYNC_GEN_3_2);
380 
381 	DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
382 	DUMPREG(HDMI_TG_CMD);
383 	DUMPREG(HDMI_TG_H_FSZ_L);
384 	DUMPREG(HDMI_TG_H_FSZ_H);
385 	DUMPREG(HDMI_TG_HACT_ST_L);
386 	DUMPREG(HDMI_TG_HACT_ST_H);
387 	DUMPREG(HDMI_TG_HACT_SZ_L);
388 	DUMPREG(HDMI_TG_HACT_SZ_H);
389 	DUMPREG(HDMI_TG_V_FSZ_L);
390 	DUMPREG(HDMI_TG_V_FSZ_H);
391 	DUMPREG(HDMI_TG_VSYNC_L);
392 	DUMPREG(HDMI_TG_VSYNC_H);
393 	DUMPREG(HDMI_TG_VSYNC2_L);
394 	DUMPREG(HDMI_TG_VSYNC2_H);
395 	DUMPREG(HDMI_TG_VACT_ST_L);
396 	DUMPREG(HDMI_TG_VACT_ST_H);
397 	DUMPREG(HDMI_TG_VACT_SZ_L);
398 	DUMPREG(HDMI_TG_VACT_SZ_H);
399 	DUMPREG(HDMI_TG_FIELD_CHG_L);
400 	DUMPREG(HDMI_TG_FIELD_CHG_H);
401 	DUMPREG(HDMI_TG_VACT_ST2_L);
402 	DUMPREG(HDMI_TG_VACT_ST2_H);
403 	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
404 	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
405 	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
406 	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
407 	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
408 	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
409 	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
410 	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
411 #undef DUMPREG
412 }
413 
414 static int hdmi_conf_index(struct drm_display_mode *mode)
415 {
416 	int i;
417 
418 	for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
419 		if (hdmi_confs[i].width == mode->hdisplay &&
420 				hdmi_confs[i].height == mode->vdisplay &&
421 				hdmi_confs[i].vrefresh == mode->vrefresh &&
422 				hdmi_confs[i].interlace ==
423 				((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
424 				 true : false))
425 			return i;
426 
427 	return -1;
428 }
429 
430 static bool hdmi_is_connected(void *ctx)
431 {
432 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
433 	u32 val = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
434 
435 	if (val)
436 		return true;
437 
438 	return false;
439 }
440 
441 static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
442 				u8 *edid, int len)
443 {
444 	struct edid *raw_edid;
445 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
446 
447 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
448 
449 	if (!hdata->ddc_port)
450 		return -ENODEV;
451 
452 	raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
453 	if (raw_edid) {
454 		memcpy(edid, raw_edid, min((1 + raw_edid->extensions)
455 					* EDID_LENGTH, len));
456 		DRM_DEBUG_KMS("width[%d] x height[%d]\n",
457 				raw_edid->width_cm, raw_edid->height_cm);
458 	} else {
459 		return -ENODEV;
460 	}
461 
462 	return 0;
463 }
464 
465 static int hdmi_check_timing(void *ctx, void *timing)
466 {
467 	struct fb_videomode *check_timing = timing;
468 	int i;
469 
470 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
471 
472 	DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", check_timing->xres,
473 			check_timing->yres, check_timing->refresh,
474 			check_timing->vmode);
475 
476 	for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
477 		if (hdmi_confs[i].width == check_timing->xres &&
478 			hdmi_confs[i].height == check_timing->yres &&
479 			hdmi_confs[i].vrefresh == check_timing->refresh &&
480 			hdmi_confs[i].interlace ==
481 			((check_timing->vmode & FB_VMODE_INTERLACED) ?
482 			 true : false))
483 			return 0;
484 
485 	return -EINVAL;
486 }
487 
488 static int hdmi_display_power_on(void *ctx, int mode)
489 {
490 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
491 
492 	switch (mode) {
493 	case DRM_MODE_DPMS_ON:
494 		DRM_DEBUG_KMS("hdmi [on]\n");
495 		break;
496 	case DRM_MODE_DPMS_STANDBY:
497 		break;
498 	case DRM_MODE_DPMS_SUSPEND:
499 		break;
500 	case DRM_MODE_DPMS_OFF:
501 		DRM_DEBUG_KMS("hdmi [off]\n");
502 		break;
503 	default:
504 		break;
505 	}
506 
507 	return 0;
508 }
509 
510 static struct exynos_hdmi_display_ops display_ops = {
511 	.is_connected	= hdmi_is_connected,
512 	.get_edid	= hdmi_get_edid,
513 	.check_timing	= hdmi_check_timing,
514 	.power_on	= hdmi_display_power_on,
515 };
516 
517 static void hdmi_conf_reset(struct hdmi_context *hdata)
518 {
519 	/* disable hpd handle for drm */
520 	hdata->hpd_handle = false;
521 
522 	/* resetting HDMI core */
523 	hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
524 	mdelay(10);
525 	hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
526 	mdelay(10);
527 
528 	/* enable hpd handle for drm */
529 	hdata->hpd_handle = true;
530 }
531 
532 static void hdmi_conf_init(struct hdmi_context *hdata)
533 {
534 	/* disable hpd handle for drm */
535 	hdata->hpd_handle = false;
536 
537 	/* enable HPD interrupts */
538 	hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
539 		HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
540 	mdelay(10);
541 	hdmi_reg_writemask(hdata, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
542 		HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
543 
544 	/* choose HDMI mode */
545 	hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
546 		HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
547 	/* disable bluescreen */
548 	hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
549 	/* choose bluescreen (fecal) color */
550 	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_0, 0x12);
551 	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_1, 0x34);
552 	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_2, 0x56);
553 	/* enable AVI packet every vsync, fixes purple line problem */
554 	hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
555 	/* force RGB, look to CEA-861-D, table 7 for more detail */
556 	hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(0), 0 << 5);
557 	hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
558 
559 	hdmi_reg_writeb(hdata, HDMI_SPD_CON, 0x02);
560 	hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
561 	hdmi_reg_writeb(hdata, HDMI_ACR_CON, 0x04);
562 
563 	/* enable hpd handle for drm */
564 	hdata->hpd_handle = true;
565 }
566 
567 static void hdmi_timing_apply(struct hdmi_context *hdata,
568 				 const struct hdmi_preset_conf *conf)
569 {
570 	const struct hdmi_core_regs *core = &conf->core;
571 	const struct hdmi_tg_regs *tg = &conf->tg;
572 	int tries;
573 
574 	/* setting core registers */
575 	hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
576 	hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
577 	hdmi_reg_writeb(hdata, HDMI_V_BLANK_0, core->v_blank[0]);
578 	hdmi_reg_writeb(hdata, HDMI_V_BLANK_1, core->v_blank[1]);
579 	hdmi_reg_writeb(hdata, HDMI_V_BLANK_2, core->v_blank[2]);
580 	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_0, core->h_v_line[0]);
581 	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_1, core->h_v_line[1]);
582 	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_2, core->h_v_line[2]);
583 	hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
584 	hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
585 	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
586 	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
587 	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
588 	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
589 	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
590 	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
591 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
592 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
593 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
594 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
595 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
596 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
597 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
598 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
599 	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
600 	/* Timing generator registers */
601 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
602 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
603 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
604 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
605 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
606 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
607 	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
608 	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
609 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
610 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
611 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
612 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
613 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
614 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
615 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
616 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
617 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
618 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
619 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
620 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
621 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
622 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
623 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
624 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
625 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
626 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
627 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
628 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
629 
630 	/* waiting for HDMIPHY's PLL to get to steady state */
631 	for (tries = 100; tries; --tries) {
632 		u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
633 		if (val & HDMI_PHY_STATUS_READY)
634 			break;
635 		mdelay(1);
636 	}
637 	/* steady state not achieved */
638 	if (tries == 0) {
639 		DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
640 		hdmi_regs_dump(hdata, "timing apply");
641 	}
642 
643 	clk_disable(hdata->res.sclk_hdmi);
644 	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
645 	clk_enable(hdata->res.sclk_hdmi);
646 
647 	/* enable HDMI and timing generator */
648 	hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
649 	if (core->int_pro_mode[0])
650 		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
651 				HDMI_FIELD_EN);
652 	else
653 		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
654 }
655 
656 static void hdmiphy_conf_reset(struct hdmi_context *hdata)
657 {
658 	u8 buffer[2];
659 
660 	clk_disable(hdata->res.sclk_hdmi);
661 	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
662 	clk_enable(hdata->res.sclk_hdmi);
663 
664 	/* operation mode */
665 	buffer[0] = 0x1f;
666 	buffer[1] = 0x00;
667 
668 	if (hdata->hdmiphy_port)
669 		i2c_master_send(hdata->hdmiphy_port, buffer, 2);
670 
671 	/* reset hdmiphy */
672 	hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
673 	mdelay(10);
674 	hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
675 	mdelay(10);
676 }
677 
678 static void hdmiphy_conf_apply(struct hdmi_context *hdata)
679 {
680 	u8 buffer[32];
681 	u8 operation[2];
682 	u8 read_buffer[32] = {0, };
683 	int ret;
684 	int i;
685 
686 	if (!hdata->hdmiphy_port) {
687 		DRM_ERROR("hdmiphy is not attached\n");
688 		return;
689 	}
690 
691 	/* pixel clock */
692 	memcpy(buffer, hdmi_confs[hdata->cur_conf].hdmiphy_data, 32);
693 	ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
694 	if (ret != 32) {
695 		DRM_ERROR("failed to configure HDMIPHY via I2C\n");
696 		return;
697 	}
698 
699 	mdelay(10);
700 
701 	/* operation mode */
702 	operation[0] = 0x1f;
703 	operation[1] = 0x80;
704 
705 	ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
706 	if (ret != 2) {
707 		DRM_ERROR("failed to enable hdmiphy\n");
708 		return;
709 	}
710 
711 	ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
712 	if (ret < 0) {
713 		DRM_ERROR("failed to read hdmiphy config\n");
714 		return;
715 	}
716 
717 	for (i = 0; i < ret; i++)
718 		DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
719 			"recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
720 }
721 
722 static void hdmi_conf_apply(struct hdmi_context *hdata)
723 {
724 	const struct hdmi_preset_conf *conf =
725 		  hdmi_confs[hdata->cur_conf].conf;
726 
727 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
728 
729 	hdmiphy_conf_reset(hdata);
730 	hdmiphy_conf_apply(hdata);
731 
732 	hdmi_conf_reset(hdata);
733 	hdmi_conf_init(hdata);
734 
735 	/* setting core registers */
736 	hdmi_timing_apply(hdata, conf);
737 
738 	hdmi_regs_dump(hdata, "start");
739 }
740 
741 static void hdmi_mode_set(void *ctx, void *mode)
742 {
743 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
744 	int conf_idx;
745 
746 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
747 
748 	conf_idx = hdmi_conf_index(mode);
749 	if (conf_idx >= 0 && conf_idx < ARRAY_SIZE(hdmi_confs))
750 		hdata->cur_conf = conf_idx;
751 	else
752 		DRM_DEBUG_KMS("not supported mode\n");
753 }
754 
755 static void hdmi_commit(void *ctx)
756 {
757 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
758 
759 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
760 
761 	hdmi_conf_apply(hdata);
762 
763 	hdata->enabled = true;
764 }
765 
766 static void hdmi_disable(void *ctx)
767 {
768 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
769 
770 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
771 
772 	if (hdata->enabled) {
773 		hdmiphy_conf_reset(hdata);
774 		hdmi_conf_reset(hdata);
775 	}
776 }
777 
778 static struct exynos_hdmi_manager_ops manager_ops = {
779 	.mode_set	= hdmi_mode_set,
780 	.commit		= hdmi_commit,
781 	.disable	= hdmi_disable,
782 };
783 
784 /*
785  * Handle hotplug events outside the interrupt handler proper.
786  */
787 static void hdmi_hotplug_func(struct work_struct *work)
788 {
789 	struct hdmi_context *hdata =
790 		container_of(work, struct hdmi_context, hotplug_work);
791 	struct exynos_drm_hdmi_context *ctx =
792 		(struct exynos_drm_hdmi_context *)hdata->parent_ctx;
793 
794 	drm_helper_hpd_irq_event(ctx->drm_dev);
795 }
796 
797 static irqreturn_t hdmi_irq_handler(int irq, void *arg)
798 {
799 	struct exynos_drm_hdmi_context *ctx = arg;
800 	struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx;
801 	u32 intc_flag;
802 
803 	intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
804 	/* clearing flags for HPD plug/unplug */
805 	if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
806 		DRM_DEBUG_KMS("unplugged, handling:%d\n", hdata->hpd_handle);
807 		hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
808 			HDMI_INTC_FLAG_HPD_UNPLUG);
809 	}
810 	if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
811 		DRM_DEBUG_KMS("plugged, handling:%d\n", hdata->hpd_handle);
812 		hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
813 			HDMI_INTC_FLAG_HPD_PLUG);
814 	}
815 
816 	if (ctx->drm_dev && hdata->hpd_handle)
817 		queue_work(hdata->wq, &hdata->hotplug_work);
818 
819 	return IRQ_HANDLED;
820 }
821 
822 static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
823 {
824 	struct device *dev = hdata->dev;
825 	struct hdmi_resources *res = &hdata->res;
826 	static char *supply[] = {
827 		"hdmi-en",
828 		"vdd",
829 		"vdd_osc",
830 		"vdd_pll",
831 	};
832 	int i, ret;
833 
834 	DRM_DEBUG_KMS("HDMI resource init\n");
835 
836 	memset(res, 0, sizeof *res);
837 
838 	/* get clocks, power */
839 	res->hdmi = clk_get(dev, "hdmi");
840 	if (IS_ERR_OR_NULL(res->hdmi)) {
841 		DRM_ERROR("failed to get clock 'hdmi'\n");
842 		goto fail;
843 	}
844 	res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
845 	if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
846 		DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
847 		goto fail;
848 	}
849 	res->sclk_pixel = clk_get(dev, "sclk_pixel");
850 	if (IS_ERR_OR_NULL(res->sclk_pixel)) {
851 		DRM_ERROR("failed to get clock 'sclk_pixel'\n");
852 		goto fail;
853 	}
854 	res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
855 	if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
856 		DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
857 		goto fail;
858 	}
859 	res->hdmiphy = clk_get(dev, "hdmiphy");
860 	if (IS_ERR_OR_NULL(res->hdmiphy)) {
861 		DRM_ERROR("failed to get clock 'hdmiphy'\n");
862 		goto fail;
863 	}
864 
865 	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
866 
867 	res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
868 		sizeof res->regul_bulk[0], GFP_KERNEL);
869 	if (!res->regul_bulk) {
870 		DRM_ERROR("failed to get memory for regulators\n");
871 		goto fail;
872 	}
873 	for (i = 0; i < ARRAY_SIZE(supply); ++i) {
874 		res->regul_bulk[i].supply = supply[i];
875 		res->regul_bulk[i].consumer = NULL;
876 	}
877 	ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
878 	if (ret) {
879 		DRM_ERROR("failed to get regulators\n");
880 		goto fail;
881 	}
882 	res->regul_count = ARRAY_SIZE(supply);
883 
884 	return 0;
885 fail:
886 	DRM_ERROR("HDMI resource init - failed\n");
887 	return -ENODEV;
888 }
889 
890 static int hdmi_resources_cleanup(struct hdmi_context *hdata)
891 {
892 	struct hdmi_resources *res = &hdata->res;
893 
894 	regulator_bulk_free(res->regul_count, res->regul_bulk);
895 	/* kfree is NULL-safe */
896 	kfree(res->regul_bulk);
897 	if (!IS_ERR_OR_NULL(res->hdmiphy))
898 		clk_put(res->hdmiphy);
899 	if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
900 		clk_put(res->sclk_hdmiphy);
901 	if (!IS_ERR_OR_NULL(res->sclk_pixel))
902 		clk_put(res->sclk_pixel);
903 	if (!IS_ERR_OR_NULL(res->sclk_hdmi))
904 		clk_put(res->sclk_hdmi);
905 	if (!IS_ERR_OR_NULL(res->hdmi))
906 		clk_put(res->hdmi);
907 	memset(res, 0, sizeof *res);
908 
909 	return 0;
910 }
911 
912 static void hdmi_resource_poweron(struct hdmi_context *hdata)
913 {
914 	struct hdmi_resources *res = &hdata->res;
915 
916 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
917 
918 	/* turn HDMI power on */
919 	regulator_bulk_enable(res->regul_count, res->regul_bulk);
920 	/* power-on hdmi physical interface */
921 	clk_enable(res->hdmiphy);
922 	/* turn clocks on */
923 	clk_enable(res->hdmi);
924 	clk_enable(res->sclk_hdmi);
925 
926 	hdmiphy_conf_reset(hdata);
927 	hdmi_conf_reset(hdata);
928 	hdmi_conf_init(hdata);
929 
930 }
931 
932 static void hdmi_resource_poweroff(struct hdmi_context *hdata)
933 {
934 	struct hdmi_resources *res = &hdata->res;
935 
936 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
937 
938 	/* turn clocks off */
939 	clk_disable(res->sclk_hdmi);
940 	clk_disable(res->hdmi);
941 	/* power-off hdmiphy */
942 	clk_disable(res->hdmiphy);
943 	/* turn HDMI power off */
944 	regulator_bulk_disable(res->regul_count, res->regul_bulk);
945 }
946 
947 static int hdmi_runtime_suspend(struct device *dev)
948 {
949 	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
950 
951 	DRM_DEBUG_KMS("%s\n", __func__);
952 
953 	hdmi_resource_poweroff((struct hdmi_context *)ctx->ctx);
954 
955 	return 0;
956 }
957 
958 static int hdmi_runtime_resume(struct device *dev)
959 {
960 	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
961 
962 	DRM_DEBUG_KMS("%s\n", __func__);
963 
964 	hdmi_resource_poweron((struct hdmi_context *)ctx->ctx);
965 
966 	return 0;
967 }
968 
969 static const struct dev_pm_ops hdmi_pm_ops = {
970 	.runtime_suspend = hdmi_runtime_suspend,
971 	.runtime_resume	 = hdmi_runtime_resume,
972 };
973 
974 static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
975 
976 void hdmi_attach_ddc_client(struct i2c_client *ddc)
977 {
978 	if (ddc)
979 		hdmi_ddc = ddc;
980 }
981 EXPORT_SYMBOL(hdmi_attach_ddc_client);
982 
983 void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
984 {
985 	if (hdmiphy)
986 		hdmi_hdmiphy = hdmiphy;
987 }
988 EXPORT_SYMBOL(hdmi_attach_hdmiphy_client);
989 
990 static int __devinit hdmi_probe(struct platform_device *pdev)
991 {
992 	struct device *dev = &pdev->dev;
993 	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
994 	struct hdmi_context *hdata;
995 	struct exynos_drm_hdmi_pdata *pdata;
996 	struct resource *res;
997 	int ret;
998 
999 	DRM_DEBUG_KMS("[%d]\n", __LINE__);
1000 
1001 	pdata = pdev->dev.platform_data;
1002 	if (!pdata) {
1003 		DRM_ERROR("no platform data specified\n");
1004 		return -EINVAL;
1005 	}
1006 
1007 	drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
1008 	if (!drm_hdmi_ctx) {
1009 		DRM_ERROR("failed to allocate common hdmi context.\n");
1010 		return -ENOMEM;
1011 	}
1012 
1013 	hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
1014 	if (!hdata) {
1015 		DRM_ERROR("out of memory\n");
1016 		kfree(drm_hdmi_ctx);
1017 		return -ENOMEM;
1018 	}
1019 
1020 	drm_hdmi_ctx->ctx = (void *)hdata;
1021 	hdata->parent_ctx = (void *)drm_hdmi_ctx;
1022 
1023 	platform_set_drvdata(pdev, drm_hdmi_ctx);
1024 
1025 	hdata->default_win = pdata->default_win;
1026 	hdata->default_timing = &pdata->timing;
1027 	hdata->default_bpp = pdata->bpp;
1028 	hdata->dev = dev;
1029 
1030 	ret = hdmi_resources_init(hdata);
1031 	if (ret) {
1032 		ret = -EINVAL;
1033 		goto err_data;
1034 	}
1035 
1036 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1037 	if (!res) {
1038 		DRM_ERROR("failed to find registers\n");
1039 		ret = -ENOENT;
1040 		goto err_resource;
1041 	}
1042 
1043 	hdata->regs_res = request_mem_region(res->start, resource_size(res),
1044 					   dev_name(dev));
1045 	if (!hdata->regs_res) {
1046 		DRM_ERROR("failed to claim register region\n");
1047 		ret = -ENOENT;
1048 		goto err_resource;
1049 	}
1050 
1051 	hdata->regs = ioremap(res->start, resource_size(res));
1052 	if (!hdata->regs) {
1053 		DRM_ERROR("failed to map registers\n");
1054 		ret = -ENXIO;
1055 		goto err_req_region;
1056 	}
1057 
1058 	/* DDC i2c driver */
1059 	if (i2c_add_driver(&ddc_driver)) {
1060 		DRM_ERROR("failed to register ddc i2c driver\n");
1061 		ret = -ENOENT;
1062 		goto err_iomap;
1063 	}
1064 
1065 	hdata->ddc_port = hdmi_ddc;
1066 
1067 	/* hdmiphy i2c driver */
1068 	if (i2c_add_driver(&hdmiphy_driver)) {
1069 		DRM_ERROR("failed to register hdmiphy i2c driver\n");
1070 		ret = -ENOENT;
1071 		goto err_ddc;
1072 	}
1073 
1074 	hdata->hdmiphy_port = hdmi_hdmiphy;
1075 
1076 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1077 	if (res == NULL) {
1078 		DRM_ERROR("get interrupt resource failed.\n");
1079 		ret = -ENXIO;
1080 		goto err_hdmiphy;
1081 	}
1082 
1083 	/* create workqueue and hotplug work */
1084 	hdata->wq = alloc_workqueue("exynos-drm-hdmi",
1085 			WQ_UNBOUND | WQ_NON_REENTRANT, 1);
1086 	if (hdata->wq == NULL) {
1087 		DRM_ERROR("Failed to create workqueue.\n");
1088 		ret = -ENOMEM;
1089 		goto err_hdmiphy;
1090 	}
1091 	INIT_WORK(&hdata->hotplug_work, hdmi_hotplug_func);
1092 
1093 	/* register hpd interrupt */
1094 	ret = request_irq(res->start, hdmi_irq_handler, 0, "drm_hdmi",
1095 				drm_hdmi_ctx);
1096 	if (ret) {
1097 		DRM_ERROR("request interrupt failed.\n");
1098 		goto err_workqueue;
1099 	}
1100 	hdata->irq = res->start;
1101 
1102 	/* register specific callbacks to common hdmi. */
1103 	exynos_drm_display_ops_register(&display_ops);
1104 	exynos_drm_manager_ops_register(&manager_ops);
1105 
1106 	hdmi_resource_poweron(hdata);
1107 
1108 	return 0;
1109 
1110 err_workqueue:
1111 	destroy_workqueue(hdata->wq);
1112 err_hdmiphy:
1113 	i2c_del_driver(&hdmiphy_driver);
1114 err_ddc:
1115 	i2c_del_driver(&ddc_driver);
1116 err_iomap:
1117 	iounmap(hdata->regs);
1118 err_req_region:
1119 	release_resource(hdata->regs_res);
1120 	kfree(hdata->regs_res);
1121 err_resource:
1122 	hdmi_resources_cleanup(hdata);
1123 err_data:
1124 	kfree(hdata);
1125 	kfree(drm_hdmi_ctx);
1126 	return ret;
1127 }
1128 
1129 static int __devexit hdmi_remove(struct platform_device *pdev)
1130 {
1131 	struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
1132 	struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx;
1133 
1134 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
1135 
1136 	hdmi_resource_poweroff(hdata);
1137 
1138 	disable_irq(hdata->irq);
1139 	free_irq(hdata->irq, hdata);
1140 
1141 	cancel_work_sync(&hdata->hotplug_work);
1142 	destroy_workqueue(hdata->wq);
1143 
1144 	hdmi_resources_cleanup(hdata);
1145 
1146 	iounmap(hdata->regs);
1147 
1148 	release_resource(hdata->regs_res);
1149 	kfree(hdata->regs_res);
1150 
1151 	/* hdmiphy i2c driver */
1152 	i2c_del_driver(&hdmiphy_driver);
1153 	/* DDC i2c driver */
1154 	i2c_del_driver(&ddc_driver);
1155 
1156 	kfree(hdata);
1157 
1158 	return 0;
1159 }
1160 
1161 struct platform_driver hdmi_driver = {
1162 	.probe		= hdmi_probe,
1163 	.remove		= __devexit_p(hdmi_remove),
1164 	.driver		= {
1165 		.name	= "exynos4-hdmi",
1166 		.owner	= THIS_MODULE,
1167 		.pm = &hdmi_pm_ops,
1168 	},
1169 };
1170 EXPORT_SYMBOL(hdmi_driver);
1171 
1172 MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
1173 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1174 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
1175 MODULE_DESCRIPTION("Samsung DRM HDMI core Driver");
1176 MODULE_LICENSE("GPL");
1177