blob: 30eb54775ae3fc48cc56639cfb2015dc5c31c672 [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
Sean Paul45517892014-01-30 16:19:05 -0500795static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
796{
797 struct hdmi_context *hdata = ctx;
798
799 hdata->drm_dev = drm_dev;
800
801 return 0;
802}
803
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900804static bool hdmi_is_connected(void *ctx)
805{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900806 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900807
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900808 return hdata->hpd;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900809}
810
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500811static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900812{
813 struct edid *raw_edid;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900814 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900815
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900816 if (!hdata->ddc_port)
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500817 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900818
819 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500820 if (!raw_edid)
821 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900822
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500823 hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
824 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
825 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
826 raw_edid->width_cm, raw_edid->height_cm);
827
828 return raw_edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900829}
830
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900831static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900832{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900833 const struct hdmiphy_config *confs;
834 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900835
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900836 if (hdata->type == HDMI_TYPE13) {
837 confs = hdmiphy_v13_configs;
838 count = ARRAY_SIZE(hdmiphy_v13_configs);
839 } else if (hdata->type == HDMI_TYPE14) {
840 confs = hdmiphy_v14_configs;
841 count = ARRAY_SIZE(hdmiphy_v14_configs);
842 } else
843 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900844
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900845 for (i = 0; i < count; i++)
846 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500847 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500848
849 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
850 return -EINVAL;
851}
852
Rahul Sharma16844fb2013-06-10 14:50:00 +0530853static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900854{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900855 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900856 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900857
Rahul Sharma16844fb2013-06-10 14:50:00 +0530858 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
859 mode->hdisplay, mode->vdisplay, mode->vrefresh,
860 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
861 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900862
Rahul Sharma16844fb2013-06-10 14:50:00 +0530863 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900864 if (ret < 0)
865 return ret;
866 return 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900867}
868
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900869static void hdmi_set_acr(u32 freq, u8 *acr)
870{
871 u32 n, cts;
872
873 switch (freq) {
874 case 32000:
875 n = 4096;
876 cts = 27000;
877 break;
878 case 44100:
879 n = 6272;
880 cts = 30000;
881 break;
882 case 88200:
883 n = 12544;
884 cts = 30000;
885 break;
886 case 176400:
887 n = 25088;
888 cts = 30000;
889 break;
890 case 48000:
891 n = 6144;
892 cts = 27000;
893 break;
894 case 96000:
895 n = 12288;
896 cts = 27000;
897 break;
898 case 192000:
899 n = 24576;
900 cts = 27000;
901 break;
902 default:
903 n = 0;
904 cts = 0;
905 break;
906 }
907
908 acr[1] = cts >> 16;
909 acr[2] = cts >> 8 & 0xff;
910 acr[3] = cts & 0xff;
911
912 acr[4] = n >> 16;
913 acr[5] = n >> 8 & 0xff;
914 acr[6] = n & 0xff;
915}
916
917static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
918{
919 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
920 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
921 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
922 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
923 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
924 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
925 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
926 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
927 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
928
Rahul Sharma5a325072012-10-04 20:48:54 +0530929 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900930 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
931 else
932 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
933}
934
935static void hdmi_audio_init(struct hdmi_context *hdata)
936{
937 u32 sample_rate, bits_per_sample, frame_size_code;
938 u32 data_num, bit_ch, sample_frq;
939 u32 val;
940 u8 acr[7];
941
942 sample_rate = 44100;
943 bits_per_sample = 16;
944 frame_size_code = 0;
945
946 switch (bits_per_sample) {
947 case 20:
948 data_num = 2;
949 bit_ch = 1;
950 break;
951 case 24:
952 data_num = 3;
953 bit_ch = 1;
954 break;
955 default:
956 data_num = 1;
957 bit_ch = 0;
958 break;
959 }
960
961 hdmi_set_acr(sample_rate, acr);
962 hdmi_reg_acr(hdata, acr);
963
964 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
965 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
966 | HDMI_I2S_MUX_ENABLE);
967
968 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
969 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
970
971 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
972
973 sample_frq = (sample_rate == 44100) ? 0 :
974 (sample_rate == 48000) ? 2 :
975 (sample_rate == 32000) ? 3 :
976 (sample_rate == 96000) ? 0xa : 0x0;
977
978 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
979 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
980
981 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
982 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
983
984 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
985 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
986 | HDMI_I2S_SEL_LRCK(6));
987 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
988 | HDMI_I2S_SEL_SDATA2(4));
989 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
990 | HDMI_I2S_SEL_SDATA2(2));
991 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
992
993 /* I2S_CON_1 & 2 */
994 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
995 | HDMI_I2S_L_CH_LOW_POL);
996 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
997 | HDMI_I2S_SET_BIT_CH(bit_ch)
998 | HDMI_I2S_SET_SDATA_BIT(data_num)
999 | HDMI_I2S_BASIC_FORMAT);
1000
1001 /* Configure register related to CUV information */
1002 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1003 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1004 | HDMI_I2S_COPYRIGHT
1005 | HDMI_I2S_LINEAR_PCM
1006 | HDMI_I2S_CONSUMER_FORMAT);
1007 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1008 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1009 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1010 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1011 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1012 HDMI_I2S_ORG_SMP_FREQ_44_1
1013 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1014 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1015
1016 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1017}
1018
1019static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1020{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001021 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001022 return;
1023
1024 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1025 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1026 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1027}
1028
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001029static void hdmi_conf_reset(struct hdmi_context *hdata)
1030{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001031 u32 reg;
1032
Rahul Sharma5a325072012-10-04 20:48:54 +05301033 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001034 reg = HDMI_V13_CORE_RSTOUT;
1035 else
1036 reg = HDMI_CORE_RSTOUT;
1037
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001038 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001039 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001040 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001041 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001042 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001043}
1044
1045static void hdmi_conf_init(struct hdmi_context *hdata)
1046{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301047 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301048
Sean Paul77006a72013-01-16 10:17:20 -05001049 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001050 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1051 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001052
1053 /* choose HDMI mode */
1054 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1055 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1056 /* disable bluescreen */
1057 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001058
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001059 if (hdata->dvi_mode) {
1060 /* choose DVI mode */
1061 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1062 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1063 hdmi_reg_writeb(hdata, HDMI_CON_2,
1064 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1065 }
1066
Rahul Sharma5a325072012-10-04 20:48:54 +05301067 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001068 /* choose bluescreen (fecal) color */
1069 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1070 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1071 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1072
1073 /* enable AVI packet every vsync, fixes purple line problem */
1074 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1075 /* force RGB, look to CEA-861-D, table 7 for more detail */
1076 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1077 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1078
1079 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1080 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1081 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1082 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301083 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1084 infoframe.any.version = HDMI_AVI_VERSION;
1085 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301086 hdmi_reg_infoframe(hdata, &infoframe);
1087
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301088 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1089 infoframe.any.version = HDMI_AUI_VERSION;
1090 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301091 hdmi_reg_infoframe(hdata, &infoframe);
1092
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001093 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001094 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1095 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001096}
1097
Rahul Sharma16844fb2013-06-10 14:50:00 +05301098static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001099{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001100 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1101 const struct hdmi_v13_core_regs *core =
1102 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001103 int tries;
1104
1105 /* setting core registers */
1106 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1107 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001108 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1109 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1110 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1111 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1112 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1113 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001114 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1115 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001116 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1117 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1118 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1119 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1120 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1121 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1122 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1123 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1124 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1125 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1126 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1127 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1128 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1129 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1130 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001131 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001132 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1133 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1134 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1135 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1136 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1137 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1138 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1139 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1140 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1141 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1142 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1143 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1144 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1145 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1146 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1147 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1148 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1149 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1150 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1151 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1152 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1153 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1154 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1155 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1156 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1157 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1158 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1159 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001160
1161 /* waiting for HDMIPHY's PLL to get to steady state */
1162 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001163 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001164 if (val & HDMI_PHY_STATUS_READY)
1165 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001166 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001167 }
1168 /* steady state not achieved */
1169 if (tries == 0) {
1170 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1171 hdmi_regs_dump(hdata, "timing apply");
1172 }
1173
Sean Paul0bfb1f82013-06-11 12:24:02 +05301174 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301175 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301176 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001177
1178 /* enable HDMI and timing generator */
1179 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1180 if (core->int_pro_mode[0])
1181 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1182 HDMI_FIELD_EN);
1183 else
1184 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1185}
1186
Rahul Sharma16844fb2013-06-10 14:50:00 +05301187static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001188{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001189 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1190 const struct hdmi_v14_core_regs *core =
1191 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001192 int tries;
1193
1194 /* setting core registers */
1195 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1196 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1197 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1198 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1199 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1200 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1201 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1202 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1203 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1204 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1205 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1206 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1207 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1208 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1209 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1210 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1211 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1212 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1213 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1214 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1215 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1216 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1217 core->v_sync_line_bef_2[0]);
1218 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1219 core->v_sync_line_bef_2[1]);
1220 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1221 core->v_sync_line_bef_1[0]);
1222 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1223 core->v_sync_line_bef_1[1]);
1224 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1225 core->v_sync_line_aft_2[0]);
1226 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1227 core->v_sync_line_aft_2[1]);
1228 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1229 core->v_sync_line_aft_1[0]);
1230 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1231 core->v_sync_line_aft_1[1]);
1232 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1233 core->v_sync_line_aft_pxl_2[0]);
1234 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1235 core->v_sync_line_aft_pxl_2[1]);
1236 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1237 core->v_sync_line_aft_pxl_1[0]);
1238 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1239 core->v_sync_line_aft_pxl_1[1]);
1240 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1241 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1242 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1243 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1244 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1245 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1246 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1247 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1248 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1249 core->v_sync_line_aft_3[0]);
1250 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1251 core->v_sync_line_aft_3[1]);
1252 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1253 core->v_sync_line_aft_4[0]);
1254 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1255 core->v_sync_line_aft_4[1]);
1256 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1257 core->v_sync_line_aft_5[0]);
1258 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1259 core->v_sync_line_aft_5[1]);
1260 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1261 core->v_sync_line_aft_6[0]);
1262 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1263 core->v_sync_line_aft_6[1]);
1264 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1265 core->v_sync_line_aft_pxl_3[0]);
1266 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1267 core->v_sync_line_aft_pxl_3[1]);
1268 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1269 core->v_sync_line_aft_pxl_4[0]);
1270 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1271 core->v_sync_line_aft_pxl_4[1]);
1272 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1273 core->v_sync_line_aft_pxl_5[0]);
1274 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1275 core->v_sync_line_aft_pxl_5[1]);
1276 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1277 core->v_sync_line_aft_pxl_6[0]);
1278 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1279 core->v_sync_line_aft_pxl_6[1]);
1280 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1281 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1282 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1283 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1284 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1285 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1286 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1287 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1288 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1289 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1290 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1291 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1292
1293 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001294 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1295 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1296 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1297 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1298 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1299 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1300 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1301 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1302 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1303 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1304 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1305 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1306 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1307 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1308 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1309 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1310 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1311 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1312 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1313 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1314 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1315 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1316 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1317 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1318 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1319 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1320 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1321 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1322 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1323 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1324 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1325 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1326 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001327
1328 /* waiting for HDMIPHY's PLL to get to steady state */
1329 for (tries = 100; tries; --tries) {
1330 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1331 if (val & HDMI_PHY_STATUS_READY)
1332 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001333 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001334 }
1335 /* steady state not achieved */
1336 if (tries == 0) {
1337 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1338 hdmi_regs_dump(hdata, "timing apply");
1339 }
1340
Sean Paul0bfb1f82013-06-11 12:24:02 +05301341 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301342 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301343 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001344
1345 /* enable HDMI and timing generator */
1346 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1347 if (core->int_pro_mode[0])
1348 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1349 HDMI_FIELD_EN);
1350 else
1351 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1352}
1353
Rahul Sharma16844fb2013-06-10 14:50:00 +05301354static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001355{
Rahul Sharma5a325072012-10-04 20:48:54 +05301356 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301357 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001358 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301359 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001360}
1361
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001362static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1363{
1364 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001365 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001366
Sean Paul0bfb1f82013-06-11 12:24:02 +05301367 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301368 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301369 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001370
1371 /* operation mode */
1372 buffer[0] = 0x1f;
1373 buffer[1] = 0x00;
1374
1375 if (hdata->hdmiphy_port)
1376 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1377
Rahul Sharma5a325072012-10-04 20:48:54 +05301378 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001379 reg = HDMI_V13_PHY_RSTOUT;
1380 else
1381 reg = HDMI_PHY_RSTOUT;
1382
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001383 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001384 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001385 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001386 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001387 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001388}
1389
Rahul Sharmaa5562252012-11-28 11:30:25 +05301390static void hdmiphy_poweron(struct hdmi_context *hdata)
1391{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301392 if (hdata->type == HDMI_TYPE14)
1393 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1394 HDMI_PHY_POWER_OFF_EN);
1395}
1396
1397static void hdmiphy_poweroff(struct hdmi_context *hdata)
1398{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301399 if (hdata->type == HDMI_TYPE14)
1400 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1401 HDMI_PHY_POWER_OFF_EN);
1402}
1403
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001404static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1405{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001406 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001407 u8 buffer[32];
1408 u8 operation[2];
1409 u8 read_buffer[32] = {0, };
1410 int ret;
1411 int i;
1412
1413 if (!hdata->hdmiphy_port) {
1414 DRM_ERROR("hdmiphy is not attached\n");
1415 return;
1416 }
1417
1418 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001419 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1420 if (i < 0) {
1421 DRM_ERROR("failed to find hdmiphy conf\n");
1422 return;
1423 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001424
Sachin Kamat5f46c332013-04-26 11:29:00 +05301425 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001426 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301427 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001428 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001429
1430 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001431 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1432 if (ret != 32) {
1433 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1434 return;
1435 }
1436
Sean Paul09760ea2013-01-14 17:03:20 -05001437 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001438
1439 /* operation mode */
1440 operation[0] = 0x1f;
1441 operation[1] = 0x80;
1442
1443 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1444 if (ret != 2) {
1445 DRM_ERROR("failed to enable hdmiphy\n");
1446 return;
1447 }
1448
1449 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1450 if (ret < 0) {
1451 DRM_ERROR("failed to read hdmiphy config\n");
1452 return;
1453 }
1454
1455 for (i = 0; i < ret; i++)
1456 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1457 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1458}
1459
1460static void hdmi_conf_apply(struct hdmi_context *hdata)
1461{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001462 hdmiphy_conf_reset(hdata);
1463 hdmiphy_conf_apply(hdata);
1464
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001465 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001466 hdmi_conf_reset(hdata);
1467 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001468 mutex_unlock(&hdata->hdmi_mutex);
1469
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001470 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001471
1472 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301473 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001474 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001475
1476 hdmi_regs_dump(hdata, "start");
1477}
1478
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001479static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1480{
1481 int i;
1482 BUG_ON(num_bytes > 4);
1483 for (i = 0; i < num_bytes; i++)
1484 reg_pair[i] = (value >> (8 * i)) & 0xff;
1485}
1486
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001487static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1488 struct drm_display_mode *m)
1489{
1490 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1491 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1492 unsigned int val;
1493
1494 hdata->mode_conf.cea_video_id =
1495 drm_match_cea_mode((struct drm_display_mode *)m);
1496 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301497 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001498
1499 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1500 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1501
1502 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1503 hdmi_set_reg(core->vsync_pol, 1, val);
1504
1505 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1506 hdmi_set_reg(core->int_pro_mode, 1, val);
1507
1508 val = (m->hsync_start - m->hdisplay - 2);
1509 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1510 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1511 hdmi_set_reg(core->h_sync_gen, 3, val);
1512
1513 /*
1514 * Quirk requirement for exynos HDMI IP design,
1515 * 2 pixels less than the actual calculation for hsync_start
1516 * and end.
1517 */
1518
1519 /* Following values & calculations differ for different type of modes */
1520 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1521 /* Interlaced Mode */
1522 val = ((m->vsync_end - m->vdisplay) / 2);
1523 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1524 hdmi_set_reg(core->v_sync_gen1, 3, val);
1525
1526 val = m->vtotal / 2;
1527 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1528 hdmi_set_reg(core->v_blank, 3, val);
1529
1530 val = (m->vtotal +
1531 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1532 val |= m->vtotal << 11;
1533 hdmi_set_reg(core->v_blank_f, 3, val);
1534
1535 val = ((m->vtotal / 2) + 7);
1536 val |= ((m->vtotal / 2) + 2) << 12;
1537 hdmi_set_reg(core->v_sync_gen2, 3, val);
1538
1539 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1540 val |= ((m->htotal / 2) +
1541 (m->hsync_start - m->hdisplay)) << 12;
1542 hdmi_set_reg(core->v_sync_gen3, 3, val);
1543
1544 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1545 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1546
1547 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1548 } else {
1549 /* Progressive Mode */
1550
1551 val = m->vtotal;
1552 val |= (m->vtotal - m->vdisplay) << 11;
1553 hdmi_set_reg(core->v_blank, 3, val);
1554
1555 hdmi_set_reg(core->v_blank_f, 3, 0);
1556
1557 val = (m->vsync_end - m->vdisplay);
1558 val |= ((m->vsync_start - m->vdisplay) << 12);
1559 hdmi_set_reg(core->v_sync_gen1, 3, val);
1560
1561 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1562 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1563 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1564 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1565 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1566 }
1567
1568 /* Timing generator registers */
1569 hdmi_set_reg(tg->cmd, 1, 0x0);
1570 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1571 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1572 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1573 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1574 hdmi_set_reg(tg->vsync, 2, 0x1);
1575 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1576 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1577 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1578 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1579 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1580 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1581 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1582}
1583
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001584static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1585 struct drm_display_mode *m)
1586{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001587 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1588 struct hdmi_v14_core_regs *core =
1589 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001590
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001591 hdata->mode_conf.cea_video_id =
1592 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001593 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301594 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001595
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001596 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1597 hdmi_set_reg(core->v_line, 2, m->vtotal);
1598 hdmi_set_reg(core->h_line, 2, m->htotal);
1599 hdmi_set_reg(core->hsync_pol, 1,
1600 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1601 hdmi_set_reg(core->vsync_pol, 1,
1602 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1603 hdmi_set_reg(core->int_pro_mode, 1,
1604 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1605
1606 /*
1607 * Quirk requirement for exynos 5 HDMI IP design,
1608 * 2 pixels less than the actual calculation for hsync_start
1609 * and end.
1610 */
1611
1612 /* Following values & calculations differ for different type of modes */
1613 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1614 /* Interlaced Mode */
1615 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1616 (m->vsync_end - m->vdisplay) / 2);
1617 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1618 (m->vsync_start - m->vdisplay) / 2);
1619 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1620 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301621 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001622 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1623 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1624 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1625 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1626 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1627 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1628 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1629 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1630 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301631 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1632 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1633 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1634 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001635 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1636 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1637 } else {
1638 /* Progressive Mode */
1639 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1640 m->vsync_end - m->vdisplay);
1641 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1642 m->vsync_start - m->vdisplay);
1643 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1644 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1645 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1646 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1647 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1648 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1649 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1650 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1651 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1652 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1653 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1654 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1655 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301656 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1657 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1658 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001659 }
1660
1661 /* Following values & calculations are same irrespective of mode type */
1662 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1663 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1664 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1665 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1666 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1667 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1668 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1669 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1670 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1671 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1672 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1673 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1674 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1675 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1676 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1677 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1678 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1679 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1680 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1681 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1682
1683 /* Timing generator registers */
1684 hdmi_set_reg(tg->cmd, 1, 0x0);
1685 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1686 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1687 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1688 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1689 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001690 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1691 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001692 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001693 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001694}
1695
Rahul Sharma16844fb2013-06-10 14:50:00 +05301696static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001697{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001698 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001699 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001700
YoungJun Chocbc4c332013-06-12 10:44:40 +09001701 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1702 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001703 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1704 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001705
Sachin Kamat5f46c332013-04-26 11:29:00 +05301706 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001707 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301708 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001709 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001710}
1711
Inki Dae1de425b2012-03-16 18:47:04 +09001712static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1713 unsigned int *height)
1714{
Inki Dae1de425b2012-03-16 18:47:04 +09001715 *width = MAX_WIDTH;
1716 *height = MAX_HEIGHT;
1717}
1718
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001719static void hdmi_commit(void *ctx)
1720{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001721 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001722
Shirish Sdda90122013-01-23 22:03:18 -05001723 mutex_lock(&hdata->hdmi_mutex);
1724 if (!hdata->powered) {
1725 mutex_unlock(&hdata->hdmi_mutex);
1726 return;
1727 }
1728 mutex_unlock(&hdata->hdmi_mutex);
1729
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001730 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001731}
1732
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001733static void hdmi_poweron(struct hdmi_context *hdata)
1734{
1735 struct hdmi_resources *res = &hdata->res;
1736
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001737 mutex_lock(&hdata->hdmi_mutex);
1738 if (hdata->powered) {
1739 mutex_unlock(&hdata->hdmi_mutex);
1740 return;
1741 }
1742
1743 hdata->powered = true;
1744
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001745 mutex_unlock(&hdata->hdmi_mutex);
1746
Seung-Woo Kimad079452013-06-05 14:34:38 +09001747 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1748 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1749
Sean Paul0bfb1f82013-06-11 12:24:02 +05301750 clk_prepare_enable(res->hdmiphy);
1751 clk_prepare_enable(res->hdmi);
1752 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301753
1754 hdmiphy_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001755}
1756
1757static void hdmi_poweroff(struct hdmi_context *hdata)
1758{
1759 struct hdmi_resources *res = &hdata->res;
1760
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001761 mutex_lock(&hdata->hdmi_mutex);
1762 if (!hdata->powered)
1763 goto out;
1764 mutex_unlock(&hdata->hdmi_mutex);
1765
1766 /*
1767 * The TV power domain needs any condition of hdmiphy to turn off and
1768 * its reset state seems to meet the condition.
1769 */
1770 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301771 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001772
Sean Paul0bfb1f82013-06-11 12:24:02 +05301773 clk_disable_unprepare(res->sclk_hdmi);
1774 clk_disable_unprepare(res->hdmi);
1775 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001776 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1777
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001778 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001779
1780 hdata->powered = false;
1781
1782out:
1783 mutex_unlock(&hdata->hdmi_mutex);
1784}
1785
1786static void hdmi_dpms(void *ctx, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001787{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001788 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001789
YoungJun Chocbc4c332013-06-12 10:44:40 +09001790 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001791
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001792 switch (mode) {
1793 case DRM_MODE_DPMS_ON:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301794 if (pm_runtime_suspended(hdata->dev))
1795 pm_runtime_get_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001796 break;
1797 case DRM_MODE_DPMS_STANDBY:
1798 case DRM_MODE_DPMS_SUSPEND:
1799 case DRM_MODE_DPMS_OFF:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301800 if (!pm_runtime_suspended(hdata->dev))
1801 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001802 break;
1803 default:
1804 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1805 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001806 }
1807}
1808
Joonyoung Shim578b6062012-04-05 20:49:26 +09001809static struct exynos_hdmi_ops hdmi_ops = {
1810 /* display */
Sean Paul45517892014-01-30 16:19:05 -05001811 .initialize = hdmi_initialize,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001812 .is_connected = hdmi_is_connected,
1813 .get_edid = hdmi_get_edid,
Rahul Sharma16844fb2013-06-10 14:50:00 +05301814 .check_mode = hdmi_check_mode,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001815
1816 /* manager */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001817 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09001818 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001819 .commit = hdmi_commit,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001820 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001821};
1822
Sean Paul77006a72013-01-16 10:17:20 -05001823static irqreturn_t hdmi_irq_thread(int irq, void *arg)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001824{
1825 struct exynos_drm_hdmi_context *ctx = arg;
1826 struct hdmi_context *hdata = ctx->ctx;
1827
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001828 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301829 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001830 mutex_unlock(&hdata->hdmi_mutex);
1831
Sean Paul45517892014-01-30 16:19:05 -05001832 if (hdata->drm_dev)
1833 drm_helper_hpd_irq_event(hdata->drm_dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001834
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001835 return IRQ_HANDLED;
1836}
1837
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001838static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001839{
1840 struct device *dev = hdata->dev;
1841 struct hdmi_resources *res = &hdata->res;
1842 static char *supply[] = {
1843 "hdmi-en",
1844 "vdd",
1845 "vdd_osc",
1846 "vdd_pll",
1847 };
1848 int i, ret;
1849
1850 DRM_DEBUG_KMS("HDMI resource init\n");
1851
Sachin Kamatadc837a2012-08-31 15:50:47 +05301852 memset(res, 0, sizeof(*res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001853
1854 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301855 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301856 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001857 DRM_ERROR("failed to get clock 'hdmi'\n");
1858 goto fail;
1859 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301860 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301861 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001862 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1863 goto fail;
1864 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301865 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301866 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001867 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1868 goto fail;
1869 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301870 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301871 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001872 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1873 goto fail;
1874 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301875 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301876 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001877 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1878 goto fail;
1879 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301880 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1881 if (IS_ERR(res->mout_hdmi)) {
1882 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1883 goto fail;
1884 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001885
Rahul Sharma59956d32013-06-11 12:24:03 +05301886 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001887
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301888 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301889 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001890 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001891 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001892 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1893 res->regul_bulk[i].supply = supply[i];
1894 res->regul_bulk[i].consumer = NULL;
1895 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301896 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001897 if (ret) {
1898 DRM_ERROR("failed to get regulators\n");
1899 goto fail;
1900 }
1901 res->regul_count = ARRAY_SIZE(supply);
1902
1903 return 0;
1904fail:
1905 DRM_ERROR("HDMI resource init - failed\n");
1906 return -ENODEV;
1907}
1908
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001909static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
1910
1911void hdmi_attach_ddc_client(struct i2c_client *ddc)
1912{
1913 if (ddc)
1914 hdmi_ddc = ddc;
1915}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001916
1917void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
1918{
1919 if (hdmiphy)
1920 hdmi_hdmiphy = hdmiphy;
1921}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001922
Rahul Sharma22c4f422012-10-04 20:48:55 +05301923static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1924 (struct device *dev)
1925{
1926 struct device_node *np = dev->of_node;
1927 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301928 u32 value;
1929
1930 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001931 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05301932 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301933
1934 if (!of_find_property(np, "hpd-gpio", &value)) {
1935 DRM_ERROR("no hpd gpio property found\n");
1936 goto err_data;
1937 }
1938
Rahul Sharma5f916e22013-06-11 19:41:29 +05301939 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05301940
1941 return pd;
1942
1943err_data:
1944 return NULL;
1945}
Rahul Sharma22c4f422012-10-04 20:48:55 +05301946
Rahul Sharma22c4f422012-10-04 20:48:55 +05301947static struct of_device_id hdmi_match_types[] = {
1948 {
1949 .compatible = "samsung,exynos5-hdmi",
1950 .data = (void *)HDMI_TYPE14,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301951 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301952 .compatible = "samsung,exynos4212-hdmi",
1953 .data = (void *)HDMI_TYPE14,
1954 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301955 /* end node */
1956 }
1957};
1958
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001959static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001960{
1961 struct device *dev = &pdev->dev;
1962 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1963 struct hdmi_context *hdata;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301964 struct s5p_hdmi_platform_data *pdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001965 struct resource *res;
Sachin Kamat88c49812013-08-28 10:47:57 +05301966 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001967 int ret;
1968
Sachin Kamat88c49812013-08-28 10:47:57 +05301969 if (!dev->of_node)
1970 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301971
Sachin Kamat88c49812013-08-28 10:47:57 +05301972 pdata = drm_hdmi_dt_parse_pdata(dev);
1973 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001974 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001975
Sachin Kamat88c49812013-08-28 10:47:57 +05301976 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001977 if (!drm_hdmi_ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001978 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001979
Sachin Kamat88c49812013-08-28 10:47:57 +05301980 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001981 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001982 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001983
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001984 mutex_init(&hdata->hdmi_mutex);
1985
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001986 drm_hdmi_ctx->ctx = (void *)hdata;
1987 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1988
1989 platform_set_drvdata(pdev, drm_hdmi_ctx);
1990
Sachin Kamat88c49812013-08-28 10:47:57 +05301991 match = of_match_node(hdmi_match_types, dev->of_node);
1992 if (!match)
1993 return -ENODEV;
1994 hdata->type = (enum hdmi_type)match->data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301995
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301996 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001997 hdata->dev = dev;
1998
1999 ret = hdmi_resources_init(hdata);
2000 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302001 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302002 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002003 }
2004
2005 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002006 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01002007 if (IS_ERR(hdata->regs))
2008 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002009
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002010 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302011 if (ret) {
2012 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302013 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302014 }
2015
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002016 /* DDC i2c driver */
2017 if (i2c_add_driver(&ddc_driver)) {
2018 DRM_ERROR("failed to register ddc i2c driver\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302019 return -ENOENT;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020 }
2021
2022 hdata->ddc_port = hdmi_ddc;
2023
2024 /* hdmiphy i2c driver */
2025 if (i2c_add_driver(&hdmiphy_driver)) {
2026 DRM_ERROR("failed to register hdmiphy i2c driver\n");
2027 ret = -ENOENT;
2028 goto err_ddc;
2029 }
2030
2031 hdata->hdmiphy_port = hdmi_hdmiphy;
2032
Sean Paul77006a72013-01-16 10:17:20 -05002033 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2034 if (hdata->irq < 0) {
2035 DRM_ERROR("failed to get GPIO irq\n");
2036 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002037 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002038 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002039
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302040 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2041
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002042 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002043 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002044 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paul77006a72013-01-16 10:17:20 -05002045 "hdmi", drm_hdmi_ctx);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002046 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002047 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002048 goto err_hdmiphy;
2049 }
2050
Rahul Sharma768c3052012-10-04 20:48:56 +05302051 /* Attach HDMI Driver to common hdmi. */
2052 exynos_hdmi_drv_attach(drm_hdmi_ctx);
2053
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054 /* register specific callbacks to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09002055 exynos_hdmi_ops_register(&hdmi_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002056
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002057 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002058
2059 return 0;
2060
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002061err_hdmiphy:
2062 i2c_del_driver(&hdmiphy_driver);
2063err_ddc:
2064 i2c_del_driver(&ddc_driver);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002065 return ret;
2066}
2067
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002068static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002069{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002070 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002071
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002072 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002073
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002074 /* hdmiphy i2c driver */
2075 i2c_del_driver(&hdmiphy_driver);
2076 /* DDC i2c driver */
2077 i2c_del_driver(&ddc_driver);
2078
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002079 return 0;
2080}
2081
Joonyoung Shimab27af82012-04-23 19:35:51 +09002082#ifdef CONFIG_PM_SLEEP
2083static int hdmi_suspend(struct device *dev)
2084{
2085 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2086 struct hdmi_context *hdata = ctx->ctx;
2087
Sean Paul77006a72013-01-16 10:17:20 -05002088 disable_irq(hdata->irq);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002089
2090 hdata->hpd = false;
Sean Paul45517892014-01-30 16:19:05 -05002091 if (hdata->drm_dev)
2092 drm_helper_hpd_irq_event(hdata->drm_dev);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002093
Rahul Sharma64327cb2012-11-28 11:30:23 +05302094 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002095 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302096 return 0;
2097 }
2098
Joonyoung Shimab27af82012-04-23 19:35:51 +09002099 hdmi_poweroff(hdata);
2100
2101 return 0;
2102}
2103
2104static int hdmi_resume(struct device *dev)
2105{
2106 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2107 struct hdmi_context *hdata = ctx->ctx;
2108
Rahul Sharma64327cb2012-11-28 11:30:23 +05302109 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2110
Sean Paul77006a72013-01-16 10:17:20 -05002111 enable_irq(hdata->irq);
Rahul Sharma64327cb2012-11-28 11:30:23 +05302112
2113 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002114 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302115 return 0;
2116 }
2117
2118 hdmi_poweron(hdata);
2119
Joonyoung Shimab27af82012-04-23 19:35:51 +09002120 return 0;
2121}
2122#endif
2123
Rahul Sharma64327cb2012-11-28 11:30:23 +05302124#ifdef CONFIG_PM_RUNTIME
2125static int hdmi_runtime_suspend(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_poweroff(hdata);
2131
2132 return 0;
2133}
2134
2135static int hdmi_runtime_resume(struct device *dev)
2136{
2137 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2138 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302139
2140 hdmi_poweron(hdata);
2141
2142 return 0;
2143}
2144#endif
2145
2146static const struct dev_pm_ops hdmi_pm_ops = {
2147 SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
2148 SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
2149};
Joonyoung Shimab27af82012-04-23 19:35:51 +09002150
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002151struct platform_driver hdmi_driver = {
2152 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002153 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002154 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302155 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002156 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09002157 .pm = &hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302158 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002159 },
2160};