blob: f1bdf991111ca68e87fb521fda0beb400adf0137 [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 Pauld9716ee2014-01-30 16:19:29 -0500808 return hdata->hpd ? connector_status_connected :
809 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500810}
811
Sean Pauld9716ee2014-01-30 16:19:29 -0500812static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900813{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900814}
815
Sean Pauld9716ee2014-01-30 16:19:29 -0500816static struct drm_connector_funcs hdmi_connector_funcs = {
817 .dpms = drm_helper_connector_dpms,
818 .fill_modes = drm_helper_probe_single_connector_modes,
819 .detect = hdmi_detect,
820 .destroy = hdmi_connector_destroy,
821};
822
823static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900824{
Sean Pauld9716ee2014-01-30 16:19:29 -0500825 struct hdmi_context *hdata = ctx_from_connector(connector);
826 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900827
Inki Dae8fa04aa2014-03-13 16:38:31 +0900828 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500829 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900830
Inki Dae8fa04aa2014-03-13 16:38:31 +0900831 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500832 if (!edid)
833 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900834
Sean Pauld9716ee2014-01-30 16:19:29 -0500835 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500836 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
837 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500838 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500839
Sean Pauld9716ee2014-01-30 16:19:29 -0500840 drm_mode_connector_update_edid_property(connector, edid);
841
842 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900843}
844
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900845static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900846{
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900847 const struct hdmiphy_config *confs;
848 int count, i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900849
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900850 if (hdata->type == HDMI_TYPE13) {
851 confs = hdmiphy_v13_configs;
852 count = ARRAY_SIZE(hdmiphy_v13_configs);
853 } else if (hdata->type == HDMI_TYPE14) {
854 confs = hdmiphy_v14_configs;
855 count = ARRAY_SIZE(hdmiphy_v14_configs);
856 } else
857 return -EINVAL;
Inki Dae1de425b2012-03-16 18:47:04 +0900858
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900859 for (i = 0; i < count; i++)
860 if (confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500861 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500862
863 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
864 return -EINVAL;
865}
866
Sean Pauld9716ee2014-01-30 16:19:29 -0500867static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -0500868 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900869{
Sean Pauld9716ee2014-01-30 16:19:29 -0500870 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900871 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900872
Rahul Sharma16844fb2013-06-10 14:50:00 +0530873 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
874 mode->hdisplay, mode->vdisplay, mode->vrefresh,
875 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
876 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900877
Sean Paulf041b252014-01-30 16:19:15 -0500878 ret = mixer_check_mode(mode);
879 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -0500880 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -0500881
Rahul Sharma16844fb2013-06-10 14:50:00 +0530882 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900883 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -0500884 return MODE_BAD;
885
886 return MODE_OK;
887}
888
889static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
890{
891 struct hdmi_context *hdata = ctx_from_connector(connector);
892
893 return hdata->encoder;
894}
895
896static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
897 .get_modes = hdmi_get_modes,
898 .mode_valid = hdmi_mode_valid,
899 .best_encoder = hdmi_best_encoder,
900};
901
902static int hdmi_create_connector(struct exynos_drm_display *display,
903 struct drm_encoder *encoder)
904{
905 struct hdmi_context *hdata = display->ctx;
906 struct drm_connector *connector = &hdata->connector;
907 int ret;
908
909 hdata->encoder = encoder;
910 connector->interlace_allowed = true;
911 connector->polled = DRM_CONNECTOR_POLL_HPD;
912
913 ret = drm_connector_init(hdata->drm_dev, connector,
914 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
915 if (ret) {
916 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900917 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -0500918 }
919
920 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
921 drm_sysfs_connector_add(connector);
922 drm_mode_connector_attach_encoder(connector, encoder);
923
924 return 0;
925}
926
Sean Paulf041b252014-01-30 16:19:15 -0500927static void hdmi_mode_fixup(struct exynos_drm_display *display,
928 struct drm_connector *connector,
929 const struct drm_display_mode *mode,
930 struct drm_display_mode *adjusted_mode)
931{
932 struct drm_display_mode *m;
933 int mode_ok;
934
935 DRM_DEBUG_KMS("%s\n", __FILE__);
936
937 drm_mode_set_crtcinfo(adjusted_mode, 0);
938
Sean Pauld9716ee2014-01-30 16:19:29 -0500939 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -0500940
941 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -0500942 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -0500943 return;
944
945 /*
946 * otherwise, find the most suitable mode among modes and change it
947 * to adjusted_mode.
948 */
949 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -0500950 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -0500951
Sean Pauld9716ee2014-01-30 16:19:29 -0500952 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -0500953 DRM_INFO("desired mode doesn't exist so\n");
954 DRM_INFO("use the most suitable mode among modes.\n");
955
956 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
957 m->hdisplay, m->vdisplay, m->vrefresh);
958
Sean Paul75626852014-01-30 16:19:16 -0500959 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -0500960 break;
961 }
962 }
963}
964
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +0900965static void hdmi_set_acr(u32 freq, u8 *acr)
966{
967 u32 n, cts;
968
969 switch (freq) {
970 case 32000:
971 n = 4096;
972 cts = 27000;
973 break;
974 case 44100:
975 n = 6272;
976 cts = 30000;
977 break;
978 case 88200:
979 n = 12544;
980 cts = 30000;
981 break;
982 case 176400:
983 n = 25088;
984 cts = 30000;
985 break;
986 case 48000:
987 n = 6144;
988 cts = 27000;
989 break;
990 case 96000:
991 n = 12288;
992 cts = 27000;
993 break;
994 case 192000:
995 n = 24576;
996 cts = 27000;
997 break;
998 default:
999 n = 0;
1000 cts = 0;
1001 break;
1002 }
1003
1004 acr[1] = cts >> 16;
1005 acr[2] = cts >> 8 & 0xff;
1006 acr[3] = cts & 0xff;
1007
1008 acr[4] = n >> 16;
1009 acr[5] = n >> 8 & 0xff;
1010 acr[6] = n & 0xff;
1011}
1012
1013static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1014{
1015 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1016 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1017 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1018 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1019 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1020 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1021 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1022 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1023 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1024
Rahul Sharma5a325072012-10-04 20:48:54 +05301025 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001026 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1027 else
1028 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1029}
1030
1031static void hdmi_audio_init(struct hdmi_context *hdata)
1032{
1033 u32 sample_rate, bits_per_sample, frame_size_code;
1034 u32 data_num, bit_ch, sample_frq;
1035 u32 val;
1036 u8 acr[7];
1037
1038 sample_rate = 44100;
1039 bits_per_sample = 16;
1040 frame_size_code = 0;
1041
1042 switch (bits_per_sample) {
1043 case 20:
1044 data_num = 2;
1045 bit_ch = 1;
1046 break;
1047 case 24:
1048 data_num = 3;
1049 bit_ch = 1;
1050 break;
1051 default:
1052 data_num = 1;
1053 bit_ch = 0;
1054 break;
1055 }
1056
1057 hdmi_set_acr(sample_rate, acr);
1058 hdmi_reg_acr(hdata, acr);
1059
1060 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1061 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1062 | HDMI_I2S_MUX_ENABLE);
1063
1064 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1065 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1066
1067 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1068
1069 sample_frq = (sample_rate == 44100) ? 0 :
1070 (sample_rate == 48000) ? 2 :
1071 (sample_rate == 32000) ? 3 :
1072 (sample_rate == 96000) ? 0xa : 0x0;
1073
1074 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1075 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1076
1077 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1078 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1079
1080 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1081 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1082 | HDMI_I2S_SEL_LRCK(6));
1083 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1084 | HDMI_I2S_SEL_SDATA2(4));
1085 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1086 | HDMI_I2S_SEL_SDATA2(2));
1087 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1088
1089 /* I2S_CON_1 & 2 */
1090 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1091 | HDMI_I2S_L_CH_LOW_POL);
1092 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1093 | HDMI_I2S_SET_BIT_CH(bit_ch)
1094 | HDMI_I2S_SET_SDATA_BIT(data_num)
1095 | HDMI_I2S_BASIC_FORMAT);
1096
1097 /* Configure register related to CUV information */
1098 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1099 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1100 | HDMI_I2S_COPYRIGHT
1101 | HDMI_I2S_LINEAR_PCM
1102 | HDMI_I2S_CONSUMER_FORMAT);
1103 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1104 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1105 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1106 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1107 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1108 HDMI_I2S_ORG_SMP_FREQ_44_1
1109 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1110 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1111
1112 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1113}
1114
1115static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1116{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001117 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001118 return;
1119
1120 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1121 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1122 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1123}
1124
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001125static void hdmi_conf_reset(struct hdmi_context *hdata)
1126{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001127 u32 reg;
1128
Rahul Sharma5a325072012-10-04 20:48:54 +05301129 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001130 reg = HDMI_V13_CORE_RSTOUT;
1131 else
1132 reg = HDMI_CORE_RSTOUT;
1133
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001134 /* resetting HDMI core */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001135 hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001136 usleep_range(10000, 12000);
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);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001139}
1140
1141static void hdmi_conf_init(struct hdmi_context *hdata)
1142{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301143 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301144
Sean Paul77006a72013-01-16 10:17:20 -05001145 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001146 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1147 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001148
1149 /* choose HDMI mode */
1150 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1151 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1152 /* disable bluescreen */
1153 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001154
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001155 if (hdata->dvi_mode) {
1156 /* choose DVI mode */
1157 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1158 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1159 hdmi_reg_writeb(hdata, HDMI_CON_2,
1160 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1161 }
1162
Rahul Sharma5a325072012-10-04 20:48:54 +05301163 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001164 /* choose bluescreen (fecal) color */
1165 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1166 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1167 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1168
1169 /* enable AVI packet every vsync, fixes purple line problem */
1170 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1171 /* force RGB, look to CEA-861-D, table 7 for more detail */
1172 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1173 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1174
1175 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1176 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1177 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1178 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301179 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1180 infoframe.any.version = HDMI_AVI_VERSION;
1181 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301182 hdmi_reg_infoframe(hdata, &infoframe);
1183
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301184 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1185 infoframe.any.version = HDMI_AUI_VERSION;
1186 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301187 hdmi_reg_infoframe(hdata, &infoframe);
1188
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001189 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001190 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1191 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001192}
1193
Rahul Sharma16844fb2013-06-10 14:50:00 +05301194static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001195{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001196 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1197 const struct hdmi_v13_core_regs *core =
1198 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001199 int tries;
1200
1201 /* setting core registers */
1202 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1203 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001204 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1205 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1206 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1207 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1208 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1209 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001210 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1211 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001212 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1213 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1214 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1215 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1216 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1217 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1218 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1219 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1220 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1221 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1222 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1223 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1224 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1225 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1226 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001227 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001228 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1229 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1230 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1231 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1232 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1233 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1234 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1235 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1236 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1237 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1238 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1239 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1240 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1241 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1242 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1243 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1244 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1245 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1246 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1247 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1248 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1249 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1250 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1251 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1252 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1253 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1254 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1255 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001256
1257 /* waiting for HDMIPHY's PLL to get to steady state */
1258 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001259 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001260 if (val & HDMI_PHY_STATUS_READY)
1261 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001262 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001263 }
1264 /* steady state not achieved */
1265 if (tries == 0) {
1266 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1267 hdmi_regs_dump(hdata, "timing apply");
1268 }
1269
Sean Paul0bfb1f82013-06-11 12:24:02 +05301270 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301271 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301272 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001273
1274 /* enable HDMI and timing generator */
1275 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1276 if (core->int_pro_mode[0])
1277 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1278 HDMI_FIELD_EN);
1279 else
1280 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1281}
1282
Rahul Sharma16844fb2013-06-10 14:50:00 +05301283static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001284{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001285 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1286 const struct hdmi_v14_core_regs *core =
1287 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001288 int tries;
1289
1290 /* setting core registers */
1291 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1292 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1293 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1294 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1295 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1296 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1297 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1298 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1299 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1300 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1301 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1302 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1303 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1304 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1305 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1306 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1307 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1308 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1309 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1310 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1311 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1312 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1313 core->v_sync_line_bef_2[0]);
1314 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1315 core->v_sync_line_bef_2[1]);
1316 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1317 core->v_sync_line_bef_1[0]);
1318 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1319 core->v_sync_line_bef_1[1]);
1320 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1321 core->v_sync_line_aft_2[0]);
1322 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1323 core->v_sync_line_aft_2[1]);
1324 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1325 core->v_sync_line_aft_1[0]);
1326 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1327 core->v_sync_line_aft_1[1]);
1328 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1329 core->v_sync_line_aft_pxl_2[0]);
1330 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1331 core->v_sync_line_aft_pxl_2[1]);
1332 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1333 core->v_sync_line_aft_pxl_1[0]);
1334 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1335 core->v_sync_line_aft_pxl_1[1]);
1336 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1337 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1338 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1339 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1340 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1341 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1342 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1343 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1344 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1345 core->v_sync_line_aft_3[0]);
1346 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1347 core->v_sync_line_aft_3[1]);
1348 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1349 core->v_sync_line_aft_4[0]);
1350 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1351 core->v_sync_line_aft_4[1]);
1352 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1353 core->v_sync_line_aft_5[0]);
1354 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1355 core->v_sync_line_aft_5[1]);
1356 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1357 core->v_sync_line_aft_6[0]);
1358 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1359 core->v_sync_line_aft_6[1]);
1360 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1361 core->v_sync_line_aft_pxl_3[0]);
1362 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1363 core->v_sync_line_aft_pxl_3[1]);
1364 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1365 core->v_sync_line_aft_pxl_4[0]);
1366 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1367 core->v_sync_line_aft_pxl_4[1]);
1368 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1369 core->v_sync_line_aft_pxl_5[0]);
1370 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1371 core->v_sync_line_aft_pxl_5[1]);
1372 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1373 core->v_sync_line_aft_pxl_6[0]);
1374 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1375 core->v_sync_line_aft_pxl_6[1]);
1376 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1377 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1378 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1379 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1380 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1381 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1382 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1383 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1384 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1385 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1386 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1387 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1388
1389 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001390 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1391 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1392 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1393 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1394 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1395 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1396 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1397 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1398 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1399 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1400 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1401 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1402 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1403 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1404 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1405 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1406 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1407 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1408 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1409 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1410 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1411 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1412 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1413 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1414 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1415 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1416 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1417 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1418 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1419 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1420 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1421 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1422 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001423
1424 /* waiting for HDMIPHY's PLL to get to steady state */
1425 for (tries = 100; tries; --tries) {
1426 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1427 if (val & HDMI_PHY_STATUS_READY)
1428 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001429 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001430 }
1431 /* steady state not achieved */
1432 if (tries == 0) {
1433 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1434 hdmi_regs_dump(hdata, "timing apply");
1435 }
1436
Sean Paul0bfb1f82013-06-11 12:24:02 +05301437 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301438 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301439 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001440
1441 /* enable HDMI and timing generator */
1442 hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
1443 if (core->int_pro_mode[0])
1444 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
1445 HDMI_FIELD_EN);
1446 else
1447 hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
1448}
1449
Rahul Sharma16844fb2013-06-10 14:50:00 +05301450static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001451{
Rahul Sharma5a325072012-10-04 20:48:54 +05301452 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301453 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001454 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301455 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001456}
1457
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001458static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1459{
1460 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001461 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001462
Sean Paul0bfb1f82013-06-11 12:24:02 +05301463 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301464 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301465 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001466
1467 /* operation mode */
1468 buffer[0] = 0x1f;
1469 buffer[1] = 0x00;
1470
1471 if (hdata->hdmiphy_port)
1472 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1473
Rahul Sharma5a325072012-10-04 20:48:54 +05301474 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001475 reg = HDMI_V13_PHY_RSTOUT;
1476 else
1477 reg = HDMI_PHY_RSTOUT;
1478
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001479 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001480 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001481 usleep_range(10000, 12000);
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);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001484}
1485
Rahul Sharmaa5562252012-11-28 11:30:25 +05301486static void hdmiphy_poweron(struct hdmi_context *hdata)
1487{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301488 if (hdata->type == HDMI_TYPE14)
1489 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1490 HDMI_PHY_POWER_OFF_EN);
1491}
1492
1493static void hdmiphy_poweroff(struct hdmi_context *hdata)
1494{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301495 if (hdata->type == HDMI_TYPE14)
1496 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1497 HDMI_PHY_POWER_OFF_EN);
1498}
1499
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001500static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1501{
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001502 const u8 *hdmiphy_data;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001503 u8 buffer[32];
1504 u8 operation[2];
1505 u8 read_buffer[32] = {0, };
1506 int ret;
1507 int i;
1508
1509 if (!hdata->hdmiphy_port) {
1510 DRM_ERROR("hdmiphy is not attached\n");
1511 return;
1512 }
1513
1514 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001515 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1516 if (i < 0) {
1517 DRM_ERROR("failed to find hdmiphy conf\n");
1518 return;
1519 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001520
Sachin Kamat5f46c332013-04-26 11:29:00 +05301521 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001522 hdmiphy_data = hdmiphy_v13_configs[i].conf;
Sachin Kamat5f46c332013-04-26 11:29:00 +05301523 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001524 hdmiphy_data = hdmiphy_v14_configs[i].conf;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001525
1526 memcpy(buffer, hdmiphy_data, 32);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001527 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
1528 if (ret != 32) {
1529 DRM_ERROR("failed to configure HDMIPHY via I2C\n");
1530 return;
1531 }
1532
Sean Paul09760ea2013-01-14 17:03:20 -05001533 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001534
1535 /* operation mode */
1536 operation[0] = 0x1f;
1537 operation[1] = 0x80;
1538
1539 ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
1540 if (ret != 2) {
1541 DRM_ERROR("failed to enable hdmiphy\n");
1542 return;
1543 }
1544
1545 ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
1546 if (ret < 0) {
1547 DRM_ERROR("failed to read hdmiphy config\n");
1548 return;
1549 }
1550
1551 for (i = 0; i < ret; i++)
1552 DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
1553 "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
1554}
1555
1556static void hdmi_conf_apply(struct hdmi_context *hdata)
1557{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001558 hdmiphy_conf_reset(hdata);
1559 hdmiphy_conf_apply(hdata);
1560
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001561 mutex_lock(&hdata->hdmi_mutex);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001562 hdmi_conf_reset(hdata);
1563 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001564 mutex_unlock(&hdata->hdmi_mutex);
1565
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001566 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001567
1568 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301569 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001570 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001571
1572 hdmi_regs_dump(hdata, "start");
1573}
1574
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001575static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1576{
1577 int i;
1578 BUG_ON(num_bytes > 4);
1579 for (i = 0; i < num_bytes; i++)
1580 reg_pair[i] = (value >> (8 * i)) & 0xff;
1581}
1582
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001583static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1584 struct drm_display_mode *m)
1585{
1586 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1587 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1588 unsigned int val;
1589
1590 hdata->mode_conf.cea_video_id =
1591 drm_match_cea_mode((struct drm_display_mode *)m);
1592 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301593 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001594
1595 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1596 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1597
1598 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1599 hdmi_set_reg(core->vsync_pol, 1, val);
1600
1601 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1602 hdmi_set_reg(core->int_pro_mode, 1, val);
1603
1604 val = (m->hsync_start - m->hdisplay - 2);
1605 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1606 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1607 hdmi_set_reg(core->h_sync_gen, 3, val);
1608
1609 /*
1610 * Quirk requirement for exynos HDMI IP design,
1611 * 2 pixels less than the actual calculation for hsync_start
1612 * and end.
1613 */
1614
1615 /* Following values & calculations differ for different type of modes */
1616 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1617 /* Interlaced Mode */
1618 val = ((m->vsync_end - m->vdisplay) / 2);
1619 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1620 hdmi_set_reg(core->v_sync_gen1, 3, val);
1621
1622 val = m->vtotal / 2;
1623 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1624 hdmi_set_reg(core->v_blank, 3, val);
1625
1626 val = (m->vtotal +
1627 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1628 val |= m->vtotal << 11;
1629 hdmi_set_reg(core->v_blank_f, 3, val);
1630
1631 val = ((m->vtotal / 2) + 7);
1632 val |= ((m->vtotal / 2) + 2) << 12;
1633 hdmi_set_reg(core->v_sync_gen2, 3, val);
1634
1635 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1636 val |= ((m->htotal / 2) +
1637 (m->hsync_start - m->hdisplay)) << 12;
1638 hdmi_set_reg(core->v_sync_gen3, 3, val);
1639
1640 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1641 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1642
1643 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1644 } else {
1645 /* Progressive Mode */
1646
1647 val = m->vtotal;
1648 val |= (m->vtotal - m->vdisplay) << 11;
1649 hdmi_set_reg(core->v_blank, 3, val);
1650
1651 hdmi_set_reg(core->v_blank_f, 3, 0);
1652
1653 val = (m->vsync_end - m->vdisplay);
1654 val |= ((m->vsync_start - m->vdisplay) << 12);
1655 hdmi_set_reg(core->v_sync_gen1, 3, val);
1656
1657 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1658 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1659 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1660 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1661 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1662 }
1663
1664 /* Timing generator registers */
1665 hdmi_set_reg(tg->cmd, 1, 0x0);
1666 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1667 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1668 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1669 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1670 hdmi_set_reg(tg->vsync, 2, 0x1);
1671 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1672 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1673 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1674 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1675 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1676 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1677 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1678}
1679
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001680static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1681 struct drm_display_mode *m)
1682{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001683 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1684 struct hdmi_v14_core_regs *core =
1685 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001686
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001687 hdata->mode_conf.cea_video_id =
1688 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001689 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301690 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001691
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001692 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1693 hdmi_set_reg(core->v_line, 2, m->vtotal);
1694 hdmi_set_reg(core->h_line, 2, m->htotal);
1695 hdmi_set_reg(core->hsync_pol, 1,
1696 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1697 hdmi_set_reg(core->vsync_pol, 1,
1698 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1699 hdmi_set_reg(core->int_pro_mode, 1,
1700 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1701
1702 /*
1703 * Quirk requirement for exynos 5 HDMI IP design,
1704 * 2 pixels less than the actual calculation for hsync_start
1705 * and end.
1706 */
1707
1708 /* Following values & calculations differ for different type of modes */
1709 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1710 /* Interlaced Mode */
1711 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1712 (m->vsync_end - m->vdisplay) / 2);
1713 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1714 (m->vsync_start - m->vdisplay) / 2);
1715 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1716 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301717 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001718 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1719 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1720 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1721 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1722 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1723 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1724 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1725 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1726 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301727 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1728 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1729 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1730 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001731 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1732 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1733 } else {
1734 /* Progressive Mode */
1735 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1736 m->vsync_end - m->vdisplay);
1737 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1738 m->vsync_start - m->vdisplay);
1739 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1740 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1741 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1742 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1743 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1744 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1745 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1746 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1747 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1748 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1749 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1750 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1751 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301752 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1753 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1754 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001755 }
1756
1757 /* Following values & calculations are same irrespective of mode type */
1758 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1759 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1760 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1761 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1762 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1763 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1764 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1765 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1766 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1767 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1768 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1769 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1770 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1771 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1772 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1773 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1774 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1775 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1776 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1777 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1778
1779 /* Timing generator registers */
1780 hdmi_set_reg(tg->cmd, 1, 0x0);
1781 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1782 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1783 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1784 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1785 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001786 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1787 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001788 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001789 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001790}
1791
Sean Paulf041b252014-01-30 16:19:15 -05001792static void hdmi_mode_set(struct exynos_drm_display *display,
1793 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001794{
Sean Paulf041b252014-01-30 16:19:15 -05001795 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001796 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001797
YoungJun Chocbc4c332013-06-12 10:44:40 +09001798 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1799 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001800 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1801 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001802
Sachin Kamat5f46c332013-04-26 11:29:00 +05301803 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001804 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301805 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001806 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001807}
1808
Sean Paulf041b252014-01-30 16:19:15 -05001809static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001810{
Sean Paulf041b252014-01-30 16:19:15 -05001811 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001812
Shirish Sdda90122013-01-23 22:03:18 -05001813 mutex_lock(&hdata->hdmi_mutex);
1814 if (!hdata->powered) {
1815 mutex_unlock(&hdata->hdmi_mutex);
1816 return;
1817 }
1818 mutex_unlock(&hdata->hdmi_mutex);
1819
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001820 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001821}
1822
Sean Paulf041b252014-01-30 16:19:15 -05001823static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001824{
Sean Paulf041b252014-01-30 16:19:15 -05001825 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001826 struct hdmi_resources *res = &hdata->res;
1827
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001828 mutex_lock(&hdata->hdmi_mutex);
1829 if (hdata->powered) {
1830 mutex_unlock(&hdata->hdmi_mutex);
1831 return;
1832 }
1833
1834 hdata->powered = true;
1835
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001836 mutex_unlock(&hdata->hdmi_mutex);
1837
Sean Paulaf65c802014-01-30 16:19:27 -05001838 pm_runtime_get_sync(hdata->dev);
1839
Seung-Woo Kimad079452013-06-05 14:34:38 +09001840 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1841 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1842
Sean Paul0bfb1f82013-06-11 12:24:02 +05301843 clk_prepare_enable(res->hdmiphy);
1844 clk_prepare_enable(res->hdmi);
1845 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301846
1847 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05001848 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001849}
1850
Sean Paulf041b252014-01-30 16:19:15 -05001851static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001852{
Sean Paulf041b252014-01-30 16:19:15 -05001853 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001854 struct hdmi_resources *res = &hdata->res;
1855
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001856 mutex_lock(&hdata->hdmi_mutex);
1857 if (!hdata->powered)
1858 goto out;
1859 mutex_unlock(&hdata->hdmi_mutex);
1860
Rahul Sharmaa5562252012-11-28 11:30:25 +05301861 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001862
Sean Paul724fd142014-05-09 15:05:10 +09001863 cancel_delayed_work(&hdata->hotplug_work);
1864
Sean Paul0bfb1f82013-06-11 12:24:02 +05301865 clk_disable_unprepare(res->sclk_hdmi);
1866 clk_disable_unprepare(res->hdmi);
1867 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001868 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1869
Sean Paulaf65c802014-01-30 16:19:27 -05001870 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001871
Sean Paulaf65c802014-01-30 16:19:27 -05001872 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001873 hdata->powered = false;
1874
1875out:
1876 mutex_unlock(&hdata->hdmi_mutex);
1877}
1878
Sean Paulf041b252014-01-30 16:19:15 -05001879static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001880{
YoungJun Chocbc4c332013-06-12 10:44:40 +09001881 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001882
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001883 switch (mode) {
1884 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05001885 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001886 break;
1887 case DRM_MODE_DPMS_STANDBY:
1888 case DRM_MODE_DPMS_SUSPEND:
1889 case DRM_MODE_DPMS_OFF:
Sean Paulaf65c802014-01-30 16:19:27 -05001890 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001891 break;
1892 default:
1893 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1894 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001895 }
1896}
1897
Sean Paulf041b252014-01-30 16:19:15 -05001898static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001899 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05001900 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001901 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05001902 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001903 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001904};
1905
Sean Paulf041b252014-01-30 16:19:15 -05001906static struct exynos_drm_display hdmi_display = {
1907 .type = EXYNOS_DISPLAY_TYPE_HDMI,
1908 .ops = &hdmi_display_ops,
1909};
1910
Sean Paul724fd142014-05-09 15:05:10 +09001911static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001912{
Sean Paul724fd142014-05-09 15:05:10 +09001913 struct hdmi_context *hdata;
1914
1915 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001916
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001917 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301918 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001919 mutex_unlock(&hdata->hdmi_mutex);
1920
Sean Paul45517892014-01-30 16:19:05 -05001921 if (hdata->drm_dev)
1922 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001923}
1924
1925static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1926{
1927 struct hdmi_context *hdata = arg;
1928
1929 mod_delayed_work(system_wq, &hdata->hotplug_work,
1930 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001931
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001932 return IRQ_HANDLED;
1933}
1934
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001935static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001936{
1937 struct device *dev = hdata->dev;
1938 struct hdmi_resources *res = &hdata->res;
1939 static char *supply[] = {
1940 "hdmi-en",
1941 "vdd",
1942 "vdd_osc",
1943 "vdd_pll",
1944 };
1945 int i, ret;
1946
1947 DRM_DEBUG_KMS("HDMI resource init\n");
1948
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001949 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301950 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301951 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001952 DRM_ERROR("failed to get clock 'hdmi'\n");
1953 goto fail;
1954 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301955 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301956 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001957 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1958 goto fail;
1959 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301960 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301961 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001962 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1963 goto fail;
1964 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301965 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301966 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001967 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1968 goto fail;
1969 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301970 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301971 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001972 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1973 goto fail;
1974 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301975 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1976 if (IS_ERR(res->mout_hdmi)) {
1977 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1978 goto fail;
1979 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001980
Rahul Sharma59956d32013-06-11 12:24:03 +05301981 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001982
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301983 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301984 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001985 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001986 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001987 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
1988 res->regul_bulk[i].supply = supply[i];
1989 res->regul_bulk[i].consumer = NULL;
1990 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301991 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001992 if (ret) {
1993 DRM_ERROR("failed to get regulators\n");
1994 goto fail;
1995 }
1996 res->regul_count = ARRAY_SIZE(supply);
1997
1998 return 0;
1999fail:
2000 DRM_ERROR("HDMI resource init - failed\n");
2001 return -ENODEV;
2002}
2003
Rahul Sharma22c4f422012-10-04 20:48:55 +05302004static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2005 (struct device *dev)
2006{
2007 struct device_node *np = dev->of_node;
2008 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302009 u32 value;
2010
2011 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002012 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302013 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302014
2015 if (!of_find_property(np, "hpd-gpio", &value)) {
2016 DRM_ERROR("no hpd gpio property found\n");
2017 goto err_data;
2018 }
2019
Rahul Sharma5f916e22013-06-11 19:41:29 +05302020 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302021
2022 return pd;
2023
2024err_data:
2025 return NULL;
2026}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302027
Rahul Sharma22c4f422012-10-04 20:48:55 +05302028static struct of_device_id hdmi_match_types[] = {
2029 {
2030 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002031 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302032 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302033 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002034 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302035 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302036 /* end node */
2037 }
2038};
2039
Inki Daef37cd5e2014-05-09 14:25:20 +09002040static int hdmi_bind(struct device *dev, struct device *master, void *data)
2041{
2042 struct drm_device *drm_dev = data;
2043 struct hdmi_context *hdata;
2044
2045 hdata = hdmi_display.ctx;
2046 hdata->drm_dev = drm_dev;
2047
2048 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2049}
2050
2051static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2052{
2053 struct exynos_drm_display *display = get_hdmi_display(dev);
2054 struct drm_encoder *encoder = display->encoder;
2055 struct hdmi_context *hdata = display->ctx;
2056
2057 encoder->funcs->destroy(encoder);
2058 drm_connector_cleanup(&hdata->connector);
2059}
2060
2061static const struct component_ops hdmi_component_ops = {
2062 .bind = hdmi_bind,
2063 .unbind = hdmi_unbind,
2064};
2065
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002066static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002067{
Inki Daef37cd5e2014-05-09 14:25:20 +09002068 struct device_node *ddc_node, *phy_node;
2069 struct s5p_hdmi_platform_data *pdata;
2070 struct hdmi_driver_data *drv_data;
2071 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002072 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002073 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002074 struct resource *res;
2075 int ret;
2076
Inki Daef37cd5e2014-05-09 14:25:20 +09002077 if (!dev->of_node)
Sachin Kamat88c49812013-08-28 10:47:57 +05302078 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302079
Sachin Kamat88c49812013-08-28 10:47:57 +05302080 pdata = drm_hdmi_dt_parse_pdata(dev);
2081 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002082 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002083
Sachin Kamat88c49812013-08-28 10:47:57 +05302084 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002085 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002086 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002087
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002088 mutex_init(&hdata->hdmi_mutex);
2089
Sean Paulf041b252014-01-30 16:19:15 -05002090 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002091
Sachin Kamat88c49812013-08-28 10:47:57 +05302092 match = of_match_node(hdmi_match_types, dev->of_node);
2093 if (!match)
2094 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002095
2096 drv_data = (struct hdmi_driver_data *)match->data;
2097 hdata->type = drv_data->type;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302098
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302099 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002100 hdata->dev = dev;
2101
2102 ret = hdmi_resources_init(hdata);
2103 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302104 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302105 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002106 }
2107
2108 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002109 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01002110 if (IS_ERR(hdata->regs))
2111 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002112
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002113 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302114 if (ret) {
2115 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302116 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302117 }
2118
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002119 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002120 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2121 if (!ddc_node) {
2122 DRM_ERROR("Failed to find ddc node in device tree\n");
2123 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002124 }
Inki Dae8fa04aa2014-03-13 16:38:31 +09002125 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2126 if (!hdata->ddc_adpt) {
2127 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Daniel Kurtz2b768132014-02-24 18:52:51 +09002128 return -ENODEV;
2129 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002130
Inki Daebfe4e842014-03-06 14:18:17 +09002131 /* Not support APB PHY yet. */
2132 if (drv_data->is_apb_phy)
2133 return -EPERM;
2134
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002135 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002136 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2137 if (!phy_node) {
2138 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2139 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002140 goto err_ddc;
2141 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002142 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2143 if (!hdata->hdmiphy_port) {
2144 DRM_ERROR("Failed to get hdmi phy i2c client from node\n");
2145 ret = -ENODEV;
2146 goto err_ddc;
2147 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002148
Sean Paul77006a72013-01-16 10:17:20 -05002149 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2150 if (hdata->irq < 0) {
2151 DRM_ERROR("failed to get GPIO irq\n");
2152 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002153 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002154 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002155
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302156 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2157
Sean Paul724fd142014-05-09 15:05:10 +09002158 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2159
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002160 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002161 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002162 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002163 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002164 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002165 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002166 goto err_hdmiphy;
2167 }
2168
Sean Paulaf65c802014-01-30 16:19:27 -05002169 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002170 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002171
Inki Daef37cd5e2014-05-09 14:25:20 +09002172 return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002173
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002174err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002175 if (hdata->hdmiphy_port)
2176 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002177err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002178 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002179 return ret;
2180}
2181
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002182static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002183{
Inki Daef37cd5e2014-05-09 14:25:20 +09002184 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002185
Sean Paul724fd142014-05-09 15:05:10 +09002186 cancel_delayed_work_sync(&hdata->hotplug_work);
2187
Daniel Kurtz2b768132014-02-24 18:52:51 +09002188 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002189 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002190
Sean Paulaf65c802014-01-30 16:19:27 -05002191 pm_runtime_disable(&pdev->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002192
Inki Daef37cd5e2014-05-09 14:25:20 +09002193 exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194 return 0;
2195}
2196
2197struct platform_driver hdmi_driver = {
2198 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002199 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002200 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302201 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002202 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302203 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002204 },
2205};