blob: 9a98d902e75efd6b1c1b1901369d848edf032a97 [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
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053056
57/* AUI header info */
58#define HDMI_AUI_VERSION 0x01
59#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053060#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
61#define AVI_4_3_CENTER_RATIO 0x9
62#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053063
Rahul Sharma5a325072012-10-04 20:48:54 +053064enum hdmi_type {
65 HDMI_TYPE13,
66 HDMI_TYPE14,
67};
68
Joonyoung Shim590f4182012-03-16 18:47:14 +090069struct hdmi_resources {
70 struct clk *hdmi;
71 struct clk *sclk_hdmi;
72 struct clk *sclk_pixel;
73 struct clk *sclk_hdmiphy;
74 struct clk *hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053075 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090076 struct regulator_bulk_data *regul_bulk;
77 int regul_count;
78};
79
Sean Paul2f7e2ed2013-01-15 08:11:08 -050080struct hdmi_tg_regs {
81 u8 cmd[1];
82 u8 h_fsz[2];
83 u8 hact_st[2];
84 u8 hact_sz[2];
85 u8 v_fsz[2];
86 u8 vsync[2];
87 u8 vsync2[2];
88 u8 vact_st[2];
89 u8 vact_sz[2];
90 u8 field_chg[2];
91 u8 vact_st2[2];
92 u8 vact_st3[2];
93 u8 vact_st4[2];
94 u8 vsync_top_hdmi[2];
95 u8 vsync_bot_hdmi[2];
96 u8 field_top_hdmi[2];
97 u8 field_bot_hdmi[2];
98 u8 tg_3d[1];
99};
100
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900101struct hdmi_v13_core_regs {
102 u8 h_blank[2];
103 u8 v_blank[3];
104 u8 h_v_line[3];
105 u8 vsync_pol[1];
106 u8 int_pro_mode[1];
107 u8 v_blank_f[3];
108 u8 h_sync_gen[3];
109 u8 v_sync_gen1[3];
110 u8 v_sync_gen2[3];
111 u8 v_sync_gen3[3];
112};
113
114struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500115 u8 h_blank[2];
116 u8 v2_blank[2];
117 u8 v1_blank[2];
118 u8 v_line[2];
119 u8 h_line[2];
120 u8 hsync_pol[1];
121 u8 vsync_pol[1];
122 u8 int_pro_mode[1];
123 u8 v_blank_f0[2];
124 u8 v_blank_f1[2];
125 u8 h_sync_start[2];
126 u8 h_sync_end[2];
127 u8 v_sync_line_bef_2[2];
128 u8 v_sync_line_bef_1[2];
129 u8 v_sync_line_aft_2[2];
130 u8 v_sync_line_aft_1[2];
131 u8 v_sync_line_aft_pxl_2[2];
132 u8 v_sync_line_aft_pxl_1[2];
133 u8 v_blank_f2[2]; /* for 3D mode */
134 u8 v_blank_f3[2]; /* for 3D mode */
135 u8 v_blank_f4[2]; /* for 3D mode */
136 u8 v_blank_f5[2]; /* for 3D mode */
137 u8 v_sync_line_aft_3[2];
138 u8 v_sync_line_aft_4[2];
139 u8 v_sync_line_aft_5[2];
140 u8 v_sync_line_aft_6[2];
141 u8 v_sync_line_aft_pxl_3[2];
142 u8 v_sync_line_aft_pxl_4[2];
143 u8 v_sync_line_aft_pxl_5[2];
144 u8 v_sync_line_aft_pxl_6[2];
145 u8 vact_space_1[2];
146 u8 vact_space_2[2];
147 u8 vact_space_3[2];
148 u8 vact_space_4[2];
149 u8 vact_space_5[2];
150 u8 vact_space_6[2];
151};
152
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900153struct hdmi_v13_conf {
154 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500155 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900156};
157
158struct hdmi_v14_conf {
159 struct hdmi_v14_core_regs core;
160 struct hdmi_tg_regs tg;
161};
162
163struct hdmi_conf_regs {
164 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500165 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530166 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900167 union {
168 struct hdmi_v13_conf v13_conf;
169 struct hdmi_v14_conf v14_conf;
170 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500171};
172
Joonyoung Shim590f4182012-03-16 18:47:14 +0900173struct hdmi_context {
174 struct device *dev;
175 struct drm_device *drm_dev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900176 bool hpd;
177 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900178 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900179 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900180
Joonyoung Shim590f4182012-03-16 18:47:14 +0900181 void __iomem *regs;
Inki Dae1055b392012-10-19 17:37:35 +0900182 void *parent_ctx;
Sean Paul77006a72013-01-16 10:17:20 -0500183 int irq;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900184
185 struct i2c_client *ddc_port;
186 struct i2c_client *hdmiphy_port;
187
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900188 /* current hdmiphy conf regs */
189 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900190
191 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900192
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530193 int hpd_gpio;
Rahul Sharma5a325072012-10-04 20:48:54 +0530194
195 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900196};
197
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500198struct hdmiphy_config {
199 int pixel_clock;
200 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900201};
202
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900203/* list of phy config settings */
204static const struct hdmiphy_config hdmiphy_v13_configs[] = {
205 {
206 .pixel_clock = 27000000,
207 .conf = {
208 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
209 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
210 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
211 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
212 },
213 },
214 {
215 .pixel_clock = 27027000,
216 .conf = {
217 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
218 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
219 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
220 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
221 },
222 },
223 {
224 .pixel_clock = 74176000,
225 .conf = {
226 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
227 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
228 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
229 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
230 },
231 },
232 {
233 .pixel_clock = 74250000,
234 .conf = {
235 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
236 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
237 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
238 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
239 },
240 },
241 {
242 .pixel_clock = 148500000,
243 .conf = {
244 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
245 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
246 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
247 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
248 },
249 },
250};
251
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500252static const struct hdmiphy_config hdmiphy_v14_configs[] = {
253 {
254 .pixel_clock = 25200000,
255 .conf = {
256 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
257 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
258 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
259 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
260 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900261 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500262 {
263 .pixel_clock = 27000000,
264 .conf = {
265 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
266 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
267 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
268 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
269 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900270 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500271 {
272 .pixel_clock = 27027000,
273 .conf = {
274 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
275 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
276 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
277 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
278 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900279 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500280 {
281 .pixel_clock = 36000000,
282 .conf = {
283 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
284 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
285 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
286 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
287 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900288 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500289 {
290 .pixel_clock = 40000000,
291 .conf = {
292 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
293 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
294 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
295 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
296 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900297 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500298 {
299 .pixel_clock = 65000000,
300 .conf = {
301 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
302 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
303 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
304 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
305 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900306 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500307 {
Shirish Se1d883c2014-03-13 14:28:27 +0900308 .pixel_clock = 71000000,
309 .conf = {
310 0x01, 0x91, 0x1e, 0x15, 0x40, 0x3c, 0xce, 0x08,
311 0x04, 0x20, 0xb2, 0xd8, 0x45, 0xa0, 0xac, 0x80,
312 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
313 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
314 },
315 },
316 {
317 .pixel_clock = 73250000,
318 .conf = {
319 0x01, 0xd1, 0x1f, 0x15, 0x40, 0x18, 0xe9, 0x08,
320 0x02, 0xa0, 0xb7, 0xd8, 0x45, 0xa0, 0xac, 0x80,
321 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
322 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
323 },
324 },
325 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500326 .pixel_clock = 74176000,
327 .conf = {
328 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
329 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
330 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
331 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
332 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900333 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500334 {
335 .pixel_clock = 74250000,
336 .conf = {
337 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
338 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
339 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
340 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
341 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900342 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500343 {
344 .pixel_clock = 83500000,
345 .conf = {
346 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
347 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
348 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
349 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
350 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900351 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500352 {
Shirish Se1d883c2014-03-13 14:28:27 +0900353 .pixel_clock = 88750000,
354 .conf = {
355 0x01, 0x91, 0x25, 0x17, 0x40, 0x30, 0xfe, 0x08,
356 0x06, 0x20, 0xde, 0xd8, 0x45, 0xa0, 0xac, 0x80,
357 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
358 0x54, 0x8a, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
359 },
360 },
361 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500362 .pixel_clock = 106500000,
363 .conf = {
364 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
365 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
366 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
367 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
368 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900369 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500370 {
371 .pixel_clock = 108000000,
372 .conf = {
373 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
374 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
375 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
376 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
377 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900378 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500379 {
Shirish Se1d883c2014-03-13 14:28:27 +0900380 .pixel_clock = 115500000,
381 .conf = {
382 0x01, 0xd1, 0x30, 0x1a, 0x40, 0x40, 0x10, 0x04,
383 0x04, 0xa0, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
384 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
385 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
386 },
387 },
388 {
389 .pixel_clock = 119000000,
390 .conf = {
391 0x01, 0x91, 0x32, 0x14, 0x40, 0x60, 0xd8, 0x08,
392 0x06, 0x20, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
393 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
394 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
395 },
396 },
397 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500398 .pixel_clock = 146250000,
399 .conf = {
400 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
401 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
402 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
403 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
404 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900405 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500406 {
407 .pixel_clock = 148500000,
408 .conf = {
409 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
410 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
411 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
412 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
413 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900414 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900415};
416
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900417static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
418{
419 return readl(hdata->regs + reg_id);
420}
421
422static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
423 u32 reg_id, u8 value)
424{
425 writeb(value, hdata->regs + reg_id);
426}
427
428static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
429 u32 reg_id, u32 value, u32 mask)
430{
431 u32 old = readl(hdata->regs + reg_id);
432 value = (value & mask) | (old & ~mask);
433 writel(value, hdata->regs + reg_id);
434}
435
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900436static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900437{
438#define DUMPREG(reg_id) \
439 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
440 readl(hdata->regs + reg_id))
441 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
442 DUMPREG(HDMI_INTC_FLAG);
443 DUMPREG(HDMI_INTC_CON);
444 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900445 DUMPREG(HDMI_V13_PHY_RSTOUT);
446 DUMPREG(HDMI_V13_PHY_VPLL);
447 DUMPREG(HDMI_V13_PHY_CMU);
448 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900449
450 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
451 DUMPREG(HDMI_CON_0);
452 DUMPREG(HDMI_CON_1);
453 DUMPREG(HDMI_CON_2);
454 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900455 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900456 DUMPREG(HDMI_STATUS_EN);
457 DUMPREG(HDMI_HPD);
458 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900459 DUMPREG(HDMI_V13_HPD_GEN);
460 DUMPREG(HDMI_V13_DC_CONTROL);
461 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900462
463 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
464 DUMPREG(HDMI_H_BLANK_0);
465 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900466 DUMPREG(HDMI_V13_V_BLANK_0);
467 DUMPREG(HDMI_V13_V_BLANK_1);
468 DUMPREG(HDMI_V13_V_BLANK_2);
469 DUMPREG(HDMI_V13_H_V_LINE_0);
470 DUMPREG(HDMI_V13_H_V_LINE_1);
471 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900472 DUMPREG(HDMI_VSYNC_POL);
473 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900474 DUMPREG(HDMI_V13_V_BLANK_F_0);
475 DUMPREG(HDMI_V13_V_BLANK_F_1);
476 DUMPREG(HDMI_V13_V_BLANK_F_2);
477 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
478 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
479 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
480 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
481 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
482 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
483 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
484 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
485 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
486 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
487 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
488 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900489
490 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
491 DUMPREG(HDMI_TG_CMD);
492 DUMPREG(HDMI_TG_H_FSZ_L);
493 DUMPREG(HDMI_TG_H_FSZ_H);
494 DUMPREG(HDMI_TG_HACT_ST_L);
495 DUMPREG(HDMI_TG_HACT_ST_H);
496 DUMPREG(HDMI_TG_HACT_SZ_L);
497 DUMPREG(HDMI_TG_HACT_SZ_H);
498 DUMPREG(HDMI_TG_V_FSZ_L);
499 DUMPREG(HDMI_TG_V_FSZ_H);
500 DUMPREG(HDMI_TG_VSYNC_L);
501 DUMPREG(HDMI_TG_VSYNC_H);
502 DUMPREG(HDMI_TG_VSYNC2_L);
503 DUMPREG(HDMI_TG_VSYNC2_H);
504 DUMPREG(HDMI_TG_VACT_ST_L);
505 DUMPREG(HDMI_TG_VACT_ST_H);
506 DUMPREG(HDMI_TG_VACT_SZ_L);
507 DUMPREG(HDMI_TG_VACT_SZ_H);
508 DUMPREG(HDMI_TG_FIELD_CHG_L);
509 DUMPREG(HDMI_TG_FIELD_CHG_H);
510 DUMPREG(HDMI_TG_VACT_ST2_L);
511 DUMPREG(HDMI_TG_VACT_ST2_H);
512 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
513 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
514 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
515 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
516 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
517 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
518 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
519 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
520#undef DUMPREG
521}
522
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900523static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
524{
525 int i;
526
527#define DUMPREG(reg_id) \
528 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
529 readl(hdata->regs + reg_id))
530
531 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
532 DUMPREG(HDMI_INTC_CON);
533 DUMPREG(HDMI_INTC_FLAG);
534 DUMPREG(HDMI_HPD_STATUS);
535 DUMPREG(HDMI_INTC_CON_1);
536 DUMPREG(HDMI_INTC_FLAG_1);
537 DUMPREG(HDMI_PHY_STATUS_0);
538 DUMPREG(HDMI_PHY_STATUS_PLL);
539 DUMPREG(HDMI_PHY_CON_0);
540 DUMPREG(HDMI_PHY_RSTOUT);
541 DUMPREG(HDMI_PHY_VPLL);
542 DUMPREG(HDMI_PHY_CMU);
543 DUMPREG(HDMI_CORE_RSTOUT);
544
545 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
546 DUMPREG(HDMI_CON_0);
547 DUMPREG(HDMI_CON_1);
548 DUMPREG(HDMI_CON_2);
549 DUMPREG(HDMI_SYS_STATUS);
550 DUMPREG(HDMI_PHY_STATUS_0);
551 DUMPREG(HDMI_STATUS_EN);
552 DUMPREG(HDMI_HPD);
553 DUMPREG(HDMI_MODE_SEL);
554 DUMPREG(HDMI_ENC_EN);
555 DUMPREG(HDMI_DC_CONTROL);
556 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
557
558 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
559 DUMPREG(HDMI_H_BLANK_0);
560 DUMPREG(HDMI_H_BLANK_1);
561 DUMPREG(HDMI_V2_BLANK_0);
562 DUMPREG(HDMI_V2_BLANK_1);
563 DUMPREG(HDMI_V1_BLANK_0);
564 DUMPREG(HDMI_V1_BLANK_1);
565 DUMPREG(HDMI_V_LINE_0);
566 DUMPREG(HDMI_V_LINE_1);
567 DUMPREG(HDMI_H_LINE_0);
568 DUMPREG(HDMI_H_LINE_1);
569 DUMPREG(HDMI_HSYNC_POL);
570
571 DUMPREG(HDMI_VSYNC_POL);
572 DUMPREG(HDMI_INT_PRO_MODE);
573 DUMPREG(HDMI_V_BLANK_F0_0);
574 DUMPREG(HDMI_V_BLANK_F0_1);
575 DUMPREG(HDMI_V_BLANK_F1_0);
576 DUMPREG(HDMI_V_BLANK_F1_1);
577
578 DUMPREG(HDMI_H_SYNC_START_0);
579 DUMPREG(HDMI_H_SYNC_START_1);
580 DUMPREG(HDMI_H_SYNC_END_0);
581 DUMPREG(HDMI_H_SYNC_END_1);
582
583 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
584 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
585 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
586 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
587
588 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
589 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
590 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
591 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
592
593 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
594 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
595 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
596 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
597
598 DUMPREG(HDMI_V_BLANK_F2_0);
599 DUMPREG(HDMI_V_BLANK_F2_1);
600 DUMPREG(HDMI_V_BLANK_F3_0);
601 DUMPREG(HDMI_V_BLANK_F3_1);
602 DUMPREG(HDMI_V_BLANK_F4_0);
603 DUMPREG(HDMI_V_BLANK_F4_1);
604 DUMPREG(HDMI_V_BLANK_F5_0);
605 DUMPREG(HDMI_V_BLANK_F5_1);
606
607 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
608 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
609 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
610 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
611 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
612 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
613 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
614 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
615
616 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
617 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
618 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
619 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
620 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
621 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
622 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
623 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
624
625 DUMPREG(HDMI_VACT_SPACE_1_0);
626 DUMPREG(HDMI_VACT_SPACE_1_1);
627 DUMPREG(HDMI_VACT_SPACE_2_0);
628 DUMPREG(HDMI_VACT_SPACE_2_1);
629 DUMPREG(HDMI_VACT_SPACE_3_0);
630 DUMPREG(HDMI_VACT_SPACE_3_1);
631 DUMPREG(HDMI_VACT_SPACE_4_0);
632 DUMPREG(HDMI_VACT_SPACE_4_1);
633 DUMPREG(HDMI_VACT_SPACE_5_0);
634 DUMPREG(HDMI_VACT_SPACE_5_1);
635 DUMPREG(HDMI_VACT_SPACE_6_0);
636 DUMPREG(HDMI_VACT_SPACE_6_1);
637
638 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
639 DUMPREG(HDMI_TG_CMD);
640 DUMPREG(HDMI_TG_H_FSZ_L);
641 DUMPREG(HDMI_TG_H_FSZ_H);
642 DUMPREG(HDMI_TG_HACT_ST_L);
643 DUMPREG(HDMI_TG_HACT_ST_H);
644 DUMPREG(HDMI_TG_HACT_SZ_L);
645 DUMPREG(HDMI_TG_HACT_SZ_H);
646 DUMPREG(HDMI_TG_V_FSZ_L);
647 DUMPREG(HDMI_TG_V_FSZ_H);
648 DUMPREG(HDMI_TG_VSYNC_L);
649 DUMPREG(HDMI_TG_VSYNC_H);
650 DUMPREG(HDMI_TG_VSYNC2_L);
651 DUMPREG(HDMI_TG_VSYNC2_H);
652 DUMPREG(HDMI_TG_VACT_ST_L);
653 DUMPREG(HDMI_TG_VACT_ST_H);
654 DUMPREG(HDMI_TG_VACT_SZ_L);
655 DUMPREG(HDMI_TG_VACT_SZ_H);
656 DUMPREG(HDMI_TG_FIELD_CHG_L);
657 DUMPREG(HDMI_TG_FIELD_CHG_H);
658 DUMPREG(HDMI_TG_VACT_ST2_L);
659 DUMPREG(HDMI_TG_VACT_ST2_H);
660 DUMPREG(HDMI_TG_VACT_ST3_L);
661 DUMPREG(HDMI_TG_VACT_ST3_H);
662 DUMPREG(HDMI_TG_VACT_ST4_L);
663 DUMPREG(HDMI_TG_VACT_ST4_H);
664 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
665 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
666 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
667 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
668 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
669 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
670 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
671 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
672 DUMPREG(HDMI_TG_3D);
673
674 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
675 DUMPREG(HDMI_AVI_CON);
676 DUMPREG(HDMI_AVI_HEADER0);
677 DUMPREG(HDMI_AVI_HEADER1);
678 DUMPREG(HDMI_AVI_HEADER2);
679 DUMPREG(HDMI_AVI_CHECK_SUM);
680 DUMPREG(HDMI_VSI_CON);
681 DUMPREG(HDMI_VSI_HEADER0);
682 DUMPREG(HDMI_VSI_HEADER1);
683 DUMPREG(HDMI_VSI_HEADER2);
684 for (i = 0; i < 7; ++i)
685 DUMPREG(HDMI_VSI_DATA(i));
686
687#undef DUMPREG
688}
689
690static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
691{
Rahul Sharma5a325072012-10-04 20:48:54 +0530692 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900693 hdmi_v13_regs_dump(hdata, prefix);
694 else
695 hdmi_v14_regs_dump(hdata, prefix);
696}
697
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530698static u8 hdmi_chksum(struct hdmi_context *hdata,
699 u32 start, u8 len, u32 hdr_sum)
700{
701 int i;
702
703 /* hdr_sum : header0 + header1 + header2
704 * start : start address of packet byte1
705 * len : packet bytes - 1 */
706 for (i = 0; i < len; ++i)
707 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
708
709 /* return 2's complement of 8 bit hdr_sum */
710 return (u8)(~(hdr_sum & 0xff) + 1);
711}
712
713static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530714 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530715{
716 u32 hdr_sum;
717 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530718 u32 mod;
719 u32 vic;
720
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530721 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
722 if (hdata->dvi_mode) {
723 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
724 HDMI_VSI_CON_DO_NOT_TRANSMIT);
725 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
726 HDMI_AVI_CON_DO_NOT_TRANSMIT);
727 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
728 return;
729 }
730
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530731 switch (infoframe->any.type) {
732 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530733 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530734 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
735 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
736 infoframe->any.version);
737 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
738 hdr_sum = infoframe->any.type + infoframe->any.version +
739 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530740
741 /* Output format zero hardcoded ,RGB YBCR selection */
742 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
743 AVI_ACTIVE_FORMAT_VALID |
744 AVI_UNDERSCANNED_DISPLAY_VALID);
745
Shirish S46154152014-03-13 10:58:28 +0530746 /*
747 * Set the aspect ratio as per the mode, mentioned in
748 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
749 */
750 switch (hdata->mode_conf.aspect_ratio) {
751 case HDMI_PICTURE_ASPECT_4_3:
752 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
753 hdata->mode_conf.aspect_ratio |
754 AVI_4_3_CENTER_RATIO);
755 break;
756 case HDMI_PICTURE_ASPECT_16_9:
757 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
758 hdata->mode_conf.aspect_ratio |
759 AVI_16_9_CENTER_RATIO);
760 break;
761 case HDMI_PICTURE_ASPECT_NONE:
762 default:
763 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
764 hdata->mode_conf.aspect_ratio |
765 AVI_SAME_AS_PIC_ASPECT_RATIO);
766 break;
767 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530768
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900769 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530770 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
771
772 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530773 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530774 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
775 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
776 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530777 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530778 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530779 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
780 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
781 infoframe->any.version);
782 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
783 hdr_sum = infoframe->any.type + infoframe->any.version +
784 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530785 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530786 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530787 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
788 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
789 break;
790 default:
791 break;
792 }
793}
794
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900795static bool hdmi_is_connected(void *ctx)
796{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900797 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900798
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900799 return hdata->hpd;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900800}
801
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500802static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900803{
804 struct edid *raw_edid;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900805 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900806
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900807 if (!hdata->ddc_port)
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500808 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900809
810 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500811 if (!raw_edid)
812 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900813
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500814 hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
815 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
816 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
817 raw_edid->width_cm, raw_edid->height_cm);
818
819 return raw_edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900820}
821
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900822static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900823{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900824 const struct hdmiphy_config *confs;
825 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900826
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900827 if (hdata->type == HDMI_TYPE13) {
828 confs = hdmiphy_v13_configs;
829 count = ARRAY_SIZE(hdmiphy_v13_configs);
830 } else if (hdata->type == HDMI_TYPE14) {
831 confs = hdmiphy_v14_configs;
832 count = ARRAY_SIZE(hdmiphy_v14_configs);
833 } else
834 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900835
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900836 for (i = 0; i < count; i++)
837 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500838 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500839
840 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
841 return -EINVAL;
842}
843
Rahul Sharma16844fb2013-06-10 14:50:00 +0530844static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900845{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900846 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900847 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900848
Rahul Sharma16844fb2013-06-10 14:50:00 +0530849 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
850 mode->hdisplay, mode->vdisplay, mode->vrefresh,
851 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
852 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900853
Rahul Sharma16844fb2013-06-10 14:50:00 +0530854 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900855 if (ret < 0)
856 return ret;
857 return 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900858}
859
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900860static void hdmi_set_acr(u32 freq, u8 *acr)
861{
862 u32 n, cts;
863
864 switch (freq) {
865 case 32000:
866 n = 4096;
867 cts = 27000;
868 break;
869 case 44100:
870 n = 6272;
871 cts = 30000;
872 break;
873 case 88200:
874 n = 12544;
875 cts = 30000;
876 break;
877 case 176400:
878 n = 25088;
879 cts = 30000;
880 break;
881 case 48000:
882 n = 6144;
883 cts = 27000;
884 break;
885 case 96000:
886 n = 12288;
887 cts = 27000;
888 break;
889 case 192000:
890 n = 24576;
891 cts = 27000;
892 break;
893 default:
894 n = 0;
895 cts = 0;
896 break;
897 }
898
899 acr[1] = cts >> 16;
900 acr[2] = cts >> 8 & 0xff;
901 acr[3] = cts & 0xff;
902
903 acr[4] = n >> 16;
904 acr[5] = n >> 8 & 0xff;
905 acr[6] = n & 0xff;
906}
907
908static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
909{
910 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
911 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
912 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
913 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
914 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
915 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
916 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
917 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
918 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
919
Rahul Sharma5a325072012-10-04 20:48:54 +0530920 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900921 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
922 else
923 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
924}
925
926static void hdmi_audio_init(struct hdmi_context *hdata)
927{
928 u32 sample_rate, bits_per_sample, frame_size_code;
929 u32 data_num, bit_ch, sample_frq;
930 u32 val;
931 u8 acr[7];
932
933 sample_rate = 44100;
934 bits_per_sample = 16;
935 frame_size_code = 0;
936
937 switch (bits_per_sample) {
938 case 20:
939 data_num = 2;
940 bit_ch = 1;
941 break;
942 case 24:
943 data_num = 3;
944 bit_ch = 1;
945 break;
946 default:
947 data_num = 1;
948 bit_ch = 0;
949 break;
950 }
951
952 hdmi_set_acr(sample_rate, acr);
953 hdmi_reg_acr(hdata, acr);
954
955 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
956 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
957 | HDMI_I2S_MUX_ENABLE);
958
959 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
960 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
961
962 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
963
964 sample_frq = (sample_rate == 44100) ? 0 :
965 (sample_rate == 48000) ? 2 :
966 (sample_rate == 32000) ? 3 :
967 (sample_rate == 96000) ? 0xa : 0x0;
968
969 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
970 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
971
972 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
973 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
974
975 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
976 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
977 | HDMI_I2S_SEL_LRCK(6));
978 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
979 | HDMI_I2S_SEL_SDATA2(4));
980 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
981 | HDMI_I2S_SEL_SDATA2(2));
982 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
983
984 /* I2S_CON_1 & 2 */
985 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
986 | HDMI_I2S_L_CH_LOW_POL);
987 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
988 | HDMI_I2S_SET_BIT_CH(bit_ch)
989 | HDMI_I2S_SET_SDATA_BIT(data_num)
990 | HDMI_I2S_BASIC_FORMAT);
991
992 /* Configure register related to CUV information */
993 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
994 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
995 | HDMI_I2S_COPYRIGHT
996 | HDMI_I2S_LINEAR_PCM
997 | HDMI_I2S_CONSUMER_FORMAT);
998 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
999 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1000 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1001 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1002 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1003 HDMI_I2S_ORG_SMP_FREQ_44_1
1004 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1005 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1006
1007 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1008}
1009
1010static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1011{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001012 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001013 return;
1014
1015 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1016 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1017 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1018}
1019
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001020static void hdmi_conf_reset(struct hdmi_context *hdata)
1021{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001022 u32 reg;
1023
Rahul Sharma5a325072012-10-04 20:48:54 +05301024 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001025 reg = HDMI_V13_CORE_RSTOUT;
1026 else
1027 reg = HDMI_CORE_RSTOUT;
1028
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001029 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001030 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001031 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001032 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001033 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001034}
1035
1036static void hdmi_conf_init(struct hdmi_context *hdata)
1037{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301038 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301039
Sean Paul77006a72013-01-16 10:17:20 -05001040 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001041 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1042 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001043
1044 /* choose HDMI mode */
1045 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1046 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1047 /* disable bluescreen */
1048 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001049
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001050 if (hdata->dvi_mode) {
1051 /* choose DVI mode */
1052 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1053 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1054 hdmi_reg_writeb(hdata, HDMI_CON_2,
1055 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1056 }
1057
Rahul Sharma5a325072012-10-04 20:48:54 +05301058 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001059 /* choose bluescreen (fecal) color */
1060 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1061 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1062 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1063
1064 /* enable AVI packet every vsync, fixes purple line problem */
1065 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1066 /* force RGB, look to CEA-861-D, table 7 for more detail */
1067 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1068 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1069
1070 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1071 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1072 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1073 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301074 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1075 infoframe.any.version = HDMI_AVI_VERSION;
1076 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301077 hdmi_reg_infoframe(hdata, &infoframe);
1078
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301079 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1080 infoframe.any.version = HDMI_AUI_VERSION;
1081 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301082 hdmi_reg_infoframe(hdata, &infoframe);
1083
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001084 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001085 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1086 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001087}
1088
Rahul Sharma16844fb2013-06-10 14:50:00 +05301089static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001090{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001091 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1092 const struct hdmi_v13_core_regs *core =
1093 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001094 int tries;
1095
1096 /* setting core registers */
1097 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1098 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001099 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1100 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1101 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1102 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1103 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1104 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001105 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1106 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001107 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1108 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1109 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1110 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1111 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1112 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1113 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1114 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1115 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1116 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1117 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1118 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1119 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1120 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1121 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001122 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001123 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1124 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1125 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1126 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1127 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1128 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1129 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1130 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1131 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1132 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1133 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1134 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1135 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1136 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1137 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1138 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1139 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1140 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1141 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1142 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1143 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1144 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1145 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1146 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1147 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1148 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1149 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1150 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001151
1152 /* waiting for HDMIPHY's PLL to get to steady state */
1153 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001154 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001155 if (val & HDMI_PHY_STATUS_READY)
1156 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001157 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001158 }
1159 /* steady state not achieved */
1160 if (tries == 0) {
1161 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1162 hdmi_regs_dump(hdata, "timing apply");
1163 }
1164
Sean Paul0bfb1f82013-06-11 12:24:02 +05301165 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301166 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301167 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001168
1169 /* enable HDMI and timing generator */
1170 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1171 if (core->int_pro_mode[0])
1172 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1173 HDMI_FIELD_EN);
1174 else
1175 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1176}
1177
Rahul Sharma16844fb2013-06-10 14:50:00 +05301178static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001179{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001180 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1181 const struct hdmi_v14_core_regs *core =
1182 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001183 int tries;
1184
1185 /* setting core registers */
1186 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1187 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1188 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1189 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1190 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1191 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1192 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1193 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1194 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1195 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1196 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1197 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1198 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1199 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1200 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1201 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1202 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1203 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1204 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1205 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1206 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1207 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1208 core->v_sync_line_bef_2[0]);
1209 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1210 core->v_sync_line_bef_2[1]);
1211 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1212 core->v_sync_line_bef_1[0]);
1213 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1214 core->v_sync_line_bef_1[1]);
1215 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1216 core->v_sync_line_aft_2[0]);
1217 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1218 core->v_sync_line_aft_2[1]);
1219 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1220 core->v_sync_line_aft_1[0]);
1221 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1222 core->v_sync_line_aft_1[1]);
1223 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1224 core->v_sync_line_aft_pxl_2[0]);
1225 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1226 core->v_sync_line_aft_pxl_2[1]);
1227 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1228 core->v_sync_line_aft_pxl_1[0]);
1229 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1230 core->v_sync_line_aft_pxl_1[1]);
1231 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1232 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1233 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1234 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1235 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1236 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1237 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1238 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1239 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1240 core->v_sync_line_aft_3[0]);
1241 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1242 core->v_sync_line_aft_3[1]);
1243 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1244 core->v_sync_line_aft_4[0]);
1245 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1246 core->v_sync_line_aft_4[1]);
1247 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1248 core->v_sync_line_aft_5[0]);
1249 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1250 core->v_sync_line_aft_5[1]);
1251 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1252 core->v_sync_line_aft_6[0]);
1253 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1254 core->v_sync_line_aft_6[1]);
1255 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1256 core->v_sync_line_aft_pxl_3[0]);
1257 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1258 core->v_sync_line_aft_pxl_3[1]);
1259 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1260 core->v_sync_line_aft_pxl_4[0]);
1261 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1262 core->v_sync_line_aft_pxl_4[1]);
1263 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1264 core->v_sync_line_aft_pxl_5[0]);
1265 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1266 core->v_sync_line_aft_pxl_5[1]);
1267 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1268 core->v_sync_line_aft_pxl_6[0]);
1269 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1270 core->v_sync_line_aft_pxl_6[1]);
1271 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1272 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1273 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1274 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1275 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1276 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1277 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1278 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1279 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1280 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1281 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1282 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1283
1284 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001285 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1286 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1287 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1288 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1289 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1290 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1291 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1292 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1293 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1294 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1295 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1296 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1297 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1298 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1299 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1300 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1301 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1302 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1303 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1304 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1305 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1306 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1307 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1308 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1309 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1310 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1311 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1312 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1313 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1314 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1315 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1316 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1317 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001318
1319 /* waiting for HDMIPHY's PLL to get to steady state */
1320 for (tries = 100; tries; --tries) {
1321 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1322 if (val & HDMI_PHY_STATUS_READY)
1323 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001324 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001325 }
1326 /* steady state not achieved */
1327 if (tries == 0) {
1328 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1329 hdmi_regs_dump(hdata, "timing apply");
1330 }
1331
Sean Paul0bfb1f82013-06-11 12:24:02 +05301332 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301333 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301334 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001335
1336 /* enable HDMI and timing generator */
1337 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1338 if (core->int_pro_mode[0])
1339 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1340 HDMI_FIELD_EN);
1341 else
1342 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1343}
1344
Rahul Sharma16844fb2013-06-10 14:50:00 +05301345static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001346{
Rahul Sharma5a325072012-10-04 20:48:54 +05301347 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301348 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001349 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301350 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001351}
1352
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001353static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1354{
1355 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001356 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001357
Sean Paul0bfb1f82013-06-11 12:24:02 +05301358 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301359 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301360 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001361
1362 /* operation mode */
1363 buffer[0] = 0x1f;
1364 buffer[1] = 0x00;
1365
1366 if (hdata->hdmiphy_port)
1367 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1368
Rahul Sharma5a325072012-10-04 20:48:54 +05301369 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001370 reg = HDMI_V13_PHY_RSTOUT;
1371 else
1372 reg = HDMI_PHY_RSTOUT;
1373
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001374 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001375 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001376 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001377 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001378 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001379}
1380
Rahul Sharmaa5562252012-11-28 11:30:25 +05301381static void hdmiphy_poweron(struct hdmi_context *hdata)
1382{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301383 if (hdata->type == HDMI_TYPE14)
1384 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1385 HDMI_PHY_POWER_OFF_EN);
1386}
1387
1388static void hdmiphy_poweroff(struct hdmi_context *hdata)
1389{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301390 if (hdata->type == HDMI_TYPE14)
1391 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1392 HDMI_PHY_POWER_OFF_EN);
1393}
1394
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001395static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1396{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001397 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001398 u8 buffer[32];
1399 u8 operation[2];
1400 u8 read_buffer[32] = {0, };
1401 int ret;
1402 int i;
1403
1404 if (!hdata->hdmiphy_port) {
1405 DRM_ERROR("hdmiphy is not attached\n");
1406 return;
1407 }
1408
1409 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001410 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1411 if (i < 0) {
1412 DRM_ERROR("failed to find hdmiphy conf\n");
1413 return;
1414 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001415
Sachin Kamat5f46c332013-04-26 11:29:00 +05301416 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001417 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301418 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001419 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001420
1421 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001422 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1423 if (ret != 32) {
1424 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1425 return;
1426 }
1427
Sean Paul09760ea2013-01-14 17:03:20 -05001428 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001429
1430 /* operation mode */
1431 operation[0] = 0x1f;
1432 operation[1] = 0x80;
1433
1434 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1435 if (ret != 2) {
1436 DRM_ERROR("failed to enable hdmiphy\n");
1437 return;
1438 }
1439
1440 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1441 if (ret < 0) {
1442 DRM_ERROR("failed to read hdmiphy config\n");
1443 return;
1444 }
1445
1446 for (i = 0; i < ret; i++)
1447 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1448 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1449}
1450
1451static void hdmi_conf_apply(struct hdmi_context *hdata)
1452{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001453 hdmiphy_conf_reset(hdata);
1454 hdmiphy_conf_apply(hdata);
1455
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001456 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001457 hdmi_conf_reset(hdata);
1458 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001459 mutex_unlock(&hdata->hdmi_mutex);
1460
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001461 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001462
1463 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301464 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001465 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001466
1467 hdmi_regs_dump(hdata, "start");
1468}
1469
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001470static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1471{
1472 int i;
1473 BUG_ON(num_bytes > 4);
1474 for (i = 0; i < num_bytes; i++)
1475 reg_pair[i] = (value >> (8 * i)) & 0xff;
1476}
1477
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001478static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1479 struct drm_display_mode *m)
1480{
1481 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1482 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1483 unsigned int val;
1484
1485 hdata->mode_conf.cea_video_id =
1486 drm_match_cea_mode((struct drm_display_mode *)m);
1487 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301488 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001489
1490 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1491 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1492
1493 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1494 hdmi_set_reg(core->vsync_pol, 1, val);
1495
1496 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1497 hdmi_set_reg(core->int_pro_mode, 1, val);
1498
1499 val = (m->hsync_start - m->hdisplay - 2);
1500 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1501 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1502 hdmi_set_reg(core->h_sync_gen, 3, val);
1503
1504 /*
1505 * Quirk requirement for exynos HDMI IP design,
1506 * 2 pixels less than the actual calculation for hsync_start
1507 * and end.
1508 */
1509
1510 /* Following values & calculations differ for different type of modes */
1511 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1512 /* Interlaced Mode */
1513 val = ((m->vsync_end - m->vdisplay) / 2);
1514 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1515 hdmi_set_reg(core->v_sync_gen1, 3, val);
1516
1517 val = m->vtotal / 2;
1518 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1519 hdmi_set_reg(core->v_blank, 3, val);
1520
1521 val = (m->vtotal +
1522 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1523 val |= m->vtotal << 11;
1524 hdmi_set_reg(core->v_blank_f, 3, val);
1525
1526 val = ((m->vtotal / 2) + 7);
1527 val |= ((m->vtotal / 2) + 2) << 12;
1528 hdmi_set_reg(core->v_sync_gen2, 3, val);
1529
1530 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1531 val |= ((m->htotal / 2) +
1532 (m->hsync_start - m->hdisplay)) << 12;
1533 hdmi_set_reg(core->v_sync_gen3, 3, val);
1534
1535 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1536 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1537
1538 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1539 } else {
1540 /* Progressive Mode */
1541
1542 val = m->vtotal;
1543 val |= (m->vtotal - m->vdisplay) << 11;
1544 hdmi_set_reg(core->v_blank, 3, val);
1545
1546 hdmi_set_reg(core->v_blank_f, 3, 0);
1547
1548 val = (m->vsync_end - m->vdisplay);
1549 val |= ((m->vsync_start - m->vdisplay) << 12);
1550 hdmi_set_reg(core->v_sync_gen1, 3, val);
1551
1552 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1553 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1554 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1555 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1556 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1557 }
1558
1559 /* Timing generator registers */
1560 hdmi_set_reg(tg->cmd, 1, 0x0);
1561 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1562 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1563 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1564 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1565 hdmi_set_reg(tg->vsync, 2, 0x1);
1566 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1567 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1568 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1569 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1570 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1571 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1572 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1573}
1574
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001575static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1576 struct drm_display_mode *m)
1577{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001578 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1579 struct hdmi_v14_core_regs *core =
1580 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001581
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001582 hdata->mode_conf.cea_video_id =
1583 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001584 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301585 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001586
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001587 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1588 hdmi_set_reg(core->v_line, 2, m->vtotal);
1589 hdmi_set_reg(core->h_line, 2, m->htotal);
1590 hdmi_set_reg(core->hsync_pol, 1,
1591 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1592 hdmi_set_reg(core->vsync_pol, 1,
1593 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1594 hdmi_set_reg(core->int_pro_mode, 1,
1595 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1596
1597 /*
1598 * Quirk requirement for exynos 5 HDMI IP design,
1599 * 2 pixels less than the actual calculation for hsync_start
1600 * and end.
1601 */
1602
1603 /* Following values & calculations differ for different type of modes */
1604 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1605 /* Interlaced Mode */
1606 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1607 (m->vsync_end - m->vdisplay) / 2);
1608 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1609 (m->vsync_start - m->vdisplay) / 2);
1610 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1611 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301612 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001613 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1614 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1615 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1616 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1617 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1618 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1619 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1620 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1621 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301622 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1623 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1624 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1625 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001626 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1627 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1628 } else {
1629 /* Progressive Mode */
1630 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1631 m->vsync_end - m->vdisplay);
1632 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1633 m->vsync_start - m->vdisplay);
1634 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1635 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1636 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1637 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1638 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1639 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1640 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1641 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1642 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1643 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1644 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1645 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1646 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301647 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1648 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1649 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001650 }
1651
1652 /* Following values & calculations are same irrespective of mode type */
1653 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1654 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1655 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1656 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1657 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1658 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1659 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1660 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1661 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1662 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1663 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1664 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1665 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1666 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1667 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1668 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1669 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1670 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1671 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1672 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1673
1674 /* Timing generator registers */
1675 hdmi_set_reg(tg->cmd, 1, 0x0);
1676 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1677 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1678 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1679 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1680 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001681 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1682 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001683 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001684 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001685}
1686
Rahul Sharma16844fb2013-06-10 14:50:00 +05301687static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001688{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001689 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001690 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001691
YoungJun Chocbc4c332013-06-12 10:44:40 +09001692 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1693 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001694 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1695 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001696
Sachin Kamat5f46c332013-04-26 11:29:00 +05301697 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001698 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301699 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001700 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001701}
1702
Inki Dae1de425b2012-03-16 18:47:04 +09001703static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1704 unsigned int *height)
1705{
Inki Dae1de425b2012-03-16 18:47:04 +09001706 *width = MAX_WIDTH;
1707 *height = MAX_HEIGHT;
1708}
1709
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001710static void hdmi_commit(void *ctx)
1711{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001712 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001713
Shirish Sdda90122013-01-23 22:03:18 -05001714 mutex_lock(&hdata->hdmi_mutex);
1715 if (!hdata->powered) {
1716 mutex_unlock(&hdata->hdmi_mutex);
1717 return;
1718 }
1719 mutex_unlock(&hdata->hdmi_mutex);
1720
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001721 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001722}
1723
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001724static void hdmi_poweron(struct hdmi_context *hdata)
1725{
1726 struct hdmi_resources *res = &hdata->res;
1727
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001728 mutex_lock(&hdata->hdmi_mutex);
1729 if (hdata->powered) {
1730 mutex_unlock(&hdata->hdmi_mutex);
1731 return;
1732 }
1733
1734 hdata->powered = true;
1735
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001736 mutex_unlock(&hdata->hdmi_mutex);
1737
Seung-Woo Kimad079452013-06-05 14:34:38 +09001738 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1739 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1740
Sean Paul0bfb1f82013-06-11 12:24:02 +05301741 clk_prepare_enable(res->hdmiphy);
1742 clk_prepare_enable(res->hdmi);
1743 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301744
1745 hdmiphy_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001746}
1747
1748static void hdmi_poweroff(struct hdmi_context *hdata)
1749{
1750 struct hdmi_resources *res = &hdata->res;
1751
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001752 mutex_lock(&hdata->hdmi_mutex);
1753 if (!hdata->powered)
1754 goto out;
1755 mutex_unlock(&hdata->hdmi_mutex);
1756
1757 /*
1758 * The TV power domain needs any condition of hdmiphy to turn off and
1759 * its reset state seems to meet the condition.
1760 */
1761 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301762 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001763
Sean Paul0bfb1f82013-06-11 12:24:02 +05301764 clk_disable_unprepare(res->sclk_hdmi);
1765 clk_disable_unprepare(res->hdmi);
1766 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001767 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1768
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001769 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001770
1771 hdata->powered = false;
1772
1773out:
1774 mutex_unlock(&hdata->hdmi_mutex);
1775}
1776
1777static void hdmi_dpms(void *ctx, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001778{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001779 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001780
YoungJun Chocbc4c332013-06-12 10:44:40 +09001781 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001782
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001783 switch (mode) {
1784 case DRM_MODE_DPMS_ON:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301785 if (pm_runtime_suspended(hdata->dev))
1786 pm_runtime_get_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001787 break;
1788 case DRM_MODE_DPMS_STANDBY:
1789 case DRM_MODE_DPMS_SUSPEND:
1790 case DRM_MODE_DPMS_OFF:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301791 if (!pm_runtime_suspended(hdata->dev))
1792 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001793 break;
1794 default:
1795 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1796 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001797 }
1798}
1799
Joonyoung Shim578b6062012-04-05 20:49:26 +09001800static struct exynos_hdmi_ops hdmi_ops = {
1801 /* display */
1802 .is_connected = hdmi_is_connected,
1803 .get_edid = hdmi_get_edid,
Rahul Sharma16844fb2013-06-10 14:50:00 +05301804 .check_mode = hdmi_check_mode,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001805
1806 /* manager */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001807 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09001808 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001809 .commit = hdmi_commit,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001810 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001811};
1812
Sean Paul77006a72013-01-16 10:17:20 -05001813static irqreturn_t hdmi_irq_thread(int irq, void *arg)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001814{
1815 struct exynos_drm_hdmi_context *ctx = arg;
1816 struct hdmi_context *hdata = ctx->ctx;
1817
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001818 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301819 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001820 mutex_unlock(&hdata->hdmi_mutex);
1821
1822 if (ctx->drm_dev)
1823 drm_helper_hpd_irq_event(ctx->drm_dev);
1824
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001825 return IRQ_HANDLED;
1826}
1827
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001828static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001829{
1830 struct device *dev = hdata->dev;
1831 struct hdmi_resources *res = &hdata->res;
1832 static char *supply[] = {
1833 "hdmi-en",
1834 "vdd",
1835 "vdd_osc",
1836 "vdd_pll",
1837 };
1838 int i, ret;
1839
1840 DRM_DEBUG_KMS("HDMI resource init\n");
1841
Sachin Kamatadc837a2012-08-31 15:50:47 +05301842 memset(res, 0, sizeof(*res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001843
1844 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301845 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301846 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001847 DRM_ERROR("failed to get clock 'hdmi'\n");
1848 goto fail;
1849 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301850 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301851 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001852 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1853 goto fail;
1854 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301855 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301856 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001857 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1858 goto fail;
1859 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301860 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301861 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001862 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1863 goto fail;
1864 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301865 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301866 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001867 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1868 goto fail;
1869 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301870 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1871 if (IS_ERR(res->mout_hdmi)) {
1872 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1873 goto fail;
1874 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001875
Rahul Sharma59956d32013-06-11 12:24:03 +05301876 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001877
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301878 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301879 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001880 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001881 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001882 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1883 res->regul_bulk[i].supply = supply[i];
1884 res->regul_bulk[i].consumer = NULL;
1885 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301886 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001887 if (ret) {
1888 DRM_ERROR("failed to get regulators\n");
1889 goto fail;
1890 }
1891 res->regul_count = ARRAY_SIZE(supply);
1892
1893 return 0;
1894fail:
1895 DRM_ERROR("HDMI resource init - failed\n");
1896 return -ENODEV;
1897}
1898
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001899static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
1900
1901void hdmi_attach_ddc_client(struct i2c_client *ddc)
1902{
1903 if (ddc)
1904 hdmi_ddc = ddc;
1905}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001906
1907void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
1908{
1909 if (hdmiphy)
1910 hdmi_hdmiphy = hdmiphy;
1911}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001912
Rahul Sharma22c4f422012-10-04 20:48:55 +05301913static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1914 (struct device *dev)
1915{
1916 struct device_node *np = dev->of_node;
1917 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301918 u32 value;
1919
1920 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001921 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05301922 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301923
1924 if (!of_find_property(np, "hpd-gpio", &value)) {
1925 DRM_ERROR("no hpd gpio property found\n");
1926 goto err_data;
1927 }
1928
Rahul Sharma5f916e22013-06-11 19:41:29 +05301929 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05301930
1931 return pd;
1932
1933err_data:
1934 return NULL;
1935}
Rahul Sharma22c4f422012-10-04 20:48:55 +05301936
Rahul Sharma22c4f422012-10-04 20:48:55 +05301937static struct of_device_id hdmi_match_types[] = {
1938 {
1939 .compatible = "samsung,exynos5-hdmi",
1940 .data = (void *)HDMI_TYPE14,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301941 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301942 .compatible = "samsung,exynos4212-hdmi",
1943 .data = (void *)HDMI_TYPE14,
1944 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301945 /* end node */
1946 }
1947};
1948
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001949static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001950{
1951 struct device *dev = &pdev->dev;
1952 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1953 struct hdmi_context *hdata;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301954 struct s5p_hdmi_platform_data *pdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001955 struct resource *res;
Sachin Kamat88c49812013-08-28 10:47:57 +05301956 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001957 int ret;
1958
Sachin Kamat88c49812013-08-28 10:47:57 +05301959 if (!dev->of_node)
1960 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301961
Sachin Kamat88c49812013-08-28 10:47:57 +05301962 pdata = drm_hdmi_dt_parse_pdata(dev);
1963 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001964 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001965
Sachin Kamat88c49812013-08-28 10:47:57 +05301966 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001967 if (!drm_hdmi_ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001968 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001969
Sachin Kamat88c49812013-08-28 10:47:57 +05301970 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001971 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001972 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001973
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001974 mutex_init(&hdata->hdmi_mutex);
1975
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001976 drm_hdmi_ctx->ctx = (void *)hdata;
1977 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1978
1979 platform_set_drvdata(pdev, drm_hdmi_ctx);
1980
Sachin Kamat88c49812013-08-28 10:47:57 +05301981 match = of_match_node(hdmi_match_types, dev->of_node);
1982 if (!match)
1983 return -ENODEV;
1984 hdata->type = (enum hdmi_type)match->data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301985
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301986 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001987 hdata->dev = dev;
1988
1989 ret = hdmi_resources_init(hdata);
1990 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301991 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301992 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001993 }
1994
1995 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001996 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001997 if (IS_ERR(hdata->regs))
1998 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001999
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002000 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302001 if (ret) {
2002 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302003 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302004 }
2005
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002006 /* DDC i2c driver */
2007 if (i2c_add_driver(&ddc_driver)) {
2008 DRM_ERROR("failed to register ddc i2c driver\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302009 return -ENOENT;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002010 }
2011
2012 hdata->ddc_port = hdmi_ddc;
2013
2014 /* hdmiphy i2c driver */
2015 if (i2c_add_driver(&hdmiphy_driver)) {
2016 DRM_ERROR("failed to register hdmiphy i2c driver\n");
2017 ret = -ENOENT;
2018 goto err_ddc;
2019 }
2020
2021 hdata->hdmiphy_port = hdmi_hdmiphy;
2022
Sean Paul77006a72013-01-16 10:17:20 -05002023 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2024 if (hdata->irq < 0) {
2025 DRM_ERROR("failed to get GPIO irq\n");
2026 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002027 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002028 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002029
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302030 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2031
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002032 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002033 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002034 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paul77006a72013-01-16 10:17:20 -05002035 "hdmi", drm_hdmi_ctx);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002036 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002037 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002038 goto err_hdmiphy;
2039 }
2040
Rahul Sharma768c3052012-10-04 20:48:56 +05302041 /* Attach HDMI Driver to common hdmi. */
2042 exynos_hdmi_drv_attach(drm_hdmi_ctx);
2043
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002044 /* register specific callbacks to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09002045 exynos_hdmi_ops_register(&hdmi_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002046
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002047 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002048
2049 return 0;
2050
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002051err_hdmiphy:
2052 i2c_del_driver(&hdmiphy_driver);
2053err_ddc:
2054 i2c_del_driver(&ddc_driver);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002055 return ret;
2056}
2057
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002058static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002059{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002060 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002061
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002062 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002063
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002064 /* hdmiphy i2c driver */
2065 i2c_del_driver(&hdmiphy_driver);
2066 /* DDC i2c driver */
2067 i2c_del_driver(&ddc_driver);
2068
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002069 return 0;
2070}
2071
Joonyoung Shimab27af82012-04-23 19:35:51 +09002072#ifdef CONFIG_PM_SLEEP
2073static int hdmi_suspend(struct device *dev)
2074{
2075 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2076 struct hdmi_context *hdata = ctx->ctx;
2077
Sean Paul77006a72013-01-16 10:17:20 -05002078 disable_irq(hdata->irq);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002079
2080 hdata->hpd = false;
2081 if (ctx->drm_dev)
2082 drm_helper_hpd_irq_event(ctx->drm_dev);
2083
Rahul Sharma64327cb2012-11-28 11:30:23 +05302084 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002085 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302086 return 0;
2087 }
2088
Joonyoung Shimab27af82012-04-23 19:35:51 +09002089 hdmi_poweroff(hdata);
2090
2091 return 0;
2092}
2093
2094static int hdmi_resume(struct device *dev)
2095{
2096 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2097 struct hdmi_context *hdata = ctx->ctx;
2098
Rahul Sharma64327cb2012-11-28 11:30:23 +05302099 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2100
Sean Paul77006a72013-01-16 10:17:20 -05002101 enable_irq(hdata->irq);
Rahul Sharma64327cb2012-11-28 11:30:23 +05302102
2103 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002104 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302105 return 0;
2106 }
2107
2108 hdmi_poweron(hdata);
2109
Joonyoung Shimab27af82012-04-23 19:35:51 +09002110 return 0;
2111}
2112#endif
2113
Rahul Sharma64327cb2012-11-28 11:30:23 +05302114#ifdef CONFIG_PM_RUNTIME
2115static int hdmi_runtime_suspend(struct device *dev)
2116{
2117 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2118 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302119
2120 hdmi_poweroff(hdata);
2121
2122 return 0;
2123}
2124
2125static int hdmi_runtime_resume(struct device *dev)
2126{
2127 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2128 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302129
2130 hdmi_poweron(hdata);
2131
2132 return 0;
2133}
2134#endif
2135
2136static const struct dev_pm_ops hdmi_pm_ops = {
2137 SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
2138 SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
2139};
Joonyoung Shimab27af82012-04-23 19:35:51 +09002140
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002141struct platform_driver hdmi_driver = {
2142 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002143 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002144 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302145 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002146 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09002147 .pm = &hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302148 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002149 },
2150};