blob: 135c9c9e2f3cc98a5df64af2d2191d2d8a52ff53 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090020
21#include "regs-hdmi.h"
22
23#include <linux/kernel.h>
24#include <linux/spinlock.h>
25#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053034#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053035#include <linux/of.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053036#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053037#include <linux/hdmi.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090038
39#include <drm/exynos_drm.h>
40
41#include "exynos_drm_drv.h"
42#include "exynos_drm_hdmi.h"
43
44#include "exynos_hdmi.h"
45
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053046#include <linux/gpio.h>
47#include <media/s5p_hdmi.h>
48
Inki Dae1de425b2012-03-16 18:47:04 +090049#define MAX_WIDTH 1920
50#define MAX_HEIGHT 1080
Seung-Woo Kimd8408322011-12-21 17:39:39 +090051#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
52
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053053/* AVI header and aspect ratio */
54#define HDMI_AVI_VERSION 0x02
55#define HDMI_AVI_LENGTH 0x0D
56#define AVI_PIC_ASPECT_RATIO_16_9 (2 << 4)
57#define AVI_SAME_AS_PIC_ASPECT_RATIO 8
58
59/* AUI header info */
60#define HDMI_AUI_VERSION 0x01
61#define HDMI_AUI_LENGTH 0x0A
62
Rahul Sharma5a325072012-10-04 20:48:54 +053063enum hdmi_type {
64 HDMI_TYPE13,
65 HDMI_TYPE14,
66};
67
Joonyoung Shim590f4182012-03-16 18:47:14 +090068struct hdmi_resources {
69 struct clk *hdmi;
70 struct clk *sclk_hdmi;
71 struct clk *sclk_pixel;
72 struct clk *sclk_hdmiphy;
73 struct clk *hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053074 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090075 struct regulator_bulk_data *regul_bulk;
76 int regul_count;
77};
78
Sean Paul2f7e2ed2013-01-15 08:11:08 -050079struct hdmi_tg_regs {
80 u8 cmd[1];
81 u8 h_fsz[2];
82 u8 hact_st[2];
83 u8 hact_sz[2];
84 u8 v_fsz[2];
85 u8 vsync[2];
86 u8 vsync2[2];
87 u8 vact_st[2];
88 u8 vact_sz[2];
89 u8 field_chg[2];
90 u8 vact_st2[2];
91 u8 vact_st3[2];
92 u8 vact_st4[2];
93 u8 vsync_top_hdmi[2];
94 u8 vsync_bot_hdmi[2];
95 u8 field_top_hdmi[2];
96 u8 field_bot_hdmi[2];
97 u8 tg_3d[1];
98};
99
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900100struct hdmi_v13_core_regs {
101 u8 h_blank[2];
102 u8 v_blank[3];
103 u8 h_v_line[3];
104 u8 vsync_pol[1];
105 u8 int_pro_mode[1];
106 u8 v_blank_f[3];
107 u8 h_sync_gen[3];
108 u8 v_sync_gen1[3];
109 u8 v_sync_gen2[3];
110 u8 v_sync_gen3[3];
111};
112
113struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500114 u8 h_blank[2];
115 u8 v2_blank[2];
116 u8 v1_blank[2];
117 u8 v_line[2];
118 u8 h_line[2];
119 u8 hsync_pol[1];
120 u8 vsync_pol[1];
121 u8 int_pro_mode[1];
122 u8 v_blank_f0[2];
123 u8 v_blank_f1[2];
124 u8 h_sync_start[2];
125 u8 h_sync_end[2];
126 u8 v_sync_line_bef_2[2];
127 u8 v_sync_line_bef_1[2];
128 u8 v_sync_line_aft_2[2];
129 u8 v_sync_line_aft_1[2];
130 u8 v_sync_line_aft_pxl_2[2];
131 u8 v_sync_line_aft_pxl_1[2];
132 u8 v_blank_f2[2]; /* for 3D mode */
133 u8 v_blank_f3[2]; /* for 3D mode */
134 u8 v_blank_f4[2]; /* for 3D mode */
135 u8 v_blank_f5[2]; /* for 3D mode */
136 u8 v_sync_line_aft_3[2];
137 u8 v_sync_line_aft_4[2];
138 u8 v_sync_line_aft_5[2];
139 u8 v_sync_line_aft_6[2];
140 u8 v_sync_line_aft_pxl_3[2];
141 u8 v_sync_line_aft_pxl_4[2];
142 u8 v_sync_line_aft_pxl_5[2];
143 u8 v_sync_line_aft_pxl_6[2];
144 u8 vact_space_1[2];
145 u8 vact_space_2[2];
146 u8 vact_space_3[2];
147 u8 vact_space_4[2];
148 u8 vact_space_5[2];
149 u8 vact_space_6[2];
150};
151
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900152struct hdmi_v13_conf {
153 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500154 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900155};
156
157struct hdmi_v14_conf {
158 struct hdmi_v14_core_regs core;
159 struct hdmi_tg_regs tg;
160};
161
162struct hdmi_conf_regs {
163 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500164 int cea_video_id;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900165 union {
166 struct hdmi_v13_conf v13_conf;
167 struct hdmi_v14_conf v14_conf;
168 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500169};
170
Joonyoung Shim590f4182012-03-16 18:47:14 +0900171struct hdmi_context {
172 struct device *dev;
173 struct drm_device *drm_dev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900174 bool hpd;
175 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900176 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900177 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900178
Joonyoung Shim590f4182012-03-16 18:47:14 +0900179 void __iomem *regs;
Inki Dae1055b392012-10-19 17:37:35 +0900180 void *parent_ctx;
Sean Paul77006a72013-01-16 10:17:20 -0500181 int irq;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900182
183 struct i2c_client *ddc_port;
184 struct i2c_client *hdmiphy_port;
185
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900186 /* current hdmiphy conf regs */
187 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900188
189 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900190
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530191 int hpd_gpio;
Rahul Sharma5a325072012-10-04 20:48:54 +0530192
193 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900194};
195
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500196struct hdmiphy_config {
197 int pixel_clock;
198 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900199};
200
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900201/* list of phy config settings */
202static const struct hdmiphy_config hdmiphy_v13_configs[] = {
203 {
204 .pixel_clock = 27000000,
205 .conf = {
206 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
207 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
208 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
209 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
210 },
211 },
212 {
213 .pixel_clock = 27027000,
214 .conf = {
215 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
216 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
217 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
218 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
219 },
220 },
221 {
222 .pixel_clock = 74176000,
223 .conf = {
224 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
225 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
226 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
227 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
228 },
229 },
230 {
231 .pixel_clock = 74250000,
232 .conf = {
233 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
234 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
235 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
236 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
237 },
238 },
239 {
240 .pixel_clock = 148500000,
241 .conf = {
242 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
243 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
244 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
245 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
246 },
247 },
248};
249
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500250static const struct hdmiphy_config hdmiphy_v14_configs[] = {
251 {
252 .pixel_clock = 25200000,
253 .conf = {
254 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
255 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
256 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
257 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
258 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900259 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500260 {
261 .pixel_clock = 27000000,
262 .conf = {
263 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
264 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
265 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
266 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
267 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900268 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500269 {
270 .pixel_clock = 27027000,
271 .conf = {
272 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
273 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
274 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
275 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
276 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900277 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500278 {
279 .pixel_clock = 36000000,
280 .conf = {
281 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
282 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
283 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
284 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
285 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900286 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500287 {
288 .pixel_clock = 40000000,
289 .conf = {
290 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
291 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
292 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
293 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
294 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900295 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500296 {
297 .pixel_clock = 65000000,
298 .conf = {
299 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
300 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
301 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
302 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
303 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900304 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500305 {
Shirish Se1d883c2014-03-13 14:28:27 +0900306 .pixel_clock = 71000000,
307 .conf = {
308 0x01, 0x91, 0x1e, 0x15, 0x40, 0x3c, 0xce, 0x08,
309 0x04, 0x20, 0xb2, 0xd8, 0x45, 0xa0, 0xac, 0x80,
310 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
311 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
312 },
313 },
314 {
315 .pixel_clock = 73250000,
316 .conf = {
317 0x01, 0xd1, 0x1f, 0x15, 0x40, 0x18, 0xe9, 0x08,
318 0x02, 0xa0, 0xb7, 0xd8, 0x45, 0xa0, 0xac, 0x80,
319 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
320 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
321 },
322 },
323 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500324 .pixel_clock = 74176000,
325 .conf = {
326 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
327 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
328 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
329 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
330 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900331 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500332 {
333 .pixel_clock = 74250000,
334 .conf = {
335 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
336 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
337 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
338 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
339 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900340 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500341 {
342 .pixel_clock = 83500000,
343 .conf = {
344 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
345 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
346 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
347 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
348 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900349 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500350 {
Shirish Se1d883c2014-03-13 14:28:27 +0900351 .pixel_clock = 88750000,
352 .conf = {
353 0x01, 0x91, 0x25, 0x17, 0x40, 0x30, 0xfe, 0x08,
354 0x06, 0x20, 0xde, 0xd8, 0x45, 0xa0, 0xac, 0x80,
355 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
356 0x54, 0x8a, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
357 },
358 },
359 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500360 .pixel_clock = 106500000,
361 .conf = {
362 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
363 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
364 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
365 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
366 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900367 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500368 {
369 .pixel_clock = 108000000,
370 .conf = {
371 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
372 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
373 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
374 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
375 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900376 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500377 {
Shirish Se1d883c2014-03-13 14:28:27 +0900378 .pixel_clock = 115500000,
379 .conf = {
380 0x01, 0xd1, 0x30, 0x1a, 0x40, 0x40, 0x10, 0x04,
381 0x04, 0xa0, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
382 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
383 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
384 },
385 },
386 {
387 .pixel_clock = 119000000,
388 .conf = {
389 0x01, 0x91, 0x32, 0x14, 0x40, 0x60, 0xd8, 0x08,
390 0x06, 0x20, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
391 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
392 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
393 },
394 },
395 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500396 .pixel_clock = 146250000,
397 .conf = {
398 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
399 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
400 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
401 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
402 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900403 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500404 {
405 .pixel_clock = 148500000,
406 .conf = {
407 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
408 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
409 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
410 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
411 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900412 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900413};
414
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900415static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
416{
417 return readl(hdata->regs + reg_id);
418}
419
420static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
421 u32 reg_id, u8 value)
422{
423 writeb(value, hdata->regs + reg_id);
424}
425
426static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
427 u32 reg_id, u32 value, u32 mask)
428{
429 u32 old = readl(hdata->regs + reg_id);
430 value = (value & mask) | (old & ~mask);
431 writel(value, hdata->regs + reg_id);
432}
433
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900434static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900435{
436#define DUMPREG(reg_id) \
437 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
438 readl(hdata->regs + reg_id))
439 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
440 DUMPREG(HDMI_INTC_FLAG);
441 DUMPREG(HDMI_INTC_CON);
442 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900443 DUMPREG(HDMI_V13_PHY_RSTOUT);
444 DUMPREG(HDMI_V13_PHY_VPLL);
445 DUMPREG(HDMI_V13_PHY_CMU);
446 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900447
448 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
449 DUMPREG(HDMI_CON_0);
450 DUMPREG(HDMI_CON_1);
451 DUMPREG(HDMI_CON_2);
452 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900453 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900454 DUMPREG(HDMI_STATUS_EN);
455 DUMPREG(HDMI_HPD);
456 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900457 DUMPREG(HDMI_V13_HPD_GEN);
458 DUMPREG(HDMI_V13_DC_CONTROL);
459 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900460
461 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
462 DUMPREG(HDMI_H_BLANK_0);
463 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900464 DUMPREG(HDMI_V13_V_BLANK_0);
465 DUMPREG(HDMI_V13_V_BLANK_1);
466 DUMPREG(HDMI_V13_V_BLANK_2);
467 DUMPREG(HDMI_V13_H_V_LINE_0);
468 DUMPREG(HDMI_V13_H_V_LINE_1);
469 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900470 DUMPREG(HDMI_VSYNC_POL);
471 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900472 DUMPREG(HDMI_V13_V_BLANK_F_0);
473 DUMPREG(HDMI_V13_V_BLANK_F_1);
474 DUMPREG(HDMI_V13_V_BLANK_F_2);
475 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
476 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
477 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
478 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
479 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
480 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
481 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
482 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
483 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
484 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
485 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
486 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900487
488 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
489 DUMPREG(HDMI_TG_CMD);
490 DUMPREG(HDMI_TG_H_FSZ_L);
491 DUMPREG(HDMI_TG_H_FSZ_H);
492 DUMPREG(HDMI_TG_HACT_ST_L);
493 DUMPREG(HDMI_TG_HACT_ST_H);
494 DUMPREG(HDMI_TG_HACT_SZ_L);
495 DUMPREG(HDMI_TG_HACT_SZ_H);
496 DUMPREG(HDMI_TG_V_FSZ_L);
497 DUMPREG(HDMI_TG_V_FSZ_H);
498 DUMPREG(HDMI_TG_VSYNC_L);
499 DUMPREG(HDMI_TG_VSYNC_H);
500 DUMPREG(HDMI_TG_VSYNC2_L);
501 DUMPREG(HDMI_TG_VSYNC2_H);
502 DUMPREG(HDMI_TG_VACT_ST_L);
503 DUMPREG(HDMI_TG_VACT_ST_H);
504 DUMPREG(HDMI_TG_VACT_SZ_L);
505 DUMPREG(HDMI_TG_VACT_SZ_H);
506 DUMPREG(HDMI_TG_FIELD_CHG_L);
507 DUMPREG(HDMI_TG_FIELD_CHG_H);
508 DUMPREG(HDMI_TG_VACT_ST2_L);
509 DUMPREG(HDMI_TG_VACT_ST2_H);
510 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
511 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
512 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
513 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
514 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
515 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
516 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
517 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
518#undef DUMPREG
519}
520
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900521static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
522{
523 int i;
524
525#define DUMPREG(reg_id) \
526 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
527 readl(hdata->regs + reg_id))
528
529 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
530 DUMPREG(HDMI_INTC_CON);
531 DUMPREG(HDMI_INTC_FLAG);
532 DUMPREG(HDMI_HPD_STATUS);
533 DUMPREG(HDMI_INTC_CON_1);
534 DUMPREG(HDMI_INTC_FLAG_1);
535 DUMPREG(HDMI_PHY_STATUS_0);
536 DUMPREG(HDMI_PHY_STATUS_PLL);
537 DUMPREG(HDMI_PHY_CON_0);
538 DUMPREG(HDMI_PHY_RSTOUT);
539 DUMPREG(HDMI_PHY_VPLL);
540 DUMPREG(HDMI_PHY_CMU);
541 DUMPREG(HDMI_CORE_RSTOUT);
542
543 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
544 DUMPREG(HDMI_CON_0);
545 DUMPREG(HDMI_CON_1);
546 DUMPREG(HDMI_CON_2);
547 DUMPREG(HDMI_SYS_STATUS);
548 DUMPREG(HDMI_PHY_STATUS_0);
549 DUMPREG(HDMI_STATUS_EN);
550 DUMPREG(HDMI_HPD);
551 DUMPREG(HDMI_MODE_SEL);
552 DUMPREG(HDMI_ENC_EN);
553 DUMPREG(HDMI_DC_CONTROL);
554 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
555
556 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
557 DUMPREG(HDMI_H_BLANK_0);
558 DUMPREG(HDMI_H_BLANK_1);
559 DUMPREG(HDMI_V2_BLANK_0);
560 DUMPREG(HDMI_V2_BLANK_1);
561 DUMPREG(HDMI_V1_BLANK_0);
562 DUMPREG(HDMI_V1_BLANK_1);
563 DUMPREG(HDMI_V_LINE_0);
564 DUMPREG(HDMI_V_LINE_1);
565 DUMPREG(HDMI_H_LINE_0);
566 DUMPREG(HDMI_H_LINE_1);
567 DUMPREG(HDMI_HSYNC_POL);
568
569 DUMPREG(HDMI_VSYNC_POL);
570 DUMPREG(HDMI_INT_PRO_MODE);
571 DUMPREG(HDMI_V_BLANK_F0_0);
572 DUMPREG(HDMI_V_BLANK_F0_1);
573 DUMPREG(HDMI_V_BLANK_F1_0);
574 DUMPREG(HDMI_V_BLANK_F1_1);
575
576 DUMPREG(HDMI_H_SYNC_START_0);
577 DUMPREG(HDMI_H_SYNC_START_1);
578 DUMPREG(HDMI_H_SYNC_END_0);
579 DUMPREG(HDMI_H_SYNC_END_1);
580
581 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
582 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
583 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
584 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
585
586 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
587 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
588 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
589 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
590
591 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
592 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
593 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
594 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
595
596 DUMPREG(HDMI_V_BLANK_F2_0);
597 DUMPREG(HDMI_V_BLANK_F2_1);
598 DUMPREG(HDMI_V_BLANK_F3_0);
599 DUMPREG(HDMI_V_BLANK_F3_1);
600 DUMPREG(HDMI_V_BLANK_F4_0);
601 DUMPREG(HDMI_V_BLANK_F4_1);
602 DUMPREG(HDMI_V_BLANK_F5_0);
603 DUMPREG(HDMI_V_BLANK_F5_1);
604
605 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
606 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
607 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
608 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
609 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
610 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
611 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
612 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
613
614 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
615 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
616 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
617 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
618 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
619 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
620 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
621 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
622
623 DUMPREG(HDMI_VACT_SPACE_1_0);
624 DUMPREG(HDMI_VACT_SPACE_1_1);
625 DUMPREG(HDMI_VACT_SPACE_2_0);
626 DUMPREG(HDMI_VACT_SPACE_2_1);
627 DUMPREG(HDMI_VACT_SPACE_3_0);
628 DUMPREG(HDMI_VACT_SPACE_3_1);
629 DUMPREG(HDMI_VACT_SPACE_4_0);
630 DUMPREG(HDMI_VACT_SPACE_4_1);
631 DUMPREG(HDMI_VACT_SPACE_5_0);
632 DUMPREG(HDMI_VACT_SPACE_5_1);
633 DUMPREG(HDMI_VACT_SPACE_6_0);
634 DUMPREG(HDMI_VACT_SPACE_6_1);
635
636 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
637 DUMPREG(HDMI_TG_CMD);
638 DUMPREG(HDMI_TG_H_FSZ_L);
639 DUMPREG(HDMI_TG_H_FSZ_H);
640 DUMPREG(HDMI_TG_HACT_ST_L);
641 DUMPREG(HDMI_TG_HACT_ST_H);
642 DUMPREG(HDMI_TG_HACT_SZ_L);
643 DUMPREG(HDMI_TG_HACT_SZ_H);
644 DUMPREG(HDMI_TG_V_FSZ_L);
645 DUMPREG(HDMI_TG_V_FSZ_H);
646 DUMPREG(HDMI_TG_VSYNC_L);
647 DUMPREG(HDMI_TG_VSYNC_H);
648 DUMPREG(HDMI_TG_VSYNC2_L);
649 DUMPREG(HDMI_TG_VSYNC2_H);
650 DUMPREG(HDMI_TG_VACT_ST_L);
651 DUMPREG(HDMI_TG_VACT_ST_H);
652 DUMPREG(HDMI_TG_VACT_SZ_L);
653 DUMPREG(HDMI_TG_VACT_SZ_H);
654 DUMPREG(HDMI_TG_FIELD_CHG_L);
655 DUMPREG(HDMI_TG_FIELD_CHG_H);
656 DUMPREG(HDMI_TG_VACT_ST2_L);
657 DUMPREG(HDMI_TG_VACT_ST2_H);
658 DUMPREG(HDMI_TG_VACT_ST3_L);
659 DUMPREG(HDMI_TG_VACT_ST3_H);
660 DUMPREG(HDMI_TG_VACT_ST4_L);
661 DUMPREG(HDMI_TG_VACT_ST4_H);
662 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
663 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
664 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
665 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
666 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
667 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
668 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
669 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
670 DUMPREG(HDMI_TG_3D);
671
672 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
673 DUMPREG(HDMI_AVI_CON);
674 DUMPREG(HDMI_AVI_HEADER0);
675 DUMPREG(HDMI_AVI_HEADER1);
676 DUMPREG(HDMI_AVI_HEADER2);
677 DUMPREG(HDMI_AVI_CHECK_SUM);
678 DUMPREG(HDMI_VSI_CON);
679 DUMPREG(HDMI_VSI_HEADER0);
680 DUMPREG(HDMI_VSI_HEADER1);
681 DUMPREG(HDMI_VSI_HEADER2);
682 for (i = 0; i < 7; ++i)
683 DUMPREG(HDMI_VSI_DATA(i));
684
685#undef DUMPREG
686}
687
688static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
689{
Rahul Sharma5a325072012-10-04 20:48:54 +0530690 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900691 hdmi_v13_regs_dump(hdata, prefix);
692 else
693 hdmi_v14_regs_dump(hdata, prefix);
694}
695
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530696static u8 hdmi_chksum(struct hdmi_context *hdata,
697 u32 start, u8 len, u32 hdr_sum)
698{
699 int i;
700
701 /* hdr_sum : header0 + header1 + header2
702 * start : start address of packet byte1
703 * len : packet bytes - 1 */
704 for (i = 0; i < len; ++i)
705 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
706
707 /* return 2's complement of 8 bit hdr_sum */
708 return (u8)(~(hdr_sum & 0xff) + 1);
709}
710
711static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530712 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530713{
714 u32 hdr_sum;
715 u8 chksum;
716 u32 aspect_ratio;
717 u32 mod;
718 u32 vic;
719
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530720 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
721 if (hdata->dvi_mode) {
722 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
723 HDMI_VSI_CON_DO_NOT_TRANSMIT);
724 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
725 HDMI_AVI_CON_DO_NOT_TRANSMIT);
726 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
727 return;
728 }
729
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530730 switch (infoframe->any.type) {
731 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530732 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530733 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
734 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
735 infoframe->any.version);
736 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
737 hdr_sum = infoframe->any.type + infoframe->any.version +
738 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530739
740 /* Output format zero hardcoded ,RGB YBCR selection */
741 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
742 AVI_ACTIVE_FORMAT_VALID |
743 AVI_UNDERSCANNED_DISPLAY_VALID);
744
745 aspect_ratio = AVI_PIC_ASPECT_RATIO_16_9;
746
747 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio |
748 AVI_SAME_AS_PIC_ASPECT_RATIO);
749
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900750 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530751 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
752
753 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530754 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530755 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
756 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
757 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530758 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530759 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530760 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
761 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
762 infoframe->any.version);
763 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
764 hdr_sum = infoframe->any.type + infoframe->any.version +
765 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530766 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530767 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530768 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
769 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
770 break;
771 default:
772 break;
773 }
774}
775
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900776static bool hdmi_is_connected(void *ctx)
777{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900778 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900779
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900780 return hdata->hpd;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900781}
782
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500783static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900784{
785 struct edid *raw_edid;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900786 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900787
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900788 if (!hdata->ddc_port)
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500789 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900790
791 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500792 if (!raw_edid)
793 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900794
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500795 hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
796 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
797 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
798 raw_edid->width_cm, raw_edid->height_cm);
799
800 return raw_edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900801}
802
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900803static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900804{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900805 const struct hdmiphy_config *confs;
806 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900807
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900808 if (hdata->type == HDMI_TYPE13) {
809 confs = hdmiphy_v13_configs;
810 count = ARRAY_SIZE(hdmiphy_v13_configs);
811 } else if (hdata->type == HDMI_TYPE14) {
812 confs = hdmiphy_v14_configs;
813 count = ARRAY_SIZE(hdmiphy_v14_configs);
814 } else
815 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900816
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900817 for (i = 0; i < count; i++)
818 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500819 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500820
821 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
822 return -EINVAL;
823}
824
Rahul Sharma16844fb2013-06-10 14:50:00 +0530825static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900826{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900827 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900828 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900829
Rahul Sharma16844fb2013-06-10 14:50:00 +0530830 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
831 mode->hdisplay, mode->vdisplay, mode->vrefresh,
832 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
833 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900834
Rahul Sharma16844fb2013-06-10 14:50:00 +0530835 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900836 if (ret < 0)
837 return ret;
838 return 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900839}
840
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900841static void hdmi_set_acr(u32 freq, u8 *acr)
842{
843 u32 n, cts;
844
845 switch (freq) {
846 case 32000:
847 n = 4096;
848 cts = 27000;
849 break;
850 case 44100:
851 n = 6272;
852 cts = 30000;
853 break;
854 case 88200:
855 n = 12544;
856 cts = 30000;
857 break;
858 case 176400:
859 n = 25088;
860 cts = 30000;
861 break;
862 case 48000:
863 n = 6144;
864 cts = 27000;
865 break;
866 case 96000:
867 n = 12288;
868 cts = 27000;
869 break;
870 case 192000:
871 n = 24576;
872 cts = 27000;
873 break;
874 default:
875 n = 0;
876 cts = 0;
877 break;
878 }
879
880 acr[1] = cts >> 16;
881 acr[2] = cts >> 8 & 0xff;
882 acr[3] = cts & 0xff;
883
884 acr[4] = n >> 16;
885 acr[5] = n >> 8 & 0xff;
886 acr[6] = n & 0xff;
887}
888
889static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
890{
891 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
892 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
893 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
894 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
895 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
896 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
897 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
898 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
899 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
900
Rahul Sharma5a325072012-10-04 20:48:54 +0530901 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900902 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
903 else
904 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
905}
906
907static void hdmi_audio_init(struct hdmi_context *hdata)
908{
909 u32 sample_rate, bits_per_sample, frame_size_code;
910 u32 data_num, bit_ch, sample_frq;
911 u32 val;
912 u8 acr[7];
913
914 sample_rate = 44100;
915 bits_per_sample = 16;
916 frame_size_code = 0;
917
918 switch (bits_per_sample) {
919 case 20:
920 data_num = 2;
921 bit_ch = 1;
922 break;
923 case 24:
924 data_num = 3;
925 bit_ch = 1;
926 break;
927 default:
928 data_num = 1;
929 bit_ch = 0;
930 break;
931 }
932
933 hdmi_set_acr(sample_rate, acr);
934 hdmi_reg_acr(hdata, acr);
935
936 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
937 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
938 | HDMI_I2S_MUX_ENABLE);
939
940 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
941 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
942
943 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
944
945 sample_frq = (sample_rate == 44100) ? 0 :
946 (sample_rate == 48000) ? 2 :
947 (sample_rate == 32000) ? 3 :
948 (sample_rate == 96000) ? 0xa : 0x0;
949
950 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
951 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
952
953 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
954 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
955
956 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
957 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
958 | HDMI_I2S_SEL_LRCK(6));
959 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
960 | HDMI_I2S_SEL_SDATA2(4));
961 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
962 | HDMI_I2S_SEL_SDATA2(2));
963 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
964
965 /* I2S_CON_1 & 2 */
966 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
967 | HDMI_I2S_L_CH_LOW_POL);
968 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
969 | HDMI_I2S_SET_BIT_CH(bit_ch)
970 | HDMI_I2S_SET_SDATA_BIT(data_num)
971 | HDMI_I2S_BASIC_FORMAT);
972
973 /* Configure register related to CUV information */
974 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
975 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
976 | HDMI_I2S_COPYRIGHT
977 | HDMI_I2S_LINEAR_PCM
978 | HDMI_I2S_CONSUMER_FORMAT);
979 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
980 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
981 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
982 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
983 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
984 HDMI_I2S_ORG_SMP_FREQ_44_1
985 | HDMI_I2S_WORD_LEN_MAX24_24BITS
986 | HDMI_I2S_WORD_LEN_MAX_24BITS);
987
988 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
989}
990
991static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
992{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900993 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900994 return;
995
996 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
997 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
998 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
999}
1000
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001001static void hdmi_conf_reset(struct hdmi_context *hdata)
1002{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001003 u32 reg;
1004
Rahul Sharma5a325072012-10-04 20:48:54 +05301005 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001006 reg = HDMI_V13_CORE_RSTOUT;
1007 else
1008 reg = HDMI_CORE_RSTOUT;
1009
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001010 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001011 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001012 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001013 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001014 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001015}
1016
1017static void hdmi_conf_init(struct hdmi_context *hdata)
1018{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301019 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301020
Sean Paul77006a72013-01-16 10:17:20 -05001021 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001022 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1023 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001024
1025 /* choose HDMI mode */
1026 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1027 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1028 /* disable bluescreen */
1029 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001030
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001031 if (hdata->dvi_mode) {
1032 /* choose DVI mode */
1033 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1034 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1035 hdmi_reg_writeb(hdata, HDMI_CON_2,
1036 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1037 }
1038
Rahul Sharma5a325072012-10-04 20:48:54 +05301039 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001040 /* choose bluescreen (fecal) color */
1041 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1042 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1043 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1044
1045 /* enable AVI packet every vsync, fixes purple line problem */
1046 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1047 /* force RGB, look to CEA-861-D, table 7 for more detail */
1048 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1049 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1050
1051 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1052 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1053 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1054 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301055 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1056 infoframe.any.version = HDMI_AVI_VERSION;
1057 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301058 hdmi_reg_infoframe(hdata, &infoframe);
1059
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301060 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1061 infoframe.any.version = HDMI_AUI_VERSION;
1062 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301063 hdmi_reg_infoframe(hdata, &infoframe);
1064
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001065 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001066 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1067 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001068}
1069
Rahul Sharma16844fb2013-06-10 14:50:00 +05301070static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001071{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001072 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1073 const struct hdmi_v13_core_regs *core =
1074 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001075 int tries;
1076
1077 /* setting core registers */
1078 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1079 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001080 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1081 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1082 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1083 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1084 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1085 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001086 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1087 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001088 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1089 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1090 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1091 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1092 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1093 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1094 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1095 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1096 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1097 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1098 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1099 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1100 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1101 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1102 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001103 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001104 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1105 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1106 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1107 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1108 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1109 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1110 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1111 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1112 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1113 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1114 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1115 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1116 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1117 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1118 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1119 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1120 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1121 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1122 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1123 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1124 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1125 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1126 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1127 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1128 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1129 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1130 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1131 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001132
1133 /* waiting for HDMIPHY's PLL to get to steady state */
1134 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001135 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001136 if (val & HDMI_PHY_STATUS_READY)
1137 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001138 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001139 }
1140 /* steady state not achieved */
1141 if (tries == 0) {
1142 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1143 hdmi_regs_dump(hdata, "timing apply");
1144 }
1145
Sean Paul0bfb1f82013-06-11 12:24:02 +05301146 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301147 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301148 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001149
1150 /* enable HDMI and timing generator */
1151 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1152 if (core->int_pro_mode[0])
1153 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1154 HDMI_FIELD_EN);
1155 else
1156 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1157}
1158
Rahul Sharma16844fb2013-06-10 14:50:00 +05301159static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001160{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001161 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1162 const struct hdmi_v14_core_regs *core =
1163 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001164 int tries;
1165
1166 /* setting core registers */
1167 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1168 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1169 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1170 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1171 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1172 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1173 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1174 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1175 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1176 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1177 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1178 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1179 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1180 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1181 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1182 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1183 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1184 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1185 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1186 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1187 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1188 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1189 core->v_sync_line_bef_2[0]);
1190 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1191 core->v_sync_line_bef_2[1]);
1192 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1193 core->v_sync_line_bef_1[0]);
1194 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1195 core->v_sync_line_bef_1[1]);
1196 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1197 core->v_sync_line_aft_2[0]);
1198 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1199 core->v_sync_line_aft_2[1]);
1200 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1201 core->v_sync_line_aft_1[0]);
1202 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1203 core->v_sync_line_aft_1[1]);
1204 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1205 core->v_sync_line_aft_pxl_2[0]);
1206 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1207 core->v_sync_line_aft_pxl_2[1]);
1208 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1209 core->v_sync_line_aft_pxl_1[0]);
1210 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1211 core->v_sync_line_aft_pxl_1[1]);
1212 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1213 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1214 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1215 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1216 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1217 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1218 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1219 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1220 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1221 core->v_sync_line_aft_3[0]);
1222 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1223 core->v_sync_line_aft_3[1]);
1224 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1225 core->v_sync_line_aft_4[0]);
1226 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1227 core->v_sync_line_aft_4[1]);
1228 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1229 core->v_sync_line_aft_5[0]);
1230 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1231 core->v_sync_line_aft_5[1]);
1232 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1233 core->v_sync_line_aft_6[0]);
1234 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1235 core->v_sync_line_aft_6[1]);
1236 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1237 core->v_sync_line_aft_pxl_3[0]);
1238 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1239 core->v_sync_line_aft_pxl_3[1]);
1240 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1241 core->v_sync_line_aft_pxl_4[0]);
1242 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1243 core->v_sync_line_aft_pxl_4[1]);
1244 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1245 core->v_sync_line_aft_pxl_5[0]);
1246 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1247 core->v_sync_line_aft_pxl_5[1]);
1248 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1249 core->v_sync_line_aft_pxl_6[0]);
1250 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1251 core->v_sync_line_aft_pxl_6[1]);
1252 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1253 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1254 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1255 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1256 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1257 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1258 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1259 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1260 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1261 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1262 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1263 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1264
1265 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001266 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1267 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1268 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1269 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1270 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1271 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1272 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1273 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1274 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1275 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1276 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1277 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1278 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1279 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1280 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1281 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1282 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1283 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1284 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1285 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1286 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1287 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1288 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1289 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1290 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1291 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1292 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1293 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1294 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1295 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1296 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1297 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1298 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001299
1300 /* waiting for HDMIPHY's PLL to get to steady state */
1301 for (tries = 100; tries; --tries) {
1302 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1303 if (val & HDMI_PHY_STATUS_READY)
1304 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001305 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001306 }
1307 /* steady state not achieved */
1308 if (tries == 0) {
1309 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1310 hdmi_regs_dump(hdata, "timing apply");
1311 }
1312
Sean Paul0bfb1f82013-06-11 12:24:02 +05301313 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301314 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301315 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001316
1317 /* enable HDMI and timing generator */
1318 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1319 if (core->int_pro_mode[0])
1320 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1321 HDMI_FIELD_EN);
1322 else
1323 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1324}
1325
Rahul Sharma16844fb2013-06-10 14:50:00 +05301326static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001327{
Rahul Sharma5a325072012-10-04 20:48:54 +05301328 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301329 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001330 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301331 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001332}
1333
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001334static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1335{
1336 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001337 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001338
Sean Paul0bfb1f82013-06-11 12:24:02 +05301339 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301340 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301341 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001342
1343 /* operation mode */
1344 buffer[0] = 0x1f;
1345 buffer[1] = 0x00;
1346
1347 if (hdata->hdmiphy_port)
1348 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1349
Rahul Sharma5a325072012-10-04 20:48:54 +05301350 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001351 reg = HDMI_V13_PHY_RSTOUT;
1352 else
1353 reg = HDMI_PHY_RSTOUT;
1354
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001355 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001356 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001357 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001358 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001359 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001360}
1361
Rahul Sharmaa5562252012-11-28 11:30:25 +05301362static void hdmiphy_poweron(struct hdmi_context *hdata)
1363{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301364 if (hdata->type == HDMI_TYPE14)
1365 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1366 HDMI_PHY_POWER_OFF_EN);
1367}
1368
1369static void hdmiphy_poweroff(struct hdmi_context *hdata)
1370{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301371 if (hdata->type == HDMI_TYPE14)
1372 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1373 HDMI_PHY_POWER_OFF_EN);
1374}
1375
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001376static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1377{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001378 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001379 u8 buffer[32];
1380 u8 operation[2];
1381 u8 read_buffer[32] = {0, };
1382 int ret;
1383 int i;
1384
1385 if (!hdata->hdmiphy_port) {
1386 DRM_ERROR("hdmiphy is not attached\n");
1387 return;
1388 }
1389
1390 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001391 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1392 if (i < 0) {
1393 DRM_ERROR("failed to find hdmiphy conf\n");
1394 return;
1395 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001396
Sachin Kamat5f46c332013-04-26 11:29:00 +05301397 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001398 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301399 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001400 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001401
1402 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001403 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1404 if (ret != 32) {
1405 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1406 return;
1407 }
1408
Sean Paul09760ea2013-01-14 17:03:20 -05001409 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001410
1411 /* operation mode */
1412 operation[0] = 0x1f;
1413 operation[1] = 0x80;
1414
1415 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1416 if (ret != 2) {
1417 DRM_ERROR("failed to enable hdmiphy\n");
1418 return;
1419 }
1420
1421 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1422 if (ret < 0) {
1423 DRM_ERROR("failed to read hdmiphy config\n");
1424 return;
1425 }
1426
1427 for (i = 0; i < ret; i++)
1428 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1429 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1430}
1431
1432static void hdmi_conf_apply(struct hdmi_context *hdata)
1433{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001434 hdmiphy_conf_reset(hdata);
1435 hdmiphy_conf_apply(hdata);
1436
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001437 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001438 hdmi_conf_reset(hdata);
1439 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001440 mutex_unlock(&hdata->hdmi_mutex);
1441
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001442 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001443
1444 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301445 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001446 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001447
1448 hdmi_regs_dump(hdata, "start");
1449}
1450
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001451static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1452{
1453 int i;
1454 BUG_ON(num_bytes > 4);
1455 for (i = 0; i < num_bytes; i++)
1456 reg_pair[i] = (value >> (8 * i)) & 0xff;
1457}
1458
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001459static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1460 struct drm_display_mode *m)
1461{
1462 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1463 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1464 unsigned int val;
1465
1466 hdata->mode_conf.cea_video_id =
1467 drm_match_cea_mode((struct drm_display_mode *)m);
1468 hdata->mode_conf.pixel_clock = m->clock * 1000;
1469
1470 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1471 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1472
1473 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1474 hdmi_set_reg(core->vsync_pol, 1, val);
1475
1476 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1477 hdmi_set_reg(core->int_pro_mode, 1, val);
1478
1479 val = (m->hsync_start - m->hdisplay - 2);
1480 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1481 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1482 hdmi_set_reg(core->h_sync_gen, 3, val);
1483
1484 /*
1485 * Quirk requirement for exynos HDMI IP design,
1486 * 2 pixels less than the actual calculation for hsync_start
1487 * and end.
1488 */
1489
1490 /* Following values & calculations differ for different type of modes */
1491 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1492 /* Interlaced Mode */
1493 val = ((m->vsync_end - m->vdisplay) / 2);
1494 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1495 hdmi_set_reg(core->v_sync_gen1, 3, val);
1496
1497 val = m->vtotal / 2;
1498 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1499 hdmi_set_reg(core->v_blank, 3, val);
1500
1501 val = (m->vtotal +
1502 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1503 val |= m->vtotal << 11;
1504 hdmi_set_reg(core->v_blank_f, 3, val);
1505
1506 val = ((m->vtotal / 2) + 7);
1507 val |= ((m->vtotal / 2) + 2) << 12;
1508 hdmi_set_reg(core->v_sync_gen2, 3, val);
1509
1510 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1511 val |= ((m->htotal / 2) +
1512 (m->hsync_start - m->hdisplay)) << 12;
1513 hdmi_set_reg(core->v_sync_gen3, 3, val);
1514
1515 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1516 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1517
1518 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1519 } else {
1520 /* Progressive Mode */
1521
1522 val = m->vtotal;
1523 val |= (m->vtotal - m->vdisplay) << 11;
1524 hdmi_set_reg(core->v_blank, 3, val);
1525
1526 hdmi_set_reg(core->v_blank_f, 3, 0);
1527
1528 val = (m->vsync_end - m->vdisplay);
1529 val |= ((m->vsync_start - m->vdisplay) << 12);
1530 hdmi_set_reg(core->v_sync_gen1, 3, val);
1531
1532 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1533 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1534 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1535 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1536 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1537 }
1538
1539 /* Timing generator registers */
1540 hdmi_set_reg(tg->cmd, 1, 0x0);
1541 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1542 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1543 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1544 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1545 hdmi_set_reg(tg->vsync, 2, 0x1);
1546 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1547 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1548 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1549 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1550 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1551 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1552 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1553}
1554
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001555static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1556 struct drm_display_mode *m)
1557{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001558 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1559 struct hdmi_v14_core_regs *core =
1560 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001561
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001562 hdata->mode_conf.cea_video_id =
1563 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001564 hdata->mode_conf.pixel_clock = m->clock * 1000;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001565
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001566 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1567 hdmi_set_reg(core->v_line, 2, m->vtotal);
1568 hdmi_set_reg(core->h_line, 2, m->htotal);
1569 hdmi_set_reg(core->hsync_pol, 1,
1570 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1571 hdmi_set_reg(core->vsync_pol, 1,
1572 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1573 hdmi_set_reg(core->int_pro_mode, 1,
1574 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1575
1576 /*
1577 * Quirk requirement for exynos 5 HDMI IP design,
1578 * 2 pixels less than the actual calculation for hsync_start
1579 * and end.
1580 */
1581
1582 /* Following values & calculations differ for different type of modes */
1583 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1584 /* Interlaced Mode */
1585 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1586 (m->vsync_end - m->vdisplay) / 2);
1587 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1588 (m->vsync_start - m->vdisplay) / 2);
1589 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1590 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301591 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001592 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1593 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1594 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1595 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1596 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1597 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1598 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1599 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1600 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301601 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1602 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1603 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1604 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001605 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1606 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1607 } else {
1608 /* Progressive Mode */
1609 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1610 m->vsync_end - m->vdisplay);
1611 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1612 m->vsync_start - m->vdisplay);
1613 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1614 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1615 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1616 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1617 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1618 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1619 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1620 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1621 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1622 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1623 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1624 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1625 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301626 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1627 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1628 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001629 }
1630
1631 /* Following values & calculations are same irrespective of mode type */
1632 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1633 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1634 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1635 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1636 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1637 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1638 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1639 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1640 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1641 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1642 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1643 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1644 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1645 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1646 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1647 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1648 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1649 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1650 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1651 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1652
1653 /* Timing generator registers */
1654 hdmi_set_reg(tg->cmd, 1, 0x0);
1655 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1656 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1657 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1658 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1659 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001660 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1661 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001662 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001663 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001664}
1665
Rahul Sharma16844fb2013-06-10 14:50:00 +05301666static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001667{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001668 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001669 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001670
YoungJun Chocbc4c332013-06-12 10:44:40 +09001671 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1672 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001673 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1674 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001675
Sachin Kamat5f46c332013-04-26 11:29:00 +05301676 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001677 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301678 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001679 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001680}
1681
Inki Dae1de425b2012-03-16 18:47:04 +09001682static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1683 unsigned int *height)
1684{
Inki Dae1de425b2012-03-16 18:47:04 +09001685 *width = MAX_WIDTH;
1686 *height = MAX_HEIGHT;
1687}
1688
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001689static void hdmi_commit(void *ctx)
1690{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001691 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001692
Shirish Sdda90122013-01-23 22:03:18 -05001693 mutex_lock(&hdata->hdmi_mutex);
1694 if (!hdata->powered) {
1695 mutex_unlock(&hdata->hdmi_mutex);
1696 return;
1697 }
1698 mutex_unlock(&hdata->hdmi_mutex);
1699
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001700 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001701}
1702
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001703static void hdmi_poweron(struct hdmi_context *hdata)
1704{
1705 struct hdmi_resources *res = &hdata->res;
1706
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001707 mutex_lock(&hdata->hdmi_mutex);
1708 if (hdata->powered) {
1709 mutex_unlock(&hdata->hdmi_mutex);
1710 return;
1711 }
1712
1713 hdata->powered = true;
1714
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001715 mutex_unlock(&hdata->hdmi_mutex);
1716
Seung-Woo Kimad079452013-06-05 14:34:38 +09001717 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1718 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1719
Sean Paul0bfb1f82013-06-11 12:24:02 +05301720 clk_prepare_enable(res->hdmiphy);
1721 clk_prepare_enable(res->hdmi);
1722 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301723
1724 hdmiphy_poweron(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001725}
1726
1727static void hdmi_poweroff(struct hdmi_context *hdata)
1728{
1729 struct hdmi_resources *res = &hdata->res;
1730
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001731 mutex_lock(&hdata->hdmi_mutex);
1732 if (!hdata->powered)
1733 goto out;
1734 mutex_unlock(&hdata->hdmi_mutex);
1735
1736 /*
1737 * The TV power domain needs any condition of hdmiphy to turn off and
1738 * its reset state seems to meet the condition.
1739 */
1740 hdmiphy_conf_reset(hdata);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301741 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001742
Sean Paul0bfb1f82013-06-11 12:24:02 +05301743 clk_disable_unprepare(res->sclk_hdmi);
1744 clk_disable_unprepare(res->hdmi);
1745 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001746 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1747
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001748 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001749
1750 hdata->powered = false;
1751
1752out:
1753 mutex_unlock(&hdata->hdmi_mutex);
1754}
1755
1756static void hdmi_dpms(void *ctx, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001757{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001758 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001759
YoungJun Chocbc4c332013-06-12 10:44:40 +09001760 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001761
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001762 switch (mode) {
1763 case DRM_MODE_DPMS_ON:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301764 if (pm_runtime_suspended(hdata->dev))
1765 pm_runtime_get_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001766 break;
1767 case DRM_MODE_DPMS_STANDBY:
1768 case DRM_MODE_DPMS_SUSPEND:
1769 case DRM_MODE_DPMS_OFF:
Rahul Sharma64327cb2012-11-28 11:30:23 +05301770 if (!pm_runtime_suspended(hdata->dev))
1771 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001772 break;
1773 default:
1774 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1775 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001776 }
1777}
1778
Joonyoung Shim578b6062012-04-05 20:49:26 +09001779static struct exynos_hdmi_ops hdmi_ops = {
1780 /* display */
1781 .is_connected = hdmi_is_connected,
1782 .get_edid = hdmi_get_edid,
Rahul Sharma16844fb2013-06-10 14:50:00 +05301783 .check_mode = hdmi_check_mode,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001784
1785 /* manager */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001786 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09001787 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001788 .commit = hdmi_commit,
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001789 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001790};
1791
Sean Paul77006a72013-01-16 10:17:20 -05001792static irqreturn_t hdmi_irq_thread(int irq, void *arg)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001793{
1794 struct exynos_drm_hdmi_context *ctx = arg;
1795 struct hdmi_context *hdata = ctx->ctx;
1796
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001797 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301798 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001799 mutex_unlock(&hdata->hdmi_mutex);
1800
1801 if (ctx->drm_dev)
1802 drm_helper_hpd_irq_event(ctx->drm_dev);
1803
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001804 return IRQ_HANDLED;
1805}
1806
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001807static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001808{
1809 struct device *dev = hdata->dev;
1810 struct hdmi_resources *res = &hdata->res;
1811 static char *supply[] = {
1812 "hdmi-en",
1813 "vdd",
1814 "vdd_osc",
1815 "vdd_pll",
1816 };
1817 int i, ret;
1818
1819 DRM_DEBUG_KMS("HDMI resource init\n");
1820
Sachin Kamatadc837a2012-08-31 15:50:47 +05301821 memset(res, 0, sizeof(*res));
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001822
1823 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301824 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301825 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001826 DRM_ERROR("failed to get clock 'hdmi'\n");
1827 goto fail;
1828 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301829 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301830 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001831 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1832 goto fail;
1833 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301834 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301835 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001836 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1837 goto fail;
1838 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301839 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301840 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001841 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1842 goto fail;
1843 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301844 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301845 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001846 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1847 goto fail;
1848 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301849 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1850 if (IS_ERR(res->mout_hdmi)) {
1851 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1852 goto fail;
1853 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001854
Rahul Sharma59956d32013-06-11 12:24:03 +05301855 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001856
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301857 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301858 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001859 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001860 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001861 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1862 res->regul_bulk[i].supply = supply[i];
1863 res->regul_bulk[i].consumer = NULL;
1864 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301865 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001866 if (ret) {
1867 DRM_ERROR("failed to get regulators\n");
1868 goto fail;
1869 }
1870 res->regul_count = ARRAY_SIZE(supply);
1871
1872 return 0;
1873fail:
1874 DRM_ERROR("HDMI resource init - failed\n");
1875 return -ENODEV;
1876}
1877
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001878static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
1879
1880void hdmi_attach_ddc_client(struct i2c_client *ddc)
1881{
1882 if (ddc)
1883 hdmi_ddc = ddc;
1884}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001885
1886void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
1887{
1888 if (hdmiphy)
1889 hdmi_hdmiphy = hdmiphy;
1890}
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001891
Rahul Sharma22c4f422012-10-04 20:48:55 +05301892static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1893 (struct device *dev)
1894{
1895 struct device_node *np = dev->of_node;
1896 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301897 u32 value;
1898
1899 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001900 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05301901 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301902
1903 if (!of_find_property(np, "hpd-gpio", &value)) {
1904 DRM_ERROR("no hpd gpio property found\n");
1905 goto err_data;
1906 }
1907
Rahul Sharma5f916e22013-06-11 19:41:29 +05301908 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05301909
1910 return pd;
1911
1912err_data:
1913 return NULL;
1914}
Rahul Sharma22c4f422012-10-04 20:48:55 +05301915
Rahul Sharma22c4f422012-10-04 20:48:55 +05301916static struct of_device_id hdmi_match_types[] = {
1917 {
1918 .compatible = "samsung,exynos5-hdmi",
1919 .data = (void *)HDMI_TYPE14,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301920 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301921 .compatible = "samsung,exynos4212-hdmi",
1922 .data = (void *)HDMI_TYPE14,
1923 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301924 /* end node */
1925 }
1926};
1927
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001928static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001929{
1930 struct device *dev = &pdev->dev;
1931 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1932 struct hdmi_context *hdata;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301933 struct s5p_hdmi_platform_data *pdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001934 struct resource *res;
Sachin Kamat88c49812013-08-28 10:47:57 +05301935 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001936 int ret;
1937
Sachin Kamat88c49812013-08-28 10:47:57 +05301938 if (!dev->of_node)
1939 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301940
Sachin Kamat88c49812013-08-28 10:47:57 +05301941 pdata = drm_hdmi_dt_parse_pdata(dev);
1942 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001943 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001944
Sachin Kamat88c49812013-08-28 10:47:57 +05301945 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001946 if (!drm_hdmi_ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001947 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001948
Sachin Kamat88c49812013-08-28 10:47:57 +05301949 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001950 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001951 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001953 mutex_init(&hdata->hdmi_mutex);
1954
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001955 drm_hdmi_ctx->ctx = (void *)hdata;
1956 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1957
1958 platform_set_drvdata(pdev, drm_hdmi_ctx);
1959
Sachin Kamat88c49812013-08-28 10:47:57 +05301960 match = of_match_node(hdmi_match_types, dev->of_node);
1961 if (!match)
1962 return -ENODEV;
1963 hdata->type = (enum hdmi_type)match->data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301964
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301965 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001966 hdata->dev = dev;
1967
1968 ret = hdmi_resources_init(hdata);
1969 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301970 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301971 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001972 }
1973
1974 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001975 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001976 if (IS_ERR(hdata->regs))
1977 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001978
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001979 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301980 if (ret) {
1981 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301982 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301983 }
1984
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001985 /* DDC i2c driver */
1986 if (i2c_add_driver(&ddc_driver)) {
1987 DRM_ERROR("failed to register ddc i2c driver\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301988 return -ENOENT;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001989 }
1990
1991 hdata->ddc_port = hdmi_ddc;
1992
1993 /* hdmiphy i2c driver */
1994 if (i2c_add_driver(&hdmiphy_driver)) {
1995 DRM_ERROR("failed to register hdmiphy i2c driver\n");
1996 ret = -ENOENT;
1997 goto err_ddc;
1998 }
1999
2000 hdata->hdmiphy_port = hdmi_hdmiphy;
2001
Sean Paul77006a72013-01-16 10:17:20 -05002002 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2003 if (hdata->irq < 0) {
2004 DRM_ERROR("failed to get GPIO irq\n");
2005 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002006 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002007 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002008
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302009 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2010
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002011 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002012 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002013 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paul77006a72013-01-16 10:17:20 -05002014 "hdmi", drm_hdmi_ctx);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002015 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002016 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002017 goto err_hdmiphy;
2018 }
2019
Rahul Sharma768c3052012-10-04 20:48:56 +05302020 /* Attach HDMI Driver to common hdmi. */
2021 exynos_hdmi_drv_attach(drm_hdmi_ctx);
2022
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002023 /* register specific callbacks to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09002024 exynos_hdmi_ops_register(&hdmi_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002025
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002026 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002027
2028 return 0;
2029
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002030err_hdmiphy:
2031 i2c_del_driver(&hdmiphy_driver);
2032err_ddc:
2033 i2c_del_driver(&ddc_driver);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002034 return ret;
2035}
2036
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002037static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002038{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002039 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002040
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002041 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002042
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002043 /* hdmiphy i2c driver */
2044 i2c_del_driver(&hdmiphy_driver);
2045 /* DDC i2c driver */
2046 i2c_del_driver(&ddc_driver);
2047
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002048 return 0;
2049}
2050
Joonyoung Shimab27af82012-04-23 19:35:51 +09002051#ifdef CONFIG_PM_SLEEP
2052static int hdmi_suspend(struct device *dev)
2053{
2054 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2055 struct hdmi_context *hdata = ctx->ctx;
2056
Sean Paul77006a72013-01-16 10:17:20 -05002057 disable_irq(hdata->irq);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002058
2059 hdata->hpd = false;
2060 if (ctx->drm_dev)
2061 drm_helper_hpd_irq_event(ctx->drm_dev);
2062
Rahul Sharma64327cb2012-11-28 11:30:23 +05302063 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002064 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302065 return 0;
2066 }
2067
Joonyoung Shimab27af82012-04-23 19:35:51 +09002068 hdmi_poweroff(hdata);
2069
2070 return 0;
2071}
2072
2073static int hdmi_resume(struct device *dev)
2074{
2075 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2076 struct hdmi_context *hdata = ctx->ctx;
2077
Rahul Sharma64327cb2012-11-28 11:30:23 +05302078 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2079
Sean Paul77006a72013-01-16 10:17:20 -05002080 enable_irq(hdata->irq);
Rahul Sharma64327cb2012-11-28 11:30:23 +05302081
2082 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002083 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302084 return 0;
2085 }
2086
2087 hdmi_poweron(hdata);
2088
Joonyoung Shimab27af82012-04-23 19:35:51 +09002089 return 0;
2090}
2091#endif
2092
Rahul Sharma64327cb2012-11-28 11:30:23 +05302093#ifdef CONFIG_PM_RUNTIME
2094static int hdmi_runtime_suspend(struct device *dev)
2095{
2096 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2097 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302098
2099 hdmi_poweroff(hdata);
2100
2101 return 0;
2102}
2103
2104static int hdmi_runtime_resume(struct device *dev)
2105{
2106 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2107 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302108
2109 hdmi_poweron(hdata);
2110
2111 return 0;
2112}
2113#endif
2114
2115static const struct dev_pm_ops hdmi_pm_ops = {
2116 SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
2117 SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
2118};
Joonyoung Shimab27af82012-04-23 19:35:51 +09002119
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002120struct platform_driver hdmi_driver = {
2121 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002122 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002123 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302124 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002125 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09002126 .pm = &hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302127 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002128 },
2129};