blob: a04fb291b6c2c6d9f7bec0ccd26bf87f6b08f4c8 [file] [log] [blame]
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001/*
2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
3 * Authors:
4 * Seung-Woo Kim <sw0312.kim@samsung.com>
5 * Inki Dae <inki.dae@samsung.com>
6 * Joonyoung Shim <jy0922.shim@samsung.com>
7 *
8 * Based on drivers/media/video/s5p-tv/hdmi_drv.c
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
David Howells760285e2012-10-02 18:01:07 +010017#include <drm/drmP.h>
18#include <drm/drm_edid.h>
19#include <drm/drm_crtc_helper.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090020
21#include "regs-hdmi.h"
22
23#include <linux/kernel.h>
24#include <linux/spinlock.h>
25#include <linux/wait.h>
26#include <linux/i2c.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090027#include <linux/platform_device.h>
28#include <linux/interrupt.h>
29#include <linux/irq.h>
30#include <linux/delay.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/regulator/consumer.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053034#include <linux/io.h>
Sachin Kamat3f1c7812013-08-14 16:38:01 +053035#include <linux/of.h>
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090036#include <linux/of_address.h>
Daniel Kurtz2b768132014-02-24 18:52:51 +090037#include <linux/i2c.h>
Rahul Sharma22c4f422012-10-04 20:48:55 +053038#include <linux/of_gpio.h>
Sachin Kamatd34d59b2014-02-04 08:40:18 +053039#include <linux/hdmi.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090040#include <linux/component.h>
Seung-Woo Kimd8408322011-12-21 17:39:39 +090041
42#include <drm/exynos_drm.h>
43
44#include "exynos_drm_drv.h"
Inki Daef37cd5e2014-05-09 14:25:20 +090045#include "exynos_drm_crtc.h"
Sean Paulf041b252014-01-30 16:19:15 -050046#include "exynos_mixer.h"
Seung-Woo Kimd8408322011-12-21 17:39:39 +090047
Tomasz Stanislawskifca57122012-10-04 20:48:46 +053048#include <linux/gpio.h>
49#include <media/s5p_hdmi.h>
50
Sean Paulf041b252014-01-30 16:19:15 -050051#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev))
Sean Pauld9716ee2014-01-30 16:19:29 -050052#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +090053
Sean Paul724fd142014-05-09 15:05:10 +090054#define HOTPLUG_DEBOUNCE_MS 1100
55
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053056/* AVI header and aspect ratio */
57#define HDMI_AVI_VERSION 0x02
58#define HDMI_AVI_LENGTH 0x0D
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053059
60/* AUI header info */
61#define HDMI_AUI_VERSION 0x01
62#define HDMI_AUI_LENGTH 0x0A
Shirish S46154152014-03-13 10:58:28 +053063#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
64#define AVI_4_3_CENTER_RATIO 0x9
65#define AVI_16_9_CENTER_RATIO 0xa
Rahul Sharmaa144c2e2012-11-26 10:52:57 +053066
Rahul Sharma5a325072012-10-04 20:48:54 +053067enum hdmi_type {
68 HDMI_TYPE13,
69 HDMI_TYPE14,
70};
71
Inki Daebfe4e842014-03-06 14:18:17 +090072struct hdmi_driver_data {
73 unsigned int type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +090074 const struct hdmiphy_config *phy_confs;
75 unsigned int phy_conf_count;
Inki Daebfe4e842014-03-06 14:18:17 +090076 unsigned int is_apb_phy:1;
77};
78
Joonyoung Shim590f4182012-03-16 18:47:14 +090079struct hdmi_resources {
80 struct clk *hdmi;
81 struct clk *sclk_hdmi;
82 struct clk *sclk_pixel;
83 struct clk *sclk_hdmiphy;
84 struct clk *hdmiphy;
Rahul Sharma59956d32013-06-11 12:24:03 +053085 struct clk *mout_hdmi;
Joonyoung Shim590f4182012-03-16 18:47:14 +090086 struct regulator_bulk_data *regul_bulk;
87 int regul_count;
88};
89
Sean Paul2f7e2ed2013-01-15 08:11:08 -050090struct hdmi_tg_regs {
91 u8 cmd[1];
92 u8 h_fsz[2];
93 u8 hact_st[2];
94 u8 hact_sz[2];
95 u8 v_fsz[2];
96 u8 vsync[2];
97 u8 vsync2[2];
98 u8 vact_st[2];
99 u8 vact_sz[2];
100 u8 field_chg[2];
101 u8 vact_st2[2];
102 u8 vact_st3[2];
103 u8 vact_st4[2];
104 u8 vsync_top_hdmi[2];
105 u8 vsync_bot_hdmi[2];
106 u8 field_top_hdmi[2];
107 u8 field_bot_hdmi[2];
108 u8 tg_3d[1];
109};
110
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900111struct hdmi_v13_core_regs {
112 u8 h_blank[2];
113 u8 v_blank[3];
114 u8 h_v_line[3];
115 u8 vsync_pol[1];
116 u8 int_pro_mode[1];
117 u8 v_blank_f[3];
118 u8 h_sync_gen[3];
119 u8 v_sync_gen1[3];
120 u8 v_sync_gen2[3];
121 u8 v_sync_gen3[3];
122};
123
124struct hdmi_v14_core_regs {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500125 u8 h_blank[2];
126 u8 v2_blank[2];
127 u8 v1_blank[2];
128 u8 v_line[2];
129 u8 h_line[2];
130 u8 hsync_pol[1];
131 u8 vsync_pol[1];
132 u8 int_pro_mode[1];
133 u8 v_blank_f0[2];
134 u8 v_blank_f1[2];
135 u8 h_sync_start[2];
136 u8 h_sync_end[2];
137 u8 v_sync_line_bef_2[2];
138 u8 v_sync_line_bef_1[2];
139 u8 v_sync_line_aft_2[2];
140 u8 v_sync_line_aft_1[2];
141 u8 v_sync_line_aft_pxl_2[2];
142 u8 v_sync_line_aft_pxl_1[2];
143 u8 v_blank_f2[2]; /* for 3D mode */
144 u8 v_blank_f3[2]; /* for 3D mode */
145 u8 v_blank_f4[2]; /* for 3D mode */
146 u8 v_blank_f5[2]; /* for 3D mode */
147 u8 v_sync_line_aft_3[2];
148 u8 v_sync_line_aft_4[2];
149 u8 v_sync_line_aft_5[2];
150 u8 v_sync_line_aft_6[2];
151 u8 v_sync_line_aft_pxl_3[2];
152 u8 v_sync_line_aft_pxl_4[2];
153 u8 v_sync_line_aft_pxl_5[2];
154 u8 v_sync_line_aft_pxl_6[2];
155 u8 vact_space_1[2];
156 u8 vact_space_2[2];
157 u8 vact_space_3[2];
158 u8 vact_space_4[2];
159 u8 vact_space_5[2];
160 u8 vact_space_6[2];
161};
162
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900163struct hdmi_v13_conf {
164 struct hdmi_v13_core_regs core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500165 struct hdmi_tg_regs tg;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900166};
167
168struct hdmi_v14_conf {
169 struct hdmi_v14_core_regs core;
170 struct hdmi_tg_regs tg;
171};
172
173struct hdmi_conf_regs {
174 int pixel_clock;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500175 int cea_video_id;
Shirish S46154152014-03-13 10:58:28 +0530176 enum hdmi_picture_aspect aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900177 union {
178 struct hdmi_v13_conf v13_conf;
179 struct hdmi_v14_conf v14_conf;
180 } conf;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500181};
182
Joonyoung Shim590f4182012-03-16 18:47:14 +0900183struct hdmi_context {
184 struct device *dev;
185 struct drm_device *drm_dev;
Sean Pauld9716ee2014-01-30 16:19:29 -0500186 struct drm_connector connector;
187 struct drm_encoder *encoder;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900188 bool hpd;
189 bool powered;
Seung-Woo Kim872d20d62012-04-24 17:39:15 +0900190 bool dvi_mode;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +0900191 struct mutex hdmi_mutex;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900192
Joonyoung Shim590f4182012-03-16 18:47:14 +0900193 void __iomem *regs;
Sean Paul77006a72013-01-16 10:17:20 -0500194 int irq;
Sean Paul724fd142014-05-09 15:05:10 +0900195 struct delayed_work hotplug_work;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900196
Inki Dae8fa04aa2014-03-13 16:38:31 +0900197 struct i2c_adapter *ddc_adpt;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900198 struct i2c_client *hdmiphy_port;
199
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900200 /* current hdmiphy conf regs */
Rahul Sharmabfa48422014-04-03 20:41:04 +0530201 struct drm_display_mode current_mode;
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900202 struct hdmi_conf_regs mode_conf;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900203
204 struct hdmi_resources res;
Joonyoung Shim7ecd34e2012-04-23 19:35:47 +0900205
Tomasz Stanislawskifca57122012-10-04 20:48:46 +0530206 int hpd_gpio;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900207 void __iomem *regs_hdmiphy;
208 const struct hdmiphy_config *phy_confs;
209 unsigned int phy_conf_count;
Rahul Sharma5a325072012-10-04 20:48:54 +0530210
211 enum hdmi_type type;
Joonyoung Shim590f4182012-03-16 18:47:14 +0900212};
213
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500214struct hdmiphy_config {
215 int pixel_clock;
216 u8 conf[32];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900217};
218
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900219/* list of phy config settings */
220static const struct hdmiphy_config hdmiphy_v13_configs[] = {
221 {
222 .pixel_clock = 27000000,
223 .conf = {
224 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
225 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
226 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
227 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
228 },
229 },
230 {
231 .pixel_clock = 27027000,
232 .conf = {
233 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
234 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
235 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
236 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
237 },
238 },
239 {
240 .pixel_clock = 74176000,
241 .conf = {
242 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
243 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
244 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
245 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
246 },
247 },
248 {
249 .pixel_clock = 74250000,
250 .conf = {
251 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
252 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
253 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
254 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
255 },
256 },
257 {
258 .pixel_clock = 148500000,
259 .conf = {
260 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
261 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
262 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
263 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
264 },
265 },
266};
267
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500268static const struct hdmiphy_config hdmiphy_v14_configs[] = {
269 {
270 .pixel_clock = 25200000,
271 .conf = {
272 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
273 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
274 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
275 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
276 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900277 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500278 {
279 .pixel_clock = 27000000,
280 .conf = {
281 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
282 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
283 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
284 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
285 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900286 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500287 {
288 .pixel_clock = 27027000,
289 .conf = {
290 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
291 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
292 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
293 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
294 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900295 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500296 {
297 .pixel_clock = 36000000,
298 .conf = {
299 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
300 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
301 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
302 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
303 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900304 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500305 {
306 .pixel_clock = 40000000,
307 .conf = {
308 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
309 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
310 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
311 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
312 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900313 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500314 {
315 .pixel_clock = 65000000,
316 .conf = {
317 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
318 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
319 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
320 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
321 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900322 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500323 {
Shirish Se1d883c2014-03-13 14:28:27 +0900324 .pixel_clock = 71000000,
325 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530326 0x01, 0xd1, 0x3b, 0x35, 0x40, 0x0c, 0x04, 0x08,
327 0x85, 0xa0, 0x63, 0xd9, 0x45, 0xa0, 0xac, 0x80,
328 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900329 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
330 },
331 },
332 {
333 .pixel_clock = 73250000,
334 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530335 0x01, 0xd1, 0x3d, 0x35, 0x40, 0x18, 0x02, 0x08,
336 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
337 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900338 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
339 },
340 },
341 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500342 .pixel_clock = 74176000,
343 .conf = {
344 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
345 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
346 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
347 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
348 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900349 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500350 {
351 .pixel_clock = 74250000,
352 .conf = {
353 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
354 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
355 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
356 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
357 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900358 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500359 {
360 .pixel_clock = 83500000,
361 .conf = {
362 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
363 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
364 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
365 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
366 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900367 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500368 {
369 .pixel_clock = 106500000,
370 .conf = {
371 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
372 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
373 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
374 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
375 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900376 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500377 {
378 .pixel_clock = 108000000,
379 .conf = {
380 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
381 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
382 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
383 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
384 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900385 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500386 {
Shirish Se1d883c2014-03-13 14:28:27 +0900387 .pixel_clock = 115500000,
388 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530389 0x01, 0xd1, 0x30, 0x12, 0x40, 0x40, 0x10, 0x08,
390 0x80, 0x80, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
391 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900392 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
393 },
394 },
395 {
396 .pixel_clock = 119000000,
397 .conf = {
Shirish S96d26532014-05-05 10:27:51 +0530398 0x01, 0xd1, 0x32, 0x1a, 0x40, 0x30, 0xd8, 0x08,
399 0x04, 0xa0, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
400 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
Shirish Se1d883c2014-03-13 14:28:27 +0900401 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
402 },
403 },
404 {
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500405 .pixel_clock = 146250000,
406 .conf = {
407 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
408 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
409 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
410 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
411 },
Seung-Woo Kime540adf2012-04-24 17:55:06 +0900412 },
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500413 {
414 .pixel_clock = 148500000,
415 .conf = {
416 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
417 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
418 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
419 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
420 },
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900421 },
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900422};
423
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900424
425struct hdmi_driver_data exynos4212_hdmi_driver_data = {
426 .type = HDMI_TYPE14,
427 .phy_confs = hdmiphy_v14_configs,
428 .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs),
429 .is_apb_phy = 0,
430};
431
432struct hdmi_driver_data exynos5_hdmi_driver_data = {
433 .type = HDMI_TYPE14,
434 .phy_confs = hdmiphy_v13_configs,
435 .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
436 .is_apb_phy = 0,
437};
438
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900439static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
440{
441 return readl(hdata->regs + reg_id);
442}
443
444static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
445 u32 reg_id, u8 value)
446{
447 writeb(value, hdata->regs + reg_id);
448}
449
450static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
451 u32 reg_id, u32 value, u32 mask)
452{
453 u32 old = readl(hdata->regs + reg_id);
454 value = (value & mask) | (old & ~mask);
455 writel(value, hdata->regs + reg_id);
456}
457
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900458static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
459 u32 reg_offset, u8 value)
460{
461 if (hdata->hdmiphy_port) {
462 u8 buffer[2];
463 int ret;
464
465 buffer[0] = reg_offset;
466 buffer[1] = value;
467
468 ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
469 if (ret == 2)
470 return 0;
471 return ret;
472 } else {
473 writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
474 return 0;
475 }
476}
477
478static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
479 u32 reg_offset, const u8 *buf, u32 len)
480{
481 if ((reg_offset + len) > 32)
482 return -EINVAL;
483
484 if (hdata->hdmiphy_port) {
485 int ret;
486
487 ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
488 if (ret == len)
489 return 0;
490 return ret;
491 } else {
492 int i;
493 for (i = 0; i < len; i++)
494 writeb(buf[i], hdata->regs_hdmiphy +
495 ((reg_offset + i)<<2));
496 return 0;
497 }
498}
499
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900500static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900501{
502#define DUMPREG(reg_id) \
503 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
504 readl(hdata->regs + reg_id))
505 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
506 DUMPREG(HDMI_INTC_FLAG);
507 DUMPREG(HDMI_INTC_CON);
508 DUMPREG(HDMI_HPD_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900509 DUMPREG(HDMI_V13_PHY_RSTOUT);
510 DUMPREG(HDMI_V13_PHY_VPLL);
511 DUMPREG(HDMI_V13_PHY_CMU);
512 DUMPREG(HDMI_V13_CORE_RSTOUT);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900513
514 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
515 DUMPREG(HDMI_CON_0);
516 DUMPREG(HDMI_CON_1);
517 DUMPREG(HDMI_CON_2);
518 DUMPREG(HDMI_SYS_STATUS);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900519 DUMPREG(HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900520 DUMPREG(HDMI_STATUS_EN);
521 DUMPREG(HDMI_HPD);
522 DUMPREG(HDMI_MODE_SEL);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900523 DUMPREG(HDMI_V13_HPD_GEN);
524 DUMPREG(HDMI_V13_DC_CONTROL);
525 DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900526
527 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
528 DUMPREG(HDMI_H_BLANK_0);
529 DUMPREG(HDMI_H_BLANK_1);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900530 DUMPREG(HDMI_V13_V_BLANK_0);
531 DUMPREG(HDMI_V13_V_BLANK_1);
532 DUMPREG(HDMI_V13_V_BLANK_2);
533 DUMPREG(HDMI_V13_H_V_LINE_0);
534 DUMPREG(HDMI_V13_H_V_LINE_1);
535 DUMPREG(HDMI_V13_H_V_LINE_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900536 DUMPREG(HDMI_VSYNC_POL);
537 DUMPREG(HDMI_INT_PRO_MODE);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900538 DUMPREG(HDMI_V13_V_BLANK_F_0);
539 DUMPREG(HDMI_V13_V_BLANK_F_1);
540 DUMPREG(HDMI_V13_V_BLANK_F_2);
541 DUMPREG(HDMI_V13_H_SYNC_GEN_0);
542 DUMPREG(HDMI_V13_H_SYNC_GEN_1);
543 DUMPREG(HDMI_V13_H_SYNC_GEN_2);
544 DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
545 DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
546 DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
547 DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
548 DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
549 DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
550 DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
551 DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
552 DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900553
554 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
555 DUMPREG(HDMI_TG_CMD);
556 DUMPREG(HDMI_TG_H_FSZ_L);
557 DUMPREG(HDMI_TG_H_FSZ_H);
558 DUMPREG(HDMI_TG_HACT_ST_L);
559 DUMPREG(HDMI_TG_HACT_ST_H);
560 DUMPREG(HDMI_TG_HACT_SZ_L);
561 DUMPREG(HDMI_TG_HACT_SZ_H);
562 DUMPREG(HDMI_TG_V_FSZ_L);
563 DUMPREG(HDMI_TG_V_FSZ_H);
564 DUMPREG(HDMI_TG_VSYNC_L);
565 DUMPREG(HDMI_TG_VSYNC_H);
566 DUMPREG(HDMI_TG_VSYNC2_L);
567 DUMPREG(HDMI_TG_VSYNC2_H);
568 DUMPREG(HDMI_TG_VACT_ST_L);
569 DUMPREG(HDMI_TG_VACT_ST_H);
570 DUMPREG(HDMI_TG_VACT_SZ_L);
571 DUMPREG(HDMI_TG_VACT_SZ_H);
572 DUMPREG(HDMI_TG_FIELD_CHG_L);
573 DUMPREG(HDMI_TG_FIELD_CHG_H);
574 DUMPREG(HDMI_TG_VACT_ST2_L);
575 DUMPREG(HDMI_TG_VACT_ST2_H);
576 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
577 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
578 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
579 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
580 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
581 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
582 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
583 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
584#undef DUMPREG
585}
586
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900587static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
588{
589 int i;
590
591#define DUMPREG(reg_id) \
592 DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
593 readl(hdata->regs + reg_id))
594
595 DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
596 DUMPREG(HDMI_INTC_CON);
597 DUMPREG(HDMI_INTC_FLAG);
598 DUMPREG(HDMI_HPD_STATUS);
599 DUMPREG(HDMI_INTC_CON_1);
600 DUMPREG(HDMI_INTC_FLAG_1);
601 DUMPREG(HDMI_PHY_STATUS_0);
602 DUMPREG(HDMI_PHY_STATUS_PLL);
603 DUMPREG(HDMI_PHY_CON_0);
604 DUMPREG(HDMI_PHY_RSTOUT);
605 DUMPREG(HDMI_PHY_VPLL);
606 DUMPREG(HDMI_PHY_CMU);
607 DUMPREG(HDMI_CORE_RSTOUT);
608
609 DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
610 DUMPREG(HDMI_CON_0);
611 DUMPREG(HDMI_CON_1);
612 DUMPREG(HDMI_CON_2);
613 DUMPREG(HDMI_SYS_STATUS);
614 DUMPREG(HDMI_PHY_STATUS_0);
615 DUMPREG(HDMI_STATUS_EN);
616 DUMPREG(HDMI_HPD);
617 DUMPREG(HDMI_MODE_SEL);
618 DUMPREG(HDMI_ENC_EN);
619 DUMPREG(HDMI_DC_CONTROL);
620 DUMPREG(HDMI_VIDEO_PATTERN_GEN);
621
622 DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
623 DUMPREG(HDMI_H_BLANK_0);
624 DUMPREG(HDMI_H_BLANK_1);
625 DUMPREG(HDMI_V2_BLANK_0);
626 DUMPREG(HDMI_V2_BLANK_1);
627 DUMPREG(HDMI_V1_BLANK_0);
628 DUMPREG(HDMI_V1_BLANK_1);
629 DUMPREG(HDMI_V_LINE_0);
630 DUMPREG(HDMI_V_LINE_1);
631 DUMPREG(HDMI_H_LINE_0);
632 DUMPREG(HDMI_H_LINE_1);
633 DUMPREG(HDMI_HSYNC_POL);
634
635 DUMPREG(HDMI_VSYNC_POL);
636 DUMPREG(HDMI_INT_PRO_MODE);
637 DUMPREG(HDMI_V_BLANK_F0_0);
638 DUMPREG(HDMI_V_BLANK_F0_1);
639 DUMPREG(HDMI_V_BLANK_F1_0);
640 DUMPREG(HDMI_V_BLANK_F1_1);
641
642 DUMPREG(HDMI_H_SYNC_START_0);
643 DUMPREG(HDMI_H_SYNC_START_1);
644 DUMPREG(HDMI_H_SYNC_END_0);
645 DUMPREG(HDMI_H_SYNC_END_1);
646
647 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
648 DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
649 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
650 DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
651
652 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
653 DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
654 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
655 DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
656
657 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
658 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
659 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
660 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
661
662 DUMPREG(HDMI_V_BLANK_F2_0);
663 DUMPREG(HDMI_V_BLANK_F2_1);
664 DUMPREG(HDMI_V_BLANK_F3_0);
665 DUMPREG(HDMI_V_BLANK_F3_1);
666 DUMPREG(HDMI_V_BLANK_F4_0);
667 DUMPREG(HDMI_V_BLANK_F4_1);
668 DUMPREG(HDMI_V_BLANK_F5_0);
669 DUMPREG(HDMI_V_BLANK_F5_1);
670
671 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
672 DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
673 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
674 DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
675 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
676 DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
677 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
678 DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
679
680 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
681 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
682 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
683 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
684 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
685 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
686 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
687 DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
688
689 DUMPREG(HDMI_VACT_SPACE_1_0);
690 DUMPREG(HDMI_VACT_SPACE_1_1);
691 DUMPREG(HDMI_VACT_SPACE_2_0);
692 DUMPREG(HDMI_VACT_SPACE_2_1);
693 DUMPREG(HDMI_VACT_SPACE_3_0);
694 DUMPREG(HDMI_VACT_SPACE_3_1);
695 DUMPREG(HDMI_VACT_SPACE_4_0);
696 DUMPREG(HDMI_VACT_SPACE_4_1);
697 DUMPREG(HDMI_VACT_SPACE_5_0);
698 DUMPREG(HDMI_VACT_SPACE_5_1);
699 DUMPREG(HDMI_VACT_SPACE_6_0);
700 DUMPREG(HDMI_VACT_SPACE_6_1);
701
702 DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
703 DUMPREG(HDMI_TG_CMD);
704 DUMPREG(HDMI_TG_H_FSZ_L);
705 DUMPREG(HDMI_TG_H_FSZ_H);
706 DUMPREG(HDMI_TG_HACT_ST_L);
707 DUMPREG(HDMI_TG_HACT_ST_H);
708 DUMPREG(HDMI_TG_HACT_SZ_L);
709 DUMPREG(HDMI_TG_HACT_SZ_H);
710 DUMPREG(HDMI_TG_V_FSZ_L);
711 DUMPREG(HDMI_TG_V_FSZ_H);
712 DUMPREG(HDMI_TG_VSYNC_L);
713 DUMPREG(HDMI_TG_VSYNC_H);
714 DUMPREG(HDMI_TG_VSYNC2_L);
715 DUMPREG(HDMI_TG_VSYNC2_H);
716 DUMPREG(HDMI_TG_VACT_ST_L);
717 DUMPREG(HDMI_TG_VACT_ST_H);
718 DUMPREG(HDMI_TG_VACT_SZ_L);
719 DUMPREG(HDMI_TG_VACT_SZ_H);
720 DUMPREG(HDMI_TG_FIELD_CHG_L);
721 DUMPREG(HDMI_TG_FIELD_CHG_H);
722 DUMPREG(HDMI_TG_VACT_ST2_L);
723 DUMPREG(HDMI_TG_VACT_ST2_H);
724 DUMPREG(HDMI_TG_VACT_ST3_L);
725 DUMPREG(HDMI_TG_VACT_ST3_H);
726 DUMPREG(HDMI_TG_VACT_ST4_L);
727 DUMPREG(HDMI_TG_VACT_ST4_H);
728 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
729 DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
730 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
731 DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
732 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
733 DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
734 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
735 DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
736 DUMPREG(HDMI_TG_3D);
737
738 DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
739 DUMPREG(HDMI_AVI_CON);
740 DUMPREG(HDMI_AVI_HEADER0);
741 DUMPREG(HDMI_AVI_HEADER1);
742 DUMPREG(HDMI_AVI_HEADER2);
743 DUMPREG(HDMI_AVI_CHECK_SUM);
744 DUMPREG(HDMI_VSI_CON);
745 DUMPREG(HDMI_VSI_HEADER0);
746 DUMPREG(HDMI_VSI_HEADER1);
747 DUMPREG(HDMI_VSI_HEADER2);
748 for (i = 0; i < 7; ++i)
749 DUMPREG(HDMI_VSI_DATA(i));
750
751#undef DUMPREG
752}
753
754static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
755{
Rahul Sharma5a325072012-10-04 20:48:54 +0530756 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900757 hdmi_v13_regs_dump(hdata, prefix);
758 else
759 hdmi_v14_regs_dump(hdata, prefix);
760}
761
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530762static u8 hdmi_chksum(struct hdmi_context *hdata,
763 u32 start, u8 len, u32 hdr_sum)
764{
765 int i;
766
767 /* hdr_sum : header0 + header1 + header2
768 * start : start address of packet byte1
769 * len : packet bytes - 1 */
770 for (i = 0; i < len; ++i)
771 hdr_sum += 0xff & hdmi_reg_read(hdata, start + i * 4);
772
773 /* return 2's complement of 8 bit hdr_sum */
774 return (u8)(~(hdr_sum & 0xff) + 1);
775}
776
777static void hdmi_reg_infoframe(struct hdmi_context *hdata,
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530778 union hdmi_infoframe *infoframe)
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530779{
780 u32 hdr_sum;
781 u8 chksum;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530782 u32 mod;
783 u32 vic;
784
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530785 mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
786 if (hdata->dvi_mode) {
787 hdmi_reg_writeb(hdata, HDMI_VSI_CON,
788 HDMI_VSI_CON_DO_NOT_TRANSMIT);
789 hdmi_reg_writeb(hdata, HDMI_AVI_CON,
790 HDMI_AVI_CON_DO_NOT_TRANSMIT);
791 hdmi_reg_writeb(hdata, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
792 return;
793 }
794
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530795 switch (infoframe->any.type) {
796 case HDMI_INFOFRAME_TYPE_AVI:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530797 hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530798 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
799 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
800 infoframe->any.version);
801 hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
802 hdr_sum = infoframe->any.type + infoframe->any.version +
803 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530804
805 /* Output format zero hardcoded ,RGB YBCR selection */
806 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
807 AVI_ACTIVE_FORMAT_VALID |
808 AVI_UNDERSCANNED_DISPLAY_VALID);
809
Shirish S46154152014-03-13 10:58:28 +0530810 /*
811 * Set the aspect ratio as per the mode, mentioned in
812 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
813 */
814 switch (hdata->mode_conf.aspect_ratio) {
815 case HDMI_PICTURE_ASPECT_4_3:
816 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
817 hdata->mode_conf.aspect_ratio |
818 AVI_4_3_CENTER_RATIO);
819 break;
820 case HDMI_PICTURE_ASPECT_16_9:
821 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
822 hdata->mode_conf.aspect_ratio |
823 AVI_16_9_CENTER_RATIO);
824 break;
825 case HDMI_PICTURE_ASPECT_NONE:
826 default:
827 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
828 hdata->mode_conf.aspect_ratio |
829 AVI_SAME_AS_PIC_ASPECT_RATIO);
830 break;
831 }
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530832
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900833 vic = hdata->mode_conf.cea_video_id;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530834 hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
835
836 chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530837 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530838 DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
839 hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
840 break;
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530841 case HDMI_INFOFRAME_TYPE_AUDIO:
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530842 hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530843 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
844 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
845 infoframe->any.version);
846 hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
847 hdr_sum = infoframe->any.type + infoframe->any.version +
848 infoframe->any.length;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530849 chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
Sachin Kamatd34d59b2014-02-04 08:40:18 +0530850 infoframe->any.length, hdr_sum);
Rahul Sharmaa144c2e2012-11-26 10:52:57 +0530851 DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
852 hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
853 break;
854 default:
855 break;
856 }
857}
858
Sean Pauld9716ee2014-01-30 16:19:29 -0500859static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
860 bool force)
Sean Paul45517892014-01-30 16:19:05 -0500861{
Sean Pauld9716ee2014-01-30 16:19:29 -0500862 struct hdmi_context *hdata = ctx_from_connector(connector);
Sean Paul45517892014-01-30 16:19:05 -0500863
Sean Paul5137c8c2014-04-03 20:41:03 +0530864 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
865
Sean Pauld9716ee2014-01-30 16:19:29 -0500866 return hdata->hpd ? connector_status_connected :
867 connector_status_disconnected;
Sean Paul45517892014-01-30 16:19:05 -0500868}
869
Sean Pauld9716ee2014-01-30 16:19:29 -0500870static void hdmi_connector_destroy(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900871{
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900872}
873
Sean Pauld9716ee2014-01-30 16:19:29 -0500874static struct drm_connector_funcs hdmi_connector_funcs = {
875 .dpms = drm_helper_connector_dpms,
876 .fill_modes = drm_helper_probe_single_connector_modes,
877 .detect = hdmi_detect,
878 .destroy = hdmi_connector_destroy,
879};
880
881static int hdmi_get_modes(struct drm_connector *connector)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900882{
Sean Pauld9716ee2014-01-30 16:19:29 -0500883 struct hdmi_context *hdata = ctx_from_connector(connector);
884 struct edid *edid;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900885
Inki Dae8fa04aa2014-03-13 16:38:31 +0900886 if (!hdata->ddc_adpt)
Sean Pauld9716ee2014-01-30 16:19:29 -0500887 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900888
Inki Dae8fa04aa2014-03-13 16:38:31 +0900889 edid = drm_get_edid(connector, hdata->ddc_adpt);
Sean Pauld9716ee2014-01-30 16:19:29 -0500890 if (!edid)
891 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900892
Sean Pauld9716ee2014-01-30 16:19:29 -0500893 hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500894 DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
895 (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
Sean Pauld9716ee2014-01-30 16:19:29 -0500896 edid->width_cm, edid->height_cm);
Rahul Sharma9c08e4b2013-01-04 07:59:11 -0500897
Sean Pauld9716ee2014-01-30 16:19:29 -0500898 drm_mode_connector_update_edid_property(connector, edid);
899
900 return drm_add_edid_modes(connector, edid);
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900901}
902
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900903static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900904{
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900905 int i;
Seung-Woo Kimd8408322011-12-21 17:39:39 +0900906
Rahul Sharmad5e9ca42014-05-09 15:34:18 +0900907 for (i = 0; i < hdata->phy_conf_count; i++)
908 if (hdata->phy_confs[i].pixel_clock == pixel_clock)
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500909 return i;
Sean Paul2f7e2ed2013-01-15 08:11:08 -0500910
911 DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
912 return -EINVAL;
913}
914
Sean Pauld9716ee2014-01-30 16:19:29 -0500915static int hdmi_mode_valid(struct drm_connector *connector,
Sean Paulf041b252014-01-30 16:19:15 -0500916 struct drm_display_mode *mode)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900917{
Sean Pauld9716ee2014-01-30 16:19:29 -0500918 struct hdmi_context *hdata = ctx_from_connector(connector);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900919 int ret;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900920
Rahul Sharma16844fb2013-06-10 14:50:00 +0530921 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
922 mode->hdisplay, mode->vdisplay, mode->vrefresh,
923 (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
924 false, mode->clock * 1000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +0900925
Sean Paulf041b252014-01-30 16:19:15 -0500926 ret = mixer_check_mode(mode);
927 if (ret)
Sean Pauld9716ee2014-01-30 16:19:29 -0500928 return MODE_BAD;
Sean Paulf041b252014-01-30 16:19:15 -0500929
Rahul Sharma16844fb2013-06-10 14:50:00 +0530930 ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900931 if (ret < 0)
Sean Pauld9716ee2014-01-30 16:19:29 -0500932 return MODE_BAD;
933
934 return MODE_OK;
935}
936
937static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
938{
939 struct hdmi_context *hdata = ctx_from_connector(connector);
940
941 return hdata->encoder;
942}
943
944static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
945 .get_modes = hdmi_get_modes,
946 .mode_valid = hdmi_mode_valid,
947 .best_encoder = hdmi_best_encoder,
948};
949
950static int hdmi_create_connector(struct exynos_drm_display *display,
951 struct drm_encoder *encoder)
952{
953 struct hdmi_context *hdata = display->ctx;
954 struct drm_connector *connector = &hdata->connector;
955 int ret;
956
957 hdata->encoder = encoder;
958 connector->interlace_allowed = true;
959 connector->polled = DRM_CONNECTOR_POLL_HPD;
960
961 ret = drm_connector_init(hdata->drm_dev, connector,
962 &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
963 if (ret) {
964 DRM_ERROR("Failed to initialize connector with drm\n");
Rahul Sharma6b986ed2013-03-06 17:33:29 +0900965 return ret;
Sean Pauld9716ee2014-01-30 16:19:29 -0500966 }
967
968 drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
969 drm_sysfs_connector_add(connector);
970 drm_mode_connector_attach_encoder(connector, encoder);
971
972 return 0;
973}
974
Sean Paulf041b252014-01-30 16:19:15 -0500975static void hdmi_mode_fixup(struct exynos_drm_display *display,
976 struct drm_connector *connector,
977 const struct drm_display_mode *mode,
978 struct drm_display_mode *adjusted_mode)
979{
980 struct drm_display_mode *m;
981 int mode_ok;
982
983 DRM_DEBUG_KMS("%s\n", __FILE__);
984
985 drm_mode_set_crtcinfo(adjusted_mode, 0);
986
Sean Pauld9716ee2014-01-30 16:19:29 -0500987 mode_ok = hdmi_mode_valid(connector, adjusted_mode);
Sean Paulf041b252014-01-30 16:19:15 -0500988
989 /* just return if user desired mode exists. */
Sean Pauld9716ee2014-01-30 16:19:29 -0500990 if (mode_ok == MODE_OK)
Sean Paulf041b252014-01-30 16:19:15 -0500991 return;
992
993 /*
994 * otherwise, find the most suitable mode among modes and change it
995 * to adjusted_mode.
996 */
997 list_for_each_entry(m, &connector->modes, head) {
Sean Pauld9716ee2014-01-30 16:19:29 -0500998 mode_ok = hdmi_mode_valid(connector, m);
Sean Paulf041b252014-01-30 16:19:15 -0500999
Sean Pauld9716ee2014-01-30 16:19:29 -05001000 if (mode_ok == MODE_OK) {
Sean Paulf041b252014-01-30 16:19:15 -05001001 DRM_INFO("desired mode doesn't exist so\n");
1002 DRM_INFO("use the most suitable mode among modes.\n");
1003
1004 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
1005 m->hdisplay, m->vdisplay, m->vrefresh);
1006
Sean Paul75626852014-01-30 16:19:16 -05001007 drm_mode_copy(adjusted_mode, m);
Sean Paulf041b252014-01-30 16:19:15 -05001008 break;
1009 }
1010 }
1011}
1012
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001013static void hdmi_set_acr(u32 freq, u8 *acr)
1014{
1015 u32 n, cts;
1016
1017 switch (freq) {
1018 case 32000:
1019 n = 4096;
1020 cts = 27000;
1021 break;
1022 case 44100:
1023 n = 6272;
1024 cts = 30000;
1025 break;
1026 case 88200:
1027 n = 12544;
1028 cts = 30000;
1029 break;
1030 case 176400:
1031 n = 25088;
1032 cts = 30000;
1033 break;
1034 case 48000:
1035 n = 6144;
1036 cts = 27000;
1037 break;
1038 case 96000:
1039 n = 12288;
1040 cts = 27000;
1041 break;
1042 case 192000:
1043 n = 24576;
1044 cts = 27000;
1045 break;
1046 default:
1047 n = 0;
1048 cts = 0;
1049 break;
1050 }
1051
1052 acr[1] = cts >> 16;
1053 acr[2] = cts >> 8 & 0xff;
1054 acr[3] = cts & 0xff;
1055
1056 acr[4] = n >> 16;
1057 acr[5] = n >> 8 & 0xff;
1058 acr[6] = n & 0xff;
1059}
1060
1061static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
1062{
1063 hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
1064 hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
1065 hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
1066 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
1067 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
1068 hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
1069 hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
1070 hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
1071 hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
1072
Rahul Sharma5a325072012-10-04 20:48:54 +05301073 if (hdata->type == HDMI_TYPE13)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001074 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
1075 else
1076 hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
1077}
1078
1079static void hdmi_audio_init(struct hdmi_context *hdata)
1080{
1081 u32 sample_rate, bits_per_sample, frame_size_code;
1082 u32 data_num, bit_ch, sample_frq;
1083 u32 val;
1084 u8 acr[7];
1085
1086 sample_rate = 44100;
1087 bits_per_sample = 16;
1088 frame_size_code = 0;
1089
1090 switch (bits_per_sample) {
1091 case 20:
1092 data_num = 2;
1093 bit_ch = 1;
1094 break;
1095 case 24:
1096 data_num = 3;
1097 bit_ch = 1;
1098 break;
1099 default:
1100 data_num = 1;
1101 bit_ch = 0;
1102 break;
1103 }
1104
1105 hdmi_set_acr(sample_rate, acr);
1106 hdmi_reg_acr(hdata, acr);
1107
1108 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
1109 | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
1110 | HDMI_I2S_MUX_ENABLE);
1111
1112 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
1113 | HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
1114
1115 hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
1116
1117 sample_frq = (sample_rate == 44100) ? 0 :
1118 (sample_rate == 48000) ? 2 :
1119 (sample_rate == 32000) ? 3 :
1120 (sample_rate == 96000) ? 0xa : 0x0;
1121
1122 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
1123 hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
1124
1125 val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
1126 hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
1127
1128 /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
1129 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
1130 | HDMI_I2S_SEL_LRCK(6));
1131 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
1132 | HDMI_I2S_SEL_SDATA2(4));
1133 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
1134 | HDMI_I2S_SEL_SDATA2(2));
1135 hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
1136
1137 /* I2S_CON_1 & 2 */
1138 hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
1139 | HDMI_I2S_L_CH_LOW_POL);
1140 hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
1141 | HDMI_I2S_SET_BIT_CH(bit_ch)
1142 | HDMI_I2S_SET_SDATA_BIT(data_num)
1143 | HDMI_I2S_BASIC_FORMAT);
1144
1145 /* Configure register related to CUV information */
1146 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
1147 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
1148 | HDMI_I2S_COPYRIGHT
1149 | HDMI_I2S_LINEAR_PCM
1150 | HDMI_I2S_CONSUMER_FORMAT);
1151 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
1152 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
1153 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
1154 | HDMI_I2S_SET_SMP_FREQ(sample_frq));
1155 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
1156 HDMI_I2S_ORG_SMP_FREQ_44_1
1157 | HDMI_I2S_WORD_LEN_MAX24_24BITS
1158 | HDMI_I2S_WORD_LEN_MAX_24BITS);
1159
1160 hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
1161}
1162
1163static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
1164{
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001165 if (hdata->dvi_mode)
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001166 return;
1167
1168 hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
1169 hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
1170 HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
1171}
1172
Rahul Sharmabfa48422014-04-03 20:41:04 +05301173static void hdmi_start(struct hdmi_context *hdata, bool start)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001174{
Rahul Sharmabfa48422014-04-03 20:41:04 +05301175 u32 val = start ? HDMI_TG_EN : 0;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001176
Rahul Sharmabfa48422014-04-03 20:41:04 +05301177 if (hdata->current_mode.flags & DRM_MODE_FLAG_INTERLACE)
1178 val |= HDMI_FIELD_EN;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001179
Rahul Sharmabfa48422014-04-03 20:41:04 +05301180 hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
1181 hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001182}
1183
1184static void hdmi_conf_init(struct hdmi_context *hdata)
1185{
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301186 union hdmi_infoframe infoframe;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301187
Sean Paul77006a72013-01-16 10:17:20 -05001188 /* disable HPD interrupts from HDMI IP block, use GPIO instead */
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001189 hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
1190 HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001191
1192 /* choose HDMI mode */
1193 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1194 HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
1195 /* disable bluescreen */
1196 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001197
Seung-Woo Kim872d20d62012-04-24 17:39:15 +09001198 if (hdata->dvi_mode) {
1199 /* choose DVI mode */
1200 hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
1201 HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
1202 hdmi_reg_writeb(hdata, HDMI_CON_2,
1203 HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
1204 }
1205
Rahul Sharma5a325072012-10-04 20:48:54 +05301206 if (hdata->type == HDMI_TYPE13) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001207 /* choose bluescreen (fecal) color */
1208 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
1209 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
1210 hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
1211
1212 /* enable AVI packet every vsync, fixes purple line problem */
1213 hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
1214 /* force RGB, look to CEA-861-D, table 7 for more detail */
1215 hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
1216 hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
1217
1218 hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
1219 hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
1220 hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
1221 } else {
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301222 infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
1223 infoframe.any.version = HDMI_AVI_VERSION;
1224 infoframe.any.length = HDMI_AVI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301225 hdmi_reg_infoframe(hdata, &infoframe);
1226
Sachin Kamatd34d59b2014-02-04 08:40:18 +05301227 infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
1228 infoframe.any.version = HDMI_AUI_VERSION;
1229 infoframe.any.length = HDMI_AUI_LENGTH;
Rahul Sharmaa144c2e2012-11-26 10:52:57 +05301230 hdmi_reg_infoframe(hdata, &infoframe);
1231
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001232 /* enable AVI packet every vsync, fixes purple line problem */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001233 hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
1234 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001235}
1236
Rahul Sharma16844fb2013-06-10 14:50:00 +05301237static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001238{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001239 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1240 const struct hdmi_v13_core_regs *core =
1241 &hdata->mode_conf.conf.v13_conf.core;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001242 int tries;
1243
1244 /* setting core registers */
1245 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1246 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001247 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
1248 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
1249 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
1250 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
1251 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
1252 hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001253 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1254 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001255 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
1256 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
1257 hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
1258 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
1259 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
1260 hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
1261 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
1262 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
1263 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
1264 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
1265 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
1266 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
1267 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
1268 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
1269 hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001270 /* Timing generator registers */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001271 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1272 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1273 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1274 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1275 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1276 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1277 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1278 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1279 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1280 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1281 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1282 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1283 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1284 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1285 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1286 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1287 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1288 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1289 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1290 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1291 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1292 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1293 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1294 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1295 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1296 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1297 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1298 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001299
1300 /* waiting for HDMIPHY's PLL to get to steady state */
1301 for (tries = 100; tries; --tries) {
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001302 u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001303 if (val & HDMI_PHY_STATUS_READY)
1304 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001305 usleep_range(1000, 2000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001306 }
1307 /* steady state not achieved */
1308 if (tries == 0) {
1309 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1310 hdmi_regs_dump(hdata, "timing apply");
1311 }
1312
Sean Paul0bfb1f82013-06-11 12:24:02 +05301313 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301314 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301315 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001316
1317 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301318 hdmi_start(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001319}
1320
Rahul Sharma16844fb2013-06-10 14:50:00 +05301321static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001322{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001323 const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1324 const struct hdmi_v14_core_regs *core =
1325 &hdata->mode_conf.conf.v14_conf.core;
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001326 int tries;
1327
1328 /* setting core registers */
1329 hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
1330 hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
1331 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
1332 hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
1333 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
1334 hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
1335 hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
1336 hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
1337 hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
1338 hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
1339 hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
1340 hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
1341 hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
1342 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
1343 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
1344 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
1345 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
1346 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
1347 hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
1348 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
1349 hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
1350 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
1351 core->v_sync_line_bef_2[0]);
1352 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
1353 core->v_sync_line_bef_2[1]);
1354 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
1355 core->v_sync_line_bef_1[0]);
1356 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
1357 core->v_sync_line_bef_1[1]);
1358 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
1359 core->v_sync_line_aft_2[0]);
1360 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
1361 core->v_sync_line_aft_2[1]);
1362 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
1363 core->v_sync_line_aft_1[0]);
1364 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
1365 core->v_sync_line_aft_1[1]);
1366 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
1367 core->v_sync_line_aft_pxl_2[0]);
1368 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
1369 core->v_sync_line_aft_pxl_2[1]);
1370 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
1371 core->v_sync_line_aft_pxl_1[0]);
1372 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
1373 core->v_sync_line_aft_pxl_1[1]);
1374 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
1375 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
1376 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
1377 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
1378 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
1379 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
1380 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
1381 hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
1382 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
1383 core->v_sync_line_aft_3[0]);
1384 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
1385 core->v_sync_line_aft_3[1]);
1386 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
1387 core->v_sync_line_aft_4[0]);
1388 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
1389 core->v_sync_line_aft_4[1]);
1390 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
1391 core->v_sync_line_aft_5[0]);
1392 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
1393 core->v_sync_line_aft_5[1]);
1394 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
1395 core->v_sync_line_aft_6[0]);
1396 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
1397 core->v_sync_line_aft_6[1]);
1398 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
1399 core->v_sync_line_aft_pxl_3[0]);
1400 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
1401 core->v_sync_line_aft_pxl_3[1]);
1402 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
1403 core->v_sync_line_aft_pxl_4[0]);
1404 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
1405 core->v_sync_line_aft_pxl_4[1]);
1406 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
1407 core->v_sync_line_aft_pxl_5[0]);
1408 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
1409 core->v_sync_line_aft_pxl_5[1]);
1410 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
1411 core->v_sync_line_aft_pxl_6[0]);
1412 hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
1413 core->v_sync_line_aft_pxl_6[1]);
1414 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
1415 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
1416 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
1417 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
1418 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
1419 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
1420 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
1421 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
1422 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
1423 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
1424 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
1425 hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
1426
1427 /* Timing generator registers */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001428 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
1429 hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
1430 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
1431 hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
1432 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
1433 hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
1434 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
1435 hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
1436 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
1437 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
1438 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
1439 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
1440 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
1441 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
1442 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
1443 hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
1444 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
1445 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
1446 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
1447 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
1448 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
1449 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
1450 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
1451 hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
1452 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
1453 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
1454 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
1455 hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
1456 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
1457 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
1458 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
1459 hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
1460 hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001461
1462 /* waiting for HDMIPHY's PLL to get to steady state */
1463 for (tries = 100; tries; --tries) {
1464 u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
1465 if (val & HDMI_PHY_STATUS_READY)
1466 break;
Sean Paul09760ea2013-01-14 17:03:20 -05001467 usleep_range(1000, 2000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001468 }
1469 /* steady state not achieved */
1470 if (tries == 0) {
1471 DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
1472 hdmi_regs_dump(hdata, "timing apply");
1473 }
1474
Sean Paul0bfb1f82013-06-11 12:24:02 +05301475 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301476 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301477 clk_prepare_enable(hdata->res.sclk_hdmi);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001478
1479 /* enable HDMI and timing generator */
Rahul Sharmabfa48422014-04-03 20:41:04 +05301480 hdmi_start(hdata, true);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001481}
1482
Rahul Sharma16844fb2013-06-10 14:50:00 +05301483static void hdmi_mode_apply(struct hdmi_context *hdata)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001484{
Rahul Sharma5a325072012-10-04 20:48:54 +05301485 if (hdata->type == HDMI_TYPE13)
Rahul Sharma16844fb2013-06-10 14:50:00 +05301486 hdmi_v13_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001487 else
Rahul Sharma16844fb2013-06-10 14:50:00 +05301488 hdmi_v14_mode_apply(hdata);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001489}
1490
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001491static void hdmiphy_conf_reset(struct hdmi_context *hdata)
1492{
1493 u8 buffer[2];
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001494 u32 reg;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001495
Sean Paul0bfb1f82013-06-11 12:24:02 +05301496 clk_disable_unprepare(hdata->res.sclk_hdmi);
Rahul Sharma59956d32013-06-11 12:24:03 +05301497 clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
Sean Paul0bfb1f82013-06-11 12:24:02 +05301498 clk_prepare_enable(hdata->res.sclk_hdmi);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001499
1500 /* operation mode */
1501 buffer[0] = 0x1f;
1502 buffer[1] = 0x00;
1503
1504 if (hdata->hdmiphy_port)
1505 i2c_master_send(hdata->hdmiphy_port, buffer, 2);
1506
Rahul Sharma5a325072012-10-04 20:48:54 +05301507 if (hdata->type == HDMI_TYPE13)
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001508 reg = HDMI_V13_PHY_RSTOUT;
1509 else
1510 reg = HDMI_PHY_RSTOUT;
1511
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001512 /* reset hdmiphy */
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001513 hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001514 usleep_range(10000, 12000);
Joonyoung Shim3ecd70b2012-03-16 18:47:03 +09001515 hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT);
Sean Paul09760ea2013-01-14 17:03:20 -05001516 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001517}
1518
Rahul Sharmaa5562252012-11-28 11:30:25 +05301519static void hdmiphy_poweron(struct hdmi_context *hdata)
1520{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301521 if (hdata->type == HDMI_TYPE14)
1522 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
1523 HDMI_PHY_POWER_OFF_EN);
1524}
1525
1526static void hdmiphy_poweroff(struct hdmi_context *hdata)
1527{
Rahul Sharmaa5562252012-11-28 11:30:25 +05301528 if (hdata->type == HDMI_TYPE14)
1529 hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
1530 HDMI_PHY_POWER_OFF_EN);
1531}
1532
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001533static void hdmiphy_conf_apply(struct hdmi_context *hdata)
1534{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001535 int ret;
1536 int i;
1537
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001538 /* pixel clock */
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001539 i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
1540 if (i < 0) {
1541 DRM_ERROR("failed to find hdmiphy conf\n");
1542 return;
1543 }
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001544
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001545 ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
1546 if (ret) {
1547 DRM_ERROR("failed to configure hdmiphy\n");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001548 return;
1549 }
1550
Sean Paul09760ea2013-01-14 17:03:20 -05001551 usleep_range(10000, 12000);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001552
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09001553 ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
1554 HDMI_PHY_DISABLE_MODE_SET);
1555 if (ret) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001556 DRM_ERROR("failed to enable hdmiphy\n");
1557 return;
1558 }
1559
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001560}
1561
1562static void hdmi_conf_apply(struct hdmi_context *hdata)
1563{
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001564 hdmiphy_conf_reset(hdata);
1565 hdmiphy_conf_apply(hdata);
1566
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001567 mutex_lock(&hdata->hdmi_mutex);
Rahul Sharmabfa48422014-04-03 20:41:04 +05301568 hdmi_start(hdata, false);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001569 hdmi_conf_init(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001570 mutex_unlock(&hdata->hdmi_mutex);
1571
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001572 hdmi_audio_init(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001573
1574 /* setting core registers */
Rahul Sharma16844fb2013-06-10 14:50:00 +05301575 hdmi_mode_apply(hdata);
Seung-Woo Kim3e148ba2012-03-16 18:47:16 +09001576 hdmi_audio_control(hdata, true);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001577
1578 hdmi_regs_dump(hdata, "start");
1579}
1580
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001581static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
1582{
1583 int i;
1584 BUG_ON(num_bytes > 4);
1585 for (i = 0; i < num_bytes; i++)
1586 reg_pair[i] = (value >> (8 * i)) & 0xff;
1587}
1588
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001589static void hdmi_v13_mode_set(struct hdmi_context *hdata,
1590 struct drm_display_mode *m)
1591{
1592 struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
1593 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
1594 unsigned int val;
1595
1596 hdata->mode_conf.cea_video_id =
1597 drm_match_cea_mode((struct drm_display_mode *)m);
1598 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301599 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001600
1601 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1602 hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
1603
1604 val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
1605 hdmi_set_reg(core->vsync_pol, 1, val);
1606
1607 val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
1608 hdmi_set_reg(core->int_pro_mode, 1, val);
1609
1610 val = (m->hsync_start - m->hdisplay - 2);
1611 val |= ((m->hsync_end - m->hdisplay - 2) << 10);
1612 val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
1613 hdmi_set_reg(core->h_sync_gen, 3, val);
1614
1615 /*
1616 * Quirk requirement for exynos HDMI IP design,
1617 * 2 pixels less than the actual calculation for hsync_start
1618 * and end.
1619 */
1620
1621 /* Following values & calculations differ for different type of modes */
1622 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1623 /* Interlaced Mode */
1624 val = ((m->vsync_end - m->vdisplay) / 2);
1625 val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
1626 hdmi_set_reg(core->v_sync_gen1, 3, val);
1627
1628 val = m->vtotal / 2;
1629 val |= ((m->vtotal - m->vdisplay) / 2) << 11;
1630 hdmi_set_reg(core->v_blank, 3, val);
1631
1632 val = (m->vtotal +
1633 ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
1634 val |= m->vtotal << 11;
1635 hdmi_set_reg(core->v_blank_f, 3, val);
1636
1637 val = ((m->vtotal / 2) + 7);
1638 val |= ((m->vtotal / 2) + 2) << 12;
1639 hdmi_set_reg(core->v_sync_gen2, 3, val);
1640
1641 val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
1642 val |= ((m->htotal / 2) +
1643 (m->hsync_start - m->hdisplay)) << 12;
1644 hdmi_set_reg(core->v_sync_gen3, 3, val);
1645
1646 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1647 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
1648
1649 hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
1650 } else {
1651 /* Progressive Mode */
1652
1653 val = m->vtotal;
1654 val |= (m->vtotal - m->vdisplay) << 11;
1655 hdmi_set_reg(core->v_blank, 3, val);
1656
1657 hdmi_set_reg(core->v_blank_f, 3, 0);
1658
1659 val = (m->vsync_end - m->vdisplay);
1660 val |= ((m->vsync_start - m->vdisplay) << 12);
1661 hdmi_set_reg(core->v_sync_gen1, 3, val);
1662
1663 hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
1664 hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
1665 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1666 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1667 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1668 }
1669
1670 /* Timing generator registers */
1671 hdmi_set_reg(tg->cmd, 1, 0x0);
1672 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1673 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1674 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1675 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1676 hdmi_set_reg(tg->vsync, 2, 0x1);
1677 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1678 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1679 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
1680 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1681 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
1682 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
1683 hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
1684}
1685
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001686static void hdmi_v14_mode_set(struct hdmi_context *hdata,
1687 struct drm_display_mode *m)
1688{
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001689 struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
1690 struct hdmi_v14_core_regs *core =
1691 &hdata->mode_conf.conf.v14_conf.core;
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001692
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001693 hdata->mode_conf.cea_video_id =
1694 drm_match_cea_mode((struct drm_display_mode *)m);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001695 hdata->mode_conf.pixel_clock = m->clock * 1000;
Shirish S46154152014-03-13 10:58:28 +05301696 hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001697
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001698 hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
1699 hdmi_set_reg(core->v_line, 2, m->vtotal);
1700 hdmi_set_reg(core->h_line, 2, m->htotal);
1701 hdmi_set_reg(core->hsync_pol, 1,
1702 (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0);
1703 hdmi_set_reg(core->vsync_pol, 1,
1704 (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
1705 hdmi_set_reg(core->int_pro_mode, 1,
1706 (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
1707
1708 /*
1709 * Quirk requirement for exynos 5 HDMI IP design,
1710 * 2 pixels less than the actual calculation for hsync_start
1711 * and end.
1712 */
1713
1714 /* Following values & calculations differ for different type of modes */
1715 if (m->flags & DRM_MODE_FLAG_INTERLACE) {
1716 /* Interlaced Mode */
1717 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1718 (m->vsync_end - m->vdisplay) / 2);
1719 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1720 (m->vsync_start - m->vdisplay) / 2);
1721 hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
1722 hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301723 hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001724 hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
1725 hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
1726 hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
1727 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
1728 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1729 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
1730 (m->htotal / 2) + (m->hsync_start - m->hdisplay));
1731 hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
1732 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
Rahul Sharma14829952013-06-18 18:19:37 +05301733 hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
1734 hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
1735 hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
1736 hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001737 hdmi_set_reg(tg->vact_st3, 2, 0x0);
1738 hdmi_set_reg(tg->vact_st4, 2, 0x0);
1739 } else {
1740 /* Progressive Mode */
1741 hdmi_set_reg(core->v_sync_line_bef_2, 2,
1742 m->vsync_end - m->vdisplay);
1743 hdmi_set_reg(core->v_sync_line_bef_1, 2,
1744 m->vsync_start - m->vdisplay);
1745 hdmi_set_reg(core->v2_blank, 2, m->vtotal);
1746 hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
1747 hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
1748 hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
1749 hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
1750 hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
1751 hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
1752 hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
1753 hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
1754 hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
1755 hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
1756 hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
1757 hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
Rahul Sharma14829952013-06-18 18:19:37 +05301758 hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
1759 hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
1760 hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001761 }
1762
1763 /* Following values & calculations are same irrespective of mode type */
1764 hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
1765 hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
1766 hdmi_set_reg(core->vact_space_1, 2, 0xffff);
1767 hdmi_set_reg(core->vact_space_2, 2, 0xffff);
1768 hdmi_set_reg(core->vact_space_3, 2, 0xffff);
1769 hdmi_set_reg(core->vact_space_4, 2, 0xffff);
1770 hdmi_set_reg(core->vact_space_5, 2, 0xffff);
1771 hdmi_set_reg(core->vact_space_6, 2, 0xffff);
1772 hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
1773 hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
1774 hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
1775 hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
1776 hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
1777 hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
1778 hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
1779 hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
1780 hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
1781 hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
1782 hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
1783 hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
1784
1785 /* Timing generator registers */
1786 hdmi_set_reg(tg->cmd, 1, 0x0);
1787 hdmi_set_reg(tg->h_fsz, 2, m->htotal);
1788 hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
1789 hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
1790 hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
1791 hdmi_set_reg(tg->vsync, 2, 0x1);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001792 hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
1793 hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001794 hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001795 hdmi_set_reg(tg->tg_3d, 1, 0x0);
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001796}
1797
Sean Paulf041b252014-01-30 16:19:15 -05001798static void hdmi_mode_set(struct exynos_drm_display *display,
1799 struct drm_display_mode *mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001800{
Sean Paulf041b252014-01-30 16:19:15 -05001801 struct hdmi_context *hdata = display->ctx;
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001802 struct drm_display_mode *m = mode;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001803
YoungJun Chocbc4c332013-06-12 10:44:40 +09001804 DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
1805 m->hdisplay, m->vdisplay,
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001806 m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
1807 "INTERLACED" : "PROGERESSIVE");
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001808
Rahul Sharmabfa48422014-04-03 20:41:04 +05301809 /* preserve mode information for later use. */
1810 drm_mode_copy(&hdata->current_mode, mode);
1811
Sachin Kamat5f46c332013-04-26 11:29:00 +05301812 if (hdata->type == HDMI_TYPE13)
Rahul Sharma6b986ed2013-03-06 17:33:29 +09001813 hdmi_v13_mode_set(hdata, mode);
Sachin Kamat5f46c332013-04-26 11:29:00 +05301814 else
Sean Paul2f7e2ed2013-01-15 08:11:08 -05001815 hdmi_v14_mode_set(hdata, mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001816}
1817
Sean Paulf041b252014-01-30 16:19:15 -05001818static void hdmi_commit(struct exynos_drm_display *display)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001819{
Sean Paulf041b252014-01-30 16:19:15 -05001820 struct hdmi_context *hdata = display->ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001821
Shirish Sdda90122013-01-23 22:03:18 -05001822 mutex_lock(&hdata->hdmi_mutex);
1823 if (!hdata->powered) {
1824 mutex_unlock(&hdata->hdmi_mutex);
1825 return;
1826 }
1827 mutex_unlock(&hdata->hdmi_mutex);
1828
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001829 hdmi_conf_apply(hdata);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001830}
1831
Sean Paulf041b252014-01-30 16:19:15 -05001832static void hdmi_poweron(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001833{
Sean Paulf041b252014-01-30 16:19:15 -05001834 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001835 struct hdmi_resources *res = &hdata->res;
1836
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001837 mutex_lock(&hdata->hdmi_mutex);
1838 if (hdata->powered) {
1839 mutex_unlock(&hdata->hdmi_mutex);
1840 return;
1841 }
1842
1843 hdata->powered = true;
1844
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001845 mutex_unlock(&hdata->hdmi_mutex);
1846
Sean Paulaf65c802014-01-30 16:19:27 -05001847 pm_runtime_get_sync(hdata->dev);
1848
Seung-Woo Kimad079452013-06-05 14:34:38 +09001849 if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
1850 DRM_DEBUG_KMS("failed to enable regulator bulk\n");
1851
Sean Paul0bfb1f82013-06-11 12:24:02 +05301852 clk_prepare_enable(res->hdmiphy);
1853 clk_prepare_enable(res->hdmi);
1854 clk_prepare_enable(res->sclk_hdmi);
Rahul Sharmaa5562252012-11-28 11:30:25 +05301855
1856 hdmiphy_poweron(hdata);
Sean Paulf041b252014-01-30 16:19:15 -05001857 hdmi_commit(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001858}
1859
Sean Paulf041b252014-01-30 16:19:15 -05001860static void hdmi_poweroff(struct exynos_drm_display *display)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001861{
Sean Paulf041b252014-01-30 16:19:15 -05001862 struct hdmi_context *hdata = display->ctx;
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001863 struct hdmi_resources *res = &hdata->res;
1864
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001865 mutex_lock(&hdata->hdmi_mutex);
1866 if (!hdata->powered)
1867 goto out;
1868 mutex_unlock(&hdata->hdmi_mutex);
1869
Rahul Sharmabfa48422014-04-03 20:41:04 +05301870 /* HDMI System Disable */
1871 hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
1872
Rahul Sharmaa5562252012-11-28 11:30:25 +05301873 hdmiphy_poweroff(hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001874
Sean Paul724fd142014-05-09 15:05:10 +09001875 cancel_delayed_work(&hdata->hotplug_work);
1876
Sean Paul0bfb1f82013-06-11 12:24:02 +05301877 clk_disable_unprepare(res->sclk_hdmi);
1878 clk_disable_unprepare(res->hdmi);
1879 clk_disable_unprepare(res->hdmiphy);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001880 regulator_bulk_disable(res->regul_count, res->regul_bulk);
1881
Sean Paulaf65c802014-01-30 16:19:27 -05001882 pm_runtime_put_sync(hdata->dev);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001883
Sean Paulaf65c802014-01-30 16:19:27 -05001884 mutex_lock(&hdata->hdmi_mutex);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001885 hdata->powered = false;
1886
1887out:
1888 mutex_unlock(&hdata->hdmi_mutex);
1889}
1890
Sean Paulf041b252014-01-30 16:19:15 -05001891static void hdmi_dpms(struct exynos_drm_display *display, int mode)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001892{
YoungJun Chocbc4c332013-06-12 10:44:40 +09001893 DRM_DEBUG_KMS("mode %d\n", mode);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001894
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001895 switch (mode) {
1896 case DRM_MODE_DPMS_ON:
Sean Paulaf65c802014-01-30 16:19:27 -05001897 hdmi_poweron(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001898 break;
1899 case DRM_MODE_DPMS_STANDBY:
1900 case DRM_MODE_DPMS_SUSPEND:
1901 case DRM_MODE_DPMS_OFF:
Sean Paulaf65c802014-01-30 16:19:27 -05001902 hdmi_poweroff(display);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001903 break;
1904 default:
1905 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
1906 break;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001907 }
1908}
1909
Sean Paulf041b252014-01-30 16:19:15 -05001910static struct exynos_drm_display_ops hdmi_display_ops = {
Sean Pauld9716ee2014-01-30 16:19:29 -05001911 .create_connector = hdmi_create_connector,
Sean Paulf041b252014-01-30 16:19:15 -05001912 .mode_fixup = hdmi_mode_fixup,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001913 .mode_set = hdmi_mode_set,
Sean Paulf041b252014-01-30 16:19:15 -05001914 .dpms = hdmi_dpms,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001915 .commit = hdmi_commit,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001916};
1917
Sean Paulf041b252014-01-30 16:19:15 -05001918static struct exynos_drm_display hdmi_display = {
1919 .type = EXYNOS_DISPLAY_TYPE_HDMI,
1920 .ops = &hdmi_display_ops,
1921};
1922
Sean Paul724fd142014-05-09 15:05:10 +09001923static void hdmi_hotplug_work_func(struct work_struct *work)
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001924{
Sean Paul724fd142014-05-09 15:05:10 +09001925 struct hdmi_context *hdata;
1926
1927 hdata = container_of(work, struct hdmi_context, hotplug_work.work);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001928
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001929 mutex_lock(&hdata->hdmi_mutex);
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05301930 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001931 mutex_unlock(&hdata->hdmi_mutex);
1932
Sean Paul45517892014-01-30 16:19:05 -05001933 if (hdata->drm_dev)
1934 drm_helper_hpd_irq_event(hdata->drm_dev);
Sean Paul724fd142014-05-09 15:05:10 +09001935}
1936
1937static irqreturn_t hdmi_irq_thread(int irq, void *arg)
1938{
1939 struct hdmi_context *hdata = arg;
1940
1941 mod_delayed_work(system_wq, &hdata->hotplug_work,
1942 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001943
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09001944 return IRQ_HANDLED;
1945}
1946
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08001947static int hdmi_resources_init(struct hdmi_context *hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001948{
1949 struct device *dev = hdata->dev;
1950 struct hdmi_resources *res = &hdata->res;
1951 static char *supply[] = {
1952 "hdmi-en",
1953 "vdd",
1954 "vdd_osc",
1955 "vdd_pll",
1956 };
1957 int i, ret;
1958
1959 DRM_DEBUG_KMS("HDMI resource init\n");
1960
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001961 /* get clocks, power */
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301962 res->hdmi = devm_clk_get(dev, "hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301963 if (IS_ERR(res->hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001964 DRM_ERROR("failed to get clock 'hdmi'\n");
1965 goto fail;
1966 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301967 res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301968 if (IS_ERR(res->sclk_hdmi)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001969 DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
1970 goto fail;
1971 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301972 res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301973 if (IS_ERR(res->sclk_pixel)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001974 DRM_ERROR("failed to get clock 'sclk_pixel'\n");
1975 goto fail;
1976 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301977 res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301978 if (IS_ERR(res->sclk_hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001979 DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
1980 goto fail;
1981 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301982 res->hdmiphy = devm_clk_get(dev, "hdmiphy");
Sachin Kamatee7cbaf2013-03-21 15:33:57 +05301983 if (IS_ERR(res->hdmiphy)) {
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001984 DRM_ERROR("failed to get clock 'hdmiphy'\n");
1985 goto fail;
1986 }
Rahul Sharma59956d32013-06-11 12:24:03 +05301987 res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
1988 if (IS_ERR(res->mout_hdmi)) {
1989 DRM_ERROR("failed to get clock 'mout_hdmi'\n");
1990 goto fail;
1991 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001992
Rahul Sharma59956d32013-06-11 12:24:03 +05301993 clk_set_parent(res->mout_hdmi, res->sclk_pixel);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001994
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05301995 res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
Sachin Kamatadc837a2012-08-31 15:50:47 +05301996 sizeof(res->regul_bulk[0]), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09001997 if (!res->regul_bulk)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001998 goto fail;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09001999 for (i = 0; i < ARRAY_SIZE(supply); ++i) {
2000 res->regul_bulk[i].supply = supply[i];
2001 res->regul_bulk[i].consumer = NULL;
2002 }
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302003 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002004 if (ret) {
2005 DRM_ERROR("failed to get regulators\n");
2006 goto fail;
2007 }
2008 res->regul_count = ARRAY_SIZE(supply);
2009
2010 return 0;
2011fail:
2012 DRM_ERROR("HDMI resource init - failed\n");
2013 return -ENODEV;
2014}
2015
Rahul Sharma22c4f422012-10-04 20:48:55 +05302016static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
2017 (struct device *dev)
2018{
2019 struct device_node *np = dev->of_node;
2020 struct s5p_hdmi_platform_data *pd;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302021 u32 value;
2022
2023 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002024 if (!pd)
Rahul Sharma22c4f422012-10-04 20:48:55 +05302025 goto err_data;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302026
2027 if (!of_find_property(np, "hpd-gpio", &value)) {
2028 DRM_ERROR("no hpd gpio property found\n");
2029 goto err_data;
2030 }
2031
Rahul Sharma5f916e22013-06-11 19:41:29 +05302032 pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
Rahul Sharma22c4f422012-10-04 20:48:55 +05302033
2034 return pd;
2035
2036err_data:
2037 return NULL;
2038}
Rahul Sharma22c4f422012-10-04 20:48:55 +05302039
Rahul Sharma22c4f422012-10-04 20:48:55 +05302040static struct of_device_id hdmi_match_types[] = {
2041 {
2042 .compatible = "samsung,exynos5-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002043 .data = &exynos5_hdmi_driver_data,
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302044 }, {
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302045 .compatible = "samsung,exynos4212-hdmi",
Inki Daebfe4e842014-03-06 14:18:17 +09002046 .data = &exynos4212_hdmi_driver_data,
Rahul Sharmacc57caf2013-06-19 18:21:07 +05302047 }, {
Tomasz Stanislawskic119ed02012-10-04 20:48:44 +05302048 /* end node */
2049 }
2050};
2051
Inki Daef37cd5e2014-05-09 14:25:20 +09002052static int hdmi_bind(struct device *dev, struct device *master, void *data)
2053{
2054 struct drm_device *drm_dev = data;
2055 struct hdmi_context *hdata;
2056
2057 hdata = hdmi_display.ctx;
2058 hdata->drm_dev = drm_dev;
2059
2060 return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
2061}
2062
2063static void hdmi_unbind(struct device *dev, struct device *master, void *data)
2064{
2065 struct exynos_drm_display *display = get_hdmi_display(dev);
2066 struct drm_encoder *encoder = display->encoder;
2067 struct hdmi_context *hdata = display->ctx;
2068
2069 encoder->funcs->destroy(encoder);
2070 drm_connector_cleanup(&hdata->connector);
2071}
2072
2073static const struct component_ops hdmi_component_ops = {
2074 .bind = hdmi_bind,
2075 .unbind = hdmi_unbind,
2076};
2077
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002078static int hdmi_probe(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002079{
Inki Daef37cd5e2014-05-09 14:25:20 +09002080 struct device_node *ddc_node, *phy_node;
2081 struct s5p_hdmi_platform_data *pdata;
2082 struct hdmi_driver_data *drv_data;
2083 const struct of_device_id *match;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002084 struct device *dev = &pdev->dev;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002085 struct hdmi_context *hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002086 struct resource *res;
2087 int ret;
2088
Inki Daef37cd5e2014-05-09 14:25:20 +09002089 if (!dev->of_node)
Sachin Kamat88c49812013-08-28 10:47:57 +05302090 return -ENODEV;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302091
Sachin Kamat88c49812013-08-28 10:47:57 +05302092 pdata = drm_hdmi_dt_parse_pdata(dev);
2093 if (!pdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002094 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002095
Sachin Kamat88c49812013-08-28 10:47:57 +05302096 hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +09002097 if (!hdata)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002098 return -ENOMEM;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002099
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002100 mutex_init(&hdata->hdmi_mutex);
2101
Sean Paulf041b252014-01-30 16:19:15 -05002102 platform_set_drvdata(pdev, &hdmi_display);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002103
Sachin Kamat88c49812013-08-28 10:47:57 +05302104 match = of_match_node(hdmi_match_types, dev->of_node);
2105 if (!match)
2106 return -ENODEV;
Inki Daebfe4e842014-03-06 14:18:17 +09002107
2108 drv_data = (struct hdmi_driver_data *)match->data;
2109 hdata->type = drv_data->type;
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002110 hdata->phy_confs = drv_data->phy_confs;
2111 hdata->phy_conf_count = drv_data->phy_conf_count;
Rahul Sharma22c4f422012-10-04 20:48:55 +05302112
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302113 hdata->hpd_gpio = pdata->hpd_gpio;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002114 hdata->dev = dev;
2115
2116 ret = hdmi_resources_init(hdata);
2117 if (ret) {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302118 DRM_ERROR("hdmi_resources_init failed\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302119 return -EINVAL;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002120 }
2121
2122 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002123 hdata->regs = devm_ioremap_resource(dev, res);
Thierry Redingd4ed6022013-01-21 11:09:02 +01002124 if (IS_ERR(hdata->regs))
2125 return PTR_ERR(hdata->regs);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002126
Seung-Woo Kimd873ab92013-05-22 21:14:14 +09002127 ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302128 if (ret) {
2129 DRM_ERROR("failed to request HPD gpio\n");
Sachin Kamat9f49d9f2012-11-23 14:13:27 +05302130 return ret;
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302131 }
2132
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002133 /* DDC i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002134 ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
2135 if (!ddc_node) {
2136 DRM_ERROR("Failed to find ddc node in device tree\n");
2137 return -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002138 }
Inki Dae8fa04aa2014-03-13 16:38:31 +09002139 hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
2140 if (!hdata->ddc_adpt) {
2141 DRM_ERROR("Failed to get ddc i2c adapter by node\n");
Daniel Kurtz2b768132014-02-24 18:52:51 +09002142 return -ENODEV;
2143 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002144
2145 /* hdmiphy i2c driver */
Daniel Kurtz2b768132014-02-24 18:52:51 +09002146 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
2147 if (!phy_node) {
2148 DRM_ERROR("Failed to find hdmiphy node in device tree\n");
2149 ret = -ENODEV;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002150 goto err_ddc;
2151 }
Rahul Sharmad5e9ca42014-05-09 15:34:18 +09002152
2153 if (drv_data->is_apb_phy) {
2154 hdata->regs_hdmiphy = of_iomap(phy_node, 0);
2155 if (!hdata->regs_hdmiphy) {
2156 DRM_ERROR("failed to ioremap hdmi phy\n");
2157 ret = -ENOMEM;
2158 goto err_ddc;
2159 }
2160 } else {
2161 hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
2162 if (!hdata->hdmiphy_port) {
2163 DRM_ERROR("Failed to get hdmi phy i2c client\n");
2164 ret = -ENODEV;
2165 goto err_ddc;
2166 }
Daniel Kurtz2b768132014-02-24 18:52:51 +09002167 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002168
Sean Paul77006a72013-01-16 10:17:20 -05002169 hdata->irq = gpio_to_irq(hdata->hpd_gpio);
2170 if (hdata->irq < 0) {
2171 DRM_ERROR("failed to get GPIO irq\n");
2172 ret = hdata->irq;
Joonyoung Shim66265a22012-04-23 19:35:49 +09002173 goto err_hdmiphy;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002174 }
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002175
Tomasz Stanislawskifca57122012-10-04 20:48:46 +05302176 hdata->hpd = gpio_get_value(hdata->hpd_gpio);
2177
Sean Paul724fd142014-05-09 15:05:10 +09002178 INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
2179
Seung-Woo Kimdcb9a7c2013-05-22 21:14:17 +09002180 ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
Sean Paul77006a72013-01-16 10:17:20 -05002181 hdmi_irq_thread, IRQF_TRIGGER_RISING |
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002182 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Sean Paulf041b252014-01-30 16:19:15 -05002183 "hdmi", hdata);
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002184 if (ret) {
Sean Paul77006a72013-01-16 10:17:20 -05002185 DRM_ERROR("failed to register hdmi interrupt\n");
Joonyoung Shimcf8fc4f2012-04-23 19:35:50 +09002186 goto err_hdmiphy;
2187 }
2188
Sean Paulaf65c802014-01-30 16:19:27 -05002189 pm_runtime_enable(dev);
Sean Paulf041b252014-01-30 16:19:15 -05002190 hdmi_display.ctx = hdata;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002191
Inki Daef37cd5e2014-05-09 14:25:20 +09002192 return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002193
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002194err_hdmiphy:
Paul Taysomb21a3bf2014-05-09 15:06:28 +09002195 if (hdata->hdmiphy_port)
2196 put_device(&hdata->hdmiphy_port->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002197err_ddc:
Inki Dae8fa04aa2014-03-13 16:38:31 +09002198 put_device(&hdata->ddc_adpt->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002199 return ret;
2200}
2201
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002202static int hdmi_remove(struct platform_device *pdev)
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002203{
Inki Daef37cd5e2014-05-09 14:25:20 +09002204 struct hdmi_context *hdata = hdmi_display.ctx;
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002205
Sean Paul724fd142014-05-09 15:05:10 +09002206 cancel_delayed_work_sync(&hdata->hotplug_work);
2207
Daniel Kurtz2b768132014-02-24 18:52:51 +09002208 put_device(&hdata->hdmiphy_port->dev);
Inki Dae8fa04aa2014-03-13 16:38:31 +09002209 put_device(&hdata->ddc_adpt->dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09002210
Sean Paulaf65c802014-01-30 16:19:27 -05002211 pm_runtime_disable(&pdev->dev);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002212
Inki Daef37cd5e2014-05-09 14:25:20 +09002213 exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002214 return 0;
2215}
2216
2217struct platform_driver hdmi_driver = {
2218 .probe = hdmi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -08002219 .remove = hdmi_remove,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002220 .driver = {
Rahul Sharma22c4f422012-10-04 20:48:55 +05302221 .name = "exynos-hdmi",
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002222 .owner = THIS_MODULE,
Sachin Kamat88c49812013-08-28 10:47:57 +05302223 .of_match_table = hdmi_match_types,
Seung-Woo Kimd8408322011-12-21 17:39:39 +09002224 },
2225};