blob: b0c58e4fdc56c08403a890dd6c424cd5e61e0822 [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>
Daniel Kurtz2b768132014-02-24 18:52:51 +090036#include <linux/i2c.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053037#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053038#include <linux/hdmi.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090039
40#include <drm/exynos_drm.h>
41
42#include "exynos_drm_drv.h"
43#include "exynos_drm_hdmi.h"
44
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053045#include <linux/gpio.h>
46#include <media/s5p_hdmi.h>
47
Inki Dae1de425b2012-03-16 18:47:04 +090048#define MAX_WIDTH 1920
49#define MAX_HEIGHT 1080
Seung-Woo Kimd8408322011-12-21 17:39:39 +090050#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
51
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053052/* AVI header and aspect ratio */
53#define HDMI_AVI_VERSION 0x02
54#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053055
56/* AUI header info */
57#define HDMI_AUI_VERSION 0x01
58#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053059#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
60#define AVI_4_3_CENTER_RATIO 0x9
61#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053062
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;
Shirish S46154152014-03-13 10:58:28 +0530165 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166 union {
167 struct hdmi_v13_conf v13_conf;
168 struct hdmi_v14_conf v14_conf;
169 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500170};
171
Joonyoung Shim590f4182012-03-16 18:47:14 +0900172struct hdmi_context {
173 struct device *dev;
174 struct drm_device *drm_dev;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900175 bool hpd;
176 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900177 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900178 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900179
Joonyoung Shim590f4182012-03-16 18:47:14 +0900180 void __iomem *regs;
Inki Dae1055b392012-10-19 17:37:35 +0900181 void *parent_ctx;
Sean Paul77006a72013-01-16 10:17:20 -0500182 int irq;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900183
184 struct i2c_client *ddc_port;
185 struct i2c_client *hdmiphy_port;
186
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900187 /* current hdmiphy conf regs */
188 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900189
190 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900191
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530192 int hpd_gpio;
Rahul Sharma5a325072012-10-04 20:48:54 +0530193
194 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900195};
196
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500197struct hdmiphy_config {
198 int pixel_clock;
199 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900200};
201
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900202/* list of phy config settings */
203static const struct hdmiphy_config hdmiphy_v13_configs[] = {
204 {
205 .pixel_clock = 27000000,
206 .conf = {
207 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
208 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
209 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
210 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
211 },
212 },
213 {
214 .pixel_clock = 27027000,
215 .conf = {
216 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
217 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
218 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
219 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
220 },
221 },
222 {
223 .pixel_clock = 74176000,
224 .conf = {
225 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
226 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
227 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
228 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
229 },
230 },
231 {
232 .pixel_clock = 74250000,
233 .conf = {
234 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
235 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
236 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
237 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
238 },
239 },
240 {
241 .pixel_clock = 148500000,
242 .conf = {
243 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
244 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
245 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
246 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
247 },
248 },
249};
250
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500251static const struct hdmiphy_config hdmiphy_v14_configs[] = {
252 {
253 .pixel_clock = 25200000,
254 .conf = {
255 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
256 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
257 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
258 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
259 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900260 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500261 {
262 .pixel_clock = 27000000,
263 .conf = {
264 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
265 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
266 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
267 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
268 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900269 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500270 {
271 .pixel_clock = 27027000,
272 .conf = {
273 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
274 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
275 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
276 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
277 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900278 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500279 {
280 .pixel_clock = 36000000,
281 .conf = {
282 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
283 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
284 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
285 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
286 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900287 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500288 {
289 .pixel_clock = 40000000,
290 .conf = {
291 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
292 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
293 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
294 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
295 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900296 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500297 {
298 .pixel_clock = 65000000,
299 .conf = {
300 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
301 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
302 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
303 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
304 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900305 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500306 {
Shirish Se1d883c2014-03-13 14:28:27 +0900307 .pixel_clock = 71000000,
308 .conf = {
309 0x01, 0x91, 0x1e, 0x15, 0x40, 0x3c, 0xce, 0x08,
310 0x04, 0x20, 0xb2, 0xd8, 0x45, 0xa0, 0xac, 0x80,
311 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
312 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
313 },
314 },
315 {
316 .pixel_clock = 73250000,
317 .conf = {
318 0x01, 0xd1, 0x1f, 0x15, 0x40, 0x18, 0xe9, 0x08,
319 0x02, 0xa0, 0xb7, 0xd8, 0x45, 0xa0, 0xac, 0x80,
320 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
321 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
322 },
323 },
324 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500325 .pixel_clock = 74176000,
326 .conf = {
327 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
328 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
329 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
330 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
331 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900332 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500333 {
334 .pixel_clock = 74250000,
335 .conf = {
336 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
337 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
338 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
339 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
340 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900341 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500342 {
343 .pixel_clock = 83500000,
344 .conf = {
345 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
346 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
347 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
348 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
349 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900350 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500351 {
Shirish Se1d883c2014-03-13 14:28:27 +0900352 .pixel_clock = 88750000,
353 .conf = {
354 0x01, 0x91, 0x25, 0x17, 0x40, 0x30, 0xfe, 0x08,
355 0x06, 0x20, 0xde, 0xd8, 0x45, 0xa0, 0xac, 0x80,
356 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
357 0x54, 0x8a, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
358 },
359 },
360 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500361 .pixel_clock = 106500000,
362 .conf = {
363 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
364 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
365 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
366 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
367 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900368 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500369 {
370 .pixel_clock = 108000000,
371 .conf = {
372 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
373 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
374 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
375 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
376 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900377 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500378 {
Shirish Se1d883c2014-03-13 14:28:27 +0900379 .pixel_clock = 115500000,
380 .conf = {
381 0x01, 0xd1, 0x30, 0x1a, 0x40, 0x40, 0x10, 0x04,
382 0x04, 0xa0, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
383 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
384 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
385 },
386 },
387 {
388 .pixel_clock = 119000000,
389 .conf = {
390 0x01, 0x91, 0x32, 0x14, 0x40, 0x60, 0xd8, 0x08,
391 0x06, 0x20, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
392 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
393 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
394 },
395 },
396 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500397 .pixel_clock = 146250000,
398 .conf = {
399 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
400 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
401 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
402 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
403 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900404 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500405 {
406 .pixel_clock = 148500000,
407 .conf = {
408 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
409 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
410 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
411 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
412 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900413 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900414};
415
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900416static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
417{
418 return readl(hdata->regs + reg_id);
419}
420
421static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
422 u32 reg_id, u8 value)
423{
424 writeb(value, hdata->regs + reg_id);
425}
426
427static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
428 u32 reg_id, u32 value, u32 mask)
429{
430 u32 old = readl(hdata->regs + reg_id);
431 value = (value & mask) | (old & ~mask);
432 writel(value, hdata->regs + reg_id);
433}
434
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900435static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900436{
437#define DUMPREG(reg_id) \
438 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
439 readl(hdata->regs + reg_id))
440 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
441 DUMPREG(HDMI_INTC_FLAG);
442 DUMPREG(HDMI_INTC_CON);
443 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900444 DUMPREG(HDMI_V13_PHY_RSTOUT);
445 DUMPREG(HDMI_V13_PHY_VPLL);
446 DUMPREG(HDMI_V13_PHY_CMU);
447 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900448
449 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
450 DUMPREG(HDMI_CON_0);
451 DUMPREG(HDMI_CON_1);
452 DUMPREG(HDMI_CON_2);
453 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900454 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900455 DUMPREG(HDMI_STATUS_EN);
456 DUMPREG(HDMI_HPD);
457 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900458 DUMPREG(HDMI_V13_HPD_GEN);
459 DUMPREG(HDMI_V13_DC_CONTROL);
460 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900461
462 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
463 DUMPREG(HDMI_H_BLANK_0);
464 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900465 DUMPREG(HDMI_V13_V_BLANK_0);
466 DUMPREG(HDMI_V13_V_BLANK_1);
467 DUMPREG(HDMI_V13_V_BLANK_2);
468 DUMPREG(HDMI_V13_H_V_LINE_0);
469 DUMPREG(HDMI_V13_H_V_LINE_1);
470 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900471 DUMPREG(HDMI_VSYNC_POL);
472 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900473 DUMPREG(HDMI_V13_V_BLANK_F_0);
474 DUMPREG(HDMI_V13_V_BLANK_F_1);
475 DUMPREG(HDMI_V13_V_BLANK_F_2);
476 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
477 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
478 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
479 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
480 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
481 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
482 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
483 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
484 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
485 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
486 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
487 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900488
489 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
490 DUMPREG(HDMI_TG_CMD);
491 DUMPREG(HDMI_TG_H_FSZ_L);
492 DUMPREG(HDMI_TG_H_FSZ_H);
493 DUMPREG(HDMI_TG_HACT_ST_L);
494 DUMPREG(HDMI_TG_HACT_ST_H);
495 DUMPREG(HDMI_TG_HACT_SZ_L);
496 DUMPREG(HDMI_TG_HACT_SZ_H);
497 DUMPREG(HDMI_TG_V_FSZ_L);
498 DUMPREG(HDMI_TG_V_FSZ_H);
499 DUMPREG(HDMI_TG_VSYNC_L);
500 DUMPREG(HDMI_TG_VSYNC_H);
501 DUMPREG(HDMI_TG_VSYNC2_L);
502 DUMPREG(HDMI_TG_VSYNC2_H);
503 DUMPREG(HDMI_TG_VACT_ST_L);
504 DUMPREG(HDMI_TG_VACT_ST_H);
505 DUMPREG(HDMI_TG_VACT_SZ_L);
506 DUMPREG(HDMI_TG_VACT_SZ_H);
507 DUMPREG(HDMI_TG_FIELD_CHG_L);
508 DUMPREG(HDMI_TG_FIELD_CHG_H);
509 DUMPREG(HDMI_TG_VACT_ST2_L);
510 DUMPREG(HDMI_TG_VACT_ST2_H);
511 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
512 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
513 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
514 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
515 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
516 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
517 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
518 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
519#undef DUMPREG
520}
521
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900522static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
523{
524 int i;
525
526#define DUMPREG(reg_id) \
527 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
528 readl(hdata->regs + reg_id))
529
530 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
531 DUMPREG(HDMI_INTC_CON);
532 DUMPREG(HDMI_INTC_FLAG);
533 DUMPREG(HDMI_HPD_STATUS);
534 DUMPREG(HDMI_INTC_CON_1);
535 DUMPREG(HDMI_INTC_FLAG_1);
536 DUMPREG(HDMI_PHY_STATUS_0);
537 DUMPREG(HDMI_PHY_STATUS_PLL);
538 DUMPREG(HDMI_PHY_CON_0);
539 DUMPREG(HDMI_PHY_RSTOUT);
540 DUMPREG(HDMI_PHY_VPLL);
541 DUMPREG(HDMI_PHY_CMU);
542 DUMPREG(HDMI_CORE_RSTOUT);
543
544 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
545 DUMPREG(HDMI_CON_0);
546 DUMPREG(HDMI_CON_1);
547 DUMPREG(HDMI_CON_2);
548 DUMPREG(HDMI_SYS_STATUS);
549 DUMPREG(HDMI_PHY_STATUS_0);
550 DUMPREG(HDMI_STATUS_EN);
551 DUMPREG(HDMI_HPD);
552 DUMPREG(HDMI_MODE_SEL);
553 DUMPREG(HDMI_ENC_EN);
554 DUMPREG(HDMI_DC_CONTROL);
555 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
556
557 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
558 DUMPREG(HDMI_H_BLANK_0);
559 DUMPREG(HDMI_H_BLANK_1);
560 DUMPREG(HDMI_V2_BLANK_0);
561 DUMPREG(HDMI_V2_BLANK_1);
562 DUMPREG(HDMI_V1_BLANK_0);
563 DUMPREG(HDMI_V1_BLANK_1);
564 DUMPREG(HDMI_V_LINE_0);
565 DUMPREG(HDMI_V_LINE_1);
566 DUMPREG(HDMI_H_LINE_0);
567 DUMPREG(HDMI_H_LINE_1);
568 DUMPREG(HDMI_HSYNC_POL);
569
570 DUMPREG(HDMI_VSYNC_POL);
571 DUMPREG(HDMI_INT_PRO_MODE);
572 DUMPREG(HDMI_V_BLANK_F0_0);
573 DUMPREG(HDMI_V_BLANK_F0_1);
574 DUMPREG(HDMI_V_BLANK_F1_0);
575 DUMPREG(HDMI_V_BLANK_F1_1);
576
577 DUMPREG(HDMI_H_SYNC_START_0);
578 DUMPREG(HDMI_H_SYNC_START_1);
579 DUMPREG(HDMI_H_SYNC_END_0);
580 DUMPREG(HDMI_H_SYNC_END_1);
581
582 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
583 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
584 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
585 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
586
587 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
588 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
589 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
590 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
591
592 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
593 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
594 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
595 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
596
597 DUMPREG(HDMI_V_BLANK_F2_0);
598 DUMPREG(HDMI_V_BLANK_F2_1);
599 DUMPREG(HDMI_V_BLANK_F3_0);
600 DUMPREG(HDMI_V_BLANK_F3_1);
601 DUMPREG(HDMI_V_BLANK_F4_0);
602 DUMPREG(HDMI_V_BLANK_F4_1);
603 DUMPREG(HDMI_V_BLANK_F5_0);
604 DUMPREG(HDMI_V_BLANK_F5_1);
605
606 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
607 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
608 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
609 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
610 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
611 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
612 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
613 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
614
615 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
616 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
617 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
618 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
619 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
620 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
621 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
622 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
623
624 DUMPREG(HDMI_VACT_SPACE_1_0);
625 DUMPREG(HDMI_VACT_SPACE_1_1);
626 DUMPREG(HDMI_VACT_SPACE_2_0);
627 DUMPREG(HDMI_VACT_SPACE_2_1);
628 DUMPREG(HDMI_VACT_SPACE_3_0);
629 DUMPREG(HDMI_VACT_SPACE_3_1);
630 DUMPREG(HDMI_VACT_SPACE_4_0);
631 DUMPREG(HDMI_VACT_SPACE_4_1);
632 DUMPREG(HDMI_VACT_SPACE_5_0);
633 DUMPREG(HDMI_VACT_SPACE_5_1);
634 DUMPREG(HDMI_VACT_SPACE_6_0);
635 DUMPREG(HDMI_VACT_SPACE_6_1);
636
637 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
638 DUMPREG(HDMI_TG_CMD);
639 DUMPREG(HDMI_TG_H_FSZ_L);
640 DUMPREG(HDMI_TG_H_FSZ_H);
641 DUMPREG(HDMI_TG_HACT_ST_L);
642 DUMPREG(HDMI_TG_HACT_ST_H);
643 DUMPREG(HDMI_TG_HACT_SZ_L);
644 DUMPREG(HDMI_TG_HACT_SZ_H);
645 DUMPREG(HDMI_TG_V_FSZ_L);
646 DUMPREG(HDMI_TG_V_FSZ_H);
647 DUMPREG(HDMI_TG_VSYNC_L);
648 DUMPREG(HDMI_TG_VSYNC_H);
649 DUMPREG(HDMI_TG_VSYNC2_L);
650 DUMPREG(HDMI_TG_VSYNC2_H);
651 DUMPREG(HDMI_TG_VACT_ST_L);
652 DUMPREG(HDMI_TG_VACT_ST_H);
653 DUMPREG(HDMI_TG_VACT_SZ_L);
654 DUMPREG(HDMI_TG_VACT_SZ_H);
655 DUMPREG(HDMI_TG_FIELD_CHG_L);
656 DUMPREG(HDMI_TG_FIELD_CHG_H);
657 DUMPREG(HDMI_TG_VACT_ST2_L);
658 DUMPREG(HDMI_TG_VACT_ST2_H);
659 DUMPREG(HDMI_TG_VACT_ST3_L);
660 DUMPREG(HDMI_TG_VACT_ST3_H);
661 DUMPREG(HDMI_TG_VACT_ST4_L);
662 DUMPREG(HDMI_TG_VACT_ST4_H);
663 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
664 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
665 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
666 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
667 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
668 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
669 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
670 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
671 DUMPREG(HDMI_TG_3D);
672
673 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
674 DUMPREG(HDMI_AVI_CON);
675 DUMPREG(HDMI_AVI_HEADER0);
676 DUMPREG(HDMI_AVI_HEADER1);
677 DUMPREG(HDMI_AVI_HEADER2);
678 DUMPREG(HDMI_AVI_CHECK_SUM);
679 DUMPREG(HDMI_VSI_CON);
680 DUMPREG(HDMI_VSI_HEADER0);
681 DUMPREG(HDMI_VSI_HEADER1);
682 DUMPREG(HDMI_VSI_HEADER2);
683 for (i = 0; i < 7; ++i)
684 DUMPREG(HDMI_VSI_DATA(i));
685
686#undef DUMPREG
687}
688
689static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
690{
Rahul Sharma5a325072012-10-04 20:48:54 +0530691 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900692 hdmi_v13_regs_dump(hdata, prefix);
693 else
694 hdmi_v14_regs_dump(hdata, prefix);
695}
696
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530697static u8 hdmi_chksum(struct hdmi_context *hdata,
698 u32 start, u8 len, u32 hdr_sum)
699{
700 int i;
701
702 /* hdr_sum : header0 + header1 + header2
703 * start : start address of packet byte1
704 * len : packet bytes - 1 */
705 for (i = 0; i < len; ++i)
706 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
707
708 /* return 2's complement of 8 bit hdr_sum */
709 return (u8)(~(hdr_sum & 0xff) + 1);
710}
711
712static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530713 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530714{
715 u32 hdr_sum;
716 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530717 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
Shirish S46154152014-03-13 10:58:28 +0530745 /*
746 * Set the aspect ratio as per the mode, mentioned in
747 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
748 */
749 switch (hdata->mode_conf.aspect_ratio) {
750 case HDMI_PICTURE_ASPECT_4_3:
751 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
752 hdata->mode_conf.aspect_ratio |
753 AVI_4_3_CENTER_RATIO);
754 break;
755 case HDMI_PICTURE_ASPECT_16_9:
756 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
757 hdata->mode_conf.aspect_ratio |
758 AVI_16_9_CENTER_RATIO);
759 break;
760 case HDMI_PICTURE_ASPECT_NONE:
761 default:
762 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
763 hdata->mode_conf.aspect_ratio |
764 AVI_SAME_AS_PIC_ASPECT_RATIO);
765 break;
766 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530767
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900768 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530769 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
770
771 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530772 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530773 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
774 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
775 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530776 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530777 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530778 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
779 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
780 infoframe->any.version);
781 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
782 hdr_sum = infoframe->any.type + infoframe->any.version +
783 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530784 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530785 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530786 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
787 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
788 break;
789 default:
790 break;
791 }
792}
793
Sean Paul45517892014-01-30 16:19:05 -0500794static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
795{
796 struct hdmi_context *hdata = ctx;
797
798 hdata->drm_dev = drm_dev;
799
800 return 0;
801}
802
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900803static bool hdmi_is_connected(void *ctx)
804{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900805 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900806
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900807 return hdata->hpd;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900808}
809
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500810static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900811{
812 struct edid *raw_edid;
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900813 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900814
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900815 if (!hdata->ddc_port)
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500816 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900817
818 raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500819 if (!raw_edid)
820 return ERR_PTR(-ENODEV);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900821
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500822 hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
823 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
824 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
825 raw_edid->width_cm, raw_edid->height_cm);
826
827 return raw_edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900828}
829
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900830static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900831{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900832 const struct hdmiphy_config *confs;
833 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900834
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900835 if (hdata->type == HDMI_TYPE13) {
836 confs = hdmiphy_v13_configs;
837 count = ARRAY_SIZE(hdmiphy_v13_configs);
838 } else if (hdata->type == HDMI_TYPE14) {
839 confs = hdmiphy_v14_configs;
840 count = ARRAY_SIZE(hdmiphy_v14_configs);
841 } else
842 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900843
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900844 for (i = 0; i < count; i++)
845 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500846 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500847
848 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
849 return -EINVAL;
850}
851
Rahul Sharma16844fb2013-06-10 14:50:00 +0530852static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900853{
Joonyoung Shimf9309d12012-04-05 20:49:22 +0900854 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900855 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900856
Rahul Sharma16844fb2013-06-10 14:50:00 +0530857 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
858 mode->hdisplay, mode->vdisplay, mode->vrefresh,
859 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
860 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900861
Rahul Sharma16844fb2013-06-10 14:50:00 +0530862 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900863 if (ret < 0)
864 return ret;
865 return 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900866}
867
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900868static void hdmi_set_acr(u32 freq, u8 *acr)
869{
870 u32 n, cts;
871
872 switch (freq) {
873 case 32000:
874 n = 4096;
875 cts = 27000;
876 break;
877 case 44100:
878 n = 6272;
879 cts = 30000;
880 break;
881 case 88200:
882 n = 12544;
883 cts = 30000;
884 break;
885 case 176400:
886 n = 25088;
887 cts = 30000;
888 break;
889 case 48000:
890 n = 6144;
891 cts = 27000;
892 break;
893 case 96000:
894 n = 12288;
895 cts = 27000;
896 break;
897 case 192000:
898 n = 24576;
899 cts = 27000;
900 break;
901 default:
902 n = 0;
903 cts = 0;
904 break;
905 }
906
907 acr[1] = cts >> 16;
908 acr[2] = cts >> 8 & 0xff;
909 acr[3] = cts & 0xff;
910
911 acr[4] = n >> 16;
912 acr[5] = n >> 8 & 0xff;
913 acr[6] = n & 0xff;
914}
915
916static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
917{
918 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
919 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
920 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
921 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
922 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
923 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
924 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
925 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
926 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
927
Rahul Sharma5a325072012-10-04 20:48:54 +0530928 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900929 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
930 else
931 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
932}
933
934static void hdmi_audio_init(struct hdmi_context *hdata)
935{
936 u32 sample_rate, bits_per_sample, frame_size_code;
937 u32 data_num, bit_ch, sample_frq;
938 u32 val;
939 u8 acr[7];
940
941 sample_rate = 44100;
942 bits_per_sample = 16;
943 frame_size_code = 0;
944
945 switch (bits_per_sample) {
946 case 20:
947 data_num = 2;
948 bit_ch = 1;
949 break;
950 case 24:
951 data_num = 3;
952 bit_ch = 1;
953 break;
954 default:
955 data_num = 1;
956 bit_ch = 0;
957 break;
958 }
959
960 hdmi_set_acr(sample_rate, acr);
961 hdmi_reg_acr(hdata, acr);
962
963 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
964 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
965 | HDMI_I2S_MUX_ENABLE);
966
967 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
968 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
969
970 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
971
972 sample_frq = (sample_rate == 44100) ? 0 :
973 (sample_rate == 48000) ? 2 :
974 (sample_rate == 32000) ? 3 :
975 (sample_rate == 96000) ? 0xa : 0x0;
976
977 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
978 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
979
980 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
981 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
982
983 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
984 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
985 | HDMI_I2S_SEL_LRCK(6));
986 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
987 | HDMI_I2S_SEL_SDATA2(4));
988 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
989 | HDMI_I2S_SEL_SDATA2(2));
990 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
991
992 /* I2S_CON_1 & 2 */
993 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
994 | HDMI_I2S_L_CH_LOW_POL);
995 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
996 | HDMI_I2S_SET_BIT_CH(bit_ch)
997 | HDMI_I2S_SET_SDATA_BIT(data_num)
998 | HDMI_I2S_BASIC_FORMAT);
999
1000 /* Configure register related to CUV information */
1001 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1002 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1003 | HDMI_I2S_COPYRIGHT
1004 | HDMI_I2S_LINEAR_PCM
1005 | HDMI_I2S_CONSUMER_FORMAT);
1006 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1007 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1008 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1009 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1010 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1011 HDMI_I2S_ORG_SMP_FREQ_44_1
1012 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1013 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1014
1015 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1016}
1017
1018static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1019{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001020 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001021 return;
1022
1023 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1024 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1025 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1026}
1027
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001028static void hdmi_conf_reset(struct hdmi_context *hdata)
1029{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001030 u32 reg;
1031
Rahul Sharma5a325072012-10-04 20:48:54 +05301032 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001033 reg = HDMI_V13_CORE_RSTOUT;
1034 else
1035 reg = HDMI_CORE_RSTOUT;
1036
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001037 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001038 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001039 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001040 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001041 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001042}
1043
1044static void hdmi_conf_init(struct hdmi_context *hdata)
1045{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301046 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301047
Sean Paul77006a72013-01-16 10:17:20 -05001048 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001049 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1050 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001051
1052 /* choose HDMI mode */
1053 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1054 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1055 /* disable bluescreen */
1056 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001057
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001058 if (hdata->dvi_mode) {
1059 /* choose DVI mode */
1060 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1061 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1062 hdmi_reg_writeb(hdata, HDMI_CON_2,
1063 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1064 }
1065
Rahul Sharma5a325072012-10-04 20:48:54 +05301066 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001067 /* choose bluescreen (fecal) color */
1068 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1069 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1070 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1071
1072 /* enable AVI packet every vsync, fixes purple line problem */
1073 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1074 /* force RGB, look to CEA-861-D, table 7 for more detail */
1075 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1076 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1077
1078 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1079 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1080 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1081 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301082 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1083 infoframe.any.version = HDMI_AVI_VERSION;
1084 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301085 hdmi_reg_infoframe(hdata, &infoframe);
1086
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301087 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1088 infoframe.any.version = HDMI_AUI_VERSION;
1089 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301090 hdmi_reg_infoframe(hdata, &infoframe);
1091
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001092 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001093 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1094 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001095}
1096
Rahul Sharma16844fb2013-06-10 14:50:00 +05301097static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001098{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001099 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1100 const struct hdmi_v13_core_regs *core =
1101 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001102 int tries;
1103
1104 /* setting core registers */
1105 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1106 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001107 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1108 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1109 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1110 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1111 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1112 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001113 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1114 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001115 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1116 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1117 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1118 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1119 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1120 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1121 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1122 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1123 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1124 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1125 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1126 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1127 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1128 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1129 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001130 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001131 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1132 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1133 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1134 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1135 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1136 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1137 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1138 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1139 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1140 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1141 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1142 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1143 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1144 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1145 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1146 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1147 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1148 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1149 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1150 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1151 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1152 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1153 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1154 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1155 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1156 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1157 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1158 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001159
1160 /* waiting for HDMIPHY's PLL to get to steady state */
1161 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001162 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001163 if (val & HDMI_PHY_STATUS_READY)
1164 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001165 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001166 }
1167 /* steady state not achieved */
1168 if (tries == 0) {
1169 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1170 hdmi_regs_dump(hdata, "timing apply");
1171 }
1172
Sean Paul0bfb1f82013-06-11 12:24:02 +05301173 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301174 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301175 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001176
1177 /* enable HDMI and timing generator */
1178 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1179 if (core->int_pro_mode[0])
1180 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1181 HDMI_FIELD_EN);
1182 else
1183 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1184}
1185
Rahul Sharma16844fb2013-06-10 14:50:00 +05301186static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001187{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001188 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1189 const struct hdmi_v14_core_regs *core =
1190 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001191 int tries;
1192
1193 /* setting core registers */
1194 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1195 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1196 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1197 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1198 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1199 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1200 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1201 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1202 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1203 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1204 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1205 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1206 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1207 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1208 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1209 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1210 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1211 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1212 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1213 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1214 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1215 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1216 core->v_sync_line_bef_2[0]);
1217 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1218 core->v_sync_line_bef_2[1]);
1219 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1220 core->v_sync_line_bef_1[0]);
1221 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1222 core->v_sync_line_bef_1[1]);
1223 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1224 core->v_sync_line_aft_2[0]);
1225 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1226 core->v_sync_line_aft_2[1]);
1227 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1228 core->v_sync_line_aft_1[0]);
1229 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1230 core->v_sync_line_aft_1[1]);
1231 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1232 core->v_sync_line_aft_pxl_2[0]);
1233 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1234 core->v_sync_line_aft_pxl_2[1]);
1235 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1236 core->v_sync_line_aft_pxl_1[0]);
1237 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1238 core->v_sync_line_aft_pxl_1[1]);
1239 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1240 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1241 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1242 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1243 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1244 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1245 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1246 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1247 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1248 core->v_sync_line_aft_3[0]);
1249 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1250 core->v_sync_line_aft_3[1]);
1251 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1252 core->v_sync_line_aft_4[0]);
1253 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1254 core->v_sync_line_aft_4[1]);
1255 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1256 core->v_sync_line_aft_5[0]);
1257 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1258 core->v_sync_line_aft_5[1]);
1259 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1260 core->v_sync_line_aft_6[0]);
1261 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1262 core->v_sync_line_aft_6[1]);
1263 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1264 core->v_sync_line_aft_pxl_3[0]);
1265 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1266 core->v_sync_line_aft_pxl_3[1]);
1267 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1268 core->v_sync_line_aft_pxl_4[0]);
1269 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1270 core->v_sync_line_aft_pxl_4[1]);
1271 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1272 core->v_sync_line_aft_pxl_5[0]);
1273 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1274 core->v_sync_line_aft_pxl_5[1]);
1275 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1276 core->v_sync_line_aft_pxl_6[0]);
1277 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1278 core->v_sync_line_aft_pxl_6[1]);
1279 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1280 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1281 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1282 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1283 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1284 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1285 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1286 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1287 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1288 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1289 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1290 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1291
1292 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001293 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1294 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1295 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1296 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1297 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1298 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1299 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1300 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1301 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1302 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1303 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1304 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1305 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1306 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1307 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1308 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1309 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1310 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1311 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1312 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1313 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1314 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1315 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1316 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1317 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1318 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1319 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1320 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1321 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1322 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1323 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1324 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1325 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001326
1327 /* waiting for HDMIPHY's PLL to get to steady state */
1328 for (tries = 100; tries; --tries) {
1329 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1330 if (val & HDMI_PHY_STATUS_READY)
1331 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001332 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001333 }
1334 /* steady state not achieved */
1335 if (tries == 0) {
1336 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1337 hdmi_regs_dump(hdata, "timing apply");
1338 }
1339
Sean Paul0bfb1f82013-06-11 12:24:02 +05301340 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301341 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301342 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001343
1344 /* enable HDMI and timing generator */
1345 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1346 if (core->int_pro_mode[0])
1347 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1348 HDMI_FIELD_EN);
1349 else
1350 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1351}
1352
Rahul Sharma16844fb2013-06-10 14:50:00 +05301353static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001354{
Rahul Sharma5a325072012-10-04 20:48:54 +05301355 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301356 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001357 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301358 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001359}
1360
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001361static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1362{
1363 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001364 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001365
Sean Paul0bfb1f82013-06-11 12:24:02 +05301366 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301367 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301368 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001369
1370 /* operation mode */
1371 buffer[0] = 0x1f;
1372 buffer[1] = 0x00;
1373
1374 if (hdata->hdmiphy_port)
1375 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1376
Rahul Sharma5a325072012-10-04 20:48:54 +05301377 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001378 reg = HDMI_V13_PHY_RSTOUT;
1379 else
1380 reg = HDMI_PHY_RSTOUT;
1381
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001382 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001383 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001384 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001385 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001386 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001387}
1388
Rahul Sharmaa5562252012-11-28 11:30:25 +05301389static void hdmiphy_poweron(struct hdmi_context *hdata)
1390{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301391 if (hdata->type == HDMI_TYPE14)
1392 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1393 HDMI_PHY_POWER_OFF_EN);
1394}
1395
1396static void hdmiphy_poweroff(struct hdmi_context *hdata)
1397{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301398 if (hdata->type == HDMI_TYPE14)
1399 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1400 HDMI_PHY_POWER_OFF_EN);
1401}
1402
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001403static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1404{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001405 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001406 u8 buffer[32];
1407 u8 operation[2];
1408 u8 read_buffer[32] = {0, };
1409 int ret;
1410 int i;
1411
1412 if (!hdata->hdmiphy_port) {
1413 DRM_ERROR("hdmiphy is not attached\n");
1414 return;
1415 }
1416
1417 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001418 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1419 if (i < 0) {
1420 DRM_ERROR("failed to find hdmiphy conf\n");
1421 return;
1422 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001423
Sachin Kamat5f46c332013-04-26 11:29:00 +05301424 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001425 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301426 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001427 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001428
1429 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001430 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1431 if (ret != 32) {
1432 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1433 return;
1434 }
1435
Sean Paul09760ea2013-01-14 17:03:20 -05001436 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001437
1438 /* operation mode */
1439 operation[0] = 0x1f;
1440 operation[1] = 0x80;
1441
1442 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1443 if (ret != 2) {
1444 DRM_ERROR("failed to enable hdmiphy\n");
1445 return;
1446 }
1447
1448 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1449 if (ret < 0) {
1450 DRM_ERROR("failed to read hdmiphy config\n");
1451 return;
1452 }
1453
1454 for (i = 0; i < ret; i++)
1455 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1456 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1457}
1458
1459static void hdmi_conf_apply(struct hdmi_context *hdata)
1460{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001461 hdmiphy_conf_reset(hdata);
1462 hdmiphy_conf_apply(hdata);
1463
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001464 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001465 hdmi_conf_reset(hdata);
1466 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001467 mutex_unlock(&hdata->hdmi_mutex);
1468
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001469 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001470
1471 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301472 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001473 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001474
1475 hdmi_regs_dump(hdata, "start");
1476}
1477
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001478static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1479{
1480 int i;
1481 BUG_ON(num_bytes > 4);
1482 for (i = 0; i < num_bytes; i++)
1483 reg_pair[i] = (value >> (8 * i)) & 0xff;
1484}
1485
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001486static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1487 struct drm_display_mode *m)
1488{
1489 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1490 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1491 unsigned int val;
1492
1493 hdata->mode_conf.cea_video_id =
1494 drm_match_cea_mode((struct drm_display_mode *)m);
1495 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301496 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001497
1498 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1499 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1500
1501 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1502 hdmi_set_reg(core->vsync_pol, 1, val);
1503
1504 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1505 hdmi_set_reg(core->int_pro_mode, 1, val);
1506
1507 val = (m->hsync_start - m->hdisplay - 2);
1508 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1509 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1510 hdmi_set_reg(core->h_sync_gen, 3, val);
1511
1512 /*
1513 * Quirk requirement for exynos HDMI IP design,
1514 * 2 pixels less than the actual calculation for hsync_start
1515 * and end.
1516 */
1517
1518 /* Following values & calculations differ for different type of modes */
1519 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1520 /* Interlaced Mode */
1521 val = ((m->vsync_end - m->vdisplay) / 2);
1522 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1523 hdmi_set_reg(core->v_sync_gen1, 3, val);
1524
1525 val = m->vtotal / 2;
1526 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1527 hdmi_set_reg(core->v_blank, 3, val);
1528
1529 val = (m->vtotal +
1530 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1531 val |= m->vtotal << 11;
1532 hdmi_set_reg(core->v_blank_f, 3, val);
1533
1534 val = ((m->vtotal / 2) + 7);
1535 val |= ((m->vtotal / 2) + 2) << 12;
1536 hdmi_set_reg(core->v_sync_gen2, 3, val);
1537
1538 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1539 val |= ((m->htotal / 2) +
1540 (m->hsync_start - m->hdisplay)) << 12;
1541 hdmi_set_reg(core->v_sync_gen3, 3, val);
1542
1543 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1544 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1545
1546 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1547 } else {
1548 /* Progressive Mode */
1549
1550 val = m->vtotal;
1551 val |= (m->vtotal - m->vdisplay) << 11;
1552 hdmi_set_reg(core->v_blank, 3, val);
1553
1554 hdmi_set_reg(core->v_blank_f, 3, 0);
1555
1556 val = (m->vsync_end - m->vdisplay);
1557 val |= ((m->vsync_start - m->vdisplay) << 12);
1558 hdmi_set_reg(core->v_sync_gen1, 3, val);
1559
1560 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1561 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1562 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1563 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1564 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1565 }
1566
1567 /* Timing generator registers */
1568 hdmi_set_reg(tg->cmd, 1, 0x0);
1569 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1570 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1571 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1572 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1573 hdmi_set_reg(tg->vsync, 2, 0x1);
1574 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1575 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1576 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1577 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1578 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1579 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1580 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1581}
1582
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001583static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1584 struct drm_display_mode *m)
1585{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001586 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1587 struct hdmi_v14_core_regs *core =
1588 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001589
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001590 hdata->mode_conf.cea_video_id =
1591 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001592 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301593 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001594
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001595 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1596 hdmi_set_reg(core->v_line, 2, m->vtotal);
1597 hdmi_set_reg(core->h_line, 2, m->htotal);
1598 hdmi_set_reg(core->hsync_pol, 1,
1599 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1600 hdmi_set_reg(core->vsync_pol, 1,
1601 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1602 hdmi_set_reg(core->int_pro_mode, 1,
1603 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1604
1605 /*
1606 * Quirk requirement for exynos 5 HDMI IP design,
1607 * 2 pixels less than the actual calculation for hsync_start
1608 * and end.
1609 */
1610
1611 /* Following values & calculations differ for different type of modes */
1612 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1613 /* Interlaced Mode */
1614 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1615 (m->vsync_end - m->vdisplay) / 2);
1616 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1617 (m->vsync_start - m->vdisplay) / 2);
1618 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1619 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301620 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001621 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1622 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1623 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1624 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1625 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1626 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1627 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1628 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1629 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301630 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1631 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1632 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1633 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001634 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1635 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1636 } else {
1637 /* Progressive Mode */
1638 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1639 m->vsync_end - m->vdisplay);
1640 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1641 m->vsync_start - m->vdisplay);
1642 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1643 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1644 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1645 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1646 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1647 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1648 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1649 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1650 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1651 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1652 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1653 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1654 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301655 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1656 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1657 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001658 }
1659
1660 /* Following values & calculations are same irrespective of mode type */
1661 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1662 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1663 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1664 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1665 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1666 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1667 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1668 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1669 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1670 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1671 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1672 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1673 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1674 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1675 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1676 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1677 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1678 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1679 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1680 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1681
1682 /* Timing generator registers */
1683 hdmi_set_reg(tg->cmd, 1, 0x0);
1684 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1685 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1686 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1687 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1688 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001689 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1690 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001691 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001692 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001693}
1694
Rahul Sharma16844fb2013-06-10 14:50:00 +05301695static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001696{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001697 struct hdmi_context *hdata = ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001698 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001699
YoungJun Chocbc4c332013-06-12 10:44:40 +09001700 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1701 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001702 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1703 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001704
Sachin Kamat5f46c332013-04-26 11:29:00 +05301705 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001706 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301707 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001708 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001709}
1710
Inki Dae1de425b2012-03-16 18:47:04 +09001711static void hdmi_get_max_resol(void *ctx, unsigned int *width,
1712 unsigned int *height)
1713{
Inki Dae1de425b2012-03-16 18:47:04 +09001714 *width = MAX_WIDTH;
1715 *height = MAX_HEIGHT;
1716}
1717
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001718static void hdmi_commit(void *ctx)
1719{
Joonyoung Shimf9309d12012-04-05 20:49:22 +09001720 struct hdmi_context *hdata = ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001721
Shirish Sdda90122013-01-23 22:03:18 -05001722 mutex_lock(&hdata->hdmi_mutex);
1723 if (!hdata->powered) {
1724 mutex_unlock(&hdata->hdmi_mutex);
1725 return;
1726 }
1727 mutex_unlock(&hdata->hdmi_mutex);
1728
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001729 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001730}
1731
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001732static void hdmi_poweron(struct hdmi_context *hdata)
1733{
1734 struct hdmi_resources *res = &hdata->res;
1735
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001736 mutex_lock(&hdata->hdmi_mutex);
1737 if (hdata->powered) {
1738 mutex_unlock(&hdata->hdmi_mutex);
1739 return;
1740 }
1741
1742 hdata->powered = true;
1743
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001744 mutex_unlock(&hdata->hdmi_mutex);
1745
Seung-Woo Kimad079452013-06-05 14:34:38 +09001746 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1747 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1748
Sean Paul0bfb1f82013-06-11 12:24:02 +05301749 clk_prepare_enable(res->hdmiphy);
1750 clk_prepare_enable(res->hdmi);
1751 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301752
1753 hdmiphy_poweron(hdata);
Sean Paul87244fa2014-01-30 16:19:07 -05001754 hdmi_commit(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,
Sean Paul54c40de2014-01-30 16:19:09 -05001815 .dpms = hdmi_dpms,
Joonyoung Shim578b6062012-04-05 20:49:26 +09001816
1817 /* manager */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001818 .mode_set = hdmi_mode_set,
Inki Dae1de425b2012-03-16 18:47:04 +09001819 .get_max_resol = hdmi_get_max_resol,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001820 .commit = hdmi_commit,
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
Rahul Sharma22c4f422012-10-04 20:48:55 +05301909static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
1910 (struct device *dev)
1911{
1912 struct device_node *np = dev->of_node;
1913 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301914 u32 value;
1915
1916 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001917 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05301918 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301919
1920 if (!of_find_property(np, "hpd-gpio", &value)) {
1921 DRM_ERROR("no hpd gpio property found\n");
1922 goto err_data;
1923 }
1924
Rahul Sharma5f916e22013-06-11 19:41:29 +05301925 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05301926
1927 return pd;
1928
1929err_data:
1930 return NULL;
1931}
Rahul Sharma22c4f422012-10-04 20:48:55 +05301932
Rahul Sharma22c4f422012-10-04 20:48:55 +05301933static struct of_device_id hdmi_match_types[] = {
1934 {
1935 .compatible = "samsung,exynos5-hdmi",
1936 .data = (void *)HDMI_TYPE14,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301937 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05301938 .compatible = "samsung,exynos4212-hdmi",
1939 .data = (void *)HDMI_TYPE14,
1940 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05301941 /* end node */
1942 }
1943};
1944
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001945static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001946{
1947 struct device *dev = &pdev->dev;
1948 struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1949 struct hdmi_context *hdata;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301950 struct s5p_hdmi_platform_data *pdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001951 struct resource *res;
Sachin Kamat88c49812013-08-28 10:47:57 +05301952 const struct of_device_id *match;
Daniel Kurtz2b768132014-02-24 18:52:51 +09001953 struct device_node *ddc_node, *phy_node;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001954 int ret;
1955
Sachin Kamat88c49812013-08-28 10:47:57 +05301956 if (!dev->of_node)
1957 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301958
Sachin Kamat88c49812013-08-28 10:47:57 +05301959 pdata = drm_hdmi_dt_parse_pdata(dev);
1960 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001961 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001962
Sachin Kamat88c49812013-08-28 10:47:57 +05301963 drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001964 if (!drm_hdmi_ctx)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001965 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001966
Sachin Kamat88c49812013-08-28 10:47:57 +05301967 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001968 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001969 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001970
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001971 mutex_init(&hdata->hdmi_mutex);
1972
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001973 drm_hdmi_ctx->ctx = (void *)hdata;
1974 hdata->parent_ctx = (void *)drm_hdmi_ctx;
1975
1976 platform_set_drvdata(pdev, drm_hdmi_ctx);
1977
Sachin Kamat88c49812013-08-28 10:47:57 +05301978 match = of_match_node(hdmi_match_types, dev->of_node);
1979 if (!match)
1980 return -ENODEV;
1981 hdata->type = (enum hdmi_type)match->data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05301982
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301983 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984 hdata->dev = dev;
1985
1986 ret = hdmi_resources_init(hdata);
1987 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05301988 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301989 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001990 }
1991
1992 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001993 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01001994 if (IS_ERR(hdata->regs))
1995 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001996
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09001997 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301998 if (ret) {
1999 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302000 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302001 }
2002
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002003 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002004 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2005 if (!ddc_node) {
2006 DRM_ERROR("Failed to find ddc node in device tree\n");
2007 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002008 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002009 hdata->ddc_port = of_find_i2c_device_by_node(ddc_node);
2010 if (!hdata->ddc_port) {
2011 DRM_ERROR("Failed to get ddc i2c client by node\n");
2012 return -ENODEV;
2013 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002014
2015 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002016 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2017 if (!phy_node) {
2018 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2019 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002020 goto err_ddc;
2021 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002022 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2023 if (!hdata->hdmiphy_port) {
2024 DRM_ERROR("Failed to get hdmi phy i2c client from node\n");
2025 ret = -ENODEV;
2026 goto err_ddc;
2027 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002028
Sean Paul77006a72013-01-16 10:17:20 -05002029 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2030 if (hdata->irq < 0) {
2031 DRM_ERROR("failed to get GPIO irq\n");
2032 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002033 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002034 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002035
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302036 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2037
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002038 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002039 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002040 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paul77006a72013-01-16 10:17:20 -05002041 "hdmi", drm_hdmi_ctx);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002042 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002043 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002044 goto err_hdmiphy;
2045 }
2046
Rahul Sharma768c3052012-10-04 20:48:56 +05302047 /* Attach HDMI Driver to common hdmi. */
2048 exynos_hdmi_drv_attach(drm_hdmi_ctx);
2049
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002050 /* register specific callbacks to common hdmi. */
Joonyoung Shim578b6062012-04-05 20:49:26 +09002051 exynos_hdmi_ops_register(&hdmi_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002052
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002053 pm_runtime_enable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002054
2055 return 0;
2056
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002057err_hdmiphy:
Daniel Kurtz2b768132014-02-24 18:52:51 +09002058 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002059err_ddc:
Daniel Kurtz2b768132014-02-24 18:52:51 +09002060 put_device(&hdata->ddc_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002061 return ret;
2062}
2063
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002064static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002065{
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002066 struct device *dev = &pdev->dev;
Daniel Kurtz2b768132014-02-24 18:52:51 +09002067 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2068 struct hdmi_context *hdata = ctx->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002069
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002070 pm_runtime_disable(dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002071
Daniel Kurtz2b768132014-02-24 18:52:51 +09002072 put_device(&hdata->hdmiphy_port->dev);
2073 put_device(&hdata->ddc_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002074
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002075 return 0;
2076}
2077
Joonyoung Shimab27af82012-04-23 19:35:51 +09002078#ifdef CONFIG_PM_SLEEP
2079static int hdmi_suspend(struct device *dev)
2080{
2081 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2082 struct hdmi_context *hdata = ctx->ctx;
2083
Sean Paul77006a72013-01-16 10:17:20 -05002084 disable_irq(hdata->irq);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002085
2086 hdata->hpd = false;
Sean Paul45517892014-01-30 16:19:05 -05002087 if (hdata->drm_dev)
2088 drm_helper_hpd_irq_event(hdata->drm_dev);
Joonyoung Shimab27af82012-04-23 19:35:51 +09002089
Rahul Sharma64327cb2012-11-28 11:30:23 +05302090 if (pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002091 DRM_DEBUG_KMS("Already suspended\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302092 return 0;
2093 }
2094
Joonyoung Shimab27af82012-04-23 19:35:51 +09002095 hdmi_poweroff(hdata);
2096
2097 return 0;
2098}
2099
2100static int hdmi_resume(struct device *dev)
2101{
2102 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2103 struct hdmi_context *hdata = ctx->ctx;
2104
Rahul Sharma64327cb2012-11-28 11:30:23 +05302105 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2106
Sean Paul77006a72013-01-16 10:17:20 -05002107 enable_irq(hdata->irq);
Rahul Sharma64327cb2012-11-28 11:30:23 +05302108
2109 if (!pm_runtime_suspended(dev)) {
YoungJun Chocbc4c332013-06-12 10:44:40 +09002110 DRM_DEBUG_KMS("Already resumed\n");
Rahul Sharma64327cb2012-11-28 11:30:23 +05302111 return 0;
2112 }
2113
2114 hdmi_poweron(hdata);
2115
Joonyoung Shimab27af82012-04-23 19:35:51 +09002116 return 0;
2117}
2118#endif
2119
Rahul Sharma64327cb2012-11-28 11:30:23 +05302120#ifdef CONFIG_PM_RUNTIME
2121static int hdmi_runtime_suspend(struct device *dev)
2122{
2123 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2124 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302125
2126 hdmi_poweroff(hdata);
2127
2128 return 0;
2129}
2130
2131static int hdmi_runtime_resume(struct device *dev)
2132{
2133 struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
2134 struct hdmi_context *hdata = ctx->ctx;
Rahul Sharma64327cb2012-11-28 11:30:23 +05302135
2136 hdmi_poweron(hdata);
2137
2138 return 0;
2139}
2140#endif
2141
2142static const struct dev_pm_ops hdmi_pm_ops = {
2143 SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
2144 SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
2145};
Joonyoung Shimab27af82012-04-23 19:35:51 +09002146
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002147struct platform_driver hdmi_driver = {
2148 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002149 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002150 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302151 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002152 .owner = THIS_MODULE,
Joonyoung Shimab27af82012-04-23 19:35:51 +09002153 .pm = &hdmi_pm_ops,
Sachin Kamat88c49812013-08-28 10:47:57 +05302154 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002155 },
2156};