blob: c021ddc1ffb4b4e982ac01874953dbb7239ddc31 [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
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090020
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>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053034#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053035#include <linux/of.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053036#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053037#include <linux/hdmi.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090038
39#include <drm/exynos_drm.h>
40
41#include "exynos_drm_drv.h"
42#include "exynos_drm_hdmi.h"
43
44#include "exynos_hdmi.h"
45
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053046#include <linux/gpio.h>
47#include <media/s5p_hdmi.h>
48
Inki Dae1de425b2012-03-16 18:47:04 +090049#define MAX_WIDTH 1920
50#define MAX_HEIGHT 1080
Seung-Woo Kimd8408322011-12-21 17:39:39 +090051#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
52
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053/* AVI header and aspect ratio */
54#define HDMI_AVI_VERSION 0x02
55#define HDMI_AVI_LENGTH 0x0D
56#define AVI_PIC_ASPECT_RATIO_16_9 (2 << 4)
57#define AVI_SAME_AS_PIC_ASPECT_RATIO 8
58
59/* AUI header info */
60#define HDMI_AUI_VERSION 0x01
61#define HDMI_AUI_LENGTH 0x0A
62
Rahul Sharma5a325072012-10-04 20:48:54 +053063enum hdmi_type {
64 HDMI_TYPE13,
65 HDMI_TYPE14,
66};
67
Joonyoung Shim590f4182012-03-16 18:47:14 +090068struct hdmi_resources {
69 struct clk *hdmi;
70 struct clk *sclk_hdmi;
71 struct clk *sclk_pixel;
72 struct clk *sclk_hdmiphy;
73 struct clk *hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053074 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090075 struct regulator_bulk_data *regul_bulk;
76 int regul_count;
77};
78
Sean Paul2f7e2ed2013-01-15 08:11:08 -050079struct hdmi_tg_regs {
80 u8 cmd[1];
81 u8 h_fsz[2];
82 u8 hact_st[2];
83 u8 hact_sz[2];
84 u8 v_fsz[2];
85 u8 vsync[2];
86 u8 vsync2[2];
87 u8 vact_st[2];
88 u8 vact_sz[2];
89 u8 field_chg[2];
90 u8 vact_st2[2];
91 u8 vact_st3[2];
92 u8 vact_st4[2];
93 u8 vsync_top_hdmi[2];
94 u8 vsync_bot_hdmi[2];
95 u8 field_top_hdmi[2];
96 u8 field_bot_hdmi[2];
97 u8 tg_3d[1];
98};
99
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900100struct hdmi_v13_core_regs {
101 u8 h_blank[2];
102 u8 v_blank[3];
103 u8 h_v_line[3];
104 u8 vsync_pol[1];
105 u8 int_pro_mode[1];
106 u8 v_blank_f[3];
107 u8 h_sync_gen[3];
108 u8 v_sync_gen1[3];
109 u8 v_sync_gen2[3];
110 u8 v_sync_gen3[3];
111};
112
113struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500114 u8 h_blank[2];
115 u8 v2_blank[2];
116 u8 v1_blank[2];
117 u8 v_line[2];
118 u8 h_line[2];
119 u8 hsync_pol[1];
120 u8 vsync_pol[1];
121 u8 int_pro_mode[1];
122 u8 v_blank_f0[2];
123 u8 v_blank_f1[2];
124 u8 h_sync_start[2];
125 u8 h_sync_end[2];
126 u8 v_sync_line_bef_2[2];
127 u8 v_sync_line_bef_1[2];
128 u8 v_sync_line_aft_2[2];
129 u8 v_sync_line_aft_1[2];
130 u8 v_sync_line_aft_pxl_2[2];
131 u8 v_sync_line_aft_pxl_1[2];
132 u8 v_blank_f2[2]; /* for 3D mode */
133 u8 v_blank_f3[2]; /* for 3D mode */
134 u8 v_blank_f4[2]; /* for 3D mode */
135 u8 v_blank_f5[2]; /* for 3D mode */
136 u8 v_sync_line_aft_3[2];
137 u8 v_sync_line_aft_4[2];
138 u8 v_sync_line_aft_5[2];
139 u8 v_sync_line_aft_6[2];
140 u8 v_sync_line_aft_pxl_3[2];
141 u8 v_sync_line_aft_pxl_4[2];
142 u8 v_sync_line_aft_pxl_5[2];
143 u8 v_sync_line_aft_pxl_6[2];
144 u8 vact_space_1[2];
145 u8 vact_space_2[2];
146 u8 vact_space_3[2];
147 u8 vact_space_4[2];
148 u8 vact_space_5[2];
149 u8 vact_space_6[2];
150};
151
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900152struct hdmi_v13_conf {
153 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500154 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900155};
156
157struct hdmi_v14_conf {
158 struct hdmi_v14_core_regs core;
159 struct hdmi_tg_regs tg;
160};
161
162struct hdmi_conf_regs {
163 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500164 int cea_video_id;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900165 union {
166 struct hdmi_v13_conf v13_conf;
167 struct hdmi_v14_conf v14_conf;
168 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500169};
170
Joonyoung Shim590f4182012-03-16 18:47:14 +0900171struct hdmi_context {
172 struct device *dev;
173 struct drm_device *drm_dev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900174 bool hpd;
175 bool powered;
Seung-Woo Kim872d20d2012-04-24 17:39:15 +0900176 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900177 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900178
Joonyoung Shim590f4182012-03-16 18:47:14 +0900179 void __iomem *regs;
Inki Dae1055b392012-10-19 17:37:35 +0900180 void *parent_ctx;
Sean Paul77006a72013-01-16 10:17:20 -0500181 int irq;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900182
183 struct i2c_client *ddc_port;
184 struct i2c_client *hdmiphy_port;
185
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900186 /* current hdmiphy conf regs */
187 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900188
189 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900190
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530191 int hpd_gpio;
Rahul Sharma5a325072012-10-04 20:48:54 +0530192
193 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900194};
195
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500196struct hdmiphy_config {
197 int pixel_clock;
198 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900199};
200
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900201/* list of phy config settings */
202static const struct hdmiphy_config hdmiphy_v13_configs[] = {
203 {
204 .pixel_clock = 27000000,
205 .conf = {
206 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
207 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
208 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
209 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
210 },
211 },
212 {
213 .pixel_clock = 27027000,
214 .conf = {
215 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
216 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
217 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
218 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
219 },
220 },
221 {
222 .pixel_clock = 74176000,
223 .conf = {
224 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
225 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
226 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
227 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
228 },
229 },
230 {
231 .pixel_clock = 74250000,
232 .conf = {
233 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
234 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
235 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
236 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
237 },
238 },
239 {
240 .pixel_clock = 148500000,
241 .conf = {
242 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
243 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
244 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
245 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
246 },
247 },
248};
249
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500250static const struct hdmiphy_config hdmiphy_v14_configs[] = {
251 {
252 .pixel_clock = 25200000,
253 .conf = {
254 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
255 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
256 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
257 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
258 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900259 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500260 {
261 .pixel_clock = 27000000,
262 .conf = {
263 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
264 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
265 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
266 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
267 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900268 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500269 {
270 .pixel_clock = 27027000,
271 .conf = {
272 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
273 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
274 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
275 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
276 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900277 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500278 {
279 .pixel_clock = 36000000,
280 .conf = {
281 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
282 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
283 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
284 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
285 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900286 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500287 {
288 .pixel_clock = 40000000,
289 .conf = {
290 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
291 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
292 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
293 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
294 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900295 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500296 {
297 .pixel_clock = 65000000,
298 .conf = {
299 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
300 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
301 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
302 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
303 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900304 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500305 {
306 .pixel_clock = 74176000,
307 .conf = {
308 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
309 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
310 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
311 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
312 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900313 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500314 {
315 .pixel_clock = 74250000,
316 .conf = {
317 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
318 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
319 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
320 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
321 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900322 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500323 {
324 .pixel_clock = 83500000,
325 .conf = {
326 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
327 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
328 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
329 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
330 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900331 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500332 {
333 .pixel_clock = 106500000,
334 .conf = {
335 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
336 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
337 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
338 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
339 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900340 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500341 {
342 .pixel_clock = 108000000,
343 .conf = {
344 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
345 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
346 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
347 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
348 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900349 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500350 {
351 .pixel_clock = 146250000,
352 .conf = {
353 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
354 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
355 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
356 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
357 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900358 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500359 {
360 .pixel_clock = 148500000,
361 .conf = {
362 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
363 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
364 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
365 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
366 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900367 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900368};
369
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900370static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
371{
372 return readl(hdata->regs + reg_id);
373}
374
375static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
376 u32 reg_id, u8 value)
377{
378 writeb(value, hdata->regs + reg_id);
379}
380
381static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
382 u32 reg_id, u32 value, u32 mask)
383{
384 u32 old = readl(hdata->regs + reg_id);
385 value = (value & mask) | (old & ~mask);
386 writel(value, hdata->regs + reg_id);
387}
388
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900389static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900390{
391#define DUMPREG(reg_id) \
392 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
393 readl(hdata->regs + reg_id))
394 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
395 DUMPREG(HDMI_INTC_FLAG);
396 DUMPREG(HDMI_INTC_CON);
397 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900398 DUMPREG(HDMI_V13_PHY_RSTOUT);
399 DUMPREG(HDMI_V13_PHY_VPLL);
400 DUMPREG(HDMI_V13_PHY_CMU);
401 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900402
403 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
404 DUMPREG(HDMI_CON_0);
405 DUMPREG(HDMI_CON_1);
406 DUMPREG(HDMI_CON_2);
407 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900408 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900409 DUMPREG(HDMI_STATUS_EN);
410 DUMPREG(HDMI_HPD);
411 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900412 DUMPREG(HDMI_V13_HPD_GEN);
413 DUMPREG(HDMI_V13_DC_CONTROL);
414 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900415
416 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
417 DUMPREG(HDMI_H_BLANK_0);
418 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900419 DUMPREG(HDMI_V13_V_BLANK_0);
420 DUMPREG(HDMI_V13_V_BLANK_1);
421 DUMPREG(HDMI_V13_V_BLANK_2);
422 DUMPREG(HDMI_V13_H_V_LINE_0);
423 DUMPREG(HDMI_V13_H_V_LINE_1);
424 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900425 DUMPREG(HDMI_VSYNC_POL);
426 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900427 DUMPREG(HDMI_V13_V_BLANK_F_0);
428 DUMPREG(HDMI_V13_V_BLANK_F_1);
429 DUMPREG(HDMI_V13_V_BLANK_F_2);
430 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
431 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
432 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
433 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
434 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
435 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
436 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
437 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
438 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
439 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
440 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
441 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900442
443 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
444 DUMPREG(HDMI_TG_CMD);
445 DUMPREG(HDMI_TG_H_FSZ_L);
446 DUMPREG(HDMI_TG_H_FSZ_H);
447 DUMPREG(HDMI_TG_HACT_ST_L);
448 DUMPREG(HDMI_TG_HACT_ST_H);
449 DUMPREG(HDMI_TG_HACT_SZ_L);
450 DUMPREG(HDMI_TG_HACT_SZ_H);
451 DUMPREG(HDMI_TG_V_FSZ_L);
452 DUMPREG(HDMI_TG_V_FSZ_H);
453 DUMPREG(HDMI_TG_VSYNC_L);
454 DUMPREG(HDMI_TG_VSYNC_H);
455 DUMPREG(HDMI_TG_VSYNC2_L);
456 DUMPREG(HDMI_TG_VSYNC2_H);
457 DUMPREG(HDMI_TG_VACT_ST_L);
458 DUMPREG(HDMI_TG_VACT_ST_H);
459 DUMPREG(HDMI_TG_VACT_SZ_L);
460 DUMPREG(HDMI_TG_VACT_SZ_H);
461 DUMPREG(HDMI_TG_FIELD_CHG_L);
462 DUMPREG(HDMI_TG_FIELD_CHG_H);
463 DUMPREG(HDMI_TG_VACT_ST2_L);
464 DUMPREG(HDMI_TG_VACT_ST2_H);
465 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
466 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
467 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
468 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
469 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
470 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
471 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
472 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
473#undef DUMPREG
474}
475
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900476static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
477{
478 int i;
479
480#define DUMPREG(reg_id) \
481 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
482 readl(hdata->regs + reg_id))
483
484 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
485 DUMPREG(HDMI_INTC_CON);
486 DUMPREG(HDMI_INTC_FLAG);
487 DUMPREG(HDMI_HPD_STATUS);
488 DUMPREG(HDMI_INTC_CON_1);
489 DUMPREG(HDMI_INTC_FLAG_1);
490 DUMPREG(HDMI_PHY_STATUS_0);
491 DUMPREG(HDMI_PHY_STATUS_PLL);
492 DUMPREG(HDMI_PHY_CON_0);
493 DUMPREG(HDMI_PHY_RSTOUT);
494 DUMPREG(HDMI_PHY_VPLL);
495 DUMPREG(HDMI_PHY_CMU);
496 DUMPREG(HDMI_CORE_RSTOUT);
497
498 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
499 DUMPREG(HDMI_CON_0);
500 DUMPREG(HDMI_CON_1);
501 DUMPREG(HDMI_CON_2);
502 DUMPREG(HDMI_SYS_STATUS);
503 DUMPREG(HDMI_PHY_STATUS_0);
504 DUMPREG(HDMI_STATUS_EN);
505 DUMPREG(HDMI_HPD);
506 DUMPREG(HDMI_MODE_SEL);
507 DUMPREG(HDMI_ENC_EN);
508 DUMPREG(HDMI_DC_CONTROL);
509 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
510
511 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
512 DUMPREG(HDMI_H_BLANK_0);
513 DUMPREG(HDMI_H_BLANK_1);
514 DUMPREG(HDMI_V2_BLANK_0);
515 DUMPREG(HDMI_V2_BLANK_1);
516 DUMPREG(HDMI_V1_BLANK_0);
517 DUMPREG(HDMI_V1_BLANK_1);
518 DUMPREG(HDMI_V_LINE_0);
519 DUMPREG(HDMI_V_LINE_1);
520 DUMPREG(HDMI_H_LINE_0);
521 DUMPREG(HDMI_H_LINE_1);
522 DUMPREG(HDMI_HSYNC_POL);
523
524 DUMPREG(HDMI_VSYNC_POL);
525 DUMPREG(HDMI_INT_PRO_MODE);
526 DUMPREG(HDMI_V_BLANK_F0_0);
527 DUMPREG(HDMI_V_BLANK_F0_1);
528 DUMPREG(HDMI_V_BLANK_F1_0);
529 DUMPREG(HDMI_V_BLANK_F1_1);
530
531 DUMPREG(HDMI_H_SYNC_START_0);
532 DUMPREG(HDMI_H_SYNC_START_1);
533 DUMPREG(HDMI_H_SYNC_END_0);
534 DUMPREG(HDMI_H_SYNC_END_1);
535
536 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
537 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
538 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
539 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
540
541 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
542 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
543 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
544 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
545
546 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
547 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
548 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
549 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
550
551 DUMPREG(HDMI_V_BLANK_F2_0);
552 DUMPREG(HDMI_V_BLANK_F2_1);
553 DUMPREG(HDMI_V_BLANK_F3_0);
554 DUMPREG(HDMI_V_BLANK_F3_1);
555 DUMPREG(HDMI_V_BLANK_F4_0);
556 DUMPREG(HDMI_V_BLANK_F4_1);
557 DUMPREG(HDMI_V_BLANK_F5_0);
558 DUMPREG(HDMI_V_BLANK_F5_1);
559
560 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
561 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
562 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
563 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
564 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
565 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
566 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
567 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
568
569 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
570 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
571 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
572 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
573 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
574 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
575 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
576 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
577
578 DUMPREG(HDMI_VACT_SPACE_1_0);
579 DUMPREG(HDMI_VACT_SPACE_1_1);
580 DUMPREG(HDMI_VACT_SPACE_2_0);
581 DUMPREG(HDMI_VACT_SPACE_2_1);
582 DUMPREG(HDMI_VACT_SPACE_3_0);
583 DUMPREG(HDMI_VACT_SPACE_3_1);
584 DUMPREG(HDMI_VACT_SPACE_4_0);
585 DUMPREG(HDMI_VACT_SPACE_4_1);
586 DUMPREG(HDMI_VACT_SPACE_5_0);
587 DUMPREG(HDMI_VACT_SPACE_5_1);
588 DUMPREG(HDMI_VACT_SPACE_6_0);
589 DUMPREG(HDMI_VACT_SPACE_6_1);
590
591 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
592 DUMPREG(HDMI_TG_CMD);
593 DUMPREG(HDMI_TG_H_FSZ_L);
594 DUMPREG(HDMI_TG_H_FSZ_H);
595 DUMPREG(HDMI_TG_HACT_ST_L);
596 DUMPREG(HDMI_TG_HACT_ST_H);
597 DUMPREG(HDMI_TG_HACT_SZ_L);
598 DUMPREG(HDMI_TG_HACT_SZ_H);
599 DUMPREG(HDMI_TG_V_FSZ_L);
600 DUMPREG(HDMI_TG_V_FSZ_H);
601 DUMPREG(HDMI_TG_VSYNC_L);
602 DUMPREG(HDMI_TG_VSYNC_H);
603 DUMPREG(HDMI_TG_VSYNC2_L);
604 DUMPREG(HDMI_TG_VSYNC2_H);
605 DUMPREG(HDMI_TG_VACT_ST_L);
606 DUMPREG(HDMI_TG_VACT_ST_H);
607 DUMPREG(HDMI_TG_VACT_SZ_L);
608 DUMPREG(HDMI_TG_VACT_SZ_H);
609 DUMPREG(HDMI_TG_FIELD_CHG_L);
610 DUMPREG(HDMI_TG_FIELD_CHG_H);
611 DUMPREG(HDMI_TG_VACT_ST2_L);
612 DUMPREG(HDMI_TG_VACT_ST2_H);
613 DUMPREG(HDMI_TG_VACT_ST3_L);
614 DUMPREG(HDMI_TG_VACT_ST3_H);
615 DUMPREG(HDMI_TG_VACT_ST4_L);
616 DUMPREG(HDMI_TG_VACT_ST4_H);
617 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
618 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
619 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
620 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
621 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
622 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
623 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
624 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
625 DUMPREG(HDMI_TG_3D);
626
627 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
628 DUMPREG(HDMI_AVI_CON);
629 DUMPREG(HDMI_AVI_HEADER0);
630 DUMPREG(HDMI_AVI_HEADER1);
631 DUMPREG(HDMI_AVI_HEADER2);
632 DUMPREG(HDMI_AVI_CHECK_SUM);
633 DUMPREG(HDMI_VSI_CON);
634 DUMPREG(HDMI_VSI_HEADER0);
635 DUMPREG(HDMI_VSI_HEADER1);
636 DUMPREG(HDMI_VSI_HEADER2);
637 for (i = 0; i < 7; ++i)
638 DUMPREG(HDMI_VSI_DATA(i));
639
640#undef DUMPREG
641}
642
643static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
644{
Rahul Sharma5a325072012-10-04 20:48:54 +0530645 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900646 hdmi_v13_regs_dump(hdata, prefix);
647 else
648 hdmi_v14_regs_dump(hdata, prefix);
649}
650
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530651static u8 hdmi_chksum(struct hdmi_context *hdata,
652 u32 start, u8 len, u32 hdr_sum)
653{
654 int i;
655
656 /* hdr_sum : header0 + header1 + header2
657 * start : start address of packet byte1
658 * len : packet bytes - 1 */
659 for (i = 0; i < len; ++i)
660 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
661
662 /* return 2's complement of 8 bit hdr_sum */
663 return (u8)(~(hdr_sum & 0xff) + 1);
664}
665
666static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530667 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530668{
669 u32 hdr_sum;
670 u8 chksum;
671 u32 aspect_ratio;
672 u32 mod;
673 u32 vic;
674
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530675 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
676 if (hdata->dvi_mode) {
677 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
678 HDMI_VSI_CON_DO_NOT_TRANSMIT);
679 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
680 HDMI_AVI_CON_DO_NOT_TRANSMIT);
681 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
682 return;
683 }
684
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530685 switch (infoframe->any.type) {
686 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530687 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530688 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
689 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
690 infoframe->any.version);
691 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
692 hdr_sum = infoframe->any.type + infoframe->any.version +
693 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530694
695 /* Output format zero hardcoded ,RGB YBCR selection */
696 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
697 AVI_ACTIVE_FORMAT_VALID |
698 AVI_UNDERSCANNED_DISPLAY_VALID);
699
700 aspect_ratio = AVI_PIC_ASPECT_RATIO_16_9;
701
702 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio |
703 AVI_SAME_AS_PIC_ASPECT_RATIO);
704
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900705 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530706 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
707
708 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530709 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530710 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
711 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
712 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530713 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530714 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530715 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
716 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
717 infoframe->any.version);
718 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
719 hdr_sum = infoframe->any.type + infoframe->any.version +
720 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530721 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530722 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530723 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
724 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
725 break;
726 default:
727 break;
728 }
729}
730
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900731static bool hdmi_is_connected(void *ctx)
732{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900733 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900734
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900735 return hdata->hpd;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900736}
737
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500738static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900739{
740 struct edid *raw_edid;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900741 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900742
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900743 if (!hdata->ddc_port)
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500744 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900745
746 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500747 if (!raw_edid)
748 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900749
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500750 hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
751 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
752 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
753 raw_edid->width_cm, raw_edid->height_cm);
754
755 return raw_edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900756}
757
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900758static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900759{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900760 const struct hdmiphy_config *confs;
761 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900762
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900763 if (hdata->type == HDMI_TYPE13) {
764 confs = hdmiphy_v13_configs;
765 count = ARRAY_SIZE(hdmiphy_v13_configs);
766 } else if (hdata->type == HDMI_TYPE14) {
767 confs = hdmiphy_v14_configs;
768 count = ARRAY_SIZE(hdmiphy_v14_configs);
769 } else
770 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900771
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900772 for (i = 0; i < count; i++)
773 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500774 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500775
776 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
777 return -EINVAL;
778}
779
Rahul Sharma16844fb2013-06-10 14:50:00 +0530780static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900781{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900782 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900783 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900784
Rahul Sharma16844fb2013-06-10 14:50:00 +0530785 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
786 mode->hdisplay, mode->vdisplay, mode->vrefresh,
787 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
788 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900789
Rahul Sharma16844fb2013-06-10 14:50:00 +0530790 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900791 if (ret < 0)
792 return ret;
793 return 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900794}
795
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900796static void hdmi_set_acr(u32 freq, u8 *acr)
797{
798 u32 n, cts;
799
800 switch (freq) {
801 case 32000:
802 n = 4096;
803 cts = 27000;
804 break;
805 case 44100:
806 n = 6272;
807 cts = 30000;
808 break;
809 case 88200:
810 n = 12544;
811 cts = 30000;
812 break;
813 case 176400:
814 n = 25088;
815 cts = 30000;
816 break;
817 case 48000:
818 n = 6144;
819 cts = 27000;
820 break;
821 case 96000:
822 n = 12288;
823 cts = 27000;
824 break;
825 case 192000:
826 n = 24576;
827 cts = 27000;
828 break;
829 default:
830 n = 0;
831 cts = 0;
832 break;
833 }
834
835 acr[1] = cts >> 16;
836 acr[2] = cts >> 8 & 0xff;
837 acr[3] = cts & 0xff;
838
839 acr[4] = n >> 16;
840 acr[5] = n >> 8 & 0xff;
841 acr[6] = n & 0xff;
842}
843
844static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
845{
846 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
847 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
848 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
849 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
850 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
851 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
852 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
853 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
854 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
855
Rahul Sharma5a325072012-10-04 20:48:54 +0530856 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900857 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
858 else
859 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
860}
861
862static void hdmi_audio_init(struct hdmi_context *hdata)
863{
864 u32 sample_rate, bits_per_sample, frame_size_code;
865 u32 data_num, bit_ch, sample_frq;
866 u32 val;
867 u8 acr[7];
868
869 sample_rate = 44100;
870 bits_per_sample = 16;
871 frame_size_code = 0;
872
873 switch (bits_per_sample) {
874 case 20:
875 data_num = 2;
876 bit_ch = 1;
877 break;
878 case 24:
879 data_num = 3;
880 bit_ch = 1;
881 break;
882 default:
883 data_num = 1;
884 bit_ch = 0;
885 break;
886 }
887
888 hdmi_set_acr(sample_rate, acr);
889 hdmi_reg_acr(hdata, acr);
890
891 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
892 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
893 | HDMI_I2S_MUX_ENABLE);
894
895 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
896 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
897
898 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
899
900 sample_frq = (sample_rate == 44100) ? 0 :
901 (sample_rate == 48000) ? 2 :
902 (sample_rate == 32000) ? 3 :
903 (sample_rate == 96000) ? 0xa : 0x0;
904
905 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
906 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
907
908 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
909 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
910
911 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
912 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
913 | HDMI_I2S_SEL_LRCK(6));
914 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
915 | HDMI_I2S_SEL_SDATA2(4));
916 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
917 | HDMI_I2S_SEL_SDATA2(2));
918 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
919
920 /* I2S_CON_1 & 2 */
921 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
922 | HDMI_I2S_L_CH_LOW_POL);
923 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
924 | HDMI_I2S_SET_BIT_CH(bit_ch)
925 | HDMI_I2S_SET_SDATA_BIT(data_num)
926 | HDMI_I2S_BASIC_FORMAT);
927
928 /* Configure register related to CUV information */
929 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
930 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
931 | HDMI_I2S_COPYRIGHT
932 | HDMI_I2S_LINEAR_PCM
933 | HDMI_I2S_CONSUMER_FORMAT);
934 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
935 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
936 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
937 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
938 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
939 HDMI_I2S_ORG_SMP_FREQ_44_1
940 | HDMI_I2S_WORD_LEN_MAX24_24BITS
941 | HDMI_I2S_WORD_LEN_MAX_24BITS);
942
943 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
944}
945
946static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
947{
Seung-Woo Kim872d20d2012-04-24 17:39:15 +0900948 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900949 return;
950
951 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
952 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
953 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
954}
955
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900956static void hdmi_conf_reset(struct hdmi_context *hdata)
957{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900958 u32 reg;
959
Rahul Sharma5a325072012-10-04 20:48:54 +0530960 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900961 reg = HDMI_V13_CORE_RSTOUT;
962 else
963 reg = HDMI_CORE_RSTOUT;
964
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900965 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900966 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -0500967 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900968 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -0500969 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900970}
971
972static void hdmi_conf_init(struct hdmi_context *hdata)
973{
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530974 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530975
Sean Paul77006a72013-01-16 10:17:20 -0500976 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900977 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
978 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900979
980 /* choose HDMI mode */
981 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
982 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
983 /* disable bluescreen */
984 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900985
Seung-Woo Kim872d20d2012-04-24 17:39:15 +0900986 if (hdata->dvi_mode) {
987 /* choose DVI mode */
988 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
989 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
990 hdmi_reg_writeb(hdata, HDMI_CON_2,
991 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
992 }
993
Rahul Sharma5a325072012-10-04 20:48:54 +0530994 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900995 /* choose bluescreen (fecal) color */
996 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
997 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
998 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
999
1000 /* enable AVI packet every vsync, fixes purple line problem */
1001 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1002 /* force RGB, look to CEA-861-D, table 7 for more detail */
1003 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1004 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1005
1006 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1007 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1008 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1009 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301010 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1011 infoframe.any.version = HDMI_AVI_VERSION;
1012 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301013 hdmi_reg_infoframe(hdata, &infoframe);
1014
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301015 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1016 infoframe.any.version = HDMI_AUI_VERSION;
1017 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301018 hdmi_reg_infoframe(hdata, &infoframe);
1019
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001020 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001021 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1022 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001023}
1024
Rahul Sharma16844fb2013-06-10 14:50:00 +05301025static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001026{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001027 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1028 const struct hdmi_v13_core_regs *core =
1029 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001030 int tries;
1031
1032 /* setting core registers */
1033 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1034 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001035 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1036 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1037 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1038 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1039 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1040 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001041 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1042 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001043 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1044 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1045 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1046 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1047 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1048 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1049 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1050 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1051 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1052 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1053 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1054 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1055 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1056 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1057 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001058 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001059 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1060 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1061 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1062 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1063 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1064 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1065 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1066 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1067 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1068 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1069 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1070 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1071 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1072 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1073 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1074 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1075 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1076 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1077 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1078 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1079 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1080 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1081 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1082 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1083 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1084 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1085 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1086 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001087
1088 /* waiting for HDMIPHY's PLL to get to steady state */
1089 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001090 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001091 if (val & HDMI_PHY_STATUS_READY)
1092 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001093 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001094 }
1095 /* steady state not achieved */
1096 if (tries == 0) {
1097 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1098 hdmi_regs_dump(hdata, "timing apply");
1099 }
1100
Sean Paul0bfb1f82013-06-11 12:24:02 +05301101 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301102 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301103 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001104
1105 /* enable HDMI and timing generator */
1106 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1107 if (core->int_pro_mode[0])
1108 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1109 HDMI_FIELD_EN);
1110 else
1111 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1112}
1113
Rahul Sharma16844fb2013-06-10 14:50:00 +05301114static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001115{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001116 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1117 const struct hdmi_v14_core_regs *core =
1118 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001119 int tries;
1120
1121 /* setting core registers */
1122 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1123 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1124 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1125 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1126 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1127 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1128 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1129 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1130 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1131 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1132 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1133 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1134 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1135 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1136 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1137 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1138 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1139 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1140 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1141 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1142 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1143 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1144 core->v_sync_line_bef_2[0]);
1145 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1146 core->v_sync_line_bef_2[1]);
1147 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1148 core->v_sync_line_bef_1[0]);
1149 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1150 core->v_sync_line_bef_1[1]);
1151 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1152 core->v_sync_line_aft_2[0]);
1153 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1154 core->v_sync_line_aft_2[1]);
1155 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1156 core->v_sync_line_aft_1[0]);
1157 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1158 core->v_sync_line_aft_1[1]);
1159 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1160 core->v_sync_line_aft_pxl_2[0]);
1161 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1162 core->v_sync_line_aft_pxl_2[1]);
1163 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1164 core->v_sync_line_aft_pxl_1[0]);
1165 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1166 core->v_sync_line_aft_pxl_1[1]);
1167 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1168 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1169 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1170 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1171 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1172 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1173 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1174 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1175 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1176 core->v_sync_line_aft_3[0]);
1177 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1178 core->v_sync_line_aft_3[1]);
1179 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1180 core->v_sync_line_aft_4[0]);
1181 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1182 core->v_sync_line_aft_4[1]);
1183 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1184 core->v_sync_line_aft_5[0]);
1185 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1186 core->v_sync_line_aft_5[1]);
1187 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1188 core->v_sync_line_aft_6[0]);
1189 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1190 core->v_sync_line_aft_6[1]);
1191 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1192 core->v_sync_line_aft_pxl_3[0]);
1193 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1194 core->v_sync_line_aft_pxl_3[1]);
1195 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1196 core->v_sync_line_aft_pxl_4[0]);
1197 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1198 core->v_sync_line_aft_pxl_4[1]);
1199 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1200 core->v_sync_line_aft_pxl_5[0]);
1201 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1202 core->v_sync_line_aft_pxl_5[1]);
1203 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1204 core->v_sync_line_aft_pxl_6[0]);
1205 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1206 core->v_sync_line_aft_pxl_6[1]);
1207 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1208 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1209 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1210 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1211 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1212 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1213 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1214 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1215 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1216 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1217 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1218 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1219
1220 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001221 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1222 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1223 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1224 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1225 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1226 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1227 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1228 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1229 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1230 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1231 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1232 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1233 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1234 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1235 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1236 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1237 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1238 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1239 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1240 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1241 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1242 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1243 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1244 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1245 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1246 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1247 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1248 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1249 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1250 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1251 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1252 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1253 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001254
1255 /* waiting for HDMIPHY's PLL to get to steady state */
1256 for (tries = 100; tries; --tries) {
1257 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1258 if (val & HDMI_PHY_STATUS_READY)
1259 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001260 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001261 }
1262 /* steady state not achieved */
1263 if (tries == 0) {
1264 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1265 hdmi_regs_dump(hdata, "timing apply");
1266 }
1267
Sean Paul0bfb1f82013-06-11 12:24:02 +05301268 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301269 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301270 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001271
1272 /* enable HDMI and timing generator */
1273 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1274 if (core->int_pro_mode[0])
1275 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1276 HDMI_FIELD_EN);
1277 else
1278 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1279}
1280
Rahul Sharma16844fb2013-06-10 14:50:00 +05301281static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001282{
Rahul Sharma5a325072012-10-04 20:48:54 +05301283 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301284 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001285 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301286 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001287}
1288
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001289static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1290{
1291 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001292 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001293
Sean Paul0bfb1f82013-06-11 12:24:02 +05301294 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301295 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301296 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001297
1298 /* operation mode */
1299 buffer[0] = 0x1f;
1300 buffer[1] = 0x00;
1301
1302 if (hdata->hdmiphy_port)
1303 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1304
Rahul Sharma5a325072012-10-04 20:48:54 +05301305 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001306 reg = HDMI_V13_PHY_RSTOUT;
1307 else
1308 reg = HDMI_PHY_RSTOUT;
1309
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001310 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001311 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001312 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001313 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001314 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001315}
1316
Rahul Sharmaa5562252012-11-28 11:30:25 +05301317static void hdmiphy_poweron(struct hdmi_context *hdata)
1318{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301319 if (hdata->type == HDMI_TYPE14)
1320 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1321 HDMI_PHY_POWER_OFF_EN);
1322}
1323
1324static void hdmiphy_poweroff(struct hdmi_context *hdata)
1325{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301326 if (hdata->type == HDMI_TYPE14)
1327 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1328 HDMI_PHY_POWER_OFF_EN);
1329}
1330
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001331static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1332{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001333 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001334 u8 buffer[32];
1335 u8 operation[2];
1336 u8 read_buffer[32] = {0, };
1337 int ret;
1338 int i;
1339
1340 if (!hdata->hdmiphy_port) {
1341 DRM_ERROR("hdmiphy is not attached\n");
1342 return;
1343 }
1344
1345 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001346 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1347 if (i < 0) {
1348 DRM_ERROR("failed to find hdmiphy conf\n");
1349 return;
1350 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001351
Sachin Kamat5f46c332013-04-26 11:29:00 +05301352 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001353 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301354 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001355 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001356
1357 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001358 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1359 if (ret != 32) {
1360 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1361 return;
1362 }
1363
Sean Paul09760ea2013-01-14 17:03:20 -05001364 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001365
1366 /* operation mode */
1367 operation[0] = 0x1f;
1368 operation[1] = 0x80;
1369
1370 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1371 if (ret != 2) {
1372 DRM_ERROR("failed to enable hdmiphy\n");
1373 return;
1374 }
1375
1376 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1377 if (ret < 0) {
1378 DRM_ERROR("failed to read hdmiphy config\n");
1379 return;
1380 }
1381
1382 for (i = 0; i < ret; i++)
1383 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1384 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1385}
1386
1387static void hdmi_conf_apply(struct hdmi_context *hdata)
1388{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001389 hdmiphy_conf_reset(hdata);
1390 hdmiphy_conf_apply(hdata);
1391
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001392 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001393 hdmi_conf_reset(hdata);
1394 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001395 mutex_unlock(&hdata->hdmi_mutex);
1396
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001397 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001398
1399 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301400 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001401 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001402
1403 hdmi_regs_dump(hdata, "start");
1404}
1405
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001406static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1407{
1408 int i;
1409 BUG_ON(num_bytes > 4);
1410 for (i = 0; i < num_bytes; i++)
1411 reg_pair[i] = (value >> (8 * i)) & 0xff;
1412}
1413
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001414static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1415 struct drm_display_mode *m)
1416{
1417 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1418 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1419 unsigned int val;
1420
1421 hdata->mode_conf.cea_video_id =
1422 drm_match_cea_mode((struct drm_display_mode *)m);
1423 hdata->mode_conf.pixel_clock = m->clock * 1000;
1424
1425 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1426 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1427
1428 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1429 hdmi_set_reg(core->vsync_pol, 1, val);
1430
1431 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1432 hdmi_set_reg(core->int_pro_mode, 1, val);
1433
1434 val = (m->hsync_start - m->hdisplay - 2);
1435 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1436 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1437 hdmi_set_reg(core->h_sync_gen, 3, val);
1438
1439 /*
1440 * Quirk requirement for exynos HDMI IP design,
1441 * 2 pixels less than the actual calculation for hsync_start
1442 * and end.
1443 */
1444
1445 /* Following values & calculations differ for different type of modes */
1446 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1447 /* Interlaced Mode */
1448 val = ((m->vsync_end - m->vdisplay) / 2);
1449 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1450 hdmi_set_reg(core->v_sync_gen1, 3, val);
1451
1452 val = m->vtotal / 2;
1453 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1454 hdmi_set_reg(core->v_blank, 3, val);
1455
1456 val = (m->vtotal +
1457 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1458 val |= m->vtotal << 11;
1459 hdmi_set_reg(core->v_blank_f, 3, val);
1460
1461 val = ((m->vtotal / 2) + 7);
1462 val |= ((m->vtotal / 2) + 2) << 12;
1463 hdmi_set_reg(core->v_sync_gen2, 3, val);
1464
1465 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1466 val |= ((m->htotal / 2) +
1467 (m->hsync_start - m->hdisplay)) << 12;
1468 hdmi_set_reg(core->v_sync_gen3, 3, val);
1469
1470 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1471 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1472
1473 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1474 } else {
1475 /* Progressive Mode */
1476
1477 val = m->vtotal;
1478 val |= (m->vtotal - m->vdisplay) << 11;
1479 hdmi_set_reg(core->v_blank, 3, val);
1480
1481 hdmi_set_reg(core->v_blank_f, 3, 0);
1482
1483 val = (m->vsync_end - m->vdisplay);
1484 val |= ((m->vsync_start - m->vdisplay) << 12);
1485 hdmi_set_reg(core->v_sync_gen1, 3, val);
1486
1487 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1488 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1489 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1490 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1491 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1492 }
1493
1494 /* Timing generator registers */
1495 hdmi_set_reg(tg->cmd, 1, 0x0);
1496 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1497 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1498 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1499 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1500 hdmi_set_reg(tg->vsync, 2, 0x1);
1501 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1502 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1503 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1504 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1505 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1506 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1507 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1508}
1509
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001510static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1511 struct drm_display_mode *m)
1512{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001513 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1514 struct hdmi_v14_core_regs *core =
1515 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001516
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001517 hdata->mode_conf.cea_video_id =
1518 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001519 hdata->mode_conf.pixel_clock = m->clock * 1000;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001520
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001521 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1522 hdmi_set_reg(core->v_line, 2, m->vtotal);
1523 hdmi_set_reg(core->h_line, 2, m->htotal);
1524 hdmi_set_reg(core->hsync_pol, 1,
1525 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1526 hdmi_set_reg(core->vsync_pol, 1,
1527 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1528 hdmi_set_reg(core->int_pro_mode, 1,
1529 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1530
1531 /*
1532 * Quirk requirement for exynos 5 HDMI IP design,
1533 * 2 pixels less than the actual calculation for hsync_start
1534 * and end.
1535 */
1536
1537 /* Following values & calculations differ for different type of modes */
1538 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1539 /* Interlaced Mode */
1540 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1541 (m->vsync_end - m->vdisplay) / 2);
1542 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1543 (m->vsync_start - m->vdisplay) / 2);
1544 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1545 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301546 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001547 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1548 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1549 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1550 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1551 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1552 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1553 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1554 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1555 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301556 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1557 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1558 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1559 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001560 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1561 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1562 } else {
1563 /* Progressive Mode */
1564 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1565 m->vsync_end - m->vdisplay);
1566 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1567 m->vsync_start - m->vdisplay);
1568 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1569 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1570 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1571 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1572 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1573 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1574 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1575 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1576 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1577 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1578 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1579 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1580 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301581 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1582 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1583 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001584 }
1585
1586 /* Following values & calculations are same irrespective of mode type */
1587 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1588 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1589 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1590 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1591 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1592 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1593 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1594 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1595 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1596 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1597 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1598 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1599 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1600 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1601 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1602 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1603 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1604 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1605 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1606 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1607
1608 /* Timing generator registers */
1609 hdmi_set_reg(tg->cmd, 1, 0x0);
1610 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1611 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1612 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1613 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1614 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001615 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1616 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001617 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001618 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001619}
1620
Rahul Sharma16844fb2013-06-10 14:50:00 +05301621static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001622{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001623 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001624 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001625
YoungJun Chocbc4c332013-06-12 10:44:40 +09001626 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1627 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001628 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1629 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001630
Sachin Kamat5f46c332013-04-26 11:29:00 +05301631 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001632 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301633 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001634 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001635}
1636
Inki Dae1de425b2012-03-16 18:47:04 +09001637static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1638 unsigned int *height)
1639{
Inki Dae1de425b2012-03-16 18:47:04 +09001640 *width = MAX_WIDTH;
1641 *height = MAX_HEIGHT;
1642}
1643
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001644static void hdmi_commit(void *ctx)
1645{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001646 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001647
Shirish Sdda90122013-01-23 22:03:18 -05001648 mutex_lock(&hdata->hdmi_mutex);
1649 if (!hdata->powered) {
1650 mutex_unlock(&hdata->hdmi_mutex);
1651 return;
1652 }
1653 mutex_unlock(&hdata->hdmi_mutex);
1654
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001655 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001656}
1657
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001658static void hdmi_poweron(struct hdmi_context *hdata)
1659{
1660 struct hdmi_resources *res = &hdata->res;
1661
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001662 mutex_lock(&hdata->hdmi_mutex);
1663 if (hdata->powered) {
1664 mutex_unlock(&hdata->hdmi_mutex);
1665 return;
1666 }
1667
1668 hdata->powered = true;
1669
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001670 mutex_unlock(&hdata->hdmi_mutex);
1671
Seung-Woo Kimad079452013-06-05 14:34:38 +09001672 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1673 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1674
Sean Paul0bfb1f82013-06-11 12:24:02 +05301675 clk_prepare_enable(res->hdmiphy);
1676 clk_prepare_enable(res->hdmi);
1677 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301678
1679 hdmiphy_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001680}
1681
1682static void hdmi_poweroff(struct hdmi_context *hdata)
1683{
1684 struct hdmi_resources *res = &hdata->res;
1685
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001686 mutex_lock(&hdata->hdmi_mutex);
1687 if (!hdata->powered)
1688 goto out;
1689 mutex_unlock(&hdata->hdmi_mutex);
1690
1691 /*
1692 * The TV power domain needs any condition of hdmiphy to turn off and
1693 * its reset state seems to meet the condition.
1694 */
1695 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301696 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001697
Sean Paul0bfb1f82013-06-11 12:24:02 +05301698 clk_disable_unprepare(res->sclk_hdmi);
1699 clk_disable_unprepare(res->hdmi);
1700 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001701 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1702
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001703 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001704
1705 hdata->powered = false;
1706
1707out:
1708 mutex_unlock(&hdata->hdmi_mutex);
1709}
1710
1711static void hdmi_dpms(void *ctx, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001712{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001713 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001714
YoungJun Chocbc4c332013-06-12 10:44:40 +09001715 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001716
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001717 switch (mode) {
1718 case DRM_MODE_DPMS_ON:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301719 if (pm_runtime_suspended(hdata->dev))
1720 pm_runtime_get_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001721 break;
1722 case DRM_MODE_DPMS_STANDBY:
1723 case DRM_MODE_DPMS_SUSPEND:
1724 case DRM_MODE_DPMS_OFF:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301725 if (!pm_runtime_suspended(hdata->dev))
1726 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001727 break;
1728 default:
1729 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1730 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001731 }
1732}
1733
Joonyoung Shim578b6062012-04-05 20:49:26 +09001734static struct exynos_hdmi_ops hdmi_ops = {
1735 /* display */
1736 .is_connected = hdmi_is_connected,
1737 .get_edid = hdmi_get_edid,
Rahul Sharma16844fb2013-06-10 14:50:00 +05301738 .check_mode = hdmi_check_mode,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001739
1740 /* manager */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001741 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09001742 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001743 .commit = hdmi_commit,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001744 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001745};
1746
Sean Paul77006a72013-01-16 10:17:20 -05001747static irqreturn_t hdmi_irq_thread(int irq, void *arg)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001748{
1749 struct exynos_drm_hdmi_context *ctx = arg;
1750 struct hdmi_context *hdata = ctx->ctx;
1751
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001752 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301753 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001754 mutex_unlock(&hdata->hdmi_mutex);
1755
1756 if (ctx->drm_dev)
1757 drm_helper_hpd_irq_event(ctx->drm_dev);
1758
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001759 return IRQ_HANDLED;
1760}
1761
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001762static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001763{
1764 struct device *dev = hdata->dev;
1765 struct hdmi_resources *res = &hdata->res;
1766 static char *supply[] = {
1767 "hdmi-en",
1768 "vdd",
1769 "vdd_osc",
1770 "vdd_pll",
1771 };
1772 int i, ret;
1773
1774 DRM_DEBUG_KMS("HDMI resource init\n");
1775
Sachin Kamatadc837a2012-08-31 15:50:47 +05301776 memset(res, 0, sizeof(*res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001777
1778 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301779 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301780 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001781 DRM_ERROR("failed to get clock 'hdmi'\n");
1782 goto fail;
1783 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301784 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301785 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001786 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1787 goto fail;
1788 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301789 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301790 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001791 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1792 goto fail;
1793 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301794 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301795 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001796 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1797 goto fail;
1798 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301799 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301800 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001801 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1802 goto fail;
1803 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301804 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1805 if (IS_ERR(res->mout_hdmi)) {
1806 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1807 goto fail;
1808 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001809
Rahul Sharma59956d32013-06-11 12:24:03 +05301810 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001811
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301812 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301813 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001814 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001815 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001816 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1817 res->regul_bulk[i].supply = supply[i];
1818 res->regul_bulk[i].consumer = NULL;
1819 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301820 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001821 if (ret) {
1822 DRM_ERROR("failed to get regulators\n");
1823 goto fail;
1824 }
1825 res->regul_count = ARRAY_SIZE(supply);
1826
1827 return 0;
1828fail:
1829 DRM_ERROR("HDMI resource init - failed\n");
1830 return -ENODEV;
1831}
1832
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001833static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
1834
1835void hdmi_attach_ddc_client(struct i2c_client *ddc)
1836{
1837 if (ddc)
1838 hdmi_ddc = ddc;
1839}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001840
1841void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
1842{
1843 if (hdmiphy)
1844 hdmi_hdmiphy = hdmiphy;
1845}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001846
Rahul Sharma22c4f422012-10-04 20:48:55 +05301847static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1848 (struct device *dev)
1849{
1850 struct device_node *np = dev->of_node;
1851 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301852 u32 value;
1853
1854 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001855 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05301856 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301857
1858 if (!of_find_property(np, "hpd-gpio", &value)) {
1859 DRM_ERROR("no hpd gpio property found\n");
1860 goto err_data;
1861 }
1862
Rahul Sharma5f916e22013-06-11 19:41:29 +05301863 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05301864
1865 return pd;
1866
1867err_data:
1868 return NULL;
1869}
Rahul Sharma22c4f422012-10-04 20:48:55 +05301870
Rahul Sharma22c4f422012-10-04 20:48:55 +05301871static struct of_device_id hdmi_match_types[] = {
1872 {
1873 .compatible = "samsung,exynos5-hdmi",
1874 .data = (void *)HDMI_TYPE14,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301875 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301876 .compatible = "samsung,exynos4212-hdmi",
1877 .data = (void *)HDMI_TYPE14,
1878 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301879 /* end node */
1880 }
1881};
1882
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001883static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001884{
1885 struct device *dev = &pdev->dev;
1886 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1887 struct hdmi_context *hdata;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301888 struct s5p_hdmi_platform_data *pdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001889 struct resource *res;
Sachin Kamat88c49812013-08-28 10:47:57 +05301890 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001891 int ret;
1892
Sachin Kamat88c49812013-08-28 10:47:57 +05301893 if (!dev->of_node)
1894 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301895
Sachin Kamat88c49812013-08-28 10:47:57 +05301896 pdata = drm_hdmi_dt_parse_pdata(dev);
1897 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001898 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001899
Sachin Kamat88c49812013-08-28 10:47:57 +05301900 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001901 if (!drm_hdmi_ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001902 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001903
Sachin Kamat88c49812013-08-28 10:47:57 +05301904 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001905 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001906 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001907
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001908 mutex_init(&hdata->hdmi_mutex);
1909
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001910 drm_hdmi_ctx->ctx = (void *)hdata;
1911 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1912
1913 platform_set_drvdata(pdev, drm_hdmi_ctx);
1914
Sachin Kamat88c49812013-08-28 10:47:57 +05301915 match = of_match_node(hdmi_match_types, dev->of_node);
1916 if (!match)
1917 return -ENODEV;
1918 hdata->type = (enum hdmi_type)match->data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301919
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301920 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001921 hdata->dev = dev;
1922
1923 ret = hdmi_resources_init(hdata);
1924 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301925 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301926 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001927 }
1928
1929 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001930 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001931 if (IS_ERR(hdata->regs))
1932 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001933
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001934 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301935 if (ret) {
1936 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301937 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301938 }
1939
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001940 /* DDC i2c driver */
1941 if (i2c_add_driver(&ddc_driver)) {
1942 DRM_ERROR("failed to register ddc i2c driver\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301943 return -ENOENT;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001944 }
1945
1946 hdata->ddc_port = hdmi_ddc;
1947
1948 /* hdmiphy i2c driver */
1949 if (i2c_add_driver(&hdmiphy_driver)) {
1950 DRM_ERROR("failed to register hdmiphy i2c driver\n");
1951 ret = -ENOENT;
1952 goto err_ddc;
1953 }
1954
1955 hdata->hdmiphy_port = hdmi_hdmiphy;
1956
Sean Paul77006a72013-01-16 10:17:20 -05001957 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
1958 if (hdata->irq < 0) {
1959 DRM_ERROR("failed to get GPIO irq\n");
1960 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09001961 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001962 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001963
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301964 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
1965
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09001966 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05001967 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001968 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paul77006a72013-01-16 10:17:20 -05001969 "hdmi", drm_hdmi_ctx);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001970 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05001971 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001972 goto err_hdmiphy;
1973 }
1974
Rahul Sharma768c3052012-10-04 20:48:56 +05301975 /* Attach HDMI Driver to common hdmi. */
1976 exynos_hdmi_drv_attach(drm_hdmi_ctx);
1977
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001978 /* register specific callbacks to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09001979 exynos_hdmi_ops_register(&hdmi_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001980
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001981 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001982
1983 return 0;
1984
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001985err_hdmiphy:
1986 i2c_del_driver(&hdmiphy_driver);
1987err_ddc:
1988 i2c_del_driver(&ddc_driver);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001989 return ret;
1990}
1991
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001992static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001993{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001994 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001995
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001996 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001997
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001998 /* hdmiphy i2c driver */
1999 i2c_del_driver(&hdmiphy_driver);
2000 /* DDC i2c driver */
2001 i2c_del_driver(&ddc_driver);
2002
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002003 return 0;
2004}
2005
Joonyoung Shimab27af82012-04-23 19:35:51 +09002006#ifdef CONFIG_PM_SLEEP
2007static int hdmi_suspend(struct device *dev)
2008{
2009 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2010 struct hdmi_context *hdata = ctx->ctx;
2011
Sean Paul77006a72013-01-16 10:17:20 -05002012 disable_irq(hdata->irq);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002013
2014 hdata->hpd = false;
2015 if (ctx->drm_dev)
2016 drm_helper_hpd_irq_event(ctx->drm_dev);
2017
Rahul Sharma64327cb2012-11-28 11:30:23 +05302018 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002019 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302020 return 0;
2021 }
2022
Joonyoung Shimab27af82012-04-23 19:35:51 +09002023 hdmi_poweroff(hdata);
2024
2025 return 0;
2026}
2027
2028static int hdmi_resume(struct device *dev)
2029{
2030 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2031 struct hdmi_context *hdata = ctx->ctx;
2032
Rahul Sharma64327cb2012-11-28 11:30:23 +05302033 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2034
Sean Paul77006a72013-01-16 10:17:20 -05002035 enable_irq(hdata->irq);
Rahul Sharma64327cb2012-11-28 11:30:23 +05302036
2037 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002038 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302039 return 0;
2040 }
2041
2042 hdmi_poweron(hdata);
2043
Joonyoung Shimab27af82012-04-23 19:35:51 +09002044 return 0;
2045}
2046#endif
2047
Rahul Sharma64327cb2012-11-28 11:30:23 +05302048#ifdef CONFIG_PM_RUNTIME
2049static int hdmi_runtime_suspend(struct device *dev)
2050{
2051 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2052 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302053
2054 hdmi_poweroff(hdata);
2055
2056 return 0;
2057}
2058
2059static int hdmi_runtime_resume(struct device *dev)
2060{
2061 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2062 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302063
2064 hdmi_poweron(hdata);
2065
2066 return 0;
2067}
2068#endif
2069
2070static const struct dev_pm_ops hdmi_pm_ops = {
2071 SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
2072 SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
2073};
Joonyoung Shimab27af82012-04-23 19:35:51 +09002074
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002075struct platform_driver hdmi_driver = {
2076 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002077 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002078 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302079 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002080 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09002081 .pm = &hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302082 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002083 },
2084};