blob: 13c783a2ee014f1b85ac57b01a1cdde1ef094e5d [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>
Inki Daef37cd5e2014-05-09 14:25:20 +090039#include <linux/component.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090040
41#include <drm/exynos_drm.h>
42
43#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090044#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050045#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090046
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053047#include <linux/gpio.h>
48#include <media/s5p_hdmi.h>
49
Sean Paulf041b252014-01-30 16:19:15 -050050#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev))
Sean Pauld9716ee2014-01-30 16:19:29 -050051#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090052
Sean Paul724fd142014-05-09 15:05:10 +090053#define HOTPLUG_DEBOUNCE_MS 1100
54
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053055/* AVI header and aspect ratio */
56#define HDMI_AVI_VERSION 0x02
57#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053058
59/* AUI header info */
60#define HDMI_AUI_VERSION 0x01
61#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053062#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
63#define AVI_4_3_CENTER_RATIO 0x9
64#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053065
Rahul Sharma5a325072012-10-04 20:48:54 +053066enum hdmi_type {
67 HDMI_TYPE13,
68 HDMI_TYPE14,
69};
70
Inki Daebfe4e842014-03-06 14:18:17 +090071struct hdmi_driver_data {
72 unsigned int type;
73 unsigned int is_apb_phy:1;
74};
75
Joonyoung Shim590f4182012-03-16 18:47:14 +090076struct hdmi_resources {
77 struct clk *hdmi;
78 struct clk *sclk_hdmi;
79 struct clk *sclk_pixel;
80 struct clk *sclk_hdmiphy;
81 struct clk *hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053082 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090083 struct regulator_bulk_data *regul_bulk;
84 int regul_count;
85};
86
Sean Paul2f7e2ed2013-01-15 08:11:08 -050087struct hdmi_tg_regs {
88 u8 cmd[1];
89 u8 h_fsz[2];
90 u8 hact_st[2];
91 u8 hact_sz[2];
92 u8 v_fsz[2];
93 u8 vsync[2];
94 u8 vsync2[2];
95 u8 vact_st[2];
96 u8 vact_sz[2];
97 u8 field_chg[2];
98 u8 vact_st2[2];
99 u8 vact_st3[2];
100 u8 vact_st4[2];
101 u8 vsync_top_hdmi[2];
102 u8 vsync_bot_hdmi[2];
103 u8 field_top_hdmi[2];
104 u8 field_bot_hdmi[2];
105 u8 tg_3d[1];
106};
107
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900108struct hdmi_v13_core_regs {
109 u8 h_blank[2];
110 u8 v_blank[3];
111 u8 h_v_line[3];
112 u8 vsync_pol[1];
113 u8 int_pro_mode[1];
114 u8 v_blank_f[3];
115 u8 h_sync_gen[3];
116 u8 v_sync_gen1[3];
117 u8 v_sync_gen2[3];
118 u8 v_sync_gen3[3];
119};
120
121struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500122 u8 h_blank[2];
123 u8 v2_blank[2];
124 u8 v1_blank[2];
125 u8 v_line[2];
126 u8 h_line[2];
127 u8 hsync_pol[1];
128 u8 vsync_pol[1];
129 u8 int_pro_mode[1];
130 u8 v_blank_f0[2];
131 u8 v_blank_f1[2];
132 u8 h_sync_start[2];
133 u8 h_sync_end[2];
134 u8 v_sync_line_bef_2[2];
135 u8 v_sync_line_bef_1[2];
136 u8 v_sync_line_aft_2[2];
137 u8 v_sync_line_aft_1[2];
138 u8 v_sync_line_aft_pxl_2[2];
139 u8 v_sync_line_aft_pxl_1[2];
140 u8 v_blank_f2[2]; /* for 3D mode */
141 u8 v_blank_f3[2]; /* for 3D mode */
142 u8 v_blank_f4[2]; /* for 3D mode */
143 u8 v_blank_f5[2]; /* for 3D mode */
144 u8 v_sync_line_aft_3[2];
145 u8 v_sync_line_aft_4[2];
146 u8 v_sync_line_aft_5[2];
147 u8 v_sync_line_aft_6[2];
148 u8 v_sync_line_aft_pxl_3[2];
149 u8 v_sync_line_aft_pxl_4[2];
150 u8 v_sync_line_aft_pxl_5[2];
151 u8 v_sync_line_aft_pxl_6[2];
152 u8 vact_space_1[2];
153 u8 vact_space_2[2];
154 u8 vact_space_3[2];
155 u8 vact_space_4[2];
156 u8 vact_space_5[2];
157 u8 vact_space_6[2];
158};
159
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900160struct hdmi_v13_conf {
161 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500162 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163};
164
165struct hdmi_v14_conf {
166 struct hdmi_v14_core_regs core;
167 struct hdmi_tg_regs tg;
168};
169
170struct hdmi_conf_regs {
171 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500172 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530173 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900174 union {
175 struct hdmi_v13_conf v13_conf;
176 struct hdmi_v14_conf v14_conf;
177 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500178};
179
Joonyoung Shim590f4182012-03-16 18:47:14 +0900180struct hdmi_context {
181 struct device *dev;
182 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500183 struct drm_connector connector;
184 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900185 bool hpd;
186 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900187 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900188 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900189
Joonyoung Shim590f4182012-03-16 18:47:14 +0900190 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500191 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900192 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900193
Inki Dae8fa04aa2014-03-13 16:38:31 +0900194 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900195 struct i2c_client *hdmiphy_port;
196
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900197 /* current hdmiphy conf regs */
198 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900199
200 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900201
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530202 int hpd_gpio;
Rahul Sharma5a325072012-10-04 20:48:54 +0530203
204 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900205};
206
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500207struct hdmiphy_config {
208 int pixel_clock;
209 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900210};
211
Jingoo Han153df692014-04-17 19:07:42 +0900212static struct hdmi_driver_data exynos4212_hdmi_driver_data = {
Inki Daebfe4e842014-03-06 14:18:17 +0900213 .type = HDMI_TYPE14,
214};
215
Jingoo Han153df692014-04-17 19:07:42 +0900216static struct hdmi_driver_data exynos5_hdmi_driver_data = {
Inki Daebfe4e842014-03-06 14:18:17 +0900217 .type = HDMI_TYPE14,
218};
219
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900220/* list of phy config settings */
221static const struct hdmiphy_config hdmiphy_v13_configs[] = {
222 {
223 .pixel_clock = 27000000,
224 .conf = {
225 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
226 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
227 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
228 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
229 },
230 },
231 {
232 .pixel_clock = 27027000,
233 .conf = {
234 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
235 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
236 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
237 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
238 },
239 },
240 {
241 .pixel_clock = 74176000,
242 .conf = {
243 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
244 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
245 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
246 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
247 },
248 },
249 {
250 .pixel_clock = 74250000,
251 .conf = {
252 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
253 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
254 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
255 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
256 },
257 },
258 {
259 .pixel_clock = 148500000,
260 .conf = {
261 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
262 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
263 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
264 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
265 },
266 },
267};
268
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500269static const struct hdmiphy_config hdmiphy_v14_configs[] = {
270 {
271 .pixel_clock = 25200000,
272 .conf = {
273 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
274 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
275 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
276 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
277 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900278 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500279 {
280 .pixel_clock = 27000000,
281 .conf = {
282 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
283 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
284 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
285 0x54, 0xe4, 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 = 27027000,
290 .conf = {
291 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
292 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
293 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
294 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
295 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900296 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500297 {
298 .pixel_clock = 36000000,
299 .conf = {
300 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
301 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
302 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
303 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
304 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900305 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500306 {
307 .pixel_clock = 40000000,
308 .conf = {
309 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
310 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
311 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
312 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
313 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900314 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500315 {
316 .pixel_clock = 65000000,
317 .conf = {
318 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
319 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
320 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
321 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
322 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900323 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500324 {
Shirish Se1d883c2014-03-13 14:28:27 +0900325 .pixel_clock = 71000000,
326 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530327 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
328 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
329 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900330 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
331 },
332 },
333 {
334 .pixel_clock = 73250000,
335 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530336 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
337 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
338 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900339 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
340 },
341 },
342 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500343 .pixel_clock = 74176000,
344 .conf = {
345 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
346 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
347 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
348 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
349 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900350 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500351 {
352 .pixel_clock = 74250000,
353 .conf = {
354 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
355 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
356 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
357 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
358 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900359 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500360 {
361 .pixel_clock = 83500000,
362 .conf = {
363 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
364 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
365 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
366 0x54, 0x93, 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 = 106500000,
371 .conf = {
372 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
373 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
374 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
375 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
376 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900377 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500378 {
379 .pixel_clock = 108000000,
380 .conf = {
381 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
382 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
383 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
384 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
385 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900386 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500387 {
Shirish Se1d883c2014-03-13 14:28:27 +0900388 .pixel_clock = 115500000,
389 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530390 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
391 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
392 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900393 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
394 },
395 },
396 {
397 .pixel_clock = 119000000,
398 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530399 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
400 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
401 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900402 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
403 },
404 },
405 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500406 .pixel_clock = 146250000,
407 .conf = {
408 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
409 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
410 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
411 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
412 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900413 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500414 {
415 .pixel_clock = 148500000,
416 .conf = {
417 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
418 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
419 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
420 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
421 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900422 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900423};
424
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900425static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
426{
427 return readl(hdata->regs + reg_id);
428}
429
430static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
431 u32 reg_id, u8 value)
432{
433 writeb(value, hdata->regs + reg_id);
434}
435
436static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
437 u32 reg_id, u32 value, u32 mask)
438{
439 u32 old = readl(hdata->regs + reg_id);
440 value = (value & mask) | (old & ~mask);
441 writel(value, hdata->regs + reg_id);
442}
443
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900444static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900445{
446#define DUMPREG(reg_id) \
447 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
448 readl(hdata->regs + reg_id))
449 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
450 DUMPREG(HDMI_INTC_FLAG);
451 DUMPREG(HDMI_INTC_CON);
452 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900453 DUMPREG(HDMI_V13_PHY_RSTOUT);
454 DUMPREG(HDMI_V13_PHY_VPLL);
455 DUMPREG(HDMI_V13_PHY_CMU);
456 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900457
458 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
459 DUMPREG(HDMI_CON_0);
460 DUMPREG(HDMI_CON_1);
461 DUMPREG(HDMI_CON_2);
462 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900463 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900464 DUMPREG(HDMI_STATUS_EN);
465 DUMPREG(HDMI_HPD);
466 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900467 DUMPREG(HDMI_V13_HPD_GEN);
468 DUMPREG(HDMI_V13_DC_CONTROL);
469 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900470
471 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
472 DUMPREG(HDMI_H_BLANK_0);
473 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900474 DUMPREG(HDMI_V13_V_BLANK_0);
475 DUMPREG(HDMI_V13_V_BLANK_1);
476 DUMPREG(HDMI_V13_V_BLANK_2);
477 DUMPREG(HDMI_V13_H_V_LINE_0);
478 DUMPREG(HDMI_V13_H_V_LINE_1);
479 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900480 DUMPREG(HDMI_VSYNC_POL);
481 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900482 DUMPREG(HDMI_V13_V_BLANK_F_0);
483 DUMPREG(HDMI_V13_V_BLANK_F_1);
484 DUMPREG(HDMI_V13_V_BLANK_F_2);
485 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
486 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
487 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
488 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
489 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
490 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
491 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
492 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
493 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
494 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
495 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
496 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900497
498 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
499 DUMPREG(HDMI_TG_CMD);
500 DUMPREG(HDMI_TG_H_FSZ_L);
501 DUMPREG(HDMI_TG_H_FSZ_H);
502 DUMPREG(HDMI_TG_HACT_ST_L);
503 DUMPREG(HDMI_TG_HACT_ST_H);
504 DUMPREG(HDMI_TG_HACT_SZ_L);
505 DUMPREG(HDMI_TG_HACT_SZ_H);
506 DUMPREG(HDMI_TG_V_FSZ_L);
507 DUMPREG(HDMI_TG_V_FSZ_H);
508 DUMPREG(HDMI_TG_VSYNC_L);
509 DUMPREG(HDMI_TG_VSYNC_H);
510 DUMPREG(HDMI_TG_VSYNC2_L);
511 DUMPREG(HDMI_TG_VSYNC2_H);
512 DUMPREG(HDMI_TG_VACT_ST_L);
513 DUMPREG(HDMI_TG_VACT_ST_H);
514 DUMPREG(HDMI_TG_VACT_SZ_L);
515 DUMPREG(HDMI_TG_VACT_SZ_H);
516 DUMPREG(HDMI_TG_FIELD_CHG_L);
517 DUMPREG(HDMI_TG_FIELD_CHG_H);
518 DUMPREG(HDMI_TG_VACT_ST2_L);
519 DUMPREG(HDMI_TG_VACT_ST2_H);
520 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
521 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
522 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
523 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
524 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
525 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
526 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
527 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
528#undef DUMPREG
529}
530
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900531static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
532{
533 int i;
534
535#define DUMPREG(reg_id) \
536 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
537 readl(hdata->regs + reg_id))
538
539 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
540 DUMPREG(HDMI_INTC_CON);
541 DUMPREG(HDMI_INTC_FLAG);
542 DUMPREG(HDMI_HPD_STATUS);
543 DUMPREG(HDMI_INTC_CON_1);
544 DUMPREG(HDMI_INTC_FLAG_1);
545 DUMPREG(HDMI_PHY_STATUS_0);
546 DUMPREG(HDMI_PHY_STATUS_PLL);
547 DUMPREG(HDMI_PHY_CON_0);
548 DUMPREG(HDMI_PHY_RSTOUT);
549 DUMPREG(HDMI_PHY_VPLL);
550 DUMPREG(HDMI_PHY_CMU);
551 DUMPREG(HDMI_CORE_RSTOUT);
552
553 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
554 DUMPREG(HDMI_CON_0);
555 DUMPREG(HDMI_CON_1);
556 DUMPREG(HDMI_CON_2);
557 DUMPREG(HDMI_SYS_STATUS);
558 DUMPREG(HDMI_PHY_STATUS_0);
559 DUMPREG(HDMI_STATUS_EN);
560 DUMPREG(HDMI_HPD);
561 DUMPREG(HDMI_MODE_SEL);
562 DUMPREG(HDMI_ENC_EN);
563 DUMPREG(HDMI_DC_CONTROL);
564 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
565
566 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
567 DUMPREG(HDMI_H_BLANK_0);
568 DUMPREG(HDMI_H_BLANK_1);
569 DUMPREG(HDMI_V2_BLANK_0);
570 DUMPREG(HDMI_V2_BLANK_1);
571 DUMPREG(HDMI_V1_BLANK_0);
572 DUMPREG(HDMI_V1_BLANK_1);
573 DUMPREG(HDMI_V_LINE_0);
574 DUMPREG(HDMI_V_LINE_1);
575 DUMPREG(HDMI_H_LINE_0);
576 DUMPREG(HDMI_H_LINE_1);
577 DUMPREG(HDMI_HSYNC_POL);
578
579 DUMPREG(HDMI_VSYNC_POL);
580 DUMPREG(HDMI_INT_PRO_MODE);
581 DUMPREG(HDMI_V_BLANK_F0_0);
582 DUMPREG(HDMI_V_BLANK_F0_1);
583 DUMPREG(HDMI_V_BLANK_F1_0);
584 DUMPREG(HDMI_V_BLANK_F1_1);
585
586 DUMPREG(HDMI_H_SYNC_START_0);
587 DUMPREG(HDMI_H_SYNC_START_1);
588 DUMPREG(HDMI_H_SYNC_END_0);
589 DUMPREG(HDMI_H_SYNC_END_1);
590
591 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
592 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
593 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
594 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
595
596 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
597 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
598 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
599 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
600
601 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
602 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
603 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
604 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
605
606 DUMPREG(HDMI_V_BLANK_F2_0);
607 DUMPREG(HDMI_V_BLANK_F2_1);
608 DUMPREG(HDMI_V_BLANK_F3_0);
609 DUMPREG(HDMI_V_BLANK_F3_1);
610 DUMPREG(HDMI_V_BLANK_F4_0);
611 DUMPREG(HDMI_V_BLANK_F4_1);
612 DUMPREG(HDMI_V_BLANK_F5_0);
613 DUMPREG(HDMI_V_BLANK_F5_1);
614
615 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
616 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
617 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
618 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
619 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
620 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
621 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
622 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
623
624 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
625 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
626 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
627 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
628 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
629 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
630 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
631 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
632
633 DUMPREG(HDMI_VACT_SPACE_1_0);
634 DUMPREG(HDMI_VACT_SPACE_1_1);
635 DUMPREG(HDMI_VACT_SPACE_2_0);
636 DUMPREG(HDMI_VACT_SPACE_2_1);
637 DUMPREG(HDMI_VACT_SPACE_3_0);
638 DUMPREG(HDMI_VACT_SPACE_3_1);
639 DUMPREG(HDMI_VACT_SPACE_4_0);
640 DUMPREG(HDMI_VACT_SPACE_4_1);
641 DUMPREG(HDMI_VACT_SPACE_5_0);
642 DUMPREG(HDMI_VACT_SPACE_5_1);
643 DUMPREG(HDMI_VACT_SPACE_6_0);
644 DUMPREG(HDMI_VACT_SPACE_6_1);
645
646 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
647 DUMPREG(HDMI_TG_CMD);
648 DUMPREG(HDMI_TG_H_FSZ_L);
649 DUMPREG(HDMI_TG_H_FSZ_H);
650 DUMPREG(HDMI_TG_HACT_ST_L);
651 DUMPREG(HDMI_TG_HACT_ST_H);
652 DUMPREG(HDMI_TG_HACT_SZ_L);
653 DUMPREG(HDMI_TG_HACT_SZ_H);
654 DUMPREG(HDMI_TG_V_FSZ_L);
655 DUMPREG(HDMI_TG_V_FSZ_H);
656 DUMPREG(HDMI_TG_VSYNC_L);
657 DUMPREG(HDMI_TG_VSYNC_H);
658 DUMPREG(HDMI_TG_VSYNC2_L);
659 DUMPREG(HDMI_TG_VSYNC2_H);
660 DUMPREG(HDMI_TG_VACT_ST_L);
661 DUMPREG(HDMI_TG_VACT_ST_H);
662 DUMPREG(HDMI_TG_VACT_SZ_L);
663 DUMPREG(HDMI_TG_VACT_SZ_H);
664 DUMPREG(HDMI_TG_FIELD_CHG_L);
665 DUMPREG(HDMI_TG_FIELD_CHG_H);
666 DUMPREG(HDMI_TG_VACT_ST2_L);
667 DUMPREG(HDMI_TG_VACT_ST2_H);
668 DUMPREG(HDMI_TG_VACT_ST3_L);
669 DUMPREG(HDMI_TG_VACT_ST3_H);
670 DUMPREG(HDMI_TG_VACT_ST4_L);
671 DUMPREG(HDMI_TG_VACT_ST4_H);
672 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
673 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
674 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
675 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
676 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
677 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
678 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
679 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
680 DUMPREG(HDMI_TG_3D);
681
682 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
683 DUMPREG(HDMI_AVI_CON);
684 DUMPREG(HDMI_AVI_HEADER0);
685 DUMPREG(HDMI_AVI_HEADER1);
686 DUMPREG(HDMI_AVI_HEADER2);
687 DUMPREG(HDMI_AVI_CHECK_SUM);
688 DUMPREG(HDMI_VSI_CON);
689 DUMPREG(HDMI_VSI_HEADER0);
690 DUMPREG(HDMI_VSI_HEADER1);
691 DUMPREG(HDMI_VSI_HEADER2);
692 for (i = 0; i < 7; ++i)
693 DUMPREG(HDMI_VSI_DATA(i));
694
695#undef DUMPREG
696}
697
698static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
699{
Rahul Sharma5a325072012-10-04 20:48:54 +0530700 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900701 hdmi_v13_regs_dump(hdata, prefix);
702 else
703 hdmi_v14_regs_dump(hdata, prefix);
704}
705
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530706static u8 hdmi_chksum(struct hdmi_context *hdata,
707 u32 start, u8 len, u32 hdr_sum)
708{
709 int i;
710
711 /* hdr_sum : header0 + header1 + header2
712 * start : start address of packet byte1
713 * len : packet bytes - 1 */
714 for (i = 0; i < len; ++i)
715 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
716
717 /* return 2's complement of 8 bit hdr_sum */
718 return (u8)(~(hdr_sum & 0xff) + 1);
719}
720
721static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530722 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530723{
724 u32 hdr_sum;
725 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530726 u32 mod;
727 u32 vic;
728
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530729 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
730 if (hdata->dvi_mode) {
731 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
732 HDMI_VSI_CON_DO_NOT_TRANSMIT);
733 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
734 HDMI_AVI_CON_DO_NOT_TRANSMIT);
735 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
736 return;
737 }
738
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530739 switch (infoframe->any.type) {
740 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530741 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530742 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
743 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
744 infoframe->any.version);
745 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
746 hdr_sum = infoframe->any.type + infoframe->any.version +
747 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530748
749 /* Output format zero hardcoded ,RGB YBCR selection */
750 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
751 AVI_ACTIVE_FORMAT_VALID |
752 AVI_UNDERSCANNED_DISPLAY_VALID);
753
Shirish S46154152014-03-13 10:58:28 +0530754 /*
755 * Set the aspect ratio as per the mode, mentioned in
756 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
757 */
758 switch (hdata->mode_conf.aspect_ratio) {
759 case HDMI_PICTURE_ASPECT_4_3:
760 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
761 hdata->mode_conf.aspect_ratio |
762 AVI_4_3_CENTER_RATIO);
763 break;
764 case HDMI_PICTURE_ASPECT_16_9:
765 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
766 hdata->mode_conf.aspect_ratio |
767 AVI_16_9_CENTER_RATIO);
768 break;
769 case HDMI_PICTURE_ASPECT_NONE:
770 default:
771 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
772 hdata->mode_conf.aspect_ratio |
773 AVI_SAME_AS_PIC_ASPECT_RATIO);
774 break;
775 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530776
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900777 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530778 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
779
780 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530781 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530782 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
783 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
784 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530785 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530786 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530787 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
788 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
789 infoframe->any.version);
790 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
791 hdr_sum = infoframe->any.type + infoframe->any.version +
792 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530793 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530794 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530795 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
796 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
797 break;
798 default:
799 break;
800 }
801}
802
Sean Pauld9716ee2014-01-30 16:19:29 -0500803static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
804 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500805{
Sean Pauld9716ee2014-01-30 16:19:29 -0500806 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500807
Sean Paul5137c8c2014-04-03 20:41:03 +0530808 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
809
Sean Pauld9716ee2014-01-30 16:19:29 -0500810 return hdata->hpd ? connector_status_connected :
811 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500812}
813
Sean Pauld9716ee2014-01-30 16:19:29 -0500814static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900815{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900816}
817
Sean Pauld9716ee2014-01-30 16:19:29 -0500818static struct drm_connector_funcs hdmi_connector_funcs = {
819 .dpms = drm_helper_connector_dpms,
820 .fill_modes = drm_helper_probe_single_connector_modes,
821 .detect = hdmi_detect,
822 .destroy = hdmi_connector_destroy,
823};
824
825static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900826{
Sean Pauld9716ee2014-01-30 16:19:29 -0500827 struct hdmi_context *hdata = ctx_from_connector(connector);
828 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900829
Inki Dae8fa04aa2014-03-13 16:38:31 +0900830 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500831 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900832
Inki Dae8fa04aa2014-03-13 16:38:31 +0900833 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500834 if (!edid)
835 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900836
Sean Pauld9716ee2014-01-30 16:19:29 -0500837 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500838 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
839 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500840 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500841
Sean Pauld9716ee2014-01-30 16:19:29 -0500842 drm_mode_connector_update_edid_property(connector, edid);
843
844 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900845}
846
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900847static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900848{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900849 const struct hdmiphy_config *confs;
850 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900851
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900852 if (hdata->type == HDMI_TYPE13) {
853 confs = hdmiphy_v13_configs;
854 count = ARRAY_SIZE(hdmiphy_v13_configs);
855 } else if (hdata->type == HDMI_TYPE14) {
856 confs = hdmiphy_v14_configs;
857 count = ARRAY_SIZE(hdmiphy_v14_configs);
858 } else
859 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900860
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900861 for (i = 0; i < count; i++)
862 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500863 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500864
865 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
866 return -EINVAL;
867}
868
Sean Pauld9716ee2014-01-30 16:19:29 -0500869static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -0500870 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900871{
Sean Pauld9716ee2014-01-30 16:19:29 -0500872 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900873 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900874
Rahul Sharma16844fb2013-06-10 14:50:00 +0530875 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
876 mode->hdisplay, mode->vdisplay, mode->vrefresh,
877 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
878 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900879
Sean Paulf041b252014-01-30 16:19:15 -0500880 ret = mixer_check_mode(mode);
881 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -0500882 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -0500883
Rahul Sharma16844fb2013-06-10 14:50:00 +0530884 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900885 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -0500886 return MODE_BAD;
887
888 return MODE_OK;
889}
890
891static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
892{
893 struct hdmi_context *hdata = ctx_from_connector(connector);
894
895 return hdata->encoder;
896}
897
898static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
899 .get_modes = hdmi_get_modes,
900 .mode_valid = hdmi_mode_valid,
901 .best_encoder = hdmi_best_encoder,
902};
903
904static int hdmi_create_connector(struct exynos_drm_display *display,
905 struct drm_encoder *encoder)
906{
907 struct hdmi_context *hdata = display->ctx;
908 struct drm_connector *connector = &hdata->connector;
909 int ret;
910
911 hdata->encoder = encoder;
912 connector->interlace_allowed = true;
913 connector->polled = DRM_CONNECTOR_POLL_HPD;
914
915 ret = drm_connector_init(hdata->drm_dev, connector,
916 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
917 if (ret) {
918 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900919 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -0500920 }
921
922 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
923 drm_sysfs_connector_add(connector);
924 drm_mode_connector_attach_encoder(connector, encoder);
925
926 return 0;
927}
928
Sean Paulf041b252014-01-30 16:19:15 -0500929static void hdmi_mode_fixup(struct exynos_drm_display *display,
930 struct drm_connector *connector,
931 const struct drm_display_mode *mode,
932 struct drm_display_mode *adjusted_mode)
933{
934 struct drm_display_mode *m;
935 int mode_ok;
936
937 DRM_DEBUG_KMS("%s\n", __FILE__);
938
939 drm_mode_set_crtcinfo(adjusted_mode, 0);
940
Sean Pauld9716ee2014-01-30 16:19:29 -0500941 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -0500942
943 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -0500944 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -0500945 return;
946
947 /*
948 * otherwise, find the most suitable mode among modes and change it
949 * to adjusted_mode.
950 */
951 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -0500952 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -0500953
Sean Pauld9716ee2014-01-30 16:19:29 -0500954 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -0500955 DRM_INFO("desired mode doesn't exist so\n");
956 DRM_INFO("use the most suitable mode among modes.\n");
957
958 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
959 m->hdisplay, m->vdisplay, m->vrefresh);
960
Sean Paul75626852014-01-30 16:19:16 -0500961 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -0500962 break;
963 }
964 }
965}
966
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900967static void hdmi_set_acr(u32 freq, u8 *acr)
968{
969 u32 n, cts;
970
971 switch (freq) {
972 case 32000:
973 n = 4096;
974 cts = 27000;
975 break;
976 case 44100:
977 n = 6272;
978 cts = 30000;
979 break;
980 case 88200:
981 n = 12544;
982 cts = 30000;
983 break;
984 case 176400:
985 n = 25088;
986 cts = 30000;
987 break;
988 case 48000:
989 n = 6144;
990 cts = 27000;
991 break;
992 case 96000:
993 n = 12288;
994 cts = 27000;
995 break;
996 case 192000:
997 n = 24576;
998 cts = 27000;
999 break;
1000 default:
1001 n = 0;
1002 cts = 0;
1003 break;
1004 }
1005
1006 acr[1] = cts >> 16;
1007 acr[2] = cts >> 8 & 0xff;
1008 acr[3] = cts & 0xff;
1009
1010 acr[4] = n >> 16;
1011 acr[5] = n >> 8 & 0xff;
1012 acr[6] = n & 0xff;
1013}
1014
1015static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1016{
1017 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1018 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1019 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1020 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1021 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1022 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1023 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1024 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1025 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1026
Rahul Sharma5a325072012-10-04 20:48:54 +05301027 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001028 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1029 else
1030 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1031}
1032
1033static void hdmi_audio_init(struct hdmi_context *hdata)
1034{
1035 u32 sample_rate, bits_per_sample, frame_size_code;
1036 u32 data_num, bit_ch, sample_frq;
1037 u32 val;
1038 u8 acr[7];
1039
1040 sample_rate = 44100;
1041 bits_per_sample = 16;
1042 frame_size_code = 0;
1043
1044 switch (bits_per_sample) {
1045 case 20:
1046 data_num = 2;
1047 bit_ch = 1;
1048 break;
1049 case 24:
1050 data_num = 3;
1051 bit_ch = 1;
1052 break;
1053 default:
1054 data_num = 1;
1055 bit_ch = 0;
1056 break;
1057 }
1058
1059 hdmi_set_acr(sample_rate, acr);
1060 hdmi_reg_acr(hdata, acr);
1061
1062 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1063 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1064 | HDMI_I2S_MUX_ENABLE);
1065
1066 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1067 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1068
1069 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1070
1071 sample_frq = (sample_rate == 44100) ? 0 :
1072 (sample_rate == 48000) ? 2 :
1073 (sample_rate == 32000) ? 3 :
1074 (sample_rate == 96000) ? 0xa : 0x0;
1075
1076 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1077 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1078
1079 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1080 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1081
1082 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1083 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1084 | HDMI_I2S_SEL_LRCK(6));
1085 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1086 | HDMI_I2S_SEL_SDATA2(4));
1087 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1088 | HDMI_I2S_SEL_SDATA2(2));
1089 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1090
1091 /* I2S_CON_1 & 2 */
1092 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1093 | HDMI_I2S_L_CH_LOW_POL);
1094 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1095 | HDMI_I2S_SET_BIT_CH(bit_ch)
1096 | HDMI_I2S_SET_SDATA_BIT(data_num)
1097 | HDMI_I2S_BASIC_FORMAT);
1098
1099 /* Configure register related to CUV information */
1100 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1101 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1102 | HDMI_I2S_COPYRIGHT
1103 | HDMI_I2S_LINEAR_PCM
1104 | HDMI_I2S_CONSUMER_FORMAT);
1105 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1106 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1107 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1108 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1109 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1110 HDMI_I2S_ORG_SMP_FREQ_44_1
1111 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1112 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1113
1114 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1115}
1116
1117static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1118{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001119 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001120 return;
1121
1122 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1123 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1124 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1125}
1126
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001127static void hdmi_conf_reset(struct hdmi_context *hdata)
1128{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001129 u32 reg;
1130
Rahul Sharma5a325072012-10-04 20:48:54 +05301131 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001132 reg = HDMI_V13_CORE_RSTOUT;
1133 else
1134 reg = HDMI_CORE_RSTOUT;
1135
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001136 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001137 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001138 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001139 hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001140 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001141}
1142
1143static void hdmi_conf_init(struct hdmi_context *hdata)
1144{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301145 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301146
Sean Paul77006a72013-01-16 10:17:20 -05001147 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001148 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1149 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001150
1151 /* choose HDMI mode */
1152 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1153 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1154 /* disable bluescreen */
1155 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001156
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001157 if (hdata->dvi_mode) {
1158 /* choose DVI mode */
1159 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1160 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1161 hdmi_reg_writeb(hdata, HDMI_CON_2,
1162 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1163 }
1164
Rahul Sharma5a325072012-10-04 20:48:54 +05301165 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001166 /* choose bluescreen (fecal) color */
1167 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1168 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1169 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1170
1171 /* enable AVI packet every vsync, fixes purple line problem */
1172 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1173 /* force RGB, look to CEA-861-D, table 7 for more detail */
1174 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1175 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1176
1177 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1178 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1179 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1180 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301181 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1182 infoframe.any.version = HDMI_AVI_VERSION;
1183 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301184 hdmi_reg_infoframe(hdata, &infoframe);
1185
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301186 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1187 infoframe.any.version = HDMI_AUI_VERSION;
1188 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301189 hdmi_reg_infoframe(hdata, &infoframe);
1190
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001191 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001192 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1193 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001194}
1195
Rahul Sharma16844fb2013-06-10 14:50:00 +05301196static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001197{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001198 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1199 const struct hdmi_v13_core_regs *core =
1200 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001201 int tries;
1202
1203 /* setting core registers */
1204 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1205 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001206 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1207 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1208 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1209 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1210 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1211 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001212 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1213 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001214 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1215 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1216 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1217 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1218 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1219 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1220 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1221 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1222 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1223 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1224 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1225 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1226 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1227 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1228 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001229 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001230 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1231 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1232 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1233 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1234 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1235 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1236 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1237 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1238 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1239 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1240 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1241 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1242 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1243 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1244 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1245 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1246 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1247 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1248 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1249 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1250 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1251 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1252 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1253 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1254 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1255 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1256 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1257 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001258
1259 /* waiting for HDMIPHY's PLL to get to steady state */
1260 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001261 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001262 if (val & HDMI_PHY_STATUS_READY)
1263 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001264 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001265 }
1266 /* steady state not achieved */
1267 if (tries == 0) {
1268 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1269 hdmi_regs_dump(hdata, "timing apply");
1270 }
1271
Sean Paul0bfb1f82013-06-11 12:24:02 +05301272 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301273 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301274 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001275
1276 /* enable HDMI and timing generator */
1277 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1278 if (core->int_pro_mode[0])
1279 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1280 HDMI_FIELD_EN);
1281 else
1282 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1283}
1284
Rahul Sharma16844fb2013-06-10 14:50:00 +05301285static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001286{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001287 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1288 const struct hdmi_v14_core_regs *core =
1289 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001290 int tries;
1291
1292 /* setting core registers */
1293 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1294 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1295 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1296 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1297 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1298 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1299 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1300 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1301 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1302 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1303 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1304 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1305 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1306 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1307 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1308 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1309 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1310 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1311 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1312 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1313 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1314 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1315 core->v_sync_line_bef_2[0]);
1316 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1317 core->v_sync_line_bef_2[1]);
1318 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1319 core->v_sync_line_bef_1[0]);
1320 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1321 core->v_sync_line_bef_1[1]);
1322 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1323 core->v_sync_line_aft_2[0]);
1324 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1325 core->v_sync_line_aft_2[1]);
1326 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1327 core->v_sync_line_aft_1[0]);
1328 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1329 core->v_sync_line_aft_1[1]);
1330 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1331 core->v_sync_line_aft_pxl_2[0]);
1332 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1333 core->v_sync_line_aft_pxl_2[1]);
1334 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1335 core->v_sync_line_aft_pxl_1[0]);
1336 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1337 core->v_sync_line_aft_pxl_1[1]);
1338 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1339 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1340 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1341 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1342 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1343 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1344 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1345 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1346 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1347 core->v_sync_line_aft_3[0]);
1348 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1349 core->v_sync_line_aft_3[1]);
1350 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1351 core->v_sync_line_aft_4[0]);
1352 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1353 core->v_sync_line_aft_4[1]);
1354 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1355 core->v_sync_line_aft_5[0]);
1356 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1357 core->v_sync_line_aft_5[1]);
1358 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1359 core->v_sync_line_aft_6[0]);
1360 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1361 core->v_sync_line_aft_6[1]);
1362 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1363 core->v_sync_line_aft_pxl_3[0]);
1364 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1365 core->v_sync_line_aft_pxl_3[1]);
1366 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1367 core->v_sync_line_aft_pxl_4[0]);
1368 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1369 core->v_sync_line_aft_pxl_4[1]);
1370 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1371 core->v_sync_line_aft_pxl_5[0]);
1372 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1373 core->v_sync_line_aft_pxl_5[1]);
1374 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1375 core->v_sync_line_aft_pxl_6[0]);
1376 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1377 core->v_sync_line_aft_pxl_6[1]);
1378 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1379 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1380 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1381 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1382 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1383 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1384 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1385 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1386 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1387 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1388 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1389 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1390
1391 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001392 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1393 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1394 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1395 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1396 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1397 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1398 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1399 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1400 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1401 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1402 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1403 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1404 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1405 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1406 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1407 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1408 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1409 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1410 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1411 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1412 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1413 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1414 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1415 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1416 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1417 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1418 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1419 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1420 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1421 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1422 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1423 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1424 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001425
1426 /* waiting for HDMIPHY's PLL to get to steady state */
1427 for (tries = 100; tries; --tries) {
1428 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1429 if (val & HDMI_PHY_STATUS_READY)
1430 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001431 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001432 }
1433 /* steady state not achieved */
1434 if (tries == 0) {
1435 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1436 hdmi_regs_dump(hdata, "timing apply");
1437 }
1438
Sean Paul0bfb1f82013-06-11 12:24:02 +05301439 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301440 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301441 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001442
1443 /* enable HDMI and timing generator */
1444 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1445 if (core->int_pro_mode[0])
1446 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1447 HDMI_FIELD_EN);
1448 else
1449 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1450}
1451
Rahul Sharma16844fb2013-06-10 14:50:00 +05301452static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001453{
Rahul Sharma5a325072012-10-04 20:48:54 +05301454 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301455 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001456 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301457 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001458}
1459
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001460static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1461{
1462 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001463 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001464
Sean Paul0bfb1f82013-06-11 12:24:02 +05301465 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301466 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301467 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001468
1469 /* operation mode */
1470 buffer[0] = 0x1f;
1471 buffer[1] = 0x00;
1472
1473 if (hdata->hdmiphy_port)
1474 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1475
Rahul Sharma5a325072012-10-04 20:48:54 +05301476 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001477 reg = HDMI_V13_PHY_RSTOUT;
1478 else
1479 reg = HDMI_PHY_RSTOUT;
1480
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001481 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001482 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001483 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001484 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001485 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001486}
1487
Rahul Sharmaa5562252012-11-28 11:30:25 +05301488static void hdmiphy_poweron(struct hdmi_context *hdata)
1489{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301490 if (hdata->type == HDMI_TYPE14)
1491 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1492 HDMI_PHY_POWER_OFF_EN);
1493}
1494
1495static void hdmiphy_poweroff(struct hdmi_context *hdata)
1496{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301497 if (hdata->type == HDMI_TYPE14)
1498 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1499 HDMI_PHY_POWER_OFF_EN);
1500}
1501
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001502static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1503{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001504 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001505 u8 buffer[32];
1506 u8 operation[2];
1507 u8 read_buffer[32] = {0, };
1508 int ret;
1509 int i;
1510
1511 if (!hdata->hdmiphy_port) {
1512 DRM_ERROR("hdmiphy is not attached\n");
1513 return;
1514 }
1515
1516 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001517 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1518 if (i < 0) {
1519 DRM_ERROR("failed to find hdmiphy conf\n");
1520 return;
1521 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001522
Sachin Kamat5f46c332013-04-26 11:29:00 +05301523 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001524 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301525 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001526 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001527
1528 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001529 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1530 if (ret != 32) {
1531 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1532 return;
1533 }
1534
Sean Paul09760ea2013-01-14 17:03:20 -05001535 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001536
1537 /* operation mode */
1538 operation[0] = 0x1f;
1539 operation[1] = 0x80;
1540
1541 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1542 if (ret != 2) {
1543 DRM_ERROR("failed to enable hdmiphy\n");
1544 return;
1545 }
1546
1547 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1548 if (ret < 0) {
1549 DRM_ERROR("failed to read hdmiphy config\n");
1550 return;
1551 }
1552
1553 for (i = 0; i < ret; i++)
1554 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1555 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1556}
1557
1558static void hdmi_conf_apply(struct hdmi_context *hdata)
1559{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001560 hdmiphy_conf_reset(hdata);
1561 hdmiphy_conf_apply(hdata);
1562
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001563 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001564 hdmi_conf_reset(hdata);
1565 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001566 mutex_unlock(&hdata->hdmi_mutex);
1567
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001568 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001569
1570 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301571 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001572 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001573
1574 hdmi_regs_dump(hdata, "start");
1575}
1576
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001577static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1578{
1579 int i;
1580 BUG_ON(num_bytes > 4);
1581 for (i = 0; i < num_bytes; i++)
1582 reg_pair[i] = (value >> (8 * i)) & 0xff;
1583}
1584
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001585static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1586 struct drm_display_mode *m)
1587{
1588 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1589 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1590 unsigned int val;
1591
1592 hdata->mode_conf.cea_video_id =
1593 drm_match_cea_mode((struct drm_display_mode *)m);
1594 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301595 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001596
1597 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1598 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1599
1600 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1601 hdmi_set_reg(core->vsync_pol, 1, val);
1602
1603 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1604 hdmi_set_reg(core->int_pro_mode, 1, val);
1605
1606 val = (m->hsync_start - m->hdisplay - 2);
1607 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1608 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1609 hdmi_set_reg(core->h_sync_gen, 3, val);
1610
1611 /*
1612 * Quirk requirement for exynos HDMI IP design,
1613 * 2 pixels less than the actual calculation for hsync_start
1614 * and end.
1615 */
1616
1617 /* Following values & calculations differ for different type of modes */
1618 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1619 /* Interlaced Mode */
1620 val = ((m->vsync_end - m->vdisplay) / 2);
1621 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1622 hdmi_set_reg(core->v_sync_gen1, 3, val);
1623
1624 val = m->vtotal / 2;
1625 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1626 hdmi_set_reg(core->v_blank, 3, val);
1627
1628 val = (m->vtotal +
1629 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1630 val |= m->vtotal << 11;
1631 hdmi_set_reg(core->v_blank_f, 3, val);
1632
1633 val = ((m->vtotal / 2) + 7);
1634 val |= ((m->vtotal / 2) + 2) << 12;
1635 hdmi_set_reg(core->v_sync_gen2, 3, val);
1636
1637 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1638 val |= ((m->htotal / 2) +
1639 (m->hsync_start - m->hdisplay)) << 12;
1640 hdmi_set_reg(core->v_sync_gen3, 3, val);
1641
1642 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1643 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1644
1645 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1646 } else {
1647 /* Progressive Mode */
1648
1649 val = m->vtotal;
1650 val |= (m->vtotal - m->vdisplay) << 11;
1651 hdmi_set_reg(core->v_blank, 3, val);
1652
1653 hdmi_set_reg(core->v_blank_f, 3, 0);
1654
1655 val = (m->vsync_end - m->vdisplay);
1656 val |= ((m->vsync_start - m->vdisplay) << 12);
1657 hdmi_set_reg(core->v_sync_gen1, 3, val);
1658
1659 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1660 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1661 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1662 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1663 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1664 }
1665
1666 /* Timing generator registers */
1667 hdmi_set_reg(tg->cmd, 1, 0x0);
1668 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1669 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1670 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1671 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1672 hdmi_set_reg(tg->vsync, 2, 0x1);
1673 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1674 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1675 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1676 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1677 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1678 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1679 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1680}
1681
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001682static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1683 struct drm_display_mode *m)
1684{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001685 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1686 struct hdmi_v14_core_regs *core =
1687 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001688
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001689 hdata->mode_conf.cea_video_id =
1690 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001691 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301692 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001693
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001694 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1695 hdmi_set_reg(core->v_line, 2, m->vtotal);
1696 hdmi_set_reg(core->h_line, 2, m->htotal);
1697 hdmi_set_reg(core->hsync_pol, 1,
1698 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1699 hdmi_set_reg(core->vsync_pol, 1,
1700 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1701 hdmi_set_reg(core->int_pro_mode, 1,
1702 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1703
1704 /*
1705 * Quirk requirement for exynos 5 HDMI IP design,
1706 * 2 pixels less than the actual calculation for hsync_start
1707 * and end.
1708 */
1709
1710 /* Following values & calculations differ for different type of modes */
1711 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1712 /* Interlaced Mode */
1713 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1714 (m->vsync_end - m->vdisplay) / 2);
1715 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1716 (m->vsync_start - m->vdisplay) / 2);
1717 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1718 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301719 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001720 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1721 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1722 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1723 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1724 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1725 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1726 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1727 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1728 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301729 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1730 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1731 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1732 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001733 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1734 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1735 } else {
1736 /* Progressive Mode */
1737 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1738 m->vsync_end - m->vdisplay);
1739 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1740 m->vsync_start - m->vdisplay);
1741 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1742 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1743 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1744 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1745 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1746 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1747 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1748 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1749 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1750 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1751 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1752 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1753 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301754 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1755 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1756 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001757 }
1758
1759 /* Following values & calculations are same irrespective of mode type */
1760 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1761 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1762 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1763 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1764 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1765 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1766 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1767 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1768 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1769 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1770 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1771 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1772 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1773 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1774 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1775 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1776 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1777 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1778 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1779 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1780
1781 /* Timing generator registers */
1782 hdmi_set_reg(tg->cmd, 1, 0x0);
1783 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1784 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1785 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1786 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1787 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001788 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1789 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001790 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001791 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001792}
1793
Sean Paulf041b252014-01-30 16:19:15 -05001794static void hdmi_mode_set(struct exynos_drm_display *display,
1795 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001796{
Sean Paulf041b252014-01-30 16:19:15 -05001797 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001798 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001799
YoungJun Chocbc4c332013-06-12 10:44:40 +09001800 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1801 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001802 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1803 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001804
Sachin Kamat5f46c332013-04-26 11:29:00 +05301805 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001806 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301807 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001808 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001809}
1810
Sean Paulf041b252014-01-30 16:19:15 -05001811static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001812{
Sean Paulf041b252014-01-30 16:19:15 -05001813 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001814
Shirish Sdda90122013-01-23 22:03:18 -05001815 mutex_lock(&hdata->hdmi_mutex);
1816 if (!hdata->powered) {
1817 mutex_unlock(&hdata->hdmi_mutex);
1818 return;
1819 }
1820 mutex_unlock(&hdata->hdmi_mutex);
1821
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001822 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001823}
1824
Sean Paulf041b252014-01-30 16:19:15 -05001825static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001826{
Sean Paulf041b252014-01-30 16:19:15 -05001827 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001828 struct hdmi_resources *res = &hdata->res;
1829
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001830 mutex_lock(&hdata->hdmi_mutex);
1831 if (hdata->powered) {
1832 mutex_unlock(&hdata->hdmi_mutex);
1833 return;
1834 }
1835
1836 hdata->powered = true;
1837
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001838 mutex_unlock(&hdata->hdmi_mutex);
1839
Sean Paulaf65c802014-01-30 16:19:27 -05001840 pm_runtime_get_sync(hdata->dev);
1841
Seung-Woo Kimad079452013-06-05 14:34:38 +09001842 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1843 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1844
Sean Paul0bfb1f82013-06-11 12:24:02 +05301845 clk_prepare_enable(res->hdmiphy);
1846 clk_prepare_enable(res->hdmi);
1847 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301848
1849 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05001850 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001851}
1852
Sean Paulf041b252014-01-30 16:19:15 -05001853static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001854{
Sean Paulf041b252014-01-30 16:19:15 -05001855 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001856 struct hdmi_resources *res = &hdata->res;
1857
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001858 mutex_lock(&hdata->hdmi_mutex);
1859 if (!hdata->powered)
1860 goto out;
1861 mutex_unlock(&hdata->hdmi_mutex);
1862
Rahul Sharmaa5562252012-11-28 11:30:25 +05301863 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001864
Sean Paul724fd142014-05-09 15:05:10 +09001865 cancel_delayed_work(&hdata->hotplug_work);
1866
Sean Paul0bfb1f82013-06-11 12:24:02 +05301867 clk_disable_unprepare(res->sclk_hdmi);
1868 clk_disable_unprepare(res->hdmi);
1869 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001870 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1871
Sean Paulaf65c802014-01-30 16:19:27 -05001872 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001873
Sean Paulaf65c802014-01-30 16:19:27 -05001874 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001875 hdata->powered = false;
1876
1877out:
1878 mutex_unlock(&hdata->hdmi_mutex);
1879}
1880
Sean Paulf041b252014-01-30 16:19:15 -05001881static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001882{
YoungJun Chocbc4c332013-06-12 10:44:40 +09001883 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001884
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001885 switch (mode) {
1886 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05001887 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001888 break;
1889 case DRM_MODE_DPMS_STANDBY:
1890 case DRM_MODE_DPMS_SUSPEND:
1891 case DRM_MODE_DPMS_OFF:
Sean Paulaf65c802014-01-30 16:19:27 -05001892 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001893 break;
1894 default:
1895 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1896 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001897 }
1898}
1899
Sean Paulf041b252014-01-30 16:19:15 -05001900static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001901 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05001902 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001903 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05001904 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001905 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001906};
1907
Sean Paulf041b252014-01-30 16:19:15 -05001908static struct exynos_drm_display hdmi_display = {
1909 .type = EXYNOS_DISPLAY_TYPE_HDMI,
1910 .ops = &hdmi_display_ops,
1911};
1912
Sean Paul724fd142014-05-09 15:05:10 +09001913static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001914{
Sean Paul724fd142014-05-09 15:05:10 +09001915 struct hdmi_context *hdata;
1916
1917 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001918
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001919 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301920 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001921 mutex_unlock(&hdata->hdmi_mutex);
1922
Sean Paul45517892014-01-30 16:19:05 -05001923 if (hdata->drm_dev)
1924 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001925}
1926
1927static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1928{
1929 struct hdmi_context *hdata = arg;
1930
1931 mod_delayed_work(system_wq, &hdata->hotplug_work,
1932 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001933
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001934 return IRQ_HANDLED;
1935}
1936
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001937static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001938{
1939 struct device *dev = hdata->dev;
1940 struct hdmi_resources *res = &hdata->res;
1941 static char *supply[] = {
1942 "hdmi-en",
1943 "vdd",
1944 "vdd_osc",
1945 "vdd_pll",
1946 };
1947 int i, ret;
1948
1949 DRM_DEBUG_KMS("HDMI resource init\n");
1950
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001951 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301952 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301953 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001954 DRM_ERROR("failed to get clock 'hdmi'\n");
1955 goto fail;
1956 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301957 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301958 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001959 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1960 goto fail;
1961 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301962 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301963 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001964 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1965 goto fail;
1966 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301967 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301968 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001969 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1970 goto fail;
1971 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301972 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301973 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001974 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1975 goto fail;
1976 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301977 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1978 if (IS_ERR(res->mout_hdmi)) {
1979 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1980 goto fail;
1981 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001982
Rahul Sharma59956d32013-06-11 12:24:03 +05301983 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301985 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301986 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001987 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001988 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001989 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1990 res->regul_bulk[i].supply = supply[i];
1991 res->regul_bulk[i].consumer = NULL;
1992 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301993 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994 if (ret) {
1995 DRM_ERROR("failed to get regulators\n");
1996 goto fail;
1997 }
1998 res->regul_count = ARRAY_SIZE(supply);
1999
2000 return 0;
2001fail:
2002 DRM_ERROR("HDMI resource init - failed\n");
2003 return -ENODEV;
2004}
2005
Rahul Sharma22c4f422012-10-04 20:48:55 +05302006static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2007 (struct device *dev)
2008{
2009 struct device_node *np = dev->of_node;
2010 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302011 u32 value;
2012
2013 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002014 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302015 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302016
2017 if (!of_find_property(np, "hpd-gpio", &value)) {
2018 DRM_ERROR("no hpd gpio property found\n");
2019 goto err_data;
2020 }
2021
Rahul Sharma5f916e22013-06-11 19:41:29 +05302022 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302023
2024 return pd;
2025
2026err_data:
2027 return NULL;
2028}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302029
Rahul Sharma22c4f422012-10-04 20:48:55 +05302030static struct of_device_id hdmi_match_types[] = {
2031 {
2032 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002033 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302034 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302035 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002036 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302037 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302038 /* end node */
2039 }
2040};
2041
Inki Daef37cd5e2014-05-09 14:25:20 +09002042static int hdmi_bind(struct device *dev, struct device *master, void *data)
2043{
2044 struct drm_device *drm_dev = data;
2045 struct hdmi_context *hdata;
2046
2047 hdata = hdmi_display.ctx;
2048 hdata->drm_dev = drm_dev;
2049
2050 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2051}
2052
2053static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2054{
2055 struct exynos_drm_display *display = get_hdmi_display(dev);
2056 struct drm_encoder *encoder = display->encoder;
2057 struct hdmi_context *hdata = display->ctx;
2058
2059 encoder->funcs->destroy(encoder);
2060 drm_connector_cleanup(&hdata->connector);
2061}
2062
2063static const struct component_ops hdmi_component_ops = {
2064 .bind = hdmi_bind,
2065 .unbind = hdmi_unbind,
2066};
2067
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002068static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002069{
Inki Daef37cd5e2014-05-09 14:25:20 +09002070 struct device_node *ddc_node, *phy_node;
2071 struct s5p_hdmi_platform_data *pdata;
2072 struct hdmi_driver_data *drv_data;
2073 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002074 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002075 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002076 struct resource *res;
2077 int ret;
2078
Inki Daef37cd5e2014-05-09 14:25:20 +09002079 if (!dev->of_node)
Sachin Kamat88c49812013-08-28 10:47:57 +05302080 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302081
Sachin Kamat88c49812013-08-28 10:47:57 +05302082 pdata = drm_hdmi_dt_parse_pdata(dev);
2083 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002084 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002085
Sachin Kamat88c49812013-08-28 10:47:57 +05302086 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002087 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002088 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002089
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002090 mutex_init(&hdata->hdmi_mutex);
2091
Sean Paulf041b252014-01-30 16:19:15 -05002092 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002093
Sachin Kamat88c49812013-08-28 10:47:57 +05302094 match = of_match_node(hdmi_match_types, dev->of_node);
2095 if (!match)
2096 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002097
2098 drv_data = (struct hdmi_driver_data *)match->data;
2099 hdata->type = drv_data->type;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302100
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302101 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002102 hdata->dev = dev;
2103
2104 ret = hdmi_resources_init(hdata);
2105 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302106 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302107 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002108 }
2109
2110 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002111 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01002112 if (IS_ERR(hdata->regs))
2113 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002114
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002115 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302116 if (ret) {
2117 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302118 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302119 }
2120
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002121 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002122 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2123 if (!ddc_node) {
2124 DRM_ERROR("Failed to find ddc node in device tree\n");
2125 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002126 }
Inki Dae8fa04aa2014-03-13 16:38:31 +09002127 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2128 if (!hdata->ddc_adpt) {
2129 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Daniel Kurtz2b768132014-02-24 18:52:51 +09002130 return -ENODEV;
2131 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002132
Inki Daebfe4e842014-03-06 14:18:17 +09002133 /* Not support APB PHY yet. */
2134 if (drv_data->is_apb_phy)
2135 return -EPERM;
2136
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002137 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002138 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2139 if (!phy_node) {
2140 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2141 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002142 goto err_ddc;
2143 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002144 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2145 if (!hdata->hdmiphy_port) {
2146 DRM_ERROR("Failed to get hdmi phy i2c client from node\n");
2147 ret = -ENODEV;
2148 goto err_ddc;
2149 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002150
Sean Paul77006a72013-01-16 10:17:20 -05002151 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2152 if (hdata->irq < 0) {
2153 DRM_ERROR("failed to get GPIO irq\n");
2154 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002155 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002156 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002157
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302158 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2159
Sean Paul724fd142014-05-09 15:05:10 +09002160 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2161
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002162 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002163 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002164 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002165 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002166 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002167 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002168 goto err_hdmiphy;
2169 }
2170
Sean Paulaf65c802014-01-30 16:19:27 -05002171 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002172 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002173
Inki Daef37cd5e2014-05-09 14:25:20 +09002174 return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002175
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002176err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002177 if (hdata->hdmiphy_port)
2178 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002179err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002180 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002181 return ret;
2182}
2183
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002184static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002185{
Inki Daef37cd5e2014-05-09 14:25:20 +09002186 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002187
Sean Paul724fd142014-05-09 15:05:10 +09002188 cancel_delayed_work_sync(&hdata->hotplug_work);
2189
Daniel Kurtz2b768132014-02-24 18:52:51 +09002190 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002191 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002192
Sean Paulaf65c802014-01-30 16:19:27 -05002193 pm_runtime_disable(&pdev->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194
Inki Daef37cd5e2014-05-09 14:25:20 +09002195 exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002196 return 0;
2197}
2198
2199struct platform_driver hdmi_driver = {
2200 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002201 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002202 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302203 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002204 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302205 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002206 },
2207};